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
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
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
00233 }
00234 }
00235
00236 void cmdStop(
00237 const std_msgs::Empty::ConstPtr& msg)
00238 {
00239
00240 if (!m_isEmergency) {
00241 m_cf.sendStop();
00242 m_sentSetpoint = true;
00243
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
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
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
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);
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);
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);
00525 }
00526
00527
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
00560 for (int i = 0; i < 100; ++i) {
00561 m_cf.sendSetpoint(0, 0, 0, 0);
00562 }
00563
00564 while(!m_isEmergency) {
00565
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
00574 m_callback_queue.callAvailable(ros::WallDuration(0.0));
00575 std::this_thread::sleep_for(std::chrono::milliseconds(1));
00576 }
00577
00578
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
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
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
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
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
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
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
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
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
00884
00885
00886
00887
00888
00889
00890 while(ros::ok()) {
00891
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
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
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
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 }