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>    55 #include <sys/types.h>    58 #include <boost/atomic.hpp>    59 #include <boost/chrono.hpp>    60 #include <boost/thread.hpp>    61 #include <boost/thread/future.hpp>    86   std::map<std::string, ros::Publisher> 
pubs_;
    87   std::map<std::string, ros::Subscriber> 
subs_;
    96   std::map<std::string, std::string> 
frames_;
   154   const int ad_num_ = 8;
   159   const int dio_num_ = 8;
   174     control_mode_ = msg->vehicle_control_mode;
   175     switch (control_mode_)
   177       case ypspur_ros::ControlMode::OPEN:
   180       case ypspur_ros::ControlMode::TORQUE:
   183       case ypspur_ros::ControlMode::VELOCITY:
   187   void cbCmdVel(
const geometry_msgs::Twist::ConstPtr& msg)
   191     if (control_mode_ == ypspur_ros::ControlMode::VELOCITY)
   193       YP::YPSpur_vel(msg->linear.x, msg->angular.z);
   196   void cbJoint(
const trajectory_msgs::JointTrajectory::ConstPtr& msg)
   200     std_msgs::Header header = msg->header;
   204     std::map<std::string, trajectory_msgs::JointTrajectory> new_cmd_joints;
   206     for (
const std::string& name : msg->joint_names)
   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();
   214       for (
auto& cmd : msg->points)
   216         if (header.stamp + cmd.time_from_start < now)
   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());
   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;
   232           p.velocities[0] = cmd.velocities[i];
   233         p.positions[0] = cmd.positions[i];
   235         cmd_joint.points.push_back(p);
   239       if (cmd_joint.points.size() != msg->points.size())
   242       new_cmd_joints[name] = cmd_joint;
   245     for (
auto& new_cmd_joint : new_cmd_joints)
   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;
   252   void cbSetVel(
const std_msgs::Float32::ConstPtr& msg, 
int num)
   255     joints_[num].vel_ = msg->data;
   256     YP::YP_set_joint_vel(joints_[num].id_, joints_[num].vel_);
   258   void cbSetAccel(
const std_msgs::Float32::ConstPtr& msg, 
int num)
   261     joints_[num].accel_ = msg->data;
   262     YP::YP_set_joint_accel(joints_[num].id_, joints_[num].accel_);
   264   void cbVel(
const std_msgs::Float32::ConstPtr& msg, 
int num)
   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_);
   271   void cbAngle(
const std_msgs::Float32::ConstPtr& msg, 
int num)
   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_);
   280     for (
auto& name : msg->joint_names)
   282       if (joint_name_to_num_.find(name) == joint_name_to_num_.end())
   284         ROS_ERROR(
"Unknown joint name '%s'", name.c_str());
   287       int num = joint_name_to_num_[name];
   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;
   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_);
   303     const auto dio_output_prev = dio_output_;
   304     const auto dio_dir_prev = dio_dir_;
   305     const unsigned int mask = 1 << id_;
   309       case ypspur_ros::DigitalOutput::HIGH_IMPEDANCE:
   310         dio_output_ &= ~mask;
   313       case ypspur_ros::DigitalOutput::LOW:
   314         dio_output_ &= ~mask;
   317       case ypspur_ros::DigitalOutput::HIGH:
   321       case ypspur_ros::DigitalOutput::PULL_UP:
   325       case ypspur_ros::DigitalOutput::PULL_DOWN:
   326         ROS_ERROR(
"Digital IO pull down is not supported on this system");
   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_);
   341     const auto dio_output_prev = dio_output_;
   342     const auto dio_dir_prev = dio_dir_;
   343     const unsigned int mask = 1 << id_;
   345     dio_output_ &= ~mask;
   346     dio_output_ |= dio_output_default_ & mask;
   348     dio_dir_ |= dio_output_default_ & mask;
   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_);
   359     const int connection_error = connection_down ? 1 : YP::YP_get_error_state();
   363     if (!connection_error)
   364       t = YP::YP_get_device_error_state(0, &err);
   365     device_error_state_ |= err;
   367     if (device_error_state_time_ + 
ros::Duration(1.0) < now || connection_down ||
   368         device_error_state_ != device_error_state_prev_)
   370       device_error_state_time_ = now;
   371       device_error_state_prev_ = device_error_state_;
   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)
   382           msg.status[0].level = diagnostic_msgs::DiagnosticStatus::OK;
   383           msg.status[0].message = 
"Motor controller doesn't "   384                                   "provide device error state.";
   390             msg.status[0].level = diagnostic_msgs::DiagnosticStatus::ERROR;
   391             msg.status[0].message = 
"Motor controller doesn't "   392                                     "update latest device error state.";
   396             msg.status[0].level = diagnostic_msgs::DiagnosticStatus::OK;
   397             msg.status[0].message = 
"Motor controller is running without error.";
   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_) + 
".";
   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_);
   419       pubs_[
"diag"].publish(msg);
   420       device_error_state_ = 0;
   428     , tf_listener_(tf_buffer_)
   430     , device_error_state_(0)
   431     , device_error_state_prev_(0)
   432     , device_error_state_time_(0)
   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_)
   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);
   446     double cmd_vel_expire_s;
   447     pnh_.
param(
"cmd_vel_expire", cmd_vel_expire_s, -1.0);
   450     std::string ad_mask(
"");
   451     ads_.resize(ad_num_);
   452     for (
int i = 0; i < ad_num_; i++)
   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"),
   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);
   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++)
   474       pnh_.
param(std::string(
"dio") + std::to_string(i) + std::string(
"_enable"),
   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)));
   481         pnh_.
param(std::string(
"dio") + std::to_string(i) + std::string(
"_output"),
   483         pnh_.
param(std::string(
"dio") + std::to_string(i) + std::string(
"_input"),
   488           subs_[param.
name_] = compat::subscribe<ypspur_ros::DigitalOutput>(
   490               pnh_, param.
name_, 1,
   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)
   500         else if (output_default.compare(
"LOW") == 0)
   502           dio_dir_default_ |= 1 << i;
   504         else if (output_default.compare(
"HIGH") == 0)
   506           dio_dir_default_ |= 1 << i;
   507           dio_output_default_ |= 1 << i;
   509         else if (output_default.compare(
"PULL_UP") == 0)
   511           dio_output_default_ |= 1 << i;
   513         else if (output_default.compare(
"PULL_DOWN") == 0)
   515           ROS_ERROR(
"Digital IO pull down is not supported on this system");
   518           digital_input_enable_ = 
true;
   522     dio_output_ = dio_output_default_;
   523     dio_dir_ = dio_dir_default_;
   524     if (digital_input_enable_)
   526       pubs_[
"din"] = compat::advertise<ypspur_ros::DigitalInput>(
   527           nh_, 
"digital_input",
   528           pnh_, 
"digital_input", 2);
   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);
   536     std::string mode_name;
   537     pnh_.
param(
"OdometryMode", mode_name, std::string(
"diff"));
   538     if (mode_name.compare(
"diff") == 0)
   541       pubs_[
"wrench"] = compat::advertise<geometry_msgs::WrenchStamped>(
   544       pubs_[
"odom"] = compat::advertise<nav_msgs::Odometry>(
   551     else if (mode_name.compare(
"none") == 0)
   556       throw(std::runtime_error(
"unknown mode: " + mode_name));
   560     bool separated_joint;
   561     pnh_.
param(
"max_joint_id", max_joint_id, 32);
   562     pnh_.
param(
"separated_joint_control", separated_joint, 
false);
   564     for (
int i = 0; i < max_joint_id; i++)
   567       name = std::string(
"joint") + std::to_string(i);
   568       if (pnh_.
hasParam(name + std::string(
"_enable")))
   571         pnh_.
param(name + std::string(
"_enable"), en, 
false);
   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);
   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,
   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,
   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,
   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,
   601               nh_, std::string(
"joint_position"),
   607     if (joints_.size() > 0)
   609       pubs_[
"joint"] = compat::advertise<sensor_msgs::JointState>(
   613           nh_, 
"joint_trajectory",
   619     control_mode_ = ypspur_ros::ControlMode::VELOCITY;
   621     pubs_[
"diag"] = nh_.
advertise<diagnostic_msgs::DiagnosticArray>(
   625     for (
int i = 0; i < 2; i++)
   627       if (i > 0 || YP::YPSpur_initex(key_) < 0)
   629         std::vector<std::string> 
args =
   634               "--msq-key", std::to_string(key_)
   636         if (digital_input_enable_)
   637           args.push_back(std::string(
"--enable-get-digital-io"));
   639           args.push_back(std::string(
"--without-device"));
   640         if (param_file_.size() > 0)
   642           args.push_back(std::string(
"-p"));
   643           args.push_back(param_file_);
   646         char** argv = 
new char*[args.size() + 1];
   647         for (
unsigned int i = 0; i < args.size(); i++)
   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;
   653         argv[args.size()] = 
nullptr;
   655         int msq = msgget(key_, 0666 | IPC_CREAT);
   656         msgctl(msq, IPC_RMID, 
nullptr);
   658         ROS_WARN(
"launching ypspur-coordinator");
   662           const int err = errno;
   663           throw(std::runtime_error(std::string(
"failed to fork process: ") + strerror(err)));
   667           execvp(ypspur_bin_.c_str(), argv);
   668           throw(std::runtime_error(
"failed to start ypspur-coordinator"));
   671         for (
unsigned int i = 0; i < args.size(); i++)
   675         for (
int i = 4; i >= 0; i--)
   678           if (waitpid(pid_, &status, WNOHANG) == pid_)
   680             if (WIFSIGNALED(status))
   682               throw(std::runtime_error(
   683                   "ypspur-coordinator dead immediately by signal " + std::to_string(WTERMSIG(status))));
   685             if (WIFEXITED(status))
   687               throw(std::runtime_error(
   688                   "ypspur-coordinator dead immediately with exit code " + std::to_string(WEXITSTATUS(status))));
   690             throw(std::runtime_error(
"ypspur-coordinator dead immediately"));
   694             throw(std::runtime_error(
"failed to init libypspur"));
   697           if (YP::YPSpur_initex(key_) >= 0)
   702       boost::atomic<bool> done(
false);
   703       auto get_vel_thread = [&ret, &done]
   705         double test_v, test_w;
   706         ret = YP::YPSpur_get_vel(&test_v, &test_w);
   709       boost::thread spur_test = boost::thread(get_vel_thread);
   716         ROS_WARN(
"ypspur-coordinator seems to be down - launching");
   722         ROS_WARN(
"ypspur-coordinator returns error - launching");
   725       ROS_WARN(
"ypspur-coordinator launched");
   729     ROS_INFO(
"ypspur-coordinator conneceted");
   732     YP::YP_get_parameter(YP::YP_PARAM_MAX_VEL, ¶ms_[
"vel"]);
   733     YP::YP_get_parameter(YP::YP_PARAM_MAX_ACC_V, ¶ms_[
"acc"]);
   734     YP::YP_get_parameter(YP::YP_PARAM_MAX_W, ¶ms_[
"angvel"]);
   735     YP::YP_get_parameter(YP::YP_PARAM_MAX_ACC_W, ¶ms_[
"angacc"]);
   738       ROS_WARN(
"default \"vel\" %0.3f used", (
float)params_[
"vel"]);
   740       ROS_WARN(
"default \"acc\" %0.3f used", (
float)params_[
"acc"]);
   742       ROS_WARN(
"default \"angvel\" %0.3f used", (
float)params_[
"angvel"]);
   744       ROS_WARN(
"default \"angacc\" %0.3f used", (
float)params_[
"angacc"]);
   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"]);
   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"]);
   756     YP::YP_set_io_data(dio_output_);
   757     YP::YP_set_io_dir(dio_dir_);
   762     if (pid_ > 0 && YP::YP_get_error_state() == 0)
   764       ROS_INFO(
"killing ypspur-coordinator (%d)", (
int)pid_);
   767       waitpid(pid_, &status, 0);
   768       ROS_INFO(
"ypspur-coordinator is killed (status: %d)", status);
   773     geometry_msgs::TransformStamped odom_trans;
   774     odom_trans.header.frame_id = frames_[
"odom"];
   775     odom_trans.child_frame_id = frames_[
"base_link"];
   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"];
   783     odom.pose.pose.position.x = 0;
   784     odom.pose.pose.position.y = 0;
   785     odom.pose.pose.position.z = 0;
   787     odom.twist.twist.linear.x = 0;
   788     odom.twist.twist.linear.y = 0;
   789     odom.twist.twist.angular.z = 0;
   791     std::map<int, geometry_msgs::TransformStamped> joint_trans;
   792     sensor_msgs::JointState joint;
   793     if (joints_.size() > 0)
   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_);
   802       for (
unsigned int i = 0; i < joints_.size(); i++)
   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;
   812     ROS_INFO(
"ypspur_ros main loop started");
   817       const float dt = 1.0 / params_[
"hz"];
   821         if (cmd_vel_time_ + cmd_vel_expire_ < now)
   825           if (control_mode_ == ypspur_ros::ControlMode::VELOCITY)
   826             YP::YPSpur_vel(0.0, 0.0);
   832         double x, y, yaw, v(0), w(0);
   835         if (!simulate_control_)
   837           t = YP::YPSpur_get_pos(YP::CS_BS, &x, &y, &yaw);
   840           YP::YPSpur_get_vel(&v, &w);
   847             v = cmd_vel_->linear.x;
   848             w = cmd_vel_->angular.z;
   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);
   856         odom.pose.pose.position.x = x;
   857         odom.pose.pose.position.y = y;
   858         odom.pose.pose.position.z = 0;
   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);
   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;
   872         if (!simulate_control_)
   874           t = YP::YPSpur_get_force(&wrench.wrench.force.x, &wrench.wrench.torque.z);
   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);
   885         if (frames_[
"origin"].
length() > 0)
   890             geometry_msgs::TransformStamped transform_msg = tf_buffer_.
