Probleme mit der Festo Motion Library

SpaeterVogel

Level-1
Beiträge
4
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

Folgendes Problem:
Ich versuche über das Bus-System CANopen einen CMMP-AS-C2-3A-M0 (Motorcontroller) über eine CPX-CEC-C1 (SPS) anzusteuern, beide Elemente sind von der Firma Festo.
Hierzu verwende ich in Codesys provided by Festo (2.3.9.19) den Baustein CMMP_AS_CTRL aus der Library-Datei Festo_Motion.lib.
Wenn ich die Bits manuell durch Forcen setze funktioniert alles, heißt: im Controller werden die Bits erkannt und der Motor bewegt sich entsprechend der Vorgaben.
Auch, wenn ich eine entsprechende Sequenz starte, die alle Bits in der richtigen Reihenfolge setzt, funktioniert alles.
Sobald ich aber versuche, das ganze automatisch anfahren zu lassen, reagiert der Controller nicht mehr darauf. Er erkennt zwar alle Bits und gibt auch das Ready-Signal aus, allerdings bewegt sich der Motor kein Stück.
Wenn ich wiederum das entsprechende Bit, was die Sequenz starten soll, durch Forcen auf False setze und dann wieder auf True, läuft der Motor wieder.

Danke schon mal im Voraus.
 
Hört sich ein wenig so an, als ob die beim Forcen durch das Aus-/Einschalten der Bits Flanken erzeugst (die der Systembaustein wahrscheinlich braucht). Bei automatischen Ablauf, wie auch immer du den programmiert hast, scheint das nicht so zu passieren. Geht es denn ein einziges Mal und dann nie wieder oder überhaupt nicht? Ich würde den Fehler eher nicht in der Lib suchen, sondern im eigenen Programm und das kann man hier nicht sehen.

PS: Was meinst übrigens mit Bits manuell setzen? Hast di ein Programm geschrieben, in welchem die die Bits manuell setzt oder setzt du die Bits an der Schnittstelle des Bausteins oder was genau?
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Um die Bits am Baustein zu setzen habe ich eine Sequenz aus Einschaltverzögerungen verwendet. Die Bits werden also nicht sofort gesetzt, sondern nach und nach. Diese werden auch im FCT als gesetzt angezeigt, also kommen sie auch beim Controller an.
 
Die Bits sind an die entsprechenden Ein- & Ausgänge des Controllerbausteins gelegt.
Die Sequenz wird hier also gestartet, wenn noch keine Referenzfahrt durchgeführt wurde (was nach einem Neustart der Fall ist) und leitet diese ein.
 

Anhänge

  • Startsequenz.jpg
    Startsequenz.jpg
    38 KB · Aufrufe: 22
Zuviel Werbung?
-> Hier kostenlos registrieren
Möglicherweise werden die ersten Bits schon gesetzt, wenn der Servo selbst noch am Hochlaufen ist. Wenn "Drive_is_Referenced" fehlt, wird genau 1 Mal der Vorgang gestartet (Flanke in Servobaustein oder im Servo selbst), dann nie wieder. Klappt das nicht, weil der Servo noch nicht soweit war, passiert danach nie wieder etwas. Es gibt doch diverse Gegensignale vom Servo (Betriebsbereit, Servo in Halt, Servo bereit usw.) Es macht Sinn, diese Signale (soweit vorhanden) in diese "Kette" mit einzubauen. Außerdem am Anfang ein generelles Signal, dass anzeigt, dass der Servo hochgelaufen ist und die Maschine betriebsbereit sowie sicher. Auch hier, sollte der Sicherheitskreis den Servo nicht starten lassen, tut er das dann auch nach Zuschalten des Sicherheitskontaktes nicht mehr. Dieser Kontakt sollte ebenfalls ganz am Anfang eingebunden sein.
 
Zuletzt bearbeitet:
Im aktuellen Programm habe ich die Verzögerung für den Start des Controllers bereits berücksichtigt, ich hatte gestern leider nur eine frühere Version zur Verfügung und habe vergessen, dies zu erwähnen.

