caster_hardware_socketcan.cpp
Go to the documentation of this file.
2 
3 #include <math.h>
4 #include <errno.h>
5 
6 const uint16_t kCanOpenSendHeader = 0x600;
7 const uint16_t kCanOpenRecvHeader = 0x580;
8 
13 
14 }
15 
16 std::string iqr::CasterHardware::ToBinary(size_t data, uint8_t length) {
17  std::string data_binary = "";
18  for(int i=0; i<length*8; i++) {
19  data_binary.append(std::to_string((data>>i)&0x01));
20  }
21 
22  return data_binary;
23 }
24 
29 }
30 
31 bool iqr::CasterHardware::SetDigitalOutputCB(caster_base::SetDigitalOutput::Request &req, caster_base::SetDigitalOutput::Response &res) {
32  ROS_INFO("set digital output %d to %d", req.io, req.active);
33 
34  if(req.io>=1 && req.io<=4) {
35  if(req.active == true) {
36  Command(kSetIndividualDO, 0x00, static_cast<uint8_t>(req.io), 1);
37  } else if (req.active == false) {
38  Command(kResetIndividualDO, 0x00, static_cast<uint8_t>(req.io), 1);
39  }
40 
41  res.result = true;
42  } else {
43  ROS_WARN("digital pin should be in 1-4, now is %d", req.io);
44  res.result = false;
45  }
46 
47  return true;
48 }
49 
50 void iqr::CasterHardware::Initialize(std::string node_name, ros::NodeHandle& nh, ros::NodeHandle& private_nh) {
51  node_name_ = node_name;
52  nh_ = nh;
53  private_nh_ = private_nh;
54 
55  private_nh_.param<std::string>("can_send_topic", send_topic_, "sent_messages");
56  private_nh_.param<std::string>("can_receive_topic", receive_topic_, "received_messages");
57  private_nh_.param<int>("can_id", can_id_, 1);
58  private_nh_.param<std::string>("left_wheel_joint", left_wheel_joint_, "drive_wheel_left_joint");
59  private_nh_.param<std::string>("right_wheel_joint", right_wheel_joint_, "drive_wheel_right_joint");
60 
61  can_pub_ = nh_.advertise<can_msgs::Frame>(send_topic_, 1000);
63 
65 
68 
70 
71  diagnostic_updater_.setHardwareID("caster_robot");
76 
77  // Clear();
78 
79  ROS_INFO("can_pub: %s, can_sub: %s, can_id: %d", send_topic_.c_str(), receive_topic_.c_str(), can_id_);
80  ROS_INFO("caster base initialized");
81 }
82 
83 void iqr::CasterHardware::LeftMotorCheck(diagnostic_updater::DiagnosticStatusWrapper& status) {
84  /* request motor flags
85  * f1 = Amps Limit currently active
86  * f2 = Motor stalled
87  * f3 = Loop Error detected
88  * f4 = Safety Stop active
89  * f5 = Forward Limit triggered
90  * f6 = Reverse Limit triggered
91  * f7 = Amps Trigger activated
92  */
93 
94  status.add("current (A)", motor_status_[kLeftMotor].current);
95  status.add("speed (RPM)", motor_status_[kLeftMotor].rpm);
96 
97  // ROS_INFO("motor %s", ToBinary(motor_status_[kLeftMotor].status, 1).c_str());
98 
99  status.summary(diagnostic_msgs::DiagnosticStatus::OK, "OK");
100  if((motor_status_[kLeftMotor].status)&0x01 == 0x01) {
101  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Amps Limit currently active");
102  }
103  if((motor_status_[kLeftMotor].status>>1)&0x01 == 0x01) {
104  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Motor stalled");
105  }
106  if((motor_status_[kLeftMotor].status>>2)&0x01 == 0x01) {
107  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Loop Error detected");
108  }
109  //if(motor_status_[kLeftMotor].status&0x08 == 0x08) {
110  if((motor_status_[kLeftMotor].status>>3)&0x01 == 0x01) {
111  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::WARN, "Safety Stop active");
112  }
113  if((motor_status_[kLeftMotor].status>>4)&0x01 == 0x01) {
114  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Forward Limit triggered");
115  }
116  if((motor_status_[kLeftMotor].status>>5)&0x01 == 0x01) {
117  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Reverse Limit triggered");
118  }
119  if((motor_status_[kLeftMotor].status>>6)&0x01 == 0x01) {
120  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Amps Trigger activated");
121  }
122 }
123 
124 void iqr::CasterHardware::RightMotorCheck(diagnostic_updater::DiagnosticStatusWrapper& status) {
125  /* request motor flags
126  * f1 = Amps Limit currently active
127  * f2 = Motor stalled
128  * f3 = Loop Error detected
129  * f4 = Safety Stop active
130  * f5 = Forward Limit triggered
131  * f6 = Reverse Limit triggered
132  * f7 = Amps Trigger activated
133  */
134 
135  status.add("current (A)", motor_status_[kRightMotor].current);
136  status.add("speed (RPM)", motor_status_[kRightMotor].rpm);
137  // status.add("counter", motor_status_[kRightMotor].counter);
138 
139  // ROS_INFO("motor %s", ToBinary(motor_status_[kLeftMotor].status, 1).c_str());
140 
141  status.summary(diagnostic_msgs::DiagnosticStatus::OK, "OK");
142  if((motor_status_[kRightMotor].status)&0x01 == 0x01) {
143  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Amps Limit currently active");
144  }
145  if((motor_status_[kRightMotor].status>>1)&0x01 == 0x01) {
146  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Motor stalled");
147  }
148  if((motor_status_[kRightMotor].status>>2)&0x01 == 0x01) {
149  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Loop Error detected");
150  }
151  if((motor_status_[kRightMotor].status>>3)&0x01 == 0x01) {
152  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::WARN, "Safety Stop active");
153  }
154  if((motor_status_[kRightMotor].status>>4)&0x01 == 0x01) {
155  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Forward Limit triggered");
156  }
157  if((motor_status_[kRightMotor].status>>5)&0x01 == 0x01) {
158  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Reverse Limit triggered");
159  }
160  if((motor_status_[kRightMotor].status>>6)&0x01 == 0x01) {
161  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Amps Trigger activated");
162  }
163 }
164 
165 void iqr::CasterHardware::StatusCheck(diagnostic_updater::DiagnosticStatusWrapper& status) {
166  /* request status flags
167  * f1 = Serial mode
168  * f2 = Pulse mode
169  * f3 = Analog mode
170  * f4 = Power stage off
171  * f5 = Stall detected
172  * f6 = At limit
173  * f7 = Unused
174  * f8 = MicroBasic script running
175  */
176 
177  std::string contorl_mode = "unknown";
178 
179  if((status_flags_)&0x01 == 0x01) {
180  contorl_mode = "Serial mode";
181  }
182  if((status_flags_>>1)&0x01 == 0x01) {
183  contorl_mode = "Pulse mode";
184  }
185  if((status_flags_>>2)&0x01 == 0x01) {
186  contorl_mode = "Analog mode";
187  }
188 
189  status.add("Control mode", contorl_mode);
190 
191  status.summary(diagnostic_msgs::DiagnosticStatus::OK, "OK");
192  if(contorl_mode == "unknown") {
193  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::WARN, "unknown control mode");
194  }
195  if((status_flags_>>3)&0x01 == 0x01) {
196  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Power stage off");
197  }
198  if((status_flags_>>4)&0x01 == 0x01) {
199  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Stall detected");
200  }
201  if((status_flags_>>5)&0x01 == 0x01) {
202  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "At limit");
203  }
204  if((status_flags_>>6)&0x01 == 0x01) {
205  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Unused");
206  }
207  if((status_flags_>>7)&0x01 == 0x01) {
208  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::OK, "MicroBasic script running");
209  }
210 }
211 
212 void iqr::CasterHardware::ControllerCheck(diagnostic_updater::DiagnosticStatusWrapper& status) {
213  /* request fault flags
214  * f1 = Overheat
215  * f2 = Overvoltage
216  * f3 = Undervoltage
217  * f4 = Short circuit
218  * f5 = Emergency stop
219  * f6 = Brushless sensor fault
220  * f7 = MOSFET failure
221  * f8 = Default configuration loaded at startup
222  */
223 
224  status.summary(diagnostic_msgs::DiagnosticStatus::OK, "OK");
225  if((fault_flags_)&0x01 == 0x01) {
226  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Overheat");
227  }
228  if((fault_flags_>>1)&0x01 == 0x01) {
229  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Overvoltage");
230  }
231  if((fault_flags_>>2)&0x01 == 0x01) {
232  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Undervoltage");
233  }
234  if((fault_flags_>>3)&0x01 == 0x01) {
235  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Short circuit");
236  }
237  if((fault_flags_>>4)&0x01 == 0x01) {
238  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Emergency stop");
239  }
240  if((fault_flags_>>5)&0x01 == 0x01) {
241  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Brushless sensor fault");
242  }
243  if((fault_flags_>>6)&0x01 == 0x01) {
244  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "MOSFET failure");
245  }
246  if((fault_flags_>>7)&0x01 == 0x01) {
247  status.mergeSummary(diagnostic_msgs::DiagnosticStatus::WARN, "Default configuration loaded at startup");
248  }
249 }
250 
251 void iqr::CasterHardware::CanReceiveCallback(const can_msgs::Frame::ConstPtr& msg) {
252  // ROS_INFO_STREAM("get msg: " << msg->id);
253  if(msg->id == kCanOpenRecvHeader+can_id_) {
254  // ROS_INFO("data length: %d", msg->dlc);
255 
256  if((msg->data[0]&0xF0) == kQuery<<4) {
257  uint16_t index = (msg->data[2]<<8) + msg->data[1];
258  uint8_t sub_index = msg->data[3];
259 
260  // ROS_INFO("Response: query %02X,%02X successful", index, sub_index);
261 
262  switch (index) {
263  case kReadMotorAmps: {
264  int16_t temp_current_x10;
265  memcpy(&temp_current_x10, msg->data.data()+4, 2);
266  motor_status_[sub_index-1].current = temp_current_x10 / 10.0;
267  // ROS_INFO("Query response, motor current %d: %f", sub_index, motor_status_[sub_index-1].current);
268  break;
269  }
270  case kReadAbsBLCounter: {
271  memcpy(&motor_status_[sub_index-1].counter, msg->data.data()+4, 4);
272  if(motor_status_[sub_index-1].counter_reset == false) {
273  motor_status_[sub_index-1].counter_offset = motor_status_[sub_index-1].counter;
274  motor_status_[sub_index-1].counter_reset = true;
275  }
276  // ROS_INFO("Query response, counter %d: %d", sub_index, motor_status_[sub_index-1].counter);
277  break;
278  }
279  case kReadBLMotorRPM: {
280  memcpy(&motor_status_[sub_index-1].rpm, msg->data.data()+4, 2);
281  // ROS_INFO("Query response, rpm %d: %d", sub_index, motor_status_[sub_index-1].rpm);
282  break;
283  }
284  case kReadStatusFlags: {
285  status_flags_ = msg->data[4];
286  // ROS_INFO("Query response, status flags %s", ToBinary(status_flags_, 1).c_str());
287  break;
288  }
289  case kReadFaultFlags: {
290  fault_flags_ = msg->data[4];
291  // ROS_INFO("Query response, fault flags %s", ToBinary(fault_flags_, 1).c_str());
292  break;
293  }
294  case kReadMotorStatusFlags: {
295  /* TODO: the index of data is different from doc */
296  motor_status_[kLeftMotor].status = msg->data[4];
297  motor_status_[kRightMotor].status = msg->data[6];
298  // ROS_INFO("Query response, motor status flags %s: %s", ToBinary(motor_status_[kLeftMotor].status, 1).c_str(), ToBinary(motor_status_[kRightMotor].status, 1).c_str());
299  break;
300  }
301  default: {
302 
303  }
304  }
305  } else if((msg->data[0]&0xF0) == kResponseCommandSuccess<<4) {
306  uint16_t index = (msg->data[2]<<8) + msg->data[1];
307  uint8_t sub_index = msg->data[3];
308  // ROS_INFO("Response: command %02X,%02X successful", index, sub_index);
309  }
310  }
311 }
312 
314  /* Clear BL Counter */
315  // Command(kSetBLCounter, static_cast<uint8_t>(kLeftMotor+1), 0, 4);
316  // Command(kSetBLCounter, static_cast<uint8_t>(kRightMotor+1), 0, 4);
317  // motor_status_[kLeftMotor].counter_offset = motor_status_[kLeftMotor].counter;
318  // motor_status_[kRightMotor].counter_offset = motor_status_[kRightMotor].counter;
319 }
320 
322  bool success = false;
323  uint32_t data;
324 
325  /* request motor speed */
326  // int16_t l_rpm=-1, r_rpm=-1;
327  // uint32_t left_rpm=-1, right_rpm=-1;
328  success = Query(kReadBLMotorRPM, static_cast<uint8_t>(kLeftMotor+1), 2);
329  success = Query(kReadBLMotorRPM, static_cast<uint8_t>(kRightMotor+1), 2);
330  // l_rpm = static_cast<int16_t>(left_rpm);
331  // r_rpm = static_cast<int16_t>(right_rpm);
332 
333  /* request motor counter */
334  // int32_t l_count=-1, r_count=-1;
335  success = Query(kReadAbsBLCounter, static_cast<uint8_t>(kLeftMotor+1), 4);
336  success = Query(kReadAbsBLCounter, static_cast<uint8_t>(kRightMotor+1), 4);
337 
338  // uint8_t status_flag;
339  success = Query(kReadStatusFlags, 0x00, 1);
340  // status_flag = static_cast<uint8_t>(data);
341 
342  // uint8_t fault_flag;
343  success = Query(kReadFaultFlags, 0x00, 1);
344  // fault_flag = static_cast<uint8_t>(data);
345 
346  /* TODO: strange rules for opencan id */
347  // uint8_t left_motor_flag, right_motor_flag;
348  success = Query(kReadMotorStatusFlags, 0x01, 4);
349  // left_motor_flag = data;
350  // right_motor_flag = data >> 16;
351 
352  success = Query(kReadMotorAmps, 0x01, 4);
353  success = Query(kReadMotorAmps, 0x02, 4);
354 
356  joints_[kRightMotor].velocity = motor_status_[kRightMotor].rpm / 60.0 / REDUCTION_RATIO * M_PI * 2.0 * -1.0;
357 
360 
361  diagnostic_updater_.update();
362 
363  // ROS_INFO("motor counter: %d, %d, %d, %d", motor_status_[kLeftMotor].counter, motor_status_[kRightMotor].counter, motor_status_[kLeftMotor].rpm, motor_status_[kRightMotor].rpm);
364  // ROS_INFO("motor counter: %f, %f, %d, %d", joints_[0].position, joints_[1].position, l_rpm, r_rpm);
365  // ROS_INFO("status: %s, fault: %s, left: %s, right: %s", \
366  ToBinary(status_flag, sizeof(status_flag)).c_str(), ToBinary(fault_flag, sizeof(fault_flag)).c_str(), \
367  ToBinary(left_motor_flag, sizeof(left_motor_flag)).c_str(), ToBinary(right_motor_flag, sizeof(right_motor_flag)).c_str());
368 }
369 
374 
375 }
376 
381  hardware_interface::JointStateHandle left_wheel_joint_state_handle(left_wheel_joint_, &joints_[0].position, &joints_[0].velocity, &joints_[0].effort);
382  joint_state_interface_.registerHandle(left_wheel_joint_state_handle);
383 
384  hardware_interface::JointHandle left_wheel_joint_handle(left_wheel_joint_state_handle, &joints_[0].velocity_command);
385  velocity_joint_interface_.registerHandle(left_wheel_joint_handle);
386 
387  hardware_interface::JointStateHandle right_wheel_joint_state_handle(right_wheel_joint_, &joints_[1].position, &joints_[1].velocity, &joints_[1].effort);
388  joint_state_interface_.registerHandle(right_wheel_joint_state_handle);
389 
390  hardware_interface::JointHandle right_wheel_joint_handle(right_wheel_joint_state_handle, &joints_[1].velocity_command);
391  velocity_joint_interface_.registerHandle(right_wheel_joint_handle);
392 
395 }
396 
398  int32_t speed[2];
399 
400  speed[0] = static_cast<int32_t>(joints_[0].velocity_command / M_PI / 2.0 * REDUCTION_RATIO * 60);
401  // int16_t s_v = ntohl(speed);
402  // memcpy(buf+5, &s_v, 4);
403  Command(kSetVelocity, static_cast<uint8_t>(kLeftMotor+1), static_cast<uint32_t>(speed[0]), 4);
404  // SendCanOpenData(1, kCommand, kSetVelocity, static_cast<uint8_t>(kLeftMotor), static_cast<uint32_t>(speed[0]), 4);
405 
406  speed[1] = static_cast<int32_t>(joints_[1].velocity_command / M_PI / 2.0 * REDUCTION_RATIO * 60) * -1.0;
407  // s_v = ntohl(speed);
408  // memcpy(buf+9, &s_v, 4);
409  Command(kSetVelocity, static_cast<uint8_t>(kRightMotor+1), static_cast<uint32_t>(speed[1]), 4);
410  // SendCanOpenData(1, kCommand, kSetVelocity, static_cast<uint8_t>(kRightMotor), static_cast<uint32_t>(speed[1]), 4);
411 
412  // ROS_INFO("command: %f, %f; rad: %d, %d", joints_[0].velocity_command, joints_[1].velocity_command, speed[0], speed[1]);
413 }
414 
415 
416 void iqr::CasterHardware::SendCanOpenData(uint32_t node_id, RoboteqClientCommandType type, RoboteqCanOpenObjectDictionary index, uint8_t sub_index, uint32_t data, uint8_t data_length) {
417  uint8_t buf[8];
418  bzero(buf, 8);
419 
420  can_msgs::Frame frame;
421  frame.header.stamp = ros::Time::now();
422 
423  frame.id = kCanOpenSendHeader + node_id;
424  frame.is_rtr = 0;
425  frame.is_extended = 0;
426  frame.is_error = 0;
427  frame.dlc = 8;
428 
429  /* set command type and data length */
430  buf[0] = (type<<4) + ((4-data_length) << 2);
431 
432  /* set index and sub index*/
433  memcpy(buf+1, &index, 2);
434  memcpy(buf+3, &sub_index, 1);
435 
436  /* set data */
437  memcpy(buf+4, &data, data_length);
438 
439  for(int i=0; i<8; i++) {
440  frame.data[i] = buf[i];
441  }
442 
443  /* send */
444  // ROS_INFO("sending");
445  can_pub_.publish(frame);
446  // ROS_INFO("Sent");
447 }
448 
449 bool iqr::CasterHardware::Query(RoboteqCanOpenObjectDictionary query, uint8_t sub_index, uint8_t data_length) {
450  SendCanOpenData(can_id_, kQuery, query, sub_index, 0x0000, data_length);
451 
452  return true;
453 }
454 
455 bool iqr::CasterHardware::Command(RoboteqCanOpenObjectDictionary query, uint8_t sub_index, uint32_t data, uint8_t data_length) {
456  SendCanOpenData(can_id_, kCommand, query, sub_index, data, data_length);
457 
458  return true;
459 }
bool Query(RoboteqCanOpenObjectDictionary query, uint8_t sub_index, uint8_t data_length)
#define REDUCTION_RATIO
void ControllerCheck(diagnostic_updater::DiagnosticStatusWrapper &status)
std::string ToBinary(size_t data, uint8_t length)
void publish(const boost::shared_ptr< M > &message) const
void Initialize(std::string node_name, ros::NodeHandle &nh, ros::NodeHandle &private_nh)
ros::ServiceServer set_io_service_
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
diagnostic_updater::Updater diagnostic_updater_
void CanReceiveCallback(const can_msgs::Frame::ConstPtr &msg)
const uint16_t kCanOpenSendHeader
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
#define ROS_WARN(...)
void StatusCheck(diagnostic_updater::DiagnosticStatusWrapper &status)
const uint16_t kCanOpenRecvHeader
void ControllerTimerCallback(const ros::TimerEvent &)
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void registerHandle(const JointStateHandle &handle)
_u16 rpm
void RightMotorCheck(diagnostic_updater::DiagnosticStatusWrapper &status)
bool SetDigitalOutputCB(caster_base::SetDigitalOutput::Request &req, caster_base::SetDigitalOutput::Response &res)
hardware_interface::JointStateInterface joint_state_interface_
bool Command(RoboteqCanOpenObjectDictionary query, uint8_t sub_index, uint32_t data, uint8_t data_length)
struct iqr::CasterHardware::Joint joints_[2]
static Time now()
_u8 data[0]
void update(const ros::Time &time, const ros::Duration &period, bool reset_controllers=false)
hardware_interface::VelocityJointInterface velocity_joint_interface_
void LeftMotorCheck(diagnostic_updater::DiagnosticStatusWrapper &status)
void SendCanOpenData(uint32_t node_id, RoboteqClientCommandType type, RoboteqCanOpenObjectDictionary index, uint8_t sub_index, uint32_t data, uint8_t data_length)
controller_manager::ControllerManager * controller_manager_


caster_base
Author(s): Ye Tian
autogenerated on Wed Dec 18 2019 03:34:39