AxisStepperEL70xx
Note
This guide is targeted towards users of the Zeugwerk Framework Addon: Equipment Beckhoff.
Stepper axes offer a good cost to value ratio for not so time-critical and not very precise positioning tasks. In the maker scene there are several common applications for steppers, e.g for 3D-printers or laser cutters. However, in industrial-automation applications, which are usually fieldbus driven (i.e. Ethercat), this gets a bit more involved.
Beckhoff's EL7031 stepper terminal seems like a good fit, but if used with NC-Motion, licensing costs can sometimes not be neglected. For simple tasks most stepper terminals are able to work without any motion or soft motion controller and they can instead be preconfigured and then commanded by I/Os (first Input = position1, second input = position2, ...). This solution lacks flexibility though.
Beckhoff's EL70xx terminal series can actually be controlled over EtherCAT without any soft-motion-controller. While in principle the terminal's documentation is enough to implement the interface to control a stepper motor through the terminal, in practice, the actual implementation is a tedious task. This is were Zeugwerk's AxisStepperEL70xx implementation comes in handy as it is a tested implementation for Beckhoff's stepper-terminal interface. This tutorial guides you through the steps that you have to take to use this implementation in your application.
The tutorial is target towards users that only use the unmanaged variant of the implementation in a context that does not use the Zeugwerk Template (AxisStepperEL70xxUM), however, all points mentioned in the tutorial apply to the managed variant as well.
Prerequisites
This tutorial requires a working runtime. This could be a runtime on an IPC, an embedded PC or a local runtime on a development PC. If you want to drive the stepper axis for real, also a working Ethercat connection is required. For simulation purposes a usermode runtime is enough and can be started on every Windows driven machine. Take a look on this tutorial for working with the usermode runtime.
For demonstration purposes we utilize a stepper axis connected to a EL7031 terminal. And use a small stepper motor with 200 full steps. The motor is mounted to a horizontal belt drive. On the negative side of the linear belt drive there is a limit switch which also acts as homing switch. The diameter of the bevel powered by the motor is 6mm which means that 1 rotation on the stepper is about 38mm on the linear belt.
Create a solution
Start Twincat XaeShell and create a new solution. After that, integrate a Standard PLC to the solution and open the MAIN program. Then add the ZCore and ZEquipmentBeckhoff libraries as references to the PLC. Lets add a Step function block out of ZCore and create some steps inside a CASE branch.
Implementation and simulation
Place the cursor under the Step variable, press F2 and select Text search on the top of the new dialogue. Now enter Stepper and select an instance of the ZEquipmentBeckhoff.AxisStepperEL7031UM FB. Be sure to have Insert with arguments and Insert with namespace prefix checked.
When working without the Zeugwerk Template, Unmanaged objects have to be used, which involves calling their cyclic behaviour manually. Make sure to call the AxisStepperEL7031UM.Cyclic() method on the very top of the MAIN.PRG, after that
- Add a variable of type BOOL, which is later used to issue a start command to the stepper
- Initialize the stepper axis with the following settings
- SetName : Name of your choice for the axis
- SetSimulation: Switch on simulation or not
- SetMotorFullsteps: Fullsteps of the Stepper motor
- SetGearRatio: mechanical gear Ratio, if attached, also needed for converting from rotational to linear movement
- SetHomingMethod: Set the desired homing method; currently OnCurrentPosition, OnPositive and NegativeLimitSwitch, and OnPositive or NegativeBlock
- SetInput1Features: choose if the homing switches should evaluated in an inverted manner
- SetInput2Features: if needed choose a featureset for input2 of stepper terminal
- SetMotorSettings: Current, voltage and coil settings
- SetPosSettings: Some limits for the trajectory calculation of the terminal
- SetStmFeatures: Sets a Speed range and motor polarity
- SetStmSettings: controller parameter, leave them in default for the first tests
- Reboot the stepper instance after initializing it, so that the changed parameters are written to the drive.
Please note that if a initialization method is not called, default values are used which are described in the comments of the methods input parameter or in the API-documentation
Then lets wait in the next step until the controller is parameterized, which is followed by homing the stepper on the negative limit switch. When done, the next step waits for some user input. We wait for a rising edge on the Start flag. To monitor what the Stepper is doing, we can use the properties ActualPosition and ActualVelocity, which we copied into two local variables.
The full declaration and implementation of the PRG is as follows.
PROGRAM MAIN
VAR
Step : ZCore.Step(begin:=0, end:=100);
Stepper : ZEquipmentBeckhoff.AxisStepperEL7031UM;
Start : BOOL := FALSE;
ActPosition, ActVelocity : LREAL;
END_VAR
Stepper.Cyclic();
ActPosition := Stepper.ActualPosition;
ActVelocity := Stepper.ActualVelocity;
CASE Step.CurrentIndex() OF
(* ------------------------------------------------------------ *)
0: // Idling
(* ------------------------------------------------------------ *)
IF Start THEN
Start := FALSE;
Step.SetNext(10);
END_IF
(* ------------------------------------------------------------ *)
10: // initialize Stepper
(* ------------------------------------------------------------ *)
IF Step.OnEntry() THEN
Stepper.SetName('Transport');
Stepper.SetSimulation(FALSE);
Stepper.Parameter.Booting.SetMotorFullsteps(LREAL_TO_UINT(360.0 / 1.8)); // 200 Full Steps
Stepper.Parameter.Booting.SetGearRatio(ratioInput:=1, ratioOutput:=1);
Stepper.Parameter.Booting.SetInput1Features(invertInput1:=FALSE,
input1Function:=ZEquipmentBeckhoff.AxisStepperEL70xxDigitalInputFunction.PlcCam);
// Stepper.Parameter.Booting.SetInput2Features(invertInput2:= , input2Function); <- if used
Stepper.Parameter.Drive.SetHomingMethod(homingMethod:=ZEquipmentBeckhoff.AxisStepperEL70xxHomingMethod.OnPositiveLimitSwitch,
distance:=100,
speedTowardsCam:=5, speedOffCam:=0.5,
offset:=150, timeout:=60);
Stepper.Parameter.Booting.SetMotorSettings(maximumCurrent:=600,
reducedCurrent:=300,
nominalVoltage:=24000,
motorCoilResistance:=64,
motorEMF:=0,
motorStartVelocity:=0,
driveOnDelayTime:=100,
driveOffDelayTime:=100);
Stepper.Parameter.Booting.SetPosSettings(velocityMax:=10,
accelerationMax:=200,
decelerationMax:=200,
decelerationEmergencyMax:=300,
calibrationVelocityToward:=1,
calibrationVelocityOff:=1,
positionWindow:=10,
monitoringWindow:=3);
Stepper.Parameter.Booting.SetStmFeatures(operationMode:=ZEquipmentBeckhoff.AxisStepperEL70xxOperationMode.PositionControl,
speedRange:=ZEquipmentBeckhoff.AxisStepperEL70xxSpeedRange.Steps2000,
invertMotorPolarity:=TRUE);
Stepper.Parameter.Booting.SetStmSettings(kp:=400,
ki:=4,
innerWindow:=0,
outerWindow:=0,
filterCutoffFrequency:=0,
ka:=100,
kd:=100);
Stepper.RebootAsync(0);
END_IF
IF Stepper.Done THEN
Step.SetNext(20);
END_IF
(* ------------------------------------------------------------ *)
20: // Start Homing
(* ------------------------------------------------------------ *)
IF Step.OnEntry() THEN
Stepper.HomingAsync(0);
END_IF
IF Stepper.Done THEN
Step.SetNext(30);
END_IF
(* ------------------------------------------------------------ *)
30: // Idling again, wait till movement should start
(* ------------------------------------------------------------ *)
IF Start THEN
Start := FALSE;
Step.SetNext(40);
END_IF
(* ------------------------------------------------------------ *)
40: // Start movement and wait till it ends
(* ------------------------------------------------------------ *)
IF Step.OnEntry() THEN
Stepper.MoveAbsoluteAsync(0, SEL(IsNullLreal(Stepper.ActualPosition, 0.1), 0, 400), 100.0);
END_IF
IF Stepper.Error THEN
Step.SetNext(99); // error occured
ELSIF NOT Stepper.Busy THEN
Step.SetNext(30); // wait till next rising edge of Start
END_IF
ELSE
;
END_CASE
Scope view
Now open a new measurement project and lets see how the stepper axis is moving. Start a new Twincat XaeShell and click on New Measurement project. Select YT Scope project and give it a proper name. On the left side in the solution explorer look for YT Chart and find the first axis, rename it to Position and create another one by Right clicking on YT Chart and then click on New Axis. Name the second axis Velocity. Now right click on YT Chart and select Properties. Look for a property entry called Stacked Axis and set this property to True. With these settings we have a better overview on the graph.
Now lets add the actual velocity and actual position to the graph. Right click on the Position axis and select Target Browser. Highlight the variables ActPosition and ActVelocity, right click on it and select Add. Last but not least move the ActVelocity variable to the second axis and then press on the Start Record button in the toolbar of the scope.
Be sure that the PLC is running in the background otherwise the Target browser will not show any variables.
Finally start the movement of the simulated stepper axis again and see how the trajectory gets calculated and simulated. With this axis a normal sequence can now be written and checked if it is working without any hardware.
Commissioning with actual hardware
To test with the real world hardware scan in the ethercat fieldbus with the EL7031 terminal. Now double click on the terminal, select the Process Data dialog and at the bottom of the dialog click on the drop down menu. Then select Positioning interface. Twincat now adapts the PDO settings for you that they are compatible with the Zeugwerk Framework implementation of the stepper terminal.
Now we have to link this terminal to the PLC. To have a better overview, start from the terminal view and expand the STM Status node. Now right click on STM Status -> Status and select Change Link Select the _implPhysical._drive._input.StmStatus variable on the stepper PLC-instance side. Do the same with
POS Status -> Statuslink to_implPhysical._drive._input.PosStatusPOS Status -> Actual Velocitylink to_implPhysical._drive._input.ActualVelocityPOS Status -> Actual Positionlink to_implPhysical._drive._input.ActualPositionSTM Control -> Controllink to_implPhysical._drive._output.StmControlPOS Control -> Controllink to_implPhysical._drive._output.PosControlPOS Control -> Target Positionlink to_implPhysical._drive._output.TargetPositionPOS Control -> Velocitylink to_implPhysical._drive._output.VelocityPOS Control -> Start typelink to_implPhysical._drive._output.StartTypePOS Control -> Accelerationlink to_implPhysical._drive._output.AccelerationPOS Control -> Decelerationlink to_implPhysical._drive._output.Deceleration
Last but not least we link the ethercat slave fieldbus variables of the stepper implementation to the actual ESC links of the terminal. This is needed to be able to parameterize the stepper terminal and observe the actual ethercat status of the hardware.
We have to link:
WcState -> WcStatelink to_ethercatSlave._impl._input.WcStateWcState -> InputTogglelink to_ethercatSlave._impl._input.InputToggleInfoData -> Statelink to_ethercatSlave._impl._input.StateInfoData -> AdsAddrlink to_ethercatSlave._impl._input.AdsAddr
Finally we have to switch off simulation by setting the Simulation:=FALSE. Activate the solution and login.
To test the movement of the stepper now online set the Start BOOL variable. In the first place the stepper makes an initialization and then starts the homing sequence. After that it waits again for a rising edge on the Start boolean.