15#include "auto_apms_px4/vehicle_command_client.hpp"
19#include "px4_ros2/utils/message_version.hpp"
24std::string toStr(VehicleCommandClient::SendCommandResult result)
27 case VehicleCommandClient::SendCommandResult::ACCEPTED:
29 case VehicleCommandClient::SendCommandResult::REJECTED:
31 case VehicleCommandClient::SendCommandResult::TIMEOUT:
38VehicleCommandClient::VehicleCommandClient(rclcpp::Node & node,
const std::chrono::milliseconds & command_timeout)
39: node_{node}, logger_{node.get_logger().get_child(
"vehicle_command_client")}, command_timeout_{command_timeout}
42 vehicle_command_pub_ = node_.create_publisher<px4_msgs::msg::VehicleCommand>(
43 "fmu/in/vehicle_command" + px4_ros2::getMessageNameVersion<px4_msgs::msg::VehicleCommand>(), 10);
45 vehicle_command_ack_sub_ = node_.create_subscription<px4_msgs::msg::VehicleCommandAck>(
46 "fmu/out/vehicle_command_ack" + px4_ros2::getMessageNameVersion<px4_msgs::msg::VehicleCommandAck>(),
47 rclcpp::QoS(1).best_effort(), [](px4_msgs::msg::VehicleCommandAck::UniquePtr msg) { (void)msg; });
52 vehicle_status_sub_ = node_.create_subscription<px4_msgs::msg::VehicleStatus>(
53 "fmu/out/vehicle_status" + px4_ros2::getMessageNameVersion<px4_msgs::msg::VehicleStatus>(), rclcpp::SensorDataQoS{},
54 [](px4_msgs::msg::VehicleStatus::UniquePtr msg) { (void)msg; });
57VehicleCommandClient::SendCommandResult VehicleCommandClient::syncSendVehicleCommand(
58 uint32_t command,
float param1,
float param2,
float param3,
float param4,
float param5,
float param6,
61 px4_msgs::msg::VehicleCommand cmd{};
62 cmd.command = command;
70 cmd.timestamp = node_.get_clock()->now().nanoseconds() / 1000;
72 return syncSendVehicleCommand(cmd);
75VehicleCommandClient::SendCommandResult VehicleCommandClient::syncSendVehicleCommand(
76 const px4_msgs::msg::VehicleCommand & cmd)
const
79 SendCommandResult result = SendCommandResult::REJECTED;
80 using AckWaitSet = rclcpp::StaticWaitSet<1, 0, 0, 0, 0, 0>;
81 AckWaitSet wait_set({{{vehicle_command_ack_sub_}}});
83 bool got_reply =
false;
84 auto start_time = std::chrono::steady_clock::now();
85 vehicle_command_pub_->publish(cmd);
88 auto now = std::chrono::steady_clock::now();
90 if (now >= start_time + command_timeout_) {
94 rclcpp::WaitResult<AckWaitSet> wait_ret = wait_set.wait(command_timeout_ - (now - start_time));
96 if (wait_ret.kind() == rclcpp::WaitResultKind::Ready) {
97 px4_msgs::msg::VehicleCommandAck ack;
98 rclcpp::MessageInfo info;
100 if (vehicle_command_ack_sub_->take(ack, info)) {
101 if (ack.command == cmd.command && ack.target_component == cmd.source_component) {
103 logger_,
"syncSendVehicleCommand: Command %i - Received acknowledgement %i", cmd.command, ack.result);
104 if (ack.result == px4_msgs::msg::VehicleCommandAck::VEHICLE_CMD_RESULT_ACCEPTED) {
105 result = SendCommandResult::ACCEPTED;
110 RCLCPP_DEBUG(logger_,
"syncSendVehicleCommand: Command %i - Acknowledgement message not valid", cmd.command);
116 result = SendCommandResult::TIMEOUT;
117 RCLCPP_WARN(logger_,
"syncSendVehicleCommand: Command %i - Timeout, no acknowledgement received", cmd.command);
120 RCLCPP_DEBUG(logger_,
"syncSendVehicleCommand: Command %i - Result code: %s", cmd.command,
toStr(result).c_str());
125bool VehicleCommandClient::arm()
const
127 return !syncSendVehicleCommand(VehicleCommand::VEHICLE_CMD_COMPONENT_ARM_DISARM, 1);
130bool VehicleCommandClient::disarm()
const
132 return !syncSendVehicleCommand(VehicleCommand::VEHICLE_CMD_COMPONENT_ARM_DISARM, 0);
137 return !syncSendVehicleCommand(VehicleCommand::VEHICLE_CMD_MISSION_START, 0);
140bool VehicleCommandClient::takeoff(
float altitude_amsl_m,
float heading_rad)
const
142 RCLCPP_DEBUG(logger_,
"Takeoff parameters: altitude_amsl_m=%f heading_rad=%f", altitude_amsl_m, heading_rad);
143 return !syncSendVehicleCommand(
144 VehicleCommand::VEHICLE_CMD_NAV_TAKEOFF, NAN, NAN, NAN, heading_rad, NAN, NAN, altitude_amsl_m);
147bool VehicleCommandClient::land()
const {
return !syncSendVehicleCommand(VehicleCommand::VEHICLE_CMD_NAV_LAND); }
149bool VehicleCommandClient::syncActivateFlightMode(uint8_t mode_id)
const
151 return !syncSendVehicleCommand(VehicleCommand::VEHICLE_CMD_SET_NAV_STATE, mode_id);
154bool VehicleCommandClient::syncActivateFlightMode(
const FlightMode & mode)
const
156 return syncActivateFlightMode(
static_cast<uint8_t
>(mode));
159bool VehicleCommandClient::syncActivateFlightMode(
const px4_ros2::ModeBase *
const mode_ptr)
const
161 return syncActivateFlightMode(mode_ptr->id());
165 uint8_t mode_id,
const std::chrono::milliseconds & timeout)
const
168 if (syncSendVehicleCommand(VehicleCommand::VEHICLE_CMD_SET_NAV_STATE, mode_id) != SendCommandResult::ACCEPTED) {
169 RCLCPP_WARN(logger_,
"syncActivateFlightModeAndWait: Command to switch to nav_state %u was not accepted", mode_id);
176 using StatusWaitSet = rclcpp::StaticWaitSet<1, 0, 0, 0, 0, 0>;
177 StatusWaitSet wait_set({{{vehicle_status_sub_}}});
179 const auto start_time = std::chrono::steady_clock::now();
181 const auto now = std::chrono::steady_clock::now();
182 if (now >= start_time + timeout) {
183 RCLCPP_WARN(logger_,
"syncActivateFlightModeAndWait: Timeout waiting for nav_state %u to become active", mode_id);
187 const rclcpp::WaitResult<StatusWaitSet> wait_ret = wait_set.wait(timeout - (now - start_time));
188 if (wait_ret.kind() != rclcpp::WaitResultKind::Ready)
continue;
190 px4_msgs::msg::VehicleStatus status;
191 rclcpp::MessageInfo info;
192 if (vehicle_status_sub_->take(status, info) && status.nav_state == mode_id) {
193 RCLCPP_DEBUG(logger_,
"syncActivateFlightModeAndWait: nav_state %u is now active", mode_id);
200 const px4_ros2::ModeBase *
const mode_ptr,
const std::chrono::milliseconds & timeout)
const
202 return syncActivateFlightModeAndWait(mode_ptr->id(), timeout);
bool syncActivateFlightModeAndWait(uint8_t mode_id, const std::chrono::milliseconds &timeout) const
Activate a flight mode and block until the vehicle actually reports it as active.
bool startMission() const
(Re)starts the uploaded mission plan.
const char * toStr(const ActionNodeErrorCode &err)
Convert the action error code to string.
Implementation of PX4 mode peers offered by px4_ros2_cpp enabling integration with AutoAPMS.