Wiselib
wiselib.testing/external_interface/pc/roomba.h
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines