00001
00008 #include "evarobot_driver/evarobot_driver.h"
00009
00010 int i_error_code;
00011
00012 IMDRIVER::IMDRIVER(double d_limit_voltage,
00013 float f_max_lin_vel,
00014 float f_max_ang_vel,
00015 float f_wheel_separation,
00016 float f_wheel_diameter,
00017 double d_frequency,
00018 unsigned int u_i_counts,
00019 double d_duty,
00020 int i_mode,
00021 boost::shared_ptr< IMGPIO > * m1_in,
00022 boost::shared_ptr< IMGPIO > * m2_in,
00023 IMGPIO * m1_en,
00024 IMGPIO * m2_en,
00025 IMADC * adc,
00026 ros::ServiceClient & client,
00027 double _timeout):b_left_motor_error(false), b_right_motor_error(false), d_timeout(_timeout), b_motor_error(false)
00028 {
00029 this->client = client;
00030 this->adc = adc;
00031 this->d_limit_voltage = d_limit_voltage;
00032
00033 this->f_left_motor_voltage = 0.0;
00034 this->f_right_motor_voltage = 0.0;
00035
00036 this->u_i_counts = u_i_counts;
00037 this->i_const_count = (u_i_counts - 1) / this->f_max_lin_vel;
00038
00039 this->pwm = new IMPWM(d_frequency, u_i_counts, d_duty, i_mode);
00040
00041 this->m1_in = m1_in;
00042 this->m2_in = m2_in;
00043 this->m1_en = m1_en;
00044 this->m2_en = m2_en;
00045
00046 for(int i = 0; i < 2; i++)
00047 this->m1_in[i]->SetPinDirection(IMGPIO::OUTPUT);
00048
00049 for(int i = 0; i < 2; i++)
00050 this->m2_in[i]->SetPinDirection(IMGPIO::OUTPUT);
00051
00052 im_msgs::SetRGB srv;
00053
00054 srv.request.times = -1;
00055 srv.request.mode = 0;
00056 srv.request.frequency = 1.0;
00057 srv.request.color = 0;
00058
00059 if(this->client.call(srv) == 0)
00060 {
00061 ROS_INFO(GetErrorDescription(-77).c_str());
00062 i_error_code = -77;
00063 }
00064
00065
00066 this->Enable();
00067
00068 }
00069
00070 IMDRIVER::~IMDRIVER()
00071 {
00072 im_msgs::SetRGB srv;
00073
00074 srv.request.times = -1;
00075 srv.request.mode = 0;
00076 srv.request.frequency = 1.0;
00077 srv.request.color = 0;
00078
00079 if(this->client.call(srv) == 0)
00080 {
00081 ROS_INFO(GetErrorDescription(-77).c_str());
00082 i_error_code = -77;
00083 }
00084
00085 this->Disable();
00086 delete pwm;
00087 delete m1_en;
00088 delete m2_en;
00089 delete adc;
00090
00091
00092
00093
00094 }
00095
00096 void IMDRIVER::UpdateParams()
00097 {
00098 if(b_is_received_params)
00099 {
00100 ROS_DEBUG("EvarobotDriver: Updating Driver Params...");
00101 ROS_DEBUG("EvarobotDriver: %f, %f", g_d_max_lin, g_d_max_ang);
00102 ROS_DEBUG("EvarobotDriver: %f, %f", g_d_wheel_separation, g_d_wheel_diameter);
00103
00104 this->f_max_lin_vel = g_d_max_lin;
00105 this->f_max_ang_vel = g_d_max_ang;
00106 this->f_wheel_separation = g_d_wheel_separation;
00107 this->f_wheel_diameter = g_d_wheel_diameter;
00108
00109 b_is_received_params = false;
00110 }
00111 }
00112
00113 void IMDRIVER::ApplyVel(float f_left_wheel_velocity, float f_right_wheel_velocity)
00114 {
00115 if(f_left_wheel_velocity > 0)
00116 {
00117 this->m1_in[0]->SetPinValue(IMGPIO::LOW);
00118 this->m1_in[1]->SetPinValue(IMGPIO::HIGH);
00119 }
00120 else if(f_left_wheel_velocity < 0)
00121 {
00122 this->m1_in[0]->SetPinValue(IMGPIO::HIGH);
00123 this->m1_in[1]->SetPinValue(IMGPIO::LOW);
00124 }
00125 else
00126 {
00127 this->m1_in[0]->SetPinValue(IMGPIO::LOW);
00128 this->m1_in[1]->SetPinValue(IMGPIO::LOW);
00129 }
00130
00131 if(f_right_wheel_velocity > 0)
00132 {
00133 this->m2_in[0]->SetPinValue(IMGPIO::HIGH);
00134 this->m2_in[1]->SetPinValue(IMGPIO::LOW);
00135 }
00136 else if(f_right_wheel_velocity < 0)
00137 {
00138 this->m2_in[0]->SetPinValue(IMGPIO::LOW);
00139 this->m2_in[1]->SetPinValue(IMGPIO::HIGH);
00140 }
00141 else
00142 {
00143 this->m2_in[0]->SetPinValue(IMGPIO::LOW);
00144 this->m2_in[1]->SetPinValue(IMGPIO::LOW);
00145 }
00146
00147 int i_left_wheel_duty = int(fabs(f_left_wheel_velocity) * 255 / this->f_max_lin_vel);
00148 int i_right_wheel_duty = int(fabs(f_right_wheel_velocity) * 255 / this->f_max_lin_vel);
00149
00150
00151 i_left_wheel_duty = i_left_wheel_duty>=this->u_i_counts ? this->u_i_counts - 1:i_left_wheel_duty;
00152 i_right_wheel_duty = i_right_wheel_duty>=this->u_i_counts ? this->u_i_counts - 1:i_right_wheel_duty;
00153
00154 if(i_left_wheel_duty != 0)
00155 pwm->SetDutyCycleCount(i_left_wheel_duty, 0);
00156
00157 if(i_right_wheel_duty != 0)
00158 pwm->SetDutyCycleCount(i_right_wheel_duty, 1);
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 }
00173
00174 void IMDRIVER::Enable()
00175 {
00176 this->m1_en->SetPinDirection(IMGPIO::OUTPUT);
00177 this->m2_en->SetPinDirection(IMGPIO::OUTPUT);
00178
00179 this->m1_en->SetPinValue(IMGPIO::HIGH);
00180 this->m2_en->SetPinValue(IMGPIO::HIGH);
00181
00182
00183
00184 }
00185
00186 void IMDRIVER::Disable()
00187 {
00188 this->m1_en->SetPinDirection(IMGPIO::OUTPUT);
00189 this->m2_en->SetPinDirection(IMGPIO::OUTPUT);
00190
00191 this->m1_en->SetPinValue(IMGPIO::LOW);
00192 this->m2_en->SetPinValue(IMGPIO::LOW);
00193
00194 }
00195
00196 int IMDRIVER::CheckError()
00197 {
00198 int i_ret = 0;
00199
00200 string str_m1_data;
00201 string str_m2_data;
00202
00203 this->m1_en->GetPinValue(str_m1_data);
00204 this->m2_en->GetPinValue(str_m2_data);
00205
00206 if(str_m1_data == IMGPIO::LOW)
00207 {
00208 --i_ret;
00209 }
00210
00211 if(str_m2_data == IMGPIO::LOW)
00212 {
00213 --i_ret;
00214 }
00215
00216 return i_ret;
00217 }
00218
00219 im_msgs::Voltage IMDRIVER::GetMotorVoltage() const
00220 {
00221 im_msgs::Voltage ret;
00222 ret.left_motor = this->f_left_motor_voltage;
00223 ret.right_motor = this->f_right_motor_voltage;
00224
00225 return ret;
00226 }
00227
00228 bool IMDRIVER::CheckMotorCurrent()
00229 {
00230 bool b_ret = true;
00231
00232 this->f_left_motor_voltage = (float)(this->adc->ReadMotorChannel(0)*5.0/4096.0);
00233 this->f_right_motor_voltage = (float)(this->adc->ReadMotorChannel(1)*5.0/4096.0);
00234
00235 ROS_DEBUG("EvarobotDriver: LEFT MOTOR: -- %f", this->f_left_motor_voltage);
00236 ROS_DEBUG("EvarobotDriver: RIGHT MOTOR: -- %f", this->f_right_motor_voltage);
00237
00238 if(this->f_left_motor_voltage >= this->d_limit_voltage)
00239 {
00240 ROS_INFO(GetErrorDescription(-78).c_str());
00241 i_error_code = -78;
00242 b_ret = false;
00243 this->b_motor_error = true;
00244 this->b_left_motor_error = true;
00245 }
00246
00247 if(this->f_right_motor_voltage >= this->d_limit_voltage)
00248 {
00249 ROS_INFO(GetErrorDescription(-79).c_str());
00250 i_error_code = -79;
00251 b_ret = false;
00252 this->b_motor_error = true;
00253 this->b_right_motor_error = true;
00254 }
00255
00256 if(!b_ret)
00257 {
00258 im_msgs::SetRGB srv;
00259
00260 srv.request.times = -1;
00261 srv.request.mode = 8;
00262 srv.request.frequency = -1;
00263 srv.request.color = 0;
00264
00265 if(this->client.call(srv) == 0)
00266 {
00267 ROS_INFO(GetErrorDescription(-77).c_str());
00268 i_error_code = -77;
00269 }
00270
00271 this->Disable();
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292 return b_ret;
00293 }
00294
00295 void IMDRIVER::ProduceDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
00296 {
00297 if(i_error_code < 0)
00298 {
00299 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, GetErrorDescription(i_error_code).c_str());
00300 i_error_code = 0;
00301 }
00302 else
00303 {
00304 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Motors are OK!");
00305 }
00306
00307 stat.add("Right Motor Voltage", this->f_right_motor_voltage);
00308 stat.add("Left Motor Voltage", this->f_left_motor_voltage);
00309 }
00310
00311 bool IMDRIVER::CheckTimeout()
00312 {
00313 double dt;
00314
00315 dt = (ros::Time::now() - this->curr_vel_time).toSec();
00316
00317 if(dt > this->d_timeout)
00318 {
00319 ROS_INFO(GetErrorDescription(-80).c_str());
00320 i_error_code = -80;
00321 this->ApplyVel(0.0, 0.0);
00322 b_timeout_err = true;
00323 }
00324 else if(dt < 0)
00325 {
00326 ROS_INFO(GetErrorDescription(-81).c_str());
00327 i_error_code = -81;
00328 this->ApplyVel(0.0, 0.0);
00329 b_timeout_err = true;
00330 }
00331 else
00332 {
00333 b_timeout_err = false;
00334 }
00335
00336 return this->b_timeout_err;
00337 }
00338
00339 void IMDRIVER::CallbackWheelVel(const im_msgs::WheelVel::ConstPtr & msg)
00340 {
00341 float f_left_wheel_velocity = msg->left_vel;
00342 float f_right_wheel_velocity = msg->right_vel;
00343 this->curr_vel_time = msg->header.stamp;
00344
00345
00346 this->UpdateParams();
00347
00348
00349 this->ApplyVel(f_left_wheel_velocity, f_right_wheel_velocity);
00350 }
00351
00352 void CallbackReconfigure(evarobot_driver::ParamsConfig &config, uint32_t level)
00353 {
00354 b_is_received_params = true;
00355
00356 g_d_max_lin = config.maxLinearVel;
00357 g_d_max_ang = config.maxAngularVel;
00358 g_d_wheel_separation = config.wheelSeparation;
00359 g_d_wheel_diameter = config.wheelDiameter;
00360
00361 }
00362
00363 int main(int argc, char **argv)
00364 {
00365 unsigned char u_c_spi_mode;
00366
00367 ros::init(argc, argv, "/evarobot_driver");
00368 ros::NodeHandle n;
00369
00370 string str_driver_path;
00371
00372 double d_max_lin_vel;
00373 double d_max_ang_vel;
00374
00375 double d_wheel_diameter;
00376 double d_wheel_separation;
00377
00378 double d_frequency;
00379 double d_duty;
00380 double d_limit_voltage;
00381
00382 double d_timeout;
00383
00384 int i_counts;
00385 int i_mode;
00386 int i_m1_in1, i_m1_in2, i_m1_en;
00387 int i_m2_in1, i_m2_in2, i_m2_en;
00388
00389 int i_spi_mode, i_spi_speed, i_spi_bits, i_adc_bits;
00390
00391
00392 n.param<string>("evarobot_driver/driverPath", str_driver_path, "/dev/spidev0.1");
00393 n.param("evarobot_driver/spiMode", i_spi_mode, 0);
00394 n.param("evarobot_driver/spiSpeed", i_spi_speed, 1000000);
00395 n.param("evarobot_driver/spiBits", i_spi_bits, 8);
00396 n.param("evarobot_driver/adcBits", i_adc_bits, 12);
00397
00398
00399 n.param<int>("evarobot_driver/M1_IN1", i_m1_in1, 1);
00400 n.param<int>("evarobot_driver/M1_IN2", i_m1_in2, 12);
00401 n.param<int>("evarobot_driver/M1_EN", i_m1_en, 5);
00402
00403
00404 n.param<int>("evarobot_driver/M2_IN1", i_m2_in1, 0);
00405 n.param<int>("evarobot_driver/M2_IN2", i_m2_in2, 19);
00406 n.param<int>("evarobot_driver/M2_EN", i_m2_en, 6);
00407
00408 n.param<double>("evarobot_driver/limitVoltage", d_limit_voltage, 0.63);
00409 n.param<double>("evarobot_driver/timeout", d_timeout, 0.5);
00410
00411 if(!n.getParam("evarobot_driver/maxLinearVel", d_max_lin_vel))
00412 {
00413 ROS_INFO(GetErrorDescription(-82).c_str());
00414 i_error_code = -82;
00415 }
00416
00417 if(!n.getParam("evarobot_driver/maxAngularVel", d_max_ang_vel))
00418 {
00419 ROS_INFO(GetErrorDescription(-83).c_str());
00420 i_error_code = -83;
00421 }
00422
00423 if(!n.getParam("evarobot_driver/wheelSeparation", d_wheel_separation))
00424 {
00425 ROS_INFO(GetErrorDescription(-84).c_str());
00426 i_error_code = -84;
00427 }
00428
00429 if(!n.getParam("evarobot_driver/wheelDiameter", d_wheel_diameter))
00430 {
00431 ROS_INFO(GetErrorDescription(-85).c_str());
00432 i_error_code = -85;
00433 }
00434
00435 if(!n.getParam("evarobot_driver/pwmFrequency", d_frequency))
00436 {
00437 ROS_INFO(GetErrorDescription(-86).c_str());
00438 i_error_code = -86;
00439 }
00440
00441 if(!n.getParam("evarobot_driver/pwmDuty", d_duty))
00442 {
00443 ROS_INFO(GetErrorDescription(-87).c_str());
00444 i_error_code = -87;
00445 }
00446
00447 if(!n.getParam("evarobot_driver/pwmCounts", i_counts))
00448 {
00449 ROS_INFO(GetErrorDescription(-88).c_str());
00450 i_error_code = -88;
00451 }
00452
00453 if(!n.getParam("evarobot_driver/pwmMode", i_mode))
00454 {
00455 ROS_INFO(GetErrorDescription(-91).c_str());
00456 i_error_code = -91;
00457 }
00458
00459
00460 if(i_mode != IMPWM::PWMMODE && i_mode != IMPWM::MSMODE)
00461 {
00462 ROS_INFO(GetErrorDescription(-89).c_str());
00463 i_error_code = -89;
00464 }
00465
00466
00467 dynamic_reconfigure::Server<evarobot_driver::ParamsConfig> srv;
00468 dynamic_reconfigure::Server<evarobot_driver::ParamsConfig>::CallbackType f;
00469 f = boost::bind(&CallbackReconfigure, _1, _2);
00470 srv.setCallback(f);
00472
00473 switch(i_spi_mode)
00474 {
00475 case 0:
00476 {
00477 u_c_spi_mode = SPI_MODE_0;
00478 break;
00479 }
00480
00481 case 1:
00482 {
00483 u_c_spi_mode = SPI_MODE_1;
00484 break;
00485 }
00486
00487 case 2:
00488 {
00489 u_c_spi_mode = SPI_MODE_2;
00490 break;
00491 }
00492
00493 case 3:
00494 {
00495 u_c_spi_mode = SPI_MODE_3;
00496 break;
00497 }
00498
00499 default:
00500 {
00501 ROS_INFO(GetErrorDescription(-90).c_str());
00502 i_error_code = -90;
00503 }
00504 }
00505
00506 IMSPI * p_im_spi;
00507 IMADC * p_im_adc;
00508 boost::shared_ptr<IMGPIO> gpio_m1_in[2];
00509 boost::shared_ptr<IMGPIO> gpio_m2_in[2];
00510 IMGPIO * gpio_m1_en;
00511 IMGPIO * gpio_m2_en;
00512
00513 try {
00514
00515 p_im_spi = new IMSPI(str_driver_path, u_c_spi_mode, i_spi_speed, i_spi_bits);
00516 p_im_adc = new IMADC(p_im_spi, i_adc_bits);
00517 } catch(int e) {
00518 ROS_INFO(GetErrorDescription(e).c_str());
00519 i_error_code = e;
00520 return 0;
00521 }
00522
00523 try {
00524 stringstream ss1, ss2;
00525
00526 ss1 << i_m1_in1;
00527 ss2 << i_m1_in2;
00528
00529 gpio_m1_in[0] = boost::shared_ptr< IMGPIO >( new IMGPIO(ss1.str()) );
00530 gpio_m1_in[1] = boost::shared_ptr< IMGPIO >( new IMGPIO(ss2.str()) );
00531
00532 ss1.str("");
00533 ss2.str("");
00534 ss1 << i_m2_in1;
00535 ss2 << i_m2_in2;
00536
00537 gpio_m2_in[0] = boost::shared_ptr< IMGPIO >( new IMGPIO(ss1.str()) );
00538 gpio_m2_in[1] = boost::shared_ptr< IMGPIO >( new IMGPIO(ss2.str()) );
00539
00540 ss1.str("");
00541 ss2.str("");
00542 ss1 << i_m1_en;
00543 ss2 << i_m2_en;
00544
00545 gpio_m1_en = new IMGPIO(ss1.str());
00546 gpio_m2_en = new IMGPIO(ss2.str());
00547 } catch(int e) {
00548 ROS_INFO(GetErrorDescription(e).c_str());
00549 i_error_code = e;
00550 return 0;
00551 }
00552
00553 ros::ServiceClient client = n.serviceClient<im_msgs::SetRGB>("evarobot_rgb/SetRGB");
00554
00555 IMDRIVER imdriver(d_limit_voltage, (float)d_max_lin_vel, (float)d_max_ang_vel,
00556 (float)d_wheel_separation, (float)d_wheel_diameter,
00557 d_frequency, i_counts, d_duty, i_mode,
00558 gpio_m1_in, gpio_m2_in, gpio_m1_en, gpio_m2_en, p_im_adc, client, d_timeout);
00559
00560 ros::Subscriber sub = n.subscribe("cntr_wheel_vel", 2, &IMDRIVER::CallbackWheelVel, &imdriver);
00561 ros::Publisher pub = n.advertise<im_msgs::Voltage>("motor_voltages", 1);
00562
00563
00564 diagnostic_updater::Updater updater;
00565 updater.setHardwareID("None");
00566 updater.add("MotorVoltages", &imdriver, &IMDRIVER::ProduceDiagnostics);
00567
00568 if(sub.getNumPublishers() < 1)
00569 {
00570 ROS_WARN("No appropriate subscriber.");
00571 }
00572
00573
00574 ros::Rate loop_rate(10.0);
00575
00576 while(ros::ok())
00577 {
00578 imdriver.CheckMotorCurrent();
00579 imdriver.CheckTimeout();
00580 pub.publish(imdriver.GetMotorVoltage());
00581
00582 updater.update();
00583 ros::spinOnce();
00584 loop_rate.sleep();
00585 }
00586
00587 return 0;
00588 }