Wiselib
|
00001 // vim: set noexpandtab ts=4 sw=4: 00002 00003 #ifndef ROOMBA_H 00004 #define ROOMBA_H 00005 00006 #warning "There is a new ROOMBA API under intermediate/robot which is more complete & precise than the one you are using right now!" 00007 00008 // TODO: Remove STL dependencies (substitute with pSTL / template parameter) 00009 // TODO: Subsitute cout with debug facet 00010 00011 #include <list> 00012 00013 #include "external_interface/pc/roomba_angle.h" 00014 #include "external_interface/pc/pc_os.h" 00015 #include "util/delegates/delegate.hpp" 00016 00017 #include <iostream> 00018 00019 namespace wiselib { 00020 00021 namespace { 00022 struct RoombaData { 00023 uint8_t bumps, wall, cliff_left, cliff_front_left, 00024 cliff_front_right, cliff_right, virtual_wall, 00025 wheel_overcurrents, dirt, unused_1, 00026 infrared_omni, buttons; 00027 int16_t distance; 00028 int16_t angle; 00029 uint8_t charging; 00030 uint16_t voltage; 00031 int16_t current; 00032 int8_t temperature; 00033 uint16_t charge, capacity, wall_signal, cliff_left_signal, 00034 cliff_front_left_signal, cliff_front_right_signal, 00035 cliff_right_signal; 00036 uint8_t unused_2, unused_3, unused_4; 00037 uint8_t charging_sources, oi_mode, song_nr, song_playing, 00038 stream_packet_count; 00039 int16_t requested_velocity, requested_radius, requested_right_velocity, 00040 requested_left_velocity; 00041 uint16_t left_encoder_counts, right_encoder_counts; 00042 uint8_t light_bumper; 00043 uint16_t light_bump_left_signal, light_bump_front_left_signal, 00044 light_bump_center_left_signal, 00045 light_bump_center_right_signal, 00046 light_bump_front_right_signal, 00047 light_bump_right_signal; 00048 uint8_t ir_opcode_left, ir_opcode_right; 00049 int16_t left_motor_current, right_motor_current, 00050 main_brush_motor_current, 00051 side_brush_motor_current; 00052 uint8_t stasis; 00053 } __attribute__ ((packed)); // struct RoombaData 00054 } // anonymous namespace 00055 00062 template<typename OsModel_P, 00063 typename ComUartModel_P, 00064 typename Math_P, 00065 typename OsModel_P::size_t MAX_RECEIVERS = 16> 00066 class RoombaModel { 00067 public: 00068 typedef RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS> self_type; 00069 typedef self_type* self_pointer_t; 00070 00071 typedef Math_P Math; 00072 typedef ComUartModel_P ComUartModel; 00073 typedef OsModel_P OsModel; 00074 00075 typedef delegate0<void> new_data_delegate_t; 00076 typedef vector_static<OsModel, new_data_delegate_t, MAX_RECEIVERS> new_data_delegates_t; 00077 00078 typedef RoombaAngle<Math> angle_t; 00079 typedef RoombaData value_t; 00080 typedef int16_t angular_velocity_t; 00081 typedef int16_t distance_t; 00082 typedef int16_t velocity_t; 00083 typedef typename OsModel::size_t size_t; 00084 typedef uint8_t block_data_t; 00085 00086 enum DataTypes { 00087 WALL = 0x01, 00088 POSITION = 0x02, 00089 BATTERY_AND_TEMPERATURE = 0x04, 00090 LIGHT_BUMPS = 0x08, 00091 00092 ALL = 0x0f, 00093 }; 00094 00095 enum { 00096 READY = 0, NO_VALUE = 1, INACTIVE = 2 00097 }; 00098 00099 RoombaModel(PCOs& os) { } 00100 00101 void init(ComUartModel_P& uart, int data_types); 00102 void init(); 00103 void destruct(); 00104 00105 // You should not manually call any method below 00106 // this comment, use RoombaSomething interfaces instead! 00107 00108 inline void data_types(); 00109 00110 inline void move(velocity_t speed); 00111 inline void turn(angular_velocity_t speed); 00112 inline void stop(); 00113 00115 inline value_t& operator()(); 00116 inline int state(); 00117 inline angle_t angle(); 00118 inline distance_t distance(); 00119 inline bool wall(); 00120 00121 template<typename T, void (T::*TMethod)(void)> 00122 int reg_new_data_callback(T* obj); 00123 int unreg_new_data_callback(typename OsModel::size_t); 00124 void notify_new_data_receivers(); 00125 00126 typename OsModel::size_t packets(); 00127 typename OsModel::size_t errors(); 00128 00129 private: 00130 typedef int16_t rotation_t; 00131 00132 enum Command { 00133 CMD_START = 0x80, CMD_BAUD, CMD_CONTROL, CMD_SAFE, CMD_FULL, CMD_POWER, 00134 CMD_SPOT, CMD_CLEAN, CMD_MAX, 00135 CMD_DRIVE, CMD_MOTORS, CMD_LEDS, CMD_SONG, CMD_PLAY, CMD_SENSORS, 00136 CMD_DOCK, 00137 CMD_PWM_MOTORS = 0x90, CMD_DRIVE_DIRECT, CMD_DRIVE_PWM, 00138 CMD_STREAM = 0x94, CMD_QUERY_LIST, CMD_ENABLE_STREAM, 00139 CMD_SCHEDULE_LEDS = 0xa2, CMD_BUTTONS = 0xa5, 00140 CMD_SCHEDULE = 0xa7, CMD_SET_TIME 00141 }; 00142 00143 enum Rotation { 00144 ROTATE_NONE = 0x8000, 00145 ROTATE_CW = 0xffff, ROTATE_CCW = 0x0001 00146 }; 00147 00148 int16_t get_packet_offset(uint8_t); 00149 int16_t get_packet_length(uint8_t); 00150 00151 void send(uint8_t); 00152 void read(typename ComUartModel::size_t, typename ComUartModel::block_data_t*); 00153 void execute_motion(velocity_t speed, rotation_t rotation); 00154 00155 ComUartModel_P* uart_; 00156 int data_types_; 00157 RoombaData roomba_data_; 00158 new_data_delegates_t callbacks_; 00159 00160 typename OsModel::size_t packets_; 00161 typename OsModel::size_t errors_; 00162 }; 00163 00164 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00165 void 00166 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00167 init(ComUartModel_P& uart, int data_types) { 00168 packets_ = 0; 00169 errors_ = 0; 00170 assert(data_types != 0); 00171 uart_ = &uart; 00172 data_types_ = data_types; 00173 // uart_->set_config(19200, 8, 'N', 1) 00174 init(); 00175 } 00176 00177 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00178 void 00179 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00180 init() { 00181 memset(&roomba_data_, 0, sizeof(roomba_data_)); 00182 00183 uart_->template reg_read_callback<self_type, &self_type::read>(this); 00184 00185 send(CMD_START); 00186 send(CMD_SAFE); 00187 00188 // Enable data stream 00189 std::list<int> data_groups; 00190 if(data_types_ & WALL) { data_groups.push_back(7); } 00191 if(data_types_ & POSITION) { 00192 data_groups.push_back(19); 00193 data_groups.push_back(20); 00194 } 00195 if(data_types_ & BATTERY_AND_TEMPERATURE) { data_groups.push_back(3); } 00196 if(data_types_ & LIGHT_BUMPS) { data_groups.push_back(106); } 00197 00198 send(CMD_STREAM); 00199 send(data_groups.size()); 00200 for(std::list<int>::iterator iter = data_groups.begin(); iter != data_groups.end(); ++iter) { 00201 send(*iter); 00202 } 00203 00204 send(CMD_ENABLE_STREAM); 00205 send(1); 00206 } // init() 00207 00208 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00209 void 00210 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00211 destruct() { 00212 //std::cout << "RoombaModel::destruct()\n"; 00213 00214 send(CMD_ENABLE_STREAM); 00215 send(0); 00216 uart_->unreg_read_callback(); 00217 stop(); 00218 send(CMD_POWER); 00219 } 00220 00221 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00222 void 00223 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00224 data_types() { 00225 return data_types_; 00226 } 00227 00228 00229 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00230 void 00231 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00232 move(RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>::velocity_t speed) { 00233 execute_motion(speed, ROTATE_NONE); 00234 } 00235 00236 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00237 void 00238 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00239 turn(RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>::angular_velocity_t r_speed) { 00240 //std::cout << "turning with " << r_speed << "\n"; 00241 if(r_speed < 0) { 00242 execute_motion(-r_speed, ROTATE_CW); 00243 } 00244 else { 00245 execute_motion(r_speed, ROTATE_CCW); 00246 } 00247 } 00248 00249 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00250 void 00251 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00252 stop() { 00253 execute_motion(0, ROTATE_NONE); 00254 } 00255 00256 00257 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00258 typename RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>::value_t& 00259 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00260 operator()() { 00261 return roomba_data_; 00262 } 00263 00264 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00265 int 00266 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00267 state() { 00268 return READY; 00269 } 00270 00271 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00272 typename RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>::angle_t 00273 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00274 angle() { 00275 angle_t angle; 00276 angle.set_roomba_units_(roomba_data_.angle); 00277 //if(roomba_data_.angle != 0) 00278 // std::cout << "roomba angle=" << roomba_data_.angle << " -> " << angle << "\n"; 00279 return angle; 00280 } 00281 00282 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00283 typename RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>::distance_t 00284 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00285 distance() { 00286 return roomba_data_.distance; 00287 } 00288 00289 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00290 bool 00291 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00292 wall() { 00293 return roomba_data_.wall; 00294 } 00295 00296 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00297 template<typename T, void (T::*TMethod)(void)> 00298 int 00299 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00300 reg_new_data_callback(T* obj) { 00301 if(callbacks_.empty()) { 00302 callbacks_.assign(MAX_RECEIVERS, new_data_delegate_t()); 00303 } 00304 00305 for(typename OsModel::size_t i = 0; i < callbacks_.size(); ++i) { 00306 if(callbacks_[i] == new_data_delegate_t()) { 00307 callbacks_[i] = new_data_delegate_t::template from_method<T, TMethod>(obj); 00308 return i; 00309 } 00310 } 00311 return -1; 00312 } 00313 00314 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00315 int 00316 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00317 unreg_new_data_callback(typename OsModel_P::size_t idx) { 00318 callbacks_[idx] = new_data_delegate_t(); 00319 return OsModel::SUCCESS; 00320 } 00321 00322 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00323 void 00324 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00325 notify_new_data_receivers() { 00326 typedef typename new_data_delegates_t::iterator iter_t; 00327 00328 for(iter_t iter = callbacks_.begin(); iter != callbacks_.end(); ++iter) { 00329 if(*iter != new_data_delegate_t()) { 00330 (*iter)(); 00331 } 00332 } 00333 } 00334 00335 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00336 int16_t 00337 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00338 get_packet_offset(uint8_t packet_type) { 00339 switch(packet_type) { 00340 case 0: 00341 case 1: 00342 case 6: 00343 case 7: 00344 case 100: return 0; 00345 case 2: return 10; 00346 case 3: return 16; 00347 case 4: return 26; 00348 case 5: return 40; 00349 case 8: return 1; 00350 case 19: return 12; 00351 case 20: return 14; 00352 case 101: return 52; 00353 case 106: return 57; 00354 default: 00355 return -1; 00356 //assert(false && "Unknown packet type"); 00357 } 00358 } // get_packet_offset 00359 00360 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00361 int16_t 00362 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00363 get_packet_length(uint8_t packet_type) { 00364 switch(packet_type) { 00365 case 1: 00366 case 3: return 10; 00367 case 2: return 6; 00368 case 4: return 14; 00369 case 5: return 12; 00370 case 7: 00371 case 8: return 1; 00372 case 19: 00373 case 20: return 2; 00374 case 100: return 80; 00375 case 106: return 12; 00376 default: 00377 //std::cout << "?"; 00378 //std::cout.flush(); 00379 return -1; 00380 //assert(false && "Unknown packet type"); 00381 } 00382 } // get_packet_length 00383 00384 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00385 void 00386 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00387 send(uint8_t byte) { 00388 //std::cout << "sending: " << (unsigned)byte << "\n"; 00389 //std::cout.flush(); 00390 00391 uart_->write(1, reinterpret_cast<char*>(&byte)); 00392 } 00393 00394 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00395 typename OsModel_P::size_t RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>::packets() { return packets_; } 00396 00397 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00398 typename OsModel_P::size_t RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>::errors() { return errors_; } 00399 00400 00401 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00402 void 00403 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00404 read( 00405 typename RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>::ComUartModel::size_t size, 00406 typename RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>::ComUartModel::block_data_t* data 00407 ) { 00408 enum { STATE_HEADER, STATE_LEN, STATE_TYPE, STATE_PAYLOAD, STATE_CHECKSUM }; 00409 typedef typename ComUartModel::size_t size_t; 00410 00411 static uint16_t state = STATE_HEADER, 00412 pos = 0, bytes_read = 0, len = 0; 00413 static int16_t packet_offset = 0, packet_length = 0; 00414 static uint8_t check = 0, packet_type = 0; 00415 00416 /*std::cout << "."; 00417 std::cout.flush();*/ 00418 00419 for(size_t i=0; i<size; i++) { 00420 block_data_t d = data[i]; 00421 00422 switch(state) { 00423 case STATE_HEADER: 00424 if(d == 19) { 00425 state = STATE_LEN; 00426 check = d; 00427 } 00428 break; 00429 00430 case STATE_LEN: 00431 check += d; 00432 len = d; 00433 bytes_read = 0; 00434 state = STATE_TYPE; 00435 break; 00436 00437 case STATE_TYPE: 00438 // Do byte-swapping for previous packet if necessary 00439 if(bytes_read) { 00440 if(packet_type >= 7 && packet_type <= 58 && packet_length == 2) { 00441 uint8_t *buf = reinterpret_cast<uint8_t*>(&roomba_data_) + packet_offset; 00442 if(OsModel::endianness == wiselib::WISELIB_LITTLE_ENDIAN) { 00443 uint8_t tmp = buf[0]; 00444 buf[0] = buf[1]; 00445 buf[1] = tmp; 00446 } 00447 } 00448 } 00449 00450 check += d; 00451 ++bytes_read; 00452 packet_type = d; 00453 packet_offset = get_packet_offset(packet_type); 00454 packet_length = get_packet_length(packet_type); 00455 if(packet_offset < 0 || packet_length < 0 || 00456 static_cast<size_t>(packet_offset + packet_length) >= sizeof(roomba_data_)) { 00457 state = STATE_HEADER; 00458 } 00459 else { 00460 state = STATE_PAYLOAD; 00461 pos = packet_offset; 00462 } 00463 break; 00464 00465 case STATE_PAYLOAD: 00466 assert(pos < sizeof(roomba_data_)); 00467 (reinterpret_cast<uint8_t*>(&roomba_data_))[pos] = d; 00468 check += d; 00469 pos++; 00470 bytes_read++; 00471 00472 if(pos == (packet_offset + packet_length)) { 00473 if(bytes_read == len) { state = STATE_CHECKSUM; } 00474 else { state = STATE_TYPE; } 00475 } 00476 break; 00477 00478 case STATE_CHECKSUM: 00479 // Do byte-swapping for previous packet if necessary 00480 if(bytes_read) { 00481 if(packet_type >= 7 && packet_type <= 58 && packet_length == 2) { 00482 uint8_t *buf = reinterpret_cast<uint8_t*>(&roomba_data_) + packet_offset; 00483 if(OsModel::endianness == wiselib::WISELIB_LITTLE_ENDIAN) { 00484 uint8_t tmp = buf[0]; 00485 buf[0] = buf[1]; 00486 buf[1] = tmp; 00487 } 00488 } 00489 } 00490 00491 packets_++; 00492 check += d; 00493 if(check == 0) { 00494 //std::cout << "."; 00495 //std::cout.flush(); 00496 notify_new_data_receivers(); 00497 } 00498 else { 00499 errors_++; 00500 // checksum failure for uart packet 00501 std::cout << "!"; 00502 std::cout.flush(); 00503 } 00504 state = STATE_HEADER; 00505 break; 00506 } 00507 } // for 00508 00509 } // read() 00510 00511 template<typename OsModel_P, typename ComUartModel_P, typename Math_P, typename OsModel_P::size_t MAX_RECEIVERS> 00512 void 00513 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>:: 00514 execute_motion( 00515 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>::velocity_t speed, 00516 RoombaModel<OsModel_P, ComUartModel_P, Math_P, MAX_RECEIVERS>::rotation_t rotation 00517 ) { 00518 send(CMD_DRIVE); 00519 send(speed >> 8); send(speed & 0xff); 00520 send(rotation >> 8); send(rotation & 0xff); 00521 } 00522 00523 00524 } // ns wiselib 00525 00526 #endif // ROOMBA_H 00527