Texas Aerial Robotics Documentation
mission7FlightCode.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <ros/ros.h>
3 #include <geometry_msgs/PoseStamped.h>
4 #include <nav_msgs/Odometry.h>
5 #include "std_msgs/Float64.h"
6 #include "std_msgs/String.h"
7 #include <mavros_msgs/CommandBool.h>
8 #include <mavros_msgs/SetMode.h>
9 #include <mavros_msgs/State.h>
10 #include <mavros_msgs/PositionTarget.h>
11 #include <unistd.h>
12 #include <geometry_msgs/Pose2D.h>
13 #include <mavros_msgs/CommandTOL.h>
14 #include <sensor_msgs/LaserScan.h>
15 #include <time.h>
16 #include <cmath>
17 #include <math.h>
18 #include <ros/duration.h>
19 
20 using namespace std;
21 
22 //Set global variables
23 mavros_msgs::State current_state;
24 nav_msgs::Odometry current_pose;
25 geometry_msgs::PoseStamped waypoint;
26 sensor_msgs::LaserScan current_2D_scan;
27 
28 std_msgs::String MODE;
29 float GYM_OFFSET;
30 float x_min;
31 float x_max;
32 float y_min;
33 float y_max;
34 float z_min;
35 float z_max;
37 double RUN_START_TIME = 0;
38 bool currentlyAvoiding = false;
39 bool lidarPresent = true;
40 
41 //get armed state
42 void state_cb(const mavros_msgs::State::ConstPtr& msg)
43 {
44  current_state = *msg;
45 }
46 //get current position of drone
47 void pose_cb(const nav_msgs::Odometry::ConstPtr& msg)
48 {
49  current_pose = *msg;
50  float q0 = current_pose.pose.pose.orientation.w;
51  float q1 = current_pose.pose.pose.orientation.x;
52  float q2 = current_pose.pose.pose.orientation.y;
53  float q3 = current_pose.pose.pose.orientation.z;
54  float psi = atan2((2*(q0*q3 + q1*q2)), (1 - 2*(pow(q2,2) + pow(q3,2))) );
55  current_heading = -psi*(180/M_PI) + 90;
56  ROS_INFO("Current Heading %f ", current_heading);
57  // ROS_INFO("x: %f y: %f z: %f", current_pose.pose.pose.position.x, current_pose.pose.pose.position.y, current_pose.pose.pose.position.z);
58 }
59 void mode_cb(const std_msgs::String::ConstPtr& msg)
60 {
61  MODE = *msg;
62  //ROS_INFO("current mode: %s", MODE.data.c_str());
63 }
64 void scan_cb(const sensor_msgs::LaserScan::ConstPtr& msg)
65 {
66  current_2D_scan = *msg;
67 }
68 //set orientation of the drone (drone should always be level)
69 void setHeading(float heading)
70 {
71  heading = -heading + 90 - GYM_OFFSET;
72  float yaw = heading*(M_PI/180);
73  float pitch = 0;
74  float roll = 0;
75 
76  float cy = cos(yaw * 0.5);
77  float sy = sin(yaw * 0.5);
78  float cr = cos(roll * 0.5);
79  float sr = sin(roll * 0.5);
80  float cp = cos(pitch * 0.5);
81  float sp = sin(pitch * 0.5);
82 
83  float qw = cy * cr * cp + sy * sr * sp;
84  float qx = cy * sr * cp - sy * cr * sp;
85  float qy = cy * cr * sp + sy * sr * cp;
86  float qz = sy * cr * cp - cy * sr * sp;
87 
88  waypoint.pose.orientation.w = qw;
89  waypoint.pose.orientation.x = qx;
90  waypoint.pose.orientation.y = qy;
91  waypoint.pose.orientation.z = qz;
92 }
93 void setHeading_cb(const std_msgs::Float64::ConstPtr& msg)
94 {
95  std_msgs::Float64 set_heading = *msg;
96  setHeading(set_heading.data);
97  // ROS_INFO("current heading: %f", current_heading.data);
98 }
99 // set position to fly to in the gym frame
100 void setDestination(float x, float y, float z)
101 {
102  float deg2rad = (M_PI/180);
103  float X = x*cos(-GYM_OFFSET*deg2rad) - y*sin(-GYM_OFFSET*deg2rad);
104  float Y = x*sin(-GYM_OFFSET*deg2rad) + y*cos(-GYM_OFFSET*deg2rad);
105  float Z = z;
106  waypoint.pose.position.x = X;
107  waypoint.pose.position.y = Y;
108  waypoint.pose.position.z = Z;
109  // ROS_INFO("Destination set to x: %f y: %f z: %f", X, Y, Z);
110  cout << "Destination set to x: " << X << " y: " << Y << " z: " << Z << endl;
111 }
112 
113 //initialize ROS
114 void init_ros()
115 {
116  ROS_INFO("INITIALIZING ROS");
117  for(int i=0; i<100; i++)
118  {
119  ros::spinOnce();
120  ros::Duration(0.01).sleep();
121  }
122 }
123 
124 // update waypoint from strat but check inputs
125 void waypoint_update(const geometry_msgs::PoseStamped::ConstPtr& msg)
126 {
127  geometry_msgs::PoseStamped waypoint_eval;
128  waypoint_eval = *msg;
129  float way_x = waypoint_eval.pose.position.x;
130  float way_y = waypoint_eval.pose.position.y;
131  float way_z = waypoint_eval.pose.position.z;
132 
133  if(!currentlyAvoiding)
134  {
135  if(way_z < z_max && way_z > z_min && way_x < x_max && way_x > x_min && way_y < y_max && way_y > y_min)
136  {
137  waypoint.pose.position.x = way_x;
138  waypoint.pose.position.y = way_y;
139  waypoint.pose.position.z = way_z;
140  setDestination(way_x,way_y,way_z);
141  }
142  else
143  {
144  ROS_INFO("The waypoint passed is out of bounds at x,y,z = %f,%f,%f",way_x,way_y,way_z);
145  }
146  }
147  else
148  {
149  ROS_INFO("Waypoint ignored. Obs avoidance in progress...");
150  }
151 }
152 
153 int main(int argc, char** argv)
154 {
155  ros::init(argc, argv, "offb_node");
156  ros::NodeHandle controlnode;
157 
158  ros::param::get("/contols_params/safety_limits/xlim/min", x_min);
159  ros::param::get("/contols_params/safety_limits/xlim/max", x_max);
160  ros::param::get("/contols_params/safety_limits/ylim/min", y_min);
161  ros::param::get("/contols_params/safety_limits/ylim/max", y_max);
162  ros::param::get("/contols_params/safety_limits/xlim/min", z_min);
163  ros::param::get("/contols_params/safety_limits/xlim/max", z_max);
164 
165  ros::Rate rate(5.0);
166  ros::Publisher gym_offset_pub = controlnode.advertise<std_msgs::Float64>("gymOffset", 1);
167  ros::Publisher local_pos_pub = controlnode.advertise<geometry_msgs::PoseStamped>("mavros/setpoint_position/local", 10);
168  ros::Publisher run_start_pub = controlnode.advertise<std_msgs::Float64>("runStartTime", 1);
169  ros::Subscriber collision_sub = controlnode.subscribe<sensor_msgs::LaserScan>("/scan", 1, scan_cb);
170  ros::Subscriber currentPos = controlnode.subscribe<nav_msgs::Odometry>("mavros/global_position/local", 10, pose_cb);
171  ros::Subscriber heading_pub = controlnode.subscribe<std_msgs::Float64>("setHeading", 1, setHeading_cb);
172  ros::Subscriber mode_sub = controlnode.subscribe<std_msgs::String>("mode", 10, mode_cb);
173  ros::Subscriber state_sub = controlnode.subscribe<mavros_msgs::State>("mavros/state", 10, state_cb);
174  ros::Subscriber waypointSubscrib = controlnode.subscribe<geometry_msgs::PoseStamped>("TARwaypoint", 10, waypoint_update);
175  ros::ServiceClient arming_client = controlnode.serviceClient<mavros_msgs::CommandBool>("mavros/cmd/arming");
176  ros::ServiceClient land_client = controlnode.serviceClient<mavros_msgs::CommandTOL>("/mavros/cmd/land");
177  ros::ServiceClient set_mode_client = controlnode.serviceClient<mavros_msgs::SetMode>("/mavros/set_mode");
178  ros::ServiceClient takeoff_client = controlnode.serviceClient<mavros_msgs::CommandTOL>("/mavros/cmd/takeoff");
179 
180  // wait for FCU connection
181  while (ros::ok() && !current_state.connected)
182  {
183  ros::spinOnce();
184  rate.sleep();
185  }
186  ROS_INFO("Connected to FCU");
187  // wait for mode to be set to guided
188  while (current_state.mode != "GUIDED")
189  {
190  ros::spinOnce();
191  rate.sleep();
192  }
193  RUN_START_TIME = ros::Time::now().toSec();
194 
195  // Publish mission start time
196  std_msgs::Float64 runStartTime;
197  runStartTime.data = RUN_START_TIME;
198  run_start_pub.publish(runStartTime);
199  ROS_INFO("Run start time %f", RUN_START_TIME);
200  ROS_INFO("Mode set to GUIDED");
201 
202  //set the orientation of the gym
203  GYM_OFFSET = 0;
204  for (int i = 1; i <= 30; ++i) {
205  ros::spinOnce();
206  ros::Duration(0.1).sleep();
207 
208  float q0 = current_pose.pose.pose.orientation.w;
209  float q1 = current_pose.pose.pose.orientation.x;
210  float q2 = current_pose.pose.pose.orientation.y;
211  float q3 = current_pose.pose.pose.orientation.z;
212  float psi = atan2((2*(q0*q3 + q1*q2)), (1 - 2*(pow(q2,2) + pow(q3,2))) ); // yaw
213 
214  GYM_OFFSET += psi*(180/M_PI);
215  // ROS_INFO("current heading%d: %f", i, GYM_OFFSET/i);
216  }
217  GYM_OFFSET /= -30;
218  GYM_OFFSET += 90;
219  ROS_INFO("the N' axis is facing: %f", GYM_OFFSET);
220  cout << GYM_OFFSET << "\n" << endl;
221  std_msgs::Float64 gymOffset;
222  gymOffset.data = GYM_OFFSET;
223  gym_offset_pub.publish(gymOffset);
224 
225  // arming
226  mavros_msgs::CommandBool arm_request;
227  arm_request.request.value = true;
228  while (!current_state.armed && !arm_request.response.success)
229  {
230  ros::Duration(.1).sleep();
231  arming_client.call(arm_request);
232  }
233  ROS_INFO("ARM sent %d", arm_request.response.success);
234 
235 
236  //request takeoff
237  mavros_msgs::CommandTOL takeoff_request;
238  takeoff_request.request.altitude = 1.5;
239 
240  while (!takeoff_request.response.success)
241  {
242  ros::Duration(.1).sleep();
243  takeoff_client.call(takeoff_request);
244  }
245  ROS_INFO("Takeoff initialized");
246  sleep(10);
247 
248  setDestination(0,0,1.5);
249  setHeading(0);
250 
251  // 2D spinning LIDAR params
252  float tollorance = .35;
253  float scanMinRange = .45;
254  float scanMaxRange = 1.75;
255 
256  while(ros::ok())
257  {
258  ros::spinOnce();
259  rate.sleep();
260 
261  // 2D LIDAR obstacle avoidance
262  int scanRayIndex = 2;
263  int scanSize = current_2D_scan.ranges.size();
264  while(lidarPresent && ((scanRayIndex+2) < scanSize)) {
265  scanRayIndex++;
266  ros::spinOnce();
267 
268  // check if 5 consecutive readings are in bounds we care about
269  if((((current_2D_scan.ranges[scanRayIndex-2] < scanMaxRange) && (current_2D_scan.ranges[scanRayIndex-2] > scanMinRange)) &&
270  ((current_2D_scan.ranges[scanRayIndex-1] < scanMaxRange) && (current_2D_scan.ranges[scanRayIndex-1] > scanMinRange)) &&
271  ((current_2D_scan.ranges[scanRayIndex+0] < scanMaxRange) && (current_2D_scan.ranges[scanRayIndex+0] > scanMinRange)) &&
272  ((current_2D_scan.ranges[scanRayIndex+1] < scanMaxRange) && (current_2D_scan.ranges[scanRayIndex+1] > scanMinRange)) &&
273  ((current_2D_scan.ranges[scanRayIndex+2] < scanMaxRange) && (current_2D_scan.ranges[scanRayIndex+2] > scanMinRange))))
274  {
275  break; // if so, stop scanning and move on
276  }
277  // Prints if we got a few detections but not a full 5
278  if(current_2D_scan.ranges[scanRayIndex] < scanMaxRange && current_2D_scan.ranges[scanRayIndex] > scanMinRange)
279  {
280  ROS_INFO("Index[%d]: %f", scanRayIndex, current_2D_scan.ranges[scanRayIndex]);
281  }
282  if(!lidarPresent || (scanRayIndex+3) == scanSize) // scanRayIndex+2 because checking multiple rays and +1 because less than in while loop
283  {
284  currentlyAvoiding = false;
285  }
286  }
287  if(lidarPresent && (scanRayIndex < scanSize && scanRayIndex > 0 && current_2D_scan.ranges[scanRayIndex] < scanMaxRange && current_2D_scan.ranges[scanRayIndex] > scanMinRange))
288  {
289  double angle_of_obstacle_RAD = current_2D_scan.angle_increment*scanRayIndex;
290  ROS_INFO("Obstacle sighted @%f (current_2D_scan.angle_increment: %f * scanRayIndex: %d)", angle_of_obstacle_RAD, current_2D_scan.angle_increment, scanRayIndex);
291  ROS_INFO("-------------------SKRTT SKRTT-------------------");
292 
293  //get current position in gym frame
294  float deg2rad = (M_PI/180);
295  float X = current_pose.pose.pose.position.x*cos(GYM_OFFSET*deg2rad) - current_pose.pose.pose.position.y*sin(GYM_OFFSET*deg2rad);
296  float Y = current_pose.pose.pose.position.x*sin(GYM_OFFSET*deg2rad) + current_pose.pose.pose.position.y*cos(GYM_OFFSET*deg2rad);
297  float Z = 1.5;
298  ROS_INFO("x: %f y: %f z: %f", X, Y, Z);
299 
300  double radius = current_2D_scan.ranges[scanRayIndex];
301  double why = radius * sin(angle_of_obstacle_RAD);
302  double ex = radius * cos(angle_of_obstacle_RAD);
303 
304  ROS_INFO("radius: %f, ex: %f, why: %f", radius, ex, why);
305 
306  //avoidance vector relative to the drone
307  float avoidXdrone = (ex/radius)*(-1.328);
308  float avoidYdrone = (why/radius)*(-1.328);
309 
310  //Transform to gym refernce frame
311  float avoidXgym = avoidXdrone*cos(-(current_heading-GYM_OFFSET)*deg2rad) - avoidYdrone*sin(-(current_heading-GYM_OFFSET)*deg2rad);
312  float avoidYgym = avoidXdrone*sin(-(current_heading-GYM_OFFSET)*deg2rad) + avoidYdrone*cos(-(current_heading-GYM_OFFSET)*deg2rad);
313 
314  ROS_INFO("goto x: %f, y: %f", avoidXgym, avoidYgym);
315  setDestination((X + avoidXgym), (Y + avoidYgym), Z);
316  currentlyAvoiding = true;
317 
318  rate.sleep();
319  rate.sleep();
320  rate.sleep();
321  }
322 
323 
324  // LAND if StratNode says to or ten min run is done (600 sec == ten min)
325  if((MODE.data == "LAND" || ((ros::Time::now().toSec()-RUN_START_TIME) > 590)) && !currentlyAvoiding)
326  {
327  mavros_msgs::CommandTOL srv_land;
328  if(land_client.call(srv_land) && srv_land.response.success)
329  ROS_INFO("land sent %d", srv_land.response.success);
330  else
331  {
332  ROS_ERROR("Landing failed");
333  }
334  }
335  else if(MODE.data == "TAKEOFF")
336  {
337  while (current_state.armed && current_state.mode == "LAND")
338  {
339  rate.sleep();
340  ros::spinOnce();
341  }
342  ros::Duration(5).sleep();
343 
344  while (current_state.mode == "LAND")
345  {
346  //set flight mode to guided
347  mavros_msgs::SetMode srv_setMode;
348  srv_setMode.request.base_mode = 0;
349  srv_setMode.request.custom_mode = "GUIDED";
350  if(set_mode_client.call(srv_setMode)){
351  ROS_INFO("setmode send ok");
352  }else{
353  ROS_ERROR("Failed SetMode");
354  return -1;
355  }
356  ros::Duration(.5).sleep();
357  ros::spinOnce();
358  }
359  // arming
360  mavros_msgs::CommandBool arm_request;
361  arm_request.request.value = true;
362  while (!current_state.armed && current_state.mode == "GUIDED")
363  {
364  arming_client.call(arm_request);
365  ros::Duration(.1).sleep();
366  ros::spinOnce();
367  }
368  ROS_INFO("ARM sent %d", arm_request.response.success);
369  mavros_msgs::CommandTOL takeoff_request;
370  takeoff_request.request.altitude = 1.5;
371 
372  while (!takeoff_request.response.success && current_state.mode == "GUIDED")
373  {
374  takeoff_client.call(takeoff_request);
375  ros::Duration(.1).sleep();
376  ros::spinOnce();
377  }
378  ROS_INFO("Takeoff sent");
379  ros::Duration(5).sleep();
380  }
381 
382  local_pos_pub.publish(waypoint);
383  gym_offset_pub.publish(gymOffset);
384  }
385  return 0;
386 }
sensor_msgs::LaserScan current_2D_scan
void pose_cb(const nav_msgs::Odometry::ConstPtr &msg)
ros::Subscriber state_sub
void set_heading(float heading)
ros::ServiceClient land_client
mavros_msgs::State current_state
std_msgs::String MODE
bool lidarPresent
ros::ServiceClient takeoff_client
float x_max
ros::ServiceClient set_mode_client
void mode_cb(const std_msgs::String::ConstPtr &msg)
float GYM_OFFSET
ros::Subscriber currentPos
float z_max
void scan_cb(const sensor_msgs::LaserScan::ConstPtr &msg)
float y_min
double RUN_START_TIME
void state_cb(const mavros_msgs::State::ConstPtr &msg)
nav_msgs::Odometry current_pose
void setHeading_cb(const std_msgs::Float64::ConstPtr &msg)
ros::Publisher local_pos_pub
float x_min
float current_heading
float z_min
void setHeading(float heading)
float y_max
void setDestination(float x, float y, float z)
ros::ServiceClient arming_client
void waypoint_update(const geometry_msgs::PoseStamped::ConstPtr &msg)
void init_ros()
int main(int argc, char **argv)
bool currentlyAvoiding
geometry_msgs::PoseStamped waypoint