00001
00002 #include <mutex>
00003
00004 #include "Crazyflie.h"
00005 #include "crtp.h"
00006 #include "crtpBootloader.h"
00007 #include "crtpNRF51.h"
00008
00009 #include "Crazyradio.h"
00010 #include "CrazyflieUSB.h"
00011
00012 #include <fstream>
00013 #include <cstring>
00014 #include <stdexcept>
00015 #include <thread>
00016 #include <cmath>
00017 #include <inttypes.h>
00018
00019 const static int MAX_RADIOS = 16;
00020 const static int MAX_USB = 4;
00021 const static bool LOG_COMMUNICATION = 0;
00022
00023 Crazyradio* g_crazyradios[MAX_RADIOS];
00024 std::mutex g_radioMutex[MAX_RADIOS];
00025
00026 CrazyflieUSB* g_crazyflieUSB[MAX_USB];
00027 std::mutex g_crazyflieusbMutex[MAX_USB];
00028
00029 Logger EmptyLogger;
00030
00031
00032 Crazyflie::Crazyflie(
00033 const std::string& link_uri,
00034 Logger& logger,
00035 std::function<void(const char*)> consoleCb)
00036 : m_radio(nullptr)
00037 , m_transport(nullptr)
00038 , m_devId(0)
00039 , m_channel(0)
00040 , m_address(0)
00041 , m_datarate(Crazyradio::Datarate_250KPS)
00042 , m_logTocEntries()
00043 , m_logBlockCb()
00044 , m_paramTocEntries()
00045 , m_paramValues()
00046 , m_emptyAckCallback(nullptr)
00047 , m_linkQualityCallback(nullptr)
00048 , m_consoleCallback(consoleCb)
00049 , m_log_use_V2(false)
00050 , m_param_use_V2(false)
00051 , m_logger(logger)
00052 {
00053 int datarate;
00054 int channel;
00055 char datarateType;
00056 bool success = false;
00057
00058 success = std::sscanf(link_uri.c_str(), "radio://%d/%d/%d%c/%" SCNx64,
00059 &m_devId, &channel, &datarate,
00060 &datarateType, &m_address) == 5;
00061 if (!success) {
00062 success = std::sscanf(link_uri.c_str(), "radio://%d/%d/%d%c",
00063 &m_devId, &channel, &datarate,
00064 &datarateType) == 4;
00065 m_address = 0xE7E7E7E7E7;
00066 }
00067
00068 if (success)
00069 {
00070 m_channel = channel;
00071 if (datarate == 250 && datarateType == 'K') {
00072 m_datarate = Crazyradio::Datarate_250KPS;
00073 }
00074 else if (datarate == 1 && datarateType == 'M') {
00075 m_datarate = Crazyradio::Datarate_1MPS;
00076 }
00077 else if (datarate == 2 && datarateType == 'M') {
00078 m_datarate = Crazyradio::Datarate_2MPS;
00079 }
00080
00081 if (m_devId >= MAX_RADIOS) {
00082 throw std::runtime_error("This version does not support that many radios. Adjust MAX_RADIOS and recompile!");
00083 }
00084
00085 {
00086 std::unique_lock<std::mutex> mlock(g_radioMutex[m_devId]);
00087 if (!g_crazyradios[m_devId]) {
00088 g_crazyradios[m_devId] = new Crazyradio(m_devId);
00089 g_crazyradios[m_devId]->enableLogging(LOG_COMMUNICATION);
00090
00091 g_crazyradios[m_devId]->setAckEnable(true);
00092 g_crazyradios[m_devId]->setArc(0);
00093 }
00094 }
00095
00096 m_radio = g_crazyradios[m_devId];
00097 }
00098 else {
00099 success = std::sscanf(link_uri.c_str(), "usb://%d",
00100 &m_devId) == 1;
00101
00102 if (m_devId >= MAX_USB) {
00103 throw std::runtime_error("This version does not support that many CFs over USB. Adjust MAX_USB and recompile!");
00104 }
00105
00106 {
00107 std::unique_lock<std::mutex> mlock(g_crazyflieusbMutex[m_devId]);
00108 if (!g_crazyflieUSB[m_devId]) {
00109 g_crazyflieUSB[m_devId] = new CrazyflieUSB(m_devId);
00110 g_crazyflieUSB[m_devId]->enableLogging(LOG_COMMUNICATION);
00111 }
00112 }
00113
00114 m_transport = g_crazyflieUSB[m_devId];
00115 }
00116
00117 if (!success) {
00118 throw std::runtime_error("Uri is not valid!");
00119 }
00120
00121
00122 if (m_radio) {
00123 crtpNrf51SetSafelinkRequest request(ENABLE_SAFELINK);
00124 sendPacketOrTimeout(request, false);
00125 }
00126
00127 m_curr_up = 0;
00128 m_curr_down = 0;
00129
00130 m_protocolVersion = getProtocolVersion();
00131
00132 }
00133
00134 int Crazyflie::getProtocolVersion()
00135 {
00136 crtpGetProtocolVersionRequest req;
00137 startBatchRequest();
00138 addRequest(req, 1);
00139 handleRequests();
00140 return getRequestResult<crtpGetProtocolVersionResponse>(0)->version;
00141 }
00142
00143 std::string Crazyflie::getFirmwareVersion()
00144 {
00145 crtpGetFirmwareVersionRequest req;
00146 startBatchRequest();
00147 addRequest(req, 1);
00148 handleRequests();
00149 return std::string(getRequestResult<crtpGetFirmwareVersionResponse>(0)->version);
00150 }
00151
00152 std::string Crazyflie::getDeviceTypeName()
00153 {
00154 crtpGetDeviceTypeNameRequest req;
00155 startBatchRequest();
00156 addRequest(req, 1);
00157 handleRequests();
00158 return std::string(getRequestResult<crtpGetDeviceTypeNameResponse>(0)->name);
00159 }
00160
00161 void Crazyflie::logReset()
00162 {
00163 crtpLogResetRequest request;
00164 startBatchRequest();
00165 addRequest(request, 1);
00166 handleRequests();
00167 }
00168
00169 void Crazyflie::sendSetpoint(
00170 float roll,
00171 float pitch,
00172 float yawrate,
00173 uint16_t thrust)
00174 {
00175 crtpSetpointRequest request(roll, pitch, yawrate, thrust);
00176 sendPacket((const uint8_t*)&request, sizeof(request));
00177 }
00178
00179 void Crazyflie::sendStop()
00180 {
00181 crtpStopRequest request;
00182 sendPacket((const uint8_t*)&request, sizeof(request));
00183 }
00184
00185 void Crazyflie::sendPositionSetpoint(
00186 float x,
00187 float y,
00188 float z,
00189 float yaw)
00190 {
00191 crtpPositionSetpointRequest request(x, y, z, yaw);
00192 sendPacket((const uint8_t*)&request, sizeof(request));
00193 }
00194
00195 void Crazyflie::sendHoverSetpoint(
00196 float vx,
00197 float vy,
00198 float yawrate,
00199 float zDistance)
00200 {
00201 crtpHoverSetpointRequest request(vx, vy, yawrate, zDistance);
00202 sendPacket((const uint8_t*)&request, sizeof(request));
00203 }
00204
00205 void Crazyflie::sendFullStateSetpoint(
00206 float x, float y, float z,
00207 float vx, float vy, float vz,
00208 float ax, float ay, float az,
00209 float qx, float qy, float qz, float qw,
00210 float rollRate, float pitchRate, float yawRate)
00211 {
00212 crtpFullStateSetpointRequest request(
00213 x, y, z,
00214 vx, vy, vz,
00215 ax, ay, az,
00216 qx, qy, qz, qw,
00217 rollRate, pitchRate, yawRate);
00218 sendPacket((const uint8_t*)&request, sizeof(request));
00219 }
00220
00221 void Crazyflie::sendExternalPositionUpdate(
00222 float x,
00223 float y,
00224 float z)
00225 {
00226 crtpExternalPositionUpdate position(x, y, z);
00227 sendPacket((const uint8_t*)&position, sizeof(position));
00228 }
00229
00230 void Crazyflie::sendPing()
00231 {
00232 uint8_t ping = 0xFF;
00233 sendPacket(&ping, sizeof(ping));
00234 }
00235
00239 void Crazyflie::transmitPackets()
00240 {
00241 if (!m_outgoing_packets.empty())
00242 {
00243 std::vector<crtpPacket_t>::iterator it;
00244 for (it = m_outgoing_packets.begin(); it != m_outgoing_packets.end(); it++)
00245 {
00246 sendPacket(it->raw, it->size+1);
00247 }
00248 m_outgoing_packets.clear();
00249 }
00250 }
00251
00252
00253 void Crazyflie::reboot()
00254 {
00255 if (m_radio) {
00256 crtpNrf51ResetInitRequest req1;
00257 sendPacketOrTimeout(req1);
00258
00259 crtpNrf51ResetRequest req2( 1);
00260 sendPacketOrTimeout(req2);
00261 }
00262 }
00263
00264 uint64_t Crazyflie::rebootToBootloader()
00265 {
00266 if (m_radio) {
00267 crtpNrf51ResetInitRequest req;
00268 startBatchRequest();
00269 addRequest(req, 2);
00270 handleRequests();
00271 const crtpNrf51ResetInitResponse* response = getRequestResult<crtpNrf51ResetInitResponse>(0);
00272
00273 uint64_t result =
00274 ((uint64_t)response->addr[0] << 0)
00275 | ((uint64_t)response->addr[1] << 8)
00276 | ((uint64_t)response->addr[2] << 16)
00277 | ((uint64_t)response->addr[3] << 24)
00278 | ((uint64_t)0xb1 << 32);
00279
00280 crtpNrf51ResetRequest req2( 0);
00281 sendPacketOrTimeout(req2);
00282
00283
00284 m_address = result;
00285 m_channel = 0;
00286 m_datarate = Crazyradio::Datarate_2MPS;
00287
00288
00289 return result;
00290 } else {
00291 return -1;
00292 }
00293 }
00294
00295 void Crazyflie::rebootFromBootloader()
00296 {
00297 if (m_radio) {
00298 bootloaderResetRequest req( 1);
00299 sendPacketOrTimeout(req, false);
00300 }
00301 }
00302
00303 void Crazyflie::sysoff()
00304 {
00305 if (m_radio) {
00306 crtpNrf51SysOffRequest req;
00307 sendPacketOrTimeout(req);
00308 }
00309 }
00310
00311 void Crazyflie::alloff()
00312 {
00313 if (m_radio) {
00314 crtpNrf51AllOffRequest req;
00315 sendPacketOrTimeout(req);
00316 }
00317 }
00318
00319 void Crazyflie::syson()
00320 {
00321 if (m_radio) {
00322 crtpNrf51SysOnRequest req;
00323 sendPacketOrTimeout(req);
00324 }
00325 }
00326
00327 float Crazyflie::vbat()
00328 {
00329 if (m_radio) {
00330 crtpNrf51GetVBatRequest req;
00331 startBatchRequest();
00332 addRequest(req, 2);
00333 handleRequests();
00334 return getRequestResult<crtpNrf51GetVBatResponse>(0)->vbat;
00335 } else {
00336 return nan("");
00337 }
00338 }
00339
00340 void Crazyflie::writeFlash(
00341 BootloaderTarget target,
00342 const std::vector<uint8_t>& data)
00343 {
00344
00345 bootloaderGetInfoRequest req(target);
00346 startBatchRequest();
00347 addRequest(req, 3);
00348 handleRequests(false, false);
00349 const bootloaderGetInfoResponse* response = getRequestResult<bootloaderGetInfoResponse>(0);
00350 uint16_t pageSize = response->pageSize;
00351 uint16_t flashStart = response->flashStart;
00352 uint16_t nBuffPage = response->nBuffPage;
00353
00354 uint16_t numPages = ceil(data.size() / (float)pageSize);
00355 if (numPages + flashStart >= response->nFlashPage) {
00356 std::stringstream sstr;
00357 sstr << "Requested size too large!";
00358 throw std::runtime_error(sstr.str());
00359 }
00360
00361 std::stringstream sstr;
00362 sstr << "pageSize: " << pageSize
00363 << " nBuffPage: " << nBuffPage
00364 << " nFlashPage: " << response->nFlashPage
00365 << " flashStart: " << flashStart
00366 << " version: " << (int)response->version
00367 << " numPages: " << numPages;
00368 m_logger.info(sstr.str());
00369
00370
00371 size_t offset = 0;
00372 uint16_t usedBuffers = 0;
00373
00374 for (uint16_t page = flashStart; page < numPages + flashStart; ++page) {
00375 std::stringstream sstr;
00376 sstr << "page: " << page - flashStart + 1 << " / " << numPages;
00377 m_logger.info(sstr.str());
00378 for (uint16_t address = 0; address < pageSize; address += 25) {
00379
00380
00381 bootloaderLoadBufferRequest req(target, usedBuffers, address);
00382 size_t requestedSize = std::min<size_t>(data.size() - offset, std::min<size_t>(25, pageSize - address));
00383 memcpy(req.data, &data[offset], requestedSize);
00384
00385
00386
00387
00388
00389
00390
00391 sendPacketOrTimeout((uint8_t*)&req, 7 + requestedSize, false);
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 offset += requestedSize;
00407 if (offset >= data.size()) {
00408 break;
00409 }
00410 }
00411 ++usedBuffers;
00412 if (usedBuffers == nBuffPage
00413 || page == numPages + flashStart - 1) {
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 bootloaderWriteFlashRequest req(target, 0, page - usedBuffers + 1, usedBuffers);
00436 sendPacketOrTimeout((uint8_t*)&req, sizeof(req), false);
00437
00438 auto start = std::chrono::system_clock::now();
00439
00440 size_t tries = 0;
00441 while (true) {
00442 ITransport::Ack ack;
00443 bootloaderFlashStatusRequest statReq(target);
00444 sendPacket((const uint8_t*)&statReq, sizeof(statReq), ack, false);
00445 if ( ack.ack
00446 && ack.size == 5
00447 && memcmp(&req, ack.data, 3) == 0) {
00448 if (ack.data[3] != 1 || ack.data[4] != 0) {
00449 throw std::runtime_error("Error during flashing!");
00450 }
00451 break;
00452 }
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 auto end = std::chrono::system_clock::now();
00464 std::chrono::duration<double> elapsedSeconds = end-start;
00465 if (elapsedSeconds.count() > 0.5) {
00466 start = end;
00467 sendPacketOrTimeout((uint8_t*)&req, sizeof(req), false);
00468 ++tries;
00469 if (tries > 5) {
00470 throw std::runtime_error("timeout");
00471 }
00472 }
00473 }
00474
00475
00476
00477
00478
00479
00480
00481 usedBuffers = 0;
00482 }
00483 }
00484
00485
00486 }
00487
00488 void Crazyflie::readFlash(
00489 BootloaderTarget target,
00490 size_t size,
00491 std::vector<uint8_t>& data)
00492 {
00493
00494 bootloaderGetInfoRequest req(target);
00495 startBatchRequest();
00496 addRequest(req, 3);
00497 handleRequests(false, false);
00498 const bootloaderGetInfoResponse* response = getRequestResult<bootloaderGetInfoResponse>(0);
00499 uint16_t pageSize = response->pageSize;
00500 uint16_t flashStart = response->flashStart;
00501
00502 uint16_t numPages = ceil(size / (float)pageSize);
00503 if (numPages + flashStart >= response->nFlashPage) {
00504 std::stringstream sstr;
00505 sstr << "Requested size too large!";
00506 throw std::runtime_error(sstr.str());
00507 }
00508
00509 std::stringstream sstr;
00510 sstr << "pageSize: " << pageSize
00511 << " nFlashPage: " << response->nFlashPage
00512 << " flashStart: " << flashStart
00513 << " version: " << (int)response->version
00514 << " numPages: " << numPages;
00515 m_logger.info(sstr.str());
00516
00517
00518 size_t offset = 0;
00519 startBatchRequest();
00520 for (uint16_t page = flashStart; page < numPages + flashStart; ++page) {
00521 for (uint16_t address = 0; address < pageSize; address += 25) {
00522
00523 bootloaderReadFlashRequest req(target, page, address);
00524 addRequest(req, 7);
00525 size_t requestedSize = std::min(25, pageSize - address);
00526 offset += requestedSize;
00527 if (offset > size) {
00528 break;
00529 }
00530 }
00531 }
00532 handleRequests(false, false);
00533
00534
00535 data.resize(size);
00536 size_t i = 0;
00537 offset = 0;
00538 for (uint16_t page = flashStart; page < numPages + flashStart; ++page) {
00539 for (uint16_t address = 0; address < pageSize; address += 25) {
00540 const bootloaderReadFlashResponse* response = getRequestResult<bootloaderReadFlashResponse>(i++);
00541 size_t requestedSize = std::min(25, pageSize - address);
00542
00543 memcpy(&data[offset], response->data, std::min(size - offset, requestedSize));
00544 offset += requestedSize;
00545 if (offset > size) {
00546 break;
00547 }
00548 }
00549 }
00550 }
00551
00552 void Crazyflie::requestLogToc(bool forceNoCache)
00553 {
00554 m_log_use_V2 = true;
00555 uint16_t len;
00556 uint32_t crc;
00557
00558 crtpLogGetInfoV2Request infoRequest;
00559 startBatchRequest();
00560 addRequest(infoRequest, 1);
00561 if (m_protocolVersion >= 4) {
00562 handleRequests();
00563 len = getRequestResult<crtpLogGetInfoV2Response>(0)->log_len;
00564 crc = getRequestResult<crtpLogGetInfoV2Response>(0)->log_crc;
00565 } else {
00566
00567 m_log_use_V2 = false;
00568
00569 crtpLogGetInfoRequest infoRequest;
00570 startBatchRequest();
00571 addRequest(infoRequest, 1);
00572 handleRequests();
00573 len = getRequestResult<crtpLogGetInfoResponse>(0)->log_len;
00574 crc = getRequestResult<crtpLogGetInfoResponse>(0)->log_crc;
00575
00576 }
00577
00578
00579 std::string fileName = "log" + std::to_string(crc) + ".csv";
00580 std::ifstream infile(fileName);
00581
00582 if (forceNoCache || !infile.good()) {
00583 m_logger.info("Log: " + std::to_string(len));
00584
00585
00586 startBatchRequest();
00587 if (m_log_use_V2) {
00588 for (size_t i = 0; i < len; ++i) {
00589 crtpLogGetItemV2Request itemRequest(i);
00590 addRequest(itemRequest, 2);
00591 }
00592 } else {
00593 for (size_t i = 0; i < len; ++i) {
00594 crtpLogGetItemRequest itemRequest(i);
00595 addRequest(itemRequest, 2);
00596 }
00597 }
00598 handleRequests();
00599
00600
00601 m_logTocEntries.resize(len);
00602 if (m_log_use_V2) {
00603 for (size_t i = 0; i < len; ++i) {
00604 auto response = getRequestResult<crtpLogGetItemV2Response>(i);
00605 LogTocEntry& entry = m_logTocEntries[i];
00606 entry.id = i;
00607 entry.type = (LogType)response->type;
00608 entry.group = std::string(&response->text[0]);
00609 entry.name = std::string(&response->text[entry.group.size() + 1]);
00610 }
00611 } else {
00612 for (size_t i = 0; i < len; ++i) {
00613 auto response = getRequestResult<crtpLogGetItemResponse>(i);
00614 LogTocEntry& entry = m_logTocEntries[i];
00615 entry.id = i;
00616 entry.type = (LogType)response->type;
00617 entry.group = std::string(&response->text[0]);
00618 entry.name = std::string(&response->text[entry.group.size() + 1]);
00619 }
00620 }
00621
00622
00623 {
00624
00625 std::string fileNameTemp = fileName + ".tmp";
00626 std::ofstream output(fileNameTemp);
00627 output << "id,type,group,name" << std::endl;
00628 for (const auto& entry : m_logTocEntries) {
00629 output << std::to_string(entry.id) << ","
00630 << std::to_string(entry.type) << ","
00631 << entry.group << ","
00632 << entry.name << std::endl;
00633 }
00634
00635 rename(fileNameTemp.c_str(), fileName.c_str());
00636 }
00637 } else {
00638 m_logger.info("Found variables in cache.");
00639 m_logTocEntries.clear();
00640 std::string line, cell;
00641 std::getline(infile, line);
00642 while (std::getline(infile, line)) {
00643 std::stringstream lineStream(line);
00644 m_logTocEntries.resize(m_logTocEntries.size() + 1);
00645 std::getline(lineStream, cell, ',');
00646 m_logTocEntries.back().id = std::stoi(cell);
00647 std::getline(lineStream, cell, ',');
00648 m_logTocEntries.back().type = (LogType)std::stoi(cell);
00649 std::getline(lineStream, cell, ',');
00650 m_logTocEntries.back().group = cell;
00651 std::getline(lineStream, cell, ',');
00652 m_logTocEntries.back().name = cell;
00653 }
00654 }
00655 }
00656
00657 void Crazyflie::requestParamToc(bool forceNoCache)
00658 {
00659 m_param_use_V2 = true;
00660 uint16_t numParam;
00661 uint32_t crc;
00662
00663 crtpParamTocGetInfoV2Request infoRequest;
00664 startBatchRequest();
00665
00666 addRequest(infoRequest, 1);
00667 if (m_protocolVersion >= 4) {
00668 handleRequests();
00669 numParam = getRequestResult<crtpParamTocGetInfoV2Response>(0)->numParam;
00670 crc = getRequestResult<crtpParamTocGetInfoV2Response>(0)->crc;
00671 } else {
00672
00673 m_param_use_V2 = false;
00674
00675 crtpParamTocGetInfoRequest infoRequest;
00676 startBatchRequest();
00677 addRequest(infoRequest, 1);
00678 handleRequests();
00679 numParam = getRequestResult<crtpParamTocGetInfoResponse>(0)->numParam;
00680 crc = getRequestResult<crtpParamTocGetInfoResponse>(0)->crc;
00681 }
00682
00683
00684 std::string fileName = "params" + std::to_string(crc) + ".csv";
00685 std::ifstream infile(fileName);
00686
00687 if (forceNoCache || !infile.good()) {
00688 m_logger.info("Params: " + std::to_string(numParam));
00689
00690
00691 startBatchRequest();
00692 if (!m_param_use_V2) {
00693 for (uint16_t i = 0; i < numParam; ++i) {
00694 crtpParamTocGetItemRequest itemRequest(i);
00695 addRequest(itemRequest, 2);
00696 crtpParamReadRequest readRequest(i);
00697 addRequest(readRequest, 1);
00698 }
00699 } else {
00700 for (uint16_t i = 0; i < numParam; ++i) {
00701 crtpParamTocGetItemV2Request itemRequest(i);
00702 addRequest(itemRequest, 2);
00703 crtpParamReadV2Request readRequest(i);
00704 addRequest(readRequest, 1);
00705 }
00706 }
00707 handleRequests();
00708
00709 m_paramTocEntries.resize(numParam);
00710
00711 if (!m_param_use_V2) {
00712 for (uint16_t i = 0; i < numParam; ++i) {
00713 auto r = getRequestResult<crtpParamTocGetItemResponse>(i*2+0);
00714 auto val = getRequestResult<crtpParamValueResponse>(i*2+1);
00715
00716 ParamTocEntry& entry = m_paramTocEntries[i];
00717 entry.id = i;
00718 entry.type = (ParamType)(r->length | r-> type << 2 | r->sign << 3);
00719 entry.readonly = r->readonly;
00720 entry.group = std::string(&r->text[0]);
00721 entry.name = std::string(&r->text[entry.group.size() + 1]);
00722
00723 ParamValue v;
00724 std::memcpy(&v, &val->valueFloat, 4);
00725 m_paramValues[i] = v;
00726 }
00727 } else {
00728 for (uint16_t i = 0; i < numParam; ++i) {
00729 auto r = getRequestResult<crtpParamTocGetItemV2Response>(i*2+0);
00730 auto val = getRequestResult<crtpParamValueV2Response>(i*2+1);
00731
00732 ParamTocEntry& entry = m_paramTocEntries[i];
00733 entry.id = i;
00734 entry.type = (ParamType)(r->length | r-> type << 2 | r->sign << 3);
00735 entry.readonly = r->readonly;
00736 entry.group = std::string(&r->text[0]);
00737 entry.name = std::string(&r->text[entry.group.size() + 1]);
00738
00739 ParamValue v;
00740 std::memcpy(&v, &val->valueFloat, 4);
00741 m_paramValues[i] = v;
00742 }
00743 }
00744
00745
00746 {
00747
00748 std::string fileNameTemp = fileName + ".tmp";
00749 std::ofstream output(fileNameTemp);
00750 output << "id,type,readonly,group,name" << std::endl;
00751 for (const auto& entry : m_paramTocEntries) {
00752 output << std::to_string(entry.id) << ","
00753 << std::to_string(entry.type) << ","
00754 << std::to_string(entry.readonly) << ","
00755 << entry.group << ","
00756 << entry.name << std::endl;
00757 }
00758
00759 rename(fileNameTemp.c_str(), fileName.c_str());
00760 }
00761 } else {
00762 m_logger.info("Found variables in cache.");
00763 m_paramTocEntries.clear();
00764 std::string line, cell;
00765 std::getline(infile, line);
00766 while (std::getline(infile, line)) {
00767 std::stringstream lineStream(line);
00768 m_paramTocEntries.resize(m_paramTocEntries.size() + 1);
00769 std::getline(lineStream, cell, ',');
00770 m_paramTocEntries.back().id = std::stoi(cell);
00771 std::getline(lineStream, cell, ',');
00772 m_paramTocEntries.back().type = (ParamType)std::stoi(cell);
00773 std::getline(lineStream, cell, ',');
00774 m_paramTocEntries.back().readonly = std::stoi(cell);
00775 std::getline(lineStream, cell, ',');
00776 m_paramTocEntries.back().group = cell;
00777 std::getline(lineStream, cell, ',');
00778 m_paramTocEntries.back().name = cell;
00779 }
00780
00781
00782 if (!m_param_use_V2) {
00783 startBatchRequest();
00784 for (size_t i = 0; i < numParam; ++i) {
00785 crtpParamReadRequest readRequest(i);
00786 addRequest(readRequest, 1);
00787 }
00788 handleRequests();
00789 for (size_t i = 0; i < numParam; ++i) {
00790 auto val = getRequestResult<crtpParamValueResponse>(i);
00791 ParamValue v;
00792 std::memcpy(&v, &val->valueFloat, 4);
00793 m_paramValues[i] = v;
00794 }
00795 } else {
00796 startBatchRequest();
00797 for (size_t i = 0; i < numParam; ++i) {
00798 crtpParamReadV2Request readRequest(i);
00799 addRequest(readRequest, 1);
00800 }
00801 handleRequests();
00802 for (size_t i = 0; i < numParam; ++i) {
00803 auto val = getRequestResult<crtpParamValueV2Response>(i);
00804 ParamValue v;
00805 std::memcpy(&v, &val->valueFloat, 4);
00806 m_paramValues[i] = v;
00807 }
00808 }
00809 }
00810 }
00811
00812 void Crazyflie::requestMemoryToc()
00813 {
00814
00815 crtpMemoryGetNumberRequest infoRequest;
00816 startBatchRequest();
00817 addRequest(infoRequest, 1);
00818 handleRequests();
00819 uint8_t len = getRequestResult<crtpMemoryGetNumberResponse>(0)->numberOfMemories;
00820
00821 m_logger.info("Memories: " + std::to_string(len));
00822
00823
00824 startBatchRequest();
00825 for (uint8_t i = 0; i < len; ++i) {
00826 crtpMemoryGetInfoRequest itemRequest(i);
00827 addRequest(itemRequest, 2);
00828 }
00829 handleRequests();
00830
00831
00832 m_memoryTocEntries.resize(len);
00833 for (uint8_t i = 0; i < len; ++i) {
00834 auto info = getRequestResult<crtpMemoryGetInfoResponse>(i);
00835
00836 MemoryTocEntry& entry = m_memoryTocEntries[i];
00837 entry.id = i;
00838 entry.type = (MemoryType)info->memType;
00839 entry.size = info->memSize;
00840 entry.addr = info->memAddr;
00841 }
00842 }
00843
00844 void Crazyflie::startSetParamRequest()
00845 {
00846 startBatchRequest();
00847 }
00848
00849 void Crazyflie::addSetParam(uint8_t id, const ParamValue& value)
00850 {
00851 bool found = false;
00852 for (auto&& entry : m_paramTocEntries) {
00853 if (entry.id == id) {
00854 found = true;
00855 if (!m_param_use_V2) {
00856 switch (entry.type) {
00857 case ParamTypeUint8:
00858 {
00859 crtpParamWriteRequest<uint8_t> request(id, value.valueUint8);
00860 addRequest(request, 1);
00861 break;
00862 }
00863 case ParamTypeInt8:
00864 {
00865 crtpParamWriteRequest<int8_t> request(id, value.valueInt8);
00866 addRequest(request, 1);
00867 break;
00868 }
00869 case ParamTypeUint16:
00870 {
00871 crtpParamWriteRequest<uint16_t> request(id, value.valueUint16);
00872 addRequest(request, 1);
00873 break;
00874 }
00875 case ParamTypeInt16:
00876 {
00877 crtpParamWriteRequest<int16_t> request(id, value.valueInt16);
00878 addRequest(request, 1);
00879 break;
00880 }
00881 case ParamTypeUint32:
00882 {
00883 crtpParamWriteRequest<uint32_t> request(id, value.valueUint32);
00884 addRequest(request, 1);
00885 break;
00886 }
00887 case ParamTypeInt32:
00888 {
00889 crtpParamWriteRequest<int32_t> request(id, value.valueInt32);
00890 addRequest(request, 1);
00891 break;
00892 }
00893 case ParamTypeFloat:
00894 {
00895 crtpParamWriteRequest<float> request(id, value.valueFloat);
00896 addRequest(request, 1);
00897 break;
00898 }
00899 }
00900 } else {
00901 switch (entry.type) {
00902 case ParamTypeUint8:
00903 {
00904 crtpParamWriteV2Request<uint8_t> request(id, value.valueUint8);
00905 addRequest(request, 2);
00906 break;
00907 }
00908 case ParamTypeInt8:
00909 {
00910 crtpParamWriteV2Request<int8_t> request(id, value.valueInt8);
00911 addRequest(request, 2);
00912 break;
00913 }
00914 case ParamTypeUint16:
00915 {
00916 crtpParamWriteV2Request<uint16_t> request(id, value.valueUint16);
00917 addRequest(request, 2);
00918 break;
00919 }
00920 case ParamTypeInt16:
00921 {
00922 crtpParamWriteV2Request<int16_t> request(id, value.valueInt16);
00923 addRequest(request, 2);
00924 break;
00925 }
00926 case ParamTypeUint32:
00927 {
00928 crtpParamWriteV2Request<uint32_t> request(id, value.valueUint32);
00929 addRequest(request, 2);
00930 break;
00931 }
00932 case ParamTypeInt32:
00933 {
00934 crtpParamWriteV2Request<int32_t> request(id, value.valueInt32);
00935 addRequest(request, 2);
00936 break;
00937 }
00938 case ParamTypeFloat:
00939 {
00940 crtpParamWriteV2Request<float> request(id, value.valueFloat);
00941 addRequest(request, 2);
00942 break;
00943 }
00944 }
00945 }
00946 }
00947 }
00948
00949 if (!found) {
00950 std::stringstream sstr;
00951 sstr << "Could not find parameter with id " << id;
00952 throw std::runtime_error(sstr.str());
00953 }
00954
00955 m_paramValues[id] = value;
00956 }
00957
00958 void Crazyflie::setRequestedParams()
00959 {
00960 handleRequests();
00961 }
00962
00963 void Crazyflie::setParam(uint8_t id, const ParamValue& value)
00964 {
00965 startBatchRequest();
00966 addSetParam(id, value);
00967 setRequestedParams();
00968 }
00969
00970 bool Crazyflie::sendPacket(
00971 const uint8_t* data,
00972 uint32_t length,
00973 bool useSafeLink)
00974 {
00975 ITransport::Ack ack;
00976 sendPacket(data, length, ack, useSafeLink);
00977 return ack.ack;
00978 }
00979
00980 void Crazyflie::sendPacketOrTimeout(
00981 const uint8_t* data,
00982 uint32_t length,
00983 bool useSafeLink,
00984 float timeout)
00985 {
00986 auto start = std::chrono::system_clock::now();
00987 while (!sendPacket(data, length, useSafeLink)) {
00988 auto end = std::chrono::system_clock::now();
00989 std::chrono::duration<double> elapsedSeconds = end-start;
00990 if (elapsedSeconds.count() > timeout) {
00991 throw std::runtime_error("timeout");
00992 }
00993 }
00994 }
00995
00996 void Crazyflie::sendPacket(
00997 const uint8_t* data,
00998 uint32_t length,
00999 ITransport::Ack& ack,
01000 bool useSafeLink)
01001 {
01002 static uint32_t numPackets = 0;
01003 static uint32_t numAcks = 0;
01004
01005 numPackets++;
01006
01007 if (m_radio) {
01008 std::unique_lock<std::mutex> mlock(g_radioMutex[m_devId]);
01009 if (m_radio->getAddress() != m_address) {
01010 m_radio->setAddress(m_address);
01011 }
01012 if (m_radio->getChannel() != m_channel) {
01013 m_radio->setChannel(m_channel);
01014 }
01015 if (m_radio->getDatarate() != m_datarate) {
01016 m_radio->setDatarate(m_datarate);
01017 }
01018 if (!m_radio->getAckEnable()) {
01019 m_radio->setAckEnable(true);
01020 }
01021
01022
01023
01024
01025
01026 if (useSafeLink) {
01027 std::vector<uint8_t> dataCopy(data, data + length);
01028 dataCopy[0] &= 0xF3;
01029 dataCopy[0] |= m_curr_up << 3 | m_curr_down << 2;
01030 m_radio->sendPacket(dataCopy.data(), length, ack);
01031 if (ack.ack && ack.size > 0 && (ack.data[0] & 0x04) == (m_curr_down << 2)) {
01032 m_curr_down = 1 - m_curr_down;
01033 }
01034 if (ack.ack) {
01035 m_curr_up = 1 - m_curr_up;
01036 }
01037 } else {
01038 m_radio->sendPacket(data, length, ack);
01039 }
01040
01041 } else {
01042 std::unique_lock<std::mutex> mlock(g_crazyflieusbMutex[m_devId]);
01043 m_transport->sendPacket(data, length, ack);
01044 }
01045 ack.data[ack.size] = 0;
01046 if (ack.ack) {
01047 handleAck(ack);
01048 numAcks++;
01049 }
01050 if (numPackets == 100) {
01051 if (m_linkQualityCallback) {
01052
01053
01054 float linkQuality = numAcks / (float)numPackets;
01055 m_linkQualityCallback(linkQuality);
01056 }
01057 numPackets = 0;
01058 numAcks = 0;
01059 }
01060 }
01061
01062 void Crazyflie::handleAck(
01063 const ITransport::Ack& result)
01064 {
01065 if (crtpConsoleResponse::match(result)) {
01066 if (result.size > 0) {
01067 crtpConsoleResponse* r = (crtpConsoleResponse*)result.data;
01068 if (m_consoleCallback) {
01069 m_consoleCallback(r->text);
01070 }
01071 }
01072
01073 }
01074 else if (crtpLogGetInfoResponse::match(result)) {
01075
01076 }
01077 else if (crtpLogGetItemResponse::match(result)) {
01078
01079 }
01080 else if (crtpLogControlResponse::match(result)) {
01081
01082 }
01083 else if (crtpLogDataResponse::match(result)) {
01084 crtpLogDataResponse* r = (crtpLogDataResponse*)result.data;
01085 auto iter = m_logBlockCb.find(r->blockId);
01086 if (iter != m_logBlockCb.end()) {
01087 iter->second(r, result.size - 5);
01088 }
01089 else {
01090 m_logger.warning("Received unrequested data for block: " + std::to_string((int)r->blockId));
01091 }
01092 }
01093 else if (crtpParamTocGetInfoResponse::match(result)) {
01094
01095 }
01096 else if (crtpParamTocGetItemResponse::match(result)) {
01097
01098 }
01099 else if (crtpParamTocGetInfoV2Response::match(result)) {
01100
01101 }
01102 else if (crtpParamTocGetItemV2Response::match(result)) {
01103
01104 }
01105 else if (crtpMemoryGetNumberResponse::match(result)) {
01106
01107 }
01108 else if (crtpMemoryGetInfoResponse::match(result)) {
01109
01110 }
01111 else if (crtpParamValueResponse::match(result)) {
01112
01113 }
01114 else if (crtpMemoryGetNumberResponse::match(result)) {
01115
01116 }
01117 else if (crtpMemoryReadResponse::match(result)) {
01118
01119 }
01120 else if (crtpMemoryWriteResponse::match(result)) {
01121
01122 }
01123 else if (crtp(result.data[0]).port == 8) {
01124
01125 }
01126 else if (crtpPlatformRSSIAck::match(result)) {
01127 if (result.size >= 3) {
01128 crtpPlatformRSSIAck* r = (crtpPlatformRSSIAck*)result.data;
01129 if (m_emptyAckCallback) {
01130 m_emptyAckCallback(r);
01131 }
01132 }
01133 }
01134 else {
01135 crtp* header = (crtp*)result.data;
01136 m_logger.warning("Don't know ack: Port: " + std::to_string((int)header->port)
01137 + " Channel: " + std::to_string((int)header->channel)
01138 + " Len: " + std::to_string((int)result.size));
01139
01140
01141
01142 if (m_genericPacketCallback) {
01143 m_genericPacketCallback(result);
01144 }
01145 }
01146 }
01147
01148 const Crazyflie::LogTocEntry* Crazyflie::getLogTocEntry(
01149 const std::string& group,
01150 const std::string& name) const
01151 {
01152 for (auto&& entry : m_logTocEntries) {
01153 if (entry.group == group && entry.name == name) {
01154 return &entry;
01155 }
01156 }
01157 return nullptr;
01158 }
01159
01160 const Crazyflie::ParamTocEntry* Crazyflie::getParamTocEntry(
01161 const std::string& group,
01162 const std::string& name) const
01163 {
01164 for (auto&& entry : m_paramTocEntries) {
01165 if (entry.group == group && entry.name == name) {
01166 return &entry;
01167 }
01168 }
01169 return nullptr;
01170 }
01171
01172 uint8_t Crazyflie::registerLogBlock(
01173 std::function<void(crtpLogDataResponse*, uint8_t)> cb)
01174 {
01175 for (uint8_t id = 0; id < 255; ++id) {
01176 if (m_logBlockCb.find(id) == m_logBlockCb.end()) {
01177 m_logBlockCb[id] = cb;
01178 return id;
01179 }
01180 }
01181 return 255;
01182 }
01183
01184 bool Crazyflie::unregisterLogBlock(
01185 uint8_t id)
01186 {
01187 m_logBlockCb.erase(m_logBlockCb.find(id));
01188 return true;
01189 }
01190
01191
01192
01193 void Crazyflie::startBatchRequest()
01194 {
01195 m_batchRequests.clear();
01196 }
01197
01198 void Crazyflie::addRequest(
01199 const uint8_t* data,
01200 size_t numBytes,
01201 size_t numBytesToMatch)
01202 {
01203 m_batchRequests.resize(m_batchRequests.size() + 1);
01204 m_batchRequests.back().request.resize(numBytes);
01205 memcpy(m_batchRequests.back().request.data(), data, numBytes);
01206 m_batchRequests.back().numBytesToMatch = numBytesToMatch;
01207 m_batchRequests.back().finished = false;
01208 }
01209
01210 void Crazyflie::handleRequests(
01211 bool crtpMode,
01212 bool useSafeLink,
01213 float baseTime,
01214 float timePerRequest)
01215 {
01216 auto start = std::chrono::system_clock::now();
01217 ITransport::Ack ack;
01218 m_numRequestsFinished = 0;
01219 bool sendPing = false;
01220
01221 float timeout = baseTime + timePerRequest * m_batchRequests.size();
01222
01223 while (true) {
01224 if (!crtpMode || !sendPing) {
01225 for (const auto& request : m_batchRequests) {
01226 if (!request.finished) {
01227
01228 sendPacket(request.request.data(), request.request.size(), ack, useSafeLink);
01229 handleBatchAck(ack, crtpMode);
01230
01231 auto end = std::chrono::system_clock::now();
01232 std::chrono::duration<double> elapsedSeconds = end-start;
01233 if (elapsedSeconds.count() > timeout) {
01234 throw std::runtime_error("timeout");
01235 }
01236 }
01237 }
01238 if (m_radio) {
01239 sendPing = true;
01240 }
01241 } else {
01242 for (size_t i = 0; i < 10; ++i) {
01243 uint8_t ping = 0xFF;
01244 sendPacket(&ping, sizeof(ping), ack, useSafeLink);
01245 handleBatchAck(ack, crtpMode);
01246
01247
01248
01249
01250 auto end = std::chrono::system_clock::now();
01251 std::chrono::duration<double> elapsedSeconds = end-start;
01252 if (elapsedSeconds.count() > timeout) {
01253 throw std::runtime_error("timeout");
01254 }
01255 }
01256
01257 sendPing = false;
01258 }
01259 if (m_numRequestsFinished == m_batchRequests.size()) {
01260 break;
01261 }
01262 }
01263 }
01264
01265 void Crazyflie::handleBatchAck(
01266 const ITransport::Ack& ack,
01267 bool crtpMode)
01268 {
01269 if (ack.ack) {
01270 for (auto& request : m_batchRequests) {
01271 if (crtpMode) {
01272 if ((crtp(ack.data[0]) == crtp(request.request[0]) || ack.data[0] == request.request[0])
01273 && memcmp(&ack.data[1], &request.request[1], request.numBytesToMatch) == 0
01274 && !request.finished) {
01275 request.ack = ack;
01276 request.finished = true;
01277 ++m_numRequestsFinished;
01278
01279 return;
01280 }
01281 } else {
01282 if (!request.finished
01283 && memcmp(&ack.data[0], &request.request[0], request.numBytesToMatch) == 0) {
01284 request.ack = ack;
01285 request.finished = true;
01286 ++m_numRequestsFinished;
01287
01288 return;
01289 }
01290 }
01291 }
01292
01293 }
01294 }
01295
01296 void Crazyflie::setGroupMask(uint8_t groupMask)
01297 {
01298 crtpCommanderHighLevelSetGroupMaskRequest request(groupMask);
01299 startBatchRequest();
01300 addRequest(request, 2);
01301 handleRequests();
01302 }
01303
01304 void Crazyflie::takeoff(float height, float duration, uint8_t groupMask)
01305 {
01306 crtpCommanderHighLevelTakeoffRequest req(groupMask, height, duration);
01307 sendPacketOrTimeout((uint8_t*)&req, sizeof(req));
01308 }
01309
01310 void Crazyflie::land(float height, float duration, uint8_t groupMask)
01311 {
01312 crtpCommanderHighLevelLandRequest req(groupMask, height, duration);
01313 sendPacketOrTimeout((uint8_t*)&req, sizeof(req));
01314 }
01315
01316 void Crazyflie::stop(uint8_t groupMask)
01317 {
01318 crtpCommanderHighLevelStopRequest req(groupMask);
01319 sendPacketOrTimeout((uint8_t*)&req, sizeof(req));
01320 }
01321
01322 void Crazyflie::goTo(float x, float y, float z, float yaw, float duration, bool relative, uint8_t groupMask)
01323 {
01324 crtpCommanderHighLevelGoToRequest req(groupMask, relative, x, y, z, yaw, duration);
01325 sendPacketOrTimeout((uint8_t*)&req, sizeof(req));
01326 }
01327
01328 void Crazyflie::uploadTrajectory(
01329 uint8_t trajectoryId,
01330 uint32_t pieceOffset,
01331 const std::vector<poly4d>& pieces)
01332 {
01333 for (const auto& entry : m_memoryTocEntries) {
01334 if (entry.type == MemoryTypeTRAJ) {
01335 startBatchRequest();
01336
01337 size_t remainingBytes = sizeof(poly4d) * pieces.size();
01338 size_t numRequests = ceil(remainingBytes / 24);
01339 for (size_t i = 0; i < numRequests; ++i) {
01340 crtpMemoryWriteRequest req(entry.id, pieceOffset * sizeof(poly4d) + i*24);
01341 size_t size = std::min<size_t>(remainingBytes, 24);
01342 memcpy(req.data, reinterpret_cast<const uint8_t*>(pieces.data()) + i * 24, size);
01343 remainingBytes -= size;
01344 addRequest(reinterpret_cast<const uint8_t*>(&req), 6 + size, 5);
01345 }
01346
01347 crtpCommanderHighLevelDefineTrajectoryRequest req(trajectoryId);
01348 req.description.trajectoryLocation = TRAJECTORY_LOCATION_MEM;
01349 req.description.trajectoryType = TRAJECTORY_TYPE_POLY4D;
01350 req.description.trajectoryIdentifier.mem.offset = pieceOffset * sizeof(poly4d);
01351 req.description.trajectoryIdentifier.mem.n_pieces = (uint8_t)pieces.size();
01352 addRequest(req, 2);
01353 handleRequests();
01354 return;
01355 }
01356 }
01357 throw std::runtime_error("Could not find MemoryTypeTRAJ!");
01358 }
01359
01360 void Crazyflie::startTrajectory(
01361 uint8_t trajectoryId,
01362 float timescale,
01363 bool reversed,
01364 bool relative,
01365 uint8_t groupMask)
01366 {
01367 crtpCommanderHighLevelStartTrajectoryRequest req(groupMask, relative, reversed, trajectoryId, timescale);
01368 sendPacketOrTimeout((uint8_t*)&req, sizeof(req));
01369 }
01370
01372
01373 CrazyflieBroadcaster::CrazyflieBroadcaster(
01374 const std::string& link_uri)
01375 : m_radio(nullptr)
01376 , m_devId(0)
01377 , m_channel(0)
01378 , m_address(0)
01379 , m_datarate(Crazyradio::Datarate_250KPS)
01380 {
01381 int datarate;
01382 int channel;
01383 char datarateType;
01384 bool success = false;
01385
01386 success = std::sscanf(link_uri.c_str(), "radio://%d/%d/%d%c/%" SCNx64,
01387 &m_devId, &channel, &datarate,
01388 &datarateType, &m_address) == 5;
01389 if (!success) {
01390 success = std::sscanf(link_uri.c_str(), "radio://%d/%d/%d%c",
01391 &m_devId, &channel, &datarate,
01392 &datarateType) == 4;
01393 m_address = 0xE7E7E7E7E7;
01394 }
01395
01396 if (success)
01397 {
01398 m_channel = channel;
01399 if (datarate == 250 && datarateType == 'K') {
01400 m_datarate = Crazyradio::Datarate_250KPS;
01401 }
01402 else if (datarate == 1 && datarateType == 'M') {
01403 m_datarate = Crazyradio::Datarate_1MPS;
01404 }
01405 else if (datarate == 2 && datarateType == 'M') {
01406 m_datarate = Crazyradio::Datarate_2MPS;
01407 }
01408
01409 if (m_devId >= MAX_RADIOS) {
01410 throw std::runtime_error("This version does not support that many radios. Adjust MAX_RADIOS and recompile!");
01411 }
01412
01413 {
01414 std::unique_lock<std::mutex> mlock(g_radioMutex[m_devId]);
01415 if (!g_crazyradios[m_devId]) {
01416 g_crazyradios[m_devId] = new Crazyradio(m_devId);
01417 g_crazyradios[m_devId]->enableLogging(LOG_COMMUNICATION);
01418
01419 g_crazyradios[m_devId]->setAckEnable(true);
01420 g_crazyradios[m_devId]->setArc(0);
01421 }
01422 }
01423
01424 m_radio = g_crazyradios[m_devId];
01425 }
01426 else {
01427 throw std::runtime_error("Uri is not valid!");
01428 }
01429 }
01430
01431 void CrazyflieBroadcaster::sendPacket(
01432 const uint8_t* data,
01433 uint32_t length)
01434 {
01435 std::unique_lock<std::mutex> mlock(g_radioMutex[m_devId]);
01436 if (m_radio->getAddress() != m_address) {
01437 m_radio->setAddress(m_address);
01438 }
01439 if (m_radio->getChannel() != m_channel) {
01440 m_radio->setChannel(m_channel);
01441 }
01442 if (m_radio->getDatarate() != m_datarate) {
01443 m_radio->setDatarate(m_datarate);
01444 }
01445 if (m_radio->getAckEnable()) {
01446 m_radio->setAckEnable(false);
01447 }
01448 m_radio->sendPacketNoAck(data, length);
01449 }
01450
01451 void CrazyflieBroadcaster::send2Packets(
01452 const uint8_t* data,
01453 uint32_t length)
01454 {
01455 std::unique_lock<std::mutex> mlock(g_radioMutex[m_devId]);
01456 if (m_radio->getAddress() != m_address) {
01457 m_radio->setAddress(m_address);
01458 }
01459 if (m_radio->getChannel() != m_channel) {
01460 m_radio->setChannel(m_channel);
01461 }
01462 if (m_radio->getDatarate() != m_datarate) {
01463 m_radio->setDatarate(m_datarate);
01464 }
01465 if (m_radio->getAckEnable()) {
01466 m_radio->setAckEnable(false);
01467 }
01468 m_radio->send2PacketsNoAck(data, length);
01469 }
01470
01471 void CrazyflieBroadcaster::takeoff(float height, float duration, uint8_t groupMask)
01472 {
01473 crtpCommanderHighLevelTakeoffRequest req(groupMask, height, duration);
01474 sendPacket((uint8_t*)&req, sizeof(req));
01475 }
01476
01477 void CrazyflieBroadcaster::land(float height, float duration, uint8_t groupMask)
01478 {
01479 crtpCommanderHighLevelLandRequest req(groupMask, height, duration);
01480 sendPacket((uint8_t*)&req, sizeof(req));
01481 }
01482
01483 void CrazyflieBroadcaster::stop(uint8_t groupMask)
01484 {
01485 crtpCommanderHighLevelStopRequest req(groupMask);
01486 sendPacket((uint8_t*)&req, sizeof(req));
01487 }
01488
01489
01490 void CrazyflieBroadcaster::goTo(float x, float y, float z, float yaw, float duration, uint8_t groupMask)
01491 {
01492 crtpCommanderHighLevelGoToRequest req(groupMask, true, x, y, z, yaw, duration);
01493 sendPacket((uint8_t*)&req, sizeof(req));
01494 }
01495
01496
01497
01498 void CrazyflieBroadcaster::startTrajectory(
01499 uint8_t trajectoryId,
01500 float timescale,
01501 bool reversed,
01502 uint8_t groupMask)
01503 {
01504 crtpCommanderHighLevelStartTrajectoryRequest req(groupMask, true, reversed, trajectoryId, timescale);
01505 sendPacket((uint8_t*)&req, sizeof(req));
01506 }
01507
01508 void CrazyflieBroadcaster::sendExternalPositions(
01509 const std::vector<externalPosition>& data)
01510 {
01511 if (data.size() == 0) {
01512 return;
01513 }
01514
01515 std::vector<crtpExternalPositionPacked> requests(ceil(data.size() / 4.0));
01516 for (size_t i = 0; i < data.size(); ++i) {
01517 size_t j = i / 4;
01518 requests[j].positions[i%4].id = data[i].id;
01519 requests[j].positions[i%4].x = data[i].x * 1000;
01520 requests[j].positions[i%4].y = data[i].y * 1000;
01521 requests[j].positions[i%4].z = data[i].z * 1000;
01522 }
01523
01524 size_t remainingRequests = requests.size();
01525 size_t i = 0;
01526 while (remainingRequests > 0) {
01527 if (remainingRequests >= 2) {
01528 send2Packets(reinterpret_cast<const uint8_t*>(&requests[i]), 2 * sizeof(crtpExternalPositionPacked));
01529 remainingRequests -= 2;
01530 i += 2;
01531 } else {
01532 sendPacket(reinterpret_cast<const uint8_t*>(&requests[i]), sizeof(crtpExternalPositionPacked));
01533 remainingRequests -= 1;
01534 i += 1;
01535 }
01536 }
01537 }
01538
01539 static float const POSITION_LIMIT = 8.0f;
01540 static const uint32_t INT24_MAX = 8388607;
01541 static inline posFixed24_t position_float_to_fix24(float x)
01542 {
01543 uint32_t val = (INT24_MAX / POSITION_LIMIT) * (x + POSITION_LIMIT);
01544 posFixed24_t result;
01545 result.low = (val >> 0) & 0xFF;
01546 result.middle = (val >> 8) & 0xFF;
01547 result.high = (val >> 16) & 0xFF;
01548 return result;
01549 }
01550
01551
01552 static inline uint32_t quatcompress(float const q[4])
01553 {
01554
01555 unsigned i_largest = 0;
01556 for (unsigned i = 1; i < 4; ++i) {
01557 if (fabsf(q[i]) > fabsf(q[i_largest])) {
01558 i_largest = i;
01559 }
01560 }
01561
01562
01563
01564
01565 unsigned negate = q[i_largest] < 0;
01566
01567
01568
01569
01570
01571 uint32_t comp = i_largest;
01572 for (unsigned i = 0; i < 4; ++i) {
01573 if (i != i_largest) {
01574 unsigned negbit = (q[i] < 0) ^ negate;
01575 unsigned mag = ((1 << 9) - 1) * (fabsf(q[i]) / (float)M_SQRT1_2) + 0.5f;
01576 comp = (comp << 10) | (negbit << 9) | mag;
01577 }
01578 }
01579
01580 return comp;
01581 }
01582
01583 void CrazyflieBroadcaster::sendExternalPoses(
01584 const std::vector<externalPose>& data)
01585 {
01586 if (data.size() == 0) {
01587 return;
01588 }
01589
01590 #if 0
01591 std::vector<crtpExternalPositionPacked> requests(ceil(data.size() / 4.0));
01592 for (size_t i = 0; i < data.size(); ++i) {
01593 size_t j = i / 4;
01594 requests[j].positions[i%4].id = data[i].id;
01595 requests[j].positions[i%4].x = data[i].x * 1000;
01596 requests[j].positions[i%4].y = data[i].y * 1000;
01597 requests[j].positions[i%4].z = data[i].z * 1000;
01598 }
01599 # else
01600 std::vector<crtpPosExtBringup> requests(ceil(data.size() / 2.0));
01601 for (size_t i = 0; i < data.size(); ++i) {
01602 size_t j = i / 2;
01603 requests[j].data.pose[i%2].id = data[i].id;
01604 requests[j].data.pose[i%2].x = position_float_to_fix24(data[i].x);
01605 requests[j].data.pose[i%2].y = position_float_to_fix24(data[i].y);
01606 requests[j].data.pose[i%2].z = position_float_to_fix24(data[i].z);
01607 float q[4] = { data[i].qx, data[i].qy, data[i].qz, data[i].qw };
01608 requests[j].data.pose[i%2].quat = quatcompress(q);
01609 }
01610 #endif
01611
01612 size_t remainingRequests = requests.size();
01613 size_t i = 0;
01614 while (remainingRequests > 0) {
01615 if (remainingRequests >= 2) {
01616 send2Packets(reinterpret_cast<const uint8_t*>(&requests[i]), 2 * sizeof(crtpExternalPositionPacked));
01617 remainingRequests -= 2;
01618 i += 2;
01619 } else {
01620 sendPacket(reinterpret_cast<const uint8_t*>(&requests[i]), sizeof(crtpExternalPositionPacked));
01621 remainingRequests -= 1;
01622 i += 1;
01623 }
01624 }
01625 }
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678