# The Hardware interface node
TIP
There are multiple helpful links for this part.
DETAILS
http://wiki.ros.org/hardware_interface (opens new window) http://wiki.ros.org/ros_control/Tutorials/Create%20your%20own%20hardware%20interface (opens new window) https://medium.com/@slaterobotics/how-to-implement-ros-control-on-a-custom-robot-748b52751f2e (opens new window) https://fjp.at/posts/ros/ros-control/ (opens new window) https://sir.upc.edu/projects/rostutorials/10-gazebo_control_tutorial/index.html (opens new window) https://fjp.at/projects/diffbot/ros-packages/base/ (opens new window)
# Building a c++ node
http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29 (opens new window)
# header file
#ifndef ROBOT_HW_INTERFACE_H_
#define ROBOT_HW_INTERFACE_H_
#include <ros/console.h>
#include <hardware_interface/robot_hw.h>
#include <hardware_interface/joint_state_interface.h>
#include <hardware_interface/joint_command_interface.h>
#include <controller_manager/controller_manager.h>
#include <joint_limits_interface/joint_limits.h>
#include <joint_limits_interface/joint_limits_interface.h>
#include <joint_limits_interface/joint_limits_rosparam.h>
#include <robota/Motor_msgs.h>
#include <robota/Control_msgs.h>
class Robot : public hardware_interface::RobotHW
{
private:
ros::NodeHandle nh;
hardware_interface::JointStateInterface jnt_state;
hardware_interface::VelocityJointInterface jnt_cmd;
joint_limits_interface::JointLimits jnt_limits;
joint_limits_interface::VelocityJointSaturationInterface jnt_vel_sat;
double pos[4];
double vel[4];
double eff[4];
double cmd[4];
ros::Subscriber sub;
ros::Publisher pub;
robota::Motor_msgs motor_msg;
robota::Control_msgs command_msg;
void teensyCallback(const robota::Motor_msgs& msg);
public:
Robot(ros::NodeHandle& nodehandle);
void read();
void write(ros::Duration elapsed_time);
};
#endif // ROBOT_HW_INTERFACE_H_
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
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
# cpp file
#include "robota/robot_hw_interface.h"
Robot::Robot(ros::NodeHandle& nodehandle)
{
// store the node handle passed to the hardware interface
// in the private member variable
nh = nodehandle;
// Initialize the other private member variables
pos[0] = 0.0; pos[1] = 0.0; pos[2] = 0.0; pos[3] = 0.0;
vel[0] = 0.0; vel[1] = 0.0; vel[2] = 0.0; vel[3] = 0.0;
eff[0] = 0.0; eff[1] = 0.0; eff[2] = 0.0; eff[3] = 0.0;
cmd[0] = 0.0; cmd[1] = 0.0; cmd[2] = 0.0; cmd[3] = 0.0;
// create joint state handles and register them
hardware_interface::JointStateHandle state_left("motor_left_shaft", &pos[0], &vel[0], &eff[0]);
hardware_interface::JointStateHandle state_right("motor_right_shaft", &pos[1], &vel[1], &eff[1]);
hardware_interface::JointStateHandle state_shoulder("motor_shoulder_shaft", &pos[2], &vel[2], &eff[2]);
hardware_interface::JointStateHandle state_elbow("motor_elbow_shaft", &pos[3], &vel[3], &eff[3]);
jnt_state.registerHandle(state_left);
jnt_state.registerHandle(state_right);
jnt_state.registerHandle(state_shoulder);
jnt_state.registerHandle(state_elbow);
registerInterface(&jnt_state);
// create joint command handles and register them
hardware_interface::JointHandle cmd_left (state_left, &cmd[0]);
hardware_interface::JointHandle cmd_right(state_right, &cmd[1]);
hardware_interface::JointHandle cmd_shoulder(state_shoulder, &cmd[2]);
hardware_interface::JointHandle cmd_elbow(state_elbow, &cmd[3]);
jnt_cmd.registerHandle(cmd_left);
jnt_cmd.registerHandle(cmd_right);
jnt_cmd.registerHandle(cmd_shoulder);
jnt_cmd.registerHandle(cmd_elbow);
registerInterface(&jnt_cmd);
// create joint limits handles and register them
joint_limits_interface::getJointLimits("motor_left_shaft", nh, jnt_limits);
joint_limits_interface::VelocityJointSaturationHandle limit_left(cmd_left, jnt_limits);
joint_limits_interface::getJointLimits("motor_right_shaft", nh, jnt_limits);
joint_limits_interface::VelocityJointSaturationHandle limit_right(cmd_right, jnt_limits);
joint_limits_interface::getJointLimits("motor_shoulder_shaft", nh, jnt_limits);
joint_limits_interface::VelocityJointSaturationHandle limit_shoulder(cmd_shoulder, jnt_limits);
joint_limits_interface::getJointLimits("motor_elbow_shaft", nh, jnt_limits);
joint_limits_interface::VelocityJointSaturationHandle limit_elbow(cmd_elbow, jnt_limits);
jnt_vel_sat.registerHandle(limit_left);
jnt_vel_sat.registerHandle(limit_right);
jnt_vel_sat.registerHandle(limit_shoulder);
jnt_vel_sat.registerHandle(limit_elbow);
registerInterface(&jnt_vel_sat);
// create a subscriber to get data from the teensy
sub = nh.subscribe("teensy/Motors", 1000, &Robot::teensyCallback, this);
// create a publisher to send data to the teensy
pub = nh.advertise<robota::Control_msgs>("teensy/Commands", 1000);
}
void Robot::read()
{
pos[0] = motor_msg.left_pos;
pos[1] = motor_msg.right_pos;
pos[2] = motor_msg.shoulder_pos;
pos[3] = motor_msg.elbow_pos;
vel[0] = motor_msg.left_vel;
vel[1] = motor_msg.right_vel;
vel[2] = motor_msg.shoulder_vel;
vel[3] = motor_msg.elbow_vel;
//ROS_INFO("In read Motor_vel: %.2f", vel[1]);
}
void Robot::write(ros::Duration elapsed_time)
{
jnt_vel_sat.enforceLimits(elapsed_time);
command_msg.left_vel = cmd[0];
command_msg.right_vel = cmd[1];
command_msg.shoulder_vel = cmd[2];
command_msg.elbow_vel = cmd[3];
pub.publish(command_msg);
//ROS_INFO("In write Commands: %.2f", cmd[1]);
}
void Robot::teensyCallback(const robota::Motor_msgs& msg)
{
motor_msg = msg;
//ROS_INFO("In callback");
}
int main(int argc, char** argv)
{
ROS_INFO("Start of main");
// initialize the hardware interface ros node
ros::init(argc, argv, "robot_node");
// and create a ros node handle/mobile_base_controller/left_wheel
ros::NodeHandle nh;
// create a hardware interface object and connect it to the controller manager
Robot robot(nh);
controller_manager::ControllerManager cm(&robot, nh);
// set the period and update rate for 10Hz
ros::Duration period(0.1);
ros::Rate rate(1.0/period.toSec());
// create a new spinner thread for the callback method and start it
ros::AsyncSpinner spinner(1);
spinner.start();
//ROS_INFO("Before main_loop");
// create an infinite loop for running the hardware interface
while(ros::ok())
{
//ROS_INFO("In main_loop");
robot.read();
cm.update(ros::Time::now(), period);
robot.write(period);
rate.sleep();
}
spinner.stop();
return 0;
}
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132