ypspur_ros.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-2017, the ypspur_ros authors
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <ros/ros.h>
31 
32 #include <diagnostic_msgs/DiagnosticArray.h>
33 #include <geometry_msgs/Twist.h>
34 #include <geometry_msgs/WrenchStamped.h>
35 #include <nav_msgs/Odometry.h>
36 #include <sensor_msgs/JointState.h>
37 #include <std_msgs/Bool.h>
38 #include <std_msgs/Float32.h>
39 #include <std_msgs/Float32MultiArray.h>
40 #include <trajectory_msgs/JointTrajectory.h>
41 #include <ypspur_ros/ControlMode.h>
42 #include <ypspur_ros/DigitalInput.h>
43 #include <ypspur_ros/DigitalOutput.h>
44 #include <ypspur_ros/JointPositionControl.h>
45 
46 #include <tf2/utils.h>
50 
51 #include <signal.h>
52 #include <string.h>
53 #include <sys/ipc.h>
54 #include <sys/msg.h>
55 #include <sys/types.h>
56 #include <sys/wait.h>
57 
58 #include <boost/atomic.hpp>
59 #include <boost/chrono.hpp>
60 #include <boost/thread.hpp>
61 #include <boost/thread/future.hpp>
62 
63 #include <exception>
64 #include <map>
65 #include <string>
66 #include <vector>
67 
68 #include <compatibility.h>
69 
70 namespace YP
71 {
72 #include <ypspur.h>
73 } // namespace YP
74 
75 bool g_shutdown = false;
76 void sigintHandler(int sig)
77 {
78  g_shutdown = true;
79 }
80 
82 {
83 private:
86  std::map<std::string, ros::Publisher> pubs_;
87  std::map<std::string, ros::Subscriber> subs_;
91  const tf2::Vector3 z_axis_;
92 
93  std::string port_;
94  std::string param_file_;
95  std::string ypspur_bin_;
96  std::map<std::string, std::string> frames_;
97  std::map<std::string, double> params_;
98  int key_;
99  bool simulate_;
101 
103 
104  pid_t pid_;
105 
107  {
109  NONE
110  };
113  {
114  public:
115  int id_;
116  std::string name_;
117  double accel_;
118  double vel_;
119  double angle_ref_;
120  double vel_ref_;
121  double vel_end_;
123  {
127  TRAJECTORY
128  };
130  trajectory_msgs::JointTrajectory cmd_joint_;
131  };
132  std::vector<JointParams> joints_;
133  std::map<std::string, int> joint_name_to_num_;
134 
135  class AdParams
136  {
137  public:
138  bool enable_;
139  std::string name_;
140  double gain_;
141  double offset_;
142  };
143  class DioParams
144  {
145  public:
146  bool enable_;
147  std::string name_;
148  bool input_;
149  bool output_;
150  };
152  std::vector<AdParams> ads_;
153  std::vector<DioParams> dios_;
154  const int ad_num_ = 8;
155  unsigned int dio_output_;
156  unsigned int dio_dir_;
157  unsigned int dio_output_default_;
158  unsigned int dio_dir_default_;
159  const int dio_num_ = 8;
160  std::map<int, ros::Time> dio_revert_;
161 
165 
166  geometry_msgs::Twist::ConstPtr cmd_vel_;
169 
171 
172  void cbControlMode(const ypspur_ros::ControlMode::ConstPtr& msg)
173  {
174  control_mode_ = msg->vehicle_control_mode;
175  switch (control_mode_)
176  {
177  case ypspur_ros::ControlMode::OPEN:
178  YP::YP_openfree();
179  break;
180  case ypspur_ros::ControlMode::TORQUE:
181  YP::YPSpur_free();
182  break;
183  case ypspur_ros::ControlMode::VELOCITY:
184  break;
185  }
186  }
187  void cbCmdVel(const geometry_msgs::Twist::ConstPtr& msg)
188  {
189  cmd_vel_ = msg;
190  cmd_vel_time_ = ros::Time::now();
191  if (control_mode_ == ypspur_ros::ControlMode::VELOCITY)
192  {
193  YP::YPSpur_vel(msg->linear.x, msg->angular.z);
194  }
195  }
196  void cbJoint(const trajectory_msgs::JointTrajectory::ConstPtr& msg)
197  {
198  const ros::Time now = ros::Time::now();
199 
200  std_msgs::Header header = msg->header;
201  if (header.stamp == ros::Time(0))
202  header.stamp = now;
203 
204  std::map<std::string, trajectory_msgs::JointTrajectory> new_cmd_joints;
205  size_t i = 0;
206  for (const std::string& name : msg->joint_names)
207  {
208  trajectory_msgs::JointTrajectory cmd_joint;
209  cmd_joint.header = header;
210  cmd_joint.joint_names.resize(1);
211  cmd_joint.joint_names[0] = name;
212  cmd_joint.points.clear();
213  std::string err_msg;
214  for (auto& cmd : msg->points)
215  {
216  if (header.stamp + cmd.time_from_start < now)
217  {
218  ROS_ERROR(
219  "Ignored outdated JointTrajectory command "
220  "(joint: %s, now: %0.6lf, stamp: %0.6lf, time_from_start: %0.6lf)",
221  name.c_str(), now.toSec(), header.stamp.toSec(), cmd.time_from_start.toSec());
222  break;
223  }
224 
225  trajectory_msgs::JointTrajectoryPoint p;
226  p.time_from_start = cmd.time_from_start;
227  p.positions.resize(1);
228  p.velocities.resize(1);
229  if (cmd.velocities.size() <= i)
230  p.velocities[0] = 0.0;
231  else
232  p.velocities[0] = cmd.velocities[i];
233  p.positions[0] = cmd.positions[i];
234 
235  cmd_joint.points.push_back(p);
236  }
237  i++;
238 
239  if (cmd_joint.points.size() != msg->points.size())
240  return;
241 
242  new_cmd_joints[name] = cmd_joint;
243  }
244  // Apply if all JointTrajectoryPoints are valid
245  for (auto& new_cmd_joint : new_cmd_joints)
246  {
247  const int joint_num = joint_name_to_num_[new_cmd_joint.first];
248  joints_[joint_num].control_ = JointParams::TRAJECTORY;
249  joints_[joint_num].cmd_joint_ = new_cmd_joint.second;
250  }
251  }
252  void cbSetVel(const std_msgs::Float32::ConstPtr& msg, int num)
253  {
254  // printf("set_vel %d %d %f\n", num, joints_[num].id_, msg->data);
255  joints_[num].vel_ = msg->data;
256  YP::YP_set_joint_vel(joints_[num].id_, joints_[num].vel_);
257  }
258  void cbSetAccel(const std_msgs::Float32::ConstPtr& msg, int num)
259  {
260  // printf("set_accel %d %d %f\n", num, joints_[num].id_, msg->data);
261  joints_[num].accel_ = msg->data;
262  YP::YP_set_joint_accel(joints_[num].id_, joints_[num].accel_);
263  }
264  void cbVel(const std_msgs::Float32::ConstPtr& msg, int num)
265  {
266  // printf("vel_ %d %d %f\n", num, joints_[num].id_, msg->data);
267  joints_[num].vel_ref_ = msg->data;
268  joints_[num].control_ = JointParams::VELOCITY;
269  YP::YP_joint_vel(joints_[num].id_, joints_[num].vel_ref_);
270  }
271  void cbAngle(const std_msgs::Float32::ConstPtr& msg, int num)
272  {
273  joints_[num].angle_ref_ = msg->data;
274  joints_[num].control_ = JointParams::POSITION;
275  YP::YP_joint_ang(joints_[num].id_, joints_[num].angle_ref_);
276  }
277  void cbJointPosition(const ypspur_ros::JointPositionControl::ConstPtr& msg)
278  {
279  int i = 0;
280  for (auto& name : msg->joint_names)
281  {
282  if (joint_name_to_num_.find(name) == joint_name_to_num_.end())
283  {
284  ROS_ERROR("Unknown joint name '%s'", name.c_str());
285  continue;
286  }
287  int num = joint_name_to_num_[name];
288  // printf("%s %d %d %f", name.c_str(), num, joints_[num].id_, msg->positions[i]);
289  joints_[num].vel_ = msg->velocities[i];
290  joints_[num].accel_ = msg->accelerations[i];
291  joints_[num].angle_ref_ = msg->positions[i];
292  joints_[num].control_ = JointParams::POSITION;
293 
294  YP::YP_set_joint_vel(joints_[num].id_, joints_[num].vel_);
295  YP::YP_set_joint_accel(joints_[num].id_, joints_[num].accel_);
296  YP::YP_joint_ang(joints_[num].id_, joints_[num].angle_ref_);
297  i++;
298  }
299  }
300 
301  void cbDigitalOutput(const ypspur_ros::DigitalOutput::ConstPtr& msg, int id_)
302  {
303  const auto dio_output_prev = dio_output_;
304  const auto dio_dir_prev = dio_dir_;
305  const unsigned int mask = 1 << id_;
306 
307  switch (msg->output)
308  {
309  case ypspur_ros::DigitalOutput::HIGH_IMPEDANCE:
310  dio_output_ &= ~mask;
311  dio_dir_ &= ~mask;
312  break;
313  case ypspur_ros::DigitalOutput::LOW:
314  dio_output_ &= ~mask;
315  dio_dir_ |= mask;
316  break;
317  case ypspur_ros::DigitalOutput::HIGH:
318  dio_output_ |= mask;
319  dio_dir_ |= mask;
320  break;
321  case ypspur_ros::DigitalOutput::PULL_UP:
322  dio_output_ |= mask;
323  dio_dir_ &= ~mask;
324  break;
325  case ypspur_ros::DigitalOutput::PULL_DOWN:
326  ROS_ERROR("Digital IO pull down is not supported on this system");
327  break;
328  }
329  if (dio_output_ != dio_output_prev)
330  YP::YP_set_io_data(dio_output_);
331  if (dio_dir_ != dio_dir_prev)
332  YP::YP_set_io_dir(dio_dir_);
333 
334  if (msg->toggle_time > ros::Duration(0))
335  {
336  dio_revert_[id_] = ros::Time::now() + msg->toggle_time;
337  }
338  }
339  void revertDigitalOutput(int id_)
340  {
341  const auto dio_output_prev = dio_output_;
342  const auto dio_dir_prev = dio_dir_;
343  const unsigned int mask = 1 << id_;
344 
345  dio_output_ &= ~mask;
346  dio_output_ |= dio_output_default_ & mask;
347  dio_dir_ &= ~mask;
348  dio_dir_ |= dio_output_default_ & mask;
349 
350  if (dio_output_ != dio_output_prev)
351  YP::YP_set_io_data(dio_output_);
352  if (dio_dir_ != dio_dir_prev)
353  YP::YP_set_io_dir(dio_dir_);
354 
355  dio_revert_[id_] = ros::Time(0);
356  }
357  void updateDiagnostics(const ros::Time& now, const bool connection_down = false)
358  {
359  const int connection_error = connection_down ? 1 : YP::YP_get_error_state();
360  double t = 0;
361 
362  int err = 0;
363  if (!connection_error)
364  t = YP::YP_get_device_error_state(0, &err);
365  device_error_state_ |= err;
366 
367  if (device_error_state_time_ + ros::Duration(1.0) < now || connection_down ||
368  device_error_state_ != device_error_state_prev_)
369  {
370  device_error_state_time_ = now;
371  device_error_state_prev_ = device_error_state_;
372 
373  diagnostic_msgs::DiagnosticArray msg;
374  msg.header.stamp = now;
375  msg.status.resize(1);
376  msg.status[0].name = "YP-Spur Motor Controller";
377  msg.status[0].hardware_id = "ipc-key" + std::to_string(key_);
378  if (device_error_state_ == 0 && connection_error == 0)
379  {
380  if (t == 0)
381  {
382  msg.status[0].level = diagnostic_msgs::DiagnosticStatus::OK;
383  msg.status[0].message = "Motor controller doesn't "
384  "provide device error state.";
385  }
386  else
387  {
388  if (ros::Time(t) < now - ros::Duration(1.0))
389  {
390  msg.status[0].level = diagnostic_msgs::DiagnosticStatus::ERROR;
391  msg.status[0].message = "Motor controller doesn't "
392  "update latest device error state.";
393  }
394  else
395  {
396  msg.status[0].level = diagnostic_msgs::DiagnosticStatus::OK;
397  msg.status[0].message = "Motor controller is running without error.";
398  }
399  }
400  }
401  else
402  {
403  msg.status[0].level = diagnostic_msgs::DiagnosticStatus::ERROR;
404  if (connection_error)
405  msg.status[0].message +=
406  "Connection to ypspur-coordinator is down.";
407  if (device_error_state_)
408  msg.status[0].message +=
409  std::string((msg.status[0].message.size() > 0 ? " " : "")) +
410  "Motor controller reported error id " +
411  std::to_string(device_error_state_) + ".";
412  }
413  msg.status[0].values.resize(2);
414  msg.status[0].values[0].key = "connection_error";
415  msg.status[0].values[0].value = std::to_string(connection_error);
416  msg.status[0].values[1].key = "device_error";
417  msg.status[0].values[1].value = std::to_string(device_error_state_);
418 
419  pubs_["diag"].publish(msg);
420  device_error_state_ = 0;
421  }
422  }
423 
424 public:
426  : nh_()
427  , pnh_("~")
428  , tf_listener_(tf_buffer_)
429  , z_axis_(0, 0, 1)
430  , device_error_state_(0)
431  , device_error_state_prev_(0)
432  , device_error_state_time_(0)
433  {
435 
436  pnh_.param("port", port_, std::string("/dev/ttyACM0"));
437  pnh_.param("ipc_key", key_, 28741);
438  pnh_.param("simulate", simulate_, false);
439  pnh_.param("simulate_control", simulate_control_, false);
440  if (simulate_control_)
441  simulate_ = true;
442  pnh_.param("ypspur_bin", ypspur_bin_, std::string("ypspur-coordinator"));
443  pnh_.param("param_file", param_file_, std::string(""));
444  pnh_.param("tf_time_offset", tf_time_offset_, 0.0);
445 
446  double cmd_vel_expire_s;
447  pnh_.param("cmd_vel_expire", cmd_vel_expire_s, -1.0);
448  cmd_vel_expire_ = ros::Duration(cmd_vel_expire_s);
449 
450  std::string ad_mask("");
451  ads_.resize(ad_num_);
452  for (int i = 0; i < ad_num_; i++)
453  {
454  pnh_.param(std::string("ad") + std::to_string(i) + std::string("_enable"),
455  ads_[i].enable_, false);
456  pnh_.param(std::string("ad") + std::to_string(i) + std::string("_name"),
457  ads_[i].name_, std::string("ad") + std::to_string(i));
458  pnh_.param(std::string("ad") + std::to_string(i) + std::string("_gain"),
459  ads_[i].gain_, 1.0);
460  pnh_.param(std::string("ad") + std::to_string(i) + std::string("_offset"),
461  ads_[i].offset_, 0.0);
462  ad_mask = (ads_[i].enable_ ? std::string("1") : std::string("0")) + ad_mask;
463  pubs_["ad/" + ads_[i].name_] = compat::advertise<std_msgs::Float32>(
464  nh_, "ad/" + ads_[i].name_,
465  pnh_, "ad/" + ads_[i].name_, 1);
466  }
467  digital_input_enable_ = false;
468  dio_output_default_ = 0;
469  dio_dir_default_ = 0;
470  dios_.resize(dio_num_);
471  for (int i = 0; i < dio_num_; i++)
472  {
474  pnh_.param(std::string("dio") + std::to_string(i) + std::string("_enable"),
475  param.enable_, false);
476  if (param.enable_)
477  {
478  pnh_.param(std::string("dio") + std::to_string(i) + std::string("_name"),
479  param.name_, std::string(std::string("dio") + std::to_string(i)));
480 
481  pnh_.param(std::string("dio") + std::to_string(i) + std::string("_output"),
482  param.output_, true);
483  pnh_.param(std::string("dio") + std::to_string(i) + std::string("_input"),
484  param.input_, false);
485 
486  if (param.output_)
487  {
488  subs_[param.name_] = compat::subscribe<ypspur_ros::DigitalOutput>(
489  nh_, param.name_,
490  pnh_, param.name_, 1,
491  boost::bind(&YpspurRosNode::cbDigitalOutput, this, _1, i));
492  }
493 
494  std::string output_default;
495  pnh_.param(std::string("dio") + std::to_string(i) + std::string("_default"),
496  output_default, std::string("HIGH_IMPEDANCE"));
497  if (output_default.compare("HIGH_IMPEDANCE") == 0)
498  {
499  }
500  else if (output_default.compare("LOW") == 0)
501  {
502  dio_dir_default_ |= 1 << i;
503  }
504  else if (output_default.compare("HIGH") == 0)
505  {
506  dio_dir_default_ |= 1 << i;
507  dio_output_default_ |= 1 << i;
508  }
509  else if (output_default.compare("PULL_UP") == 0)
510  {
511  dio_output_default_ |= 1 << i;
512  }
513  else if (output_default.compare("PULL_DOWN") == 0)
514  {
515  ROS_ERROR("Digital IO pull down is not supported on this system");
516  }
517  if (param.input_)
518  digital_input_enable_ = true;
519  }
520  dios_[i] = param;
521  }
522  dio_output_ = dio_output_default_;
523  dio_dir_ = dio_dir_default_;
524  if (digital_input_enable_)
525  {
526  pubs_["din"] = compat::advertise<ypspur_ros::DigitalInput>(
527  nh_, "digital_input",
528  pnh_, "digital_input", 2);
529  }
530 
531  pnh_.param("odom_id", frames_["odom"], std::string("odom"));
532  pnh_.param("base_link_id", frames_["base_link"], std::string("base_link"));
533  pnh_.param("origin_id", frames_["origin"], std::string(""));
534  pnh_.param("hz", params_["hz"], 200.0);
535 
536  std::string mode_name;
537  pnh_.param("OdometryMode", mode_name, std::string("diff"));
538  if (mode_name.compare("diff") == 0)
539  {
540  mode_ = DIFF;
541  pubs_["wrench"] = compat::advertise<geometry_msgs::WrenchStamped>(
542  nh_, "wrench",
543  pnh_, "wrench", 1);
544  pubs_["odom"] = compat::advertise<nav_msgs::Odometry>(
545  nh_, "odom",
546  pnh_, "odom", 1);
547  subs_["cmd_vel"] = compat::subscribe(
548  nh_, "cmd_vel",
549  pnh_, "cmd_vel", 1, &YpspurRosNode::cbCmdVel, this);
550  }
551  else if (mode_name.compare("none") == 0)
552  {
553  }
554  else
555  {
556  throw(std::runtime_error("unknown mode: " + mode_name));
557  }
558 
559  int max_joint_id;
560  bool separated_joint;
561  pnh_.param("max_joint_id", max_joint_id, 32);
562  pnh_.param("separated_joint_control", separated_joint, false);
563  int num = 0;
564  for (int i = 0; i < max_joint_id; i++)
565  {
566  std::string name;
567  name = std::string("joint") + std::to_string(i);
568  if (pnh_.hasParam(name + std::string("_enable")))
569  {
570  bool en;
571  pnh_.param(name + std::string("_enable"), en, false);
572  if (en)
573  {
574  JointParams jp;
575  jp.id_ = i;
576  pnh_.param(name + std::string("_name"), jp.name_, name);
577  pnh_.param(name + std::string("_accel"), jp.accel_, 3.14);
578  joint_name_to_num_[jp.name_] = num;
579  joints_.push_back(jp);
580  // printf("%s %d %d", jp.name_.c_str(), jp.id_, joint_name_to_num_[jp.name_]);
581  if (separated_joint)
582  {
583  subs_[jp.name_ + std::string("_setVel")] = compat::subscribe<std_msgs::Float32>(
584  nh_, jp.name_ + std::string("/set_vel"),
585  pnh_, jp.name_ + std::string("_setVel"), 1,
586  boost::bind(&YpspurRosNode::cbSetVel, this, _1, num));
587  subs_[jp.name_ + std::string("_setAccel")] = compat::subscribe<std_msgs::Float32>(
588  nh_, jp.name_ + std::string("/set_accel"),
589  pnh_, jp.name_ + std::string("_setAccel"), 1,
590  boost::bind(&YpspurRosNode::cbSetAccel, this, _1, num));
591  subs_[jp.name_ + std::string("_vel")] = compat::subscribe<std_msgs::Float32>(
592  nh_, jp.name_ + std::string("/vel"),
593  pnh_, jp.name_ + std::string("_vel"), 1,
594  boost::bind(&YpspurRosNode::cbVel, this, _1, num));
595  subs_[jp.name_ + std::string("_pos")] = compat::subscribe<std_msgs::Float32>(
596  nh_, jp.name_ + std::string("/pos"),
597  pnh_, jp.name_ + std::string("_pos"), 1,
598  boost::bind(&YpspurRosNode::cbAngle, this, _1, num));
599  }
600  subs_[std::string("joint_position")] = compat::subscribe(
601  nh_, std::string("joint_position"),
602  pnh_, std::string("joint_position"), 1, &YpspurRosNode::cbJointPosition, this);
603  num++;
604  }
605  }
606  }
607  if (joints_.size() > 0)
608  {
609  pubs_["joint"] = compat::advertise<sensor_msgs::JointState>(
610  nh_, "joint_states",
611  pnh_, "joint", 2);
612  subs_["joint"] = compat::subscribe(
613  nh_, "joint_trajectory",
614  pnh_, "cmd_joint", joints_.size() * 2, &YpspurRosNode::cbJoint, this);
615  }
616  subs_["control_mode"] = compat::subscribe(
617  nh_, "control_mode",
618  pnh_, "control_mode", 1, &YpspurRosNode::cbControlMode, this);
619  control_mode_ = ypspur_ros::ControlMode::VELOCITY;
620 
621  pubs_["diag"] = nh_.advertise<diagnostic_msgs::DiagnosticArray>(
622  "/diagnostics", 1);
623 
624  pid_ = 0;
625  for (int i = 0; i < 2; i++)
626  {
627  if (i > 0 || YP::YPSpur_initex(key_) < 0)
628  {
629  std::vector<std::string> args =
630  {
631  ypspur_bin_,
632  "-d", port_,
633  "--admask", ad_mask,
634  "--msq-key", std::to_string(key_)
635  };
636  if (digital_input_enable_)
637  args.push_back(std::string("--enable-get-digital-io"));
638  if (simulate_)
639  args.push_back(std::string("--without-device"));
640  if (param_file_.size() > 0)
641  {
642  args.push_back(std::string("-p"));
643  args.push_back(param_file_);
644  }
645 
646  char** argv = new char*[args.size() + 1];
647  for (unsigned int i = 0; i < args.size(); i++)
648  {
649  argv[i] = new char[args[i].size() + 1];
650  memcpy(argv[i], args[i].c_str(), args[i].size());
651  argv[i][args[i].size()] = 0;
652  }
653  argv[args.size()] = nullptr;
654 
655  int msq = msgget(key_, 0666 | IPC_CREAT);
656  msgctl(msq, IPC_RMID, nullptr);
657 
658  ROS_WARN("launching ypspur-coordinator");
659  pid_ = fork();
660  if (pid_ == -1)
661  {
662  const int err = errno;
663  throw(std::runtime_error(std::string("failed to fork process: ") + strerror(err)));
664  }
665  else if (pid_ == 0)
666  {
667  execvp(ypspur_bin_.c_str(), argv);
668  throw(std::runtime_error("failed to start ypspur-coordinator"));
669  }
670 
671  for (unsigned int i = 0; i < args.size(); i++)
672  delete argv[i];
673  delete argv;
674 
675  for (int i = 4; i >= 0; i--)
676  {
677  int status;
678  if (waitpid(pid_, &status, WNOHANG) == pid_)
679  {
680  if (WIFSIGNALED(status))
681  {
682  throw(std::runtime_error(
683  "ypspur-coordinator dead immediately by signal " + std::to_string(WTERMSIG(status))));
684  }
685  if (WIFEXITED(status))
686  {
687  throw(std::runtime_error(
688  "ypspur-coordinator dead immediately with exit code " + std::to_string(WEXITSTATUS(status))));
689  }
690  throw(std::runtime_error("ypspur-coordinator dead immediately"));
691  }
692  else if (i == 0)
693  {
694  throw(std::runtime_error("failed to init libypspur"));
695  }
697  if (YP::YPSpur_initex(key_) >= 0)
698  break;
699  }
700  }
701  double ret;
702  boost::atomic<bool> done(false);
703  auto get_vel_thread = [&ret, &done]
704  {
705  double test_v, test_w;
706  ret = YP::YPSpur_get_vel(&test_v, &test_w);
707  done = true;
708  };
709  boost::thread spur_test = boost::thread(get_vel_thread);
710  ros::WallDuration(0.1).sleep();
711  if (!done)
712  {
713  // There is no way to kill thread safely in C++11
714  // So, just leave it detached.
715  spur_test.detach();
716  ROS_WARN("ypspur-coordinator seems to be down - launching");
717  continue;
718  }
719  spur_test.join();
720  if (ret < 0)
721  {
722  ROS_WARN("ypspur-coordinator returns error - launching");
723  continue;
724  }
725  ROS_WARN("ypspur-coordinator launched");
726  break;
727  }
728 
729  ROS_INFO("ypspur-coordinator conneceted");
730  signal(SIGINT, sigintHandler);
731 
732  YP::YP_get_parameter(YP::YP_PARAM_MAX_VEL, &params_["vel"]);
733  YP::YP_get_parameter(YP::YP_PARAM_MAX_ACC_V, &params_["acc"]);
734  YP::YP_get_parameter(YP::YP_PARAM_MAX_W, &params_["angvel"]);
735  YP::YP_get_parameter(YP::YP_PARAM_MAX_ACC_W, &params_["angacc"]);
736 
737  if (!pnh_.hasParam("vel"))
738  ROS_WARN("default \"vel\" %0.3f used", (float)params_["vel"]);
739  if (!pnh_.hasParam("acc"))
740  ROS_WARN("default \"acc\" %0.3f used", (float)params_["acc"]);
741  if (!pnh_.hasParam("angvel"))
742  ROS_WARN("default \"angvel\" %0.3f used", (float)params_["angvel"]);
743  if (!pnh_.hasParam("angacc"))
744  ROS_WARN("default \"angacc\" %0.3f used", (float)params_["angacc"]);
745 
746  pnh_.param("vel", params_["vel"], params_["vel"]);
747  pnh_.param("acc", params_["acc"], params_["acc"]);
748  pnh_.param("angvel", params_["angvel"], params_["angvel"]);
749  pnh_.param("angacc", params_["angacc"], params_["angacc"]);
750 
751  YP::YPSpur_set_vel(params_["vel"]);
752  YP::YPSpur_set_accel(params_["acc"]);
753  YP::YPSpur_set_angvel(params_["angvel"]);
754  YP::YPSpur_set_angaccel(params_["angacc"]);
755 
756  YP::YP_set_io_data(dio_output_);
757  YP::YP_set_io_dir(dio_dir_);
758  }
760  {
761  // Kill ypspur-coordinator if the communication is still active.
762  if (pid_ > 0 && YP::YP_get_error_state() == 0)
763  {
764  ROS_INFO("killing ypspur-coordinator (%d)", (int)pid_);
765  kill(pid_, SIGINT);
766  int status;
767  waitpid(pid_, &status, 0);
768  ROS_INFO("ypspur-coordinator is killed (status: %d)", status);
769  }
770  }
771  bool spin()
772  {
773  geometry_msgs::TransformStamped odom_trans;
774  odom_trans.header.frame_id = frames_["odom"];
775  odom_trans.child_frame_id = frames_["base_link"];
776 
777  nav_msgs::Odometry odom;
778  geometry_msgs::WrenchStamped wrench;
779  odom.header.frame_id = frames_["odom"];
780  odom.child_frame_id = frames_["base_link"];
781  wrench.header.frame_id = frames_["base_link"];
782 
783  odom.pose.pose.position.x = 0;
784  odom.pose.pose.position.y = 0;
785  odom.pose.pose.position.z = 0;
786  odom.pose.pose.orientation = tf2::toMsg(tf2::Quaternion(z_axis_, 0));
787  odom.twist.twist.linear.x = 0;
788  odom.twist.twist.linear.y = 0;
789  odom.twist.twist.angular.z = 0;
790 
791  std::map<int, geometry_msgs::TransformStamped> joint_trans;
792  sensor_msgs::JointState joint;
793  if (joints_.size() > 0)
794  {
795  joint.header.frame_id = std::string("");
796  joint.velocity.resize(joints_.size());
797  joint.position.resize(joints_.size());
798  joint.effort.resize(joints_.size());
799  for (auto& j : joints_)
800  joint.name.push_back(j.name_);
801 
802  for (unsigned int i = 0; i < joints_.size(); i++)
803  {
804  joint_trans[i].header.frame_id = joints_[i].name_ + std::string("_in");
805  joint_trans[i].child_frame_id = joints_[i].name_ + std::string("_out");
806  joint.velocity[i] = 0;
807  joint.position[i] = 0;
808  joint.effort[i] = 0;
809  }
810  }
811 
812  ROS_INFO("ypspur_ros main loop started");
813  ros::Rate loop(params_["hz"]);
814  while (!g_shutdown)
815  {
816  const auto now = ros::Time::now();
817  const float dt = 1.0 / params_["hz"];
818 
819  if (cmd_vel_ && cmd_vel_expire_ > ros::Duration(0))
820  {
821  if (cmd_vel_time_ + cmd_vel_expire_ < now)
822  {
823  // cmd_vel is too old and expired
824  cmd_vel_ = nullptr;
825  if (control_mode_ == ypspur_ros::ControlMode::VELOCITY)
826  YP::YPSpur_vel(0.0, 0.0);
827  }
828  }
829 
830  if (mode_ == DIFF)
831  {
832  double x, y, yaw, v(0), w(0);
833  double t;
834 
835  if (!simulate_control_)
836  {
837  t = YP::YPSpur_get_pos(YP::CS_BS, &x, &y, &yaw);
838  if (t <= 0.0)
839  break;
840  YP::YPSpur_get_vel(&v, &w);
841  }
842  else
843  {
844  t = ros::Time::now().toSec();
845  if (cmd_vel_)
846  {
847  v = cmd_vel_->linear.x;
848  w = cmd_vel_->angular.z;
849  }
850  yaw = tf2::getYaw(odom.pose.pose.orientation) + dt * w;
851  x = odom.pose.pose.position.x + dt * v * cosf(yaw);
852  y = odom.pose.pose.position.y + dt * v * sinf(yaw);
853  }
854 
855  odom.header.stamp = ros::Time(t);
856  odom.pose.pose.position.x = x;
857  odom.pose.pose.position.y = y;
858  odom.pose.pose.position.z = 0;
859  odom.pose.pose.orientation = tf2::toMsg(tf2::Quaternion(z_axis_, yaw));
860  odom.twist.twist.linear.x = v;
861  odom.twist.twist.linear.y = 0;
862  odom.twist.twist.angular.z = w;
863  pubs_["odom"].publish(odom);
864 
865  odom_trans.header.stamp = ros::Time(t) + ros::Duration(tf_time_offset_);
866  odom_trans.transform.translation.x = x;
867  odom_trans.transform.translation.y = y;
868  odom_trans.transform.translation.z = 0;
869  odom_trans.transform.rotation = odom.pose.pose.orientation;
870  tf_broadcaster_.sendTransform(odom_trans);
871 
872  if (!simulate_control_)
873  {
874  t = YP::YPSpur_get_force(&wrench.wrench.force.x, &wrench.wrench.torque.z);
875  if (t <= 0.0)
876  break;
877  }
878  wrench.header.stamp = ros::Time(t);
879  wrench.wrench.force.y = 0;
880  wrench.wrench.force.z = 0;
881  wrench.wrench.torque.x = 0;
882  wrench.wrench.torque.y = 0;
883  pubs_["wrench"].publish(wrench);
884 
885  if (frames_["origin"].length() > 0)
886  {
887  try
888  {
890  geometry_msgs::TransformStamped transform_msg = tf_buffer_.lookupTransform(
891  frames_["origin"], frames_["base_link"],
892  ros::Time(0));
893  tf2::fromMsg(transform_msg, transform);
894 
895  tf2Scalar yaw, pitch, roll;
896  transform.getBasis().getEulerYPR(yaw, pitch, roll);
897  YP::YPSpur_adjust_pos(YP::CS_GL, transform.getOrigin().x(),
898  transform.getOrigin().y(),
899  yaw);
900  }
901  catch (tf2::TransformException& ex)
902  {
903  ROS_ERROR("Failed to feedback localization result to YP-Spur (%s)", ex.what());
904  }
905  }
906  }
907  if (joints_.size() > 0)
908  {
909  double t;
910  if (!simulate_control_)
911  {
912  t = -1.0;
913  while (t < 0.0)
914  {
915  int i = 0;
916  for (auto& j : joints_)
917  {
918  const double t0 = YP::YP_get_joint_ang(j.id_, &joint.position[i]);
919  const double t1 = YP::YP_get_joint_vel(j.id_, &joint.velocity[i]);
920  const double t2 = YP::YP_get_joint_torque(j.id_, &joint.effort[i]);
921 
922  if (t0 != t1 || t1 != t2)
923  {
924  // Retry if updated during this joint
925  t = -1.0;
926  break;
927  }
928  if (t < 0.0)
929  {
930  t = t0;
931  }
932  else if (t != t0)
933  {
934  // Retry if updated during loops
935  t = -1.0;
936  break;
937  }
938  i++;
939  }
940  }
941  if (t <= 0.0)
942  break;
943  joint.header.stamp = ros::Time(t);
944  }
945  else
946  {
947  t = ros::Time::now().toSec();
948  for (unsigned int i = 0; i < joints_.size(); i++)
949  {
950  auto vel_prev = joint.velocity[i];
951  switch (joints_[i].control_)
952  {
953  case JointParams::STOP:
954  break;
955  case JointParams::TRAJECTORY:
956  case JointParams::POSITION:
957  case JointParams::VELOCITY:
958  switch (joints_[i].control_)
959  {
960  case JointParams::POSITION:
961  {
962  float position_err = joints_[i].angle_ref_ - joint.position[i];
963  joints_[i].vel_ref_ = sqrtf(2.0 * joints_[i].accel_ * fabs(position_err));
964  if (joints_[i].vel_ref_ > joints_[i].vel_)
965  joints_[i].vel_ref_ = joints_[i].vel_;
966  if (position_err < 0)
967  joints_[i].vel_ref_ = -joints_[i].vel_ref_;
968  }
969  break;
970  case JointParams::TRAJECTORY:
971  {
972  float position_err = joints_[i].angle_ref_ - joint.position[i];
973  float v_sq = joints_[i].vel_end_ * joints_[i].vel_end_ + 2.0 * joints_[i].accel_ * position_err;
974  joints_[i].vel_ref_ = sqrtf(fabs(v_sq));
975 
976  float vel_max;
977  if (fabs(joints_[i].vel_) < fabs(joints_[i].vel_end_))
978  {
979  if (fabs(position_err) <
980  (joints_[i].vel_end_ * joints_[i].vel_end_ - joints_[i].vel_ * joints_[i].vel_) /
981  (2.0 * joints_[i].accel_))
982  vel_max = fabs(joints_[i].vel_end_);
983  else
984  vel_max = joints_[i].vel_;
985  }
986  else
987  vel_max = joints_[i].vel_;
988 
989  if (joints_[i].vel_ref_ > vel_max)
990  joints_[i].vel_ref_ = vel_max;
991  if (position_err < 0)
992  joints_[i].vel_ref_ = -joints_[i].vel_ref_;
993  }
994  break;
995  default:
996  break;
997  }
998  joint.velocity[i] = joints_[i].vel_ref_;
999  if (joint.velocity[i] < vel_prev - dt * joints_[i].accel_)
1000  {
1001  joint.velocity[i] = vel_prev - dt * joints_[i].accel_;
1002  }
1003  else if (joint.velocity[i] > vel_prev + dt * joints_[i].accel_)
1004  {
1005  joint.velocity[i] = vel_prev + dt * joints_[i].accel_;
1006  }
1007  joint.position[i] += joint.velocity[i] * dt;
1008  break;
1009  }
1010  }
1011  joint.header.stamp = ros::Time(t);
1012  }
1013  pubs_["joint"].publish(joint);
1014 
1015  for (unsigned int i = 0; i < joints_.size(); i++)
1016  {
1017  joint_trans[i].transform.rotation = tf2::toMsg(tf2::Quaternion(z_axis_, joint.position[i]));
1018  joint_trans[i].header.stamp = ros::Time(t) + ros::Duration(tf_time_offset_);
1019  tf_broadcaster_.sendTransform(joint_trans[i]);
1020  }
1021 
1022  for (unsigned int jid = 0; jid < joints_.size(); jid++)
1023  {
1024  if (joints_[jid].control_ != JointParams::TRAJECTORY)
1025  continue;
1026 
1027  auto& cmd_joint_ = joints_[jid].cmd_joint_;
1028  auto t = now - cmd_joint_.header.stamp;
1029  if (t < ros::Duration(0))
1030  continue;
1031 
1032  bool done = true;
1033  for (auto& cmd : cmd_joint_.points)
1034  {
1035  if (cmd.time_from_start < ros::Duration(0))
1036  continue;
1037  if (now > cmd_joint_.header.stamp + cmd.time_from_start)
1038  continue;
1039  done = false;
1040 
1041  double ang_err = cmd.positions[0] - joint.position[jid];
1042  double& vel_end_ = cmd.velocities[0];
1043  double& vel_start = joint.velocity[jid];
1044  auto t_left = cmd.time_from_start - t;
1045 
1046  double v;
1047  double v_min;
1048  bool v_found = true;
1049  while (true)
1050  {
1051  // ROS_INFO("st: %0.3f, en: %0.3f, err: %0.3f, t: %0.3f",
1052  // vel_start, vel_end_, ang_err, t_left.toSec());
1053  int s;
1054  if (vel_end_ > vel_start)
1055  s = 1;
1056  else
1057  s = -1;
1058  v = (s * (vel_start + vel_end_) * (vel_start - vel_end_) +
1059  ang_err * joints_[jid].accel_ * 2.0) /
1060  (2.0 * s * (vel_start - vel_end_) + joints_[jid].accel_ * 2.0 * (t_left.toSec()));
1061 
1062  double err_deacc;
1063  err_deacc = fabs(vel_end_ * vel_end_ - v * v) / (joints_[jid].accel_ * 2.0);
1064  // ROS_INFO("v+-: %0.3f", v);
1065  v_min = fabs(v);
1066  if ((vel_start * s <= v * s || err_deacc >= fabs(ang_err)) &&
1067  v * s <= vel_end_ * s)
1068  break;
1069 
1070  v_min = DBL_MAX;
1071 
1072  auto vf = [](const double& st, const double& en,
1073  const double& acc, const double& err, const double& t,
1074  const int& sig, const int& sol, double& ret)
1075  {
1076  double sq;
1077  sq = -4.0 * st * st +
1078  8.0 * st * en -
1079  4.0 * en * en +
1080  4.0 * sig * acc * 2 * (t * (st + en) - 2.0 * err) +
1081  4.0 * acc * acc * t * t;
1082  if (sq < 0)
1083  return false;
1084 
1085  ret = (2.0 * sig * (st + en) + 2.0 * acc * t + sol * sqrt(sq)) / (4.0 * sig);
1086 
1087  return true;
1088  };
1089 
1090  v_found = false;
1091 
1092  if (vf(vel_start, vel_end_, joints_[jid].accel_, ang_err, t_left.toSec(),
1093  1, 1, v))
1094  {
1095  // ROS_INFO("v++: sol+ %0.3f", v);
1096  if (v >= vel_start && v >= vel_end_)
1097  {
1098  if (v_min > fabs(v))
1099  v_min = fabs(v);
1100  v_found = true;
1101  }
1102  }
1103  if (vf(vel_start, vel_end_, joints_[jid].accel_, ang_err, t_left.toSec(),
1104  -1, 1, v))
1105  {
1106  // ROS_INFO("v--: sol+ %0.3f", v);
1107  if (v <= vel_start && v <= vel_end_)
1108  {
1109  if (v_min > fabs(v))
1110  v_min = fabs(v);
1111  v_found = true;
1112  }
1113  }
1114  if (vf(vel_start, vel_end_, joints_[jid].accel_, ang_err, t_left.toSec(),
1115  1, -1, v))
1116  {
1117  // ROS_INFO("v++: sol- %0.3f", v);
1118  if (v >= vel_start && v >= vel_end_)
1119  {
1120  if (v_min > fabs(v))
1121  v_min = fabs(v);
1122  v_found = true;
1123  }
1124  }
1125  if (vf(vel_start, vel_end_, joints_[jid].accel_, ang_err, t_left.toSec(),
1126  -1, -1, v))
1127  {
1128  // ROS_INFO("v--: sol- %0.3f", v);
1129  if (v <= vel_start && v <= vel_end_)
1130  {
1131  if (v_min > fabs(v))
1132  v_min = fabs(v);
1133  v_found = true;
1134  }
1135  }
1136  break;
1137  }
1138  if (v_found)
1139  {
1140  // ROS_INFO("v: %0.3f", v_min);
1141  joints_[jid].angle_ref_ = cmd.positions[0];
1142  joints_[jid].vel_end_ = vel_end_;
1143  joints_[jid].vel_ = v_min;
1144 
1145  YP::YP_set_joint_vel(joints_[jid].id_, v_min);
1146  YP::YP_set_joint_accel(joints_[jid].id_, joints_[jid].accel_);
1147  YP::YP_joint_ang_vel(joints_[jid].id_, cmd.positions[0], vel_end_);
1148  }
1149  else
1150  {
1151  ROS_ERROR("Impossible trajectory given");
1152  }
1153  break;
1154  }
1155 
1156  if (done)
1157  {
1158  if ((joints_[jid].vel_end_ > 0.0 &&
1159  joints_[jid].angle_ref_ > joint.position[jid] &&
1160  joints_[jid].angle_ref_ < joint.position[jid] + joints_[jid].vel_ref_ * dt) ||
1161  (joints_[jid].vel_end_ < 0.0 &&
1162  joints_[jid].angle_ref_ < joint.position[jid] &&
1163  joints_[jid].angle_ref_ > joint.position[jid] + joints_[jid].vel_ref_ * dt))
1164  {
1165  joints_[jid].control_ = JointParams::VELOCITY;
1166  joints_[jid].vel_ref_ = joints_[jid].vel_end_;
1167  }
1168  }
1169  }
1170  }
1171 
1172  for (int i = 0; i < ad_num_; i++)
1173  {
1174  if (ads_[i].enable_)
1175  {
1176  std_msgs::Float32 ad;
1177  ad.data = YP::YP_get_ad_value(i) * ads_[i].gain_ + ads_[i].offset_;
1178  pubs_["ad/" + ads_[i].name_].publish(ad);
1179  }
1180  }
1181 
1182  if (digital_input_enable_)
1183  {
1184  ypspur_ros::DigitalInput din;
1185 
1186  din.header.stamp = ros::Time::now();
1187  int in = YP::YP_get_ad_value(15);
1188  for (int i = 0; i < dio_num_; i++)
1189  {
1190  if (!dios_[i].enable_)
1191  continue;
1192  din.name.push_back(dios_[i].name_);
1193  if (in & (1 << i))
1194  din.state.push_back(true);
1195  else
1196  din.state.push_back(false);
1197  }
1198  pubs_["din"].publish(din);
1199  }
1200 
1201  for (int i = 0; i < dio_num_; i++)
1202  {
1203  if (dio_revert_[i] != ros::Time(0))
1204  {
1205  if (dio_revert_[i] < now)
1206  {
1207  revertDigitalOutput(i);
1208  }
1209  }
1210  }
1211  updateDiagnostics(now);
1212 
1213  if (YP::YP_get_error_state())
1214  break;
1215 
1216  ros::spinOnce();
1217  loop.sleep();
1218 
1219  int status;
1220  if (waitpid(pid_, &status, WNOHANG) == pid_)
1221  {
1222  if (WIFEXITED(status))
1223  {
1224  ROS_ERROR("ypspur-coordinator exited");
1225  }
1226  else
1227  {
1228  if (WIFSTOPPED(status))
1229  {
1230  ROS_ERROR("ypspur-coordinator dead with signal %d",
1231  WSTOPSIG(status));
1232  }
1233  else
1234  {
1235  ROS_ERROR("ypspur-coordinator dead");
1236  }
1237  updateDiagnostics(now, true);
1238  }
1239  break;
1240  }
1241  }
1242  ROS_INFO("ypspur_ros main loop terminated");
1243 
1244  if (YP::YP_get_error_state())
1245  {
1246  ROS_ERROR("ypspur-coordinator is not active");
1247  return false;
1248  }
1249  return true;
1250  }
1251 };
1252 
1253 int main(int argc, char* argv[])
1254 {
1255  ros::init(argc, argv, "ypspur_ros");
1256  ros::NodeHandle nh;
1257 
1258  int ret = 0;
1259 
1260  try
1261  {
1262  YpspurRosNode yr;
1263  if (!yr.spin())
1264  ret = 1;
1265  }
1266  catch (std::runtime_error& e)
1267  {
1268  ROS_ERROR("%s", e.what());
1269  ret = 1;
1270  }
1271 
1272  ros::WallDuration(0.1).sleep();
1273  return ret;
1274 }
int main(int argc, char *argv[])
std::map< std::string, int > joint_name_to_num_
Definition: ypspur_ros.cpp:133
void cbVel(const std_msgs::Float32::ConstPtr &msg, int num)
Definition: ypspur_ros.cpp:264
bool param(const std::string &param_name, T &param_val, const T &default_val)
void cbJointPosition(const ypspur_ros::JointPositionControl::ConstPtr &msg)
Definition: ypspur_ros.cpp:277
std::vector< AdParams > ads_
Definition: ypspur_ros.cpp:152
tf2_ros::TransformBroadcaster tf_broadcaster_
Definition: ypspur_ros.cpp:90
void updateDiagnostics(const ros::Time &now, const bool connection_down=false)
Definition: ypspur_ros.cpp:357
std::map< std::string, double > params_
Definition: ypspur_ros.cpp:97
void sigintHandler(int sig)
Definition: ypspur_ros.cpp:76
void cbCmdVel(const geometry_msgs::Twist::ConstPtr &msg)
Definition: ypspur_ros.cpp:187
std::map< int, ros::Time > dio_revert_
Definition: ypspur_ros.cpp:160
XmlRpcServer s
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
double tf2Scalar
ros::NodeHandle nh_
Definition: ypspur_ros.cpp:84
std::string ypspur_bin_
Definition: ypspur_ros.cpp:95
std::string param_file_
Definition: ypspur_ros.cpp:94
std::vector< DioParams > dios_
Definition: ypspur_ros.cpp:153
#define ROS_WARN(...)
geometry_msgs::TransformStamped t
int ad[16]
trajectory_msgs::JointTrajectory cmd_joint_
Definition: ypspur_ros.cpp:130
std::vector< JointParams > joints_
Definition: ypspur_ros.cpp:132
TF2SIMD_FORCE_INLINE tf2Scalar length(const Quaternion &q)
bool sleep() const
void cbControlMode(const ypspur_ros::ControlMode::ConstPtr &msg)
Definition: ypspur_ros.cpp:172
void cbAngle(const std_msgs::Float32::ConstPtr &msg, int num)
Definition: ypspur_ros.cpp:271
tf2_ros::TransformListener tf_listener_
Definition: ypspur_ros.cpp:89
#define ROS_INFO(...)
ros::NodeHandle pnh_
Definition: ypspur_ros.cpp:85
bool param(const std::string &param_name, T &param_val, const T &default_val) const
bool digital_input_enable_
Definition: ypspur_ros.cpp:151
bool g_shutdown
Definition: ypspur_ros.cpp:75
ros::Time cmd_vel_time_
Definition: ypspur_ros.cpp:167
void fromMsg(const A &, B &b)
OdometryMode mode_
Definition: ypspur_ros.cpp:111
std::map< std::string, std::string > frames_
Definition: ypspur_ros.cpp:96
unsigned int dio_output_default_
Definition: ypspur_ros.cpp:157
const tf2::Vector3 z_axis_
Definition: ypspur_ros.cpp:91
double tf_time_offset_
Definition: ypspur_ros.cpp:102
bool simulate_control_
Definition: ypspur_ros.cpp:100
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void cbSetVel(const std_msgs::Float32::ConstPtr &msg, int num)
Definition: ypspur_ros.cpp:252
std::string port_
Definition: ypspur_ros.cpp:93
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
std::map< std::string, ros::Publisher > pubs_
Definition: ypspur_ros.cpp:86
void sendTransform(const geometry_msgs::TransformStamped &transform)
ros::Duration cmd_vel_expire_
Definition: ypspur_ros.cpp:168
bool sleep()
double getYaw(const A &a)
tf2_ros::Buffer tf_buffer_
Definition: ypspur_ros.cpp:88
B toMsg(const A &a)
unsigned int dio_dir_
Definition: ypspur_ros.cpp:156
unsigned int dio_dir_default_
Definition: ypspur_ros.cpp:158
ros::Time device_error_state_time_
Definition: ypspur_ros.cpp:164
void cbJoint(const trajectory_msgs::JointTrajectory::ConstPtr &msg)
Definition: ypspur_ros.cpp:196
void cbSetAccel(const std_msgs::Float32::ConstPtr &msg, int num)
Definition: ypspur_ros.cpp:258
void checkCompatMode()
Definition: compatibility.h:60
int device_error_state_
Definition: ypspur_ros.cpp:162
static Time now()
double p(YPSpur_param id, enum motor_id motor)
bool hasParam(const std::string &key) const
int device_error_state_prev_
Definition: ypspur_ros.cpp:163
unsigned int dio_output_
Definition: ypspur_ros.cpp:155
ros::Subscriber subscribe(ros::NodeHandle &nh_new, const std::string &topic_new, ros::NodeHandle &nh_old, const std::string &topic_old, uint32_t queue_size, void(T::*fp)(M) const, T *obj, const ros::TransportHints &transport_hints=ros::TransportHints())
Definition: compatibility.h:98
ROSCPP_DECL void spinOnce()
void cbDigitalOutput(const ypspur_ros::DigitalOutput::ConstPtr &msg, int id_)
Definition: ypspur_ros.cpp:301
#define ROS_ERROR(...)
geometry_msgs::Twist::ConstPtr cmd_vel_
Definition: ypspur_ros.cpp:166
std::map< std::string, ros::Subscriber > subs_
Definition: ypspur_ros.cpp:87
void revertDigitalOutput(int id_)
Definition: ypspur_ros.cpp:339


ypspur_ros
Author(s): Atsushi Watanabe
autogenerated on Thu May 13 2021 03:01:26