Das genannte Problem konnte ich trotzdem beheben, indem ich einfach das Ready-Bit vom Controller-Baustein in die Bedingungen für den endgültigen Start einbezogen habe.
Scheinbar reagiert der Controller mit der Freigabe ein wenig verzögert.

Trotzdem danke für deine Hilfe.
 
Hallo,

nunja der Hochlauf ist eindeutig definiert und über alle Festo Antrieb annährend identisch über das FHPP Protokoll.

Der Hochlauf sollte bei diesem Antrieb wie folgt aussehen:
Code:
170: (* Versorgungsspannung des Motorcontollers prüfen° *)
 IF my_CMMx_CTRL.SupplyVoltagePresent THEN
  my_CMMx_CTRL.Halt := TRUE; (* Halt Signal setzen falls Betriebsspannung vorhanden ist *)
  tTimeout := TIME() + tDefaultTimeout;
  nStep := 180;
 ELSE
  my_ST_Error.eMsgSpace := emsOthers;
  nStep := nStep + 1000 + 2; (* logged 172 *)
 END_IF;
180: (* Regelung einschalten *)
 IF my_CMMx_CTRL.HaltActive THEN
  my_CMMx_CTRL.EnableDrive := TRUE;
  tTimeout := TIME() + tDefaultTimeout;
  nStep := 190;
 END_IF (* logged 181 *)
190: (* Stop Signal setzen (Low active) *)
 IF my_CMMx_CTRL.DriveEnabled THEN
  my_CMMx_CTRL.Stop := TRUE;
  tTimeout := TIME() + tDefaultTimeout;
  nStep := 200;
 END_IF (* logged 191 *)
200: (* Prüfung ob Antrieb betriebsbereit ist *)
 IF  my_CMMx_CTRL.Ready THEN
  (* Prüfung ob Antrieb bereit für Auftrag *)
  IF my_CMMx_CTRL.AckStart THEN
   nStep := 1000 + nStep + 2; (* logged 202 *)
  (* Referenzfahrt ausführen falls Antrieb nicht referenziert ist *)
  ELSIF NOT my_CMMx_CTRL.DriveIsReferenced
   AND NOT my_CMMx_CTRL.AckStart
  THEN
   eStatus := easReferenceRun; (* Status "Referenzfahrt läuft" melden *)
   my_CMMx_CTRL.StartHoming  := TRUE;
   tTimeout := TIME() + tDefaultTimeout;
   nStep := 210;
  ELSE
   eStatus := easReadyForTask; (* Status "Bereit für Fahrauftrag" melden *)
   tTimeout := tDisarmTimeout;
   nStep := 300;
  END_IF;
 END_IF (* logged 201 *)
210: (* Warten auf Bestätigung, dass Referenzfahrt gestartet wurde *)
 IF my_CMMx_CTRL.AckStart THEN
  my_CMMx_CTRL.StartHoming := FALSE;
  tTimeout := TIME() + tDefaultTimeout;
  nStep := 220;
 END_IF (* logged 211 *)
220: (* Warten auf negative Flanke von AckStart *)
 IF NOT my_CMMx_CTRL.AckStart THEN
  tTimeout := tDisarmTimeout; (* Timeout ausschalten da Referenzfahrt unter Umständen sehr lange dauern kann *)
  nStep := 230;
 END_IF; (* logged 221 *)
230: (* Warten auf Rückmeldung, dass Antrieb referenziert ist *)
 IF my_CMMx_CTRL.DriveIsReferenced THEN
  tTimeout := TIME() + tDefaultTimeout;
  nStep := 240;
 END_IF;
240: (* Negative Flanke von AckStart abfragen *)
 IF NOT my_CMMx_CTRL.AckStart THEN
  tTimeout := tDisarmTimeout;
  nStep := 300;
 END_IF; (* logged 241 *)

Dann ist der Controller bereit. Vorausgesetzt die Hardwareeingänge "Reglerfrg." "Endstufenfrg" und Spg ist gesetzt.

