crazyflie_server.cpp
Go to the documentation of this file.
00001 #include <ros/ros.h>
00002 #include <ros/callback_queue.h>
00003 
00004 #include "crazyflie_driver/AddCrazyflie.h"
00005 #include "crazyflie_driver/GoTo.h"
00006 #include "crazyflie_driver/Land.h"
00007 #include "crazyflie_driver/RemoveCrazyflie.h"
00008 #include "crazyflie_driver/SetGroupMask.h"
00009 #include "crazyflie_driver/StartTrajectory.h"
00010 #include "crazyflie_driver/Stop.h"
00011 #include "crazyflie_driver/Takeoff.h"
00012 #include "crazyflie_driver/UpdateParams.h"
00013 #include "crazyflie_driver/UploadTrajectory.h"
00014 #include "crazyflie_driver/sendPacket.h"
00015 
00016 #include "crazyflie_driver/LogBlock.h"
00017 #include "crazyflie_driver/GenericLogData.h"
00018 #include "crazyflie_driver/FullState.h"
00019 #include "crazyflie_driver/Hover.h"
00020 #include "crazyflie_driver/Stop.h"
00021 #include "crazyflie_driver/Position.h"
00022 #include "crazyflie_driver/crtpPacket.h"
00023 #include "crazyflie_cpp/Crazyradio.h"
00024 #include "crazyflie_cpp/crtp.h"
00025 #include "std_srvs/Empty.h"
00026 #include <std_msgs/Empty.h>
00027 #include "geometry_msgs/Twist.h"
00028 #include "geometry_msgs/PointStamped.h"
00029 #include "geometry_msgs/PoseStamped.h"
00030 #include "sensor_msgs/Imu.h"
00031 #include "sensor_msgs/Temperature.h"
00032 #include "sensor_msgs/MagneticField.h"
00033 #include "std_msgs/Float32.h"
00034 
00035 //#include <regex>
00036 #include <thread>
00037 #include <mutex>
00038 
00039 #include <string>
00040 #include <map>
00041 
00042 #include <crazyflie_cpp/Crazyflie.h>
00043 
00044 constexpr double pi() { return 3.141592653589793238462643383279502884; }
00045 
00046 double degToRad(double deg) {
00047     return deg / 180.0 * pi();
00048 }
00049 
00050 double radToDeg(double rad) {
00051     return rad * 180.0 / pi();
00052 }
00053 
00054 class ROSLogger : public Logger
00055 {
00056 public:
00057   ROSLogger()
00058     : Logger()
00059   {
00060   }
00061 
00062   virtual ~ROSLogger() {}
00063 
00064   virtual void info(const std::string& msg)
00065   {
00066     ROS_INFO("%s", msg.c_str());
00067   }
00068 
00069   virtual void warning(const std::string& msg)
00070   {
00071     ROS_WARN("%s", msg.c_str());
00072   }
00073 
00074   virtual void error(const std::string& msg)
00075   {
00076     ROS_ERROR("%s", msg.c_str());
00077   }
00078 };
00079 
00080 static ROSLogger rosLogger;
00081 
00082 class CrazyflieROS
00083 {
00084 public:
00085   CrazyflieROS(
00086     const std::string& link_uri,
00087     const std::string& tf_prefix,
00088     float roll_trim,
00089     float pitch_trim,
00090     bool enable_logging,
00091     bool enable_parameters,
00092     std::vector<crazyflie_driver::LogBlock>& log_blocks,
00093     bool use_ros_time,
00094     bool enable_logging_imu,
00095     bool enable_logging_temperature,
00096     bool enable_logging_magnetic_field,
00097     bool enable_logging_pressure,
00098     bool enable_logging_battery,
00099     bool enable_logging_pose,
00100     bool enable_logging_packets)
00101     : m_tf_prefix(tf_prefix)
00102     , m_cf(
00103       link_uri,
00104       rosLogger,
00105       std::bind(&CrazyflieROS::onConsole, this, std::placeholders::_1))
00106     , m_isEmergency(false)
00107     , m_roll_trim(roll_trim)
00108     , m_pitch_trim(pitch_trim)
00109     , m_enableLogging(enable_logging)
00110     , m_enableParameters(enable_parameters)
00111     , m_logBlocks(log_blocks)
00112     , m_use_ros_time(use_ros_time)
00113     , m_enable_logging_imu(enable_logging_imu)
00114     , m_enable_logging_temperature(enable_logging_temperature)
00115     , m_enable_logging_magnetic_field(enable_logging_magnetic_field)
00116     , m_enable_logging_pressure(enable_logging_pressure)
00117     , m_enable_logging_battery(enable_logging_battery)
00118     , m_enable_logging_pose(enable_logging_pose)
00119     , m_enable_logging_packets(enable_logging_packets)
00120     , m_serviceEmergency()
00121     , m_serviceUpdateParams()
00122     , m_serviceSetGroupMask()
00123     , m_serviceTakeoff()
00124     , m_serviceLand()
00125     , m_serviceStop()
00126     , m_serviceGoTo()
00127     , m_serviceUploadTrajectory()
00128     , m_serviceStartTrajectory()
00129     , m_subscribeCmdVel()
00130     , m_subscribeCmdFullState()
00131     , m_subscribeCmdHover()
00132     , m_subscribeCmdStop()
00133     , m_subscribeCmdPosition()
00134     , m_subscribeExternalPosition()
00135     , m_pubImu()
00136     , m_pubTemp()
00137     , m_pubMag()
00138     , m_pubPressure()
00139     , m_pubBattery()
00140     , m_pubRssi()
00141     , m_sentSetpoint(false)
00142     , m_sentExternalPosition(false)
00143   {
00144     m_thread = std::thread(&CrazyflieROS::run, this);
00145   }
00146 
00147   void stop()
00148   {
00149     ROS_INFO_NAMED(m_tf_prefix, "Disconnecting ...");
00150     m_isEmergency = true;
00151     m_thread.join();
00152   }
00153 
00160   bool sendPacket (
00161     crazyflie_driver::sendPacket::Request &req,
00162     crazyflie_driver::sendPacket::Response &res)
00163   {
00165     crtpPacket_t packet;
00166     packet.size = req.packet.size;
00167     packet.header = req.packet.header;
00168     for (int i = 0; i < CRTP_MAX_DATA_SIZE; i++) {
00169       packet.data[i] = req.packet.data[i];
00170     }
00171     m_cf.queueOutgoingPacket(packet);
00172     return true;
00173   }
00174 
00175 private:
00176   struct logImu {
00177     float acc_x;
00178     float acc_y;
00179     float acc_z;
00180     float gyro_x;
00181     float gyro_y;
00182     float gyro_z;
00183   } __attribute__((packed));
00184 
00185   struct log2 {
00186     float mag_x;
00187     float mag_y;
00188     float mag_z;
00189     float baro_temp;
00190     float baro_pressure;
00191     float pm_vbat;
00192   } __attribute__((packed));
00193 
00194   struct logPose {
00195     float x;
00196     float y;
00197     float z;
00198     int32_t quatCompressed;
00199   } __attribute__((packed));
00200 
00201 private:
00202   bool emergency(
00203     std_srvs::Empty::Request& req,
00204     std_srvs::Empty::Response& res)
00205   {
00206     ROS_FATAL_NAMED(m_tf_prefix, "Emergency requested!");
00207     m_isEmergency = true;
00208     m_cf.emergencyStop();
00209 
00210     return true;
00211   }
00212 
00213   template<class T, class U>
00214   void updateParam(uint8_t id, const std::string& ros_param) {
00215       U value;
00216       ros::param::get(ros_param, value);
00217       m_cf.setParam<T>(id, (T)value);
00218   }
00219 
00220 void cmdHoverSetpoint(
00221     const crazyflie_driver::Hover::ConstPtr& msg)
00222   {
00223      //ROS_INFO("got a hover setpoint");
00224     if (!m_isEmergency) {
00225       float vx = msg->vx;
00226       float vy = msg->vy;
00227       float yawRate = msg->yawrate;
00228       float zDistance = msg->zDistance;
00229 
00230       m_cf.sendHoverSetpoint(vx, vy, yawRate, zDistance);
00231       m_sentSetpoint = true;
00232       //ROS_INFO("set a hover setpoint");
00233     }
00234   }
00235 
00236 void cmdStop(
00237     const std_msgs::Empty::ConstPtr& msg)
00238   {
00239      //ROS_INFO("got a stop setpoint");
00240     if (!m_isEmergency) {
00241       m_cf.sendStop();
00242       m_sentSetpoint = true;
00243       //ROS_INFO("set a stop setpoint");
00244     }
00245   }
00246 
00247 void cmdPositionSetpoint(
00248     const crazyflie_driver::Position::ConstPtr& msg)
00249   {
00250     if(!m_isEmergency) {
00251       float x = msg->x;
00252       float y = msg->y;
00253       float z = msg->z;
00254       float yaw = msg->yaw;
00255 
00256       m_cf.sendPositionSetpoint(x, y, z, yaw);
00257       m_sentSetpoint = true;
00258     }
00259   }
00260 
00261   bool updateParams(
00262     crazyflie_driver::UpdateParams::Request& req,
00263     crazyflie_driver::UpdateParams::Response& res)
00264   {
00265     ROS_INFO_NAMED(m_tf_prefix, "Update parameters");
00266     for (auto&& p : req.params) {
00267       std::string ros_param = "/" + m_tf_prefix + "/" + p;
00268       size_t pos = p.find("/");
00269       std::string group(p.begin(), p.begin() + pos);
00270       std::string name(p.begin() + pos + 1, p.end());
00271 
00272       auto entry = m_cf.getParamTocEntry(group, name);
00273       if (entry)
00274       {
00275         switch (entry->type) {
00276           case Crazyflie::ParamTypeUint8:
00277             updateParam<uint8_t, int>(entry->id, ros_param);
00278             break;
00279           case Crazyflie::ParamTypeInt8:
00280             updateParam<int8_t, int>(entry->id, ros_param);
00281             break;
00282           case Crazyflie::ParamTypeUint16:
00283             updateParam<uint16_t, int>(entry->id, ros_param);
00284             break;
00285           case Crazyflie::ParamTypeInt16:
00286             updateParam<int16_t, int>(entry->id, ros_param);
00287             break;
00288           case Crazyflie::ParamTypeUint32:
00289             updateParam<uint32_t, int>(entry->id, ros_param);
00290             break;
00291           case Crazyflie::ParamTypeInt32:
00292             updateParam<int32_t, int>(entry->id, ros_param);
00293             break;
00294           case Crazyflie::ParamTypeFloat:
00295             updateParam<float, float>(entry->id, ros_param);
00296             break;
00297         }
00298       }
00299       else {
00300         ROS_ERROR_NAMED(m_tf_prefix, "Could not find param %s/%s", group.c_str(), name.c_str());
00301       }
00302     }
00303     return true;
00304   }
00305 
00306   void cmdVelChanged(
00307     const geometry_msgs::Twist::ConstPtr& msg)
00308   {
00309     if (!m_isEmergency) {
00310       float roll = msg->linear.y + m_roll_trim;
00311       float pitch = - (msg->linear.x + m_pitch_trim);
00312       float yawrate = msg->angular.z;
00313       uint16_t thrust = std::min<uint16_t>(std::max<float>(msg->linear.z, 0.0), 60000);
00314 
00315       m_cf.sendSetpoint(roll, pitch, yawrate, thrust);
00316       m_sentSetpoint = true;
00317     }
00318   }
00319 
00320   void cmdFullStateSetpoint(
00321     const crazyflie_driver::FullState::ConstPtr& msg)
00322   {
00323     //ROS_INFO("got a full state setpoint");
00324     if (!m_isEmergency) {
00325       float x = msg->pose.position.x;
00326       float y = msg->pose.position.y;
00327       float z = msg->pose.position.z;
00328       float vx = msg->twist.linear.x;
00329       float vy = msg->twist.linear.y;
00330       float vz = msg->twist.linear.z;
00331       float ax = msg->acc.x;
00332       float ay = msg->acc.y;
00333       float az = msg->acc.z;
00334 
00335       float qx = msg->pose.orientation.x;
00336       float qy = msg->pose.orientation.y;
00337       float qz = msg->pose.orientation.z;
00338       float qw = msg->pose.orientation.w;
00339       float rollRate = msg->twist.angular.x;
00340       float pitchRate = msg->twist.angular.y;
00341       float yawRate = msg->twist.angular.z;
00342 
00343       m_cf.sendFullStateSetpoint(
00344         x, y, z,
00345         vx, vy, vz,
00346         ax, ay, az,
00347         qx, qy, qz, qw,
00348         rollRate, pitchRate, yawRate);
00349       m_sentSetpoint = true;
00350       //ROS_INFO("set a full state setpoint");
00351     }
00352   }
00353 
00354   void positionMeasurementChanged(
00355     const geometry_msgs::PointStamped::ConstPtr& msg)
00356   {
00357     m_cf.sendExternalPositionUpdate(msg->point.x, msg->point.y, msg->point.z);
00358     m_sentExternalPosition = true;
00359   }
00360 
00361   void poseMeasurementChanged(
00362     const geometry_msgs::PoseStamped::ConstPtr& msg)
00363   {
00364     m_cf.sendExternalPoseUpdate(
00365       msg->pose.position.x, msg->pose.position.y, msg->pose.position.z,
00366       msg->pose.orientation.x, msg->pose.orientation.y, msg->pose.orientation.z, msg->pose.orientation.w);
00367     m_sentExternalPosition = true;
00368   }
00369 
00370   void run()
00371   {
00372     ros::NodeHandle n;
00373     n.setCallbackQueue(&m_callback_queue);
00374 
00375     m_subscribeCmdVel = n.subscribe(m_tf_prefix + "/cmd_vel", 1, &CrazyflieROS::cmdVelChanged, this);
00376     m_subscribeCmdFullState = n.subscribe(m_tf_prefix + "/cmd_full_state", 1, &CrazyflieROS::cmdFullStateSetpoint, this);
00377     m_subscribeExternalPosition = n.subscribe(m_tf_prefix + "/external_position", 1, &CrazyflieROS::positionMeasurementChanged, this);
00378     m_subscribeExternalPose = n.subscribe(m_tf_prefix + "/external_pose", 1, &CrazyflieROS::poseMeasurementChanged, this);
00379     m_serviceEmergency = n.advertiseService(m_tf_prefix + "/emergency", &CrazyflieROS::emergency, this);
00380     m_subscribeCmdHover = n.subscribe(m_tf_prefix + "/cmd_hover", 1, &CrazyflieROS::cmdHoverSetpoint, this);
00381     m_subscribeCmdStop = n.subscribe(m_tf_prefix + "/cmd_stop", 1, &CrazyflieROS::cmdStop, this);
00382     m_subscribeCmdPosition = n.subscribe(m_tf_prefix + "/cmd_position", 1, &CrazyflieROS::cmdPositionSetpoint, this);
00383 
00384 
00385     m_serviceSetGroupMask = n.advertiseService(m_tf_prefix + "/set_group_mask", &CrazyflieROS::setGroupMask, this);
00386     m_serviceTakeoff = n.advertiseService(m_tf_prefix + "/takeoff", &CrazyflieROS::takeoff, this);
00387     m_serviceLand = n.advertiseService(m_tf_prefix + "/land", &CrazyflieROS::land, this);
00388     m_serviceStop = n.advertiseService(m_tf_prefix + "/stop", &CrazyflieROS::stop, this);
00389     m_serviceGoTo = n.advertiseService(m_tf_prefix + "/go_to", &CrazyflieROS::goTo, this);
00390     m_serviceUploadTrajectory = n.advertiseService(m_tf_prefix + "/upload_trajectory", &CrazyflieROS::uploadTrajectory, this);
00391     m_serviceStartTrajectory = n.advertiseService(m_tf_prefix + "/start_trajectory", &CrazyflieROS::startTrajectory, this);
00392 
00393     if (m_enable_logging_imu) {
00394       m_pubImu = n.advertise<sensor_msgs::Imu>(m_tf_prefix + "/imu", 10);
00395     }
00396     if (m_enable_logging_temperature) {
00397       m_pubTemp = n.advertise<sensor_msgs::Temperature>(m_tf_prefix + "/temperature", 10);
00398     }
00399     if (m_enable_logging_magnetic_field) {
00400       m_pubMag = n.advertise<sensor_msgs::MagneticField>(m_tf_prefix + "/magnetic_field", 10);
00401     }
00402     if (m_enable_logging_pressure) {
00403       m_pubPressure = n.advertise<std_msgs::Float32>(m_tf_prefix + "/pressure", 10);
00404     }
00405     if (m_enable_logging_battery) {
00406       m_pubBattery = n.advertise<std_msgs::Float32>(m_tf_prefix + "/battery", 10);
00407     }
00408     if (m_enable_logging_pose) {
00409       m_pubPose = n.advertise<geometry_msgs::PoseStamped>(m_tf_prefix + "/pose", 10);
00410     }
00411     if (m_enable_logging_packets) {
00412       m_pubPackets = n.advertise<crazyflie_driver::crtpPacket>(m_tf_prefix + "/packets", 10);
00413       std::function<void(const ITransport::Ack&)> cb_genericPacket = std::bind(&CrazyflieROS::onGenericPacket, this, std::placeholders::_1);
00414       m_cf.setGenericPacketCallback(cb_genericPacket);
00415     }
00416     m_pubRssi = n.advertise<std_msgs::Float32>(m_tf_prefix + "/rssi", 10);
00417 
00418     for (auto& logBlock : m_logBlocks)
00419     {
00420       m_pubLogDataGeneric.push_back(n.advertise<crazyflie_driver::GenericLogData>(m_tf_prefix + "/" + logBlock.topic_name, 10));
00421     }
00422 
00423     m_sendPacketServer = n.advertiseService(m_tf_prefix + "/send_packet"  , &CrazyflieROS::sendPacket, this);
00424 
00425     // m_cf.reboot();
00426 
00427     auto start = std::chrono::system_clock::now();
00428 
00429     m_cf.logReset();
00430 
00431     std::function<void(float)> cb_lq = std::bind(&CrazyflieROS::onLinkQuality, this, std::placeholders::_1);
00432     m_cf.setLinkQualityCallback(cb_lq);
00433 
00434     if (m_enableParameters)
00435     {
00436       ROS_INFO_NAMED(m_tf_prefix, "Requesting parameters...");
00437       m_cf.requestParamToc();
00438       for (auto iter = m_cf.paramsBegin(); iter != m_cf.paramsEnd(); ++iter) {
00439         auto entry = *iter;
00440         std::string paramName = "/" + m_tf_prefix + "/" + entry.group + "/" + entry.name;
00441         switch (entry.type) {
00442           case Crazyflie::ParamTypeUint8:
00443             ros::param::set(paramName, m_cf.getParam<uint8_t>(entry.id));
00444             break;
00445           case Crazyflie::ParamTypeInt8:
00446             ros::param::set(paramName, m_cf.getParam<int8_t>(entry.id));
00447             break;
00448           case Crazyflie::ParamTypeUint16:
00449             ros::param::set(paramName, m_cf.getParam<uint16_t>(entry.id));
00450             break;
00451           case Crazyflie::ParamTypeInt16:
00452             ros::param::set(paramName, m_cf.getParam<int16_t>(entry.id));
00453             break;
00454           case Crazyflie::ParamTypeUint32:
00455             ros::param::set(paramName, (int)m_cf.getParam<uint32_t>(entry.id));
00456             break;
00457           case Crazyflie::ParamTypeInt32:
00458             ros::param::set(paramName, m_cf.getParam<int32_t>(entry.id));
00459             break;
00460           case Crazyflie::ParamTypeFloat:
00461             ros::param::set(paramName, m_cf.getParam<float>(entry.id));
00462             break;
00463         }
00464       }
00465       m_serviceUpdateParams = n.advertiseService(m_tf_prefix + "/update_params", &CrazyflieROS::updateParams, this);
00466     }
00467 
00468     std::unique_ptr<LogBlock<logImu> > logBlockImu;
00469     std::unique_ptr<LogBlock<log2> > logBlock2;
00470     std::unique_ptr<LogBlock<logPose> > logBlockPose;
00471     std::vector<std::unique_ptr<LogBlockGeneric> > logBlocksGeneric(m_logBlocks.size());
00472     if (m_enableLogging) {
00473 
00474       std::function<void(const crtpPlatformRSSIAck*)> cb_ack = std::bind(&CrazyflieROS::onEmptyAck, this, std::placeholders::_1);
00475       m_cf.setEmptyAckCallback(cb_ack);
00476 
00477       ROS_INFO_NAMED(m_tf_prefix, "Requesting Logging variables...");
00478       m_cf.requestLogToc();
00479 
00480       if (m_enable_logging_imu) {
00481         std::function<void(uint32_t, logImu*)> cb = std::bind(&CrazyflieROS::onImuData, this, std::placeholders::_1, std::placeholders::_2);
00482 
00483         logBlockImu.reset(new LogBlock<logImu>(
00484           &m_cf,{
00485             {"acc", "x"},
00486             {"acc", "y"},
00487             {"acc", "z"},
00488             {"gyro", "x"},
00489             {"gyro", "y"},
00490             {"gyro", "z"},
00491           }, cb));
00492         logBlockImu->start(1); // 10ms
00493       }
00494 
00495       if (   m_enable_logging_temperature
00496           || m_enable_logging_magnetic_field
00497           || m_enable_logging_pressure
00498           || m_enable_logging_battery)
00499       {
00500         std::function<void(uint32_t, log2*)> cb2 = std::bind(&CrazyflieROS::onLog2Data, this, std::placeholders::_1, std::placeholders::_2);
00501 
00502         logBlock2.reset(new LogBlock<log2>(
00503           &m_cf,{
00504             {"mag", "x"},
00505             {"mag", "y"},
00506             {"mag", "z"},
00507             {"baro", "temp"},
00508             {"baro", "pressure"},
00509             {"pm", "vbat"},
00510           }, cb2));
00511         logBlock2->start(10); // 100ms
00512       }
00513 
00514       if (m_enable_logging_pose) {
00515         std::function<void(uint32_t, logPose*)> cb = std::bind(&CrazyflieROS::onPoseData, this, std::placeholders::_1, std::placeholders::_2);
00516 
00517         logBlockPose.reset(new LogBlock<logPose>(
00518           &m_cf,{
00519             {"stateEstimate", "x"},
00520             {"stateEstimate", "y"},
00521             {"stateEstimate", "z"},
00522             {"stateEstimateZ", "quat"}
00523           }, cb));
00524         logBlockPose->start(1); // 10ms
00525       }
00526 
00527       // custom log blocks
00528       size_t i = 0;
00529       for (auto& logBlock : m_logBlocks)
00530       {
00531         std::function<void(uint32_t, std::vector<double>*, void* userData)> cb =
00532           std::bind(
00533             &CrazyflieROS::onLogCustom,
00534             this,
00535             std::placeholders::_1,
00536             std::placeholders::_2,
00537             std::placeholders::_3);
00538 
00539         logBlocksGeneric[i].reset(new LogBlockGeneric(
00540           &m_cf,
00541           logBlock.variables,
00542           (void*)&m_pubLogDataGeneric[i],
00543           cb));
00544         logBlocksGeneric[i]->start(logBlock.frequency / 10);
00545         ++i;
00546       }
00547 
00548 
00549     }
00550 
00551     ROS_INFO_NAMED(m_tf_prefix, "Requesting memories...");
00552     m_cf.requestMemoryToc();
00553 
00554     ROS_INFO_NAMED(m_tf_prefix, "Ready...");
00555     auto end = std::chrono::system_clock::now();
00556     std::chrono::duration<double> elapsedSeconds = end-start;
00557     ROS_INFO_NAMED(m_tf_prefix, "Elapsed: %f s", elapsedSeconds.count());
00558 
00559     // Send 0 thrust initially for thrust-lock
00560     for (int i = 0; i < 100; ++i) {
00561        m_cf.sendSetpoint(0, 0, 0, 0);
00562     }
00563 
00564     while(!m_isEmergency) {
00565       // make sure we ping often enough to stream data out
00566       if (m_enableLogging && !m_sentSetpoint && !m_sentExternalPosition) {
00567         m_cf.transmitPackets();
00568         m_cf.sendPing();
00569       }
00570       m_sentSetpoint = false;
00571       m_sentExternalPosition = false;
00572 
00573       // Execute any ROS related functions now
00574       m_callback_queue.callAvailable(ros::WallDuration(0.0));
00575       std::this_thread::sleep_for(std::chrono::milliseconds(1));
00576     }
00577 
00578     // Make sure we turn the engines off
00579     for (int i = 0; i < 100; ++i) {
00580        m_cf.sendSetpoint(0, 0, 0, 0);
00581     }
00582 
00583   }
00584 
00585   void onImuData(uint32_t time_in_ms, logImu* data) {
00586     if (m_enable_logging_imu) {
00587       sensor_msgs::Imu msg;
00588       if (m_use_ros_time) {
00589         msg.header.stamp = ros::Time::now();
00590       } else {
00591         msg.header.stamp = ros::Time(time_in_ms / 1000.0);
00592       }
00593       msg.header.frame_id = m_tf_prefix + "/base_link";
00594       msg.orientation_covariance[0] = -1;
00595 
00596       // measured in deg/s; need to convert to rad/s
00597       msg.angular_velocity.x = degToRad(data->gyro_x);
00598       msg.angular_velocity.y = degToRad(data->gyro_y);
00599       msg.angular_velocity.z = degToRad(data->gyro_z);
00600 
00601       // measured in mG; need to convert to m/s^2
00602       msg.linear_acceleration.x = data->acc_x * 9.81;
00603       msg.linear_acceleration.y = data->acc_y * 9.81;
00604       msg.linear_acceleration.z = data->acc_z * 9.81;
00605 
00606       m_pubImu.publish(msg);
00607     }
00608   }
00609 
00610   void onLog2Data(uint32_t time_in_ms, log2* data) {
00611 
00612     if (m_enable_logging_temperature) {
00613       sensor_msgs::Temperature msg;
00614       if (m_use_ros_time) {
00615         msg.header.stamp = ros::Time::now();
00616       } else {
00617         msg.header.stamp = ros::Time(time_in_ms / 1000.0);
00618       }
00619       msg.header.frame_id = m_tf_prefix + "/base_link";
00620       // measured in degC
00621       msg.temperature = data->baro_temp;
00622       m_pubTemp.publish(msg);
00623     }
00624 
00625     if (m_enable_logging_magnetic_field) {
00626       sensor_msgs::MagneticField msg;
00627       if (m_use_ros_time) {
00628         msg.header.stamp = ros::Time::now();
00629       } else {
00630         msg.header.stamp = ros::Time(time_in_ms / 1000.0);
00631       }
00632       msg.header.frame_id = m_tf_prefix + "/base_link";
00633 
00634       // measured in Tesla
00635       msg.magnetic_field.x = data->mag_x;
00636       msg.magnetic_field.y = data->mag_y;
00637       msg.magnetic_field.z = data->mag_z;
00638       m_pubMag.publish(msg);
00639     }
00640 
00641     if (m_enable_logging_pressure) {
00642       std_msgs::Float32 msg;
00643       // hPa (=mbar)
00644       msg.data = data->baro_pressure;
00645       m_pubPressure.publish(msg);
00646     }
00647 
00648     if (m_enable_logging_battery) {
00649       std_msgs::Float32 msg;
00650       // V
00651       msg.data = data->pm_vbat;
00652       m_pubBattery.publish(msg);
00653     }
00654   }
00655 
00656   void onPoseData(uint32_t time_in_ms, logPose* data) {
00657     if (m_enable_logging_pose) {
00658       geometry_msgs::PoseStamped msg;
00659       if (m_use_ros_time) {
00660         msg.header.stamp = ros::Time::now();
00661       } else {
00662         msg.header.stamp = ros::Time(time_in_ms / 1000.0);
00663       }
00664       msg.header.frame_id = m_tf_prefix + "/base_link";
00665 
00666       msg.pose.position.x = data->x;
00667       msg.pose.position.y = data->y;
00668       msg.pose.position.z = data->z;
00669 
00670       float q[4];
00671       quatdecompress(data->quatCompressed, q);
00672       msg.pose.orientation.x = q[0];
00673       msg.pose.orientation.y = q[1];
00674       msg.pose.orientation.z = q[2];
00675       msg.pose.orientation.w = q[3];
00676 
00677       m_pubPose.publish(msg);
00678     }
00679   }
00680 
00681   void onLogCustom(uint32_t time_in_ms, std::vector<double>* values, void* userData) {
00682 
00683     ros::Publisher* pub = reinterpret_cast<ros::Publisher*>(userData);
00684 
00685     crazyflie_driver::GenericLogData msg;
00686     if (m_use_ros_time) {
00687       msg.header.stamp = ros::Time::now();
00688     } else {
00689       msg.header.stamp = ros::Time(time_in_ms / 1000.0);
00690     }
00691     msg.header.frame_id = m_tf_prefix + "/base_link";
00692     msg.values = *values;
00693 
00694     pub->publish(msg);
00695   }
00696 
00697   void onEmptyAck(const crtpPlatformRSSIAck* data) {
00698       std_msgs::Float32 msg;
00699       // dB
00700       msg.data = data->rssi;
00701       m_pubRssi.publish(msg);
00702   }
00703 
00704   void onLinkQuality(float linkQuality) {
00705       if (linkQuality < 0.7) {
00706         ROS_WARN_NAMED(m_tf_prefix, "Link Quality low (%f)", linkQuality);
00707       }
00708   }
00709 
00710   void onConsole(const char* msg) {
00711     static std::string messageBuffer;
00712     messageBuffer += msg;
00713     size_t pos = messageBuffer.find('\n');
00714     if (pos != std::string::npos) {
00715       messageBuffer[pos] = 0;
00716       ROS_INFO_NAMED(m_tf_prefix, "CF Console: %s", messageBuffer.c_str());
00717       messageBuffer.erase(0, pos+1);
00718     }
00719   }
00720 
00721   void onGenericPacket(const ITransport::Ack& ack) {
00722     crazyflie_driver::crtpPacket packet;
00723     packet.size = ack.size;
00724     packet.header = ack.data[0];
00725     memcpy(&packet.data[0], &ack.data[1], ack.size);
00726     m_pubPackets.publish(packet);
00727   }
00728 
00729   bool setGroupMask(
00730     crazyflie_driver::SetGroupMask::Request& req,
00731     crazyflie_driver::SetGroupMask::Response& res)
00732   {
00733     ROS_INFO_NAMED(m_tf_prefix, "SetGroupMask requested");
00734     m_cf.setGroupMask(req.groupMask);
00735     return true;
00736   }
00737 
00738   bool takeoff(
00739     crazyflie_driver::Takeoff::Request& req,
00740     crazyflie_driver::Takeoff::Response& res)
00741   {
00742     ROS_INFO_NAMED(m_tf_prefix, "Takeoff requested");
00743     m_cf.takeoff(req.height, req.duration.toSec(), req.groupMask);
00744     return true;
00745   }
00746 
00747   bool land(
00748     crazyflie_driver::Land::Request& req,
00749     crazyflie_driver::Land::Response& res)
00750   {
00751     ROS_INFO_NAMED(m_tf_prefix, "Land requested");
00752     m_cf.land(req.height, req.duration.toSec(), req.groupMask);
00753     return true;
00754   }
00755 
00756   bool stop(
00757     crazyflie_driver::Stop::Request& req,
00758     crazyflie_driver::Stop::Response& res)
00759   {
00760     ROS_INFO_NAMED(m_tf_prefix, "Stop requested");
00761     m_cf.stop(req.groupMask);
00762     return true;
00763   }
00764 
00765   bool goTo(
00766     crazyflie_driver::GoTo::Request& req,
00767     crazyflie_driver::GoTo::Response& res)
00768   {
00769     ROS_INFO_NAMED(m_tf_prefix, "GoTo requested");
00770     m_cf.goTo(req.goal.x, req.goal.y, req.goal.z, req.yaw, req.duration.toSec(), req.relative, req.groupMask);
00771     return true;
00772   }
00773 
00774   bool uploadTrajectory(
00775     crazyflie_driver::UploadTrajectory::Request& req,
00776     crazyflie_driver::UploadTrajectory::Response& res)
00777   {
00778     ROS_INFO_NAMED(m_tf_prefix, "UploadTrajectory requested");
00779 
00780     std::vector<Crazyflie::poly4d> pieces(req.pieces.size());
00781     for (size_t i = 0; i < pieces.size(); ++i) {
00782       if (   req.pieces[i].poly_x.size() != 8
00783           || req.pieces[i].poly_y.size() != 8
00784           || req.pieces[i].poly_z.size() != 8
00785           || req.pieces[i].poly_yaw.size() != 8) {
00786         ROS_FATAL_NAMED(m_tf_prefix, "Wrong number of pieces!");
00787         return false;
00788       }
00789       pieces[i].duration = req.pieces[i].duration.toSec();
00790       for (size_t j = 0; j < 8; ++j) {
00791         pieces[i].p[0][j] = req.pieces[i].poly_x[j];
00792         pieces[i].p[1][j] = req.pieces[i].poly_y[j];
00793         pieces[i].p[2][j] = req.pieces[i].poly_z[j];
00794         pieces[i].p[3][j] = req.pieces[i].poly_yaw[j];
00795       }
00796     }
00797     m_cf.uploadTrajectory(req.trajectoryId, req.pieceOffset, pieces);
00798 
00799     ROS_INFO_NAMED(m_tf_prefix, "Upload completed!");
00800     return true;
00801   }
00802 
00803   bool startTrajectory(
00804     crazyflie_driver::StartTrajectory::Request& req,
00805     crazyflie_driver::StartTrajectory::Response& res)
00806   {
00807     ROS_INFO_NAMED(m_tf_prefix, "StartTrajectory requested");
00808     m_cf.startTrajectory(req.trajectoryId, req.timescale, req.reversed, req.relative, req.groupMask);
00809     return true;
00810   }
00811 
00812 private:
00813   std::string m_tf_prefix;
00814   Crazyflie m_cf;
00815   bool m_isEmergency;
00816   float m_roll_trim;
00817   float m_pitch_trim;
00818   bool m_enableLogging;
00819   bool m_enableParameters;
00820   std::vector<crazyflie_driver::LogBlock> m_logBlocks;
00821   bool m_use_ros_time;
00822   bool m_enable_logging_imu;
00823   bool m_enable_logging_temperature;
00824   bool m_enable_logging_magnetic_field;
00825   bool m_enable_logging_pressure;
00826   bool m_enable_logging_battery;
00827   bool m_enable_logging_pose;
00828   bool m_enable_logging_packets;
00829 
00830   ros::ServiceServer m_serviceEmergency;
00831   ros::ServiceServer m_serviceUpdateParams;
00832   ros::ServiceServer m_sendPacketServer;
00833 
00834   // High-level setpoints
00835   ros::ServiceServer m_serviceSetGroupMask;
00836   ros::ServiceServer m_serviceTakeoff;
00837   ros::ServiceServer m_serviceLand;
00838   ros::ServiceServer m_serviceStop;
00839   ros::ServiceServer m_serviceGoTo;
00840   ros::ServiceServer m_serviceUploadTrajectory;
00841   ros::ServiceServer m_serviceStartTrajectory;
00842 
00843   ros::Subscriber m_subscribeCmdVel;
00844   ros::Subscriber m_subscribeCmdFullState;
00845   ros::Subscriber m_subscribeCmdHover;
00846   ros::Subscriber m_subscribeCmdStop;
00847   ros::Subscriber m_subscribeCmdPosition;
00848   ros::Subscriber m_subscribeExternalPosition;
00849   ros::Subscriber m_subscribeExternalPose;
00850   ros::Publisher m_pubImu;
00851   ros::Publisher m_pubTemp;
00852   ros::Publisher m_pubMag;
00853   ros::Publisher m_pubPressure;
00854   ros::Publisher m_pubBattery;
00855   ros::Publisher m_pubPose;
00856   ros::Publisher m_pubPackets;
00857   ros::Publisher m_pubRssi;
00858   std::vector<ros::Publisher> m_pubLogDataGeneric;
00859 
00860   bool m_sentSetpoint, m_sentExternalPosition;
00861 
00862   std::thread m_thread;
00863   ros::CallbackQueue m_callback_queue;
00864 };
00865 
00866 class CrazyflieServer
00867 {
00868 public:
00869   CrazyflieServer()
00870   {
00871 
00872   }
00873 
00874   void run()
00875   {
00876     ros::NodeHandle n;
00877     ros::CallbackQueue callback_queue;
00878     n.setCallbackQueue(&callback_queue);
00879 
00880     ros::ServiceServer serviceAdd = n.advertiseService("add_crazyflie", &CrazyflieServer::add_crazyflie, this);
00881     ros::ServiceServer serviceRemove = n.advertiseService("remove_crazyflie", &CrazyflieServer::remove_crazyflie, this);
00882 
00883     // // High-level API
00884     // ros::ServiceServer serviceTakeoff = n.advertiseService("takeoff", &CrazyflieServer::takeoff, this);
00885     // ros::ServiceServer serviceLand = n.advertiseService("land", &CrazyflieROS::land, this);
00886     // ros::ServiceServer serviceStop = n.advertiseService("stop", &CrazyflieROS::stop, this);
00887     // ros::ServiceServer serviceGoTo = n.advertiseService("go_to", &CrazyflieROS::goTo, this);
00888     // ros::ServiceServer startTrajectory = n.advertiseService("start_trajectory", &CrazyflieROS::startTrajectory, this);
00889 
00890     while(ros::ok()) {
00891       // Execute any ROS related functions now
00892       callback_queue.callAvailable(ros::WallDuration(0.0));
00893       std::this_thread::sleep_for(std::chrono::milliseconds(1));
00894     }
00895   }
00896 
00897 private:
00898 
00899   bool add_crazyflie(
00900     crazyflie_driver::AddCrazyflie::Request  &req,
00901     crazyflie_driver::AddCrazyflie::Response &res)
00902   {
00903     ROS_INFO("Adding %s as %s with trim(%f, %f). Logging: %d, Parameters: %d, Use ROS time: %d",
00904       req.uri.c_str(),
00905       req.tf_prefix.c_str(),
00906       req.roll_trim,
00907       req.pitch_trim,
00908       req.enable_parameters,
00909       req.enable_logging,
00910       req.use_ros_time);
00911 
00912     // Ignore if the uri is already in use
00913     if (m_crazyflies.find(req.uri) != m_crazyflies.end()) {
00914       ROS_ERROR("Cannot add %s, already added.", req.uri.c_str());
00915       return false;
00916     }
00917 
00918     CrazyflieROS* cf = new CrazyflieROS(
00919       req.uri,
00920       req.tf_prefix,
00921       req.roll_trim,
00922       req.pitch_trim,
00923       req.enable_logging,
00924       req.enable_parameters,
00925       req.log_blocks,
00926       req.use_ros_time,
00927       req.enable_logging_imu,
00928       req.enable_logging_temperature,
00929       req.enable_logging_magnetic_field,
00930       req.enable_logging_pressure,
00931       req.enable_logging_battery,
00932       req.enable_logging_pose,
00933       req.enable_logging_packets);
00934 
00935     m_crazyflies[req.uri] = cf;
00936 
00937     return true;
00938   }
00939 
00940   bool remove_crazyflie(
00941     crazyflie_driver::RemoveCrazyflie::Request  &req,
00942     crazyflie_driver::RemoveCrazyflie::Response &res)
00943   {
00944 
00945     if (m_crazyflies.find(req.uri) == m_crazyflies.end()) {
00946       ROS_ERROR("Cannot remove %s, not connected.", req.uri.c_str());
00947       return false;
00948     }
00949 
00950     ROS_INFO("Removing crazyflie at uri %s.", req.uri.c_str());
00951 
00952     m_crazyflies[req.uri]->stop();
00953     delete m_crazyflies[req.uri];
00954     m_crazyflies.erase(req.uri);
00955 
00956     ROS_INFO("Crazyflie %s removed.", req.uri.c_str());
00957 
00958     return true;
00959   }
00960 
00961   // bool takeoff(
00962   //   crazyflie_driver::Takeoff::Request& req,
00963   //   crazyflie_driver::Takeoff::Response& res)
00964   // {
00965   //   ROS_INFO("Takeoff requested");
00966   //   m_cfbc.takeoff(req.height, req.duration.toSec(), req.groupMask);
00967   //   return true;
00968   // }
00969 
00970   // bool land(
00971   //   crazyflie_driver::Land::Request& req,
00972   //   crazyflie_driver::Land::Response& res)
00973   // {
00974   //   ROS_INFO("Land requested");
00975   //   m_cfbc.land(req.height, req.duration.toSec(), req.groupMask);
00976   //   return true;
00977   // }
00978 
00979   // bool stop(
00980   //   crazyflie_driver::Stop::Request& req,
00981   //   crazyflie_driver::Stop::Response& res)
00982   // {
00983   //   ROS_INFO("Stop requested");
00984   //   m_cfbc.stop(req.groupMask);
00985   //   return true;
00986   // }
00987 
00988   // bool goTo(
00989   //   crazyflie_driver::GoTo::Request& req,
00990   //   crazyflie_driver::GoTo::Response& res)
00991   // {
00992   //   ROS_INFO("GoTo requested");
00993   //   // this is always relative
00994   //   m_cfbc.goTo(req.goal.x, req.goal.y, req.goal.z, req.yaw, req.duration.toSec(), req.groupMask);
00995   //   return true;
00996   // }
00997 
00998   // bool startTrajectory(
00999   //   crazyflie_driver::StartTrajectory::Request& req,
01000   //   crazyflie_driver::StartTrajectory::Response& res)
01001   // {
01002   //   ROS_INFO("StartTrajectory requested");
01003   //   // this is always relative
01004   //   m_cfbc.startTrajectory(req.index, req.numPieces, req.timescale, req.reversed, req.groupMask);
01005   //   return true;
01006   // }
01007 
01008 private:
01009   std::map<std::string, CrazyflieROS*> m_crazyflies;
01010 };
01011 
01012 
01013 
01014 
01015 int main(int argc, char **argv)
01016 {
01017   ros::init(argc, argv, "crazyflie_server");
01018 
01019   CrazyflieServer cfserver;
01020   cfserver.run();
01021 
01022   return 0;
01023 }


crazyflie_driver
Author(s): Wolfgang Hoenig
autogenerated on Wed Jun 12 2019 19:20:47