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_)