当前位置:   article > 正文

ros下使用CANopen与电机进行通讯_使用ros进行can通讯

使用ros进行can通讯

CAN总线的通讯模式:

PDO:过程数据对象(Process Data Object),过程数据的发送,实时、速度快,提供对设备应用对象的直接访问通道,它用来传输实时短帧数据,具有较高的优先权。PDO 传输的数据必须少于或等于 8 个字节,在应用层上不包含传输控制信息,报文利用率极高通常编码器的数据读取以及车轮的控制通过PDO。

SDO:服务数据对象(Service Data Obiect),服务数据的发送接收,实时性要求不高,SDO一般用来配置和获得节点的配置参数例如修改、修改字典\od对象、电机的工作模式或读取电机的工作状态。
 

与ROS的通讯方式比较:

CAN总线的通讯ROS的通信非常相似,PDO模式与ros的话题消息通信机制高度相似,而SDO与ros的服务高度相似。但can总线的通信是通过broadcast的形式,ros通信中采用的分布式(订阅

)的形式。

在设备支持CANopen的情况下需要通过运行以下指令对CAN口进行初始化:

sudo modprobe can
sudo ip link set can1 type can bitrate 500000
sudo ip link set can1 up

通常以下两种情况会导致两台设备无法通过can通信:

1两台设备的can波特率不一致

2接线错误

随后运行ros-canopen包将can消息转化为话题消息(默认安装连接的是can0如果想用其他can口需要修改源码然后重新编译)

sdo模式下指令为:

站号ID # 操作符(1B) 索引(2B) 子索引(1B) 数据(4B) 例如

cansend can1 601#2F606000FDFF

pdo模式下指令为:

站号ID # 数据(4B) 例如

