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.
To create a program, instantiate the Client class from PRC.GRPC.Client
Client client = new Client();
var connectFeedback = await client.Connect(ip);
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());
}
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");`
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);
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);
Beyond the basic lifecycle above, the Client class provides:
UpdateRobot(float simulationState, bool streamFeedback = false) – queries the robot state at a normalized toolpath position (0.0–1.0), e.g. for driving a simulation slider.