gcs_image_bridge.cpp
Go to the documentation of this file.
00001 
00006 /*
00007  * Copyright 2014 Vladimir Ermakov.
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 3 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00016  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00017  * for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License along
00020  * with this program; if not, write to the Free Software Foundation, Inc.,
00021  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00022  */
00023 
00024 #include <ros/ros.h>
00025 #include <ros/console.h>
00026 
00027 #include <mavros/utils.h>
00028 #include <mavconn/interface.h>
00029 
00030 #include <mavros/Mavlink.h>
00031 
00032 #include <sensor_msgs/image_encodings.h>
00033 #include <image_transport/image_transport.h>
00034 #include <cv_bridge/cv_bridge.h>
00035 #include <cv.h>
00036 #include <highgui.h>
00037 
00038 using namespace mavros;
00039 using namespace mavconn;
00040 namespace enc = sensor_msgs::image_encodings;
00041 
00042 int jpeg_quality;
00043 MAVConnInterface::Ptr gcs_link;
00044 ros::Publisher mavlink_pub;
00045 
00046 void mavlink_pub_cb(const mavlink_message_t *mmsg, uint8_t sysid, uint8_t compid)
00047 {
00048         MavlinkPtr rmsg = boost::make_shared<Mavlink>();
00049 
00050         rmsg->header.stamp = ros::Time::now();
00051         mavutils::copy_mavlink_to_ros(mmsg, rmsg);
00052         mavlink_pub.publish(rmsg);
00053 }
00054 
00055 void mavlink_sub_cb(const Mavlink::ConstPtr &rmsg)
00056 {
00057         mavlink_message_t mmsg;
00058 
00059         if (mavutils::copy_ros_to_mavlink(rmsg, mmsg))
00060                 gcs_link->send_message(&mmsg, rmsg->sysid, rmsg->compid);
00061         else
00062                 ROS_ERROR("Packet drop: illegal payload64 size");
00063 }
00064 
00065 void send_jpeg_image(std::vector<uint8_t> &jpeg_buffer, int jpeg_quality,
00066                 int height, int width)
00067 {
00068         constexpr size_t PAYLOAD_SIZE = sizeof(mavlink_encapsulated_data_t::data);
00069         mavlink_message_t msg;
00070 
00071         if (jpeg_buffer.empty()) {
00072                 ROS_ERROR("IMG: Empty JPEG buffer!");
00073                 return;
00074         }
00075 
00076         size_t packet_count = jpeg_buffer.size() / PAYLOAD_SIZE + 1;
00077         if (jpeg_buffer.capacity() < packet_count * PAYLOAD_SIZE) {
00078                 // preventing copying unowned data in next step
00079                 ROS_DEBUG("IMG: Reserved: %zu -> %zu bytes", jpeg_buffer.capacity(),
00080                                 packet_count * PAYLOAD_SIZE);
00081                 jpeg_buffer.reserve(packet_count * PAYLOAD_SIZE);
00082         }
00083 
00084         ROS_DEBUG("IMG: Send image %d x %d, %zu bytes in %zu packets",
00085                         width, height, jpeg_buffer.size(), packet_count);
00086 
00087         mavlink_msg_data_transmission_handshake_pack_chan(
00088                 gcs_link->get_system_id(),
00089                 gcs_link->get_component_id(),
00090                 gcs_link->get_channel(),
00091                 &msg,
00092                 MAVLINK_DATA_STREAM_IMG_JPEG,
00093                 jpeg_buffer.size(),
00094                 width,
00095                 height,
00096                 packet_count,
00097                 PAYLOAD_SIZE,
00098                 jpeg_quality);
00099         gcs_link->send_message(&msg);
00100 
00101         for (size_t seqnr = 0; seqnr < packet_count; seqnr++) {
00102                 mavlink_msg_encapsulated_data_pack_chan(
00103                                 gcs_link->get_system_id(),
00104                                 gcs_link->get_component_id(),
00105                                 gcs_link->get_channel(),
00106                                 &msg,
00107                                 seqnr,
00108                                 jpeg_buffer.data() + (PAYLOAD_SIZE * seqnr));
00109                 gcs_link->send_message(&msg);
00110 
00111                 //ROS_DEBUG("IMG: chunk %2zu, %p->%p", seqnr, jpeg_buffer.data(),
00112                 //              jpeg_buffer.data() + (PAYLOAD_SIZE * seqnr));
00113         }
00114 }
00115 
00116 void image_cb(const sensor_msgs::Image::ConstPtr &img_msg)
00117 {
00118         constexpr size_t PAYLOAD_SIZE = sizeof(mavlink_encapsulated_data_t::data);
00119         cv_bridge::CvImageConstPtr cv_ptr;
00120 
00121         try {
00122                 if (enc::isColor(img_msg->encoding))
00123                         cv_ptr = cv_bridge::toCvShare(img_msg, "bgr8");
00124                 else
00125                         cv_ptr = cv_bridge::toCvShare(img_msg);
00126 
00127                 // code from image_transport_plugins compressed_publisher.cpp
00128                 std::vector<int> params;
00129                 std::vector<uint8_t> jpeg_buffer;
00130                 params.resize(3, 0);
00131                 // typical image size 60-70 packet
00132                 jpeg_buffer.reserve(80 * PAYLOAD_SIZE);
00133 
00134                 params[0] = CV_IMWRITE_JPEG_QUALITY;
00135                 params[1] = jpeg_quality;
00136 
00137                 if (cv::imencode(".jpg", cv_ptr->image, jpeg_buffer, params)) {
00138                         float comp_ratio = (float)(cv_ptr->image.rows *
00139                                         cv_ptr->image.cols *
00140                                         cv_ptr->image.elemSize())
00141                                 / jpeg_buffer.size();
00142 
00143                         ROS_DEBUG("IMG: JPEG quality %d, ratio %f", jpeg_quality, comp_ratio);
00144 
00145                         send_jpeg_image(jpeg_buffer, jpeg_quality,
00146                                         cv_ptr->image.rows,
00147                                         cv_ptr->image.cols);
00148                 }
00149                 else {
00150                         ROS_ERROR("IMG: cv::imencode (jpeg) failed");
00151                         return;
00152                 }
00153         }
00154         catch (cv_bridge::Exception &ex) {
00155                 ROS_ERROR("IMG: %s", ex.what());
00156         }
00157         catch (cv::Exception &ex) {
00158                 ROS_ERROR("IMG: %s", ex.what());
00159         }
00160 }
00161 
00162 int main(int argc, char *argv[])
00163 {
00164         ros::init(argc, argv, "gcs_image_bridge");
00165         ros::NodeHandle priv_nh("~");
00166         ros::NodeHandle mavlink_nh("/mavlink");
00167         ros::Subscriber mavlink_sub;
00168         image_transport::ImageTransport it(mavlink_nh);
00169         image_transport::Subscriber image_sub;
00170 
00171         std::string gcs_url;
00172         priv_nh.param<std::string>("gcs_url", gcs_url, "udp://@");
00173         priv_nh.param("jpeg_quality", jpeg_quality, 60);
00174 
00175         try {
00176                 gcs_link = MAVConnInterface::open_url(gcs_url);
00177         }
00178         catch (mavconn::DeviceError &ex) {
00179                 ROS_FATAL("GCS: %s", ex.what());
00180                 return 0;
00181         }
00182 
00183         mavlink_pub = mavlink_nh.advertise<Mavlink>("to", 10);
00184         gcs_link->message_received.connect(mavlink_pub_cb);
00185 
00186         mavlink_sub = mavlink_nh.subscribe("from", 10, mavlink_sub_cb,
00187                         ros::TransportHints()
00188                                 .unreliable()
00189                                 .maxDatagramSize(1024));
00190 
00191         image_sub = it.subscribe("gcs_image", 1, image_cb);
00192 
00193         ros::spin();
00194         return 0;
00195 }
00196 


mavros_extras
Author(s): Vladimir Ermakov
autogenerated on Wed Aug 26 2015 12:29:20