ardrone_driver.cpp
Go to the documentation of this file.
00001 
00025 #include <signal.h>
00026 #include <string>
00027 #include <algorithm>
00028 #include <vector>
00029 
00030 #include <ardrone_autonomy/ardrone_driver.h>
00031 #include <ardrone_autonomy/teleop_twist.h>
00032 #include <ardrone_autonomy/video.h>
00033 
00034 
00036 // class ARDroneDriver
00038 
00039 ARDroneDriver::ARDroneDriver()
00040   : private_nh("~"),
00041     image_transport(node_handle),
00042     // Ugly: This has been defined in the template file. Cleaner way to guarantee initilaztion?
00043     initialized_navdata_publishers(false),
00044     last_frame_id(-1),
00045     last_navdata_id(-1),
00046     is_inited(false),
00047     last_receive_time(0.0)
00048 {
00049   cmd_vel_sub = node_handle.subscribe("cmd_vel", 1, &CmdVelCallback);
00050   takeoff_sub = node_handle.subscribe("ardrone/takeoff", 1, &TakeoffCallback);
00051   reset_sub = node_handle.subscribe("ardrone/reset", 1, &ResetCallback);
00052   land_sub = node_handle.subscribe("ardrone/land", 1, &LandCallback);
00053   image_pub = image_transport.advertiseCamera("ardrone/image_raw", 10);
00054   hori_pub = image_transport.advertiseCamera("ardrone/front/image_raw", 10);
00055   vert_pub = image_transport.advertiseCamera("ardrone/bottom/image_raw", 10);
00056   toggle_cam_srv = node_handle.advertiseService("ardrone/togglecam", ToggleCamCallback);
00057   set_cam_channel_srv = node_handle.advertiseService("ardrone/setcamchannel", SetCamChannelCallback);
00058   set_led_animation_srv = node_handle.advertiseService("ardrone/setledanimation", SetLedAnimationCallback);
00059   flat_trim_srv = node_handle.advertiseService("ardrone/flattrim", FlatTrimCallback);
00060   set_flight_anim_srv = node_handle.advertiseService("ardrone/setflightanimation", SetFlightAnimationCallback);
00061   set_record_srv = node_handle.advertiseService("ardrone/setrecord", SetRecordCallback);
00062 
00063   /* TF Frames */
00064   private_nh.param<std::string>("drone_frame_id", drone_frame_id, "ardrone_base");
00065   drone_frame_base = drone_frame_id + "_link";
00066   drone_frame_imu = drone_frame_id + "_imu";
00067   drone_frame_front_cam = drone_frame_id + "_frontcam";
00068   drone_frame_bottom_cam = drone_frame_id + "_bottomcam";
00069 
00070   if (private_nh.hasParam("root_frame"))
00071   {
00072     ROS_WARN("Changing `root_frame` has been deprecated since version 1.4. ");
00073   }
00074 
00075   // Fill constant parts of IMU Message
00076   // If no rosparam is set then the default value of 0.0 will be assigned to all covariance values
00077   for (int i = 0; i < 9; i++)
00078   {
00079     imu_msg.linear_acceleration_covariance[i] = 0.0;
00080     imu_msg.angular_velocity_covariance[i] = 0.0;
00081     imu_msg.orientation_covariance[i] = 0.0;
00082   }
00083   ReadCovParams("~cov/imu_la", imu_msg.linear_acceleration_covariance);
00084   ReadCovParams("~cov/imu_av", imu_msg.angular_velocity_covariance);
00085   ReadCovParams("~cov/imu_or", imu_msg.orientation_covariance);
00086 
00087   if (private_nh.hasParam("do_imu_caliberation"))
00088   {
00089     ROS_WARN("IMU Caliberation has been deprecated since 1.4.");
00090   }
00091 
00092   // Camera Info Manager
00093   cinfo_hori = new camera_info_manager::CameraInfoManager(ros::NodeHandle("ardrone/front"), "ardrone_front");
00094   cinfo_vert = new camera_info_manager::CameraInfoManager(ros::NodeHandle("ardrone/bottom"), "ardrone_bottom");
00095 
00096   // TF Stuff
00097 
00098 
00099   // Front Cam to Base
00100   // TODO(mani-monaj): Precise values for Drone1 & Drone2
00101   tf_base_front = tf::StampedTransform(
00102                     tf::Transform(
00103                       tf::createQuaternionFromRPY(-90.0 * _DEG2RAD, 0.0, -90.0 * _DEG2RAD),
00104                       tf::Vector3(0.21, 0.0, 0.0)),
00105                     ros::Time::now(), drone_frame_base, drone_frame_front_cam);
00106 
00107   // Bottom Cam to Base (Bad Assumption: No translation from IMU and Base)
00108   // TODO(mani-monaj): This should be different from Drone 1 & 2.
00109   tf_base_bottom = tf::StampedTransform(
00110                      tf::Transform(
00111                        tf::createQuaternionFromRPY(180.0 * _DEG2RAD, 0.0, 90.0 * _DEG2RAD),
00112                        tf::Vector3(0.0, -0.02, 0.0)),
00113                      ros::Time::now(), drone_frame_base, drone_frame_bottom_cam);
00114 
00115   // reset odometry
00116   odometry[0] = odometry[1] = 0;
00117 }
00118 
00119 ARDroneDriver::~ARDroneDriver()
00120 {
00121   delete cinfo_hori;
00122   delete cinfo_vert;
00123 }
00124 
00125 void ARDroneDriver::run()
00126 {
00127   ros::Rate loop_rate(looprate);
00128   const ros::Time startTime = ros::Time::now();
00129   static int freq_dev = 0;
00130   while (node_handle.ok())
00131   {
00132     if (!is_inited)  // Give the Drone 5s of free time to finish init phase
00133     {
00134       if (((ros::Time::now() - startTime).toSec()) > 5.0)
00135       {
00136         is_inited = true;
00137 
00138         // Send the configuration to the drone
00139         ConfigureDrone();
00140 
00141         vp_os_mutex_lock(&navdata_lock);
00142         ROS_INFO("Successfully connected to '%s' (AR-Drone %d.0 - Firmware: %s) - Battery(%%): %d",
00143                  ardrone_control_config.ardrone_name,
00144                  (IS_ARDRONE1) ? 1 : 2,
00145                  ardrone_control_config.num_version_soft,
00146                  shared_raw_navdata_ptr->navdata_demo.vbat_flying_percentage);
00147         ROS_INFO("Navdata Publish Settings:");
00148         ROS_INFO("    Legacy Navdata Mode: %s", enabled_legacy_navdata ? "On" : "Off");
00149         ROS_INFO("    ROS Loop Rate: %d Hz", looprate);
00150         ROS_INFO("    Realtime Navdata Publish: %s", realtime_navdata ? "On" : "Off");
00151         ROS_INFO("    Realtime Video Publish: %s", realtime_video ? "On" : "Off");
00152         ROS_INFO("    Drone Navdata Send Speed: %s",
00153                  ardrone_application_default_config.navdata_demo == 0 ?
00154                    "200Hz (navdata_demo=0)" : "15Hz (navdata_demo=1)");
00155         // TODO(mani-monaj): Enabled Navdata Demo
00156         vp_os_mutex_unlock(&navdata_lock);
00157         if (ardrone_control_config.num_version_soft[0] == '0')
00158         {
00159           ROS_WARN("The AR-Drone has a suspicious Firmware number. It usually means the network link is unreliable.");
00160         }
00161       }
00162     }
00163     else
00164     {
00165       if (!realtime_video)
00166       {
00167         vp_os_mutex_lock(&video_lock);
00168         copy_current_frame_id = current_frame_id;
00169         vp_os_mutex_unlock(&video_lock);
00170         if (copy_current_frame_id != last_frame_id)
00171         {
00172           last_frame_id = copy_current_frame_id;
00173           PublishVideo();
00174         }
00175       }
00176 
00177       if (!realtime_navdata)
00178       {
00179         vp_os_mutex_lock(&navdata_lock);
00180         copy_current_navdata_id = current_navdata_id;
00181         vp_os_mutex_unlock(&navdata_lock);
00182         if (copy_current_navdata_id != last_navdata_id)
00183         {
00184           vp_os_mutex_lock(&navdata_lock);
00185           last_navdata_id = copy_current_navdata_id;
00186 
00187           // Thread safe copy of interesting Navdata data
00188           // TODO(mani-monaj): This is a very expensive task, can we optimize here?
00189           // maybe ignoring the copy when it is not needed.
00190           const navdata_unpacked_t navdata_raw = *shared_raw_navdata_ptr;
00191           const ros::Time navdata_receive_time = shared_navdata_receive_time;
00192           vp_os_mutex_unlock(&navdata_lock);
00193 
00194           // This function is defined in the template NavdataMessageDefinitions.h template file
00195           PublishNavdataTypes(navdata_raw, navdata_receive_time);
00196           PublishNavdata(navdata_raw, navdata_receive_time);
00197           PublishOdometry(navdata_raw, navdata_receive_time);
00198         }
00199       }
00200       if (freq_dev == 0) PublishTF();
00201 
00202       // (looprate / 5)Hz  TF publish
00203       // TODO(mani-monaj): Make TF publish rate fixed
00204       freq_dev = (freq_dev + 1) % 5;
00205     }
00206     ros::spinOnce();
00207     loop_rate.sleep();
00208   }
00209   printf("ROS loop terminated ... \n");
00210 }
00211 
00212 void ARDroneDriver::ConfigureDrone()
00213 {
00214   #include "ardrone_autonomy/snippet_configure_drone.h"
00215 }
00216 
00217 double ARDroneDriver::CalcAverage(const std::vector<double> &vec)
00218 {
00219   double ret = 0.0;
00220   for (unsigned int i = 0; i < vec.size(); i++)
00221   {
00222     ret += vec[i];
00223   }
00224   return (ret / vec.size());
00225 }
00226 
00227 bool ARDroneDriver::ReadCovParams(const std::string &param_name, boost::array<double, 9> &cov_array)
00228 {
00229   XmlRpc::XmlRpcValue cov_list;
00230   std::stringstream str_stream;
00231   if (ros::param::get(param_name, cov_list))
00232   {
00233     if (cov_list.getType() != XmlRpc::XmlRpcValue::TypeArray)
00234     {
00235       ROS_WARN("Covariance values for %s is not a list", param_name.c_str());
00236       return false;
00237     }
00238 
00239     if (cov_list.size() != 9)
00240     {
00241       ROS_WARN("Covariance list size for %s is not of size 9 (Size: %d)", param_name.c_str(), cov_list.size());
00242       return false;
00243     }
00244     str_stream << param_name << " set to [";
00245     for (int32_t i = 0; i < cov_list.size(); i++)
00246     {
00247       ROS_ASSERT(cov_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
00248       cov_array[i] = static_cast<double>(cov_list[i]);
00249       str_stream << cov_array[i] << ((i < 8) ? ", " : "");
00250     }
00251     str_stream << "]";
00252     ROS_INFO("%s", str_stream.str().c_str());
00253     return true;
00254   }
00255   else
00256   {
00257     ROS_INFO("No values found for `%s` in parameters, set all to zero.", param_name.c_str());
00258     return false;
00259   }
00260 }
00261 
00262 void ARDroneDriver::PublishVideo()
00263 {
00264   if (
00265     (image_pub.getNumSubscribers() == 0) &&
00266     (hori_pub.getNumSubscribers() == 0) &&
00267     (vert_pub.getNumSubscribers() == 0)
00268   ) return;
00269 
00270   // Camera Info (NO PIP)
00271 
00272   sensor_msgs::CameraInfo cinfo_msg_hori = cinfo_hori->getCameraInfo();
00273   sensor_msgs::CameraInfo cinfo_msg_vert = cinfo_vert->getCameraInfo();
00274 
00275   cinfo_msg_hori.header.frame_id = drone_frame_front_cam;
00276   cinfo_msg_vert.header.frame_id = drone_frame_bottom_cam;
00277 
00278   if (IS_ARDRONE1)
00279   {
00280     /*
00281     * Information on buffer and image sizes.
00282     * Buffer is always in QVGA size, however for different Camera Modes
00283     * The picture and PIP sizes are different.
00284     *
00285     * image_raw and buffer are always 320x240. In order to preserve backward compatibilty image_raw remains
00286     * always as before. Two new set of topics are added for two new cameras : /ardrone/front/xxx and /ardrone/bottom/xxx
00287     *
00288     * In Camera State 0 front image relays the buffer  and image_raw and bottom image are not updated.
00289     *
00290     * In Camera State 1 bottom image is a 174x144 crop of the buffer. The front image is not updated
00291     *
00292     * In Camera State 2 bottom image is a PIP cut of size (87x72) from buffer.
00293     * The bottom image is a (320-87)x(240) cut of the buffer.
00294     *
00295     * In Camera State 3 front image is a PIP cut of size (58x42) from buffer.
00296     * The bottom image is a (174-58)x144 crop of the buffer.
00297     */
00298     sensor_msgs::Image image_msg;
00299     sensor_msgs::Image::_data_type::iterator _it;
00300 
00301     if ((cam_state == ZAP_CHANNEL_HORI) || (cam_state == ZAP_CHANNEL_LARGE_HORI_SMALL_VERT))
00302     {
00303       image_msg.header.frame_id = drone_frame_front_cam;
00304     }
00305     else if ((cam_state == ZAP_CHANNEL_VERT) || (cam_state == ZAP_CHANNEL_LARGE_VERT_SMALL_HORI))
00306     {
00307       image_msg.header.frame_id = drone_frame_bottom_cam;
00308     }
00309     else
00310     {
00311       ROS_WARN_ONCE("Something is wrong with camera channel config.");
00312     }
00313 
00314     image_msg.width = D1_STREAM_WIDTH;
00315     image_msg.height = D1_STREAM_HEIGHT;
00316     image_msg.encoding = "rgb8";
00317     image_msg.is_bigendian = false;
00318     image_msg.step = D1_STREAM_WIDTH * 3;
00319     image_msg.data.resize(D1_STREAM_WIDTH * D1_STREAM_HEIGHT * 3);
00320 
00321     if (!realtime_video) vp_os_mutex_lock(&video_lock);
00322     image_msg.header.stamp = shared_video_receive_time;
00323     std::copy(buffer, buffer + (D1_STREAM_WIDTH * D1_STREAM_HEIGHT * 3), image_msg.data.begin());
00324     if (!realtime_video) vp_os_mutex_unlock(&video_lock);
00325 
00326     cinfo_msg_hori.header.stamp = image_msg.header.stamp;
00327     cinfo_msg_vert.header.stamp = image_msg.header.stamp;
00328 
00329     if (cam_state == ZAP_CHANNEL_HORI)
00330     {
00331       /*
00332       * Horizontal camera is activated, only /ardrone/front/ is being updated
00333       */
00334       cinfo_msg_hori.width = D1_STREAM_WIDTH;
00335       cinfo_msg_hori.height = D1_STREAM_HEIGHT;
00336 
00337       image_pub.publish(image_msg, cinfo_msg_hori);
00338       hori_pub.publish(image_msg, cinfo_msg_hori);
00339     }
00340     else if (cam_state == ZAP_CHANNEL_VERT)
00341     {
00342       /*
00343       * Vertical camera is activated, only /ardrone/bottom/ is being updated
00344       */
00345       image_msg.width = D1_VERTSTREAM_WIDTH;
00346       image_msg.height = D1_VERTSTREAM_HEIGHT;
00347       image_msg.encoding = "rgb8";
00348       image_msg.is_bigendian = false;
00349       image_msg.step = D1_VERTSTREAM_WIDTH * 3;
00350       image_msg.data.clear();
00351       image_msg.data.resize(D1_VERTSTREAM_WIDTH * D1_VERTSTREAM_HEIGHT * 3);
00352       _it = image_msg.data.begin();
00353       if (!realtime_video) vp_os_mutex_lock(&video_lock);
00354       for (int row = 0; row < D1_VERTSTREAM_HEIGHT ; row++)
00355       {
00356         int _b = row * D1_STREAM_WIDTH * 3;
00357         int _e = _b + image_msg.step;
00358         _it = std::copy(buffer + _b, buffer + _e, _it);
00359       }
00360       if (!realtime_video) vp_os_mutex_unlock(&video_lock);
00361 
00362       cinfo_msg_vert.width = D1_VERTSTREAM_WIDTH;
00363       cinfo_msg_vert.height = D1_VERTSTREAM_HEIGHT;
00364       image_pub.publish(image_msg, cinfo_msg_vert);
00365       vert_pub.publish(image_msg, cinfo_msg_vert);
00366     }
00367     else if (cam_state == ZAP_CHANNEL_LARGE_HORI_SMALL_VERT)
00368     {
00369       /*
00370       * The Picture in Picture is activated with vertical camera inside the horizontal
00371       * camera. Both /ardrone/front and /ardrone/bottom is being updated
00372       */
00373 
00374       // Front (Cropping the first 88 columns)
00375       image_msg.width = D1_STREAM_WIDTH  - D1_MODE2_PIP_WIDTH;
00376       image_msg.height = D1_STREAM_HEIGHT;
00377       image_msg.encoding = "rgb8";
00378       image_msg.is_bigendian = false;
00379       image_msg.step = (D1_STREAM_WIDTH - D1_MODE2_PIP_WIDTH) * 3;
00380       image_msg.data.clear();
00381       image_msg.data.resize((D1_STREAM_WIDTH - D1_MODE2_PIP_WIDTH)*D1_STREAM_HEIGHT * 3);
00382       _it = image_msg.data.begin();
00383       if (!realtime_video) vp_os_mutex_lock(&video_lock);
00384       for (int row = 0; row < D1_STREAM_HEIGHT; row++)
00385       {
00386         int _b = (row * D1_STREAM_WIDTH * 3) + (D1_MODE2_PIP_WIDTH * 3);
00387         int _e = _b + image_msg.step;
00388         _it = std::copy(buffer + _b, buffer + _e, _it);
00389       }
00390       if (!realtime_video) vp_os_mutex_unlock(&video_lock);
00391 
00392       cinfo_msg_hori.width = D1_STREAM_WIDTH - D1_MODE2_PIP_WIDTH;
00393       cinfo_msg_hori.height = D1_STREAM_HEIGHT;
00394       hori_pub.publish(image_msg, cinfo_msg_hori);
00395 
00396       // Bottom
00397       image_msg.width = D1_MODE2_PIP_WIDTH;
00398       image_msg.height = D1_MODE2_PIP_HEIGHT;
00399       image_msg.encoding = "rgb8";
00400       image_msg.is_bigendian = false;
00401       image_msg.step = D1_MODE2_PIP_WIDTH * 3;
00402       image_msg.data.clear();
00403       image_msg.data.resize(D1_MODE2_PIP_WIDTH * D1_MODE2_PIP_HEIGHT * 3);
00404       _it = image_msg.data.begin();
00405       if (!realtime_video) vp_os_mutex_lock(&video_lock);
00406       for (int row = 0; row < D1_MODE2_PIP_HEIGHT; row++)
00407       {
00408         int _b = row * D1_STREAM_WIDTH * 3;
00409         int _e = _b + image_msg.step;
00410         _it = std::copy(buffer + _b, buffer + _e, _it);
00411       }
00412       if (!realtime_video) vp_os_mutex_unlock(&video_lock);
00413 
00414       cinfo_msg_vert.width = D1_MODE2_PIP_WIDTH;
00415       cinfo_msg_vert.height = D1_MODE2_PIP_HEIGHT;
00416       vert_pub.publish(image_msg, cinfo_msg_vert);
00417     }
00418     else if (cam_state == ZAP_CHANNEL_LARGE_VERT_SMALL_HORI)
00419     {
00420       /*
00421       * The Picture in Picture is activated with horizontal camera inside the vertical
00422       * camera. Both /ardrone/front and /ardrone/bottom is being updated
00423       */
00424 
00425       // Bottom  (Cropping the first 58 columns)
00426       image_msg.width = D1_VERTSTREAM_WIDTH   - D1_MODE3_PIP_WIDTH;
00427       image_msg.height = D1_VERTSTREAM_HEIGHT;
00428       image_msg.encoding = "rgb8";
00429       image_msg.is_bigendian = false;
00430       image_msg.step = (D1_VERTSTREAM_WIDTH - D1_MODE3_PIP_WIDTH) * 3;
00431       image_msg.data.clear();
00432       image_msg.data.resize((D1_VERTSTREAM_WIDTH - D1_MODE3_PIP_WIDTH)* D1_VERTSTREAM_HEIGHT * 3);
00433       _it = image_msg.data.begin();
00434       for (int row = 0; row < D1_VERTSTREAM_HEIGHT; row++)
00435       {
00436         int _b = (row * (D1_STREAM_WIDTH * 3)) + (D1_MODE3_PIP_WIDTH * 3);
00437         int _e = _b + image_msg.step;
00438         if (!realtime_video) vp_os_mutex_lock(&video_lock);
00439         _it = std::copy(buffer + _b, buffer + _e, _it);
00440         if (!realtime_video) vp_os_mutex_unlock(&video_lock);
00441       }
00442 
00443       cinfo_msg_vert.width = D1_VERTSTREAM_WIDTH - D1_MODE3_PIP_WIDTH;
00444       cinfo_msg_vert.height = D1_VERTSTREAM_HEIGHT;
00445       vert_pub.publish(image_msg, cinfo_msg_vert);
00446 
00447       // Front
00448       image_msg.width = D1_MODE3_PIP_WIDTH;
00449       image_msg.height = D1_MODE3_PIP_HEIGHT;
00450       image_msg.encoding = "rgb8";
00451       image_msg.is_bigendian = false;
00452       image_msg.step = D1_MODE3_PIP_WIDTH * 3;
00453       image_msg.data.clear();
00454       image_msg.data.resize(D1_MODE3_PIP_WIDTH * D1_MODE3_PIP_HEIGHT * 3);
00455       _it = image_msg.data.begin();
00456       if (!realtime_video) vp_os_mutex_lock(&video_lock);
00457       for (int row = 0; row < D1_MODE3_PIP_HEIGHT; row++)
00458       {
00459         int _b = row * D1_STREAM_WIDTH * 3;
00460         int _e = _b + image_msg.step;
00461         _it = std::copy(buffer + _b, buffer + _e, _it);
00462       }
00463       if (!realtime_video) vp_os_mutex_unlock(&video_lock);
00464 
00465       cinfo_msg_hori.width = D1_MODE3_PIP_WIDTH;
00466       cinfo_msg_hori.height = D1_MODE3_PIP_HEIGHT;
00467       hori_pub.publish(image_msg, cinfo_msg_hori);
00468     }
00469   }
00470 
00476   if (IS_ARDRONE2)
00477   {
00478     sensor_msgs::Image image_msg;
00479     sensor_msgs::Image::_data_type::iterator _it;
00480 
00481     if (cam_state == ZAP_CHANNEL_HORI)
00482     {
00483       image_msg.header.frame_id = drone_frame_front_cam;
00484     }
00485     else if (cam_state == ZAP_CHANNEL_VERT)
00486     {
00487       image_msg.header.frame_id = drone_frame_bottom_cam;
00488     }
00489     else
00490     {
00491       ROS_WARN_ONCE("Something is wrong with camera channel config.");
00492     }
00493 
00494     image_msg.width = D2_STREAM_WIDTH;
00495     image_msg.height = D2_STREAM_HEIGHT;
00496     image_msg.encoding = "rgb8";
00497     image_msg.is_bigendian = false;
00498     image_msg.step = D2_STREAM_WIDTH * 3;
00499     image_msg.data.resize(D2_STREAM_WIDTH * D2_STREAM_HEIGHT * 3);
00500     if (!realtime_video) vp_os_mutex_lock(&video_lock);
00501     image_msg.header.stamp = shared_video_receive_time;
00502     std::copy(buffer, buffer + (D2_STREAM_WIDTH * D2_STREAM_HEIGHT * 3), image_msg.data.begin());
00503     if (!realtime_video) vp_os_mutex_unlock(&video_lock);
00504     // We only put the width and height in here.
00505 
00506     cinfo_msg_hori.header.stamp = image_msg.header.stamp;
00507     cinfo_msg_vert.header.stamp = image_msg.header.stamp;
00508 
00509     if (cam_state == ZAP_CHANNEL_HORI)
00510     {
00511       /*
00512       * Horizontal camera is activated, only /ardrone/front/ is being updated
00513       */
00514       cinfo_msg_hori.width = D2_STREAM_WIDTH;
00515       cinfo_msg_hori.height = D2_STREAM_HEIGHT;
00516       image_pub.publish(image_msg, cinfo_msg_hori);  // /ardrone
00517       hori_pub.publish(image_msg, cinfo_msg_hori);
00518     }
00519     else if (cam_state == ZAP_CHANNEL_VERT)
00520     {
00521       /*
00522       * Vertical camera is activated, only /ardrone/bottom/ is being updated
00523       */
00524       cinfo_msg_vert.width = D2_STREAM_WIDTH;
00525       cinfo_msg_vert.height = D2_STREAM_HEIGHT;
00526       image_pub.publish(image_msg, cinfo_msg_vert);  // /ardrone
00527       vert_pub.publish(image_msg, cinfo_msg_vert);
00528     }
00529   }
00530 }
00531 
00532 void ARDroneDriver::PublishNavdata(const navdata_unpacked_t &navdata_raw, const ros::Time &navdata_receive_time)
00533 {
00534   if (!enabled_legacy_navdata ||
00535       ((navdata_pub.getNumSubscribers() == 0) &&
00536        (imu_pub.getNumSubscribers() == 0) &&
00537        (mag_pub.getNumSubscribers() == 0)))
00538     return;  // why bother, no one is listening.
00539 
00540   legacynavdata_msg.header.stamp = navdata_receive_time;
00541   legacynavdata_msg.header.frame_id = drone_frame_base;
00542   legacynavdata_msg.batteryPercent = navdata_raw.navdata_demo.vbat_flying_percentage;
00543   legacynavdata_msg.state = (navdata_raw.navdata_demo.ctrl_state >> 16);
00544 
00545   // positive means counterclockwise rotation around axis
00546   legacynavdata_msg.rotX = navdata_raw.navdata_demo.phi / 1000.0;  // tilt left/right
00547   legacynavdata_msg.rotY = -navdata_raw.navdata_demo.theta / 1000.0;  // tilt forward/backward
00548   legacynavdata_msg.rotZ = -navdata_raw.navdata_demo.psi / 1000.0;  // orientation
00549 
00550   legacynavdata_msg.altd = navdata_raw.navdata_demo.altitude;  // cm
00551   legacynavdata_msg.vx = navdata_raw.navdata_demo.vx;  // mm/sec
00552   legacynavdata_msg.vy = -navdata_raw.navdata_demo.vy;  // mm/sec
00553   legacynavdata_msg.vz = -navdata_raw.navdata_demo.vz;  // mm/sec
00554   // msg.tm = navdata_raw.navdata_time.time;
00555   // First 21 bits (LSB) are usecs + 11 HSB are seconds
00556   legacynavdata_msg.tm = (navdata_raw.navdata_time.time & 0x001FFFFF) + (navdata_raw.navdata_time.time >> 21) * 1000000;
00557   legacynavdata_msg.ax = navdata_raw.navdata_phys_measures.phys_accs[ACC_X] / 1000.0;  // g
00558   legacynavdata_msg.ay = -navdata_raw.navdata_phys_measures.phys_accs[ACC_Y] / 1000.0;  // g
00559   legacynavdata_msg.az = -navdata_raw.navdata_phys_measures.phys_accs[ACC_Z] / 1000.0;  // g
00560 
00561   legacynavdata_msg.motor1 = navdata_raw.navdata_pwm.motor1;
00562   legacynavdata_msg.motor2 = navdata_raw.navdata_pwm.motor2;
00563   legacynavdata_msg.motor3 = navdata_raw.navdata_pwm.motor3;
00564   legacynavdata_msg.motor4 = navdata_raw.navdata_pwm.motor4;
00565 
00566   // New stuff
00567 
00568   if (IS_ARDRONE2)
00569   {
00570     legacynavdata_msg.magX = (int32_t)navdata_raw.navdata_magneto.mx;
00571     legacynavdata_msg.magY = (int32_t)navdata_raw.navdata_magneto.my;
00572     legacynavdata_msg.magZ = (int32_t)navdata_raw.navdata_magneto.mz;
00573 
00574     legacynavdata_msg.pressure = navdata_raw.navdata_pressure_raw.Pression_meas;  // typo in the SDK!
00575     legacynavdata_msg.temp = navdata_raw.navdata_pressure_raw.Temperature_meas;
00576 
00577     legacynavdata_msg.wind_speed = navdata_raw.navdata_wind_speed.wind_speed;
00578     legacynavdata_msg.wind_angle = navdata_raw.navdata_wind_speed.wind_angle;
00579     legacynavdata_msg.wind_comp_angle = navdata_raw.navdata_wind_speed.wind_compensation_phi;
00580   }
00581   else
00582   {
00583     legacynavdata_msg.magX = legacynavdata_msg.magY = legacynavdata_msg.magZ = 0;
00584     legacynavdata_msg.pressure = 0.0;
00585     legacynavdata_msg.temp = 0.0;
00586     legacynavdata_msg.wind_speed = 0.0;
00587     legacynavdata_msg.wind_angle = 0.0;
00588     legacynavdata_msg.wind_comp_angle = 0.0;
00589   }
00590 
00591   // Tag Detection, need to clear vectors first because it's a member variable now
00592   legacynavdata_msg.tags_type.clear();
00593   legacynavdata_msg.tags_xc.clear();
00594   legacynavdata_msg.tags_yc.clear();
00595   legacynavdata_msg.tags_width.clear();
00596   legacynavdata_msg.tags_height.clear();
00597   legacynavdata_msg.tags_orientation.clear();
00598   legacynavdata_msg.tags_distance.clear();
00599 
00600   legacynavdata_msg.tags_count = navdata_raw.navdata_vision_detect.nb_detected;
00601   for (int i = 0; i < navdata_raw.navdata_vision_detect.nb_detected; i++)
00602   {
00603     /*
00604      * The tags_type is in raw format. In order to extract the information
00605      * macros from ardrone_api.h is needed.
00606      *
00607      * #define DETECTION_MAKE_TYPE(source,tag) ( ((source)<<16) | (tag) )
00608      * #define DETECTION_EXTRACT_SOURCE(type)  ( ((type)>>16) & 0x0FF )
00609      * #define DETECTION_EXTRACT_TAG(type)     ( (type) & 0x0FF )
00610      *
00611      * Please also note that the xc, yc, width and height are in [0,1000] range
00612      * and must get converted back based on image resolution.
00613      */
00614     legacynavdata_msg.tags_type.push_back(navdata_raw.navdata_vision_detect.type[i]);
00615     legacynavdata_msg.tags_xc.push_back(navdata_raw.navdata_vision_detect.xc[i]);
00616     legacynavdata_msg.tags_yc.push_back(navdata_raw.navdata_vision_detect.yc[i]);
00617     legacynavdata_msg.tags_width.push_back(navdata_raw.navdata_vision_detect.width[i]);
00618     legacynavdata_msg.tags_height.push_back(navdata_raw.navdata_vision_detect.height[i]);
00619     legacynavdata_msg.tags_orientation.push_back(navdata_raw.navdata_vision_detect.orientation_angle[i]);
00620     legacynavdata_msg.tags_distance.push_back(navdata_raw.navdata_vision_detect.dist[i]);
00621   }
00622 
00623   /* IMU */
00624   imu_msg.header.frame_id = drone_frame_base;
00625   imu_msg.header.stamp = navdata_receive_time;
00626 
00627   // IMU - Linear Acc
00628   imu_msg.linear_acceleration.x = legacynavdata_msg.ax * 9.8;
00629   imu_msg.linear_acceleration.y = legacynavdata_msg.ay * 9.8;
00630   imu_msg.linear_acceleration.z = legacynavdata_msg.az * 9.8;
00631 
00632   // IMU - Rotation Matrix
00633   tf::Quaternion q;
00634   q.setRPY(legacynavdata_msg.rotX * _DEG2RAD, legacynavdata_msg.rotY * _DEG2RAD, legacynavdata_msg.rotZ * _DEG2RAD);
00635   tf::quaternionTFToMsg(q, imu_msg.orientation);
00636 
00637   // IMU - Gyro (Gyro is being sent in deg/sec)
00638   // TODO(mani-monaj): Should Gyro be added to Navdata?
00639   imu_msg.angular_velocity.x = navdata_raw.navdata_phys_measures.phys_gyros[GYRO_X] * DEG_TO_RAD;
00640   imu_msg.angular_velocity.y = -navdata_raw.navdata_phys_measures.phys_gyros[GYRO_Y] * DEG_TO_RAD;
00641   imu_msg.angular_velocity.z = -navdata_raw.navdata_phys_measures.phys_gyros[GYRO_Z] * DEG_TO_RAD;
00642 
00643   mag_msg.header.frame_id = drone_frame_base;
00644   mag_msg.header.stamp = navdata_receive_time;
00645   const float mag_normalizer = sqrt(legacynavdata_msg.magX * legacynavdata_msg.magX +
00646                                     legacynavdata_msg.magY * legacynavdata_msg.magY +
00647                                     legacynavdata_msg.magZ * legacynavdata_msg.magZ);
00648 
00649   // TODO(mani-monaj): Check if it is really needed that magnetometer message includes normalized value
00650   if (fabs(mag_normalizer) > 1e-9f)
00651   {
00652     mag_msg.vector.x = legacynavdata_msg.magX / mag_normalizer;
00653     mag_msg.vector.y = legacynavdata_msg.magY / mag_normalizer;
00654     mag_msg.vector.z = legacynavdata_msg.magZ / mag_normalizer;
00655     mag_pub.publish(mag_msg);
00656   }
00657   else
00658   {
00659     ROS_WARN_THROTTLE(30, "There is something wrong with the magnetometer readings (Magnitude is extremely small).");
00660   }
00661 
00662   navdata_pub.publish(legacynavdata_msg);
00663   imu_pub.publish(imu_msg);
00664 }
00665 
00666 // Load actual auto-generated code to publish full navdata
00667 #define NAVDATA_STRUCTS_SOURCE
00668 #include <ardrone_autonomy/NavdataMessageDefinitions.h>
00669 #undef NAVDATA_STRUCTS_SOURCE
00670 
00671 void ARDroneDriver::PublishTF()
00672 {
00673   tf_base_front.stamp_ = ros::Time::now();
00674   tf_base_bottom.stamp_ = ros::Time::now();
00675   tf_odom.stamp_ = ros::Time::now();
00676   tf_broad.sendTransform(tf_base_front);
00677   tf_broad.sendTransform(tf_base_bottom);
00678   tf_broad.sendTransform(tf_odom);
00679 }
00680 
00681 void ARDroneDriver::PublishOdometry(const navdata_unpacked_t &navdata_raw, const ros::Time &navdata_receive_time)
00682 {
00683   if (last_receive_time.isValid())
00684   {
00685     double delta_t = (navdata_receive_time - last_receive_time).toSec();
00686     odometry[0] += ((cos((navdata_raw.navdata_demo.psi / 180000.0) * M_PI) *
00687                      navdata_raw.navdata_demo.vx - sin((navdata_raw.navdata_demo.psi / 180000.0) * M_PI) *
00688                      -navdata_raw.navdata_demo.vy) * delta_t) / 1000.0;
00689     odometry[1] += ((sin((navdata_raw.navdata_demo.psi / 180000.0) * M_PI) *
00690                      navdata_raw.navdata_demo.vx + cos((navdata_raw.navdata_demo.psi / 180000.0) * M_PI) *
00691                      -navdata_raw.navdata_demo.vy) * delta_t) / 1000.0;
00692   }
00693   last_receive_time = navdata_receive_time;
00694 
00695   nav_msgs::Odometry odo_msg;
00696   odo_msg.header.stamp = navdata_receive_time;
00697   odo_msg.header.frame_id = "odom";
00698   odo_msg.child_frame_id = drone_frame_base;
00699 
00700   odo_msg.pose.pose.position.x = odometry[0];
00701   odo_msg.pose.pose.position.y = odometry[1];
00702   odo_msg.pose.pose.position.z = navdata_raw.navdata_demo.altitude / 1000;
00703   odo_msg.pose.pose.orientation = tf::createQuaternionMsgFromRollPitchYaw(
00704         navdata_raw.navdata_demo.phi / 180000.0 * M_PI,
00705         -navdata_raw.navdata_demo.theta / 180000.0 * M_PI,
00706         -navdata_raw.navdata_demo.psi / 180000.0 * M_PI);
00707 
00708   odo_msg.twist.twist.linear.x = navdata_raw.navdata_demo.vx / 1000.0;
00709   odo_msg.twist.twist.linear.y = -navdata_raw.navdata_demo.vy / 1000.0;
00710   odo_msg.twist.twist.linear.z = -navdata_raw.navdata_demo.vz / 1000.0;
00711 
00712   if (odo_pub.getNumSubscribers() > 0)
00713   {
00714     odo_pub.publish(odo_msg);
00715   }
00716 
00717   tf::Vector3 t;
00718   tf::pointMsgToTF(odo_msg.pose.pose.position, t);
00719   tf::Quaternion q;
00720   tf::quaternionMsgToTF(odo_msg.pose.pose.orientation, q);
00721 
00722   tf_odom.frame_id_ = "odom";
00723   tf_odom.child_frame_id_ = drone_frame_base;
00724   tf_odom.setOrigin(t);
00725   tf_odom.setRotation(q);
00726 }
00727 
00728 void ControlCHandler(int signal)
00729 {
00730   ros::shutdown();
00731   should_exit = 1;
00732 }
00733 
00735 // custom_main
00737 
00738 // extern "C" int custom_main(int argc, char** argv)
00739 int main(int argc, char** argv)
00740 {
00741   C_RESULT res = C_FAIL;
00742   char * drone_ip_address = NULL;
00743 
00744   // We need to implement our own Signal handler instead of ROS to shutdown
00745   // the SDK threads correctly.
00746 
00747   ros::init(argc, argv, "ardrone_driver", ros::init_options::NoSigintHandler);
00748 
00749   signal(SIGABRT, &ControlCHandler);
00750   signal(SIGTERM, &ControlCHandler);
00751   signal(SIGINT, &ControlCHandler);
00752 
00753   // Now to setup the drone and communication channels
00754   // We do this here because calling ardrone_tool_main uses an old
00755   // function initialization and is no longer recommended by parrot
00756   // I've based this section off the ControlEngine's initialization
00757   // routine (distributed with ARDrone SDK 2.0 Examples) as well as
00758   // the ardrone_tool_main function
00759 
00760   // Parse command line for
00761   // Backward compatibility with `-ip` command line argument
00762   argc--;
00763   argv++;
00764   while (argc && *argv[0] == '-')
00765   {
00766     if (!strcmp(*argv, "-ip") && (argc > 1))
00767     {
00768       drone_ip_address = *(argv + 1);
00769       printf("Using custom ip address %s\n", drone_ip_address);
00770       argc--;
00771       argv++;
00772     }
00773     argc--;
00774     argv++;
00775   }
00776 
00777   // Configure wifi
00778   vp_com_wifi_config_t *config = reinterpret_cast<vp_com_wifi_config_t*>(wifi_config());
00779 
00780   if (config)
00781   {
00782     vp_os_memset(&wifi_ardrone_ip[0], 0, ARDRONE_IPADDRESS_SIZE);
00783 
00784     // TODO(mani-monaj): Check if IP is valid
00785     if (drone_ip_address)
00786     {
00787       printf("===================+> %s\n", drone_ip_address);
00788       strncpy(&wifi_ardrone_ip[0], drone_ip_address, ARDRONE_IPADDRESS_SIZE - 1);
00789     }
00790     else
00791     {
00792       printf("===================+> %s\n", config->server);
00793       strncpy(&wifi_ardrone_ip[0], config->server, ARDRONE_IPADDRESS_SIZE - 1);
00794     }
00795   }
00796 
00797   while (-1 == getDroneVersion(".", wifi_ardrone_ip, &ardroneVersion))
00798   {
00799     printf("Getting AR.Drone version ...\n");
00800     vp_os_delay(250);
00801   }
00802 
00803   // Setup communication channels
00804   res = ardrone_tool_setup_com(NULL);
00805   if (FAILED(res))
00806   {
00807     PRINT("Wifi initialization failed. It means either:\n");
00808     PRINT("\t* you're not root (it's mandatory because you can set up wifi connection only as root)\n");
00809     PRINT("\t* wifi device is not present (on your pc or on your card)\n");
00810     PRINT("\t* you set the wrong name for wifi interface (for example rausb0 instead of wlan0) \n");
00811     PRINT("\t* ap is not up (reboot card or remove wifi usb dongle)\n");
00812     PRINT("\t* wifi device has no antenna\n");
00813   }
00814   else
00815   {
00816     // setup the application and user profiles for the driver
00817     const char* appname = reinterpret_cast<const char*>(DRIVER_APPNAME);
00818     const char* usrname = reinterpret_cast<const char*>(DRIVER_USERNAME);
00819     ardrone_gen_appid(appname, "2.0", app_id, app_name, APPLI_NAME_SIZE);
00820     ardrone_gen_usrid(usrname, usr_id, usr_name, USER_NAME_SIZE);
00821 
00822     // and finally initialize everything!
00823     // this will then call our sdk, which then starts the ::run() method of this file as an ardrone client thread
00824 
00825     res = ardrone_tool_init(wifi_ardrone_ip,
00826                             strlen(wifi_ardrone_ip),
00827                             NULL,
00828                             app_name,
00829                             usr_name,
00830                             NULL,
00831                             NULL,
00832                             MAX_FLIGHT_STORING_SIZE,
00833                             NULL);
00834 
00835     while (SUCCEED(res) && ardrone_tool_exit() == FALSE)
00836     {
00837       res = ardrone_tool_update();
00838     }
00839     res = ardrone_tool_shutdown();
00840   }
00841   return SUCCEED(res) ? 0 : -1;
00842 }


ardrone_autonomy
Author(s): Mani Monajjemi, Mani Monajjemi
autogenerated on Fri Aug 28 2015 10:07:51