18 #include <opencv2/opencv.hpp> 25 #include <mavros_msgs/OpticalFlowRad.h> 26 #include <sensor_msgs/Imu.h> 27 #include <geometry_msgs/Vector3Stamped.h> 28 #include <geometry_msgs/PointStamped.h> 29 #include <geometry_msgs/TwistStamped.h> 46 mavros_msgs::OpticalFlowRad
flow_;
67 local_frame_id_ = nh.
param<std::string>(
"mavros/local_position/tf/frame_id",
"map");
68 fcu_frame_id_ = nh.
param<std::string>(
"mavros/local_position/tf/child_frame_id",
"base_link");
69 roi_px_ = nh_priv.
param(
"roi", 128);
70 roi_rad_ = nh_priv.
param(
"roi_rad", 0.0);
71 calc_flow_gyro_ = nh_priv.
param(
"calc_flow_gyro",
false);
75 flow_pub_ = nh.
advertise<mavros_msgs::OpticalFlowRad>(
"mavros/px4flow/raw/send", 1);
76 velo_pub_ = nh_priv.
advertise<geometry_msgs::TwistStamped>(
"angular_velocity", 1);
77 shift_pub_ = nh_priv.
advertise<geometry_msgs::Vector3Stamped>(
"shift", 1);
79 flow_.integrated_xgyro = NAN;
80 flow_.integrated_ygyro = NAN;
81 flow_.integrated_zgyro = NAN;
82 flow_.time_delta_distance_us = 0;
84 flow_.temperature = 0;
90 for (
int i = 0; i < 3; ++i) {
91 for (
int j = 0; j < 3; ++j) {
92 camera_matrix_.at<
double>(i, j) = cinfo->K[3 * i + j];
95 dist_coeffs_ = cv::Mat(cinfo->D,
true);
100 double brightness = (1 - quality) * 25;;
101 cv::Scalar color(brightness, brightness, brightness);
102 double radius = std::sqrt(x * x + y * y);
105 cv::Point center(frame.cols >> 1, frame.rows >> 1);
106 cv::circle(frame, center, (
int)(radius*5), color, 3, cv::LINE_AA);
107 cv::line(frame, center, cv::Point(center.x + (
int)(x*5), center.y + (
int)(y*5)), color, 3, cv::LINE_AA);
110 void flow(
const sensor_msgs::ImageConstPtr& msg,
const sensor_msgs::CameraInfoConstPtr& cinfo)
116 if (roi_.width == 0) {
119 std::vector<cv::Point3f> object_points = {
120 cv::Point3f(-
sin(roi_rad_ / 2), -
sin(roi_rad_ / 2),
cos(roi_rad_ / 2)),
121 cv::Point3f(
sin(roi_rad_ / 2),
sin(roi_rad_ / 2),
cos(roi_rad_ / 2)),
124 std::vector<double> vec { 0, 0, 0 };
125 std::vector<cv::Point2f> img_points;
126 cv::projectPoints(object_points, vec, vec, camera_matrix_, dist_coeffs_, img_points);
128 roi_ = cv::Rect(cv::Point2i(round(img_points[0].
x), round(img_points[0].
y)),
129 cv::Point2i(round(img_points[1].x), round(img_points[1].y)));
131 ROS_INFO(
"ROI: %d %d - %d %d ", roi_.tl().x, roi_.tl().y, roi_.br().x, roi_.br().y);
133 }
else if (roi_px_ != 0) {
134 roi_ = cv::Rect((msg->width / 2 - roi_px_ / 2), (msg->height / 2 - roi_px_ / 2), roi_px_, roi_px_);
138 if (roi_.width != 0) {
143 img.convertTo(curr_, CV_32F);
146 prev_ = curr_.clone();
147 prev_stamp_ = msg->header.stamp;
148 cv::createHanningWindow(hann_, curr_.size(), CV_32F);
152 cv::Point2d shift = cv::phaseCorrelate(prev_, curr_, hann_, &response);
155 static geometry_msgs::Vector3Stamped shift_vec;
156 shift_vec.header.stamp = msg->header.stamp;
157 shift_vec.header.frame_id = msg->header.frame_id;
158 shift_vec.vector.x = shift.x;
159 shift_vec.vector.y = shift.y;
163 uint32_t flow_center_x = msg->width / 2;
164 uint32_t flow_center_y = msg->height / 2;
165 shift.x += flow_center_x;
166 shift.y += flow_center_y;
168 std::vector<cv::Point2d> points_dist = { shift };
169 std::vector<cv::Point2d> points_undist(1);
171 cv::undistortPoints(points_dist, points_undist, camera_matrix_, dist_coeffs_, cv::noArray(), camera_matrix_);
172 points_undist[0].x -= flow_center_x;
173 points_undist[0].y -= flow_center_y;
176 double focal_length_x = camera_matrix_.at<
double>(0, 0);
177 double focal_length_y = camera_matrix_.at<
double>(1, 1);
178 double flow_x =
atan2(points_undist[0].
x, focal_length_x);
179 double flow_y =
atan2(points_undist[0].
y, focal_length_y);
182 static geometry_msgs::Vector3Stamped flow_camera, flow_fcu;
183 flow_camera.header.frame_id = msg->header.frame_id;
184 flow_camera.header.stamp = msg->header.stamp;
185 flow_camera.vector.x = flow_y;
186 flow_camera.vector.y = -flow_x;
188 tf_buffer_->transform(flow_camera, flow_fcu, fcu_frame_id_);
196 uint32_t integration_time_us = integration_time.
toSec() * 1.0e6;
198 if (calc_flow_gyro_) {
200 auto flow_gyro_camera =
calcFlowGyro(msg->header.frame_id, prev_stamp_, msg->header.stamp);
201 static geometry_msgs::Vector3Stamped flow_gyro_fcu;
202 tf_buffer_->transform(flow_gyro_camera, flow_gyro_fcu, fcu_frame_id_);
203 flow_.integrated_xgyro = flow_gyro_fcu.vector.x;
204 flow_.integrated_ygyro = flow_gyro_fcu.vector.y;
205 flow_.integrated_zgyro = flow_gyro_fcu.vector.z;
214 flow_.header.stamp = msg->header.stamp;
215 flow_.integration_time_us = integration_time_us;
216 flow_.integrated_x = flow_fcu.vector.x;
217 flow_.integrated_y = flow_fcu.vector.y;
218 flow_.quality = (uint8_t)(response * 255);
224 drawFlow(img, shift_vec.vector.x, shift_vec.vector.y, response);
226 out_msg.
header.frame_id = msg->header.frame_id;
227 out_msg.
header.stamp = msg->header.stamp;
234 static geometry_msgs::TwistStamped velo;
235 velo.header.stamp = msg->header.stamp;
237 velo.twist.angular.x = flow_.integrated_x / integration_time.
toSec();
238 velo.twist.angular.y = flow_.integrated_y / integration_time.
toSec();
241 prev_ = curr_.clone();
242 prev_stamp_ = msg->header.stamp;
249 tf2::fromMsg(tf_buffer_->lookupTransform(frame_id, local_frame_id_, prev).transform.rotation, prev_rot);
250 tf2::fromMsg(tf_buffer_->lookupTransform(frame_id, local_frame_id_, curr,
ros::Duration(0.1)).transform.rotation, curr_rot);
252 geometry_msgs::Vector3Stamped
flow;
254 flow.header.stamp = curr;
256 auto diff = ((curr_rot - prev_rot) * prev_rot.
inverse()) * 2.0
f;
257 flow.vector.x = -
diff.x();
258 flow.vector.y = -
diff.y();
259 flow.vector.z = -
diff.z();
CvImageConstPtr toCvShare(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
image_transport::CameraSubscriber img_sub_
uint32_t getNumSubscribers() const
CameraSubscriber subscribeCamera(const std::string &base_topic, uint32_t queue_size, const CameraSubscriber::Callback &callback, const ros::VoidPtr &tracked_object=ros::VoidPtr(), const TransportHints &transport_hints=TransportHints())
ros::NodeHandle & getNodeHandle() const
Publisher advertise(const std::string &base_topic, uint32_t queue_size, bool latch=false)
std::string local_frame_id_
std::unique_ptr< tf2_ros::TransformListener > tf_listener_
ros::NodeHandle & getPrivateNodeHandle() const
mavlink::common::MAV_FRAME frame
std::string fcu_frame_id_
mavros_msgs::OpticalFlowRad flow_
ros::Publisher shift_pub_
sensor_msgs::ImagePtr toImageMsg() const
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
void publish(const boost::shared_ptr< M > &message) const
void fromMsg(const A &, B &b)
Quaternion inverse() const
std::unique_ptr< tf2_ros::Buffer > tf_buffer_
void parseCameraInfo(const sensor_msgs::CameraInfoConstPtr &cinfo)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
geometry_msgs::Vector3Stamped calcFlowGyro(const std::string &frame_id, const ros::Time &prev, const ros::Time &curr)
void flow(const sensor_msgs::ImageConstPtr &msg, const sensor_msgs::CameraInfoConstPtr &cinfo)
void publish(const sensor_msgs::Image &message) const
#define NODELET_INFO(...)
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
image_transport::Publisher img_pub_
void drawFlow(Mat &frame, double x, double y, double quality) const
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)