lookupTransform(
   891                 frames_[
"origin"], frames_[
"base_link"],
   896             transform.getBasis().getEulerYPR(yaw, pitch, roll);
   897             YP::YPSpur_adjust_pos(YP::CS_GL, transform.getOrigin().x(),
   898                                   transform.getOrigin().y(),
   903             ROS_ERROR(
"Failed to feedback localization result to YP-Spur (%s)", ex.what());
   907       if (joints_.size() > 0)
   910         if (!simulate_control_)
   916             for (
auto& j : joints_)
   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]);
   922               if (t0 != t1 || t1 != t2)
   948           for (
unsigned int i = 0; i < joints_.size(); i++)
   950             auto vel_prev = joint.velocity[i];
   951             switch (joints_[i].control_)
   953               case JointParams::STOP:
   955               case JointParams::TRAJECTORY:
   956               case JointParams::POSITION:
   957               case JointParams::VELOCITY:
   958                 switch (joints_[i].control_)
   960                   case JointParams::POSITION:
   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_;
   970                   case JointParams::TRAJECTORY:
   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));
   977                     if (fabs(joints_[i].vel_) < fabs(joints_[i].vel_end_))
   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_);
   984                         vel_max = joints_[i].vel_;
   987                       vel_max = joints_[i].vel_;
   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_;
   998                 joint.velocity[i] = joints_[i].vel_ref_;
   999                 if (joint.velocity[i] < vel_prev - dt * joints_[i].accel_)
  1001                   joint.velocity[i] = vel_prev - dt * joints_[i].accel_;
  1003                 else if (joint.velocity[i] > vel_prev + dt * joints_[i].accel_)
  1005                   joint.velocity[i] = vel_prev + dt * joints_[i].accel_;
  1007                 joint.position[i] += joint.velocity[i] * dt;
  1013         pubs_[
"joint"].publish(joint);
  1015         for (
unsigned int i = 0; i < joints_.size(); i++)
  1022         for (
unsigned int jid = 0; jid < joints_.size(); jid++)
  1024           if (joints_[jid].control_ != JointParams::TRAJECTORY)
  1027           auto& cmd_joint_ = joints_[jid].cmd_joint_;
  1028           auto t = now - cmd_joint_.header.stamp;
  1033           for (
auto& cmd : cmd_joint_.points)
  1037             if (now > cmd_joint_.header.stamp + cmd.time_from_start)
  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;
  1048             bool v_found = 
