00001 #include "ros/ros.h"
00002 #include "crazyflie_driver/AddCrazyflie.h"
00003 #include "crazyflie_driver/RemoveCrazyflie.h"
00004 #include "crazyflie_driver/LogBlock.h"
00005 #include "crazyflie_driver/GenericLogData.h"
00006 #include "crazyflie_driver/UpdateParams.h"
00007 #include "crazyflie_driver/sendPacket.h"
00008 #include "crazyflie_driver/crtpPacket.h"
00009 #include "crazyflie_cpp/Crazyradio.h"
00010 #include "crazyflie_cpp/crtp.h"
00011 #include "std_srvs/Empty.h"
00012 #include "geometry_msgs/Twist.h"
00013 #include "geometry_msgs/PointStamped.h"
00014 #include "sensor_msgs/Imu.h"
00015 #include "sensor_msgs/Temperature.h"
00016 #include "sensor_msgs/MagneticField.h"
00017 #include "std_msgs/Float32.h"
00018
00019
00020 #include <thread>
00021 #include <mutex>
00022
00023 #include <string>
00024 #include <map>
00025
00026 #include <crazyflie_cpp/Crazyflie.h>
00027
00028 constexpr double pi() { return 3.141592653589793238462643383279502884; }
00029
00030 double degToRad(double deg) {
00031 return deg / 180.0 * pi();
00032 }
00033
00034 double radToDeg(double rad) {
00035 return rad * 180.0 / pi();
00036 }
00037
00038 class CrazyflieROS
00039 {
00040 public:
00041 CrazyflieROS(
00042 const std::string& link_uri,
00043 const std::string& tf_prefix,
00044 float roll_trim,
00045 float pitch_trim,
00046 bool enable_logging,
00047 bool enable_parameters,
00048 std::vector<crazyflie_driver::LogBlock>& log_blocks,
00049 bool use_ros_time,
00050 bool enable_logging_imu,
00051 bool enable_logging_temperature,
00052 bool enable_logging_magnetic_field,
00053 bool enable_logging_pressure,
00054 bool enable_logging_battery,
00055 bool enable_logging_packets)
00056 : m_cf(link_uri)
00057 , m_tf_prefix(tf_prefix)
00058 , m_isEmergency(false)
00059 , m_roll_trim(roll_trim)
00060 , m_pitch_trim(pitch_trim)
00061 , m_enableLogging(enable_logging)
00062 , m_enableParameters(enable_parameters)
00063 , m_logBlocks(log_blocks)
00064 , m_use_ros_time(use_ros_time)
00065 , m_enable_logging_imu(enable_logging_imu)
00066 , m_enable_logging_temperature(enable_logging_temperature)
00067 , m_enable_logging_magnetic_field(enable_logging_magnetic_field)
00068 , m_enable_logging_pressure(enable_logging_pressure)
00069 , m_enable_logging_battery(enable_logging_battery)
00070 , m_enable_logging_packets(enable_logging_packets)
00071 , m_serviceEmergency()
00072 , m_serviceUpdateParams()
00073 , m_subscribeCmdVel()
00074 , m_subscribeExternalPosition()
00075 , m_pubImu()
00076 , m_pubTemp()
00077 , m_pubMag()
00078 , m_pubPressure()
00079 , m_pubBattery()
00080 , m_pubRssi()
00081 , m_sentSetpoint(false)
00082 , m_sentExternalPosition(false)
00083 {
00084 ros::NodeHandle n;
00085 m_subscribeCmdVel = n.subscribe(tf_prefix + "/cmd_vel", 1, &CrazyflieROS::cmdVelChanged, this);
00086 m_subscribeExternalPosition = n.subscribe(tf_prefix + "/external_position", 1, &CrazyflieROS::positionMeasurementChanged, this);
00087 m_serviceEmergency = n.advertiseService(tf_prefix + "/emergency", &CrazyflieROS::emergency, this);
00088
00089 if (m_enable_logging_imu) {
00090 m_pubImu = n.advertise<sensor_msgs::Imu>(tf_prefix + "/imu", 10);
00091 }
00092 if (m_enable_logging_temperature) {
00093 m_pubTemp = n.advertise<sensor_msgs::Temperature>(tf_prefix + "/temperature", 10);
00094 }
00095 if (m_enable_logging_magnetic_field) {
00096 m_pubMag = n.advertise<sensor_msgs::MagneticField>(tf_prefix + "/magnetic_field", 10);
00097 }
00098 if (m_enable_logging_pressure) {
00099 m_pubPressure = n.advertise<std_msgs::Float32>(tf_prefix + "/pressure", 10);
00100 }
00101 if (m_enable_logging_battery) {
00102 m_pubBattery = n.advertise<std_msgs::Float32>(tf_prefix + "/battery", 10);
00103 }
00104 if (m_enable_logging_packets) {
00105 m_pubPackets = n.advertise<crazyflie_driver::crtpPacket>(tf_prefix + "/packets", 10);
00106 }
00107 m_pubRssi = n.advertise<std_msgs::Float32>(tf_prefix + "/rssi", 10);
00108
00109 for (auto& logBlock : m_logBlocks)
00110 {
00111 m_pubLogDataGeneric.push_back(n.advertise<crazyflie_driver::GenericLogData>(tf_prefix + "/" + logBlock.topic_name, 10));
00112 }
00113
00114 m_sendPacketServer = n.advertiseService(tf_prefix + "/send_packet" , &CrazyflieROS::sendPacket, this);
00115
00116 m_thread = std::thread(&CrazyflieROS::run, this);
00117 }
00118
00119 void stop()
00120 {
00121 ROS_INFO("Disconnecting ...");
00122 m_isEmergency = true;
00123 m_thread.join();
00124 }
00125
00132 bool sendPacket (
00133 crazyflie_driver::sendPacket::Request &req,
00134 crazyflie_driver::sendPacket::Response &res)
00135 {
00137 crtpPacket_t packet;
00138 packet.size = req.packet.size;
00139 packet.header = req.packet.header;
00140 for (int i = 0; i < CRTP_MAX_DATA_SIZE; i++) {
00141 packet.data[i] = req.packet.data[i];
00142 }
00143 m_cf.queueOutgoingPacket(packet);
00144 return true;
00145 }
00146
00147 private:
00148 ros::ServiceServer m_sendPacketServer;
00149
00154 void publishPackets() {
00155 std::vector<Crazyradio::Ack> packets = m_cf.retrieveGenericPackets();
00156 if (!packets.empty())
00157 {
00158 std::vector<Crazyradio::Ack>::iterator it;
00159 for (it = packets.begin(); it != packets.end(); it++)
00160 {
00161 crazyflie_driver::crtpPacket packet;
00162 packet.size = it->size;
00163 packet.header = it->data[0];
00164 for(int i = 0; i < packet.size; i++)
00165 {
00166 packet.data[i] = it->data[i+1];
00167 }
00168 m_pubPackets.publish(packet);
00169 }
00170 }
00171 }
00172
00173 private:
00174 struct logImu {
00175 float acc_x;
00176 float acc_y;
00177 float acc_z;
00178 float gyro_x;
00179 float gyro_y;
00180 float gyro_z;
00181 } __attribute__((packed));
00182
00183 struct log2 {
00184 float mag_x;
00185 float mag_y;
00186 float mag_z;
00187 float baro_temp;
00188 float baro_pressure;
00189 float pm_vbat;
00190 } __attribute__((packed));
00191
00192 private:
00193 bool emergency(
00194 std_srvs::Empty::Request& req,
00195 std_srvs::Empty::Response& res)
00196 {
00197 ROS_FATAL("Emergency requested!");
00198 m_isEmergency = true;
00199
00200 return true;
00201 }
00202
00203 template<class T, class U>
00204 void updateParam(uint8_t id, const std::string& ros_param) {
00205 U value;
00206 ros::param::get(ros_param, value);
00207 m_cf.setParam<T>(id, (T)value);
00208 }
00209
00210 bool updateParams(
00211 crazyflie_driver::UpdateParams::Request& req,
00212 crazyflie_driver::UpdateParams::Response& res)
00213 {
00214 ROS_INFO("Update parameters");
00215 for (auto&& p : req.params) {
00216 std::string ros_param = "/" + m_tf_prefix + "/" + p;
00217 size_t pos = p.find("/");
00218 std::string group(p.begin(), p.begin() + pos);
00219 std::string name(p.begin() + pos + 1, p.end());
00220
00221 auto entry = m_cf.getParamTocEntry(group, name);
00222 if (entry)
00223 {
00224 switch (entry->type) {
00225 case Crazyflie::ParamTypeUint8:
00226 updateParam<uint8_t, int>(entry->id, ros_param);
00227 break;
00228 case Crazyflie::ParamTypeInt8:
00229 updateParam<int8_t, int>(entry->id, ros_param);
00230 break;
00231 case Crazyflie::ParamTypeUint16:
00232 updateParam<uint16_t, int>(entry->id, ros_param);
00233 break;
00234 case Crazyflie::ParamTypeInt16:
00235 updateParam<int16_t, int>(entry->id, ros_param);
00236 break;
00237 case Crazyflie::ParamTypeUint32:
00238 updateParam<uint32_t, int>(entry->id, ros_param);
00239 break;
00240 case Crazyflie::ParamTypeInt32:
00241 updateParam<int32_t, int>(entry->id, ros_param);
00242 break;
00243 case Crazyflie::ParamTypeFloat:
00244 updateParam<float, float>(entry->id, ros_param);
00245 break;
00246 }
00247 }
00248 else {
00249 ROS_ERROR("Could not find param %s/%s", group.c_str(), name.c_str());
00250 }
00251 }
00252 return true;
00253 }
00254
00255 void cmdVelChanged(
00256 const geometry_msgs::Twist::ConstPtr& msg)
00257 {
00258 if (!m_isEmergency) {
00259 float roll = msg->linear.y + m_roll_trim;
00260 float pitch = - (msg->linear.x + m_pitch_trim);
00261 float yawrate = msg->angular.z;
00262 uint16_t thrust = std::min<uint16_t>(std::max<float>(msg->linear.z, 0.0), 60000);
00263
00264 m_cf.sendSetpoint(roll, pitch, yawrate, thrust);
00265 m_sentSetpoint = true;
00266 }
00267 }
00268
00269 void positionMeasurementChanged(
00270 const geometry_msgs::PointStamped::ConstPtr& msg)
00271 {
00272 m_cf.sendExternalPositionUpdate(msg->point.x, msg->point.y, msg->point.z);
00273 m_sentExternalPosition = true;
00274 }
00275
00276 void run()
00277 {
00278
00279
00280 auto start = std::chrono::system_clock::now();
00281
00282 m_cf.logReset();
00283
00284 std::function<void(float)> cb_lq = std::bind(&CrazyflieROS::onLinkQuality, this, std::placeholders::_1);
00285 m_cf.setLinkQualityCallback(cb_lq);
00286
00287
00288
00289 if (m_enableParameters)
00290 {
00291 ROS_INFO("Requesting parameters...");
00292 m_cf.requestParamToc();
00293 for (auto iter = m_cf.paramsBegin(); iter != m_cf.paramsEnd(); ++iter) {
00294 auto entry = *iter;
00295 std::string paramName = "/" + m_tf_prefix + "/" + entry.group + "/" + entry.name;
00296 switch (entry.type) {
00297 case Crazyflie::ParamTypeUint8:
00298 ros::param::set(paramName, m_cf.getParam<uint8_t>(entry.id));
00299 break;
00300 case Crazyflie::ParamTypeInt8:
00301 ros::param::set(paramName, m_cf.getParam<int8_t>(entry.id));
00302 break;
00303 case Crazyflie::ParamTypeUint16:
00304 ros::param::set(paramName, m_cf.getParam<uint16_t>(entry.id));
00305 break;
00306 case Crazyflie::ParamTypeInt16:
00307 ros::param::set(paramName, m_cf.getParam<int16_t>(entry.id));
00308 break;
00309 case Crazyflie::ParamTypeUint32:
00310 ros::param::set(paramName, (int)m_cf.getParam<uint32_t>(entry.id));
00311 break;
00312 case Crazyflie::ParamTypeInt32:
00313 ros::param::set(paramName, m_cf.getParam<int32_t>(entry.id));
00314 break;
00315 case Crazyflie::ParamTypeFloat:
00316 ros::param::set(paramName, m_cf.getParam<float>(entry.id));
00317 break;
00318 }
00319 }
00320 ros::NodeHandle n;
00321 m_serviceUpdateParams = n.advertiseService(m_tf_prefix + "/update_params", &CrazyflieROS::updateParams, this);
00322 }
00323
00324 std::unique_ptr<LogBlock<logImu> > logBlockImu;
00325 std::unique_ptr<LogBlock<log2> > logBlock2;
00326 std::vector<std::unique_ptr<LogBlockGeneric> > logBlocksGeneric(m_logBlocks.size());
00327 if (m_enableLogging) {
00328
00329 std::function<void(const crtpPlatformRSSIAck*)> cb_ack = std::bind(&CrazyflieROS::onEmptyAck, this, std::placeholders::_1);
00330 m_cf.setEmptyAckCallback(cb_ack);
00331
00332 ROS_INFO("Requesting Logging variables...");
00333 m_cf.requestLogToc();
00334
00335 if (m_enable_logging_imu) {
00336 std::function<void(uint32_t, logImu*)> cb = std::bind(&CrazyflieROS::onImuData, this, std::placeholders::_1, std::placeholders::_2);
00337
00338 logBlockImu.reset(new LogBlock<logImu>(
00339 &m_cf,{
00340 {"acc", "x"},
00341 {"acc", "y"},
00342 {"acc", "z"},
00343 {"gyro", "x"},
00344 {"gyro", "y"},
00345 {"gyro", "z"},
00346 }, cb));
00347 logBlockImu->start(1);
00348 }
00349
00350 if ( m_enable_logging_temperature
00351 || m_enable_logging_magnetic_field
00352 || m_enable_logging_pressure
00353 || m_enable_logging_battery)
00354 {
00355 std::function<void(uint32_t, log2*)> cb2 = std::bind(&CrazyflieROS::onLog2Data, this, std::placeholders::_1, std::placeholders::_2);
00356
00357 logBlock2.reset(new LogBlock<log2>(
00358 &m_cf,{
00359 {"mag", "x"},
00360 {"mag", "y"},
00361 {"mag", "z"},
00362 {"baro", "temp"},
00363 {"baro", "pressure"},
00364 {"pm", "vbat"},
00365 }, cb2));
00366 logBlock2->start(10);
00367 }
00368
00369
00370 size_t i = 0;
00371 for (auto& logBlock : m_logBlocks)
00372 {
00373 std::function<void(uint32_t, std::vector<double>*, void* userData)> cb =
00374 std::bind(
00375 &CrazyflieROS::onLogCustom,
00376 this,
00377 std::placeholders::_1,
00378 std::placeholders::_2,
00379 std::placeholders::_3);
00380
00381 logBlocksGeneric[i].reset(new LogBlockGeneric(
00382 &m_cf,
00383 logBlock.variables,
00384 (void*)&m_pubLogDataGeneric[i],
00385 cb));
00386 logBlocksGeneric[i]->start(logBlock.frequency / 10);
00387 ++i;
00388 }
00389
00390
00391 }
00392
00393 ROS_INFO("Ready...");
00394 auto end = std::chrono::system_clock::now();
00395 std::chrono::duration<double> elapsedSeconds = end-start;
00396 ROS_INFO("Elapsed: %f s", elapsedSeconds.count());
00397
00398
00399 for (int i = 0; i < 100; ++i) {
00400 m_cf.sendSetpoint(0, 0, 0, 0);
00401 }
00402
00403 while(!m_isEmergency) {
00404
00405 if (m_enableLogging && !m_sentSetpoint && !m_sentExternalPosition) {
00406 m_cf.transmitPackets();
00407 m_cf.sendPing();
00408 if(m_enable_logging_packets) {
00409 this->publishPackets();
00410 }
00411 }
00412 m_sentSetpoint = false;
00413 m_sentExternalPosition = false;
00414 std::this_thread::sleep_for(std::chrono::milliseconds(1));
00415 }
00416
00417
00418 for (int i = 0; i < 100; ++i) {
00419 m_cf.sendSetpoint(0, 0, 0, 0);
00420 }
00421
00422 }
00423
00424 void onImuData(uint32_t time_in_ms, logImu* data) {
00425 if (m_enable_logging_imu) {
00426 sensor_msgs::Imu msg;
00427 if (m_use_ros_time) {
00428 msg.header.stamp = ros::Time::now();
00429 } else {
00430 msg.header.stamp = ros::Time(time_in_ms / 1000.0);
00431 }
00432 msg.header.frame_id = m_tf_prefix + "/base_link";
00433 msg.orientation_covariance[0] = -1;
00434
00435
00436 msg.angular_velocity.x = degToRad(data->gyro_x);
00437 msg.angular_velocity.y = degToRad(data->gyro_y);
00438 msg.angular_velocity.z = degToRad(data->gyro_z);
00439
00440
00441 msg.linear_acceleration.x = data->acc_x * 9.81;
00442 msg.linear_acceleration.y = data->acc_y * 9.81;
00443 msg.linear_acceleration.z = data->acc_z * 9.81;
00444
00445 m_pubImu.publish(msg);
00446 }
00447 }
00448
00449 void onLog2Data(uint32_t time_in_ms, log2* data) {
00450
00451 if (m_enable_logging_temperature) {
00452 sensor_msgs::Temperature msg;
00453 if (m_use_ros_time) {
00454 msg.header.stamp = ros::Time::now();
00455 } else {
00456 msg.header.stamp = ros::Time(time_in_ms / 1000.0);
00457 }
00458 msg.header.frame_id = m_tf_prefix + "/base_link";
00459
00460 msg.temperature = data->baro_temp;
00461 m_pubTemp.publish(msg);
00462 }
00463
00464 if (m_enable_logging_magnetic_field) {
00465 sensor_msgs::MagneticField msg;
00466 if (m_use_ros_time) {
00467 msg.header.stamp = ros::Time::now();
00468 } else {
00469 msg.header.stamp = ros::Time(time_in_ms / 1000.0);
00470 }
00471 msg.header.frame_id = m_tf_prefix + "/base_link";
00472
00473
00474 msg.magnetic_field.x = data->mag_x;
00475 msg.magnetic_field.y = data->mag_y;
00476 msg.magnetic_field.z = data->mag_z;
00477 m_pubMag.publish(msg);
00478 }
00479
00480 if (m_enable_logging_pressure) {
00481 std_msgs::Float32 msg;
00482
00483 msg.data = data->baro_pressure;
00484 m_pubPressure.publish(msg);
00485 }
00486
00487 if (m_enable_logging_battery) {
00488 std_msgs::Float32 msg;
00489
00490 msg.data = data->pm_vbat;
00491 m_pubBattery.publish(msg);
00492 }
00493 }
00494
00495 void onLogCustom(uint32_t time_in_ms, std::vector<double>* values, void* userData) {
00496
00497 ros::Publisher* pub = reinterpret_cast<ros::Publisher*>(userData);
00498
00499 crazyflie_driver::GenericLogData msg;
00500 if (m_use_ros_time) {
00501 msg.header.stamp = ros::Time::now();
00502 } else {
00503 msg.header.stamp = ros::Time(time_in_ms / 1000.0);
00504 }
00505 msg.header.frame_id = m_tf_prefix + "/base_link";
00506 msg.values = *values;
00507
00508 pub->publish(msg);
00509 }
00510
00511 void onEmptyAck(const crtpPlatformRSSIAck* data) {
00512 std_msgs::Float32 msg;
00513
00514 msg.data = data->rssi;
00515 m_pubRssi.publish(msg);
00516 }
00517
00518 void onLinkQuality(float linkQuality) {
00519 if (linkQuality < 0.7) {
00520 ROS_WARN("Link Quality low (%f)", linkQuality);
00521 }
00522 }
00523
00524 private:
00525 Crazyflie m_cf;
00526 std::string m_tf_prefix;
00527 bool m_isEmergency;
00528 float m_roll_trim;
00529 float m_pitch_trim;
00530 bool m_enableLogging;
00531 bool m_enableParameters;
00532 std::vector<crazyflie_driver::LogBlock> m_logBlocks;
00533 bool m_use_ros_time;
00534 bool m_enable_logging_imu;
00535 bool m_enable_logging_temperature;
00536 bool m_enable_logging_magnetic_field;
00537 bool m_enable_logging_pressure;
00538 bool m_enable_logging_battery;
00539 bool m_enable_logging_packets;
00540
00541 ros::ServiceServer m_serviceEmergency;
00542 ros::ServiceServer m_serviceUpdateParams;
00543 ros::Subscriber m_subscribeCmdVel;
00544 ros::Subscriber m_subscribeExternalPosition;
00545 ros::Publisher m_pubImu;
00546 ros::Publisher m_pubTemp;
00547 ros::Publisher m_pubMag;
00548 ros::Publisher m_pubPressure;
00549 ros::Publisher m_pubBattery;
00550 ros::Publisher m_pubPackets;
00551 ros::Publisher m_pubRssi;
00552 std::vector<ros::Publisher> m_pubLogDataGeneric;
00553
00554 bool m_sentSetpoint, m_sentExternalPosition;
00555
00556 std::thread m_thread;
00557 };
00558
00559 static std::map<std::string, CrazyflieROS*> crazyflies;
00560
00561 bool add_crazyflie(
00562 crazyflie_driver::AddCrazyflie::Request &req,
00563 crazyflie_driver::AddCrazyflie::Response &res)
00564 {
00565 ROS_INFO("Adding %s as %s with trim(%f, %f). Logging: %d, Parameters: %d, Use ROS time: %d",
00566 req.uri.c_str(),
00567 req.tf_prefix.c_str(),
00568 req.roll_trim,
00569 req.pitch_trim,
00570 req.enable_parameters,
00571 req.enable_logging,
00572 req.use_ros_time);
00573
00574
00575 if (crazyflies.find(req.uri) != crazyflies.end()) {
00576 ROS_ERROR("Cannot add %s, already added.", req.uri.c_str());
00577 return false;
00578 }
00579
00580 CrazyflieROS* cf = new CrazyflieROS(
00581 req.uri,
00582 req.tf_prefix,
00583 req.roll_trim,
00584 req.pitch_trim,
00585 req.enable_logging,
00586 req.enable_parameters,
00587 req.log_blocks,
00588 req.use_ros_time,
00589 req.enable_logging_imu,
00590 req.enable_logging_temperature,
00591 req.enable_logging_magnetic_field,
00592 req.enable_logging_pressure,
00593 req.enable_logging_battery,
00594 req.enable_logging_packets);
00595
00596 crazyflies[req.uri] = cf;
00597
00598 return true;
00599 }
00600
00601 bool remove_crazyflie(
00602 crazyflie_driver::RemoveCrazyflie::Request &req,
00603 crazyflie_driver::RemoveCrazyflie::Response &res)
00604 {
00605
00606 if (crazyflies.find(req.uri) == crazyflies.end()) {
00607 ROS_ERROR("Cannot remove %s, not connected.", req.uri.c_str());
00608 return false;
00609 }
00610
00611 ROS_INFO("Removing crazyflie at uri %s.", req.uri.c_str());
00612
00613 crazyflies[req.uri]->stop();
00614 delete crazyflies[req.uri];
00615 crazyflies.erase(req.uri);
00616
00617 ROS_INFO("Crazyflie %s removed.", req.uri.c_str());
00618
00619 return true;
00620 }
00621
00622 int main(int argc, char **argv)
00623 {
00624 ros::init(argc, argv, "crazyflie_server");
00625 ros::NodeHandle n;
00626
00627 ros::ServiceServer serviceAdd = n.advertiseService("add_crazyflie", add_crazyflie);
00628 ros::ServiceServer serviceRemove = n.advertiseService("remove_crazyflie", remove_crazyflie);
00629 ros::spin();
00630
00631 return 0;
00632 }