Motion system, position & kinematics
Read the robot position as a robtarget or a jointtarget, jog the robot, compute forward and inverse kinematics, and manage mechanical units and calibration.
robot.Rws.MotionSystem covers everything about how the robot stands and how it moves: the mechanical units of the system and their axes, where the tool currently is, jogging, the kinematics calculations, the collision supervision and the calibration.
This is the service that moves a real robot. Reading is always safe. Writing needs the mastership of the Motion domain, and most of the time also a controller in manual mode with the motors on, which is read and changed through the control panel.
Geometry types
The positions of the SDK are built from a few small classes of the UnderAutomation.ABB.Common namespace. They are the same types everywhere, so a position read here can be written into a RAPID variable without conversion.
| Type | Holds |
|---|---|
Position | X, Y, Z |
Quaternion | Q1 to Q4, an orientation as a unit quaternion |
Pose | a Position plus an Orientation |
RobotConfiguration | Quarter1, Quarter4, Quarter6 and QuarterX, which say in which turn the axes sit |
RobotJoints | Axis1 to Axis6, the six axes of the arm |
ExternalJoints | AxisA to AxisF, the six external axes |
RobTarget | a Pose plus a Configuration and the ExternalAxes |
JointTarget | RobotAxes plus ExternalAxes |
A pose alone does not say how the robot reaches it. The same point in space is usually reachable in several ways, and RobotConfiguration is what tells them apart.
An external axis the system does not use is reported with a large value instead of a real one. Compare it with the constant ExternalJoints.NotInUse rather than with zero.
Units are not the same everywhere, and this is the convention of the controller, not a choice of the SDK:
| Where | Units |
|---|---|
| Positions, axis poses and base frames | millimetres, and degrees for the joints |
| The four kinematics calculations | metres and radians |
public class Position {// Initializes a new position at the originpublic Position()// Initializes a new positionpublic Position(double x, double y, double z)// Returns a string representation of this positionpublic override string ToString()// Coordinate along the X axispublic double X { get; set; }// Coordinate along the Y axispublic double Y { get; set; }// Coordinate along the Z axispublic double Z { get; set; }}
public class Quaternion {// Initializes a new quaternion with no rotation at all (1, 0, 0, 0)public Quaternion()// Initializes a new quaternionpublic Quaternion(double q1, double q2, double q3, double q4)// Real component of the quaternionpublic double Q1 { get; set; }// First imaginary component of the quaternionpublic double Q2 { get; set; }// Second imaginary component of the quaternionpublic double Q3 { get; set; }// Third imaginary component of the quaternionpublic double Q4 { get; set; }// Returns a string representation of this orientationpublic override string ToString()}
public class Pose : Position {// Initializes a new pose at the origin, with no rotationpublic Pose()// Initializes a new posepublic Pose(double x, double y, double z, double q1, double q2, double q3, double q4)// Initializes a new posepublic Pose(double x, double y, double z, Quaternion orientation)// Orientation held at this position. Never null: a pose built without one carries the identity rotation.public Quaternion Orientation { get; set; }// Returns a string representation of this posepublic override string ToString()}
public class RobotConfiguration {// Initializes a new configuration with every quarter revolution set to zeropublic RobotConfiguration()// Initializes a new configurationpublic RobotConfiguration(int quarter1, int quarter4, int quarter6, int quarterX)// Quarter revolution axis 1 sits inpublic int Quarter1 { get; set; }// Quarter revolution axis 4 sits inpublic int Quarter4 { get; set; }// Quarter revolution axis 6 sits inpublic int Quarter6 { get; set; }// Index of the arm configuration, which tells the remaining joint combinations apartpublic int QuarterX { get; set; }// Returns a string representation of this configurationpublic override string ToString()}
public class RobotJoints {// Initializes the six axes to zeropublic RobotJoints()// Initializes the six axespublic RobotJoints(double axis1, double axis2, double axis3, double axis4, double axis5, double axis6)// Value of axis 1public double Axis1 { get; set; }// Value of axis 2public double Axis2 { get; set; }// Value of axis 3public double Axis3 { get; set; }// Value of axis 4public double Axis4 { get; set; }// Value of axis 5public double Axis5 { get; set; }// Value of axis 6public double Axis6 { get; set; }// Returns a string representation of these joint valuespublic override string ToString()}
public class ExternalJoints {// Initializes the six external axes to zeropublic ExternalJoints()// Initializes the six external axespublic ExternalJoints(double axisA, double axisB, double axisC, double axisD, double axisE, double axisF)// Value of external axis Apublic double AxisA { get; set; }// Value of external axis Bpublic double AxisB { get; set; }// Value of external axis Cpublic double AxisC { get; set; }// Value of external axis Dpublic double AxisD { get; set; }// Value of external axis Epublic double AxisE { get; set; }// Value of external axis Fpublic double AxisF { get; set; }// Value the controller reports for an external axis that is not in usepublic const double NotInUse = 9000000000// Returns a string representation of these external axis valuespublic override string ToString()}
public class RobTarget : Pose {// Initializes a new target at the origin, with no rotationpublic RobTarget()// Initializes a new targetpublic RobTarget(double x, double y, double z, Quaternion orientation, RobotConfiguration configuration, ExternalJoints externalAxes)// Axis configuration used to reach the pose. Never null.public RobotConfiguration Configuration { get; set; }// Values of the six external axes, null when the reading does not report thempublic ExternalJoints ExternalAxes { get; set; }// Returns a string representation of this targetpublic override string ToString()}
public class JointTarget {// Initializes a new joint target with every axis at zeropublic JointTarget()// Initializes a new joint targetpublic JointTarget(RobotJoints robotAxes, ExternalJoints externalAxes)// Values of the six external axes. Never null.public ExternalJoints ExternalAxes { get; set; }// Values of the six axes of the robot arm. Never null.public RobotJoints RobotAxes { get; set; }// Returns a string representation of this joint targetpublic override string ToString()}
Mechanical units
A mechanical unit is anything the controller drives: the robot arm itself, a track, a positioner. GetMechanicalUnits lists them, GetMechanicalUnit describes one of them, and SetMechanicalUnit changes its properties.
// Every mechanical unit of the system, with its activation stateforeach (MechanicalUnitItem unit in robot.Rws.MotionSystem.GetMechanicalUnits()){Console.WriteLine($"{unit.Name} : {unit.Mode}, drive module {unit.DriveModule}");}// Everything the controller knows about one unitMechanicalUnitInfo info = robot.Rws.MotionSystem.GetMechanicalUnit("ROB_1");Console.WriteLine($"{info.Type}, task {info.TaskName}, status {info.Status}");Console.WriteLine($"tool {info.ToolName}, work object {info.WorkObjectName}, payload {info.PayloadName}");Console.WriteLine($"{info.Axes} axes, jog mode {info.JogMode}, frame {info.CoordinateSystem}");// Axis by axis. Axes are numbered from 1.int axisCount = robot.Rws.MotionSystem.GetAxisCount("ROB_1");for (int axis = 1; axis <= axisCount; axis++){AxisInfo axisInfo = robot.Rws.MotionSystem.GetAxis("ROB_1", axis);Pose axisPose = robot.Rws.MotionSystem.GetAxisPose("ROB_1", axis);Console.WriteLine($"axis {axisInfo.Number} : {axisInfo.Status}, at {axisPose}");}// Where the base of the unit stands, in millimetresBaseFrame baseFrame = robot.Rws.MotionSystem.GetBaseFrame("ROB_1");Console.WriteLine($"base frame {baseFrame}, type {baseFrame.Type}");// Changing a property of a unit needs the mastership of the motion domain.// Give only the properties you want to change, leave the others null.robot.Rws.Mastership.Request(MastershipDomain.Motion);try{robot.Rws.MotionSystem.SetMechanicalUnit("ROB_1",tool: "tGripper",jogMode: JogMode.Cartesian,coordinateSystem: CoordinateSystem.Base);}finally{robot.Rws.Mastership.Release();}// The controller answers success even when it could not apply one of the properties.// Read the unit back to see what it really did.Console.WriteLine(robot.Rws.MotionSystem.GetMechanicalUnit("ROB_1").ToolName);
MechanicalUnitInfo.Status says whether the unit can move at all:
MechanicalUnitStatus | Meaning |
|---|---|
Synchronized | Calibrated and synchronized, the unit can be moved |
NotCommutated | One or several motors have not been commutated |
NotCalibrated | The unit has never been calibrated |
NotAbsoluteSynchronized, NotRelativeSynchronized | The measurement of one or several axes is not synchronized |
Locked, LockedShow | The unit is locked and refuses to move |
Initiated, Undefined, Unknown | The unit is starting up, or the controller does not report its state |
SetMechanicalUnit needs the mastership of the Motion domain. Give only the properties you want to change and leave the others null. The controller answers with a success status even when it could not apply one of them, so read the unit back to see what it really did.
SetBaseFrame and SetAxisPose declare where a unit or an axis sits in the cell. They do not move anything, they change the calibration of the cell, and the user account needs the matching UAS grant. The controller takes the request and applies the frame afterwards, so a success means the request was accepted, not that the new frame is already in use.
// Gets the state of one axis of a mechanical unit (synchronous)AxisInfo GetAxis(string mechanicalUnit, int axis);// Gets how many axes a mechanical unit has (synchronous)int GetAxisCount(string mechanicalUnit);// Gets where one axis of a mechanical unit sits (synchronous) The position is expressed in millimetres.Pose GetAxisPose(string mechanicalUnit, int axis);// Gets where the base of a mechanical unit sits (synchronous) The position is expressed in millimetres.BaseFrame GetBaseFrame(string mechanicalUnit);// Gets everything the controller knows about one mechanical unit (synchronous)MechanicalUnitInfo GetMechanicalUnit(string mechanicalUnit);// Lists the mechanical units of the motion system (synchronous)MechanicalUnitItem[] GetMechanicalUnits();// Declares where one axis of a mechanical unit sits (synchronous) The position is expressed in millimetres.void SetAxisPose(string mechanicalUnit, int axis, Pose pose);// Declares where the base of a mechanical unit sits (synchronous) The position is expressed in millimetres.void SetBaseFrame(string mechanicalUnit, Pose baseFrame);// Changes one or several properties of a mechanical unit (synchronous) Every argument but the unit name is optional; leave the ones you do not want to touch null. At least one of them has to be given.void SetMechanicalUnit(string mechanicalUnit, string tool = null, string workObject = null, string payload = null, string totalPayload = null, MechanicalUnitMode? mode = null, JogMode? jogMode = null, CoordinateSystem? coordinateSystem = null);// Places a mechanical unit at the given joint values without moving it there (synchronous) Only a virtual controller accepts this: it teleports the simulated robot, which a real one cannot do.void SetMechanicalUnitPosition(string mechanicalUnit, JointTarget position);
Every method also exists in an asynchronous version, with the same name followed by Async and an optional CancellationToken.
public class MechanicalUnitItem {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.MechanicalUnitItem" data-throw-if-not-resolved="false"></xref> classpublic MechanicalUnitItem()// Whether the unit can be activated, null when the controller did not report itpublic bool? ActivationAllowed { get; set; }// Number of the drive module the unit is connected to, null when the controller did not report itpublic int? DriveModule { get; set; }// Whether the unit is activatedpublic MechanicalUnitMode Mode { get; set; }// Name of the mechanical unit, for example "ROB_1"public string Name { get; set; }// Returns a string representation of this mechanical unitpublic override string ToString()}
public class MechanicalUnitInfo {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.MechanicalUnitInfo" data-throw-if-not-resolved="false"></xref> classpublic MechanicalUnitInfo()// Number of axes of the unit, null when the controller did not report itpublic int? Axes { get; set; }// Reference frame the cartesian positions of the unit are expressed inpublic CoordinateSystem CoordinateSystem { get; set; }// Name of the mechanical unit integrated into this one. A unit that integrates no other one is// reported with a placeholder name rather than an empty value.public string HasIntegratedUnit { get; set; }// Name of the mechanical unit this one is integrated into. A unit that is integrated into no other// one is reported with a placeholder name rather than an empty value.public string IsIntegratedUnit { get; set; }// How the jogging commands sent to the unit are interpretedpublic JogMode JogMode { get; set; }// Whether the unit is activatedpublic MechanicalUnitMode Mode { get; set; }// Name of the mechanical unit, for example "ROB_1"public string Name { get; set; }// Name of the active payloadpublic string PayloadName { get; set; }// Calibration and synchronization state of the unitpublic MechanicalUnitStatus Status { get; set; }// Name of the RAPID task that drives the unitpublic string TaskName { get; set; }// Returns a string representation of this mechanical unitpublic override string ToString()// Name of the active toolpublic string ToolName { get; set; }// Number of axes of the unit and of the units integrated with it,// null when the controller did not report itpublic int? TotalAxes { get; set; }// Name of the active total payload, which is the payload plus the load of the toolpublic string TotalPayloadName { get; set; }// Kind of mechanical unitpublic MechanicalUnitType Type { get; set; }// Name of the active work objectpublic string WorkObjectName { get; set; }}
public enum MechanicalUnitMode {// The mechanical unit is activated and takes part in the motionActivated = 1// The mechanical unit is deactivated and stays where it isDeactivated = 2// The controller reported a mode this library does not knowUnknown = 0}
public enum MechanicalUnitType {// No mechanical unitNone = 1// A robot arm without a tool center point, which can only be moved axis by axisRobot = 3// A single external axis, such as a track or a positionerSingle = 4// A robot arm holding a tool center point, which can be moved in cartesian coordinatesTcpRobot = 2// The controller knows the unit but does not report what it isUndefined = 5// The controller reported a type this library does not knowUnknown = 0}
public enum MechanicalUnitStatus {// The unit is starting upInitiated = 1// The unit is locked and refuses to moveLocked = 7// The unit is locked, and the controller shows it as suchLockedShow = 8// One or several absolute measurement axes are not synchronizedNotAbsoluteSynchronized = 4// The unit has never been calibratedNotCalibrated = 3// One or several motors have not been commutatedNotCommutated = 2// One or several relative measurement axes are not synchronizedNotRelativeSynchronized = 5// The unit is calibrated and synchronized, and can be movedSynchronized = 6// The controller knows the unit but does not report its stateUndefined = 9// The controller reported a state this library does not knowUnknown = 0}
public class AxisInfo {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.AxisInfo" data-throw-if-not-resolved="false"></xref> classpublic AxisInfo()// Logical joint number of the axis, null when the controller did not report itpublic int? LogicalAxis { get; set; }// Number of the axis inside its mechanical unit, starting at 1public int Number { get; set; }// Calibration and synchronization state of the axispublic MechanicalUnitStatus Status { get; set; }// Returns a string representation of this axispublic override string ToString()}
public class BaseFrame : Pose {// Initializes a new base frame at the origin, with no rotationpublic BaseFrame()// Returns a string representation of this base framepublic override string ToString()// Kind of base frame the controller reports, for example "IRBRobot"public string Type { get; set; }}
public enum CoordinateSystem {// The base frame of the mechanical unitBase = 2// The frame of the active toolTool = 3// The controller reported a frame this library does not knowUnknown = 0// The frame of the active work objectWorkObject = 4// The world frame, shared by every mechanical unit of the systemWorld = 1}
public enum JogMode {// The tool is aligned with the closest axis of the active coordinate systemAlign = 4// Each command moves one axis of the first axis groupAxisGroup1 = 1// Each command moves one axis of the second axis groupAxisGroup2 = 2// The tool is moved along the axes of the active coordinate systemCartesian = 3// The robot changes axis configuration without moving the tool center pointConfigurationJog = 6// The robot moves to a given positionGoToPosition = 5// The controller reported a mode this library does not knowUnknown = 0}
Read the robot position
Four readings answer the same question in four ways. All of them are read only and need no mastership.
| Method | Returns |
|---|---|
GetRobTarget(unit) | RobTarget, the Cartesian position with the axis configuration and the external axes |
GetCartesianPosition(unit) | RobTarget without the external axes, ExternalAxes is then null |
GetJointTarget(unit) | JointTarget, the joint values |
GetPhysicalJoints(unit) | RobotJoints, the raw values of the measurement system of the unit |
// Where the tool is, in millimetres, with the axis configuration and the external axesRobTarget target = robot.Rws.MotionSystem.GetRobTarget("ROB_1");Console.WriteLine($"X={target.X} Y={target.Y} Z={target.Z}");Console.WriteLine($"orientation {target.Orientation}");Console.WriteLine($"configuration {target.Configuration}");Console.WriteLine($"external axes {target.ExternalAxes}");// The same reading in another frame, with a given tool and work objectRobTarget inWorld = robot.Rws.MotionSystem.GetRobTarget("ROB_1", CoordinateSystem.World,tool: "tGripper", workObject: "wobj0");Console.WriteLine(inWorld);// The joint values, robot axes in degreesJointTarget joints = robot.Rws.MotionSystem.GetJointTarget("ROB_1");Console.WriteLine($"axis 1 = {joints.RobotAxes.Axis1} deg");Console.WriteLine($"axis 2 = {joints.RobotAxes.Axis2} deg");// An external axis the system does not define comes back as ExternalJoints.NotInUseif (joints.ExternalAxes.AxisA != ExternalJoints.NotInUse){Console.WriteLine($"external axis A = {joints.ExternalAxes.AxisA}");}// alwaysRead asks the controller to measure again instead of answering with the value it holdsJointTarget measured = robot.Rws.MotionSystem.GetJointTarget("ROB_1", alwaysRead: true);Console.WriteLine(measured);// Cartesian position without the external axes. ExternalAxes is null here.RobTarget cartesian = robot.Rws.MotionSystem.GetCartesianPosition("ROB_1");Console.WriteLine(cartesian);// The raw values of the measurement system of the unitRobotJoints physical = robot.Rws.MotionSystem.GetPhysicalJoints("ROB_1");Console.WriteLine(physical);// The same two positions seen from a RAPID task instead of a mechanical unitRobTarget taskTarget = robot.Rws.Rapid.GetRobTarget("T_ROB1");JointTarget taskJoints = robot.Rws.Rapid.GetJointTarget("T_ROB1");// Which external joints of the task carry a real valueRapidExternalJointStates states = robot.Rws.Rapid.GetExternalJointStates("T_ROB1");Console.WriteLine($"external joint 1 : {states.Joint1}");// The units the task can moveforeach (RapidMechanicalUnitItem unit in robot.Rws.Rapid.GetMechanicalUnits("T_ROB1")){Console.WriteLine($"{unit.Name} : {unit.Type}, {unit.Mode}");}
GetRobTarget takes a CoordinateSystem, a tool and a work object. Without them it answers in the base frame of the unit, with the tool and the work object currently active on it. Passing a tool that does not exist is refused by the controller.
GetJointTarget has an alwaysRead parameter. By default the controller answers with the value it already holds. With alwaysRead: true it measures the position again, which costs more and is what you want when the robot has just moved.
// Gets where the tool of a mechanical unit currently is, without the external axes (synchronous) The position is expressed in millimetres.RobTarget GetCartesianPosition(string mechanicalUnit, CoordinateSystem coordinateSystem = CoordinateSystem.Base, string tool = null, string workObject = null, bool logErrors = false);// Gets the joint values a mechanical unit currently stands at (synchronous) The robot axes are expressed in degrees.JointTarget GetJointTarget(string mechanicalUnit, bool alwaysRead = false);// Gets the physical joint values of a mechanical unit, as its measurement system reads them (synchronous)RobotJoints GetPhysicalJoints(string mechanicalUnit);// Gets where the tool of a mechanical unit currently is (synchronous) The position is expressed in millimetres.RobTarget GetRobTarget(string mechanicalUnit, CoordinateSystem coordinateSystem = CoordinateSystem.Base, string tool = null, string workObject = null);
Every method also exists in an asynchronous version, with the same name followed by Async and an optional CancellationToken.
Position of a RAPID task
The same two positions can also be read from a RAPID task instead of a mechanical unit. Those methods are on robot.Rws.Rapid, and the last block of the snippet above shows them.
| Method | Returns |
|---|---|
robot.Rws.Rapid.GetRobTarget(task) | RobTarget of the robot of that task |
robot.Rws.Rapid.GetJointTarget(task) | JointTarget of the robot of that task |
robot.Rws.Rapid.GetExternalJointStates(task) | What each external joint of the task is doing |
robot.Rws.Rapid.GetMechanicalUnits(task) | The units the positions of the task are expressed in |
Which one to use:
- Read from the motion system when you work with a mechanical unit by name, when you need another coordinate system, another tool or another work object, or when you want the raw measurement.
- Read from the RAPID task when your code already works with tasks, or when you want the position exactly as the running program sees it.
GetExternalJointStates is what says how to read the external axis values of the task: a joint can be linear, rotating, inactive, or active without a position. A RobTarget read from a task reports an inactive external axis with the same large value as ExternalJoints.NotInUse.
// Gets what each of the six external joints of a task is doing (synchronous) This is what says how to read the corresponding value of GetJointTarget(System.String): a joint reported as not active carries no meaningful position.RapidExternalJointStates GetExternalJointStates(string task);// Gets the joint values of the robot of a task (synchronous)JointTarget GetJointTarget(string task);// Gets the mechanical units the positions of a task are expressed in (synchronous)RapidMechanicalUnitItem[] GetMechanicalUnits(string task);// Gets where the tool of a task currently stands, as a position and an orientation (synchronous)RobTarget GetRobTarget(string task, string tool = null, string workObject = null);
Every method also exists in an asynchronous version, with the same name followed by Async and an optional CancellationToken.
public class RapidExternalJointStates {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidExternalJointStates" data-throw-if-not-resolved="false"></xref> classpublic RapidExternalJointStates()// State of the first external jointpublic RapidJointState Joint1 { get; set; }// State of the second external jointpublic RapidJointState Joint2 { get; set; }// State of the third external jointpublic RapidJointState Joint3 { get; set; }// State of the fourth external jointpublic RapidJointState Joint4 { get; set; }// State of the fifth external jointpublic RapidJointState Joint5 { get; set; }// State of the sixth external jointpublic RapidJointState Joint6 { get; set; }// Returns a string representation of these joint statespublic override string ToString()}
public enum RapidJointState {// The joint moves along a lineLinear = 1// The joint is active but has no positionNoPosition = 4// The joint is not activeNotActive = 3// The joint turnsRotating = 2// The controller reported a state this library does not knowUnknown = 0}
public class RapidMechanicalUnitItem {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.RapidMechanicalUnitItem" data-throw-if-not-resolved="false"></xref> classpublic RapidMechanicalUnitItem()// Whether the unit is activatedpublic MechanicalUnitMode Mode { get; set; }// Name of the unit, for example "ROB_1"public string Name { get; set; }// Returns a string representation of this unitpublic override string ToString()// Kind of unitpublic MechanicalUnitType Type { get; set; }}
Move to a target
SetPositionTarget sends the robot to a Cartesian target. It really moves the arm. The preconditions are the same as for jogging: the controller in manual mode, the motors on, this client as the local client of the controller, and the mastership of the Motion domain.
SetMechanicalUnitPosition does not move anything. It places the unit at the given joint values. Only a virtual controller accepts it, a real one refuses the call.
// SetPositionTarget really moves the robot to a cartesian target.// Same preconditions as jogging: manual mode, motors on, local client, motion mastership.RobTarget target = robot.Rws.MotionSystem.GetRobTarget("ROB_1");target.Z += 10; // 10 mm uprobot.Rws.Mastership.Request(MastershipDomain.Motion);try{robot.Rws.MotionSystem.SetPositionTarget(target);}finally{robot.Rws.Mastership.Release();}// SetMechanicalUnitPosition does not move anything: it places the unit at the given joint// values. Only a virtual controller accepts it, a real one refuses the call.JointTarget joints = new JointTarget(new RobotJoints(0, 0, 0, 0, 30, 0), new ExternalJoints());robot.Rws.Mastership.Request(MastershipDomain.Motion);try{robot.Rws.MotionSystem.SetMechanicalUnitPosition("ROB_1", joints);}finally{robot.Rws.Mastership.Release();}
// Places a mechanical unit at the given joint values without moving it there (synchronous) Only a virtual controller accepts this: it teleports the simulated robot, which a real one cannot do.void SetMechanicalUnitPosition(string mechanicalUnit, JointTarget position);// Sends the robot to a cartesian target (synchronous) The position is expressed in millimetres, in the coordinate system currently active for the mechanical unit selected for jogging.void SetPositionTarget(RobTarget target);
Every method also exists in an asynchronous version, with the same name followed by Async and an optional CancellationToken.
Jog the robot
Jogging moves the robot step by step, the way the operator does from the FlexPendant. Four conditions have to be met, and none of them can be arranged by a request:
- The controller is in manual mode. In automatic mode the request is refused with the HTTP status code 403.
- The motors are on.
- This client is the local client of the controller.
- This connection holds the mastership of the
Motiondomain.
// Check the preconditions before asking the robot to moveOperationMode mode = robot.Rws.Panel.GetOperationMode();ControllerState state = robot.Rws.Panel.GetControllerState();if (mode == OperationMode.Automatic || state != ControllerState.MotorsOn){Console.WriteLine("Jogging is refused in this state");return;}robot.Rws.Mastership.Request(MastershipDomain.Motion);try{// Which unit the jogging commands apply torobot.Rws.MotionSystem.SetJoggingMechanicalUnit("ROB_1");// How the six values are read depends on the jog mode of that unitrobot.Rws.MotionSystem.SetMechanicalUnit("ROB_1", jogMode: JogMode.AxisGroup1);// The change count of the last reading. The controller refuses a command// built on a state that has moved on since.MotionSystemInfo info = robot.Rws.MotionSystem.GetInfo();// One small step on axis 1, nothing on the other fiveRobotJoints step = new RobotJoints(100, 0, 0, 0, 0, 0);robot.Rws.MotionSystem.Jog(step, info.ChangeCount.Value, JogIncrementMode.Small);}finally{robot.Rws.Mastership.Release();}// With JogIncrementMode.None the robot moves for as long as the command is repeated,// so the loop itself is what stops the motion.MotionSystemInfo current = robot.Rws.MotionSystem.GetInfo();RobotJoints speed = new RobotJoints(50, 0, 0, 0, 0, 0);for (int i = 0; i < 20; i++){robot.Rws.MotionSystem.Jog(speed, current.ChangeCount.Value, JogIncrementMode.None);System.Threading.Thread.Sleep(100);}// Some jogging requests are accepted by the controller and still not honoured.// The error state says what went wrong.MotionSystemErrorState error = robot.Rws.MotionSystem.GetErrorState();Console.WriteLine($"{error.State}, {error.Count} error(s)");
SetJoggingMechanicalUnit chooses which unit the following jogging commands apply to. Jog then sends six values. How they are read depends on the jog mode of that unit, which SetMechanicalUnit sets:
JogMode | The six values are |
|---|---|
AxisGroup1, AxisGroup2 | One value per axis of the group |
Cartesian | A motion of the tool along the axes of the active coordinate system |
Align | An alignment of the tool with the closest axis of the active coordinate system |
GoToPosition | A position to move to |
ConfigurationJog | A change of axis configuration that does not move the tool center point |
Jog also takes the change count of the last reading of the motion system. The controller refuses a command built on a state that has moved on since, so read GetInfo().ChangeCount before jogging.
JogIncrementMode | Effect |
|---|---|
None | The robot moves for as long as the command is repeated. The loop is what stops the motion. |
User | One step of the size configured in the system parameters |
Small, Medium, Large | One step of the corresponding size |
A jogging request can be accepted by the controller and still not honoured. GetErrorState then says why, see the last section of this page.
// Moves the mechanical unit currently selected for jogging (synchronous) The unit is the one SetJoggingMechanicalUnit(System.String) chose, and how the six values are interpreted depends on its jog mode: axis by axis, along the axes of a coordinate system, and so on.void Jog(RobotJoints axes, int changeCount, JogIncrementMode incrementMode = JogIncrementMode.None);// Chooses which mechanical unit the jogging commands apply to (synchronous)void SetJoggingMechanicalUnit(string mechanicalUnit);
Every method also exists in an asynchronous version, with the same name followed by Async and an optional CancellationToken.
public enum JogIncrementMode {// One large stepLarge = 4// One medium stepMedium = 3// The robot moves for as long as the command is repeated, with no fixed stepNone = 0// One small stepSmall = 2// One step of the size configured in the system parametersUser = 1}
Kinematics
The controller can compute where the tool would be for a set of joint values, and which joint values put the tool at a given pose. Nothing moves, and no mastership is needed.
These four calculations work in metres and radians, unlike every other reading of the service. The values are passed and returned in the same classes, only the unit changes.
// These four calculations work in metres and radians, not in millimetres and degrees.// Tool relative to the mounting flange. Here the flange itself, with no rotation.Pose toolFrame = new Pose(0, 0, 0, new Quaternion(1, 0, 0, 0));// Forward kinematics: where the tool would be for these joint valuesJointTarget joints = new JointTarget(new RobotJoints(0, 0, 0, 0, 0.5, 0), new ExternalJoints());RobTarget pose = robot.Rws.MotionSystem.GetPoseFromJoints("ROB_1", toolFrame, joints);Console.WriteLine($"tool at {pose.X} {pose.Y} {pose.Z} metres, configuration {pose.Configuration}");// Inverse kinematics: which joint values put the tool at that pose.// previousJoints decides between the solutions the pose admits.JointTarget solution = robot.Rws.MotionSystem.GetJointsFromPose("ROB_1", pose, new ExternalJoints(),toolFrame, joints, pose.Configuration);Console.WriteLine($"axis 5 = {solution.RobotAxes.Axis5} rad");// The controller has a second calculation for the same question. It does not always// pick the same solution.JointTarget other = robot.Rws.MotionSystem.GetJointsFromCartesian("ROB_1", pose, new ExternalJoints(),toolFrame, joints, pose.Configuration);Console.WriteLine(other);// Every way of reaching the pose. A six axis robot usually has eight.JointSolution[] solutions = robot.Rws.MotionSystem.GetAllJointSolutions("ROB_1", pose, new ExternalJoints(),toolFrame, pose.Configuration);foreach (JointSolution s in solutions){Console.WriteLine($"{s.Configuration} : {s.RobotAxes}");}
| Method | Answers |
|---|---|
GetPoseFromJoints | Forward kinematics: the pose for these joint values |
GetJointsFromPose | Inverse kinematics: the joint values for this pose |
GetJointsFromCartesian | The same question, through a second calculation of the controller |
GetAllJointSolutions | Every joint combination that reaches the pose, one per axis configuration |
GetJointsFromPose and GetJointsFromCartesian take the same arguments and do not always return the same solution. Both are exposed because a controller can accept one and refuse the other. Compare the pose they reach rather than the joint values themselves.
previousJoints is what decides between the solutions a pose admits. Pass the joint values the robot is currently in, so the answer is the closest one.
Set robotHoldsWorkObject to true when the tool is fixed in the cell and the robot carries the work object. Set logErrors to true to have the controller write an event log message when the calculation fails.
A pose that cannot be reached is refused by the controller and reported as an RwsException.
// Asks the controller for every joint combination that puts the tool at the given pose (synchronous) A six axis robot usually reaches the same pose in eight different ways, each one in a different axis configuration.JointSolution[] GetAllJointSolutions(string mechanicalUnit, Pose pose, ExternalJoints externalAxes, Pose toolFrame, RobotConfiguration configuration, bool robotHoldsWorkObject = false);// Asks the controller which joint values put the tool at the given pose, staying close to the joint values the robot is already in (synchronous)JointTarget GetJointsFromCartesian(string mechanicalUnit, Pose pose, ExternalJoints externalAxes, Pose toolFrame, JointTarget previousJoints, RobotConfiguration configuration, bool robotHoldsWorkObject = false, bool logErrors = false);// Asks the controller which joint values put the tool at the given pose (synchronous)JointTarget GetJointsFromPose(string mechanicalUnit, Pose pose, ExternalJoints externalAxes, Pose toolFrame, JointTarget previousJoints, RobotConfiguration configuration, bool robotHoldsWorkObject = false, bool logErrors = false);// Asks the controller where the tool would be if the robot stood at the given joint values, without moving it there (synchronous)RobTarget GetPoseFromJoints(string mechanicalUnit, Pose toolFrame, JointTarget joints, bool robotHoldsWorkObject = false, bool logErrors = false);
Every method also exists in an asynchronous version, with the same name followed by Async and an optional CancellationToken.
public class JointSolution : JointTarget {// Initializes a new solution with every axis at zeropublic JointSolution()// Axis configuration this solution corresponds to. Never null.public RobotConfiguration Configuration { get; set; }// Returns a string representation of this solutionpublic override string ToString()}
Collision supervision
The controller watches the torque of the axes and stops the robot when it meets an unexpected resistance. There is one setting for jogging and one for a programmed path, per mechanical unit.
// Collision detection while the unit is joggedMotionSupervision jogging = robot.Rws.MotionSystem.GetMotionSupervision("ROB_1");Console.WriteLine($"jogging supervision {jogging.Enabled}, sensitivity {jogging.Level} %");// Collision detection while the unit follows a programmed pathPathSupervision path = robot.Rws.MotionSystem.GetPathSupervision("ROB_1");Console.WriteLine($"path supervision {path.Enabled}, sensitivity {path.Level} %");// Writing these four values needs the mastership of the motion domain.// The lower the percentage, the sooner the controller reports a collision.robot.Rws.Mastership.Request(MastershipDomain.Motion);try{robot.Rws.MotionSystem.SetMotionSupervisionMode("ROB_1", true);robot.Rws.MotionSystem.SetMotionSupervisionLevel("ROB_1", 80);robot.Rws.MotionSystem.SetPathSupervisionMode("ROB_1", true);robot.Rws.MotionSystem.SetPathSupervisionLevel("ROB_1", 80);}finally{robot.Rws.Mastership.Release();}// Collision prediction stops the robot before it hits something the controller// knows about. It is a separate setting, and it needs no mastership.bool predicting = robot.Rws.MotionSystem.GetCollisionPredictionMode();if (!predicting){// Refused when the collision detection option is not installed.// The error message then names the missing option.robot.Rws.MotionSystem.SetCollisionPredictionMode(true);}
| Setting | Applies while |
|---|---|
MotionSupervision | The unit is jogged |
PathSupervision | The unit follows a programmed path |
The level is a percentage. The lower the value, the sooner the controller reports a collision. The four write methods need the mastership of the Motion domain.
Collision prediction is a different feature: it stops the robot before it hits something the controller already knows about, where the supervision only reacts once the arm meets a resistance. GetCollisionPredictionMode and SetCollisionPredictionMode need no mastership.
All of this belongs to the Collision Detection option. On a controller built without it, switching the feature on is refused with the HTTP status code 403 and the SDK reports an error naming the missing option. Writing back the value the controller already holds is accepted.
SetNonMotionExecutionMode is nearby but different: it runs the RAPID program while skipping every motion instruction, which is how a program is tested without the robot leaving its position. It belongs to the editing domain, not to the motion one, so take every domain before calling it.
// Tells whether the controller predicts collisions before they happen (synchronous) Collision prediction stops the robot before it hits something it knows about, where the motion supervision only reacts once the arm meets an unexpected resistance.bool GetCollisionPredictionMode();// Gets the collision detection settings that apply while a mechanical unit is jogged (synchronous)MotionSupervision GetMotionSupervision(string mechanicalUnit);// Tells whether the controller runs RAPID programs without moving the robot (synchronous) In that mode the program executes normally but every motion instruction is skipped, which is how a program is tested without the robot leaving its position.bool GetNonMotionExecutionMode();// Gets the collision detection settings that apply while a mechanical unit follows a programmed path (synchronous)PathSupervision GetPathSupervision(string mechanicalUnit);// Switches collision prediction on or off (synchronous)void SetCollisionPredictionMode(bool enabled);// Sets how sensitive the jogging collision detection of a mechanical unit is (synchronous)void SetMotionSupervisionLevel(string mechanicalUnit, int sensitivity);// Switches the jogging collision detection of a mechanical unit on or off (synchronous)void SetMotionSupervisionMode(string mechanicalUnit, bool enabled);// Chooses whether the controller runs RAPID programs without moving the robot (synchronous)void SetNonMotionExecutionMode(bool enabled);// Sets how sensitive the path collision detection of a mechanical unit is (synchronous)void SetPathSupervisionLevel(string mechanicalUnit, int level);// Switches the path collision detection of a mechanical unit on or off (synchronous)void SetPathSupervisionMode(string mechanicalUnit, bool enabled);
Every method also exists in an asynchronous version, with the same name followed by Async and an optional CancellationToken.
public class MotionSupervision {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.MotionSupervision" data-throw-if-not-resolved="false"></xref> classpublic MotionSupervision()// Whether the supervision is switched on, null when the controller did not report itpublic bool? Enabled { get; set; }// Sensitivity of the supervision, as a percentage: the lower the value, the sooner a collision is// reported. Null when the controller did not report it.public int? Level { get; set; }// Returns a string representation of these settingspublic override string ToString()}
public class PathSupervision {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.PathSupervision" data-throw-if-not-resolved="false"></xref> classpublic PathSupervision()// Whether the supervision is switched on, null when the controller did not report itpublic bool? Enabled { get; set; }// Sensitivity of the supervision, as a percentage: the lower the value, the sooner a collision is// reported. Null when the controller did not report it.public int? Level { get; set; }// Returns a string representation of these settingspublic override string ToString()}
Lead through
Lead through releases the arm so an operator can push it around by hand. The motors have to be on and the robot has to support the feature. This is one of the two writes of the service that need no mastership.
// Is the arm free to be pushed by hand right nowLeadThroughStatus status = robot.Rws.MotionSystem.GetLeadThrough("ROB_1");Console.WriteLine(status);// Switching it on releases the arm: the motors have to be on, and the robot// has to support lead through. This call needs no mastership.robot.Rws.MotionSystem.SetLeadThrough("ROB_1", true);// Switching it off makes the arm hold its position againrobot.Rws.MotionSystem.SetLeadThrough("ROB_1", false);
GetLeadThrough returns Active when the arm gives way when pushed, and Inactive when it holds its position.
// Tells whether an operator can push the arm of a mechanical unit around by hand (synchronous)LeadThroughStatus GetLeadThrough(string mechanicalUnit);// Lets an operator push the arm of a mechanical unit around by hand, or stops letting them (synchronous)void SetLeadThrough(string mechanicalUnit, bool active);
Every method also exists in an asynchronous version, with the same name followed by Async and an optional CancellationToken.
public enum LeadThroughStatus {// The arm gives way when pushedActive = 1// The arm holds its positionInactive = 2// The controller reported a state this library does not knowUnknown = 0}
Calibration
The calibration says where each axis really is. Reading it is safe and tells you why a unit reports something else than Synchronized.
// How each joint of the unit was calibratedCalibrationInfo calibration = robot.Rws.MotionSystem.GetCalibrationInfo("ROB_1");Console.WriteLine($"method {calibration.CalibrationMethodUsed}, {calibration.ExistingJointCount} joint(s)");// The controller always answers with more joint slots than the unit has.// The extra ones carry no name and are marked as not existing.foreach (CalibrationJointInfo joint in calibration.Joints){if (!joint.Exists) continue;Console.WriteLine($"{joint.JointName} : factory {joint.FactoryCalibrationMethod}, now {joint.CurrentCalibrationMethod}");}// The name each joint carries, and the name of its calibration dataforeach (MotorCalibrationName name in robot.Rws.MotionSystem.GetMotorCalibrationNames("ROB_1")){Console.WriteLine($"joint {name.Number} : {name.JointName}, data {name.CalibrationName}");}// The calibration is stored twice: in the controller cabinet and in the robot itself.// The two copies are meant to agree.SmbData smb = robot.Rws.MotionSystem.GetSmbData("ROB_1");Console.WriteLine($"cabinet calibration {smb.CabinetCalibrationStatus}");Console.WriteLine($"robot calibration {smb.RobotCalibrationStatus}");if (smb.CabinetCalibrationStatus == SmbDataStatus.ValidNotEqual){Console.WriteLine("the two copies do not hold the same data");}
GetCalibrationInfo always answers with a fixed number of joint slots, larger than the number of joints the unit really has. The extra ones carry no name and have Exists set to false. ExistingJointCount counts the real ones.
The calibration data is stored twice, once in the controller cabinet and once in the robot itself. GetSmbData returns both copies with a status per block of data. ValidNotEqual means the two copies are present but do not agree.
The write operations replace the calibration of an axis. RWS offers no way to put the previous one back, so a wrong calibration leaves the robot moving to the wrong place until somebody recalibrates it from the FlexPendant. They need the mastership of the Motion domain, and the measurement board operations also need the controller in manual mode with this client as its local client.
// These four operations replace the calibration of an axis. RWS has no way to// put the previous one back, so read the state first and be sure of the position// the axis is standing in.MechanicalUnitInfo unit = robot.Rws.MotionSystem.GetMechanicalUnit("ROB_1");if (unit.Status != MechanicalUnitStatus.Synchronized){Console.WriteLine($"ROB_1 is {unit.Status}");}robot.Rws.Mastership.Request(MastershipDomain.Motion);try{// Teaches the controller how the rotor of the motor is oriented.// Needed once after a motor has been replaced.robot.Rws.MotionSystem.Commutate("ROB_1", 1);// Move the axis to its synchronization mark first: the controller stores// the position the axis is in right now.robot.Rws.MotionSystem.SynchronizeAxisRevolutionCounter("ROB_1", 1);robot.Rws.MotionSystem.UpdateRevolutionCounter("ROB_1", 1);// Takes the current position of the axis as its new calibration positionrobot.Rws.MotionSystem.FineCalibrate("ROB_1", 1);}finally{robot.Rws.Mastership.Release();}// Copy one of the two calibration data stores over the other. The overwritten// one is gone, so read both first and keep the good one.robot.Rws.MotionSystem.SetSmbData("ROB_1", SmbDataTransfer.RobotToController);// Erase one of them. The controller cannot recover it.robot.Rws.MotionSystem.ClearSmbData("ROB_1", SmbDataMemory.Controller);
| Method | Effect |
|---|---|
Commutate | Teaches the controller how the rotor of the motor is oriented. Needed once after a motor has been replaced. |
SynchronizeAxisRevolutionCounter | Tells the controller the axis stands at its synchronization mark |
UpdateRevolutionCounter | Updates the revolution counter of the axis |
FineCalibrate | Takes the current position of the axis as its new calibration position |
SetSmbData | Copies one of the two data stores over the other |
ClearSmbData | Erases one of the two data stores |
For the three operations that store a position, move the axis to its synchronization mark first. The controller stores the position the axis is in at the moment of the call.
Methods of MotionSystemService :// Erases one of the two serial measurement board data stores (synchronous)void ClearSmbData(string mechanicalUnit, SmbDataMemory memory);// Commutates the motor of one axis, which teaches the controller how the rotor of that motor is oriented (synchronous) Needed once after a motor has been replaced, before the axis can be calibrated.void Commutate(string mechanicalUnit, int axis);// Fine calibrates one axis of a mechanical unit (synchronous)void FineCalibrate(string mechanicalUnit, int axis);// Gets how each joint of a mechanical unit was calibrated (synchronous)CalibrationInfo GetCalibrationInfo(string mechanicalUnit);// Gets the name each joint of a mechanical unit carries, and the name of its calibration data (synchronous)MotorCalibrationName[] GetMotorCalibrationNames(string mechanicalUnit);// Gets the serial measurement board data of a mechanical unit, as held by the controller cabinet and by the robot itself (synchronous) The two copies are meant to agree. When they do not, one of them is written over the other with Data.SmbDataTransfer).SmbData GetSmbData(string mechanicalUnit);// Copies one of the two serial measurement board data stores over the other (synchronous)void SetSmbData(string mechanicalUnit, SmbDataTransfer direction);// Synchronizes the revolution counter of one axis, telling the controller that the axis stands at its synchronization mark (synchronous)void SynchronizeAxisRevolutionCounter(string mechanicalUnit, int axis);// Updates the revolution counter of one axis of a mechanical unit (synchronous)void UpdateRevolutionCounter(string mechanicalUnit, int axis);
Every method also exists in an asynchronous version, with the same name followed by Async and an optional CancellationToken.
public class CalibrationInfo {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.CalibrationInfo" data-throw-if-not-resolved="false"></xref> classpublic CalibrationInfo()// Number of joints of the unit that are in use, null when the controller did not report itpublic int? ActiveJointCount { get; set; }// Name of the calibration method the unit was last calibrated with, for example "AxisCalibration"public string CalibrationMethodUsed { get; set; }// Kind of calibration window the controller offers for this unit,// null when the controller did not report itpublic int? CalibrationWindowType { get; set; }// Number of joints that exist on the unit, counted from <xref href="UnderAutomation.ABB.Rws.Data.CalibrationInfo.Joints" data-throw-if-not-resolved="false"></xref>public int ExistingJointCount { get; }// Number of entries in <xref href="UnderAutomation.ABB.Rws.Data.CalibrationInfo.Joints" data-throw-if-not-resolved="false"></xref>, which is fixed and larger than// <xref href="UnderAutomation.ABB.Rws.Data.CalibrationInfo.ActiveJointCount" data-throw-if-not-resolved="false"></xref>. Null when the controller did not report it.public int? JointCount { get; set; }// One entry per joint slot of the unit, the unused ones marked as such. Never null.public CalibrationJointInfo[] Joints { get; set; }// Returns a string representation of this calibrationpublic override string ToString()}
public class CalibrationJointInfo {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.CalibrationJointInfo" data-throw-if-not-resolved="false"></xref> classpublic CalibrationJointInfo()// Method the joint is currently calibrated withpublic string CurrentCalibrationMethod { get; set; }// Whether the joint exists on this mechanical unit. The controller always answers with a fixed// number of entries and marks the unused ones, which carry no name at all.public bool Exists { get; set; }// Method the joint was calibrated with in the factorypublic string FactoryCalibrationMethod { get; set; }// Name of the joint, for example "rob1_1", empty for an entry that does not existpublic string JointName { get; set; }// Returns a string representation of this jointpublic override string ToString()}
public class MotorCalibrationName {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.MotorCalibrationName" data-throw-if-not-resolved="false"></xref> classpublic MotorCalibrationName()// Name of the calibration data of the joint, usually the same as <xref href="UnderAutomation.ABB.Rws.Data.MotorCalibrationName.JointName" data-throw-if-not-resolved="false"></xref>public string CalibrationName { get; set; }// Name of the joint, for example "rob1_1"public string JointName { get; set; }// Number of the joint inside its mechanical unit, starting at 1public int Number { get; set; }// Returns a string representation of these namespublic override string ToString()}
public class SmbData {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.SmbData" data-throw-if-not-resolved="false"></xref> classpublic SmbData()// State of the absolute accuracy data stored in the cabinetpublic SmbDataStatus CabinetAbsoluteAccuracyStatus { get; set; }// State of the axis calibration data stored in the cabinetpublic SmbDataStatus CabinetAxisCalibrationStatus { get; set; }// State of the calibration data stored in the cabinetpublic SmbDataStatus CabinetCalibrationStatus { get; set; }// High part of the serial number stored in the cabinetpublic string CabinetSerialNumberHighPart { get; set; }// Low part of the serial number stored in the cabinetpublic string CabinetSerialNumberLowPart { get; set; }// Whether the serial number stored in the cabinet is usable, null when the controller did not report itpublic bool? CabinetSerialNumberValid { get; set; }// State of the service information data stored in the cabinetpublic SmbDataStatus CabinetServiceInformationStatus { get; set; }// Number of the drive module the data belongs to, null when the controller did not report itpublic int? DriveModule { get; set; }// Number of the measurement board the data belongs to, null when the controller did not report itpublic int? MeasurementBoard { get; set; }// Number of the measurement link the data belongs to, null when the controller did not report itpublic int? MeasurementLink { get; set; }// State of the absolute accuracy data stored in the robotpublic SmbDataStatus RobotAbsoluteAccuracyStatus { get; set; }// State of the axis calibration data stored in the robotpublic SmbDataStatus RobotAxisCalibrationStatus { get; set; }// State of the calibration data stored in the robotpublic SmbDataStatus RobotCalibrationStatus { get; set; }// High part of the serial number stored in the robotpublic string RobotSerialNumberHighPart { get; set; }// Low part of the serial number stored in the robotpublic string RobotSerialNumberLowPart { get; set; }// Whether the serial number stored in the robot is usable, null when the controller did not report itpublic bool? RobotSerialNumberValid { get; set; }// State of the service information data stored in the robotpublic SmbDataStatus RobotServiceInformationStatus { get; set; }// Returns a string representation of this datapublic override string ToString()}
public enum SmbDataStatus {// The robot system does not use this block of dataNotUsed = 4// The data is missing or unusableNotValid = 3// The controller reported a state this library does not knowUnknown = 0// The data is present and the two copies agreeValid = 1// The data is present on both sides, but the two copies differValidNotEqual = 2}
public enum SmbDataTransfer {// The copy held by the controller cabinet is written into the robotControllerToRobot = 1// The copy held by the robot is written into the controller cabinetRobotToController = 0}
public enum SmbDataMemory {// The copy held by the controller cabinetController = 1// The copy held by the robot itselfRobot = 0}
State of the motion system
GetInfo gives the overview: which unit the jogging commands apply to, whether absolute accuracy is on, and the change count.
// Overview of the motion system: which unit the jogging commands apply to,// and the counter the controller increments on every changeMotionSystemInfo info = robot.Rws.MotionSystem.GetInfo();Console.WriteLine($"jogging applies to {info.MechanicalUnitName}");Console.WriteLine($"change count {info.ChangeCount}, absolute accuracy {info.AbsoluteAccuracyActive}");// Ask whether anything moved since that reading, instead of reading everything againif (info.ChangeCount.HasValue && robot.Rws.MotionSystem.HasChanged(info.ChangeCount.Value)){Console.WriteLine("the motion system changed");}// The last error the motion system ran into. Most of them come from a jogging// request the controller accepted and could not honour.MotionSystemErrorState error = robot.Rws.MotionSystem.GetErrorState();if (error.State != MotionErrorState.Ok){Console.WriteLine($"{error.State} ({error.RawState}), {error.Count} error(s)");}// Run the RAPID program without moving the robot. The instructions execute,// the motion ones are skipped.bool skipped = robot.Rws.MotionSystem.GetNonMotionExecutionMode();robot.Rws.Mastership.Request();try{robot.Rws.MotionSystem.SetNonMotionExecutionMode(true);}finally{robot.Rws.Mastership.Release();}
The change count is a counter the controller increments on every change of the motion system. Reading it once and asking HasChanged afterwards is cheaper than fetching the whole state again to find out that nothing moved. Only pass a count a previous reading gave: the controller does not track how two counts relate, so a count it never reported comes back as changed.
GetErrorState returns the last error the motion system ran into and how many it has counted. Most of them come from a jogging request the controller accepted and could not honour, and they stay reported until a new one replaces them.
MotionErrorState | Meaning |
|---|---|
Ok | No error |
MechanicalUnitNotActive | A mechanical unit was jogged whose activation failed |
UncalibratedJogMotionType | An uncalibrated robot was jogged in a mode that needs its calibration |
UnnormalizedQuaternion | A tool, a load or a work object carries an orientation that is not normalized |
ErroneousToolMass | A load definition carries a negative mass |
RobotHoldMismatch | The tool and the work object disagree on which one the robot holds |
WorkObjectMechanicalUnitNotFound | A unit used in coordinated jogging was not found |
InvalidJogMotionType | The requested jogging mode is not valid |
Unknown | The controller reported an error the library does not know, RawState then holds it |
// Gets the last error the motion system ran into, and how many errors it has counted (synchronous) Most of these errors are raised by a jogging request the controller could not honour, and stay reported until a new one replaces them.MotionSystemErrorState GetErrorState();// Gets an overview of the motion system: the mechanical unit jogging applies to, the change counter and the payload and accuracy settings (synchronous)MotionSystemInfo GetInfo();// Tells whether the motion system changed since it reported the given change count (synchronous) Reading MotionSystemInfo.ChangeCount once and asking this afterwards is cheaper than fetching the whole state again to find out that nothing moved.bool HasChanged(int changeCount);
Every method also exists in an asynchronous version, with the same name followed by Async and an optional CancellationToken.
public class MotionSystemInfo {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.MotionSystemInfo" data-throw-if-not-resolved="false"></xref> classpublic MotionSystemInfo()// Whether absolute accuracy is switched on, null when the controller did not report itpublic bool? AbsoluteAccuracyActive { get; set; }// Counter the controller increments on every change of the motion system.//// <p>Pass it to <code>MotionSystemService.HasChanged()</code> to find out whether anything moved// since a previous reading, without fetching the whole state again.</p>public int? ChangeCount { get; set; }// Name of the mechanical unit the jogging commands currently apply topublic string MechanicalUnitName { get; set; }// Whether the payload of the robot is set by the running program rather than by the mechanical unit,// null when the controller did not report itpublic bool? ModalPayloadMode { get; set; }// Rate at which the controller refreshes the motion system state, null when it did not report itpublic int? PollRate { get; set; }// Returns a string representation of this motion systempublic override string ToString()}
public class MotionSystemErrorState {// Initializes a new instance of the <xref href="UnderAutomation.ABB.Rws.Data.MotionSystemErrorState" data-throw-if-not-resolved="false"></xref> classpublic MotionSystemErrorState()// Number of errors counted since the controller started, incremented on every new error,// null when the controller did not report itpublic int? Count { get; set; }// Error state exactly as the controller reported it, useful when <xref href="UnderAutomation.ABB.Rws.Data.MotionSystemErrorState.State" data-throw-if-not-resolved="false"></xref> is// <xref href="UnderAutomation.ABB.Rws.Data.MotionErrorState.Unknown" data-throw-if-not-resolved="false"></xref>public string RawState { get; set; }// Last error the motion system ran intopublic MotionErrorState State { get; set; }// Returns a string representation of this error statepublic override string ToString()}
public enum MotionErrorState {// A load definition carries a negative massErroneousToolMass = 5// The requested jogging mode is not validInvalidJogMotionType = 8// A mechanical unit was jogged whose activation failedMechanicalUnitNotActive = 2// No errorOk = 1// The tool and the work object disagree on which one the robot holdsRobotHoldMismatch = 6// An uncalibrated robot was jogged in a mode that needs its calibrationUncalibratedJogMotionType = 3// The controller reported an error this library does not knowUnknown = 0// A quaternion that is not normalized reached the jogging task, from a tool, a load or a work objectUnnormalizedQuaternion = 4// A mechanical unit used in coordinated jogging was not foundWorkObjectMechanicalUnitNotFound = 7}