Example driver

In the examples subfolder you will find a minimal example of a running driver. It starts an instance of the UrDriver class and prints the RTDE values read from the controller. To run it make sure to

  • have an instance of a robot controller / URSim running at the configured IP address (or adapt the address to your needs)

  • run it from the package’s main folder (the one where the README.md file is stored), as for simplicity reasons it doesn’t use any sophisticated method to locate the required files.

This page will walk you through the full_driver.cpp example.

Initialization

At first, we create a ExampleRobotWrapper object giving it the robot’s IP address, script file and RTDE recipes.

Listing 60 examples/full_driver.cpp
62  bool headless_mode = true;
63  g_my_robot = std::make_unique<ExampleRobotWrapper>(robot_ip, OUTPUT_RECIPE, INPUT_RECIPE, headless_mode,
64                                                     "external_control.urp");
65  if (!g_my_robot->isHealthy())
66  {
67    URCL_LOG_ERROR("Something in the robot initialization went wrong. Exiting. Please check the output above.");
68    return 1;
69  }
70  // --------------- INITIALIZATION END -------------------

Robot control loop

This example reads the robot’s joint positions, increments / decrements the 5th axis and sends that back as a joint command for the next cycle. This way, the robot will move its wrist first until a positive limit and then back to 0.

To read the joint data, the driver’s RTDE client is used:

Listing 61 examples/full_driver.cpp
 87  // Once RTDE communication is started, we have to make sure to read from the interface buffer, as
 88  // otherwise we will get pipeline overflows. Therefor, do this directly before starting your main
 89  // loop.
 90  g_my_robot->getUrDriver()->startRTDECommunication();
 91  rtde_interface::DataPackage data_pkg(g_my_robot->getUrDriver()->getRTDEOutputRecipe());
 92  while (!(passed_positive_part && passed_negative_part))
 93  {
 94    // Read latest RTDE package. This will block for a hard-coded timeout (see UrDriver), so the
 95    // robot will effectively be in charge of setting the frequency of this loop.
 96    // In a real-world application this thread should be scheduled with real-time priority in order
 97    // to ensure that this is called in time.
 98    if (!g_my_robot->getUrDriver()->getDataPackage(data_pkg))
 99    {
100      URCL_LOG_WARN("Could not get fresh data package from robot");
101      return 1;
102    }
103    // Read current joint positions from robot data
104    if (!data_pkg.getData("actual_q", g_joint_positions))
105    {
106      // This throwing should never happen unless misconfigured
107      std::string error_msg = "Did not find 'actual_q' in data sent from robot. This should not happen!";
108      throw std::runtime_error(error_msg);
109    }
110
111    if (first_pass)
112    {
113      joint_target = g_joint_positions;
114      first_pass = false;
115    }

The first read operation will initialize the target buffer with the current robot position. Next, the target joint configuration is calculated:

Listing 62 examples/full_driver.cpp
117    // Open loop control. The target is incremented with a constant each control loop
118    if (passed_positive_part == false)
119    {
120      increment = increment_constant;
121      if (g_joint_positions[5] >= 2)
122      {
123        passed_positive_part = true;
124      }
125    }
126    else if (passed_negative_part == false)
127    {
128      increment = -increment_constant;
129      if (g_joint_positions[5] <= 0)
130      {
131        passed_negative_part = true;
132      }
133    }
134    joint_target[5] += increment;

To send the control command, the robot’s ReverseInterface is used via the writeJointCommand() function:

Listing 63 examples/full_driver.cpp
135    // Setting the RobotReceiveTimeout time is for example purposes only. This will make the example running more
136    // reliable on non-realtime systems. Use with caution in productive applications.
137    bool ret = g_my_robot->getUrDriver()->writeJointCommand(joint_target, comm::ControlMode::MODE_SERVOJ,
138                                                            RobotReceiveTimeout::millisec(100));
139    if (!ret)
140    {
141      URCL_LOG_ERROR("Could not send joint command. Make sure that the robot is in remote control mode and connected "
142                     "with a network cable.");
143      return 1;
144    }