00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #include "Robots/LoBot/io/LoRCCar.H"
00046 #include "Robots/LoBot/control/LoTurnArbiter.H"
00047 #include "Robots/LoBot/config/LoConfigHelpers.H"
00048 #include "Robots/LoBot/misc/LoExcept.H"
00049 #include "Robots/LoBot/util/LoMath.H"
00050 #include "Robots/LoBot/util/LoTime.H"
00051
00052
00053 #include "Util/log.H"
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 namespace lobot {
00077
00078
00079
00080 RCCar::RCCar(const ModelManager& mgr)
00081 : base(mgr, Params::device(), Params::baud_rate()),
00082 m_speed_pid(Params::speed_gains()),
00083 m_rpm_filter(Params::rpm_filter_size())
00084 {}
00085
00086
00087
00088 void RCCar::drive(float speed, int pwm)
00089 {
00090 if (Params::bypass_rpm_sensor())
00091 drive(pwm) ;
00092 else
00093 drive(speed) ;
00094 }
00095
00096 void RCCar::drive(float speed)
00097 {
00098 if (is_zero(speed))
00099 {
00100 send_propeller(STOP) ;
00101 m_speed_pid.reset() ;
00102 m_rpm_filter.reset() ;
00103 return ;
00104 }
00105
00106 float speed_cmd = m_speed_pid.cmd(speed - current_speed()) ;
00107 float rpm_cmd = speed_cmd/Params::rpm_speed_factor() ;
00108 int pwm = sensors().motor_pwm() + round(rpm_cmd * Params::rpm_pwm_factor());
00109 drive(pwm) ;
00110 }
00111
00112 void RCCar::drive(int pwm)
00113 {
00114 if (pwm < 0)
00115 send_propeller(REVERSE, clamp(-pwm, 10, 100) * 127/100) ;
00116 else if (pwm > 0)
00117 send_propeller(FORWARD, clamp( pwm, 10, 100) * 127/100) ;
00118 else
00119 send_propeller(STOP) ;
00120 }
00121
00122 void RCCar::turn(float direction)
00123 {
00124 if (direction < 0)
00125 send_propeller(RIGHT, round(-direction * Params::steering_pwm_factor()));
00126 else if (direction > 0)
00127 send_propeller(LEFT, round( direction * Params::steering_pwm_factor()));
00128 else
00129 send_propeller(STRAIGHT) ;
00130 }
00131
00132 void RCCar::spin(float)
00133 {
00134 throw motor_error(IN_PLACE_TURNS_NOT_SUPPORTED) ;
00135 }
00136
00137 void RCCar::off()
00138 {
00139
00140 send_propeller(OFF) ;
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 update() ;
00155 }
00156
00157
00158
00159 bool RCCar::update_sensors()
00160 {
00161 int M = ((recv_propeller(GET_MOTOR_DIR) == REVERSE) ? -1 : +1)
00162 * recv_propeller(GET_MOTOR_PWM) * 100/127 ;
00163 int S = ((recv_propeller(GET_SERVO_DIR) == RIGHT) ? -1 : +1)
00164 * recv_propeller(GET_SERVO_PWM) ;
00165 float R = recv_propeller(GET_RPM, 4)/1000.0f ;
00166
00167 motor_pwm(M) ;
00168 servo_pwm(S) ;
00169 rpm(R) ;
00170 m_rpm_filter.add(R) ;
00171 speed(sign(M) * m_rpm_filter.value() * Params::rpm_speed_factor()) ;
00172 heading(round(S/Params::steering_pwm_factor())) ;
00173 time_stamp(current_time()) ;
00174
00175 #ifndef LOBOT_MOTOR_NO_PRINT
00176 LERROR("drive = [%4d %8.2f %8.2f %7.2f]; turn = [%4d %6.1f]",
00177 M, R, m_rpm_filter.value(), current_speed(), S, current_heading()) ;
00178 #endif
00179 return true ;
00180 }
00181
00182 bool RCCar::stopped() const
00183 {
00184 return sensors().motor_pwm() == 0 ;
00185 }
00186
00187
00188
00189 #ifdef LOBOT_MOTOR_DEVMODE
00190
00191
00192 class fake_propeller {
00193 int motor_dir, motor_pwm ;
00194 int servo_dir, servo_pwm ;
00195
00196 enum {
00197 FORWARD_CMD = 100,
00198 REVERSE_CMD = 101,
00199 STOP_CMD = 102,
00200
00201 LEFT_CMD = 110,
00202 RIGHT_CMD = 111,
00203 STRAIGHT_CMD = 112,
00204
00205 OFF_CMD = 120,
00206
00207 GET_MOTOR_DIR = 130,
00208 GET_MOTOR_PWM = 131,
00209 GET_SERVO_DIR = 132,
00210 GET_SERVO_PWM = 133,
00211 GET_RPM = 134,
00212 } ;
00213
00214 public:
00215 fake_propeller() ;
00216 void send(int cmd) ;
00217 void send(int cmd, int param) ;
00218 int recv(int cmd) ;
00219 } ;
00220
00221 fake_propeller::fake_propeller()
00222 : motor_dir(0), motor_pwm(0),
00223 servo_dir(0), servo_pwm(0)
00224 {}
00225
00226 void fake_propeller::send(int cmd)
00227 {
00228 switch (cmd)
00229 {
00230 case STOP_CMD:
00231 motor_dir = STOP_CMD ;
00232 motor_pwm = 0 ;
00233 break ;
00234 case STRAIGHT_CMD:
00235 servo_dir = STRAIGHT_CMD ;
00236 servo_pwm = 0 ;
00237 break ;
00238 case OFF_CMD:
00239 motor_dir = STOP_CMD ;
00240 motor_pwm = 0 ;
00241 servo_dir = STRAIGHT_CMD ;
00242 servo_pwm = 0 ;
00243 break ;
00244 }
00245 }
00246
00247 void fake_propeller::send(int cmd, int param)
00248 {
00249 switch (cmd)
00250 {
00251 case FORWARD_CMD:
00252 motor_dir = FORWARD_CMD ;
00253 motor_pwm = clamp(param, 0, 127) ;
00254 break ;
00255 case REVERSE_CMD:
00256 motor_dir = REVERSE_CMD ;
00257 motor_pwm = clamp(param, 0, 127) ;
00258 break ;
00259 case LEFT_CMD:
00260 servo_dir = LEFT_CMD ;
00261 servo_pwm = clamp(param, 0, 100) ;
00262 break ;
00263 case RIGHT_CMD:
00264 servo_dir = RIGHT_CMD ;
00265 servo_pwm = clamp(param, 0, 100) ;
00266 break ;
00267 }
00268 }
00269
00270 int fake_propeller::recv(int cmd)
00271 {
00272 switch (cmd)
00273 {
00274 case GET_MOTOR_DIR:
00275 return motor_dir ;
00276 case GET_MOTOR_PWM:
00277 return motor_pwm ;
00278 case GET_SERVO_DIR:
00279 return servo_dir ;
00280 case GET_SERVO_PWM:
00281 return servo_pwm ;
00282 case GET_RPM:
00283 return 0 ;
00284 }
00285 return -1 ;
00286 }
00287
00288 static fake_propeller propeller ;
00289
00290 void RCCar::send_propeller(int cmd)
00291 {
00292 propeller.send(cmd) ;
00293 }
00294
00295 void RCCar::send_propeller(int cmd, int param)
00296 {
00297 propeller.send(cmd, param) ;
00298 }
00299
00300 int RCCar::recv_propeller(int cmd, int)
00301 {
00302 return propeller.recv(cmd) ;
00303 }
00304
00305 #else // the real Propeller interface
00306
00307 void RCCar::send_propeller(int cmd)
00308 {
00309 char buf[] = {cmd} ;
00310 m_serial.write(buf, sizeof(buf)) ;
00311 }
00312
00313 void RCCar::send_propeller(int cmd, int param)
00314 {
00315 char buf[] = {cmd, param} ;
00316 m_serial.write(buf, sizeof(buf)) ;
00317 }
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 #if __GNUC__ >= 4 && __GNUC_MINOR__ >= 3
00349 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
00350 #endif
00351
00352 int RCCar::recv_propeller(int cmd, int n)
00353 {
00354 send_propeller(cmd) ;
00355
00356 const int MAX_TRIES = 10 ;
00357 int tries = 0 ;
00358 for(;;)
00359 {
00360 usleep(50000) ;
00361
00362 char buf[n + 1] ;
00363 std::fill_n(buf, n + 1, 0) ;
00364
00365 if (m_serial.read(buf, n) >= n) {
00366 std::reverse(buf, buf + n) ;
00367 return *reinterpret_cast<int*>(buf) ;
00368 }
00369
00370 if (++tries <= MAX_TRIES)
00371 continue ;
00372 throw motor_error(MOTOR_READ_FAILURE) ;
00373 }
00374 return 0 ;
00375 }
00376
00377 #endif // LOBOT_MOTOR_DEVMODE
00378
00379
00380
00381 RCCar::~RCCar(){}
00382
00383
00384
00385
00386 RCCar::Params::Params()
00387 : m_device(robot_conf<std::string>("serial_port", "/dev/ttyUSB0")),
00388 m_baud_rate(clamp(robot_conf("baud_rate", 38400), 50, 115200)),
00389 m_wheel_diameter(clamp(robot_conf("wheel_diameter", 139.70f),
00390 10.0f, 1000.0f)),
00391 m_rpm_speed_factor(3.14159f * m_wheel_diameter/60000),
00392 m_rpm_pwm_factor(clamp(robot_conf("rpm_pwm_factor", 0.3f),
00393 0.001f, 1.0f)),
00394 m_rpm_filter_size(clamp(robot_conf("rpm_filter_size", 10), 1, 100)),
00395 m_bypass_rpm_sensor(robot_conf("bypass_rpm_sensor", false)),
00396 m_speed_gains(get_conf("robot", "speed_gains",
00397 make_triple(1.0f, 0.01f, 0.0f))),
00398 m_steering_pwm_factor(clamp(robot_conf("max_steering_pwm", 75.0f),
00399 50.0f, 90.0f)/TurnArbiter::turn_max())
00400 {}
00401
00402
00403 RCCar::Params::~Params(){}
00404
00405
00406
00407 }
00408
00409
00410
00411
00412
00413
00414