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