-
Notifications
You must be signed in to change notification settings - Fork 308
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
doc: add README.md for hardware_interface
- Loading branch information
Showing
1 changed file
with
24 additions
and
284 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,299 +1,39 @@ | ||
# Hardware Interfaces {#mainpage} | ||
# Hardware Interfaces | ||
|
||
hardware interfaces are used by ROS control in conjunction with one of the | ||
available ROS controllers to send (\ref hardware_interface::RobotHW::write) | ||
commands to the hardware and receive (\ref hardware_interface::RobotHW::read) | ||
Hardware interfaces are used by ROS control in conjunction with one of the | ||
available ROS controllers to send (\ref hardware_interface::RobotHW::write) | ||
commands to the hardware and receive (\ref hardware_interface::RobotHW::read) | ||
states from the robot's resources (joints, sensors, actuators). | ||
|
||
A list of available hardware interfaces (provided via the HardwareResourceManager) | ||
as of this writing: | ||
A list of available hardware interfaces (provided via the HardwareResourceManager) | ||
as of this writing are: | ||
|
||
- [JointCommandInterface](\ref hardware_interface::JointCommandInterface): | ||
- [JointCommandInterface](include/hardware_interface/joint_command_interface.h): | ||
hardware interface to support commanding and reading the state of an array of | ||
joints. Note that these commands can have any semantic meaning as long as each | ||
can be represented by a single double, they are not necessarily effort commands. | ||
To specify a meaning to this command, see the derived classes: | ||
- [EffortJointInterface](\ref hardware_interface::EffortJointInterface): | ||
- [EffortJointInterface](https://github.com/ros-controls/ros_control/blob/c6ee2451cf919307b7c1dbc75b32bec7d1b52d23/hardware_interface/include/hardware_interface/joint_command_interface.h#L82): | ||
for commanding and reading effort-based joints. | ||
- [VelocityJointInterface](\ref hardware_interface::VelocityJointInterface): | ||
- [VelocityJointInterface](https://github.com/ros-controls/ros_control/blob/c6ee2451cf919307b7c1dbc75b32bec7d1b52d23/hardware_interface/include/hardware_interface/joint_command_interface.h#L85): | ||
for commanding and reading velocity-based joints. | ||
- [PositionJointInterface](\ref hardware_interface::PositionJointInterface): | ||
- [PositionJointInterface](https://github.com/ros-controls/ros_control/blob/c6ee2451cf919307b7c1dbc75b32bec7d1b52d23/hardware_interface/include/hardware_interface/joint_command_interface.h#L88): | ||
for commanding and reading position-based joints. | ||
- [JointStateInterfaces](\ref hardware_interface::JointStateInterface): | ||
- [JointStateInterfaces](include/hardware_interface/joint_state_interface.h): | ||
hardware interface to support reading the state of an array of named joints, | ||
each of which has some position, velocity, and effort (force or torque). | ||
- [ActuatorStateInterfaces](\ref hardware_interface::ActuatorStateInterface): | ||
- [ActuatorStateInterfaces](include/hardware_interface/actuator_state_interface.h): | ||
hardware interface to support reading the state of an array of named actuators, | ||
each of which has some position, velocity, and effort (force or torque). | ||
- [ActuatorCommandInterfaces](\ref hardware_interface::ActuatorCommandInterface) | ||
- [EffortActuatorInterface](\ref hardware_interface::EffortActuatorInterface) | ||
- [VelocityActuatorInterface](\ref hardware_interface::VelocityActuatorInterface) | ||
- [PositionActuatorInterface](\ref hardware_interface::PositionActuatorInterface) | ||
- Force-torque sensor Interface | ||
- IMU sensor Interface | ||
|
||
Note that \ref hardware_interface::JointCommandInterface allows both reading | ||
joint state and commanding [effort|velocity|position]-based joints | ||
(see this [answer](https://answers.ros.org/question/209619/differences-between-hardware-interfaces/?answer=209636#post-id-209636)). | ||
|
||
## Setting up a new robot | ||
|
||
The following example explains how to set up a new robot to work with the | ||
[controller_manager](http://wiki.ros.org/controller_manager). When you make your | ||
robot support one or more of the standard interfaces, you will be able to take | ||
advantage of a large library of controllers (see | ||
[ros_controllers](https://github.com/ros-controls/ros_controllers)) | ||
that work on the standard interfaces mentioned above. | ||
|
||
![hw_interface_2.png](https://raw.githubusercontent.com/wiki/ros-controls/ros_control/hw_interface_2.png) | ||
|
||
Assuming a robot with two joints: A & B where both joints are position controlled. | ||
Such a robot is defined with class derived from \ref hardware_interface::RobotHW | ||
that should provide the standard [PositionJointInterface](\ref hardware_interface::PositionJointInterface) and the | ||
[JointStateInterface](\ref hardware_interface::JointStateInterface), so it can re-use all controllers that are already | ||
written to work with the [PositionJointInterface](\ref hardware_interface::PositionJointInterface) and the | ||
[JointStateInterface](\ref hardware_interface::JointStateInterface). The code would look like this: | ||
|
||
|
||
```cpp | ||
#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() | ||
{ | ||
// Initialization of the robot's resources (joints, sensors, actuators) and | ||
// interfacs can be done here or inside init(). | ||
} | ||
|
||
bool init(ros::NodeHandle &root_nh, ros::NodeHandle &robot_hw_nh) | ||
{ | ||
// Create a JointStateHandle for each joint and register them with the | ||
// JointStateInterface. | ||
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); | ||
|
||
// Register the JointStateInterface containing the read only joints | ||
// with this robot's hardware_interface::RobotHW. | ||
registerInterface(&jnt_state_interface); | ||
|
||
// Create a JointHandle (read and write) for each controllable joint | ||
// using the read-only joint handles within the JointStateInterface and | ||
// register them with the JointPositionInterface. | ||
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); | ||
|
||
// Register the JointPositionInterface containing the read/write joints | ||
// with this robot's hardware_interface::RobotHW. | ||
registerInterface(&jnt_pos_interface); | ||
|
||
return true; | ||
} | ||
|
||
private: | ||
hardware_interface::JointStateInterface jnt_state_interface; | ||
hardware_interface::PositionJointInterface jnt_pos_interface; | ||
|
||
// Data member array to store the controller commands which are sent to the | ||
// robot's resources (joints, actuators) | ||
double cmd[2]; | ||
|
||
// Data member arrays to store the state of the robot's resources (joints, sensors) | ||
double pos[2]; | ||
double vel[2]; | ||
double eff[2]; | ||
}; | ||
``` | ||
This code represents a custom robot and is required to control it. | ||
The functions above are designed to give the controller manager (and the | ||
controllers inside the controller manager) access to the joint state of a | ||
custom robot, and to command it. When the controller manager runs, the | ||
controllers will read from the pos, vel and eff variables of the custom robot | ||
hardware interface, and the controller will write the desired command into the | ||
cmd variable. It's mandatory to make sure the pos, vel and eff variables always | ||
have the latest joint state available, and to make sure that whatever is written | ||
into the cmd variable gets executed by the robot. This can be done by implementing | ||
\ref hardware_interface::RobotHW::read() and a \ref hardware_interface::RobotHW::write() | ||
methods. A node's `main()` function can be implemented like this: | ||
```cpp | ||
#include <ros/ros.h> | ||
#include <my_robot/my_robot.h> | ||
#include <controller_manager/controller_manager.h> | ||
int main(int argc, char **argv) | ||
{ | ||
// Initialize the ROS node | ||
ros::init(argc, argv, "my_robot"); | ||
// Create an instance of your robot so that this instance knows about all | ||
// the resources that are available. | ||
MyRobot::MyRobot robot; | ||
// Create an instance of the controller manager and pass it the robot, | ||
// so that it can handle its resources. | ||
controller_manager::ControllerManager cm(&robot); | ||
// Setup a separate thread that will be used to service ROS callbacks. | ||
ros:AsyncSpinner spinner(1); | ||
spinner.start(); | ||
// Setup for the control loop. | ||
ros::Time prev_time = ros::Time::now(); | ||
ros::Rate rate(10.0); // 10 Hz rate | ||
while (ros::ok()) | ||
{ | ||
// Basic bookkeeping to get the system time in order to compute the control period. | ||
const ros::Time time = ros:Time::now(); | ||
const ros::Duration period = time - prev_time; | ||
// Execution of the actual control loop. | ||
robot.read(); | ||
cm.update(time, period); | ||
root.write(); | ||
// All these steps keep getting repeated with the specified rate. | ||
rate.sleep(); | ||
} | ||
return 0; | ||
} | ||
``` | ||
|
||
As the image above suggests, a custom robot hardware interface is not | ||
limited to be composed of only one single interface. The robot can provide as | ||
many interfaces as required. It could for example provide both the | ||
\ref hardware_interface::PositionJointInterface and the | ||
\ref hardware_interface::VelocityJointInterface, and many more. | ||
|
||
|
||
## Resource Management | ||
|
||
The controller manager keeps track of which resources are in use by each of the | ||
controllers. A resource can be something like 'right_elbow_joint', 'base', | ||
'left_arm', 'wrist_joints'. Pretty much anything a specific robot can consist of. | ||
Put simply, resources are specified in the robot's hardware interface (derived from | ||
\ref hardware_interface::RobotHW). And a robot is represented by a bunch of | ||
hardware interfaces, where one is a set of similar resources. For example, the | ||
\ref hardware_interface::PositionJointInterface groups the position controlled | ||
joints as resources. It is also possible to implement a custom hardware interface, | ||
and define custom resources. When controllers are getting initialized, they | ||
request a number of resources from the hardware interface; these requests get | ||
recorded by the controller manager. So the controller manager knows exactly | ||
which controller has requested which resources. | ||
|
||
The RobotHW class has a simple default implementation for resource management: | ||
it simply prevents two controllers that are using the same resource to be | ||
running at the same time. Note that two controllers that are using the same | ||
resource can be loaded at the same time, but can't be running at the same time. | ||
If this simple resource management scheme fits to a robot, nothing else needs to | ||
be done, the controller manager will automatically apply this scheme. If a robot | ||
needs a different scheme, it is possible to create a custom one, by implementing | ||
one single function: | ||
|
||
```cpp | ||
class MyRobot : public hardware_interface::RobotHW | ||
{ | ||
public: | ||
MyRobot() | ||
{ | ||
// register hardware interfaces interfaces | ||
... | ||
... (see the code above) | ||
... | ||
|
||
|
||
// Implement robot-specific resouce management | ||
bool checkForConflict(const std::list<ControllerInfo>& info) const | ||
{ | ||
// This list of controllers cannot be running at the same time | ||
... | ||
return true; | ||
|
||
// This list of controller can be running at the same time | ||
... | ||
return false; | ||
} | ||
} | ||
}; | ||
``` | ||
|
||
The input to the \ref hardware_interface::RobotHW::checkForConflict method is a list of | ||
controller info objects. Each of these objects matches to one single controller, | ||
and contains all the info about that controller. This info includes the | ||
controller name, controller type, hardware interface type, and the list of | ||
resources that are claimed by the controller. Based on all this info, it is | ||
possible to come up with a custom scheme to decide if the given list of | ||
controllers is allowed to be running at the same time. | ||
|
||
|
||
## Creating a robot-specific interface | ||
|
||
The standard interfaces are helpful to avoid writing a whole new set of | ||
controllers for a robot, and to take advantage of the libraries of existing | ||
controllers. But in case a robot has some features that are not supported by the | ||
standard interfaces it is possible to leverage the standard interfaces | ||
(and re-use the standard controllers) for the features of a robot that are standard. | ||
And at the same time expose robot-specific features in a robot-specific interface. | ||
The image shown above shows a robot with both standard and robot-specific interfaces. | ||
|
||
The code for such a robot looks like this: | ||
|
||
```cpp | ||
class MyRobot : public hardware_interface::RobotHW | ||
{ | ||
public: | ||
MyRobot() | ||
{ | ||
// Register the joint state and position interfaces. | ||
... | ||
... (see the code above) | ||
... | ||
|
||
// Register some robot specific interfaces. | ||
registerInterface(&cool_interface); | ||
} | ||
|
||
private: | ||
MyCustomInterface cool_interface; | ||
}; | ||
``` | ||
Anotehr way is to register the MyRobot class itself: | ||
```cpp | ||
class MyRobot : public hardware_interface::RobotHW, public hardware_interface::HardwareInterface | ||
{ | ||
public: | ||
MyRobot() | ||
{ | ||
// Register the joint state and position interfaces. | ||
... | ||
... (see the code above) | ||
... | ||
// Register the MyRobot class itself to make the 'someCoolFunction' available. | ||
// The MyRobot class inherits from HardwareInterface to make this possible. | ||
registerInterface(this); | ||
} | ||
void someCoolFunction(); | ||
}; | ||
``` | ||
|
||
With this, the custom interfaces could be nothing more than adding any number of | ||
function calls to a custom robot class, and registering the robot class itself. | ||
These robot-specific functions will only be available to controllers that are | ||
specifically designed for the custom robot, but at the same time, the robot will | ||
still work with standard controllers using the standard interfaces of the robot. | ||
- [ActuatorCommandInterfaces](include/hardware_interface/actuator_command_interface.h) | ||
- [EffortActuatorInterface](https://github.com/ros-controls/ros_control/blob/c6ee2451cf919307b7c1dbc75b32bec7d1b52d23/hardware_interface/include/hardware_interface/actuator_command_interface.h#L79) | ||
- [VelocityActuatorInterface](https://github.com/ros-controls/ros_control/blob/c6ee2451cf919307b7c1dbc75b32bec7d1b52d23/hardware_interface/include/hardware_interface/actuator_command_interface.h#L82) | ||
- [PositionActuatorInterface](https://github.com/ros-controls/ros_control/blob/c6ee2451cf919307b7c1dbc75b32bec7d1b52d23/hardware_interface/include/hardware_interface/actuator_command_interface.h#L85) | ||
- [PosVelJointInterface](/include/hardware_interface/posvel_command_interface.h) | ||
- [PosVelAccJointInterface](/include/hardware_interface/posvelacc_command_interface.h) | ||
- [Force-torque sensor Interface](include/hardware_interface/force_torque_sensor_interface.h) | ||
- [IMU sensor Interface](/include/hardware_interface/imu_sensor_interface.h) | ||
|
||
Note that \ref hardware_interface::JointCommandInterface allows both reading | ||
joint state and commanding [effort|velocity|position]-based joints | ||
(see this [answer](https://answers.ros.org/question/209619/differences-between-hardware-interfaces/?answer=209636#post-id-209636)). |