cansend can1 201#00400600

  1. #include <ros/ros.h>
  2. #include <ros/spinner.h>
  3. #include <std_msgs/String.h>
  4. #include <tf/transform_broadcaster.h>
  5. #include <nav_msgs/Odometry.h>
  6. #include <geometry_msgs/Twist.h>
  7. #include <std_msgs/String.h>
  8. #include <std_msgs/Int8.h>
  9. #include <std_msgs/Float32.h>
  10. #include <std_msgs/Float32MultiArray.h>
  11. #include <socketcan_bridge/topic_to_socketcan.h>
  12. #include <socketcan_bridge/socketcan_to_topic.h>
  13. #include <can_msgs/Frame.h>
  14. #include <socketcan_interface/socketcan.h>
  15. #include <iostream>
  16. #define LEFT_MOTOR_CAN_ID 0x601
  17. #define RIGHT_MOTOR_CAN_ID 0x602
  18. #define LEFT_MOTOR_PDO_ID 0x201
  19. #define RIGHT_MOTOR_PDO_ID 0x202
  20. #define DISTANCE_WHEELS 0.562
  21. #define DIAMETER_WHEELS 0.169
  22. #define PI 3.1415926
  23. #define EXP_DOUBLE 1e-6
  24. bool flag_send = false;
  25. ros::Publisher roscan_send_message;
  26. void setCANopenMotorToward(unsigned int ID, uint8_t toward)
  27. {
  28. ROS_INFO("Ready to send can_message : motor toward");
  29. setlocale(LC_ALL, "");
  30. uint8_t transition[8];
  31. can_msgs::Frame can_frame;
  32. memset(&transition, 0, sizeof(transition));
  33. //只发送一个字节0x2F 发送两个字节0x2B 发送四个字节0x23
  34. transition[0] = 0x2F;
  35. //设置电机方向的索引为607E低位在前高位在后
  36. transition[1] = 0x7E;
  37. transition[2] = 0x60;
  38. //子索引为00
  39. transition[3] = 0x00;
  40. //设置方向,低位在前高位在后
  41. transition[4] = toward;
  42. transition[5] = 0x00;
  43. transition[6] = 0x00;
  44. transition[7] = 0x00;
  45. can_frame.id = ID;
  46. can_frame.is_extended = true;
  47. can_frame.is_rtr = false;
  48. can_frame.is_error = false;
  49. can_frame.dlc = 8; //有效数据长度
  50. for (uint8_t i = 0; i < can_frame.dlc; i++)
  51. {
  52. can_frame.data[i] = transition[i];
  53. }
  54. roscan_send_message.publish(can_frame);
  55. ROS_INFO("send messages succeed : work model shift");
  56. }
  57. void setCANopenMotorSpeed(unsigned int ID, double speed)
  58. {
  59. bool flag_sign = false;
  60. if(speed < 0)
  61. {
  62. flag_sign = true;
  63. }
  64. double rpm = fabs(speed);
  65. int encoder_resolution = 10000;
  66. int dec = rpm *512* encoder_resolution/1875;
  67. if(flag_sign == true)
  68. {
  69. dec = (~dec) + 1;
  70. }
  71. ROS_INFO("Ready to send can_message : motor speed 0x%X" , dec);
  72. setlocale(LC_ALL, "");
  73. uint8_t transition[8];
  74. can_msgs::Frame can_frame;
  75. memset(&transition, 0, sizeof(transition));
  76. //设置轮子转速
  77. unsigned int encode_tmp = 0xff;
  78. transition[0] = dec&encode_tmp;
  79. transition[1] = (dec>>8)&encode_tmp;
  80. transition[2] = (dec>>16)&encode_tmp;
  81. transition[3] = (dec>>24)&encode_tmp;
  82. can_frame.id = ID;
  83. can_frame.is_extended = true;
  84. can_frame.is_rtr = false;
  85. can_frame.is_error = false;
  86. can_frame.dlc = 4; //有效数据长度
  87. for (uint8_t i = 0; i < can_frame.dlc; i++)
  88. {
  89. can_frame.data[i] = transition[i];
  90. }
  91. roscan_send_message.publish(can_frame);
  92. ROS_INFO("send messages succeed : motor speed %X %X %X %X",transition[0],transition[1],transition[2],transition[3]);
  93. }
  94. void setCANopenMotorWorkMdl(unsigned int ID , uint8_t work_mdl)
  95. {
  96. ROS_INFO("Ready to send can_message : work model shift");
  97. setlocale(LC_ALL, "");
  98. uint8_t transition[8];
  99. can_msgs::Frame can_frame;
  100. memset(&transition, 0, sizeof(transition));
  101. //只发送一个字节0x2F 发送两个字节0x2B 发送四个字节0x23
  102. transition[0] = 0x2F;
  103. //设置工作模式的索引为6060低位在前高位在后
  104. transition[1] = 0x60;
  105. transition[2] = 0x60;
  106. //子索引为00
  107. transition[3] = 0x00;
  108. //位置模式是0 速度模式是3
  109. transition[4] = work_mdl;
  110. //剩下全部补0即可
  111. transition[5] = 0x00;
  112. transition[6] = 0x00;
  113. transition[7] = 0x00;
  114. can_frame.id = ID;
  115. can_frame.is_extended = true;
  116. can_frame.is_rtr = false;
  117. can_frame.is_error = false;
  118. can_frame.dlc = 8; //有效数据长度
  119. for (uint8_t i = 0; i < can_frame.dlc; i++)
  120. {
  121. can_frame.data[i] = transition[i];
  122. }
  123. roscan_send_message.publish(can_frame);
  124. ROS_INFO("send messages succeed : work model shift");
  125. }
  126. void WorkMdlCallback(const std_msgs::Int8 & msg)
  127. {
  128. ROS_INFO("work model setting : %d" ,msg.data);
  129. setCANopenMotorWorkMdl(LEFT_MOTOR_CAN_ID,static_cast<uint8_t>(msg.data));
  130. setCANopenMotorWorkMdl(RIGHT_MOTOR_CAN_ID,static_cast<uint8_t>(msg.data));
  131. //send_can_message();
  132. }
  133. void MotorSpeedCallback(const std_msgs::Float32MultiArray & msg)
  134. {
  135. ROS_INFO("motor speed setting : %f" ,msg.data[1]);
  136. //如果是左轮
  137. unsigned int id;
  138. uint8_t dir;
  139. if(msg.data.size() == 2)
  140. {
  141. if(msg.data[0] < 0)
  142. {
  143. ROS_INFO("motor speed setting : left wheel");
  144. id = LEFT_MOTOR_PDO_ID;
  145. }
  146. //如果是右轮
  147. else if(msg.data[0] > 0)
  148. {
  149. ROS_INFO("motor speed setting : right wheel");
  150. id = RIGHT_MOTOR_PDO_ID;
  151. }
  152. setCANopenMotorSpeed(id,msg.data[1]);
  153. }
  154. else if(msg.data.size() == 3)
  155. {
  156. id = LEFT_MOTOR_PDO_ID;
  157. setCANopenMotorSpeed(id,msg.data[1]);
  158. id = RIGHT_MOTOR_PDO_ID;
  159. setCANopenMotorSpeed(id,msg.data[2]);
  160. }
  161. }
  162. void cmdVelCallback(const geometry_msgs::Twist & msg)
  163. {
  164. // vel_left = (curr_cmd.lin - curr_cmd.ang * L/ 2.0) / left_wheel_radius;
  165. // vel_right = (curr_cmd.lin + curr_cmd.ang * L/ 2.0) / right_wheel_radius;
  166. // m/s
  167. double v_line_x = msg.linear.x;
  168. double v_angr_z = msg.angular.z;
  169. double radius = DIAMETER_WHEELS / 2;
  170. double dist_w = DISTANCE_WHEELS;
  171. double vel_left = (v_line_x - v_angr_z * dist_w / 2.0) / radius; // m/s
  172. double vel_right = (v_line_x + v_angr_z * dist_w / 2.0) / radius;
  173. double speed_left = vel_left * 2 * PI; // rad/s
  174. double speed_right = vel_right * 2 * PI;
  175. speed_left *= 9.55; //rpm
  176. speed_right *= 9.55;
  177. unsigned int id;
  178. id = LEFT_MOTOR_PDO_ID;
  179. setCANopenMotorSpeed(id,speed_left);
  180. id = RIGHT_MOTOR_PDO_ID;
  181. setCANopenMotorSpeed(id,-speed_right);
  182. }
  183. int main(int argc, char **argv)
  184. {
  185. ros::init(argc, argv, "can_sender");
  186. ros::NodeHandle n("~");
  187. ros::Subscriber work_mdl_sub = n.subscribe("/work_mdl_shift" , 60 , WorkMdlCallback);
  188. ros::Subscriber motor_speed_sub = n.subscribe("/motor_speed" , 60 , MotorSpeedCallback);
  189. ros::Subscriber cmd_vel_sub = n.subscribe("/cmd_vel" , 60 , cmdVelCallback);
  190. roscan_send_message = n.advertise<can_msgs::Frame>("/sent_messages", 100);
  191. ros::spin();
  192. }

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号