true;
  1054               if (vel_end_ > vel_start)
  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()));
  1063               err_deacc = fabs(vel_end_ * vel_end_ - v * v) / (joints_[jid].accel_ * 2.0);
  1066               if ((vel_start * s <= v * s || err_deacc >= fabs(ang_err)) &&
  1067                   v * s <= vel_end_ * s)
  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)
  1077                 sq = -4.0 * st * st +
  1080                      4.0 * sig * acc * 2 * (t * (st + en) - 2.0 * err) +
  1081                      4.0 * acc * acc * t * t;
  1085                 ret = (2.0 * sig * (st + en) + 2.0 * acc * t + sol * 
sqrt(sq)) / (4.0 * sig);
  1092               if (vf(vel_start, vel_end_, joints_[jid].accel_, ang_err, t_left.toSec(),
  1096                 if (v >= vel_start && v >= vel_end_)
  1098                   if (v_min > fabs(v))
  1103               if (vf(vel_start, vel_end_, joints_[jid].accel_, ang_err, t_left.toSec(),
  1107                 if (v <= vel_start && v <= vel_end_)
  1109                   if (v_min > fabs(v))
  1114               if (vf(vel_start, vel_end_, joints_[jid].accel_, ang_err, t_left.toSec(),
  1118                 if (v >= vel_start && v >= vel_end_)
  1120                   if (v_min > fabs(v))
  1125               if (vf(vel_start, vel_end_, joints_[jid].accel_, ang_err, t_left.toSec(),
  1129                 if (v <= vel_start && v <= vel_end_)
  1131                   if (v_min > fabs(v))
  1141               joints_[jid].angle_ref_ = cmd.positions[0];
  1142               joints_[jid].vel_end_ = vel_end_;
  1143               joints_[jid].vel_ = v_min;
  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_);
  1151               ROS_ERROR(
"Impossible trajectory given");
  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))
  1165               joints_[jid].control_ = JointParams::VELOCITY;
  1166               joints_[jid].vel_ref_ = joints_[jid].vel_end_;
  1172       for (
int i = 0; i < ad_num_; i++)
  1174         if (ads_[i].enable_)
  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);
  1182       if (digital_input_enable_)
  1184         ypspur_ros::DigitalInput din;
  1187         int in = YP::YP_get_ad_value(15);
  1188         for (
int i = 0; i < dio_num_; i++)
  1190           if (!dios_[i].enable_)
  1192           din.name.push_back(dios_[i].name_);
  1194             din.state.push_back(
true);
  1196             din.state.push_back(
false);
  1198         pubs_[
"din"].publish(din);
  1201       for (
int i = 0; i < dio_num_; i++)
  1205           if (dio_revert_[i] < now)
  1207             revertDigitalOutput(i);
  1211       updateDiagnostics(now);
  1213       if (YP::YP_get_error_state())
  1220       if (waitpid(pid_, &status, WNOHANG) == pid_)
  1222         if (WIFEXITED(status))
  1228           if (WIFSTOPPED(status))
  1230             ROS_ERROR(
"ypspur-coordinator dead with signal %d",
  1237           updateDiagnostics(now, 
true);
  1242     ROS_INFO(
"ypspur_ros main loop terminated");
  1244     if (YP::YP_get_error_state())
  1246       ROS_ERROR(
"ypspur-coordinator is not active");
  1266   catch (std::runtime_error& e)
 int main(int argc, char *argv[])
std::map< std::string, int > joint_name_to_num_
void cbVel(const std_msgs::Float32::ConstPtr &msg, int num)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val)
void cbJointPosition(const ypspur_ros::JointPositionControl::ConstPtr &msg)
std::vector< AdParams > ads_
tf2_ros::TransformBroadcaster tf_broadcaster_
void updateDiagnostics(const ros::Time &now, const bool connection_down=false)
std::map< std::string, double > params_
void sigintHandler(int sig)
void cbCmdVel(const geometry_msgs::Twist::ConstPtr &msg)
std::map< int, ros::Time > dio_revert_
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)
std::vector< DioParams > dios_
geometry_msgs::TransformStamped t
trajectory_msgs::JointTrajectory cmd_joint_
std::vector< JointParams > joints_
TF2SIMD_FORCE_INLINE tf2Scalar length(const Quaternion &q)
void cbControlMode(const ypspur_ros::ControlMode::ConstPtr &msg)
void cbAngle(const std_msgs::Float32::ConstPtr &msg, int num)
tf2_ros::TransformListener tf_listener_
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const 
bool digital_input_enable_
void fromMsg(const A &, B &b)
std::map< std::string, std::string > frames_
unsigned int dio_output_default_
const tf2::Vector3 z_axis_
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void cbSetVel(const std_msgs::Float32::ConstPtr &msg, int num)
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
std::map< std::string, ros::Publisher > pubs_
ros::Duration cmd_vel_expire_
double getYaw(const A &a)
tf2_ros::Buffer tf_buffer_
unsigned int dio_dir_default_
ros::Time device_error_state_time_
void cbJoint(const trajectory_msgs::JointTrajectory::ConstPtr &msg)
void cbSetAccel(const std_msgs::Float32::ConstPtr &msg, int num)
double p(YPSpur_param id, enum motor_id motor)
bool hasParam(const std::string &key) const 
int device_error_state_prev_
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())
ROSCPP_DECL void spinOnce()
void cbDigitalOutput(const ypspur_ros::DigitalOutput::ConstPtr &msg, int id_)
geometry_msgs::Twist::ConstPtr cmd_vel_
std::map< std::string, ros::Subscriber > subs_
void revertDigitalOutput(int id_)