APIs, concepts, guides, and more
Quick Start

Learn how to use RapidCodeRemote (gRPC) for remote control of RMP hardware in C#.

Warning
This is a sample program to assist in the integration of the RMP motion controller with your application. It may not contain all of the logic and safety features that your application requires. We recommend that you wire an external hardware emergency stop (e-stop) button for safety when using our code sample apps. Doing so will help ensure the safety of you and those around you and will prevent potential injury or damage.

The sample apps assume that the system (network, axes, I/O) are configured prior to running the code featured in the sample app. See the Configuration page for more information.


In this page:


📜 Client Creation

Learn how to set up the gRPC client to communicate with the RapidServer.

// create grpc channel and clients
var address = $"http://{Constants.RAPIDSERVER_IP}:{Constants.RAPIDSERVER_PORT}";
var channel = GrpcChannel.ForAddress(address); // grpc channel used to communicate with the server
var serverClient = new ServerControlServiceClient(channel); // grpc client for using the ServerControlService
var rmpClient = new RMPServiceClient(channel); // grpc client for using the RMPService


📜 Server Info

Learn how to query server details and verify connection. Shows how to retrieve server name, ID, and version information.

// request and display basic information about the server
void ServerInfoGet(ServerControlServiceClient client)
{
Console.WriteLine("\n 📜 Server Info");
ServerGetInfoRequest infoRequest = new ServerGetInfoRequest();
ServerGetInfoResponse infoResponse = client.GetInfo(infoRequest);
CheckErrors(infoResponse.Header);
Console.WriteLine($"Connected to server named '{infoResponse.Name}' with ID: {infoResponse.Id:X}");
Console.WriteLine($"Server version: {infoResponse.Version}");
}


📜 Controller Creation

Learn how to create a remote MotionController on the server. Shows how to initialize the motion control system via gRPC.

// create the MotionController on the server
void ControllerCreate(RMPServiceClient client)
{
Console.WriteLine("\n 📜 Controller Create");
MotionControllerResponse motionControllerResponse = client.MotionController(new MotionControllerRequest
{
Action = new MotionControllerAction { Create = new MotionControllerCreationParameters() }
});
CheckErrors(motionControllerResponse.Header);
Console.WriteLine("Motion Controller created successfully");
}


📜 Controller Shutdown

Learn how to properly shutdown the remote motion controller. Shows how to cleanly terminate the motion control system.

// shutdown the motion controller
void ControllerShutdown(RMPServiceClient client)
{
Console.WriteLine("\n 📜 Controller Shutdown");
client.MotionController(new MotionControllerRequest
{
Action = new MotionControllerAction { Shutdown = new MotionControllerAction.Types.Shutdown() }
});
Console.WriteLine("Motion Controller shut down successfully");
}


📜 Network Start

Learn how to start the EtherCAT network.

void NetworkStart(bool discoverBeforeStart = false)
{
Console.WriteLine("\n 📜 Network Start");
var action = new NetworkAction();
if (discoverBeforeStart)
action.DiscoverAndStart = new NetworkAction.Types.DiscoverAndStart();
else
action.Start = new NetworkAction.Types.Start();
NetworkResponse networkResponse = rmpClient.Network(new NetworkRequest
{
Action = action
});
CheckErrors(networkResponse.Header);
}
#pragma warning restore CS8321


📜 Axis Count

Learn how to set the axis count for phantom axes. Shows how to configure the number of axes remotely.

// set the axis count so we have phantom axes to work with
void AxisCountSet(RMPServiceClient client)
{
Console.WriteLine("\n 📜 Axis Count");
MotionControllerResponse motionControllerResponse = client.MotionController(new MotionControllerRequest
{
Config = new MotionControllerConfig { AxisCount = Constants.AXIS_COUNT }
});
CheckErrors(motionControllerResponse.Header);
Console.WriteLine($"Axis count set to: {motionControllerResponse.Config.AxisCount}");
}


📜 Axis Status

Learn how to check axis state and status remotely. Shows how to retrieve current axis information via gRPC.

// check the state of the axis at index 0
void AxisStatusGet(RMPServiceClient client)
{
Console.WriteLine("\n 📜 Axis Status");
AxisResponse axisResponse = client.Axis(new AxisRequest { Index = Constants.AXIS_0_INDEX });
CheckErrors(axisResponse.Header);
Console.WriteLine($"Axis {Constants.AXIS_0_INDEX} state: {axisResponse.Status.State}");
}


📜 Axis Motion: Point-to-Point

Learn how to execute simple position moves remotely. Shows how to configure axis, clear faults, and command point-to-point moves.

// demonstrate a simple point-to-point move
void AxisMotionPointToPoint(RMPServiceClient client)
{
Console.WriteLine("\n 📜 Axis Motion: Point-to-Point");
// configure the axis for phantom use
AxisResponse axisResponse = client.Axis(new AxisRequest
{
Index = Constants.AXIS_0_INDEX,
Config = new AxisConfig
{
UserUnits = 1000,
ErrorLimit = new AxisConfig.Types.ErrorLimit { Action = RSIAction.None } // ignore position errors for phantom axis
}
});
CheckErrors(axisResponse.Header);
// clear any faults and set initial position
axisResponse = client.Axis(new AxisRequest
{
Index = Constants.AXIS_0_INDEX,
Action = new AxisAction
{
ClearFaults = new AxisAction.Types.ClearFaults(),
PositionSet = new AxisAction.Types.PositionSet { Position = 0 }
}
});
CheckErrors(axisResponse.Header);
// command a point-to-point move from position 0 to position 10
var moveAction = new AxisAction
{
Move = new AxisAction.Types.Move
{
PointToPoint = new AxisMovePointToPoint
{
Acceleration = 100,
Deceleration = 100,
Velocity = 10,
Position = 10,
JerkPercent = 50
}
}
};
axisResponse = client.Axis(new AxisRequest { Index = Constants.AXIS_0_INDEX, Action = moveAction });
CheckErrors(axisResponse.Header);
Console.WriteLine($"Commanded move to position 10");
// wait for motion to complete
System.Threading.Thread.Sleep(1000);
// check final position
axisResponse = client.Axis(new AxisRequest { Index = Constants.AXIS_0_INDEX });
CheckErrors(axisResponse.Header);
Console.WriteLine($"Final command position: {axisResponse.Status.Position.Command}");
}


