14 #include <ros/topic.h> 17 #include <laser_assembler/AssembleScans2.h> 20 #include <geometry_msgs/PoseStamped.h> 21 #include <geometry_msgs/TwistStamped.h> 24 #include <sensor_msgs/NavSatFix.h> 25 #include <sensor_msgs/PointCloud2.h> 28 #include <mavros_msgs/CommandBool.h> 29 #include <mavros_msgs/SetMode.h> 30 #include <mavros_msgs/State.h> 31 #include <mavros_msgs/CommandTOL.h> 32 #include <mavros_msgs/CommandHome.h> 35 #include <pcl/io/pcd_io.h> 36 #include <pcl/point_types.h> 38 #include <pcl_conversions/pcl_conversions.h> 41 const geometry_msgs::PoseStamped &goal_pose,
double threshold=0.5)
43 geometry_msgs::Point curr = curr_pose.pose.position;
44 geometry_msgs::Point goal = goal_pose.pose.position;
45 return std::sqrt(std::pow(goal.x - curr.x, 2)
46 + std::pow(goal.y - curr.y, 2)
47 + std::pow(goal.z - curr.z, 2)) > threshold ?
false :
true;
57 std::array<std::vector<double>, 2>
linearInterp(
const std::array<double, 2> &p1,
58 const std::array<double, 2> &p2,
const double step)
61 double a = (p1.at(1) - p2.at(1)) / (p1.at(0) - p2.at(0));
63 double b = p1.at(1) - a*p1.at(0);
66 int num_steps = std::floor((p2.at(0) - p1.at(0))/step);
69 std::vector<double> points_x(num_steps+1);
72 points_x.front() = p1.at(0);
73 for(
int i=1; i<num_steps; ++i)
75 points_x.at(i) = step * i + p1.at(0);
77 points_x.back() = p2.at(0);
80 std::vector<double> points_y(num_steps+1);
83 points_y.front() = p1.at(1);
84 for(
int i=1; i<num_steps; ++i)
86 points_y.at(i) = a*(p1.at(0) + i*step) + b;
88 points_y.back() = p2.at(1);
91 std::array<std::vector<double>, 2> points;
92 points.front() = points_x;
93 points.back() = points_y;
105 std::vector<geometry_msgs::PoseStamped>
getBilinearPath(
const geometry_msgs::PoseStamped &start,
106 const geometry_msgs::PoseStamped &goal,
107 const double step=0.05)
109 std::vector<geometry_msgs::PoseStamped> bilinear_path;
112 std::array<double, 2> start_xy = {start.pose.position.x, start.pose.position.y};
113 std::array<double, 2> start_xz = {start.pose.position.x, start.pose.position.z};
115 std::array<double, 2> goal_xy = {goal.pose.position.x, goal.pose.position.y};
116 std::array<double, 2> goal_xz = {goal.pose.position.x, goal.pose.position.z};
119 std::array<std::vector<double>, 2> points_xy =
linearInterp(start_xy, goal_xy, step);
120 std::array<std::vector<double>, 2> points_xz =
linearInterp(start_xz, goal_xz, step);
123 int num_points = points_xy.at(0).size();
128 for(
int i=0; i<num_points; ++i)
130 geometry_msgs::PoseStamped pose;
131 pose.pose.orientation = start.pose.orientation;
132 pose.pose.position.x = points_xy.front().at(i);
133 pose.pose.position.y = points_xy.back().at(i);
134 pose.pose.position.z = points_xz.back().at(i);
136 bilinear_path.push_back(pose);
139 catch (std::out_of_range &ex)
141 ROS_ERROR(
"%s", ex.what());
144 return bilinear_path;
147 int main(
int argc,
char **argv)
149 ros::init(argc, argv,
"simple_sweep_demo");
150 ros::NodeHandle nh(
"~");
155 geometry_msgs::PoseStamped local_pos;
157 sensor_msgs::NavSatFix global_pos;
159 geometry_msgs::TwistStamped fcu_vel;
162 ros::Subscriber state_sub = nh.subscribe<mavros_msgs::State>
163 (
"/mavros/state", 10,
164 [&
current_state](
const mavros_msgs::State::ConstPtr& msg){current_state=*msg;});
165 ros::Subscriber local_pos_sub = nh.subscribe<geometry_msgs::PoseStamped>
166 (
"/mavros/local_position/pose", 100,
167 [&local_pos](
const geometry_msgs::PoseStamped::ConstPtr& msg){local_pos=*msg;});
168 ros::Subscriber curr_gpos_sub = nh.subscribe<sensor_msgs::NavSatFix>
169 (
"/mavros/global_position/global", 10,
170 [&global_pos](
const sensor_msgs::NavSatFix::ConstPtr& msg){global_pos=*msg;});
171 ros::Subscriber fcu_vel_sub = nh.subscribe<geometry_msgs::TwistStamped>
172 (
"/mavros/local_position/velocity", 100,
173 [&fcu_vel](
const geometry_msgs::TwistStamped::ConstPtr& msg){fcu_vel=*msg;});
176 ros::Publisher target_pos_pub = nh.advertise<geometry_msgs::PoseStamped>
177 (
"/mavros/setpoint_position/local", 10);
178 ros::Publisher point_cloud_pub = nh.advertise<sensor_msgs::PointCloud2>
182 ros::ServiceClient arming_client = nh.serviceClient<mavros_msgs::CommandBool>
183 (
"/mavros/cmd/arming");
184 ros::ServiceClient set_hp_client = nh.serviceClient<mavros_msgs::CommandHome>
185 (
"/mavros/cmd/set_home");
186 ros::ServiceClient takeoff_client = nh.serviceClient<mavros_msgs::CommandTOL>
187 (
"/mavros/cmd/takeoff");
188 ros::ServiceClient landing_client = nh.serviceClient<mavros_msgs::CommandTOL>
189 (
"/mavros/cmd/land");
190 ros::ServiceClient set_mode_client = nh.serviceClient<mavros_msgs::SetMode>
191 (
"/mavros/set_mode");
192 ros::ServiceClient pc_gen_client = nh.serviceClient<laser_assembler::AssembleScans2>
193 (
"/assemble_scans2");
196 float takeoff_height;
197 nh.param<
float>(
"takeoff_height", takeoff_height, 5.5);
199 ROS_INFO(
"Takeoff height: %f", takeoff_height);
203 nh.param<
float>(
"flight_length", flight_length, 20.0);
205 ROS_INFO(
"Flight Length: %f", flight_length);
208 ros::service::waitForService(
"/assemble_scans2");
209 laser_assembler::AssembleScans2 pc_gen_cmd;
212 ros::Rate rate(20.0);
215 while(ros::ok() and current_state.connected){
221 ROS_INFO(
"Waiting for message from /mavros/global_position/global");
222 const std::string gpos_topic =
"/mavros/global_position/global";
223 sensor_msgs::NavSatFix init_gpos = *ros::topic::waitForMessage<sensor_msgs::NavSatFix>(gpos_topic);
224 double init_latitude = init_gpos.latitude;
225 double init_longitude = init_gpos.longitude;
226 double init_altitude = init_gpos.altitude;
227 ROS_INFO(
"Initial Lat: %f Lon: %f Alt: %f", init_latitude, init_longitude, init_altitude);
230 mavros_msgs::CommandBool arm_cmd;
231 arm_cmd.request.value =
true;
232 while(ros::ok() and not(arming_client.call(arm_cmd))){
236 ROS_INFO(
"Vehicle armed.");
239 mavros_msgs::CommandTOL takeoff_cmd;
240 takeoff_cmd.request.altitude = init_altitude + takeoff_height;
241 takeoff_cmd.request.longitude = init_longitude;
242 takeoff_cmd.request.latitude = init_latitude;
243 ROS_DEBUG(
"set lat: %f, lon: %f, alt: %f", init_latitude, init_longitude, init_altitude);
245 while(ros::ok() and not(takeoff_client.call(takeoff_cmd)) and
246 takeoff_cmd.response.success){
250 while(ros::ok() and local_pos.pose.position.z < takeoff_height-0.1){
253 ROS_DEBUG(
"Current lat: %f, lon: %f, alt: %f", global_pos.latitude,
254 global_pos.longitude,
255 global_pos.altitude);
257 ROS_INFO(
"Vehicle tookoff.");
259 pc_gen_cmd.request.begin = ros::Time::now();
262 geometry_msgs::PoseStamped target_pos_msg;
263 target_pos_msg.pose.position.x = 0;
264 target_pos_msg.pose.position.y = flight_length;
265 target_pos_msg.pose.position.z = takeoff_height;
266 target_pos_msg.pose.orientation.x = local_pos.pose.orientation.x;
267 target_pos_msg.pose.orientation.y = local_pos.pose.orientation.y;
268 target_pos_msg.pose.orientation.z = local_pos.pose.orientation.z;
269 target_pos_msg.pose.orientation.w = local_pos.pose.orientation.w;
271 for(
int i=0; i<100; ++i)
273 target_pos_pub.publish(target_pos_msg);
277 mavros_msgs::SetMode offb_set_mode;
278 offb_set_mode.request.custom_mode =
"OFFBOARD";
279 while(ros::ok() and not(set_mode_client.call(offb_set_mode))){
283 ROS_INFO(
"Offboard enabled.");
286 std::vector<geometry_msgs::PoseStamped> bilinear_path;
288 ROS_INFO(
"Vehicle moving forward...");
290 for(
auto pose: bilinear_path)
295 target_pos_pub.publish(pose);
306 ROS_INFO(
"Vehicle arrived destination.");
308 pc_gen_cmd.request.end = ros::Time::now();
309 ROS_INFO(
"End buffering laser scan data.");
312 mavros_msgs::CommandTOL landing_cmd;
313 landing_cmd.request.altitude = global_pos.altitude - takeoff_height + 0.5;
314 landing_cmd.request.longitude = global_pos.longitude;
315 landing_cmd.request.latitude = global_pos.latitude;
317 while(ros::ok() and not(landing_client.call(landing_cmd)) and
318 landing_cmd.response.success){
322 ROS_INFO(
"Vehicle landing...");
324 while(ros::ok() and local_pos.pose.position.z > 0.1){
328 ROS_INFO(
"Vehicle landed.");
331 arm_cmd.request.value =
false;
332 while(ros::ok() and !arming_client.call(arm_cmd) && arm_cmd.response.success){
334 ROS_INFO(
"Vehicle disarmed");
336 if (pc_gen_client.call(pc_gen_cmd)){
338 sensor_msgs::PointCloud2 ros_cloud = pc_gen_cmd.response.cloud;
340 ROS_INFO(
"Got cloud with %lu points.", ros_cloud.data.size());
341 for(
int i=0; i<10; ++i){
342 point_cloud_pub.publish(ros_cloud);
348 pcl::PointCloud<pcl::PointXYZ> pcl_cloud;
349 pcl::fromROSMsg(ros_cloud, pcl_cloud);
352 std::string home_dir = std::getenv(
"HOME");
354 pcl::io::savePCDFileASCII(home_dir+
"/sweep.pcd", pcl_cloud);
355 ROS_INFO(
"Pointcloud saved to \"$HOME/sweep.pcd\".");
356 }
catch(
const pcl::IOException& e){
357 ROS_ERROR(
"%s", e.what());
362 ROS_INFO(
"Service \"assemble_scan\" call failed.");
bool isGoalReached(const geometry_msgs::PoseStamped &curr_pose, const geometry_msgs::PoseStamped &goal_pose, double threshold=0.5)
mavros_msgs::State current_state
int main(int argc, char **argv)
std::array< std::vector< double >, 2 > linearInterp(const std::array< double, 2 > &p1, const std::array< double, 2 > &p2, const double step)
Perform linear interpolation.
std::vector< geometry_msgs::PoseStamped > getBilinearPath(const geometry_msgs::PoseStamped &start, const geometry_msgs::PoseStamped &goal, const double step=0.05)
Return interpolated path using bilinear interpolation from two waypoints.