Crazyflie.h
Go to the documentation of this file.
00001 #pragma once
00002 
00003 #include <cstring>
00004 #include <sstream>
00005 
00006 #include "Crazyradio.h"
00007 #include "crtp.h"
00008 #include <list>
00009 #include <set>
00010 #include <map>
00011 #include <iostream>
00012 #include <chrono>
00013 
00014 class Crazyflie
00015 {
00016 public:
00017   enum ParamType {
00018     ParamTypeUint8  = 0x00 | (0x00<<2) | (0x01<<3),
00019     ParamTypeInt8   = 0x00 | (0x00<<2) | (0x00<<3),
00020     ParamTypeUint16 = 0x01 | (0x00<<2) | (0x01<<3),
00021     ParamTypeInt16  = 0x01 | (0x00<<2) | (0x00<<3),
00022     ParamTypeUint32 = 0x02 | (0x00<<2) | (0x01<<3),
00023     ParamTypeInt32  = 0x02 | (0x00<<2) | (0x00<<3),
00024     ParamTypeFloat  = 0x02 | (0x01<<2) | (0x00<<3),
00025   };
00026 
00027   struct ParamTocEntry {
00028     uint8_t id;
00029     ParamType type;
00030     bool readonly;
00031     // ParamLength length;
00032     // ParamType type;
00033     // ParamSign sign;
00034     // bool readonly;
00035     // ParamGroup paramGroup;
00036     std::string group;
00037     std::string name;
00038   };
00039 
00040   union ParamValue{
00041     uint8_t valueUint8;
00042     int8_t valueInt8;
00043     uint16_t valueUint16;
00044     int16_t valueInt16;
00045     uint32_t valueUint32;
00046     int32_t valueInt32;
00047     float valueFloat;
00048   };
00049 
00050   enum LogType {
00051     LogTypeUint8  = 1,
00052     LogTypeUint16 = 2,
00053     LogTypeUint32 = 3,
00054     LogTypeInt8   = 4,
00055     LogTypeInt16  = 5,
00056     LogTypeInt32  = 6,
00057     LogTypeFloat  = 7,
00058     LogTypeFP16   = 8,
00059   };
00060 
00061   struct LogTocEntry {
00062     uint8_t id;
00063     LogType type;
00064     std::string group;
00065     std::string name;
00066   };
00067 
00068   enum BootloaderTarget {
00069     TargetSTM32 = 0xFF,
00070     TargetNRF51 = 0xFE,
00071   };
00072 
00073 public:
00074   Crazyflie(
00075     const std::string& link_uri);
00076 
00077   void logReset();
00078 
00079   void sendSetpoint(
00080     float roll,
00081     float pitch,
00082     float yawrate,
00083     uint16_t thrust);
00084 
00085   void sendExternalPositionUpdate(
00086     float x,
00087     float y,
00088     float z);
00089 
00090   void sendPing();
00091 
00092   void reboot();
00093   // returns new address
00094   uint64_t rebootToBootloader();
00095   void sysoff();
00096   void trySysOff();
00097   void alloff();
00098   void syson();
00099   float vbat();
00100 
00101   void writeFlash(
00102     BootloaderTarget target,
00103     const std::vector<uint8_t>& data);
00104   void readFlash(
00105     BootloaderTarget target,
00106     size_t size,
00107     std::vector<uint8_t>& data);
00108   void requestLogToc();
00109 
00110   void requestParamToc();
00111 
00112   std::vector<ParamTocEntry>::const_iterator paramsBegin() const {
00113     return m_paramTocEntries.begin();
00114   }
00115   std::vector<ParamTocEntry>::const_iterator paramsEnd() const {
00116     return m_paramTocEntries.end();
00117   }
00118 
00119   std::vector<LogTocEntry>::const_iterator logVariablesBegin() const {
00120     return m_logTocEntries.begin();
00121   }
00122   std::vector<LogTocEntry>::const_iterator logVariablesEnd() const {
00123     return m_logTocEntries.end();
00124   }
00125 
00126   template<class T>
00127   void setParam(uint8_t id, const T& value) {
00128     ParamValue v;
00129     memcpy(&v, &value, sizeof(value));
00130     setParam(id, v);
00131   }
00132 
00133   template<class T>
00134   T getParam(uint8_t id) const {
00135     ParamValue v = getParam(id);
00136     return *(reinterpret_cast<T*>(&v));
00137   }
00138 
00139   const ParamTocEntry* getParamTocEntry(
00140     const std::string& group,
00141     const std::string& name) const;
00142 
00143   void setEmptyAckCallback(
00144     std::function<void(const crtpPlatformRSSIAck*)> cb) {
00145     m_emptyAckCallback = cb;
00146   }
00147 
00148   void setLinkQualityCallback(
00149     std::function<void(float)> cb) {
00150     m_linkQualityCallback = cb;
00151   }
00152 
00153   void setConsoleCallback(
00154     std::function<void(const char*)> cb) {
00155     m_consoleCallback = cb;
00156   }
00157 
00158   static size_t size(LogType t) {
00159     switch(t) {
00160       case LogTypeUint8:
00161       case LogTypeInt8:
00162         return 1;
00163         break;
00164       case LogTypeUint16:
00165       case LogTypeInt16:
00166       case LogTypeFP16:
00167         return 2;
00168         break;
00169       case LogTypeUint32:
00170       case LogTypeInt32:
00171       case LogTypeFloat:
00172       return 4;
00173       break;
00174     }
00175   }
00176 
00183   std::vector<Crazyradio::Ack> retrieveGenericPackets() {
00184     std::vector<Crazyradio::Ack> packets = m_generic_packets;
00185     m_generic_packets.clear();
00186     return packets;
00187   }
00188 
00193   void queueOutgoingPacket(const crtpPacket_t& packet) {
00194     m_outgoing_packets.push_back(packet);
00195   }
00196 
00197   void transmitPackets();
00198 
00199 private:
00200   void sendPacket(
00201     const uint8_t* data,
00202     uint32_t length,
00203     Crazyradio::Ack& result);
00204 
00205   bool sendPacket(
00206     const uint8_t* data,
00207     uint32_t length);
00208 
00209  void sendPacketOrTimeout(
00210    const uint8_t* data,
00211    uint32_t length,
00212    float timeout = 1.0);
00213 
00214   void handleAck(
00215     const Crazyradio::Ack& result);
00216 
00217   std::vector<Crazyradio::Ack> m_generic_packets;
00218   std::vector<crtpPacket_t> m_outgoing_packets;
00219 
00224   void queueGenericPacket(const Crazyradio::Ack& result) {
00225     m_generic_packets.push_back(result);
00226   }
00227 
00228   void startBatchRequest();
00229 
00230   void addRequest(
00231     const uint8_t* data,
00232     size_t numBytes,
00233     size_t numBytesToMatch);
00234 
00235   template<typename R>
00236   void addRequest(
00237     const R& request,
00238     size_t numBytesToMatch)
00239   {
00240     addRequest(
00241       reinterpret_cast<const uint8_t*>(&request), sizeof(request), numBytesToMatch);
00242   }
00243 
00244   void handleRequests(
00245     float baseTime = 0.5,
00246     float timePerRequest = 0.05);
00247 
00248   void handleBatchAck(
00249     const Crazyradio::Ack& result);
00250 
00251   template<typename R>
00252   const R* getRequestResult(size_t index) const {
00253     return reinterpret_cast<const R*>(m_batchRequests[index].ack.data);
00254   }
00255 
00256 private:
00257   struct logInfo {
00258     uint8_t len;
00259     uint32_t log_crc;
00260     uint8_t log_max_packet;
00261     uint8_t log_max_ops;
00262   };
00263 
00265 
00266   struct paramInfo {
00267     uint8_t len;
00268     uint32_t crc;
00269   };
00270 
00271   // enum ParamLength {
00272   //   ParamLength1Byte  = 0,
00273   //   ParamLength2Bytes = 1,
00274   //   ParamLength3Bytes = 2,
00275   //   ParamLength4Bytes = 3,
00276   // };
00277 
00278   // enum ParamType {
00279   //   ParamTypeInt   = 0,
00280   //   ParamTypeFloat = 1,
00281   // };
00282 
00283   // enum ParamSign {
00284   //   ParamSignSigned   = 0,
00285   //   ParamSignUnsigned = 1,
00286   // };
00287 
00288   // enum ParamGroup {
00289   //   ParamGroupVariable = 0,
00290   //   ParamGroupGroup    = 1,
00291   // };
00292 
00293 
00294 private:
00295   const LogTocEntry* getLogTocEntry(
00296     const std::string& group,
00297     const std::string& name) const;
00298 
00299   uint8_t registerLogBlock(
00300     std::function<void(crtpLogDataResponse*, uint8_t)> cb);
00301 
00302   bool unregisterLogBlock(
00303     uint8_t id);
00304 
00305   void setParam(uint8_t id, const ParamValue& value);
00306   const ParamValue& getParam(uint8_t id) const {
00307     return m_paramValues.at(id);
00308   }
00309 
00310 private:
00311   Crazyradio* m_radio;
00312   ITransport* m_transport;
00313   int m_devId;
00314 
00315   uint8_t m_channel;
00316   uint64_t m_address;
00317   Crazyradio::Datarate m_datarate;
00318 
00319   std::vector<LogTocEntry> m_logTocEntries;
00320   std::map<uint8_t, std::function<void(crtpLogDataResponse*, uint8_t)> > m_logBlockCb;
00321 
00322   std::vector<ParamTocEntry> m_paramTocEntries;
00323   std::map<uint8_t, ParamValue> m_paramValues;
00324 
00325   std::function<void(const crtpPlatformRSSIAck*)> m_emptyAckCallback;
00326   std::function<void(float)> m_linkQualityCallback;
00327   std::function<void(const char*)> m_consoleCallback;
00328 
00329   template<typename T>
00330   friend class LogBlock;
00331   friend class LogBlockGeneric;
00332 
00333   // batch system
00334   struct batchRequest
00335   {
00336     std::vector<uint8_t> request;
00337     size_t numBytesToMatch;
00338     ITransport::Ack ack;
00339     bool finished;
00340   };
00341   std::vector<batchRequest> m_batchRequests;
00342   size_t m_numRequestsFinished;
00343 };
00344 
00345 template<class T>
00346 class LogBlock
00347 {
00348 public:
00349   LogBlock(
00350     Crazyflie* cf,
00351     std::list<std::pair<std::string, std::string> > variables,
00352     std::function<void(uint32_t, T*)>& callback)
00353     : m_cf(cf)
00354     , m_callback(callback)
00355     , m_id(0)
00356   {
00357     m_id = m_cf->registerLogBlock([=](crtpLogDataResponse* r, uint8_t s) { this->handleData(r, s);});
00358     crtpLogCreateBlockRequest request;
00359     request.id = m_id;
00360     int i = 0;
00361     for (auto&& pair : variables) {
00362       const Crazyflie::LogTocEntry* entry = m_cf->getLogTocEntry(pair.first, pair.second);
00363       if (entry) {
00364         request.items[i].logType = entry->type;
00365         request.items[i].id = entry->id;
00366         ++i;
00367       }
00368       else {
00369         std::stringstream sstr;
00370         sstr << "Could not find " << pair.first << "." << pair.second << " in log toc!";
00371         throw std::runtime_error(sstr.str());
00372       }
00373     }
00374 
00375     m_cf->startBatchRequest();
00376     m_cf->addRequest(reinterpret_cast<const uint8_t*>(&request), 3 + 2*i, 2);
00377     m_cf->handleRequests();
00378     auto r = m_cf->getRequestResult<crtpLogControlResponse>(0);
00379     if (r->result != crtpLogControlResultOk
00380         && r->result != crtpLogControlResultBlockExists) {
00381       std::stringstream sstr;
00382       sstr << "Could not create log block! Result: " << (int)r->result << " " << (int)m_id << " " << (int)r->requestByte1 << " " << (int)r->command;
00383       throw std::runtime_error(sstr.str());
00384     }
00385   }
00386 
00387   ~LogBlock()
00388   {
00389     stop();
00390     m_cf->unregisterLogBlock(m_id);
00391   }
00392 
00393 
00394   void start(uint8_t period)
00395   {
00396     crtpLogStartRequest request(m_id, period);
00397     m_cf->startBatchRequest();
00398     m_cf->addRequest(request, 2);
00399     m_cf->handleRequests();
00400   }
00401 
00402   void stop()
00403   {
00404     crtpLogStopRequest request(m_id);
00405     m_cf->startBatchRequest();
00406     m_cf->addRequest(request, 2);
00407     m_cf->handleRequests();
00408   }
00409 
00410 private:
00411   void handleData(crtpLogDataResponse* response, uint8_t size) {
00412     if (size == sizeof(T)) {
00413       uint32_t time_in_ms = ((uint32_t)response->timestampHi << 8) | (response->timestampLo);
00414       T* t = (T*)response->data;
00415       m_callback(time_in_ms, t);
00416     }
00417     else {
00418       throw std::runtime_error("Size doesn't match!");
00419     }
00420   }
00421 
00422 private:
00423   Crazyflie* m_cf;
00424   std::function<void(uint32_t, T*)> m_callback;
00425   uint8_t m_id;
00426 };
00427 
00429 
00430 class LogBlockGeneric
00431 {
00432 public:
00433   LogBlockGeneric(
00434     Crazyflie* cf,
00435     const std::vector<std::string>& variables,
00436     void* userData,
00437     std::function<void(uint32_t, std::vector<double>*, void* userData)>& callback)
00438     : m_cf(cf)
00439     , m_userData(userData)
00440     , m_callback(callback)
00441     , m_id(0)
00442   {
00443     m_id = m_cf->registerLogBlock([=](crtpLogDataResponse* r, uint8_t s) { this->handleData(r, s);});
00444     crtpLogCreateBlockRequest request;
00445     request.id = m_id;
00446     int i = 0;
00447     size_t s = 0;
00448     for (auto&& var : variables) {
00449       auto pos = var.find(".");
00450       std::string first = var.substr(0, pos);
00451       std::string second = var.substr(pos+1);
00452       const Crazyflie::LogTocEntry* entry = m_cf->getLogTocEntry(first, second);
00453       if (entry) {
00454         s += Crazyflie::size(entry->type);
00455         if (s > 26) {
00456           std::stringstream sstr;
00457           sstr << "Can't configure that many variables in a single log block!"
00458                << " Ignoring " << first << "." << second << std::endl;
00459           throw std::runtime_error(sstr.str());
00460         } else {
00461           request.items[i].logType = entry->type;
00462           request.items[i].id = entry->id;
00463           ++i;
00464           m_types.push_back(entry->type);
00465         }
00466       }
00467       else {
00468         std::stringstream sstr;
00469         sstr << "Could not find " << first << "." << second << " in log toc!";
00470         throw std::runtime_error(sstr.str());
00471       }
00472     }
00473     m_cf->startBatchRequest();
00474     m_cf->addRequest(reinterpret_cast<const uint8_t*>(&request), 3 + 2*i, 2);
00475     m_cf->handleRequests();
00476     auto r = m_cf->getRequestResult<crtpLogControlResponse>(0);
00477     if (r->result != crtpLogControlResultOk
00478         && r->result != crtpLogControlResultBlockExists) {
00479       throw std::runtime_error("Could not create log block!");
00480     }
00481   }
00482 
00483   ~LogBlockGeneric()
00484   {
00485     stop();
00486     m_cf->unregisterLogBlock(m_id);
00487   }
00488 
00489 
00490   void start(uint8_t period)
00491   {
00492     crtpLogStartRequest request(m_id, period);
00493     m_cf->startBatchRequest();
00494     m_cf->addRequest(request, 2);
00495     m_cf->handleRequests();
00496   }
00497 
00498   void stop()
00499   {
00500     crtpLogStopRequest request(m_id);
00501     m_cf->startBatchRequest();
00502     m_cf->addRequest(request, 2);
00503     m_cf->handleRequests();
00504   }
00505 
00506 private:
00507   void handleData(crtpLogDataResponse* response, uint8_t size) {
00508 
00509     std::vector<double> result;
00510     size_t pos = 0;
00511     for (size_t i = 0; i < m_types.size(); ++i)
00512     {
00513       switch (m_types[i])
00514       {
00515       case Crazyflie::LogTypeUint8:
00516         {
00517           uint8_t value;
00518           memcpy(&value, &response->data[pos], sizeof(uint8_t));
00519           result.push_back(value);
00520           pos += sizeof(uint8_t);
00521           break;
00522         }
00523       case Crazyflie::LogTypeInt8:
00524         {
00525           int8_t value;
00526           memcpy(&value, &response->data[pos], sizeof(int8_t));
00527           result.push_back(value);
00528           pos += sizeof(int8_t);
00529           break;
00530         }
00531       case Crazyflie::LogTypeUint16:
00532         {
00533           uint16_t value;
00534           memcpy(&value, &response->data[pos], sizeof(uint16_t));
00535           result.push_back(value);
00536           pos += sizeof(uint16_t);
00537           break;
00538         }
00539       case Crazyflie::LogTypeInt16:
00540         {
00541           int16_t value;
00542           memcpy(&value, &response->data[pos], sizeof(int16_t));
00543           result.push_back(value);
00544           pos += sizeof(int16_t);
00545           break;
00546         }
00547       case Crazyflie::LogTypeUint32:
00548         {
00549           uint32_t value;
00550           memcpy(&value, &response->data[pos], sizeof(uint32_t));
00551           result.push_back(value);
00552           pos += sizeof(uint32_t);
00553           break;
00554         }
00555       case Crazyflie::LogTypeInt32:
00556         {
00557           int32_t value;
00558           memcpy(&value, &response->data[pos], sizeof(int32_t));
00559           result.push_back(value);
00560           pos += sizeof(int32_t);
00561           break;
00562         }
00563       case Crazyflie::LogTypeFloat:
00564         {
00565           float value;
00566           memcpy(&value, &response->data[pos], sizeof(float));
00567           result.push_back(value);
00568           pos += sizeof(float);
00569           break;
00570         }
00571       case Crazyflie::LogTypeFP16:
00572         {
00573           double value;
00574           memcpy(&value, &response->data[pos], sizeof(double));
00575           result.push_back(value);
00576           pos += sizeof(double);
00577           break;
00578         }
00579       }
00580     }
00581 
00582     uint32_t time_in_ms = ((uint32_t)response->timestampHi << 8) | (response->timestampLo);
00583     m_callback(time_in_ms, &result, m_userData);
00584   }
00585 
00586 private:
00587   Crazyflie* m_cf;
00588   void* m_userData;
00589   std::function<void(uint32_t, std::vector<double>*, void*)> m_callback;
00590   uint8_t m_id;
00591   std::vector<Crazyflie::LogType> m_types;
00592 };


crazyflie_cpp
Author(s): Wolfgang Hoenig
autogenerated on Sun Oct 8 2017 02:47:59