Go to the documentation of this file.00001 #include <string>
00002 #include <ros/ros.h>
00003 #include <tf/transform_broadcaster.h>
00004 #include <rflex/b21_driver.h>
00005 #include <std_msgs/Bool.h>
00006 #include <std_msgs/Float32.h>
00007 #include <sensor_msgs/JointState.h>
00008 #include <geometry_msgs/Twist.h>
00009 #include <sensor_msgs/PointCloud.h>
00010 #include <nav_msgs/Odometry.h>
00011 #include <angles/angles.h>
00012
00013 #include <dynamic_reconfigure/server.h>
00014 #include <rflex/B21Config.h>
00015
00016 #include <diagnostic_updater/diagnostic_updater.h>
00017 #include <diagnostic_updater/publisher.h>
00018
00038 class B21Node {
00039 private:
00040 B21 driver;
00041
00042 ros::Subscriber sub;
00043 ros::Publisher base_sonar_pub;
00044 ros::Publisher body_sonar_pub;
00045 ros::Publisher voltage_pub;
00046 ros::Publisher brake_power_pub;
00047 ros::Publisher sonar_power_pub;
00048 ros::Publisher odom_pub;
00049 ros::Publisher plugged_pub;
00050 ros::Publisher joint_pub;
00051 ros::Publisher bump_pub;
00052 tf::TransformBroadcaster broadcaster;
00053
00054 dynamic_reconfigure::Server<rflex::B21Config> server;
00055 diagnostic_updater::Updater updater;
00056
00057 bool isSonarOn, isBrakeOn;
00058 float acceleration;
00059 float last_distance, last_bearing;
00060 float x_odo, y_odo, a_odo;
00061 float cmdTranslation, cmdRotation;
00062 bool brake_dirty, sonar_dirty;
00063 bool initialized;
00064 float first_bearing;
00065 int updateTimer;
00066 int prev_bumps;
00067 bool sonar_just_on;
00068
00069 void publishOdometry();
00070 void publishSonar();
00071 void publishBumps();
00072
00073 public:
00074 ros::NodeHandle n;
00075 B21Node();
00076 ~B21Node();
00077 int initialize(const char* port);
00078 void spinOnce();
00079
00080
00081 void NewCommand (const geometry_msgs::Twist::ConstPtr& msg);
00082 void configure(rflex::B21Config &config, uint32_t level);
00083 void produce_diagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat);
00084 };
00085
00086 B21Node::B21Node() : n ("~") {
00087 isSonarOn = isBrakeOn = false;
00088 brake_dirty = sonar_dirty = false;
00089 sonar_just_on = false;
00090 cmdTranslation = cmdRotation = 0.0;
00091 updateTimer = 99;
00092 initialized = false;
00093 prev_bumps = 0;
00094 sub = n.subscribe<geometry_msgs::Twist>("cmd_vel", 1, &B21Node::NewCommand, this);
00095 acceleration = 0.7;
00096
00097 dynamic_reconfigure::Server<rflex::B21Config>::CallbackType f;
00098 f = boost::bind(&B21Node::configure, this, _1, _2);
00099 server.setCallback(f);
00100
00101 base_sonar_pub = n.advertise<sensor_msgs::PointCloud>("sonar_cloud_base", 50);
00102 body_sonar_pub = n.advertise<sensor_msgs::PointCloud>("sonar_cloud_body", 50);
00103 sonar_power_pub = n.advertise<std_msgs::Bool>("sonar_power", 1);
00104 brake_power_pub = n.advertise<std_msgs::Bool>("brake_power", 1);
00105 voltage_pub = n.advertise<std_msgs::Float32>("voltage", 1);
00106 odom_pub = n.advertise<nav_msgs::Odometry>("odom", 50);
00107 plugged_pub = n.advertise<std_msgs::Bool>("plugged_in", 1);
00108 joint_pub = n.advertise<sensor_msgs::JointState>("state", 1);
00109 bump_pub = n.advertise<sensor_msgs::PointCloud>("bump", 5);
00110 }
00111
00112 int B21Node::initialize(const char* port) {
00113 int ret = driver.initialize(port);
00114 if (ret < 0)
00115 return ret;
00116
00117 driver.setOdometryPeriod (100000);
00118 driver.setDigitalIoPeriod(100000);
00119 driver.motionSetDefaults();
00120 updater.setHardwareID("none");
00121 updater.add("B21 Status", this, &B21Node::produce_diagnostics);
00122 return 0;
00123 }
00124
00125 B21Node::~B21Node() {
00126 driver.motionSetDefaults();
00127 driver.setOdometryPeriod(0);
00128 driver.setDigitalIoPeriod(0);
00129 driver.setSonarPower(false);
00130 driver.setIrPower(false);
00131 }
00132
00134 void B21Node::NewCommand(const geometry_msgs::Twist::ConstPtr& msg) {
00135 cmdTranslation = msg->linear.x;
00136 cmdRotation = msg->angular.z;
00137 }
00138
00139 void B21Node::configure(rflex::B21Config &config, uint32_t level) {
00140 acceleration = config.cmd_accel;
00141 isSonarOn = config.sonar_enabled;
00142 isBrakeOn = config.brake_enabled;
00143 sonar_dirty = true;
00144 brake_dirty = true;
00145 }
00146
00147 void B21Node::spinOnce() {
00148
00149 if (updateTimer>=100) {
00150 driver.sendSystemStatusCommand();
00151 updateTimer = 0;
00152 }
00153 updateTimer++;
00154
00155 if (cmdTranslation != 0 || cmdRotation != 0)
00156 driver.setMovement(cmdTranslation, cmdRotation, acceleration);
00157
00158 if (sonar_dirty) {
00159 driver.setSonarPower(isSonarOn);
00160 sonar_dirty = false;
00161 driver.sendSystemStatusCommand();
00162 }
00163 if (brake_dirty) {
00164 driver.setBrakePower(isBrakeOn);
00165 brake_dirty = false;
00166 updateTimer = 99;
00167 }
00168
00169 std_msgs::Bool bmsg;
00170 bmsg.data = isSonarOn;
00171 sonar_power_pub.publish(bmsg);
00172 bmsg.data = driver.getBrakePower();
00173 brake_power_pub.publish(bmsg);
00174 bmsg.data = driver.isPluggedIn();
00175 plugged_pub.publish(bmsg);
00176 std_msgs::Float32 vmsg;
00177 vmsg.data = driver.getVoltage();
00178 voltage_pub.publish(vmsg);
00179
00180 publishOdometry();
00181 publishSonar();
00182 publishBumps();
00183 updater.update();
00184 }
00185
00188 void B21Node::publishOdometry() {
00189 if (!driver.isOdomReady()) {
00190 return;
00191 }
00192
00193 float distance = driver.getDistance();
00194 float true_bearing = angles::normalize_angle(driver.getBearing());
00195
00196 if (!initialized) {
00197 initialized = true;
00198 first_bearing = true_bearing;
00199 x_odo = 0;
00200 y_odo = 0;
00201 a_odo = 0*true_bearing;
00202 } else {
00203 float bearing = true_bearing - first_bearing;
00204 float d_dist = distance-last_distance;
00205 float d_bearing = bearing - last_bearing;
00206
00207 if (d_dist > 50 || d_dist < -50)
00208 return;
00209
00210 a_odo += d_bearing;
00211 a_odo = angles::normalize_angle(a_odo);
00212
00213
00214 x_odo += d_dist * cos(a_odo);
00215 y_odo += d_dist * sin(a_odo);
00216 }
00217 last_distance = distance;
00218 last_bearing = true_bearing - first_bearing;
00219
00220
00221 geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(last_bearing);
00222
00223
00224 geometry_msgs::TransformStamped odom_trans;
00225 odom_trans.header.stamp = ros::Time::now();
00226 odom_trans.header.frame_id = "odom";
00227 odom_trans.child_frame_id = "base";
00228
00229 odom_trans.transform.translation.x = x_odo;
00230 odom_trans.transform.translation.y = y_odo;
00231 odom_trans.transform.rotation = odom_quat;
00232
00233
00234 broadcaster.sendTransform(odom_trans);
00235
00236
00237 nav_msgs::Odometry odom;
00238 odom.header.stamp = ros::Time::now();
00239 odom.header.frame_id = "odom";
00240
00241
00242 odom.pose.pose.position.x = x_odo;
00243 odom.pose.pose.position.y = y_odo;
00244 odom.pose.pose.orientation = odom_quat;
00245
00246
00247 odom.child_frame_id = "base";
00248 float tvel = driver.getTranslationalVelocity();
00249 odom.twist.twist.linear.x = tvel*cos(a_odo);
00250 odom.twist.twist.linear.y = tvel*sin(a_odo);
00251 odom.twist.twist.angular.z = driver.getRotationalVelocity();
00252
00253
00254 odom_pub.publish(odom);
00255
00256
00257 sensor_msgs::JointState joint_state;
00258 joint_state.header.stamp = ros::Time::now();
00259 joint_state.name.resize(1);
00260 joint_state.position.resize(1);
00261 joint_state.name[0] = "lewis_twist";
00262 joint_state.position[0] = true_bearing;
00263
00264 joint_pub.publish(joint_state);
00265
00266 }
00267
00268 void B21Node::publishSonar() {
00269 sensor_msgs::PointCloud cloud;
00270 cloud.header.stamp = ros::Time::now();
00271 cloud.header.frame_id = "base";
00272
00273 if (isSonarOn) {
00274 driver.getBaseSonarPoints(&cloud);
00275 base_sonar_pub.publish(cloud);
00276
00277 driver.getBodySonarPoints(&cloud);
00278 cloud.header.frame_id = "body";
00279 body_sonar_pub.publish(cloud);
00280
00281 } else if (sonar_just_on) {
00282 base_sonar_pub.publish(cloud);
00283 cloud.header.frame_id = "body";
00284 body_sonar_pub.publish(cloud);
00285 }
00286 }
00287
00288 void B21Node::publishBumps() {
00289 sensor_msgs::PointCloud cloud1, cloud2;
00290 cloud1.header.stamp = ros::Time::now();
00291 cloud2.header.stamp = ros::Time::now();
00292 cloud1.header.frame_id = "base";
00293 cloud2.header.frame_id = "body";
00294 int bumps = driver.getBaseBumps(&cloud1) +
00295 driver.getBodyBumps(&cloud2);
00296
00297 if (bumps>0 || prev_bumps>0) {
00298 bump_pub.publish(cloud1);
00299 bump_pub.publish(cloud2);
00300 }
00301 prev_bumps = bumps;
00302 }
00303
00304 void B21Node::produce_diagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat) {
00305 if( !driver.getBrakePower() )
00306 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Motors are enabled");
00307 else
00308 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Brake is enabled");
00309
00310 stat.add("Sonar", isSonarOn);
00311 stat.add("Plugged In", driver.isPluggedIn());
00312 stat.add("Voltage", driver.getVoltage());
00313 }
00314
00315 int main(int argc, char** argv) {
00316 ros::init(argc, argv, "b21");
00317 B21Node node;
00318 std::string port;
00319 node.n.param<std::string>("port", port, "/dev/ttyUSB0");
00320 ROS_INFO("Attempting to connect to %s", port.c_str());
00321 if (node.initialize(port.c_str())<0) {
00322 ROS_ERROR("Could not initialize RFLEX driver!\n");
00323 return 0;
00324 }
00325 ROS_INFO("Connected!");
00326
00327
00328 int hz;
00329 node.n.param("rate", hz, 10);
00330 ros::Rate loop_rate(hz);
00331
00332 while (ros::ok()) {
00333 node.spinOnce();
00334
00335 ros::spinOnce();
00336
00337 loop_rate.sleep();
00338 }
00339
00340 return 0;
00341 }