b21_node.cc
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         // Message Listener
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     // Sending the status command too often overwhelms the driver
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         //integrate latest motion into odometry
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     //since all odometry is 6DOF we'll need a quaternion created from yaw
00221     geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(last_bearing);
00222 
00223     //first, we'll publish the transform over tf
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     //send the transform
00234     broadcaster.sendTransform(odom_trans);
00235     
00236     //next, we'll publish the odometry message over ROS
00237     nav_msgs::Odometry odom;
00238     odom.header.stamp = ros::Time::now();
00239     odom.header.frame_id = "odom";
00240 
00241     //set the position
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     //set the velocity
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     //publish the message
00254     odom_pub.publish(odom);
00255 
00256     // finally, publish the joint state
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         // Process a round of subscription messages
00335         ros::spinOnce();
00336         // This will adjust as needed per iteration
00337         loop_rate.sleep();
00338     }
00339 
00340     return 0;
00341 }


rflex
Author(s): David V. Lu!!, Mikhail Medvedev
autogenerated on Fri Aug 28 2015 12:58:58