Fanuc SDK documentation
RMI overview
RMI (Remote Motion Interface) is a TCP-based protocol for sending motion commands, managing frames, and controlling the robot remotely.
RMI (Remote Motion Interface) is a TCP-based protocol that lets you send TP-equivalent motion instructions and administrative commands to a Fanuc controller in real time.
Robot requirements
- Option R912 (Remote Motion Interface) must be loaded on the controller.
- The bootstrap port is 16001 (TCP).
- Before calling
Initialize(), the teach pendant must be disabled and the controller must be in AUTO mode. - Do not leave the RMI_MOVE TP program selected on the teach pendant before calling
Initialize().
How it works
- Connect to the controller on the bootstrap port (16001). The controller assigns a working port for the session.
- Call
Initialize()to create theRMI_MOVETP program and start it. - Send motion or non-motion instructions via
SendTpInstruction(). Each call returns anRmiInstructionResponseyou can track. - The client manages the 8-slot controller buffer automatically. Instructions beyond that limit are held locally and sent as soon as a slot is free.
- When done, call
Abort()orDisconnect(). Always end your session with one of those; otherwise the controller keeps RMI_MOVE selected and other TP programs cannot run.
Quick example
// Initialize the RMI_MOVE program on the controller.// TP must be disabled and the controller must be in AUTO mode.robot.Rmi.Initialize();// Linear motion at 100 mm/s to a Cartesian target (tool 1, frame 0)var instr = new LinearMotionTpInstruction{SpeedType = RmiLinearSpeedType.MmSec,Speed = 100,TermType = RmiTerminationType.Fine,Target = new CartesianPositionWithUserFrame(500, 200, 300, 0, 90, 0, tool: 1, frame: 0)};RmiInstructionResponse r = robot.Rmi.SendTpInstruction(instr);// Wait for the controller to confirm the motion completedr.WaitForCompletion();if (r.Status == RmiInstructionStatus.Error)System.Console.WriteLine("Error: " + r.ErrorText);// Abort when done — always end the session with Abort() or Disconnect()robot.Rmi.Abort();robot.Disconnect();
Connection
// Enable RMI and connect. The bootstrap port is 16001.// The controller assigns a working port automatically.ConnectionParameters parameters = new ConnectionParameters("192.168.0.1");parameters.Rmi.Enable = true;robot.Connect(parameters);System.Console.WriteLine("Connected: " + robot.Rmi.Connected);System.Console.WriteLine("Protocol version: " + robot.Rmi.MajorVersion + "." + robot.Rmi.MinorVersion);System.Console.WriteLine("Working port: " + robot.Rmi.WorkingPort);// Subscribe to events before sending instructionsrobot.Rmi.SystemFaultReceived += seqId =>System.Console.WriteLine("System fault on sequence " + seqId);robot.Rmi.ConnectionTerminated += () =>System.Console.WriteLine("Controller closed the RMI session");robot.Rmi.RecordedCartesianPositionReceived += pos =>System.Console.WriteLine("Recorded position " + pos.PositionId);robot.Disconnect();
Initialize and status
Call Initialize() after connecting. Check the controller state with GetStatus() first if needed.
// Check controller state before initializingRmiControllerStatusResponse status = robot.Rmi.GetStatus();System.Console.WriteLine("Servo ready: " + status.ServoReady);System.Console.WriteLine("TP enabled: " + status.TPEnabled);System.Console.WriteLine("RMI running: " + status.RmiMotionStatus);// Initialize: creates and starts the RMI_MOVE TP program.// Will throw if TP is enabled or servos are off.robot.Rmi.Initialize();// For multi-group controllers, specify a group mask (bit N = group N+1)// robot.Rmi.Initialize(groupMask: 0b00000011); // groups 1 and 2// Enable real-time singularity avoidance (requires MajorVersion >= 6, R792 option)// robot.Rmi.Initialize(rtsa: true);// Set palletizing motion mode (requires MajorVersion >= 7)// robot.Rmi.Initialize(pltzMode: RmiPltzMode.ZeroDown);System.Console.WriteLine("RMI initialized");// The controller checks sequence IDs by default.// AutoSetNextSequenceId() resynchronizes the counter if needed.robot.Rmi.AutoSetNextSequenceId();robot.Rmi.Abort();robot.Disconnect();
Instruction pipeline
SendTpInstruction() returns an RmiInstructionResponse immediately. The instruction goes through several states:
| Status | Meaning |
|---|---|
LocalQueued | Held in the client buffer, not yet sent (controller buffer full). |
ControllerQueued | Sent to the controller, waiting its turn. |
Executing | The robot is currently executing this instruction. |
Completed | Done without error. |
Error | Failed. Check ErrorId and ErrorText. |
Call WaitForCompletion() to block until the instruction reaches a terminal state.
Next steps
- Motion commands: linear, joint, circular, spline motions and non-motion instructions.
- Frames, I/O & status: frame management, I/O, position reading, registers.
API reference
Members of Rmi.RmiClient :public class RmiClient : RmiClientBase, IDisposable {// Creates a new instance of the RMI client.public RmiClient()// Connect to the FANUC controller using the RMI protocol.public void Connect(string ip, int port = 16001, int readTimeoutMs = 2000)}
public abstract class RmiClientBase : IDisposable {// Creates a new instance of the RMI client.public RmiClientBase()// Abort the running motion program. Note that a Reset() will be called automatically if the controller is in the HOLD state.public void Abort()// Calls internally <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.GetStatus" data-throw-if-not-resolved="false"></xref> and set <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.LastSequenceId" data-throw-if-not-resolved="false"></xref> only if $RMI_CFG.$Chk_seqID = FALSE. It also set <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.CheckSequenceId" data-throw-if-not-resolved="false"></xref> to $RMI_CFG.$Chk_seqID.public RmiControllerStatusResponse AutoSetNextSequenceId()// Indicates whether the controller checks for consecutive sequence IDs in motion instructions ($RMI_CFG.$Chk_seqID). Modified by <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.AutoSetNextSequenceId" data-throw-if-not-resolved="false"></xref>.public bool CheckSequenceId { get; set; }// Removes all instructions with a terminal status (<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>) from the tracked instruction list.// Instructions that are still pending or in progress are not affected.public void ClearCompletedInstructions()// Cancels and removes all instructions that are still in the local client buffer// (<xref href="UnderAutomation.Fanuc.Rmi.Data.RmiInstructionStatus.LocalQueued" data-throw-if-not-resolved="false"></xref>). These instructions have not been sent// to the controller yet. Each cancelled instruction is marked with an error so that any// thread blocked on <xref href="UnderAutomation.Fanuc.Rmi.Data.RmiInstructionResponse.WaitForCompletion(System.Int32)" data-throw-if-not-resolved="false"></xref> is unblocked.// Instructions already sent to the controller are not affected.public void ClearLocalQueuedInstructions()// Connect to the controller: perform the bootstrap handshake on the given port,// obtain the working port, then switch to it for all subsequent commands.protected void ConnectInternal(string host, int port, int readTimeoutMs = 2000)// Indicates that the client is currently connected to the controller working port.public bool Connected { get; }// Fired when the controller closes the session (e.g. communication idle timeout).// The client is automatically disconnected after this event fires.public event Action ConnectionTerminated// Resume a paused motion program.public void Continue()// Disconnect from the controller by sending the disconnect command on the working port.// Safe to call even when already disconnected.public void Disconnect()// Disconnect from the controller and release resources.public void Dispose()// Get extended controller status including drive power state and speed clamp.public RmiExtendedControllerStatusResponse GetExtendedStatus()// Get the current controller and RMI motion status.public RmiControllerStatusResponse GetStatus()// Get the current UFRAME and UTOOL numbers.public RmiUFrameUToolNumbersResponse GetUFrameUTool(byte? group = null)// Initialize RMI and start the motion program. Must be called before sending any motion instructions.// It also Resets <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.LastSequenceId" data-throw-if-not-resolved="false"></xref> and empty the instruction buffer <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.Instructions" data-throw-if-not-resolved="false"></xref>public void Initialize(byte? groupMask = null, bool? rtsa = null, RmiPltzMode? pltzMode = null)// All instructions submitted since the last <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.Initialize(System.Nullable%7bSystem.Byte%7d%2cSystem.Nullable%7bSystem.Boolean%7d%2cSystem.Nullable%7bUnderAutomation.Fanuc.Rmi.Data.RmiPltzMode%7d)" data-throw-if-not-resolved="false"></xref> or explicit clear,// in submission order. Includes instructions in all states: <xref href="UnderAutomation.Fanuc.Rmi.Data.RmiInstructionStatus.LocalQueued" data-throw-if-not-resolved="false"></xref>,// <xref href="UnderAutomation.Fanuc.Rmi.Data.RmiInstructionStatus.ControllerQueued" data-throw-if-not-resolved="false"></xref>, <xref href="UnderAutomation.Fanuc.Rmi.Data.RmiInstructionStatus.Executing" data-throw-if-not-resolved="false"></xref>,// <xref href="UnderAutomation.Fanuc.Rmi.Data.RmiInstructionStatus.Completed" data-throw-if-not-resolved="false"></xref> and <xref href="UnderAutomation.Fanuc.Rmi.Data.RmiInstructionStatus.Error" data-throw-if-not-resolved="false"></xref>.// Returns a snapshot array; the array is not updated after it is returned.public RmiInstructionResponse[] Instructions { get; }// Indicates that the controller has entered the HOLD state and will not accept new TP instructions// until <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.Reset" data-throw-if-not-resolved="false"></xref> is called.//// <p>// The HOLD state is entered in two situations:// </p>// <ul><li>// An invalid sequence ID was detected (error RMIT-029, error code 2556957). RMI checks that sequence IDs are// consecutive. If a gap is found, RMI rejects the instruction and enters HOLD. The controller continues// executing the TP instructions already queued but blocks all new ones. Use <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.AutoSetNextSequenceId" data-throw-if-not-resolved="false"></xref>// to recover the correct sequence ID, then call <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.Reset" data-throw-if-not-resolved="false"></xref> before resuming.// </li><li>// An invalid motion instruction was received (error RMIT-024, error code 2556952), for example a motion// option that is not loaded on the controller. RMI returns an error for that instruction, puts the// controller in HOLD, and continues executing any instructions already in the TP program queue. Call// <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.Reset" data-throw-if-not-resolved="false"></xref> once the problem is corrected, then resume sending instructions.// </li></ul>// <p>// All instructions sent while in the HOLD state are ignored by the controller and returned with an error code.// This flag is cleared automatically when <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.Reset" data-throw-if-not-resolved="false"></xref> succeeds.// </p>public bool IsInHoldState { get; }// Sequence ID used for the last instruction sent to the controller. Reset to 0 by <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.Initialize(System.Nullable%7bSystem.Byte%7d%2cSystem.Nullable%7bSystem.Boolean%7d%2cSystem.Nullable%7bUnderAutomation.Fanuc.Rmi.Data.RmiPltzMode%7d)" data-throw-if-not-resolved="false"></xref>.. Modified by <xref href="UnderAutomation.Fanuc.Rmi.Internal.RmiClientBase.AutoSetNextSequenceId" data-throw-if-not-resolved="false"></xref>.public int LastSequenceId { get; }// Controller protocol major version reported during the connection handshake.public short MajorVersion { get; }// Controller protocol minor version reported during the connection handshake.public short MinorVersion { get; }// Pause the running motion program.public void Pause()// Read current Cartesian TCP position.public RmiCartesianPositionResponse ReadCartesianPosition(byte? group = null)// Read a digital input port value.public RmiDigitalInputValueResponse ReadDIN(short portNumber)// Read the most recent controller error text. Up to 5 consecutive errors can be requested.public RmiControllerErrorTextResponse ReadError(byte? count = null)// Read a generic IO port (DI, DO, AI, AO, GO, RO, FLAG, RI, UI, UO).public RmiIoPortValueResponse ReadIOPort(RmiIoPortType portType, int portNumber)// Read current joint angles.public RmiJointAnglesSampleResponse ReadJointAngles(byte? group = null)// Read a numeric registerpublic RmiNumericRegisterValueResponse ReadNumericRegister(int number)// Read a position registerpublic RmiPositionRegisterDataResponse ReadPositionRegister(short number, byte? group = null)// Read the current TCP speed in mm/s.public RmiTcpSpeedResponse ReadTcpSpeed()// RMI connection parameters used during Connect().public int ReadTimeoutMs { get; }// Read the UFRAME at the given index.public RmiIndexedFrameResponse ReadUFrame(byte number, byte? group = null)// Read the UTOOL at the given index.public RmiIndexedFrameResponse ReadUTool(byte number, byte? group = null)// Read a system variable by name (name must include the leading <code>$</code> character).public RmiVariableValueResponse ReadVariable(string name)// Fired when the controller sends a Cartesian position via the RMI Position Record menu.public event Action<RmiRecordedCartesianPosition> RecordedCartesianPositionReceived// Fired when the controller sends a joint position via the RMI Position Record menu.public event Action<RmiRecordedJointPosition> RecordedJointPositionReceived// Reset controller errors and exit the HOLD state.public void Reset()// Serializes the instruction to the RMI wire format and queues it on the controller.// Returns an <xref href="UnderAutomation.Fanuc.Rmi.Data.RmiInstructionResponse" data-throw-if-not-resolved="false"></xref> that tracks execution.public RmiInstructionResponse SendTpInstruction(RmiInstructionBase instruction)// Set the program speed override (1–100 %).public void SetOverride(byte value)// Define payload compensation parameters for a payload schedule.public void SetPayloadCompensation(byte scheduleNumber, float massKg, float cgXm, float cgYm, float cgZm, float inertiaXkgm2, float inertiaYkgm2, float inertiaZkgm2, byte? group = null)// Define payload compensation parameters for a payload schedule.public void SetPayloadCompensation(RmiSetPayloadCompensationParameters p)// Immediately apply a payload schedule to the active group (command, not an instruction).public void SetPayloadSchedule(byte scheduleNumber, byte? group = null)// Define payload mass, center of gravity, and optionally inertia for a payload schedule.public void SetPayloadValue(byte scheduleNumber, float massKg, float cgXm, float cgYm, float cgZm, float? inertiaXkgm2 = null, float? inertiaYkgm2 = null, float? inertiaZkgm2 = null, byte? group = null)// Define payload mass, center of gravity, and optionally inertia for a payload schedule.public void SetPayloadValue(RmiSetPayloadParameters p)// Set the current UFRAME and UTOOL numbers.public void SetUFrameUTool(byte uframe, byte utool, byte? group = null)// Fired when the controller reports a system fault on a given sequence.// The argument is the SequenceID of the faulted instruction (0 when unknown).public event Action<int> SystemFaultReceived// Fired when an unknown packet is received from the controller.public event Action<RmiResponseBase> UnknownPacketReceived// Working port returned by the controller; all commands use this port after connection.public int WorkingPort { get; }// Write a digital output port value.public void WriteDOUT(short portNumber, RmiOnOff value)// Write a generic IO port (AO, GO, DO, RO, FLAG).public void WriteIOPort(RmiIoPortType portType, int portNumber, double value)// Write a float value to a numeric registerpublic void WriteNumericRegisterAsDouble(int number, double value)// Write an integer value to a numeric registerpublic void WriteNumericRegisterAsInteger(int number, int value)// Write a Cartesian position registerpublic void WritePositionRegisterCartesian(short number, CartesianPositionWithUserFrame target, byte? group = null)// Write the UFRAME at the given index.public void WriteUFrame(byte number, XYZWPRPosition position, byte? group = null)// Write the UTOOL at the given index.public void WriteUTool(byte number, XYZWPRPosition position, byte? group = null)// Write a float value to a system variable (name must include the leading <code>$</code>).public void WriteVariableAsDouble(string name, double value)// Write an integer value to a system variable (name must include the leading <code>$</code>).public void WriteVariableAsInteger(string name, int value)}
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)}
public class RmiControllerStatusResponse : RmiResponseBase {public RmiControllerStatusResponse()// Indicates the value of $RMI_CFG.$Chk_seqID, which is the configuration value that determines whether the controller checks valid incremented sequence IDs on incoming instructions.public bool CheckSequenceId { get; }public override bool Equals(object obj)public override int GetHashCode()// The next valid sequence ID. This key is only valid if the system variable $RMI_CFG.$Chk_seqID = TRUEpublic int? NextSequenceId { get; set; }// Number of user frames available in the robot controllerpublic byte NumberUFrame { get; set; }// Number of user tools available in the robot controllerpublic byte NumberUTool { get; set; }// RMI_MOVE program statuspublic TaskStatus ProgramStatus { get; set; }// The Remote Motion Interface is runningpublic bool RmiMotionStatus { get; set; }// The robot controller is ready for motionpublic bool ServoReady { get; set; }// Single step modepublic bool SingleStepMode { get; set; }// The current speed override setting (1–100).public byte SpeedOverride { get; set; }// Teach Pendant Enabled (Switch on position ON) The Remote Motion interface only works when the teach pendant is disabledpublic bool TPEnabled { get; set; }public override string ToString()}