Nun können die verschiedenen Betriebsarten ausgewählt werden:

Code:
310: (* Entsprechend des Kommandos Bewegung ausführen *)
(* IF   nChangeOPM = 0
  AND NOT bOPMChangeRequired
 THEN*)
  CASE eCommand OF
   easStartAbsolute..easStartRelative: (* Positionierung ausführen *)
    my_CMMx_CTRL.OPM := 1; (* Positionierbetriebsart *)
    (* Bei Relativfahrt Flag an CMMx Baustein setzen *)
    my_CMMx_CTRL.AbsoluteRelative := eCommand = easStartRelative;
    (* Bewegung kann nicht ausgeführt werden da Antrieb nicht bereit *)
    IF nSetValueVelocity = 0 THEN
     eStatus := easErrDrive;
     nStep := 1000 + nStep + 5;

    ELSE (* Bewegung ausführen *)
     my_CMMx_CTRL.SetValuePosition := nSetValuePosition;
     rTemp := (DINT_TO_REAL(nSetValueVelocity) / DINT_TO_REAL(nMaxVelocity)) * 100; (* Umrechnung der Sollgeschwindigkeit in Prozentwert des Maximums *)
     my_CMMx_CTRL.SetValueVelocity := REAL_TO_USINT(rTemp);
     my_CMMx_CTRL.StartTask := TRUE;
     tTimeout := TIME() + tDefaultTimeout;
     nStep := 400;
    END_IF;
   easJogPos..easJogNeg: (* In positive Richtung joggen *)
    my_CMMx_CTRL.OPM := 1; (* Positionierbetriebsart *)
    my_CMMx_CTRL.JoggingPos := eCommand = easJogPos;
    my_CMMx_CTRL.JoggingNeg := eCommand = easJogNeg;
    tTimeout := tDisarmTimeout;
    nStep := 500;

   easStartVelocity:
    my_CMMx_CTRL.OPM := 9; (* Drehzahlregelung *)
    my_CMMx_CTRL.SetValueRotRamp := DINT_TO_SINT(nSetValueAcceleration);
    my_CMMx_CTRL.SetValueRotSpeed := nSetValueVelocity; (* Umrechnung hier nicht notwendig da die Sollwertvorgabe an RotSpeed nicht in Prozentwerten erfolgt *)
    my_CMMx_CTRL.StartTask := TRUE;
    tTimeout := TIME() + tDefaultTimeout;
    nStep := 600;
   easStartTorque:
    ;
  END_CASE;
 (*END_IF;*)

(*****************************************************)
(* Direktbetrieb Positionierung       *)
(*****************************************************)
400: (* Warten auf Bestätigung des Fahrbefehls *)
 IF my_CMMx_CTRL.AckStart THEN
  eStatus := easInMotion;
  my_CMMx_CTRL.StartTask := FALSE;
  tTimeout := TIME() + tDefaultTimeout;
  nStep := 410;
 END_IF;
410: (* Warten auf Rücksetzen der Bestätigung *)
 IF NOT my_CMMx_CTRL.AckStart THEN
  tTimeout := tDisarmTimeout;
  nStep := 420;
 END_IF;
420:
 (* Weiterschaltbedingungen für Positionieraufträge *)
 (* Fall 1: Warten auf Erreichen des Ziels *)
 IF my_CMMx_CTRL.MC THEN
  eStatus := easMotionComplete; (* Meldung "Antrieb steht im Ziel" setzen *)
  tTimeout := tDisarmTimeout;
  nStep := 430;
 (* Fall 2: Positionierung anhalten und Restweg löschen *)
 ELSIF eCommand = easHaltDrive THEN
  my_CMMx_CTRL.Halt := FALSE;
  eStatus := easReadyForTask; (* Meldung "Antrieb bereit für neuen Auftrag" setzen *)
  tTimeout := TIME() + tDefaultTimeout;
  nStep := 440;
 (* Fall 3: Positionierung weiter ausführen jedoch als Bereit für neuen Auftrag setzen *)
 ELSIF eCommand = easNewTask THEN
  eStatus := easReadyForTask; (* Meldung "Antrieb bereit für neuen Auftrag" setzen *)
  tTimeout := tDisarmTimeout;
  nStep := 300;
 END_IF;
