Repository navigation
v7.0.1.0
Stream Motion (J519): new API
Breaking change: the Stream Motion API was rewritten. You do not build and send packets anymore. The SDK synchronizes the positions with the status of the robot, sends a few positions in advance, and stops the robot smoothly when your application stops giving positions. Code written for the previous API must be updated (see "How to migrate" below).
The client (robot.StreamMotion, or StreamMotionClient alone) gives three ways to move the robot:
- Queue of trajectories: plan a trajectory with the new motion planner and call
Enqueue(). It returns an id forWaitForMotion().WaitForIdle()waits for the whole queue. Control the motion withOverride,Pause(),Resume()andAbort(). - Target tracking: call
StartTracking(), then change the target at any time withSetJointTrackingTarget()orSetCartesianTrackingTarget(). - Callback streaming: call
StartCallbackStreaming(), then give each position in theSetpointRequestedevent withe.SetJoints(),e.SetCartesian()ore.Hold().
using UnderAutomation.Fanuc.Motion; // FanucMotion
using UnderAutomation.Robotics.Motion; // MotionPlanner, Trajectory
var parameters = new ConnectionParameters("192.168.0.1");
parameters.StreamMotion.Enable = true;
robot.Connect(parameters);
var sm = robot.StreamMotion;
// Read the limits of the robot, start the status output and measure the communication cycle
sm.StartMonitoring();
// J1 +10 degrees then back, at 20% of the velocity limits
JointsPosition start = sm.QueueEndJointPosition;
var target = new JointsPosition(start.Values) { J1 = start.J1 + 10 };
var planner = new MotionPlanner(sm.JointLimits, null);
Trajectory trajectory = planner.CreateJointPath(FanucMotion.ToJointValues(start))
.MoveJoint(FanucMotion.ToJointValues(target), 20, FanucMotion.Cnt(100))
.MoveJoint(FanucMotion.ToJointValues(start), 20, FanucMotion.Fine())
.Build();
// The motion starts when the TP program reaches IBGN start
sm.WaitForMotion(sm.Enqueue(trajectory), 60000);
// Release the TP program: it continues after IBGN end
sm.Finish(10000);// Follow a target that can change at any time, at 30% of the velocity limits
sm.StartTracking(PositionFormat.Joint, 30);
sm.SetJointTrackingTarget(new JointsPosition(start.Values) { J1 = start.J1 + 10 });
sm.WaitForIdle(10000);
sm.StopTracking();Other new features:
- Protocol versions 1, 2 and 3 with
ConnectionParameters.StreamMotion.ProtocolVersion(default 1, must not be higher than$STMO.$USABLE_VER). Version 2 sends joint positions in double precision. - New connection settings:
BufferLeadTime(0.024 s),PacketStackSize(10),StatusTimeoutMs(1000 ms) andHighPriority(true).Portis still 60015. Stategives the state of the client:Disconnected,Connected,Monitoring,Ready,StreamingorFinishing.WaitForReady()waits until the TP program reachesIBGN start.LastStatusand theStatusReceivedevent give the joint and Cartesian positions, the motor currents and the flags of the robot (IsWaitingForCommand,IsMoving...).CycleTimegives the measured communication cycle andStatisticsthe quality of the communication.- New events:
SessionStarted,SessionEnded(with aSessionEndReason),MotionCompleted,UnderrunandErrorOccurred. Errors are thrown asStreamMotionException, with aStreamMotionErrorcode. - A session uses only one format, joint or Cartesian: call
Finish()to use the other format in the next session.HasActiveFormatandActiveFormatgive the current format. ReadLimits()reads the velocity, acceleration and jerk limits of each axis.ReferenceLimitsare always safe,ComputeLimits()gives the limits for a flange speed and a payload, andGetTable()gives the raw table of one axis.- I/O synchronized with the motion:
AddIOMonitor()reads ranges of 16 I/O,GetIO()andIOValuesgive their values,WriteIO()andWriteIOGroup()write outputs, andIOAnticipationcompensates the delay of the robot. An output can also be switched at a precise time of a trajectory. Features.HasStreamMotiontells if the J519 option is installed on the robot.
How to migrate:
| Previous API | New API |
|---|---|
Start() / Stop() |
StartMonitoring() / StopMonitoring() |
SendJointCommand(), SendCartesianCommand(), SendCommand() in a loop |
Enqueue() a Trajectory, follow a target with StartTracking(), or give each position with StartCallbackStreaming() |
isLastData = true |
Finish() |
StateReceived event, LastState |
StatusReceived event, LastStatus |
ReceiveError event |
ErrorOccurred event |
RequestThreshold() |
ReadLimits() |
IsStreaming |
State == StreamMotionState.Streaming |
RobotFrequency, MeasuredFrequency |
CycleTime |
PacketCount |
Statistics |
SendTimeoutMs, ReceiveTimeoutMs |
StatusTimeoutMs |
StreamMotionClient.Connect(ip, port, sendTimeoutMs, receiveTimeoutMs) |
StreamMotionClient.Connect(ip, new StreamMotionConnectParameters { ... }) |
The types CommandPacket, StatePacket, MotionData, DataStyle, RobotStatus, AckPacket, ThresholdType, IOReadResult, StateReceivedEventArgs and ReceiveErrorEventArgs were removed.
Documentation: Stream Motion
New motion planner
The new namespace UnderAutomation.Robotics.Motion creates smooth trajectories that respect velocity, acceleration and jerk limits. It works offline, without robot. Trajectories can be sent with Stream Motion, used in a simulation, or checked before use.
The UnderAutomation.Robotics namespaces are common to all UnderAutomation robot SDKs: the same code plans trajectories for other robot brands. The FANUC specific part is in UnderAutomation.Fanuc.Motion: the FanucMotion class converts JointsPosition and XYZWPRPosition, gives the FINE, CNT and CR terminations and the I/O signals, and returns the FANUC positions of a trajectory.
JointLimits(velocity, acceleration and jerk of 9 axes) andCartesianLimits(linear and angular velocity, acceleration and jerk). On a robot, read the joint limits withrobot.StreamMotion.ReadLimits().ReferenceLimits.MotionPlannercreates joint and Cartesian paths. WithToolFrameandUserFrame, targets are tool positions in this user frame.- Positions of the planner:
JointValuesandCartesianPose(X, Y, Z,Orientationand external axes).Orientationconverts from and to quaternions, Euler angles (EulerConvention), rotation vectors and rotation matrices. The W, P, R angles of FANUC areEulerConvention.FixedXYZ. - Joint paths:
MoveJoint()(speed in %, termination, optional acceleration in %),MoveJointTime(),MoveJointSpline(),Wait()andSetIO(). - Cartesian paths:
MoveLinear(),MoveCircular(),MoveLinearTime(),MoveSpline(), and shapes in any plane:AddCircle(),AddRectangle(),AddPolygon(),AddHelix()andAddSpiral(). - Terminations as in a TP program:
FanucMotion.Fine(),FanucMotion.Cnt(0..100)andFanucMotion.Cr(distanceMm). They are the same asTermination.Stop(),Termination.Overlap(percent)andTermination.Corner(distanceMm). - All motions use jerk limited profiles. The profile is also available alone with
DoubleSProfile.
using UnderAutomation.Fanuc.Motion; // FanucMotion
using UnderAutomation.Fanuc.StreamMotion.Data; // IOType
using UnderAutomation.Robotics.Geometry; // JointValues, CartesianPose
using UnderAutomation.Robotics.Motion; // MotionPlanner, Trajectory
var jointLimits = new JointLimits(
new double[] { 120, 120, 180, 180, 180, 180 }, // velocity, deg/s
new double[] { 300, 300, 450, 675, 675, 675 }, // acceleration, deg/s2
new double[] { 1125, 1125, 1687, 2530, 1265, 2530 }); // jerk, deg/s3
var cartesianLimits = new CartesianLimits(500, 2000, 10000, 90, 360, 1800);
var planner = new MotionPlanner(jointLimits, cartesianLimits);
// J P[1] 100% CNT50, J P[2] 30% FINE ACC50, DO[1]=ON, WAIT 0.5 s, then back in 2 s
var start = new JointValues(0, 0, 0, 0, -90, 0);
Trajectory joint = planner.CreateJointPath(start)
.MoveJoint(new JointValues(40, 0, 0, 0, -90, 0), 100, FanucMotion.Cnt(50))
.MoveJoint(new JointValues(40, 30, -20, 0, -60, 0), 30, FanucMotion.Fine(), 50)
.SetIO(FanucMotion.Signal(IOType.DO, 1), true)
.Wait(0.5)
.MoveJointTime(start, 2.0, FanucMotion.Fine())
.Build();
// L 200mm/sec CR10, then C at 150mm/sec FINE
Func<double, double, double, double, double, double, CartesianPose> wpr =
(x, y, z, w, p, r) => FanucMotion.ToCartesianPose(new XYZWPRPosition(x, y, z, w, p, r));
Trajectory cartesian = planner.CreateCartesianPath(wpr(500, 0, 300, 180, 0, 0))
.MoveLinear(wpr(600, 0, 300, 180, 0, 0), 200, FanucMotion.Cr(10))
.MoveCircular(wpr(550, 150, 300, 180, 0, 0), wpr(500, 100, 300, 180, 0, 30), 150, FanucMotion.Fine())
.Build();
// FANUC positions of the trajectory, one per 8 ms, with continuous W, P, R
ExtendedCartesianPosition[] positions = FanucMotion.SampleCartesian(cartesian, 0.008);A Trajectory gives its Duration, the position at any time (GetJoints(), GetCartesian()), samples at a fixed period (SampleJoints(), SampleCartesian()) and its I/O events (IOEvents, AddIOEvent()). Trajectories can also be created from your own positions:
Trajectory.FromJointSamples()andFanucMotion.FromCartesianSamples(): one position per communication cycle, sent without any change.Trajectory.FromTimedJoints()andTrajectory.FromTimedCartesian(): a few positions with their time.Check()andCheckCartesian()compute the velocity, acceleration and jerk as the robot does and return a report.Retime()andRetimeCartesian()play the same path slower so that the limits are respected (withsinglePrecision, also after the rounding of protocol version 1).
Trajectory trajectory = Trajectory.FromTimedJoints(
new[] { new JointValues(0, 0, 0, 0, -90, 0), new JointValues(90, 0, 0, 0, -90, 0) },
new[] { 0.0, 0.5 });
TrajectoryReport report = trajectory.Check(jointLimits, 0.008, true);
if (!report.IsValid)
trajectory = trajectory.Retime(jointLimits, 0.008, true);
JointValues[] samples = trajectory.SampleJoints(0.008);Documentation: Motion planner
Quaternions and frame operations
New Quaternion class (Qw, Qx, Qy, Qz) with Slerp(), AngleTo(), FromAxisAngle(), ToAxisAngle(), FromRotationMatrix(), ToRotationMatrix(), Multiply(), Conjugate() and Normalize().
New methods on XYZWPRPosition, so also on CartesianPosition: GetQuaternion(), SetQuaternion(), Multiply(), Inverse(), FlangeToTcp(), TcpToFlange(), UserFrameToWorld() and WorldToUserFrame().
ToHomogeneousMatrix() moved from CartesianPosition to its base class XYZWPRPosition. Existing code still compiles.
var tool = new XYZWPRPosition(0, 0, 150, 0, 0, 0); // tool frame, relative to the flange
var userFrame = new XYZWPRPosition(800, -200, 0, 0, 0, 90); // user frame, relative to the world frame
var flange = new XYZWPRPosition(700, 0, 400, 180, 0, 0); // flange in the world frame
XYZWPRPosition tcpInUserFrame = flange.FlangeToTcp(tool).WorldToUserFrame(userFrame);
Quaternion a = new XYZWPRPosition(0, 0, 0, 180, 0, 0).GetQuaternion();
Quaternion b = new XYZWPRPosition(0, 0, 0, 180, 30, 0).GetQuaternion();
Quaternion halfWay = Quaternion.Slerp(a, b, 0.5);
double angle = a.AngleTo(b); // 30 degreesDocumentation: Frames & orientations