最近需要在ROS中使用CAN,这里简单汇总一下看过的资料,参考文献如下:
1. ROS Control and CAN interface on a custom robot
2. ros_canopen wiki
ros_canopen: can_msgs | canopen_402 | canopen_chain_node | canopen_master | canopen_motor_node | socketcan_bridge | socketcan_interface
3. ros_canopen github
这些资料主要讲述在ROS中使用Canopen。这些软件包为ROS内的CANopen设备提供支持。
它可以分为不同的部分:
以canopen_motor_node为例:
----
The node includes a controller_manager instance that can be used to spawn controller_interface compliant controllers. Depending on the motor device different interfaces are support.
For each joint a hardware_interface::JointStateHandle is registered with the position, velocity and effort of the specific drive. The actual value is determined by the conversion functions.
In addition handles for the following command interfaces are available if the given modes are supported by the device:
hardware_interface::PositionJointInterface:
hardware_interface::VelocityJointInterface:
hardware_interface::EffortJointInterface:
----
All standardized drive modes are implemented, these modes can be substituted in sub classes and others can be added.
The following table lists all supported drive modes and their data objects. The objects used should be mapped to PDOs.
Name |
ID |
target object |
RPDO mapping parameter |
comments |
Profiled Position |
1 |
607A |
0x607a0020 |
|
Velocity |
2 |
6042 |
0x60420010 |
|
Profiled Velocity |
3 |
60FF |
0x60ff0020 |
|
Profiled Torque |
4 |
6071 |
0x60710010 |
not yet tested |
Interpolated Position |
7 |
60C1sub1 |
0x60c10120 |
|
Cyclic Synchronous Position |
8 |
607A |
0x607a0020 |
not yet tested |
Cyclic Synchronous Velocity |
9 |
60FF |
0x60ff0020 |
not yet tested |
Cyclic Synchronous Torque |
10 |
7071 |
0x60710010 |
not yet tested |
The modes can be switched at run-time, the 402 state might be switched in order to switch the mode, if necessary.
Not all devices support all operation modes. The driver limits the set of available modes based on object 6502.
----
namespace canopen
{
class MotorBase : public canopen::Layer {
protected:
MotorBase(const std::string &name) : Layer(name) {}
public:
enum OperationMode
{
No_Mode = 0,
Profiled_Position = 1,
Velocity = 2,
Profiled_Velocity = 3,
Profiled_Torque = 4,
Reserved = 5,
Homing = 6,
Interpolated_Position = 7,
Cyclic_Synchronous_Position = 8,
Cyclic_Synchronous_Velocity = 9,
Cyclic_Synchronous_Torque = 10,
};
ProfiledPositionMode(boost::shared_ptr storage) : ModeTargetHelper(MotorBase::Profiled_Position) {
storage->entry(target_position_, 0x607A);
virtual void registerDefaultModes(boost::shared_ptr storage){
registerMode (MotorBase::Profiled_Position, storage);
registerMode (MotorBase::Velocity, storage);
registerMode (MotorBase::Profiled_Velocity, storage);
registerMode (MotorBase::Profiled_Torque, storage);
registerMode (MotorBase::Homing, storage);
registerMode (MotorBase::Interpolated_Position, storage);
registerMode (MotorBase::Cyclic_Synchronous_Position, storage);
registerMode (MotorBase::Cyclic_Synchronous_Velocity, storage);
registerMode (MotorBase::Cyclic_Synchronous_Torque, storage);
}
class InterfaceMapping {
typedef boost::bimap, boost::bimaps::set_of > bimap_type;
bimap_type mapping_;
public:
InterfaceMapping(){
mapping_.insert(bimap_type::value_type("hardware_interface::PositionJointInterface" ,canopen::MotorBase::Profiled_Position));
mapping_.insert(bimap_type::value_type("hardware_interface::PositionJointInterface" ,canopen::MotorBase::Interpolated_Position));
mapping_.insert(bimap_type::value_type("hardware_interface::PositionJointInterface" ,canopen::MotorBase::Cyclic_Synchronous_Position));
mapping_.insert(bimap_type::value_type("hardware_interface::VelocityJointInterface" ,canopen::MotorBase::Velocity));
mapping_.insert(bimap_type::value_type("hardware_interface::VelocityJointInterface" ,canopen::MotorBase::Profiled_Velocity));
mapping_.insert(bimap_type::value_type("hardware_interface::VelocityJointInterface" ,canopen::MotorBase::Cyclic_Synchronous_Velocity));
mapping_.insert(bimap_type::value_type("hardware_interface::EffortJointInterface" ,canopen::MotorBase::Profiled_Torque));
mapping_.insert(bimap_type::value_type("hardware_interface::EffortJointInterface" ,canopen::MotorBase::Cyclic_Synchronous_Torque));
}
std::vector getInterfaceModes(const std::string &interface){
std::vector modes;
BOOST_FOREACH(bimap_type::left_reference i, mapping_.left.equal_range(interface)){
modes.push_back(i.second);
}
return modes;
}
bool hasConflict(const std::string &interface, canopen::MotorBase::OperationMode mode){
bimap_type::right_const_iterator it;
if((it = mapping_.right.find(mode)) != mapping_.right.end()){
return it->second != interface;
}
return false;
}
};
----
具体使用认真参考wiki和源码即可。
补充资料:
This is definitely still a WIP but I feel that it’s useful enough at this stage to make it publicly known. I’ve developed a wxWidgets-based tool for analysis of CAN messages and signals. I call it DeCANstructor and it’s available on Github20. Please feel free to provide any feedback/feature requests/etc. there. In addition to working with SocketCAN through ros_canopen6, it also works with multi-channel and PCIe Kvaser devices through Kvaser’s CANLIB and my company’s kvaser_interface9 (which outputs the same messages as ros_canopen).