00001
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <mavros/mavros_plugin.h>
00028 #include <pluginlib/class_list_macros.h>
00029
00030 #include <sensor_msgs/image_encodings.h>
00031 #include <image_transport/image_transport.h>
00032 #include <cv_bridge/cv_bridge.h>
00033 #include <cv.h>
00034 #include <highgui.h>
00035
00036 namespace mavplugin {
00037 namespace enc = sensor_msgs::image_encodings;
00038
00044 class ImagePubPlugin : public MavRosPlugin {
00045 public:
00046 ImagePubPlugin() :
00047 im_width(0), im_height(0),
00048 im_size(0), im_packets(0), im_payload(0),
00049 im_seqnr(0), im_type(255),
00050 im_buffer{}
00051 { };
00052
00053 void initialize(UAS &uas_,
00054 ros::NodeHandle &nh,
00055 diagnostic_updater::Updater &diag_updater)
00056 {
00057 nh.param<std::string>("camera_frame_id", frame_id, "px4flow");
00058
00059 itp = boost::make_shared<image_transport::ImageTransport>(nh);
00060 image_pub = itp->advertise("camera_image", 1);
00061 }
00062
00063 const std::string get_name() const {
00064 return "ImagePub";
00065 }
00066
00067 const message_map get_rx_handlers() {
00068 return {
00069 MESSAGE_HANDLER(MAVLINK_MSG_ID_DATA_TRANSMISSION_HANDSHAKE, &ImagePubPlugin::handle_data_transmission_handshake),
00070 MESSAGE_HANDLER(MAVLINK_MSG_ID_ENCAPSULATED_DATA, &ImagePubPlugin::handle_encapsulated_data)
00071 };
00072 }
00073
00074 private:
00075 boost::shared_ptr<image_transport::ImageTransport> itp;
00076 image_transport::Publisher image_pub;
00077
00078 std::string frame_id;
00079
00080 size_t im_width, im_height;
00081 size_t im_size, im_packets, im_payload;
00082 size_t im_seqnr;
00083 uint8_t im_type;
00084 std::vector<uint8_t> im_buffer;
00085
00087 static constexpr size_t MAX_BUFFER_RESERVE_DIFF = 0x20000;
00088
00089 bool check_supported_type(uint8_t type) const {
00090 return (type == MAVLINK_DATA_STREAM_IMG_JPEG ||
00091 type == MAVLINK_DATA_STREAM_IMG_BMP ||
00092 type == MAVLINK_DATA_STREAM_IMG_RAW8U ||
00093
00094 type == MAVLINK_DATA_STREAM_IMG_PGM ||
00095 type == MAVLINK_DATA_STREAM_IMG_PNG);
00096 }
00097
00098 void publish_raw8u_image() {
00099 sensor_msgs::ImagePtr image = boost::make_shared<sensor_msgs::Image>();
00100
00101 image->header.frame_id = frame_id;
00102 image->header.stamp = ros::Time::now();
00103 image->height = im_height;
00104 image->width = im_width;
00105 image->encoding = enc::MONO8;
00106 image->is_bigendian = false;
00107 image->step = im_width;
00108 image->data = im_buffer;
00109
00110 image_pub.publish(image);
00111 }
00112
00113 void publish_compressed_image() {
00114 cv_bridge::CvImagePtr cv_ptr(new cv_bridge::CvImage);
00115
00116 cv_ptr->header.frame_id = frame_id;
00117 cv_ptr->header.stamp = ros::Time::now();
00118
00119 try {
00120 cv_ptr->image = cv::imdecode(cv::Mat(im_buffer), CV_LOAD_IMAGE_UNCHANGED);
00121 if (cv_ptr->image.channels() == 1)
00122 cv_ptr->encoding = enc::MONO8;
00123 else
00124 cv_ptr->encoding = enc::BGR8;
00125 }
00126 catch (cv::Exception &ex) {
00127 ROS_ERROR_NAMED("image", "IMG: %s", ex.what());
00128 return;
00129 }
00130
00131 image_pub.publish(cv_ptr->toImageMsg());
00132 }
00133
00134 void publish_image() {
00135 switch (im_type) {
00136 case MAVLINK_DATA_STREAM_IMG_RAW8U:
00137 publish_raw8u_image();
00138 break;
00139 case MAVLINK_DATA_STREAM_IMG_JPEG:
00140 case MAVLINK_DATA_STREAM_IMG_BMP:
00141 case MAVLINK_DATA_STREAM_IMG_PGM:
00142 case MAVLINK_DATA_STREAM_IMG_PNG:
00143 publish_compressed_image();
00144 break;
00145 default:
00146 ROS_ERROR_NAMED("image", "IMG: Unsupported image type: %d", im_type);
00147 }
00148 }
00149
00150 void handle_data_transmission_handshake(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
00151 mavlink_data_transmission_handshake_t img_header;
00152 mavlink_msg_data_transmission_handshake_decode(msg, &img_header);
00153
00154 if (!check_supported_type(img_header.type)) {
00155 ROS_WARN_NAMED("image", "IMG: Unknown stream type: %d", img_header.type);
00156 im_packets = 0;
00157 return;
00158 }
00159
00160
00161 im_seqnr = 0;
00162 im_type = img_header.type;
00163 im_size = img_header.size;
00164 im_width = img_header.width;
00165 im_height = img_header.height;
00166 im_packets = img_header.packets;
00167 im_payload = img_header.payload;
00168
00169 ROS_DEBUG_NAMED("image", "IMG: header: %zu x %zu t:%d, %zu bytes in %zu packets",
00170 im_width, im_height, im_type,
00171 im_size, im_packets);
00172
00173
00174 im_buffer.clear();
00175 if (im_buffer.capacity() < im_size ||
00176 im_buffer.capacity() > im_size + MAX_BUFFER_RESERVE_DIFF) {
00177 im_buffer.reserve(im_size);
00178 }
00179 }
00180
00181 void handle_encapsulated_data(const mavlink_message_t *msg, uint8_t sysid, uint8_t compid) {
00182 if (im_packets == 0)
00183 return;
00184
00185 mavlink_encapsulated_data_t img_data;
00186 mavlink_msg_encapsulated_data_decode(msg, &img_data);
00187
00188 size_t seqnr = img_data.seqnr;
00189
00190
00191 if (seqnr + 1 > im_packets) {
00192 ROS_ERROR_NAMED("image", "IMG: More data packets, than specified in handshake, seqnr: %zu, packets: %zu",
00193 seqnr, im_packets);
00194 im_packets = 0;
00195 return;
00196 }
00197
00198 if (seqnr > im_seqnr) {
00199 ROS_WARN_NAMED("image", "IMG: %zu data packets probably lost", seqnr - im_seqnr);
00200
00201 im_buffer.resize(std::min(im_size, (seqnr - 1) * im_payload), 0);
00202 im_seqnr = seqnr;
00203 }
00204
00205 size_t bytes_to_copy = im_payload;
00206 if (seqnr * im_payload + bytes_to_copy >= im_size)
00207 bytes_to_copy = im_size - seqnr * im_payload;
00208
00209 if (seqnr == im_seqnr) {
00210
00211 im_seqnr++;
00212 im_buffer.insert(im_buffer.end(), img_data.data, img_data.data + bytes_to_copy);
00213 }
00214 else {
00215
00216 ROS_DEBUG_NAMED("image", "IMG: reordered data message, seqnr: %zu, waiting: %zu",
00217 seqnr, im_seqnr);
00218 memcpy(im_buffer.data() + (seqnr * im_payload), img_data.data, bytes_to_copy);
00219 }
00220
00221 if (seqnr + 1 == im_packets) {
00222 im_packets = 0;
00223 publish_image();
00224 }
00225 }
00226 };
00227
00228 };
00229
00230 PLUGINLIB_EXPORT_CLASS(mavplugin::ImagePubPlugin, mavplugin::MavRosPlugin)