Motion commands
Send linear, joint, and circular motion commands with configurable speed, termination type, and acceleration via RMI.
RMI lets you send TP-equivalent motion instructions to the robot. Each call to SendTpInstruction() returns an RmiInstructionResponse that tracks the instruction through its execution lifecycle.
Linear motion
Move the robot in a straight line to a Cartesian target:
// Linear motion to a Cartesian target (tool 1, frame 0)var move = new LinearMotionTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 100,TermType = RmiTerminationType.Fine,Target = new CartesianPositionWithUserFrame(500, 200, 300, 0, 90, 0, tool: 1, frame: 0)};robot.Rmi.SendTpInstruction(move).WaitForCompletion();// Incremental linear motion (delta from current position)var inc = new LinearRelativeTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 50,TermType = RmiTerminationType.Fine,Target = new CartesianPositionWithUserFrame(0, 0, -50, 0, 0, 0, 1, 0)};robot.Rmi.SendTpInstruction(inc).WaitForCompletion();// Linear motion with joint-angle target representationvar jrep = new LinearMotionJRepTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 80,TermType = RmiTerminationType.Fine,Joints = new JointsPosition(10, -20, 30, 0, 60, 0)};robot.Rmi.SendTpInstruction(jrep).WaitForCompletion();// CNT blending: chain motions without stoppingvar p1 = new LinearMotionTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 200,TermType = RmiTerminationType.Cnt,TermValue = 100,Target = new CartesianPositionWithUserFrame(600, 0, 400, 0, 90, 0, 1, 0)};var p2 = new LinearMotionTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 200,TermType = RmiTerminationType.Fine, // last motion must be Fine (or NoBlend = true)Target = new CartesianPositionWithUserFrame(700, 0, 350, 0, 90, 0, 1, 0)};robot.Rmi.SendTpInstruction(p1);robot.Rmi.SendTpInstruction(p2).WaitForCompletion();
Speed types for linear motion
RmiLinearSpeedType | Description |
|---|---|
MmSec | Millimeters per second. |
InchMin | Inches per minute (0.1 in/min units). |
Time | Duration in 0.1-second steps. |
MSec | Duration in milliseconds. |
Termination types
RmiTerminationType | Description |
|---|---|
Fine | Stop precisely at the target. |
Cnt | Continuous blending with the next motion (value 1-100). The last motion sent must be Fine unless NoBlend = true. |
Cr | Corner region (requires Advanced Constant Path option). |
Joint motion
Move using joint interpolation (Cartesian target or joint-angle target):
// Joint motion with Cartesian target, percent speedvar cart = new JointMotionTpInstruction{SpeedType = RmiJointSpeedType.Percent,Speed = 10,TermType = RmiTerminationType.Fine,Target = new CartesianPositionWithUserFrame(500, 200, 300, 0, 90, 0, tool: 1, frame: 0)};robot.Rmi.SendTpInstruction(cart).WaitForCompletion();// Joint motion with joint-angle target representationvar jrep = new JointMotionJRepTpInstruction{SpeedType = RmiJointSpeedType.Percent,Speed = 5,TermType = RmiTerminationType.Fine,Joints = new JointsPosition(10, -20, 30, 0, 60, 0)};robot.Rmi.SendTpInstruction(jrep).WaitForCompletion();// Incremental joint motion (joint-angle delta)var relJrep = new JointRelativeJRepTpInstruction{SpeedType = RmiJointSpeedType.Percent,Speed = 5,TermType = RmiTerminationType.Fine,Joints = new JointsPosition(0, 0, 0, 0, 5, 0) // rotate J5 by 5 degrees};robot.Rmi.SendTpInstruction(relJrep).WaitForCompletion();
Speed types for joint motion
RmiJointSpeedType | Description |
|---|---|
Percent | Percentage of maximum joint speed (1-100). |
Time | Duration in 0.1-second steps. |
MSec | Duration in milliseconds. |
Circular motion
Circular motion requires a via point and a destination:
// Circular motion: define a via-point and a destinationvar arc = new CircularMotionTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 80,TermType = RmiTerminationType.Fine,Via = new CartesianPositionWithUserFrame(600, 100, 350, 0, 90, 0, tool: 1, frame: 0),Target = new CartesianPositionWithUserFrame(700, 0, 300, 0, 90, 0, tool: 1, frame: 0)};robot.Rmi.SendTpInstruction(arc).WaitForCompletion();// Incremental circular motion (via and target are deltas)var arcRel = new CircularRelativeTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 60,TermType = RmiTerminationType.Fine,Via = new CartesianPositionWithUserFrame(50, 50, 0, 0, 0, 0, 1, 0),Target = new CartesianPositionWithUserFrame(100, 0, 0, 0, 0, 0, 1, 0)};robot.Rmi.SendTpInstruction(arcRel).WaitForCompletion();
Spline motion
Spline motion requires firmware MajorVersion >= 7 (V9.40P/54 or later). The controller needs at least one more spline instruction after the first to start executing the segment.
// Spline motion requires MajorVersion >= 7 (firmware V9.40P/54 or later).// The controller will not execute the first spline segment until it receives// a second instruction (motion or non-motion) after the last spline point.robot.Rmi.SendTpInstruction(new SplineMotionTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 200,TermType = RmiTerminationType.Cnt,TermValue = 100,Target = new CartesianPositionWithUserFrame(500, 100, 300, 0, 90, 0, 1, 0)});robot.Rmi.SendTpInstruction(new SplineMotionTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 200,TermType = RmiTerminationType.Cnt,TermValue = 100,Target = new CartesianPositionWithUserFrame(550, 200, 320, 0, 90, 0, 1, 0)});robot.Rmi.SendTpInstruction(new SplineMotionTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 200,TermType = RmiTerminationType.Fine,Target = new CartesianPositionWithUserFrame(600, 100, 300, 0, 90, 0, 1, 0)});// Send a non-spline instruction to flush the spline buffer and trigger executionrobot.Rmi.SendTpInstruction(new WaitTimeTpInstruction { Seconds = 0.1 }).WaitForCompletion();// Spline with joint-angle representationrobot.Rmi.SendTpInstruction(new SplineMotionJRepTpInstruction{SpeedType = RmiJointSpeedType.Percent,Speed = 50,TermType = RmiTerminationType.Cnt,TermValue = 100,Joints = new JointsPosition(10, -20, 30, 0, 60, 0)});robot.Rmi.SendTpInstruction(new SplineMotionJRepTpInstruction{SpeedType = RmiJointSpeedType.Percent,Speed = 50,TermType = RmiTerminationType.Fine,Joints = new JointsPosition(15, -15, 35, 5, 55, 5)});robot.Rmi.SendTpInstruction(new WaitTimeTpInstruction { Seconds = 0.1 }).WaitForCompletion();
Relative (incremental) motions
All motion types have incremental variants. The position is a delta from the current robot position:
| Absolute | Incremental |
|---|---|
LinearMotionTpInstruction | LinearRelativeTpInstruction |
JointMotionTpInstruction | JointRelativeTpInstruction |
CircularMotionTpInstruction | CircularRelativeTpInstruction |
LinearMotionJRepTpInstruction | LinearRelativeJRepTpInstruction |
JointMotionJRepTpInstruction | JointRelativeJRepTpInstruction |
Motion options
Most instruction classes expose optional motion modifiers:
| Property | Type | Description |
|---|---|---|
Acc | byte? | Acceleration override (20-100 %). |
OffsetPrNumber | short? | Offset position register number. |
ToolOffsetPrNumber | short? | Tool offset PR number (MajorVersion >= 4). |
VisionPrNumber | short? | Vision offset register number. |
WristJoint | bool | Enable wrist-joint mode (linear and circular only). |
Mrot | bool | MROT option — requires WristJoint and R640 option. |
NoBlend | bool | Allow CNT motion to execute without waiting for the next instruction (MajorVersion >= 5). |
Alim | int? | Acceleration limit in mm/s² (MajorVersion >= 5, R921 option). |
AlimReg | short? | Register-based acceleration limit (MajorVersion >= 5, R921 option). |
LcbType | string | Local Condition Block type: "TB", "TA", or "DB". |
LcbValue | short? | LCB value (ms for TA/TB, 0.01 mm for DB). |
PortType | RmiPortType? | Output port type (DOUT or ROUT) triggered by LCB. |
PortNumber | short? | LCB output port number. |
PortValue | RmiOnOff? | LCB output port value (ON or OFF). |
Non-motion instructions
Insert wait conditions, frame changes, and program calls between motions:
// Wait for digital input DI[1] to turn ON before continuingrobot.Rmi.SendTpInstruction(new WaitDinTpInstruction{PortNumber = 1,Value = RmiOnOff.ON});// Wait 0.5 secondsrobot.Rmi.SendTpInstruction(new WaitTimeTpInstruction { Seconds = 0.5 });// Switch to UFRAME 2 for the next motionsrobot.Rmi.SendTpInstruction(new SetUFrameTpInstruction { FrameNumber = 2 });// Switch to UTOOL 3robot.Rmi.SendTpInstruction(new SetUToolTpInstruction { ToolNumber = 3 });// Activate payload schedule 1robot.Rmi.SendTpInstruction(new SetPayloadTpInstruction { ScheduleNumber = 1 });// Call a TP program (requires MajorVersion >= 4)robot.Rmi.SendTpInstruction(new CallProgramTpInstruction { ProgramName = "GRIPPER_OPEN" }).WaitForCompletion();
Tracking instruction status
// Send several instructions. Each returns immediately.for (int i = 0; i < 5; i++){var instr = new LinearMotionTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 100,TermType = RmiTerminationType.Fine,Target = new CartesianPositionWithUserFrame(500 + i * 20, 200, 300, 0, 90, 0, 1, 0)};RmiInstructionResponse r = robot.Rmi.SendTpInstruction(instr);// Subscribe to status changesr.StatusChanged += status =>Console.WriteLine($" Seq {r.SequenceId}: {status}");}// Wait for all instructions to completeforeach (RmiInstructionResponse r in robot.Rmi.Instructions)r.WaitForCompletion();// Print final resultsforeach (RmiInstructionResponse r in robot.Rmi.Instructions){if (r.Status == RmiInstructionStatus.Error)Console.WriteLine($" Seq {r.SequenceId} failed: {r.ErrorText}");elseConsole.WriteLine($" Seq {r.SequenceId} completed OK");}// Remove completed instructions from the tracking listrobot.Rmi.ClearCompletedInstructions();
Complete example
using System;using UnderAutomation.Fanuc;using UnderAutomation.Fanuc.Common;using UnderAutomation.Fanuc.Rmi.Data;using UnderAutomation.Fanuc.Rmi.TpInstructions;public class RmiMotion{static void Main(){FanucRobot robot = new FanucRobot();ConnectionParameters parameters = new ConnectionParameters("192.168.0.1");parameters.Rmi.Enable = true;robot.Connect(parameters);// Check statusRmiControllerStatusResponse status = robot.Rmi.GetStatus();if (status.TPEnabled){Console.WriteLine("Turn off the teach pendant before proceeding.");return;}if (!status.ServoReady){Console.WriteLine("Servos are not ready.");return;}// Initialize RMI_MOVErobot.Rmi.Initialize();// Set speed overriderobot.Rmi.SetOverride(80);// Move to a start positionrobot.Rmi.SendTpInstruction(new JointMotionJRepTpInstruction{SpeedType = RmiJointSpeedType.Percent,Speed = 10,TermType = RmiTerminationType.Fine,Joints = new JointsPosition(0, 0, 0, 0, 0, 0)}).WaitForCompletion();// Approachrobot.Rmi.SendTpInstruction(new LinearMotionTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 200,TermType = RmiTerminationType.Cnt,TermValue = 50,Target = new CartesianPositionWithUserFrame(500, 200, 350, 0, 90, 0, 1, 0)});// Descend to pick positionrobot.Rmi.SendTpInstruction(new LinearMotionTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 50,TermType = RmiTerminationType.Fine,Target = new CartesianPositionWithUserFrame(500, 200, 300, 0, 90, 0, 1, 0)}).WaitForCompletion();// Activate gripperrobot.Rmi.SendTpInstruction(new CallProgramTpInstruction { ProgramName = "GRIP_ON" }).WaitForCompletion();// Retractrobot.Rmi.SendTpInstruction(new LinearMotionTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 100,TermType = RmiTerminationType.Fine,Target = new CartesianPositionWithUserFrame(500, 200, 400, 0, 90, 0, 1, 0)}).WaitForCompletion();// Check HOLD stateif (robot.Rmi.IsInHoldState){Console.WriteLine("Controller in HOLD. Calling Reset...");robot.Rmi.Reset();}robot.Rmi.Abort();robot.Disconnect();}}
API reference
Members of Rmi.TpInstructions.LinearMotionTpInstruction :public class LinearMotionTpInstruction : CartesianMotionTpInstructionBase {public LinearMotionTpInstruction()// Acceleration limit value. <code>null</code> uses the controller default. Requires MajorVersion >= 5 and the R921 option.public int? Alim { get; set; }// Acceleration limit register number. <code>null</code> disables register-based limit. Requires MajorVersion >= 5 and the R921 option.public short? AlimReg { get; set; }// When <code>true</code>, enables coordinated motion (MROT).public bool Mrot { get; set; }// When <code>true</code>, disables blending with the next instruction. Requires MajorVersion >= 5.public bool NoBlend { get; set; }// Speed unit (mm/s, inch/min, or time).public RmiLinearSpeedType SpeedType { get; set; }// When <code>true</code>, enables wrist-joint mode for this motion.public bool WristJoint { get; set; }}
public class JointMotionTpInstruction : CartesianMotionTpInstructionBase {public JointMotionTpInstruction()// When <code>true</code>, enables coordinated motion (MROT).public bool Mrot { get; set; }// When <code>true</code>, disables blending with the next instruction.public bool NoBlend { get; set; }// Speed unit (percent override or time).public RmiJointSpeedType SpeedType { get; set; }}
public class JointMotionJRepTpInstruction : JRepMotionTpInstructionBase {public JointMotionJRepTpInstruction()// When <code>true</code>, enables coordinated motion (MROT).public bool Mrot { get; set; }// When <code>true</code>, disables blending with the next instruction.public bool NoBlend { get; set; }// Speed unit (percent override or time).public RmiJointSpeedType SpeedType { get; set; }}
public class CircularMotionTpInstruction : CartesianMotionTpInstructionBase {public CircularMotionTpInstruction()// When <code>true</code>, enables coordinated motion (MROT).public bool Mrot { get; set; }// When <code>true</code>, disables blending with the next instruction.public bool NoBlend { get; set; }// Speed unit (mm/s, inch/min, or time).public RmiLinearSpeedType SpeedType { get; set; }// Via-point Cartesian position that defines the arc.public CartesianPositionWithUserFrame Via { get; set; }// When <code>true</code>, enables wrist-joint mode for this motion.public bool WristJoint { get; set; }}
public class SplineMotionTpInstruction : CartesianMotionTpInstructionBase {public SplineMotionTpInstruction()// Speed unit (mm/s, inch/min, or time).public RmiLinearSpeedType SpeedType { get; set; }}
public abstract class FullMotionTpInstructionBase : MotionTpInstructionBase {protected FullMotionTpInstructionBase()// Optional acceleration override (1-100 %). <code>null</code> uses the controller default.public byte? Acc { get; set; }// Lock-and-continue (LCB) condition type string. <code>null</code> disables LCB.public string LcbType { get; set; }// Lock-and-continue (LCB) condition value. Required when <xref href="UnderAutomation.Fanuc.Rmi.TpInstructions.FullMotionTpInstructionBase.LcbType" data-throw-if-not-resolved="false"></xref> is set.public short? LcbValue { get; set; }// Offset position register number. <code>null</code> disables offset.public short? OffsetPrNumber { get; set; }// Digital output port number. Required when <xref href="UnderAutomation.Fanuc.Rmi.TpInstructions.FullMotionTpInstructionBase.PortType" data-throw-if-not-resolved="false"></xref> is set.public short? PortNumber { get; set; }// Digital output port type to trigger at the end of this motion. <code>null</code> disables output.public RmiPortType? PortType { get; set; }// Digital output port value. Required when <xref href="UnderAutomation.Fanuc.Rmi.TpInstructions.FullMotionTpInstructionBase.PortType" data-throw-if-not-resolved="false"></xref> is set.public RmiOnOff? PortValue { get; set; }// Tool-offset position register number. <code>null</code> disables tool offset. Requires MajorVersion >= 4.public short? ToolOffsetPrNumber { get; set; }// Vision offset position register number. <code>null</code> disables vision offset.public short? VisionPrNumber { get; set; }}
public class RmiInstructionResponse : RmiResponseBase {public RmiInstructionResponse()public override bool Equals(object obj)public override int GetHashCode()// Sent instructionpublic RmiInstructionBase Instruction { get; }// Sequence identifier assigned to this instruction. 0 until the instruction has been dispatched to the controller.public int SequenceId { get; }// Current execution state of the instruction.public RmiInstructionStatus Status { get; }// Fired each time <xref href="UnderAutomation.Fanuc.Rmi.Data.RmiInstructionResponse.Status" data-throw-if-not-resolved="false"></xref> changes. The argument is the new status value.// This event may be raised from a background thread.public event Action<RmiInstructionStatus> StatusChangedpublic override string ToString()// Blocks the calling thread until the instruction reaches a terminal state// (<xref href="UnderAutomation.Fanuc.Rmi.Data.RmiInstructionStatus.Completed" data-throw-if-not-resolved="false"></xref> or <xref href="UnderAutomation.Fanuc.Rmi.Data.RmiInstructionStatus.Error" data-throw-if-not-resolved="false"></xref>),// or until <code class="paramref">timeoutMs</code> milliseconds have elapsed.// Pass -1 (or omit) to wait indefinitely.public bool WaitForCompletion(int timeoutMs = -1)}