When controlling a robot you typically use one of the interfaces from the ControlBoardInterfaces.h header file.
These are meant to abstract a great deal of details but not all of it since we want to retain the possibility of efficient and specialized motor control code.
We take an example of a motor control device since this is simpler to explain than a general controller. The approach itself is completely general though as for other device abstactions in yarp. In particular, the following is an extract of the EsdMotionControl (see EsdMotionControl.h) declaration which wraps the iCub controller:
class yarp::dev::EsdMotionControl : public DeviceDriver, public IPidControlRaw, public IPositionControlRaw, public IVelocityControlRaw, public IEncodersRaw, public IAmplifierControlRaw, public IControlDebug, public IControlLimitsRaw, public ImplementPositionControl<EsdMotionControl, IPositionControl>, public ImplementVelocityControl<EsdMotionControl, IVelocityControl>, public ImplementPidControl<EsdMotionControl, IPidControl>, public ImplementEncoders<EsdMotionControl, IEncoders>, public ImplementAmplifierControl<EsdMotionControl, IAmplifierControl>, public ImplementControlLimits<EsdMotionControl, IControlLimits>
Beside the confusion here due to the multiplicity of interfaces the important thing to notice is the standard inheritance from DeviceDriver. The controller abstraction assumes:
These features are mapped directly onto interfaces. There are "raw" interfaces that speak directly to the control cards and wrapped interfaces that convert and rescale the values before sending them to the control cards. The wrapped interfaces accept angle in degrees, speed in degrees per seconds, etc. The numbering of the axes is also made coherent with respect to the robot kinematics.
The wrapped interfaces are implemented through an "implement" template since the code is likely to be reused in other device drivers: i.e. any control card would perform the same type of mapping. These interfaces use the corresponding "raw" version internally (ControlBoardInterfacesImpl.h).
Robot control is typically effected by:
when done:
The loading of the controller parameters can be also done from a file by using the Property class and the fromConfigFile() method. This is the preferred method since the list of parameters is fairly large.
For the EsdMotionControl , for example, you find:
[CAN] CanAddresses 14 13 12 128 128 128 128 128 128 128 128 128 128 128 128 128 CanDeviceNum 0 CanMyAddress 0 CanPollingInterval 2 CanTimeout 20 [GENERAL] Joints 6 MaxDAC 100.0 100.0 100.0 100.0 100.0 100.0 AxisMap 0 1 2 3 4 5 Encoder 375.46 375.46 1399.46 1399.46 1399.46 1399.46 Zeros 0.0 0.0 0.0 0.0 0.0 0.0 Verbose 0 [LIMITS] Max 31.9 31.9 30.0 50.0 80.0 45.0 Min -29.29 -29.9 -30.0 -50.0 -80.0 -10.0 Currents 1220.0 1220.0 1220.0 1220.0 1220.0 1220.0 [PIDS] Pid0 32 128 2 1333 1333 4 0 Pid1 32 128 2 1333 1333 4 0 Pid2 32 128 2 1333 1333 4 0 Pid3 32 128 2 1333 1333 4 0 Pid4 32 128 4 1333 1333 4 0 Pid5 32 128 1 1333 1333 4 0
Some of them are specific to the control card, other are a bit more general. After loading the parameters and opening the device, perhaps through the PolyDriver, you need to:
All these operations are performed through the wrapped interfaces. The "raw" interfaces are not normally used (they are used internally though). Once you are all set with this part, you can then start moving your axes by issuing commands through the:
methods. They come in two flavors, one for single joints and another to move all joints simultaneously. The accuracy of the movement is clearly control card and robot dependent. They assume also that you set the reference speeds and accelerations appropriately.
To finish working with a motion control device, be gentle and reverse the settings you changed (some of them might stay resident in the controller memory). As a last operation before close(), disable the amplifiers so that it becomes safe again to move the robot.