15 #include <boost/format.hpp> 17 #include <GeographicLib/Geodesic.hpp> 25 #include <std_srvs/Trigger.h> 26 #include <geometry_msgs/PoseStamped.h> 27 #include <geometry_msgs/TwistStamped.h> 28 #include <geometry_msgs/Vector3Stamped.h> 29 #include <geometry_msgs/QuaternionStamped.h> 30 #include <sensor_msgs/NavSatFix.h> 31 #include <sensor_msgs/BatteryState.h> 32 #include <mavros_msgs/CommandBool.h> 33 #include <mavros_msgs/SetMode.h> 34 #include <mavros_msgs/PositionTarget.h> 35 #include <mavros_msgs/AttitudeTarget.h> 36 #include <mavros_msgs/Thrust.h> 37 #include <mavros_msgs/State.h> 38 #include <mavros_msgs/StatusText.h> 39 #include <mavros_msgs/ManualControl.h> 41 #include <clover/GetTelemetry.h> 42 #include <clover/Navigate.h> 43 #include <clover/NavigateGlobal.h> 44 #include <clover/SetPosition.h> 45 #include <clover/SetVelocity.h> 46 #include <clover/SetAttitude.h> 47 #include <clover/SetRates.h> 54 using mavros_msgs::PositionTarget;
55 using mavros_msgs::AttitudeTarget;
56 using mavros_msgs::Thrust;
97 geometry_msgs::TransformStamped
body;
134 template<
typename T, T& STORAGE>
143 if (s.mode !=
"OFFBOARD") {
151 if (
body.child_frame_id.empty())
return;
180 if (tf_buffer.
canTransform(target, source, stamp))
return true;
186 #define TIMEOUT(msg, timeout) (ros::Time::now() - msg.header.stamp > timeout) 188 bool getTelemetry(GetTelemetry::Request& req, GetTelemetry::Response& res)
192 if (req.frame_id.empty())
195 res.frame_id = req.frame_id;
208 res.pitch_rate = NAN;
212 res.cell_voltage = NAN;
215 res.connected =
state.connected;
216 res.armed =
state.armed;
217 res.mode =
state.mode;
223 res.x =
transform.transform.translation.x;
224 res.y =
transform.transform.translation.y;
225 res.z =
transform.transform.translation.z;
227 double yaw, pitch, roll;
240 Vector3Stamped vec, vec_out;
241 vec.header.stamp =
velocity.header.stamp;
242 vec.header.frame_id =
velocity.header.frame_id;
244 tf_buffer.
transform(vec, vec_out, req.frame_id);
246 res.vx = vec_out.vector.x;
247 res.vy = vec_out.vector.y;
248 res.vz = vec_out.vector.z;
252 res.yaw_rate =
velocity.twist.angular.z;
253 res.pitch_rate =
velocity.twist.angular.y;
254 res.roll_rate =
velocity.twist.angular.x;
265 if (!
battery.cell_voltage.empty()) {
266 res.cell_voltage =
battery.cell_voltage[0];
278 if (
state.mode !=
"OFFBOARD") {
281 static mavros_msgs::SetMode sm;
282 sm.request.custom_mode =
"OFFBOARD";
284 if (!set_mode.
call(sm))
285 throw std::runtime_error(
"Error calling set_mode service");
290 if (
state.mode ==
"OFFBOARD") {
293 string report =
"OFFBOARD timed out";
296 throw std::runtime_error(report);
306 mavros_msgs::CommandBool srv;
307 srv.request.value =
true;
308 if (!arming.
call(srv)) {
309 throw std::runtime_error(
"Error calling arming service");
318 string report =
"Arming timed out";
321 throw std::runtime_error(report);
331 return std::sqrt(x * x + y * y + z * z);
336 return hypot(from.x - to.x, from.y - to.y, from.z - to.z);
347 float time = distance / speed;
348 float passed = std::min((stamp -
nav_start.header.stamp).toSec() / time, 1.0);
357 auto earth = GeographicLib::Geodesic::WGS84();
360 double _, distance, azimuth;
363 double x_offset, y_offset;
364 double azimuth_radians = azimuth * M_PI / 180;
365 x_offset = distance *
sin(azimuth_radians);
366 y_offset = distance *
cos(azimuth_radians);
369 throw std::runtime_error(
"No local position");
377 pose.pose.position.x = local.transform.translation.x + x_offset;
378 pose.pose.position.y = local.transform.translation.y + y_offset;
379 pose.pose.orientation.w = 1;
431 PositionTarget::IGNORE_VY +
432 PositionTarget::IGNORE_VZ +
433 PositionTarget::IGNORE_AFX +
434 PositionTarget::IGNORE_AFY +
435 PositionTarget::IGNORE_AFZ +
436 PositionTarget::IGNORE_YAW;
443 if (!
setpoint.child_frame_id.empty()) {
456 PositionTarget::IGNORE_PY +
457 PositionTarget::IGNORE_PZ +
458 PositionTarget::IGNORE_AFX +
459 PositionTarget::IGNORE_AFY +
460 PositionTarget::IGNORE_AFZ;
480 att_raw_msg.type_mask = AttitudeTarget::IGNORE_ATTITUDE;
495 throw std::runtime_error(
"Manual control timeout, RC is switched off?");
500 const uint8_t SWITCH_POS_NONE = 0;
501 const uint8_t SWITCH_POS_ON = 1;
502 const uint8_t SWITCH_POS_MIDDLE = 2;
503 const uint8_t SWITCH_POS_OFF = 3;
505 const int KILL_SWITCH_BIT = 12;
506 uint8_t kill_switch = (
manual_control.buttons & (0b11 << KILL_SWITCH_BIT)) >> KILL_SWITCH_BIT;
508 if (kill_switch == SWITCH_POS_ON)
509 throw std::runtime_error(
"Kill switch is on");
516 throw std::runtime_error(
"State timeout, check mavros settings");
518 if (!
state.connected)
519 throw std::runtime_error(
"No connection to FCU, https://clover.coex.tech/connection");
522 #define ENSURE_FINITE(var) { if (!std::isfinite(var)) throw std::runtime_error(#var " argument cannot be NaN or Inf"); } 525 float pitch,
float roll,
float yaw,
float pitch_rate,
float roll_rate,
float yaw_rate,
526 float lat,
float lon,
float thrust,
float speed,
string frame_id,
bool auto_arm,
527 uint8_t& success,
string& message)
533 throw std::runtime_error(
"Busy");
545 if (frame_id.empty())
554 if (!auto_arm && std::isfinite(yaw) &&
555 isnan(x) && isnan(y) && isnan(z) && isnan(vx) && isnan(vy) && isnan(vz) &&
556 isnan(pitch) && isnan(roll) && isnan(thrust) &&
557 isnan(lat) && isnan(lon)) {
561 throw std::runtime_error(
"Can't transform from " + frame_id +
" to " +
setpoint_position.header.frame_id);
563 message =
"Changing yaw only";
567 q.header.stamp =
stamp;
571 goto publish_setpoint;
573 throw std::runtime_error(
"Setting yaw is possible only when position or velocity setpoints active");
577 if (!auto_arm && std::isfinite(yaw_rate) &&
578 isnan(x) && isnan(y) && isnan(z) && isnan(vx) && isnan(vy) && isnan(vz) &&
579 isnan(pitch) && isnan(roll) && isnan(yaw) && isnan(thrust) &&
580 isnan(lat) && isnan(lon)) {
583 message =
"Changing yaw rate only";
587 goto publish_setpoint;
589 throw std::runtime_error(
"Setting yaw rate is possible only when position or velocity setpoints active");
611 }
else if (sp_type ==
RATES) {
619 throw std::runtime_error(
"No local position, check settings");
622 throw std::runtime_error(
"Navigate speed must be positive, " +
std::to_string(speed) +
" passed");
629 if (yaw_rate != 0 && !std::isnan(yaw))
630 throw std::runtime_error(
"Yaw value should be NaN for setting yaw rate");
632 if (std::isnan(yaw_rate) && std::isnan(yaw))
633 throw std::runtime_error(
"Both yaw and yaw_rate cannot be NaN");
638 throw std::runtime_error(
"No global position");
644 throw std::runtime_error(
"Can't transform from " + frame_id +
" to " + reference_frame);
648 throw std::runtime_error(
"Can't transform from " + reference_frame +
" to " +
local_frame);
654 pose_local.header.stamp =
stamp;
655 auto xy_in_req_frame = tf_buffer.
transform(pose_local, frame_id);
656 x = xy_in_req_frame.pose.position.x;
657 y = xy_in_req_frame.pose.position.y;
670 message =
"Navigating from current setpoint";
691 ps.header.stamp =
stamp;
692 ps.pose.position.x =
x;
693 ps.pose.position.y =
y;
694 ps.pose.position.z =
z;
695 ps.pose.orientation.w = 1.0;
697 if (std::isnan(yaw)) {
700 }
else if (std::isinf(yaw) && yaw > 0) {
715 static Vector3Stamped vel;
717 vel.header.stamp =
stamp;
728 if (sp_type ==
RATES) {
738 setpoint_timer.
start();
741 if (!
target.child_frame_id.empty()) {
756 }
else if (
state.mode !=
"OFFBOARD") {
757 setpoint_timer.
stop();
758 throw std::runtime_error(
"Copter is not in OFFBOARD mode, use auto_arm?");
759 }
else if (!
state.armed) {
760 setpoint_timer.
stop();
761 throw std::runtime_error(
"Copter is not armed, use auto_arm?");
764 }
catch (
const std::exception&
e) {
776 bool navigate(Navigate::Request& req, Navigate::Response& res) {
777 return serve(
NAVIGATE, req.x, req.y, req.z, NAN, NAN, NAN, NAN, NAN, req.yaw, NAN, NAN, req.yaw_rate, NAN, NAN, NAN, req.speed, req.frame_id, req.auto_arm, res.success, res.message);
780 bool navigateGlobal(NavigateGlobal::Request& req, NavigateGlobal::Response& res) {
781 return serve(
NAVIGATE_GLOBAL, NAN, NAN, req.z, NAN, NAN, NAN, NAN, NAN, req.yaw, NAN, NAN, req.yaw_rate, req.lat, req.lon, NAN, req.speed, req.frame_id, req.auto_arm, res.success, res.message);
784 bool setPosition(SetPosition::Request& req, SetPosition::Response& res) {
785 return serve(
POSITION, req.x, req.y, req.z, NAN, NAN, NAN, NAN, NAN, req.yaw, NAN, NAN, req.yaw_rate, NAN, NAN, NAN, NAN, req.frame_id, req.auto_arm, res.success, res.message);
788 bool setVelocity(SetVelocity::Request& req, SetVelocity::Response& res) {
789 return serve(
VELOCITY, NAN, NAN, NAN, req.vx, req.vy, req.vz, NAN, NAN, req.yaw, NAN, NAN, req.yaw_rate, NAN, NAN, NAN, NAN, req.frame_id, req.auto_arm, res.success, res.message);
792 bool setAttitude(SetAttitude::Request& req, SetAttitude::Response& res) {
793 return serve(
ATTITUDE, NAN, NAN, NAN, NAN, NAN, NAN, req.pitch, req.roll, req.yaw, NAN, NAN, NAN, NAN, NAN, req.thrust, NAN, req.frame_id, req.auto_arm, res.success, res.message);
796 bool setRates(SetRates::Request& req, SetRates::Response& res) {
797 return serve(
RATES, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, req.pitch_rate, req.roll_rate, req.yaw_rate, NAN, NAN, req.thrust, NAN,
"", req.auto_arm, res.success, res.message);
800 bool land(std_srvs::Trigger::Request& req, std_srvs::Trigger::Response& res)
804 throw std::runtime_error(
"Busy");
811 if (
state.mode !=
"OFFBOARD") {
812 throw std::runtime_error(
"Copter is not in OFFBOARD mode");
816 static mavros_msgs::SetMode sm;
817 sm.request.custom_mode =
"AUTO.LAND";
819 if (!set_mode.
call(sm))
820 throw std::runtime_error(
"Can't call set_mode service");
822 if (!sm.response.mode_sent)
823 throw std::runtime_error(
"Can't send set_mode request");
828 if (
state.mode ==
"AUTO.LAND") {
834 throw std::runtime_error(
"Land request timed out");
840 }
catch (
const std::exception&
e) {
841 res.message = e.what();
848 int main(
int argc,
char **argv)
850 ros::init(argc, argv,
"simple_offboard");
859 nh.
param<
string>(
"mavros/local_position/tf/child_frame_id",
fcu_frame,
"base_link");
860 nh_priv.
param(
"target_frame",
target.child_frame_id,
string(
"navigate_target"));
861 nh_priv.
param(
"setpoint",
setpoint.child_frame_id,
string(
"setpoint"));
867 nh_priv.
param<
string>(
"body_frame",
body.child_frame_id,
"body");
873 global_position_timeout =
ros::Duration(nh_priv.
param(
"global_position_timeout", 10.0));
878 telemetry_transform_timeout =
ros::Duration(nh_priv.
param(
"telemetry_transform_timeout", 0.5));
884 arming = nh.
serviceClient<mavros_msgs::CommandBool>(
"mavros/cmd/arming");
885 set_mode = nh.
serviceClient<mavros_msgs::SetMode>(
"mavros/set_mode");
889 auto velocity_sub = nh.
subscribe(
"mavros/local_position/velocity_body", 1, &handleMessage<TwistStamped, velocity>);
890 auto global_position_sub = nh.
subscribe(
"mavros/global_position/global", 1, &handleMessage<NavSatFix, global_position>);
891 auto battery_sub = nh.
subscribe(
"mavros/battery", 1, &handleMessage<BatteryState, battery>);
892 auto statustext_sub = nh.
subscribe(
"mavros/statustext/recv", 1, &handleMessage<mavros_msgs::StatusText, statustext>);
893 auto manual_control_sub = nh.
subscribe(
"mavros/manual_control/control", 1, &handleMessage<mavros_msgs::ManualControl, manual_control>);
897 position_pub = nh.
advertise<PoseStamped>(
"mavros/setpoint_position/local", 1);
898 position_raw_pub = nh.
advertise<PositionTarget>(
"mavros/setpoint_raw/local", 1);
899 attitude_pub = nh.
advertise<PoseStamped>(
"mavros/setpoint_attitude/attitude", 1);
900 attitude_raw_pub = nh.
advertise<AttitudeTarget>(
"mavros/setpoint_raw/attitude", 1);
901 rates_pub = nh.
advertise<TwistStamped>(
"mavros/setpoint_attitude/cmd_vel", 1);
902 thrust_pub = nh.
advertise<Thrust>(
"mavros/setpoint_attitude/thrust", 1);
void publishSetpoint(const ros::TimerEvent &event)
mavros_msgs::ManualControl manual_control
ros::Duration telemetry_transform_timeout
ros::Duration arming_timeout
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
std::shared_ptr< tf2_ros::StaticTransformBroadcaster > static_transform_broadcaster
GeographicLib::Geocentric earth
enum setpoint_type_t setpoint_type
void getEulerYPR(const A &a, double &yaw, double &pitch, double &roll)
ros::Publisher position_pub
T & transform(const T &in, T &out, const std::string &target_frame, ros::Duration timeout=ros::Duration(0.0)) const
Vector3Stamped setpoint_velocity_transformed
ros::Publisher position_raw_pub
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
QuaternionStamped setpoint_attitude
void handleMessage(const T &msg)
PoseStamped local_position
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
ros::Subscriber statustext_sub
double hypot(double x, double y, double z)
TransformStamped setpoint
static double getYaw(const Quaternion &bt_q)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
bool call(MReq &req, MRes &res)
bool navigateGlobal(NavigateGlobal::Request &req, NavigateGlobal::Response &res)
PoseStamped setpoint_position_transformed
bool getTelemetry(GetTelemetry::Request &req, GetTelemetry::Response &res)
ros::ServiceClient arming
PoseStamped setpoint_position
ros::Duration manual_control_timeout
geometry_msgs::TransformStamped body
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
bool waitTransform(const string &target, const string &source, const ros::Time &stamp, const ros::Duration &timeout)
std::map< string, string > reference_frames
#define ENSURE_FINITE(var)
std::string to_string(MAV_SENSOR_ORIENTATION orientation)
void checkManualControl()
PositionTarget position_raw_msg
ros::Publisher attitude_raw_pub
bool land_only_in_offboard
ros::Duration offboard_timeout
ros::Duration transform_timeout
virtual bool canTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &target_time, const ros::Duration timeout, std::string *errstr=NULL) const
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
void publish(const boost::shared_ptr< M > &message) const
ros::Duration state_timeout
ros::Duration global_position_timeout
std::shared_ptr< tf2_ros::TransformBroadcaster > transform_broadcaster
#define ROS_WARN_THROTTLE(period,...)
void setRPY(const tfScalar &roll, const tfScalar &pitch, const tfScalar &yaw)
bool getParam(const std::string &key, std::string &s) const
ros::Duration land_timeout
static void quaternionTFToMsg(const Quaternion &bt, geometry_msgs::Quaternion &msg)
QuaternionStamped setpoint_attitude_transformed
bool setVelocity(SetVelocity::Request &req, SetVelocity::Response &res)
void getNavigateSetpoint(const ros::Time &stamp, float speed, Point &nav_setpoint)
ros::Subscriber local_position_sub
bool setPosition(SetPosition::Request &req, SetPosition::Response &res)
bool setRates(SetRates::Request &req, SetRates::Response &res)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ros::Duration battery_timeout
ros::Duration local_position_timeout
ros::Duration velocity_timeout
bool serve(enum setpoint_type_t sp_type, float x, float y, float z, float vx, float vy, float vz, float pitch, float roll, float yaw, float pitch_rate, float roll_rate, float yaw_rate, float lat, float lon, float thrust, float speed, string frame_id, bool auto_arm, uint8_t &success, string &message)
double getYaw(const A &a)
bool land(std_srvs::Trigger::Request &req, std_srvs::Trigger::Response &res)
static geometry_msgs::Quaternion createQuaternionMsgFromYaw(double yaw)
ros::Publisher attitude_pub
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
static geometry_msgs::Quaternion createQuaternionMsgFromRollPitchYaw(double roll, double pitch, double yaw)
#define TIMEOUT(msg, timeout)
ros::ServiceClient set_mode
ros::Timer setpoint_timer
int main(int argc, char **argv)
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
float getDistance(const Point &from, const Point &to)
ros::Publisher thrust_pub
ROSCPP_DECL void spinOnce()
mavros_msgs::StatusText statustext
ROSCPP_DECL bool search(const std::string &ns, const std::string &key, std::string &result)
bool setAttitude(SetAttitude::Request &req, SetAttitude::Response &res)
void handleState(const mavros_msgs::State &s)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
bool navigate(Navigate::Request &req, Navigate::Response &res)
PoseStamped globalToLocal(double lat, double lon)
NavSatFix global_position
tf2_ros::Buffer tf_buffer
void publish(const ros::Time stamp)
void handleLocalPosition(const PoseStamped &pose)
AttitudeTarget att_raw_msg
enum @0 setpoint_yaw_type
Vector3Stamped setpoint_velocity