AutoAPMS
Resilient Robot Mission Management
Loading...
Searching...
No Matches
vehicle_command_client.cpp
Go to the documentation of this file.
1// Copyright 2024 Robin Müller
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
16
17#include <functional>
18
19namespace auto_apms_px4
20{
21
23{
24 switch (result)
25 {
27 return "ACCEPTED";
29 return "REJECTED";
31 return "TIMEOUT";
32 default:
33 return "undefined";
34 }
35}
36
37VehicleCommandClient::VehicleCommandClient(rclcpp::Node& node, const std::chrono::milliseconds& command_timeout)
38 : node_{ node }, logger_{ node.get_logger().get_child("vehicle_command_client") }, command_timeout_{ command_timeout }
39{
40 // Create vehicle command publisher and acknowledgement signal subscriber
41 vehicle_command_pub_ = node_.create_publisher<px4_msgs::msg::VehicleCommand>("/fmu/in/vehicle_command", 10);
42
43 vehicle_command_ack_sub_ = node_.create_subscription<px4_msgs::msg::VehicleCommandAck>(
44 "/fmu/out/vehicle_command_ack", rclcpp::QoS(1).best_effort(),
45 [](px4_msgs::msg::VehicleCommandAck::UniquePtr msg) { (void)msg; });
46}
47
49 float param2, float param3,
50 float param4, float param5,
51 float param6, float param7) const
52{
53 px4_msgs::msg::VehicleCommand cmd{};
54 cmd.command = command;
55 cmd.param1 = param1;
56 cmd.param2 = param2;
57 cmd.param3 = param3;
58 cmd.param4 = param4;
59 cmd.param5 = param5;
60 cmd.param6 = param6;
61 cmd.param7 = param7;
62 cmd.timestamp = node_.get_clock()->now().nanoseconds() / 1000;
63
64 return SyncSendVehicleCommand(cmd);
65}
66
68VehicleCommandClient::SyncSendVehicleCommand(const px4_msgs::msg::VehicleCommand& cmd) const
69{
71 rclcpp::WaitSet wait_set;
72 wait_set.add_subscription(vehicle_command_ack_sub_);
73
74 bool got_reply = false;
75 auto start_time = std::chrono::steady_clock::now();
76 vehicle_command_pub_->publish(cmd);
77
78 while (!got_reply)
79 {
80 auto now = std::chrono::steady_clock::now();
81
82 if (now >= start_time + command_timeout_)
83 {
84 break;
85 }
86
87 auto wait_ret = wait_set.wait(command_timeout_ - (now - start_time));
88
89 if (wait_ret.kind() == rclcpp::WaitResultKind::Ready)
90 {
91 px4_msgs::msg::VehicleCommandAck ack;
92 rclcpp::MessageInfo info;
93
94 if (vehicle_command_ack_sub_->take(ack, info))
95 {
96 if (ack.command == cmd.command && ack.target_component == cmd.source_component)
97 {
98 RCLCPP_DEBUG(logger_, "SyncSendVehicleCommand: Command %i - received ack result %i", cmd.command, ack.result);
99 if (ack.result == px4_msgs::msg::VehicleCommandAck::VEHICLE_CMD_RESULT_ACCEPTED)
100 {
102 }
103 got_reply = true;
104 }
105 }
106 else
107 {
108 RCLCPP_DEBUG(logger_, "SyncSendVehicleCommand: Command %i - message not valid", cmd.command);
109 }
110 }
111 }
112
113 wait_set.remove_subscription(vehicle_command_ack_sub_);
114
115 if (!got_reply)
116 {
118 RCLCPP_WARN(logger_, "SyncSendVehicleCommand: Command %i - timeout, no ack received", cmd.command);
119 }
120
121 RCLCPP_DEBUG(logger_, "SyncSendVehicleCommand: Command %i - returned %s", cmd.command, toStr(result).c_str());
122
123 return result;
124}
125
127{
128 return !SyncSendVehicleCommand(VehicleCommand::VEHICLE_CMD_COMPONENT_ARM_DISARM, 1);
129}
130
132{
133 return !SyncSendVehicleCommand(VehicleCommand::VEHICLE_CMD_COMPONENT_ARM_DISARM, 0);
134}
135
137{
138 return !SyncSendVehicleCommand(VehicleCommand::VEHICLE_CMD_MISSION_START, 0);
139}
140
141bool VehicleCommandClient::Takeoff(float altitude_amsl_m, float heading_rad) const
142{
143 RCLCPP_DEBUG(logger_, "Takeoff parameters: altitude_amsl_m=%f heading_rad=%f", altitude_amsl_m, heading_rad);
144 return !SyncSendVehicleCommand(VehicleCommand::VEHICLE_CMD_NAV_TAKEOFF, NAN, NAN, NAN, heading_rad, NAN, NAN,
145 altitude_amsl_m);
146}
147
149{
150 return !SyncSendVehicleCommand(VehicleCommand::VEHICLE_CMD_NAV_LAND);
151}
152
154{
155 return !SyncSendVehicleCommand(VehicleCommand::VEHICLE_CMD_SET_NAV_STATE, mode_id);
156}
157
159{
160 return SyncActivateFlightMode(static_cast<uint8_t>(mode));
161}
162
163bool VehicleCommandClient::SyncActivateFlightMode(const px4_ros2::ModeBase* const mode_ptr) const
164{
165 return SyncActivateFlightMode(mode_ptr->id());
166}
167
168} // namespace auto_apms_px4
bool StartMission() const
(Re)starts the uploaded mission plan.
SendCommandResult SyncSendVehicleCommand(uint32_t command, float param1=NAN, float param2=NAN, float param3=NAN, float param4=NAN, float param5=NAN, float param6=NAN, float param7=NAN) const
bool SyncActivateFlightMode(uint8_t mode_id) const
VehicleCommandClient(rclcpp::Node &node, const std::chrono::milliseconds &command_timeout=std::chrono::milliseconds(500))
std::string toStr(VehicleCommandClient::SendCommandResult result)