📜 Axis Motion: Streaming

Learn how to continuously stream motion points for complex trajectories. Shows how to send batches of streaming points and manage motion execution.

// demonstrate streaming motion with continuously added points
void AxisMotionStreaming(RMPServiceClient client)
{
Console.WriteLine("\n 📜 Axis Motion: Streaming");
// configure the axis
AxisResponse axisResponse = client.Axis(new AxisRequest
{
Index = Constants.AXIS_0_INDEX,
Config = new AxisConfig
{
UserUnits = 1000,
ErrorLimit = new AxisConfig.Types.ErrorLimit { Action = RSIAction.None }
}
});
CheckErrors(axisResponse.Header);
// wait for any previous motion to complete
Console.WriteLine("Waiting for axis to stop moving...");
while (true)
{
axisResponse = client.Axis(new AxisRequest { Index = Constants.AXIS_0_INDEX });
CheckErrors(axisResponse.Header);
if (axisResponse.Status.State != RSIState.Moving)
break;
System.Threading.Thread.Sleep(100);
}
// clear faults and set initial position
axisResponse = client.Axis(new AxisRequest
{
Index = Constants.AXIS_0_INDEX,
Action = new AxisAction
{
ClearFaults = new AxisAction.Types.ClearFaults(),
PositionSet = new AxisAction.Types.PositionSet { Position = 0 }
}
});
CheckErrors(axisResponse.Header);
// get initial motion id
int originalMotionId = (int)axisResponse.Status.MotionId;
// create first batch of streaming points (sine wave pattern)
var streamingMove = new MoveStreaming();
int numPoints = 100;
double amplitude = 1.0;
for (int i = 0; i < numPoints; i++)
{
double position = Math.Sin(i / (double)numPoints * 2 * Math.PI) * amplitude;
streamingMove.Positions.Add(position);
streamingMove.Times.Add(1.0 / numPoints);
}
streamingMove.EmptyCount = 50;
streamingMove.Retain = false;
streamingMove.Final = false;
// send first streaming move
var moveAction = new AxisAction
{
Move = new AxisAction.Types.Move { Streaming = streamingMove }
};
axisResponse = client.Axis(new AxisRequest { Index = Constants.AXIS_0_INDEX, Action = moveAction });
CheckErrors(axisResponse.Header);
Console.WriteLine("Sent first streaming move batch");
// add additional batches while motion executes
int previousMotionId = (int)axisResponse.Status.MotionId - 1;
for (int batch = 2; batch <= 5; batch++)
{
// wait for previous batch to start executing
while (true)
{
axisResponse = client.Axis(new AxisRequest { Index = Constants.AXIS_0_INDEX });
CheckErrors(axisResponse.Header);
if (axisResponse.Status.MotionIdExecuting >= previousMotionId)
break;
System.Threading.Thread.Sleep(10);
}
// create next batch with increasing amplitude
streamingMove = new MoveStreaming();
amplitude = batch;
for (int i = 0; i < numPoints; i++)
{
double position = Math.Sin(i / (double)numPoints * 2 * Math.PI) * amplitude;
streamingMove.Positions.Add(position);
streamingMove.Times.Add(1.0 / numPoints);
}
streamingMove.EmptyCount = 50;
streamingMove.Retain = false;
streamingMove.Final = (batch == 5); // mark last batch as final
moveAction = new AxisAction
{
Move = new AxisAction.Types.Move { Streaming = streamingMove }
};
axisResponse = client.Axis(new AxisRequest { Index = Constants.AXIS_0_INDEX, Action = moveAction });
CheckErrors(axisResponse.Header);
previousMotionId = (int)axisResponse.Status.MotionId - 1;
Console.WriteLine($"Sent streaming batch {batch} (amplitude={amplitude}, final={streamingMove.Final})");
}
// wait for motion to complete
Console.WriteLine("Waiting for streaming motion to complete...");
while (true)
{
// get motion status
axisResponse = client.Axis(new AxisRequest { Index = Constants.AXIS_0_INDEX });
CheckErrors(axisResponse.Header);
if (axisResponse.Status.State != RSIState.Moving)
break;
System.Threading.Thread.Sleep(100);
}
Console.WriteLine($"Streaming motion complete. Final state: {axisResponse.Status.State}");
Console.WriteLine($"Final command position: {axisResponse.Status.Position.Command}");
}


📜 Error Handling

Learn how to check RPC responses for errors. Shows how to validate server responses and handle error conditions.

// check response header for errors and throw if any exist
void CheckErrors(RSI.RapidServer.ResponseHeader header)
{
if (header.Errors.Count > 0)
{
string message = "RPC had errors:\n";
foreach (var error in header.Errors)
{
message += $" {error.Message}\n";
}
throw new Exception(message);
}
}