430: (* Warten auf Bestätigung des Fahrbefehls *)
 IF eCommand = easAckTask THEN
  eStatus := easReadyForTask; (* Meldung "Antrieb bereit für neuen Auftrag" setzen *)
  tTimeout := tDisarmTimeout;
  nStep := 300; (* Rücksprung zu Kommandoverteiler *)
 END_IF;
440: (* Warten auf ausgeführten Halt *)
 IF NOT my_CMMx_CTRL.HaltActive THEN
  my_CMMx_CTRL.Halt := TRUE;
  my_CMMx_CTRL.ClearRemainingPosition := TRUE;
  tTimeout := TIME() + tDefaultTimeout;
  nStep := 450;
 END_IF;
450: (* Warten auf ausgeführten Halt *)
 IF my_CMMx_CTRL.HaltActive THEN
  my_CMMx_CTRL.ClearRemainingPosition := FALSE;
  tTimeout := tDisarmTimeout;
  nStep := 300;
 END_IF;

(*****************************************************)
(* Tippbetrieb           *)
(*****************************************************)
500: (* Warten auf Bestätigung, dass der Antrieb in entsprechende Richtung tippt.
  Sofort anhalten sobald das Kommando easAckMove kommt! *)
 IF   my_CMMx_CTRL.AckStart
  OR  eCommand = easAckTask (* Sofort Tippen abbrechen bei easAckTask *)
 THEN
  eStatus := easInMotion;
  tTimeout := tDisarmTimeout;
  nStep := 510;
 END_IF;
510: (* Warten auf Kommando easAckMove dann Tippen stoppen *)
 IF eCommand = easAckTask THEN
  eStatus := easReadyForTask; (* Meldung "Antrieb bereit für neuen Auftrag" setzen *)
  my_CMMx_CTRL.JoggingPos := FALSE;
  my_CMMx_CTRL.JoggingNeg := FALSE;
  tTimeout := tDisarmTimeout;
  nStep := 300;
 END_IF;

(*****************************************************)
(* Direktbetrieb Drehzahlregelung      *)
(*****************************************************)
600: (* Warten auf Bestätigung des Fahrbefehls *)
 IF my_CMMx_CTRL.AckStart THEN
  eStatus := easInMotion;
  my_CMMx_CTRL.StartTask := FALSE;
  tTimeout := TIME() + tDefaultTimeout;
  nStep := 610;
 END_IF;
610: (* Warten auf Rücksetzen der Bestätigung *)
 IF NOT my_CMMx_CTRL.AckStart THEN
  tTimeout := tDisarmTimeout;
  nStep := 620;
 END_IF;
620: (* Warten auf Bestätigung des Fahrbefehls *)
 IF eCommand = easAckTask THEN
  my_CMMx_CTRL.SetValueRotSpeed := 0; (* System anhalten *)
  my_CMMx_CTRL.StartTask := TRUE;
  tTimeout := TIME() + tDefaultTimeout;
  nStep := 630;
 END_IF;
630: (* Warten auf Bestätigung des Fahrbefehls *)
 IF my_CMMx_CTRL.AckStart THEN
  eStatus := easInMotion;
  my_CMMx_CTRL.StartTask := FALSE;
  tTimeout := TIME() + tDefaultTimeout;
  nStep := 640;
 END_IF;
640: (* Warten auf Rücksetzen der Bestätigung *)
 IF NOT my_CMMx_CTRL.AckStart THEN
  eStatus := easReadyForTask; (* Meldung "Antrieb bereit für neuen Auftrag" setzen *)
  tTimeout := tDisarmTimeout;
  nStep := 300;
 END_IF;
 
Zurück
Oben