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


ardrone_autonomy
Author(s): Mani Monajjemi, Mani Monajjemi
autogenerated on Sun Oct 5 2014 22:17:06