Writing Hardwara Interface Node
The Big Picture
The following shows the big picture of how to use ros_control with either simulation or a real robot. It can be seen in the picture that the class “hardware_interface::RobotHW” should be implemented in a hardware interface node when ros_control is used with a real robot. On the other hand, the class “hardware_interface::RobotHWSim” should be implemented when ros_control is used with simulation in Gazebo.
In a real robot, the hardware interface node reads the joint state (joint sensor data) and writes control commands to the embedded controller which subsequently control the actuators in real-time.
In Gazebo simulation, the implementation of “hardware_interface::RobotHWSim” reads from the simulated sensor and writes control command to the simulated actuators. You don’t need to write a hardware interface node if you use ros_control with Gazebo simulation.

Using ros_control with a custom real robot
If you have an off-the-shelf ROS-enabled robot, the connection between ros_control and the robot’s hardware is already established. However, if you have a custom robot and you want to use ros_control to control the robot, then you need to write a hardware interface node which sits between the hardware_interface components of ros_control and the control hardware (i.e. actuators and sensors) of the custom robot.
The main control loop when using ros_control with a real robot can be illustated in the picture below:

The three main tasks being done in the control loop is:
- reading the joint state
- updating the control loop all the time
- writing control commands to the actuator
Some examples of hardware interface nodes can be found in the following links:
- http://wiki.ros.org/ros_control/Tutorials/Create%20your%20own%20hardware%20interface
- https://medium.com/@slaterobotics/how-to-implement-ros-control-on-a-custom-robot-748b52751f2e; https://github.com/SlateRobotics/tr1_hardware_interface
- https://sir.upc.edu/projects/rostutorials/10-gazebo_control_tutorial/index.html#hardware-abstraction-layer
- https://www.rosroboticslearning.com/ros-control
- https://cse400.luciochen.com/codes/HardwareInterface.html#building-a-c-node
- https://github.com/PickNikRobotics/ros_control_boilerplate
- https://github.com/eborghi10/my_ROS_mobile_robot/tree/e04acfd3e7eb4584ba0aab8a969a74d6c30eed34
The following is a simple example of a hardware interface node as provided in ROS Wiki. In this example, the robot having two actuated joints namely A and B uses JointStateInterface and PositionJointInterface. Actually, the robot can also additionally use, for example, VelocityJointInterface and many more interfaces.
The main function shows clearly that the three main tasks of the control loop are performed: reading, updating, and writing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#include <hardware_interface/joint_command_interface.h> #include <hardware_interface/joint_state_interface.h> #include <hardware_interface/robot_hw.h> class MyRobot : public hardware_interface::RobotHW { public: MyRobot() { // connect and register the joint state interface hardware_interface::JointStateHandle state_handle_a("A", &pos[0], &vel[0], &eff[0]); jnt_state_interface.registerHandle(state_handle_a); hardware_interface::JointStateHandle state_handle_b("B", &pos[1], &vel[1], &eff[1]); jnt_state_interface.registerHandle(state_handle_b); registerInterface(&jnt_state_interface); // connect and register the joint position interface hardware_interface::JointHandle pos_handle_a(jnt_state_interface.getHandle("A"), &cmd[0]); jnt_pos_interface.registerHandle(pos_handle_a); hardware_interface::JointHandle pos_handle_b(jnt_state_interface.getHandle("B"), &cmd[1]); jnt_pos_interface.registerHandle(pos_handle_b); registerInterface(&jnt_pos_interface); } private: hardware_interface::JointStateInterface jnt_state_interface; hardware_interface::PositionJointInterface jnt_pos_interface; double cmd[2]; double pos[2]; double vel[2]; double eff[2]; }; main() { MyRobot robot; controller_manager::ControllerManager cm(&robot); while (true) { robot.read(); cm.update(robot.get_time(), robot.get_period()); robot.write(); sleep(); } } |
Notice that the hardware interface needs to load before the controller manager or the manager will likely crash.