00001 #include <string>
00002 #include <string.h>
00003 #include "RoboteqDevice.h"
00004 #include "ErrorCodes.h"
00005 #include "Constants.h"
00006 #include "ros/ros.h"
00007 #include "geometry_msgs/Twist.h"
00008 #include "komodo_rover/StampedEncoders.h"
00009 #include "nav_msgs/Odometry.h"
00010 #include "tf/tf.h"
00011 #include <tf/transform_broadcaster.h>
00012 #include <cmath>
00013 #include <iostream>
00014 #include <stdio.h>
00015 #include <std_srvs/Empty.h>
00016 #include "sensor_msgs/Imu.h"
00017 #include "tf/transform_datatypes.h"
00018 #include "std_msgs/Float32.h"
00019
00020 using namespace std;
00021
00022 ros::Publisher rover_bat_pub;
00023
00024 RoboteqDevice device;
00025
00026 #define MAX_ERRORS 5
00027
00028 bool rp_from_imu = true;
00029 bool y_from_imu = true;
00030 int enc_loop_count = 0, enc_loop_div;
00031 int encoder_cpr, encoder_ppr;
00032 int status = -1;
00033 int prev_l_encoder = 0, prev_r_encoder = 0;
00034 int l_encoder_init = 0, r_encoder_init = 0;
00035 bool first_enc_read = true;
00036 double Left_Motor_command = 0;
00037 double Right_Motor_command = 0;
00038 ros::Publisher odom_pub;
00039 ros::Publisher encoder_pub;
00040 tf::TransformBroadcaster *odom_broadcaster;
00041
00042
00043
00044 geometry_msgs::Quaternion q_imu = tf::createQuaternionMsgFromYaw(0);
00045
00046 int l_encoder=0;
00047 int r_encoder=0;
00048
00049 double wheel_circumference = 0.0;
00050 double wheel_base_length = 0.0;
00051 double wheel_diameter = 0.0;
00052 double motors_loop_rate;
00053 double encoders_loop_rate;
00054 double tf_loop_rate;
00055 std::string odom_frame_id;
00056 int enc_error_count = 0;
00057 int mot_error_count = 0;
00058 double target_speed = 0.0;
00059 double target_direction = 0.0;
00060
00061 double rot_cov = 0.0;
00062 double pos_cov = 0.0;
00063
00064 int rpm_limit;
00065
00066
00067 double xx = 0, yy = 0, tt = 0;
00068 ros::Time prev_time, mot_loop_time, enc_loop_time, bat_loop_time, tf_loop_time;
00069
00070 void updtae_state();
00071
00072 double wrapToPi(double angle) {
00073 angle += M_PI;
00074 bool is_neg = (angle < 0);
00075 angle = fmod(angle, (2.0 * M_PI));
00076 if (is_neg) {
00077 angle += (2.0 * M_PI);
00078 }
00079 angle -= M_PI;
00080 return angle;
00081 }
00082
00083 void cmd_velCallback(const geometry_msgs::Twist::ConstPtr& msg) {
00084
00085
00086
00087 double Right_Motor_v = msg->linear.x;
00088 double Left_Motor_v = msg->angular.z * (wheel_base_length / 2.0);
00089
00090 double Left_Motor_rpm = Left_Motor_v * (60.0 / (M_PI * wheel_diameter));
00091 double Right_Motor_rpm = Right_Motor_v * (60.0 / (M_PI * wheel_diameter));
00092
00093 if (Left_Motor_rpm > rpm_limit)
00094 Left_Motor_rpm = rpm_limit;
00095 if (Left_Motor_rpm < -rpm_limit)
00096 Left_Motor_rpm = -rpm_limit;
00097 if (Right_Motor_rpm > rpm_limit)
00098 Right_Motor_rpm = rpm_limit;
00099 if (Right_Motor_rpm < -rpm_limit)
00100 Right_Motor_rpm = -rpm_limit;
00101
00102
00103 Left_Motor_command = Left_Motor_rpm*1000.0/(double)rpm_limit;
00104 Right_Motor_command = Right_Motor_rpm*1000.0/(double)rpm_limit;
00105
00106
00107
00108 }
00109
00110 void controlLoop() {
00111
00112 int status1 = -1;
00113 int status2 = -1;
00114
00115 status1 = device.SetCommand(_GO, 1, (int) Right_Motor_command);
00116 status2 = device.SetCommand(_GO, 2, (int) Left_Motor_command);
00117 if ((status1 != RQ_SUCCESS) || (status2 != RQ_SUCCESS)) {
00118 ROS_ERROR("Error commanding motors. error codes: m1=%d m2=%d", status1,status2);
00119 mot_error_count = mot_error_count + 1;
00120 if (mot_error_count >= MAX_ERRORS) {
00121 ROS_ERROR("Error commanding motors -> Resarting connection...");
00122 device.Disconnect();
00123 }
00124 return;
00125 }
00126 mot_error_count = 0;
00127 Left_Motor_command = 0.0;
00128 Right_Motor_command = 0.0;
00129
00130 }
00131
00132 void queryBat() {
00133
00134
00135
00136
00137 int status3 = -1;
00138
00139 int bat;
00140 status3 = device.GetValue(_VOLTS, 2, bat);
00141 if (status3 == RQ_SUCCESS) {
00142
00143 std_msgs::Float32 v_bat;
00144 v_bat.data=(float)bat/10;
00145 rover_bat_pub.publish(v_bat);
00146 }
00147 else {
00148 ROS_ERROR("Error reading battary voltage");
00149 }
00150 }
00151
00152 void queryEncoders() {
00153
00154 int status1 = -1, status2 = -1;
00155
00156
00157 if (!ros::ok() || !device.IsConnected())
00158 return;
00159
00160 ros::Time now = ros::Time::now();
00161 double delta_time = (now - prev_time).toSec();
00162 if (((status1 = device.GetValue(_C, 1, r_encoder)) != RQ_SUCCESS)
00163 || ((status2 = device.GetValue(_C, 2, l_encoder)) != RQ_SUCCESS)) {
00164 ROS_ERROR("Error reading encoders. error codes: e1=%d e2=%d", status1,
00165 status2);
00166 enc_error_count = enc_error_count + 1;
00167
00168 if (enc_error_count >= MAX_ERRORS) {
00169 ROS_ERROR("Error reading encoders -> Resarting connection...");
00170 device.Disconnect();
00171 }
00172 return;
00173 }
00174 enc_error_count = 0;
00175
00176 l_encoder = l_encoder - l_encoder_init;
00177 r_encoder = r_encoder - r_encoder_init;
00178
00179 komodo_rover::StampedEncoders encoder_msg;
00180 encoder_msg.header.stamp = now;
00181 encoder_msg.header.frame_id = "base_link";
00182 encoder_msg.encoders.time_delta = delta_time;
00183 encoder_msg.encoders.left_wheel = l_encoder;
00184 encoder_msg.encoders.right_wheel = r_encoder;
00185
00186 encoder_pub.publish(encoder_msg);
00187 }
00188
00189 void updtae_state() {
00190
00191 ros::Time now = ros::Time::now();
00192 double delta_time = (now - prev_time).toSec();
00193
00194 prev_time = now;
00195
00196
00197 if (first_enc_read) {
00198 prev_l_encoder = l_encoder;
00199 prev_r_encoder = r_encoder;
00200 }
00201 int diff_l_encoder = l_encoder-prev_l_encoder ;
00202 int diff_r_encoder = r_encoder-prev_r_encoder ;
00203 prev_l_encoder = l_encoder;
00204 prev_r_encoder = r_encoder;
00205
00206 double l_w = diff_l_encoder * 2.0 * M_PI / (double) encoder_cpr
00207 / delta_time;
00208
00209 double r_w = diff_r_encoder * 2.0 * M_PI / (double) encoder_cpr
00210 / delta_time;
00211
00212
00213
00214 double l_v = l_w * wheel_diameter / 2.0;
00215 double r_v = r_w * wheel_diameter / 2.0;
00216
00217 double v = (l_v + r_v) / 2.0;
00218
00219 double w = (r_v - l_v) / wheel_base_length;
00220
00221
00222 geometry_msgs::Quaternion quat;
00223 double roll = 0, pitch = 0, yaw = 0;
00224 tf::Quaternion q;
00225 tf::quaternionMsgToTF(q_imu, q);
00226 tf::Matrix3x3(q).getRPY(roll, pitch, yaw);
00227
00228 if (first_enc_read) {
00229
00230 xx = 0;
00231 yy = 0;
00232 tt = 0;
00233 first_enc_read = false;
00234 }
00235 else {
00236
00237 if (!rp_from_imu) {
00238 roll = 0;
00239 pitch = 0;
00240 }
00241
00242
00243
00244
00245 if (y_from_imu) {
00246 tt = wrapToPi(yaw);
00247 }
00248
00249 else {
00250 tt = tt + w * delta_time;
00251 tt = wrapToPi(tt);
00252
00253 }
00254 }
00255
00256 quat = tf::createQuaternionMsgFromRollPitchYaw(wrapToPi(roll),
00257 wrapToPi(pitch), tt);
00258
00259
00260 xx = xx + (v * cos(tt))*delta_time;
00261 yy = yy + (v * sin(tt))*delta_time;
00262
00263
00264
00265 nav_msgs::Odometry odom_msg;
00266
00267 odom_msg.header.stamp = now;
00268 odom_msg.header.frame_id = odom_frame_id;
00269 odom_msg.pose.pose.position.x = xx;
00270 odom_msg.pose.pose.position.y = yy;
00271 odom_msg.pose.pose.position.z = 0;
00272 odom_msg.pose.pose.orientation = quat;
00273 odom_msg.child_frame_id = "base_link";
00274 odom_msg.twist.twist.linear.x = v;
00275 odom_msg.twist.twist.linear.y = 0;
00276 odom_msg.twist.twist.angular.z = w;
00277
00278 odom_msg.pose.covariance[0] = pos_cov;
00279 odom_msg.pose.covariance[7] = pos_cov;
00280 odom_msg.pose.covariance[14] = 1e100;
00281 odom_msg.pose.covariance[21] = 1e100;
00282 odom_msg.pose.covariance[28] = 1e100;
00283 odom_msg.pose.covariance[35] = rot_cov;
00284 odom_msg.twist.covariance = odom_msg.pose.covariance;
00285
00286 odom_pub.publish(odom_msg);
00287
00288
00289 geometry_msgs::TransformStamped odom_trans;
00290 odom_trans.header.stamp = now;
00291 odom_trans.header.frame_id = odom_frame_id;
00292 odom_trans.child_frame_id = "base_link";
00293 odom_trans.transform.translation.x = xx;
00294 odom_trans.transform.translation.y = yy;
00295 odom_trans.transform.translation.z = 0.0;
00296 odom_trans.transform.rotation = quat;
00297 odom_broadcaster->sendTransform(odom_trans);
00298 }
00299
00300 bool zero_enc_callback(std_srvs::Empty::Request& request,
00301 std_srvs::Empty::Response& response) {
00302 ROS_INFO("Zeroing odometry");
00303
00304 first_enc_read = true;
00305 return true;
00306 }
00307
00308 void imu_Callback(const sensor_msgs::Imu::ConstPtr& msg) {
00309
00310 q_imu = msg->orientation;
00311
00312
00313 }
00314
00315
00316
00317
00318 int main(int argc, char **argv) {
00319
00320
00321
00322 ros::init(argc, argv, "Roboteq_Driver");
00323 ros::NodeHandle n("~");
00324 prev_time = ros::Time::now();
00325 mot_loop_time = ros::Time::now();
00326 enc_loop_time = ros::Time::now();
00327 bat_loop_time = ros::Time::now();
00328 tf_loop_time = ros::Time::now();
00329 std::string port;
00330 n.param("serial_port", port, std::string("/dev/Roboteq"));
00331 n.param("wheel_diameter", wheel_diameter, 0.2);
00332 wheel_circumference = wheel_diameter * M_PI;
00333 n.param("wheel_base_length", wheel_base_length, 0.45);
00334 n.param("encoder_ppr", encoder_ppr, 512);
00335 encoder_cpr = encoder_ppr * 4;
00336 n.param("odom_frame_id", odom_frame_id, std::string("/odom"));
00337 n.param("rpm_limit", rpm_limit, 500);
00338 n.param("rotation_covariance", rot_cov, 1.0);
00339 n.param("position_covariance", pos_cov, 1.0);
00340 n.param("motors_loop_rate", motors_loop_rate, 20.0);
00341
00342 n.param("encoders_loop_rate", encoders_loop_rate, 5.0);
00343 n.param("tf_loop_rate", tf_loop_rate, 10.0);
00344 n.param("roll_pitch_from_imu", rp_from_imu, true);
00345 n.param("yaw_from_imu", y_from_imu, true);
00346
00347 ros::Subscriber imu_sub = n.subscribe("/imu/data", 10, imu_Callback);
00348
00349
00350 odom_pub = n.advertise < nav_msgs::Odometry > ("/odom", 10);
00351
00352 encoder_pub = n.advertise < komodo_rover::StampedEncoders > ("/encoders", 10);
00353
00354 odom_broadcaster = new tf::TransformBroadcaster;
00355
00356 ros::Subscriber sub = n.subscribe("/cmd_vel", 1, cmd_velCallback);
00357
00358 ros::ServiceServer service = n.advertiseService("zero_odometry",
00359 zero_enc_callback);
00360
00361
00362 rover_bat_pub = n.advertise<std_msgs::Float32>("/rover_bat", 10);
00363
00364
00365 ros::AsyncSpinner spinner(1);
00366 spinner.start();
00367
00368 while (ros::ok()) {
00369 ROS_INFO("Connecting to port %s", port.c_str());
00370 status = device.Connect(port);
00371 if (status != RQ_SUCCESS) {
00372 ROS_ERROR(
00373 "Error connecting to device. Error code: %d. Trying again in 5 seconds...",
00374 status);
00375 for (int i = 0; i < 100; ++i) {
00376 updtae_state();
00377 ros::Duration(5.0 / 100.0).sleep();
00378 if (!ros::ok())
00379 break;
00380
00381 ros::Time now_time0 = ros::Time::now();
00382 if ((now_time0 - tf_loop_time).toSec()
00383 >= 1.0 / tf_loop_rate) {
00384
00385 updtae_state ();
00386 tf_loop_time = now_time0;
00387 }
00388
00389 }
00390 continue;
00391 }
00392
00393
00394
00395
00396
00397
00398
00399 while ((device.IsConnected()) && (ros::ok())) {
00400
00401 ros::Time now_time = ros::Time::now();
00402
00403 if ((now_time - mot_loop_time).toSec() >= 1.0 / motors_loop_rate) {
00404 controlLoop();
00405
00406 mot_loop_time = now_time;
00407 }
00408 if ((now_time - enc_loop_time).toSec()
00409 >= 1.0 / encoders_loop_rate) {
00410 queryEncoders();
00411
00412 enc_loop_time = now_time;
00413 }
00414 if ((now_time - tf_loop_time).toSec()
00415 >= 1.0 / tf_loop_rate) {
00416
00417 updtae_state ();
00418 tf_loop_time = now_time;
00419 }
00420
00421 if ((now_time - bat_loop_time).toSec() >= 1.0) {
00422 queryBat();
00423
00424 bat_loop_time = now_time;
00425 }
00426
00427
00428
00429 }
00430 if ((ros::ok()) && (!device.IsConnected())) {
00431 ROS_ERROR("Connection failed!");
00432 continue;
00433 }
00434
00435 }
00436
00437 spinner.stop();
00438 device.Disconnect();
00439 ROS_INFO("Disconnected");
00440 return 0;
00441 }
00442