00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
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
00112
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
00128 std::vector<int> params;
00129 std::vector<uint8_t> jpeg_buffer;
00130 params.resize(3, 0);
00131
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