00001 #include "ros/ros.h"
00002 #include <lizi/lizi_raw.h>
00003 #include <lizi/lizi_gps.h>
00004 #include <lizi/lizi_pan_tilt.h>
00005 #include <lizi/lizi_command.h>
00006 #include <lizi/set_odom.h>
00007 #include "sensor_msgs/Imu.h"
00008 #include "sensor_msgs/Range.h"
00009 #include "sensor_msgs/NavSatFix.h"
00010 #include "sensor_msgs/NavSatStatus.h"
00011 #include <sensor_msgs/JointState.h>
00012 #include "geometry_msgs/Twist.h"
00013 #include "geometry_msgs/Quaternion.h"
00014 #include "geometry_msgs/Vector3Stamped.h"
00015 #include "nav_msgs/Odometry.h"
00016 #include "tf/transform_datatypes.h"
00017 #include <tf/transform_broadcaster.h>
00018 #include <math.h>
00019
00020
00021 ros::Publisher left_urf_pub;
00022 ros::Publisher rear_urf_pub;
00023 ros::Publisher right_urf_pub;
00024
00025 ros::Publisher odom_pub;
00026 ros::Publisher gps_pub;
00027 ros::Publisher imu_pub;
00028 ros::Publisher command_pub;
00029 ros::Publisher pan_tilt_pub;
00030
00031
00032 sensor_msgs::Range left_urf_msg;
00033 sensor_msgs::Range rear_urf_msg;
00034 sensor_msgs::Range right_urf_msg;
00035
00036 std::string lizi_id;
00037 std::string gps_frame_id;
00038 std::string odom_frame_id;
00039 std::string base_frame_id;
00040 std::string imu_frame_id;
00041 std::string cmd_vel_topic;
00042 std::string pan_tilt_topic;
00043 std::string lizi_command_topic;
00044 std::string gps_pub_topic;
00045 std::string set_odom_srv;
00046 std::string odom_topic;
00047 std::string lizi_raw_topic;
00048 std::string lizi_gps_topic;
00049 std::string left_urf_frame_id;
00050 std::string rear_urf_frame_id;
00051 std::string right_urf_frame_id;
00052 std::string pan_joint_id;
00053 std::string tilt_joint_id;
00054 std::string FR_joint_id;
00055 std::string FL_joint_id;
00056 std::string RR_joint_id;
00057 std::string RL_joint_id;
00058
00059 std::string joint_states_topic;
00060
00061 sensor_msgs::JointState jointstate_msg;
00062
00063 tf::TransformBroadcaster *imu_broadcaster;
00064 tf::TransformBroadcaster *odom_broadcaster;
00065
00066 double wheel_base_length;
00067 double wheel_diameter;
00068 double encoder_cpr;
00069
00070 int l_encoder=0,pre_l_encoder=0;
00071 int r_encoder=0,pre_r_encoder=0;
00072 geometry_msgs::Quaternion q_imu;
00073 double xx = 0, yy = 0, tt = 0;
00074 bool first_enc_read = true;
00075
00076 bool fuse_imu_roll_pitch;
00077 bool fuse_imu_yaw;
00078 double slip_factor;
00079
00080 double rot_cov = 0.0;
00081 double pos_cov = 0.0;
00082 ros::Time prev_time;
00083
00084 bool wd_on=false;
00085 ros::Time wd_time;
00086
00087 double pan=0;
00088 double tilt=0;
00089
00090
00091
00092 void cmd_velCallback(const geometry_msgs::Twist::ConstPtr& msg) {
00093
00094 if (wd_on) wd_on=false;
00095
00096 wd_time = ros::Time::now();
00097
00098
00099 double Right_Motor_v = msg->linear.x + msg->angular.z * (wheel_base_length / 2.0);
00100 double Left_Motor_v = msg->linear.x - msg->angular.z * (wheel_base_length / 2.0);
00101
00102 lizi::lizi_command command_msg;
00103 command_msg.left_wheel=(int)(Left_Motor_v*encoder_cpr/(M_PI * wheel_diameter));
00104 command_msg.right_wheel=(int)(Right_Motor_v*encoder_cpr/(M_PI * wheel_diameter));
00105 command_pub.publish(command_msg);
00106
00107
00108
00109 }
00110
00111 double wrapToPi(double angle) {
00112 angle += M_PI;
00113 bool is_neg = (angle < 0);
00114 angle = fmod(angle, (2.0 * M_PI));
00115 if (is_neg) {
00116 angle += (2.0 * M_PI);
00117 }
00118 angle -= M_PI;
00119 return angle;
00120 }
00121
00122 void encodersCallback(int32_t left_ticks, int32_t right_ticks) {
00123
00124 ros::Time now = ros::Time::now();
00125 double delta_time = (now - prev_time).toSec();
00126 prev_time = now;
00127
00128 pre_l_encoder=l_encoder;
00129 pre_r_encoder=r_encoder;
00130
00131 l_encoder = left_ticks;
00132 r_encoder = right_ticks;
00133
00134
00136 double l_tics_per_s=(double)(l_encoder-pre_l_encoder)/delta_time;
00137 double r_tics_per_s=(double)(r_encoder-pre_r_encoder)/delta_time;
00138
00139 double l_w = l_tics_per_s * 2.0 * M_PI / (double) encoder_cpr;
00140 double r_w = r_tics_per_s * 2.0 * M_PI / (double) encoder_cpr;
00141
00142
00143
00144 double l_v = l_w * wheel_diameter / 2.0;
00145 double r_v = r_w * wheel_diameter / 2.0;
00146
00147 double v = (l_v + r_v) / 2.0;
00148
00149 double w = (r_v - l_v) / wheel_base_length;
00150
00151 if (first_enc_read) {
00152
00153 xx = 0;
00154 yy = 0;
00155 tt = 0;
00156 first_enc_read = false;
00157 }
00158
00159 tt = tt + w * delta_time*slip_factor;
00160 tt = wrapToPi(tt);
00161 xx = xx + (v * cos(tt))*delta_time;
00162 yy = yy + (v * sin(tt))*delta_time;
00163
00164
00165
00166 nav_msgs::Odometry odom_msg;
00167
00168 geometry_msgs::Quaternion q_odom;
00169
00170 odom_msg.header.stamp = now;
00171 odom_msg.header.frame_id = odom_frame_id;
00172 odom_msg.pose.pose.position.x = xx;
00173 odom_msg.pose.pose.position.y = yy;
00174 odom_msg.pose.pose.position.z = 0;
00175 double roll = 0, pitch = 0, yaw = 0;
00176 if ((fuse_imu_roll_pitch)&&(fuse_imu_yaw)) {
00177 q_odom =q_imu;
00178 tf::Quaternion q;
00179 tf::quaternionMsgToTF(q_imu, q);
00180 tf::Matrix3x3(q).getRPY(roll, pitch, yaw);
00181 tt=yaw;
00182 }
00183 else if ((!fuse_imu_roll_pitch)&&(fuse_imu_yaw)) {
00184 tf::Quaternion q;
00185 tf::quaternionMsgToTF(q_imu, q);
00186 tf::Matrix3x3(q).getRPY(roll, pitch, yaw);
00187 q_odom =tf::createQuaternionMsgFromRollPitchYaw(0,0, yaw);
00188 tt=yaw;
00189 }
00190 else if ((fuse_imu_roll_pitch)&&(!fuse_imu_yaw)) {
00191 tf::Quaternion q;
00192 tf::quaternionMsgToTF(q_imu, q);
00193 tf::Matrix3x3(q).getRPY(roll, pitch, yaw);
00194 q_odom =tf::createQuaternionMsgFromRollPitchYaw(roll,pitch, tt);
00195 }
00196 else if ((!fuse_imu_roll_pitch)&&(!fuse_imu_yaw)) {
00197 q_odom =tf::createQuaternionMsgFromRollPitchYaw(0,0, tt);
00198 }
00199
00200 odom_msg.pose.pose.orientation=q_odom;
00201
00202 odom_msg.child_frame_id = base_frame_id;
00203 odom_msg.twist.twist.linear.x = v;
00204 odom_msg.twist.twist.linear.y = 0;
00205 odom_msg.twist.twist.angular.z = w;
00206
00207 odom_msg.pose.covariance[0] = pos_cov;
00208 odom_msg.pose.covariance[7] = pos_cov;
00209 odom_msg.pose.covariance[14] = 1e100;
00210 odom_msg.pose.covariance[21] = 1e100;
00211 odom_msg.pose.covariance[28] = 1e100;
00212 odom_msg.pose.covariance[35] = rot_cov;
00213 odom_msg.twist.covariance = odom_msg.pose.covariance;
00214
00215 odom_pub.publish(odom_msg);
00216
00217
00218 geometry_msgs::TransformStamped odom_trans;
00219 odom_trans.header.stamp = now;
00220 odom_trans.header.frame_id = odom_frame_id;
00221 odom_trans.child_frame_id = base_frame_id;
00222 odom_trans.transform.translation.x = xx;
00223 odom_trans.transform.translation.y = yy;
00224 odom_trans.transform.translation.z = 0.0;
00225 odom_trans.transform.rotation = q_odom;
00226
00227
00228 odom_broadcaster->sendTransform(odom_trans);
00229
00230
00231 jointstate_msg.header.stamp = ros::Time::now();
00232 jointstate_msg.position[0]=pan;
00233 jointstate_msg.position[1]=tilt;
00234
00235
00236
00237 pan_tilt_pub.publish(jointstate_msg);
00238
00239 }
00240
00241 void gpsCallback(const lizi::lizi_gps::ConstPtr& msg) {
00242
00243
00244 sensor_msgs::NavSatFix gps_msg;
00245 gps_msg.header.frame_id = gps_frame_id;
00246 gps_msg.header.stamp = ros::Time::now();
00247 gps_msg.latitude = msg->Lat;
00248 gps_msg.longitude = msg->Lon;
00249 gps_msg.altitude = msg->Alt;
00250
00251 sensor_msgs::NavSatStatus gps_status_msg;
00252
00253 gps_status_msg.service = 1;
00254 if (msg->Status == 0) {
00255 gps_status_msg.status = 1;
00256 }
00257 else {
00258 gps_status_msg.status = 0;
00259
00260 }
00261
00262 gps_msg.status = gps_status_msg;
00263
00264 gps_msg.position_covariance_type = 1;
00265
00266
00267
00268
00269
00270
00271 float cov = (msg->HDOP) * (msg->HDOP);
00272 gps_msg.position_covariance[0] = cov;
00273 gps_msg.position_covariance[4] = cov;
00274 gps_msg.position_covariance[8] = cov;
00275
00276 gps_pub.publish(gps_msg);
00277
00278
00279
00280
00281 }
00282
00283 void urfCallback(float left_urf,float rear_urf,float right_urf) {
00284
00285
00286 ros::Time now = ros::Time::now();
00287
00288 left_urf_msg.header.stamp = now;
00289 left_urf_msg.range = left_urf ;
00290
00291 rear_urf_msg.header.stamp = now;
00292 rear_urf_msg.range = rear_urf ;
00293
00294 right_urf_msg.header.stamp = now;
00295 right_urf_msg.range = right_urf ;
00296
00297
00298 left_urf_pub.publish(left_urf_msg);
00299 rear_urf_pub.publish(rear_urf_msg);
00300 right_urf_pub.publish(right_urf_msg);
00301
00302 }
00303
00304
00305
00306 void imuCallback(float qw,float qx,float qy,float qz) {
00307
00308
00309 sensor_msgs::Imu imu_msg;
00310
00311 imu_msg.header.frame_id = imu_frame_id;
00312 imu_msg.header.stamp = ros::Time::now();
00313 q_imu.w=qw;
00314 q_imu.x=qx;
00315 q_imu.y=qy;
00316 q_imu.z=qz;
00317
00318 double roll = 0, pitch = 0, yaw = 0;
00319 tf::Quaternion q;
00320 tf::quaternionMsgToTF(q_imu, q);
00321 tf::Matrix3x3(q).getRPY(roll, pitch, yaw);
00322
00323 q_imu =tf::createQuaternionMsgFromRollPitchYaw(roll,-pitch, -yaw);
00324
00325 imu_msg.orientation=q_imu;
00326
00327
00328 double angular_velocity_stdev_ = 0.012;
00329 double orientation_stdev_ = 0.035;
00330 double linear_acceleration_stdev_ = 0.098;
00331
00332 double angular_velocity_covariance = angular_velocity_stdev_
00333 * angular_velocity_stdev_;
00334 double orientation_covariance = orientation_stdev_ * orientation_stdev_;
00335 double linear_acceleration_covariance = linear_acceleration_stdev_
00336 * linear_acceleration_stdev_;
00337
00338 imu_msg.linear_acceleration_covariance[0] = linear_acceleration_covariance;
00339 imu_msg.linear_acceleration_covariance[4] = linear_acceleration_covariance;
00340 imu_msg.linear_acceleration_covariance[8] = linear_acceleration_covariance;
00341
00342 imu_msg.angular_velocity_covariance[0] = angular_velocity_covariance;
00343 imu_msg.angular_velocity_covariance[4] = angular_velocity_covariance;
00344 imu_msg.angular_velocity_covariance[8] = angular_velocity_covariance;
00345
00346 imu_msg.orientation_covariance[0] = orientation_covariance;
00347 imu_msg.orientation_covariance[4] = orientation_covariance;
00348 imu_msg.orientation_covariance[8] = orientation_covariance;
00349 imu_pub.publish(imu_msg);
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 }
00363 void rawCallback(const lizi::lizi_raw::ConstPtr& msg) {
00364 float qw=msg->qw;
00365 float qx=msg->qx;
00366 float qy=msg->qy;
00367 float qz=msg->qz;
00368 imuCallback(qw,qx,qy,qz);
00369
00370 int32_t left_ticks=msg->left_ticks;
00371 int32_t right_ticks=msg->right_ticks;
00372 encodersCallback( left_ticks, right_ticks);
00373
00374 float left_urf=msg->left_urf;
00375 float rear_urf=msg->rear_urf;
00376 float right_urf=msg->right_urf;
00377 urfCallback(left_urf, rear_urf, right_urf);
00378
00379 }
00380
00381 bool set_odom(lizi::set_odom::Request &req, lizi::set_odom::Response &res)
00382 {
00383
00384 xx=req.x;
00385 yy=req.y;
00386 tt=req.theta;
00387 ROS_INFO("Set odometry to: x=%.3f, y=%.3f, theta=%.3f", xx, yy,tt);
00388
00389 return true;
00390 }
00391
00392
00393 void pan_tiltCallback(const lizi::lizi_pan_tilt::ConstPtr& msg) {
00394
00395
00396
00397 pan=-1.0*msg->pan_angle;
00398 tilt=-1.0*msg->tilt_angle;
00399 if (pan*180/M_PI>35) pan=35*M_PI/180;
00400 else if (pan*180/M_PI<-35) pan=-35*M_PI/180;
00401
00402 if (tilt*180/M_PI>30) tilt=30*M_PI/180;
00403 else if (tilt*180/M_PI<-30) tilt=-30*M_PI/180;
00404
00405
00406 }
00407 int main(int argc, char **argv) {
00408
00409
00410 ros::init(argc, argv, "lizi_node", ros::init_options::AnonymousName);
00411
00412 ros::NodeHandle n;
00413 int liziID;
00414 n.param("Lizi_ID", lizi_id, std::string("0"));
00415
00416 std::string pre="lizi_";
00417 pre+=lizi_id;
00418 n.param("GPS_frame_id", gps_frame_id, std::string("/map"));
00419
00420
00421 std::string pre1="lizi_";
00422 pre1+=lizi_id;
00423 n.param("odom_frame_id", odom_frame_id, std::string(pre1+"_odom"));
00424 n.param("base_frame_id", base_frame_id, std::string(pre1+"_base_link"));
00425 n.param("imu_frame_id", imu_frame_id, std::string(pre1+"_imu_link"));
00426 n.param("left_urf_frame_id", left_urf_frame_id, std::string(pre1+"_Left_URF_link"));
00427 n.param("rear_urf_frame_id", rear_urf_frame_id, std::string(pre1+"_Rear_URF_link"));
00428 n.param("right_urf_frame_id", right_urf_frame_id, std::string(pre1+"_Right_URF_link"));
00429 n.param("pan_joint_id", pan_joint_id, std::string(pre1+"_Asus_Pan_Joint"));
00430 n.param("tilt_joint_id", tilt_joint_id, std::string(pre1+"_Asus_Tilt_Joint"));
00431 n.param("FR_joint_id", FR_joint_id, std::string(pre1+"_FR_Wheel_Joint"));
00432 n.param("FL_joint_id", FL_joint_id, std::string(pre1+"_FL_Wheel_Joint"));
00433 n.param("RR_joint_id", RR_joint_id, std::string(pre1+"_RR_Wheel_Joint"));
00434 n.param("RL_joint_id", RL_joint_id, std::string(pre1+"_RL_Wheel_Joint"));
00435
00436
00437 n.param("cmd_vel_sub_topic", cmd_vel_topic, std::string("cmd_vel"));
00438 n.param("pan_tilt_sub_topic", pan_tilt_topic, std::string("pan_tilt"));
00439
00440 n.param("lizi_raw_sub_topic", lizi_raw_topic, std::string("lizi_raw"));
00441 n.param("lizi_gps_sub_topic", lizi_gps_topic, std::string("raw_gps"));
00442
00443 n.param("odom_pub_topic", odom_topic, std::string("odom_pub"));
00444 n.param("gps_pub_topic", gps_pub_topic, std::string("gps_pub"));
00445
00446 n.param("joint_states_topic", joint_states_topic, std::string("joint_states"));
00447
00448 n.param("lizi_command_pub_topic", lizi_command_topic, std::string("command"));
00449
00450 n.param("set_odom_srv", set_odom_srv, std::string("set_odom"));
00451
00452 n.param("wheel_diameter", wheel_diameter, 0.12);
00453 n.param("wheel_base_length", wheel_base_length, 0.275);
00454 n.param("encoder_cpr", encoder_cpr, 4288.0);
00455 n.param("rotation_covariance", rot_cov, 1.0);
00456 n.param("position_covariance", pos_cov, 1.0);
00457 n.param("fuse_imu_roll_pitch", fuse_imu_roll_pitch, true);
00458 n.param("fuse_imu_yaw", fuse_imu_yaw, false);
00459 n.param("slip_factor", slip_factor, 0.85);
00460
00461 q_imu.x=0;
00462 q_imu.y=0;
00463 q_imu.z=1;
00464 q_imu.w=0;
00465
00466
00467 ros::ServiceServer service = n.advertiseService(set_odom_srv, set_odom);
00468
00469
00470 ros::Subscriber raw_sub = n.subscribe(lizi_raw_topic, 10, rawCallback);
00471 ros::Subscriber gps_sub = n.subscribe(lizi_gps_topic, 10, gpsCallback);
00472 ros::Subscriber vel_sub = n.subscribe(cmd_vel_topic, 5, cmd_velCallback);
00473
00474 ros::Subscriber pan_tilt_sub = n.subscribe(pan_tilt_topic, 1, pan_tiltCallback);
00475
00476 imu_pub = n.advertise < sensor_msgs::Imu > ("imu_pub", 10);
00477
00478
00479 jointstate_msg.name.push_back(pan_joint_id);
00480 jointstate_msg.position.push_back(0);
00481 jointstate_msg.name.push_back(tilt_joint_id);
00482 jointstate_msg.position.push_back(0);
00483
00484 jointstate_msg.name.push_back(FR_joint_id);
00485 jointstate_msg.position.push_back(0);
00486 jointstate_msg.name.push_back(FL_joint_id);
00487 jointstate_msg.position.push_back(0);
00488 jointstate_msg.name.push_back(RR_joint_id);
00489 jointstate_msg.position.push_back(0);
00490 jointstate_msg.name.push_back(RL_joint_id);
00491 jointstate_msg.position.push_back(0);
00492
00493 right_urf_msg.header.frame_id = right_urf_frame_id;
00494 right_urf_msg.field_of_view = 0.7;
00495 right_urf_msg.radiation_type = 0;
00496 right_urf_msg.min_range = 0.25;
00497 right_urf_msg.max_range = 6;
00498
00499 rear_urf_msg.header.frame_id = rear_urf_frame_id;
00500 rear_urf_msg.field_of_view = 0.7;
00501 rear_urf_msg.radiation_type = 0;
00502 rear_urf_msg.min_range = 0.25;
00503 rear_urf_msg.max_range = 6;
00504
00505 left_urf_msg.header.frame_id = left_urf_frame_id;
00506 left_urf_msg.field_of_view = 0.7;
00507 left_urf_msg.radiation_type = 0;
00508 left_urf_msg.min_range = 0.25;
00509 left_urf_msg.max_range = 6;
00510
00511
00512 right_urf_pub = n.advertise < sensor_msgs::Range > ("Rangers/Right_URF", 5);
00513 rear_urf_pub = n.advertise < sensor_msgs::Range > ("Rangers/Rear_URF", 5);
00514 left_urf_pub = n.advertise < sensor_msgs::Range > ("Rangers/Left_URF", 5);
00515
00516 odom_pub = n.advertise < nav_msgs::Odometry > (odom_topic, 10);
00517
00518
00519 command_pub = n.advertise < lizi::lizi_command > (lizi_command_topic, 5);
00520 pan_tilt_pub = n.advertise < sensor_msgs::JointState > (joint_states_topic, 5);
00521
00522
00523
00524 gps_pub = n.advertise < sensor_msgs::NavSatFix > (gps_pub_topic, 5);
00525
00526
00527 imu_broadcaster = new tf::TransformBroadcaster;
00528
00529 odom_broadcaster = new tf::TransformBroadcaster;
00530 wd_time=ros::Time::now();
00531 while (n.ok()) {
00532
00533
00534
00535
00536
00537
00538
00539
00540 ros::spinOnce();
00541 }
00542
00543
00544
00545 return 0;
00546 }
00547