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(id = null)– the robot as the server resolved it, as aPRC.Core.Classes.Robot: itsProperties(definition, kinematics, tools, base, external axes, collision geometry), its liveState(axis position including external axes, tool and flange frames, visualization transformations), itsVariableDirectory, and aDriverinstance holding the server's current settings (read them withDriver.Settings.ToDictionary(); this driver is never connected). Without anidit returns this client's robot, with one any set-up machine. ItsPropertiescan be passed toSetupRobotagain as they are.GetMachineData(id, excludeGeometry = true)– the same for any connected machine by its ID, e.g. from a Supervisor client monitoring other machines; with geometry excluded, no meshes are transferred. The conversion takes tens of milliseconds, so for polling at 30–60 Hz call theGetRobotDatarpc directly.RobotProperties– the robot properties this client was set up with (your own instance, not the server's resolved robot).QueryVariables()– reads the current variables of all connected machines without writing a variable.DescribeLibrary(driverClass = "")– the setup catalog of the connected server as aJsonObjectwith the proto's field names (robots,drivers,external_axes): every preset robot, every driver with its settings schema and every external-axis preset. It needs onlyConnect, no robot setup; pass a driver class to get just that driver's schema.Result.Fileson theSimulationFeedbackreturned byAddTask– every generated program file with its name and content, the primary program first (Result.Codeis the primary file's text). Write all of them; a driver such as KSS on iiQKA.OS 2 can produce more than one file.Ping(),Disconnect()andReconnect()– connection health check (returns the server's current time), 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.IntegrationsGet the PRC.GRPC.dll, PRC.Library.dll and PRC.Core.dll from the Developer download page at the Download page.
