00001
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <ros/ros.h>
00015 #include <ros/console.h>
00016
00017 #include <urdf/model.h>
00018 #include <mavros_msgs/RCOut.h>
00019 #include <sensor_msgs/JointState.h>
00020
00021 class ServoDescription {
00022 public:
00023 std::string joint_name;
00024 float joint_lower;
00025 float joint_upper;
00026
00027 size_t rc_channel;
00028
00029 uint16_t rc_min;
00030 uint16_t rc_max;
00031 uint16_t rc_trim;
00032 uint16_t rc_dz;
00033 bool rc_rev;
00034
00035 ServoDescription() :
00036 joint_name{},
00037 joint_lower(-M_PI/4),
00038 joint_upper(M_PI/4),
00039 rc_channel(0),
00040 rc_min(1000),
00041 rc_max(2000),
00042 rc_trim(1500),
00043 rc_dz(0),
00044 rc_rev(false)
00045 { };
00046
00047 ServoDescription(std::string joint_name_, double lower_, double upper_,
00048 int channel_,
00049 int min_, int max_, int trim_, int dz_,
00050 bool rev_) :
00051 joint_name(joint_name_),
00052 joint_lower(lower_),
00053 joint_upper(upper_),
00054 rc_channel(channel_),
00055 rc_min(min_),
00056 rc_max(max_),
00057 rc_trim(trim_),
00058 rc_dz(dz_),
00059 rc_rev(rev_)
00060 { };
00061
00066 inline float normalize(uint16_t pwm) {
00067
00068 pwm = std::max(pwm, rc_min);
00069 pwm = std::min(pwm, rc_max);
00070
00071
00072 float chan;
00073 if (pwm > (rc_trim + rc_dz)) {
00074 chan = (pwm - rc_trim - rc_dz) / (float)(rc_max - rc_trim - rc_dz);
00075 }
00076 else if (pwm < (rc_trim - rc_dz)) {
00077 chan = (pwm - rc_trim + rc_dz) / (float)(rc_trim - rc_min - rc_dz);
00078 }
00079 else {
00080 chan = 0.0;
00081 }
00082
00083 if (rc_rev)
00084 chan *= -1;
00085
00086 if (!std::isfinite(chan)) {
00087 ROS_DEBUG("SSP: not finite result in RC%zu channel normalization!", rc_channel);
00088 chan = 0.0;
00089 }
00090
00091 return chan;
00092 }
00093
00094 float calculate_position(uint16_t pwm) {
00095 float channel = normalize(pwm);
00096
00097
00098
00099 float position = (channel + 1.0) * (joint_upper - joint_lower) / (1.0 + 1.0) + joint_lower;
00100
00101 return position;
00102 }
00103 };
00104
00105 class ServoStatePublisher {
00106 public:
00107 ServoStatePublisher() :
00108 nh()
00109 {
00110 ros::NodeHandle priv_nh("~");
00111
00112 XmlRpc::XmlRpcValue param_dict;
00113 priv_nh.getParam("", param_dict);
00114
00115 ROS_ASSERT(param_dict.getType() == XmlRpc::XmlRpcValue::TypeStruct);
00116
00117 urdf::Model model;
00118 model.initParam("robot_description");
00119 ROS_INFO("SSP: URDF robot: %s", model.getName().c_str());
00120
00121 for (auto &pair : param_dict) {
00122 ROS_DEBUG("SSP: Loading joint: %s", pair.first.c_str());
00123
00124
00125 ros::NodeHandle pnh(priv_nh, pair.first);
00126
00127 bool rc_rev;
00128 int rc_channel, rc_min, rc_max, rc_trim, rc_dz;
00129
00130 if (!pnh.getParam("rc_channel", rc_channel)) {
00131 ROS_ERROR("SSP: '%s' should provice rc_channel", pair.first.c_str());
00132 continue;
00133 }
00134
00135 pnh.param("rc_min", rc_min, 1000);
00136 pnh.param("rc_max", rc_max, 2000);
00137 if (!pnh.getParam("rc_trim", rc_trim)) {
00138 rc_trim = rc_min + (rc_max - rc_min) / 2;
00139 }
00140
00141 pnh.param("rc_dz", rc_dz, 0);
00142 pnh.param("rc_rev", rc_rev, false);
00143
00144 auto joint = model.getJoint(pair.first);
00145 if (!joint) {
00146 ROS_ERROR("SSP: URDF: there no joint '%s'", pair.first.c_str());
00147 continue;
00148 }
00149 if (!joint->limits) {
00150 ROS_ERROR("SSP: URDF: joint '%s' should provide <limit>", pair.first.c_str());
00151 continue;
00152 }
00153
00154 double lower = joint->limits->lower;
00155 double upper = joint->limits->upper;
00156
00157 servos.emplace_back(pair.first, lower, upper, rc_channel, rc_min, rc_max, rc_trim, rc_dz, rc_rev);
00158 ROS_INFO("SSP: joint '%s' (RC%d) loaded", pair.first.c_str(), rc_channel);
00159 }
00160
00161 rc_out_sub = nh.subscribe("rc_out", 10, &ServoStatePublisher::rc_out_cb, this);
00162 joint_states_pub = nh.advertise<sensor_msgs::JointState>("joint_states", 10);
00163 }
00164
00165 void spin() {
00166 if (servos.empty()) {
00167 ROS_WARN("SSP: there nothing to do, exiting");
00168 return;
00169 }
00170
00171 ROS_INFO("SSP: Initialization done. %zu joints served", servos.size());
00172 ros::spin();
00173 }
00174
00175 private:
00176 ros::NodeHandle nh;
00177 ros::Subscriber rc_out_sub;
00178 ros::Publisher joint_states_pub;
00179
00180 std::list<ServoDescription> servos;
00181
00182 void rc_out_cb(const mavros_msgs::RCOut::ConstPtr &msg) {
00183 if (msg->channels.empty())
00184 return;
00185
00186 auto states = boost::make_shared<sensor_msgs::JointState>();
00187 states->header.stamp = msg->header.stamp;
00188
00189 for (auto &desc : servos) {
00190 if (!(desc.rc_channel != 0 && desc.rc_channel <= msg->channels.size()))
00191 continue;
00192
00193 uint16_t pwm = msg->channels[desc.rc_channel - 1];
00194 if (pwm == 0 || pwm == UINT16_MAX)
00195 continue;
00196
00197 states->name.emplace_back(desc.joint_name);
00198 states->position.emplace_back(desc.calculate_position(pwm));
00199 }
00200
00201 joint_states_pub.publish(states);
00202 }
00203 };
00204
00205 int main(int argc, char *argv[])
00206 {
00207 ros::init(argc, argv, "servo_state_publisher");
00208
00209 ServoStatePublisher state_publisher;
00210 state_publisher.spin();
00211 return 0;
00212 }
00213