C# Library: PRC.GRPC
The C# reference library contains a level of abstraction beyond the underlying GRPC integration. Most code is available in the PRC.GRPC namespace. The library targets NET8 to improve compatibility. It can be run from newer runtimes such as .NET 10 (as the PRC.Server is doing) without any problems.
Connect#
To create a program, instantiate the Client class from PRC.GRPC.Client
Client client = new Client();
var connectFeedback = await client.Connect(ip);Handle Events#
To get updates from the simulation, subscribe to the provided events when either the robot's state or its settings are updated.
client.RobotStateUpdatedEventHandler += new EventHandler<Client.RobotStateUpdatedEventArgs>(RobotStateUpdated);
client.RobotSettingsUpdatedEventHandler += new EventHandler<Client.RobotSettingsUpdatedEventArgs>(RobotSettingsUpdated);
////////////////////////////
internal static void RobotStateUpdated(object sender, Client.RobotStateUpdatedEventArgs e)
{
Console.WriteLine("New update at " + e.RobotState.NormalizedToolpathFactor);
}
internal static void RobotSettingsUpdated(object? sender, Client.RobotSettingsUpdatedEventArgs e)
{
Console.WriteLine("Robot settings updated. New settings are: " + e.RobotSettings.ToString());
}Create a Robot#
To create a program, instantiate the Client class from PRC.GRPC.Client
Next up, create a robot and set its default tool and base. With this information you can now setup the robot itself. Choose a unique ID and select the right driver, such as KUKA.KSS_KRL_Driver. The setupFeedback variable then also contains the current default settings of the driver.
PRC.Library.Robots.KUKA.KUKA_KR610R11002 robot = new PRC.Library.Robots.KUKA.KUKA_KR610R11002();
PRC.Core.Classes.Tool tool = new PRC.Core.Classes.Tool();
robot.ToolDictionary = new Dictionary<string, PRC.Core.Classes.Tool>
{
["0"] = tool
};
robot.InitialBase = new PRC.Core.Classes.Base();
var setupFeedback = await client.SetupRobot("Unique robot ID", robot, "KUKA.KSS_KRL_Driver");`Define the Program#
Now create a base Task and add the relevant Motion Groups, in the example a PTP Motion Group containing two Axis motions.
PRC.Core.Commands.Task robotTask = new PRC.Core.Commands.Task();
robotTask.TaskType = PRC.Core.Primitives.Enums.TaskType.SimulateAndExecuteTask;
robotTask.Name = "InitTest";
PRC.Core.Commands.Motion.Groups.PTPMotionGroup ptpMotionGroup = new PRC.Core.Commands.Motion.Groups.PTPMotionGroup();
ptpMotionGroup.Base = new PRC.Core.Classes.Base();
ptpMotionGroup.ToolID = "0";
ptpMotionGroup.Interpolation = "C_PTP";
ptpMotionGroup.PTPMotions = new PRC.Core.Interfaces.IMotion[2];
ptpMotionGroup.PTPMotions[0] = (new PRC.Core.Commands.Motion.Axis()
{
Target = new PRC.Core.Primitives.JointTarget()
{
AxisValues = new float[] { -45, -90, 90, 0, 0, 0 },
Speed = new float[] { 0.15f }
}
});
ptpMotionGroup.PTPMotions[1] = (new PRC.Core.Commands.Motion.Axis()
{
Target = new PRC.Core.Primitives.JointTarget()
{
AxisValues = new float[] { 45, -90, 90, 0, 0, 0 },
Speed = new float[] { 0.15f }
}
});
robotTask.Commands.Add(ptpMotionGroup);Run the Program#
Finally, add the task to the server and wait for the result. This will, for example, include the robot code to be executed at the robot. The example below writes the KRL code into a console window.
var simFeedback = await client.AddTask(robotTask, setupFeedback.Settings);
Console.WriteLine("KRL Code: " + Environment.NewLine + (simFeedback.Result.Code ?? "No code generated") + Environment.NewLine);Further Client Capabilities#
Beyond the basic lifecycle above, the Client class provides:
UpdateRobot(float simulationState, bool streamFeedback = false, bool includeVariables = false)– queries the robot state at a normalized toolpath position (0.0–1.0), e.g. for driving a simulation slider. By default the reply omits the variable map (which otherwise carries every connected robot's variables on every query), keeping slider polls small – passincludeVariables: trueif you need it, or read variables viaQueryVariables()/UpdateVariable().UpdateVariable(Variable variable)– sets or updates a robot variable and returns the variables of all connected robots.UpdateVariableChecked(Variable variable)– likeUpdateVariable, but returns an explicit server acknowledgement (success, message, and the variable map), so callers can distinguish a delivered update from a dropped one.GetRobotData()– retrieves the resolved robot definition (per-joint geometry, kinematics, tools, base, collision geometry, external axes) after a successfulSetupRobot. The reply also carries the machine's live state: current driver settings, variables, axis position (including external axes), Cartesian tool and flange frames, and the per-element visualization transformations.GetMachineData(id, excludeGeometry = true)– the same query for any connected machine by its ID, e.g. from a Supervisor client monitoring other machines. With geometry excluded, the reply shrinks from ~900 KB to under 1 KB for a KR6, making it cheap enough to poll at 30–60 Hz.QueryVariables()– reads the current variables of all connected machines without writing a variable.Ping(),Disconnect()andReconnect()– connection health check, graceful shutdown, and a full reconnect that re-establishes the connection, robot setup, and last task.Reconnectresends the originally sent setup payload, so later modifications to the shared robot instance do not change what is re-sent.- Cancellation:
AddTaskaccepts an optionalCancellationToken. A cancelled call returns an error feedback ("Task superseded by a newer request.") instead of throwing – useful when a newer task supersedes one that is still simulating. - Timeouts: All calls carry client-side deadlines, settable per client instance:
ShortCallTimeout(default 10 s, forUpdateRobot/UpdateVariable/Ping),SetupTimeout(default 60 s), andTaskTimeout(default 10 min, covering simulation plus code generation of large toolpaths). A timed-out or failed call returns an error feedback rather than throwing. - Progress & liveness:
SimulationProgressreports the simulation progress in percent (0–100) from the server heartbeat (also available via theSimulationProgressEventHandlerevent), e.g. for progress bars during longAddTaskcalls.LastFeedbackUtcholds the time of the last received feedback message – since the server heartbeats every second, a stale value can be used as a liveness watchdog. CallClearEvents()to unsubscribe all event handlers.
You can download the full code from here:
github.com PRC.IntegrationsThe PRC.GRPC.dll, PRC.Library.dll and PRC.Core.dll are part of the Download package.
Parametric Robot Control