Skip to content

Commit c3b04f0

Browse files
authored
Merge pull request #21 from aerostack2/platform_test
[as2_platform_pixhawk] Platform test
2 parents ae78854 + 15ec06e commit c3b04f0

File tree

5 files changed

+304
-22
lines changed

5 files changed

+304
-22
lines changed

config/platform_config_file.yaml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
ros__parameters:
33
cmd_freq: 100.0 # Hz of platform commands send
44
info_freq: 10.0 # Hz of platform info publish
5-
mass: 1.0 # Kg
6-
max_thrust: 15.0 # N
7-
min_thrust: 0.15 # N
8-
external_odom: false # Use external odometry source
5+
max_thrust: 15.0 # Max thrust to send to platform (N)
6+
min_thrust: 0.15 # Min thrust to send to platform (N)
7+
external_odom: false # Flag to use external odometry source

include/as2_platform_pixhawk/pixhawk_platform.hpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,26 +58,30 @@
5858
#include <px4_msgs/msg/vehicle_odometry.hpp>
5959
#include <px4_msgs/msg/vehicle_rates_setpoint.hpp>
6060

61-
#include <as2_core/utils/frame_utils.hpp>
61+
#include <geometry_msgs/msg/pose_stamped.hpp>
62+
#include <geometry_msgs/msg/twist_stamped.hpp>
63+
#include <nav_msgs/msg/odometry.hpp>
64+
#include <sensor_msgs/msg/battery_state.hpp>
65+
#include <sensor_msgs/msg/imu.hpp>
66+
#include <sensor_msgs/msg/nav_sat_fix.hpp>
67+
#include <sensor_msgs/msg/nav_sat_status.hpp>
68+
#include "as2_core/custom/tf2_geometry_msgs.hpp"
69+
70+
#include "as2_core/utils/frame_utils.hpp"
6271
#include "as2_core/aerial_platform.hpp"
6372
#include "as2_core/names/topics.hpp"
6473
#include "as2_core/sensor.hpp"
6574
#include "as2_core/utils/tf_utils.hpp"
6675
#include "as2_msgs/msg/control_mode.hpp"
6776
#include "as2_msgs/msg/thrust.hpp"
68-
#include "geometry_msgs/msg/pose_stamped.hpp"
69-
#include "geometry_msgs/msg/twist_stamped.hpp"
70-
#include "nav_msgs/msg/odometry.hpp"
71-
#include "sensor_msgs/msg/battery_state.hpp"
72-
#include "sensor_msgs/msg/imu.hpp"
73-
#include "sensor_msgs/msg/nav_sat_fix.hpp"
74-
#include "sensor_msgs/msg/nav_sat_status.hpp"
75-
#include "tf2_geometry_msgs/tf2_geometry_msgs.h"
77+
78+
namespace as2_platform_pixhawk
79+
{
7680

7781
class PixhawkPlatform : public as2::AerialPlatform
7882
{
7983
public:
80-
PixhawkPlatform();
84+
explicit PixhawkPlatform(const rclcpp::NodeOptions & options = rclcpp::NodeOptions());
8185
~PixhawkPlatform() {}
8286

8387
public:
@@ -155,7 +159,6 @@ class PixhawkPlatform : public as2::AerialPlatform
155159
px4_msgs::msg::VehicleRatesSetpoint px4_rates_setpoint_;
156160
px4_msgs::msg::VehicleOdometry px4_visual_odometry_msg_;
157161

158-
float mass_;
159162
float max_thrust_;
160163
float min_thrust_;
161164
bool simulation_mode_ = false;
@@ -177,4 +180,6 @@ class PixhawkPlatform : public as2::AerialPlatform
177180
void px4GpsCallback(const px4_msgs::msg::SensorGps::SharedPtr msg);
178181
};
179182

183+
} // namespace as2_platform_pixhawk
184+
180185
#endif // AS2_PLATFORM_PIXHAWK__PIXHAWK_PLATFORM_HPP_

src/pixhawk_platform.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@
3939

4040
#include "pixhawk_platform.hpp"
4141

42-
PixhawkPlatform::PixhawkPlatform()
43-
: as2::AerialPlatform()
42+
namespace as2_platform_pixhawk
43+
{
44+
45+
PixhawkPlatform::PixhawkPlatform(const rclcpp::NodeOptions & options)
46+
: as2::AerialPlatform(options)
4447
{
4548
configureSensors();
4649

4750
base_link_frame_id_ = as2::tf::generateTfName(this, "base_link");
4851
odom_frame_id_ = as2::tf::generateTfName(this, "odom");
4952

50-
this->declare_parameter<float>("mass");
51-
mass_ = this->get_parameter("mass").as_double();
52-
5353
this->declare_parameter<float>("max_thrust");
5454
max_thrust_ = this->get_parameter("max_thrust").as_double();
5555

@@ -59,7 +59,6 @@ PixhawkPlatform::PixhawkPlatform()
5959
this->declare_parameter<bool>("external_odom");
6060
external_odom_ = this->get_parameter("external_odom").as_bool();
6161

62-
RCLCPP_INFO(this->get_logger(), "Mass: %f", mass_);
6362
RCLCPP_INFO(this->get_logger(), "Max thrust: %f", max_thrust_);
6463
RCLCPP_INFO(this->get_logger(), "Min thrust: %f", min_thrust_);
6564
RCLCPP_INFO(
@@ -835,3 +834,5 @@ bool PixhawkPlatform::getFlagSimulationMode()
835834
// TODO(miferco97): check if this is better than creating a variable to store the value
836835
return this->get_parameter("use_sim_time").as_bool();
837836
}
837+
838+
} // namespace as2_platform_pixhawk

src/pixhawk_platform_node.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
int main(int argc, char * argv[])
4444
{
4545
rclcpp::init(argc, argv);
46-
auto node = std::make_shared<PixhawkPlatform>();
46+
auto node = std::make_shared<as2_platform_pixhawk::PixhawkPlatform>();
4747
node->preset_loop_frequency(300);
4848
as2::spinLoop(node);
4949

tests/pixhawk_platform_test.cpp

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
// Copyright 2023 Universidad Politécnica de Madrid
2+
//
3+
// Redistribution and use in source and binary forms, with or without
4+
// modification, are permitted provided that the following conditions are met:
5+
//
6+
// * Redistributions of source code must retain the above copyright
7+
// notice, this list of conditions and the following disclaimer.
8+
//
9+
// * Redistributions in binary form must reproduce the above copyright
10+
// notice, this list of conditions and the following disclaimer in the
11+
// documentation and/or other materials provided with the distribution.
12+
//
13+
// * Neither the name of the Universidad Politécnica de Madrid nor the names
14+
// of its
15+
// contributors may be used to endorse or promote products derived from
16+
// this software without specific prior written permission.
17+
//
18+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
// POSSIBILITY OF SUCH DAMAGE.
29+
30+
/**
31+
* @file pixhawk_platform_test.cpp
32+
*
33+
* Pixhawk test
34+
*
35+
* @author Rafael Perez-Segui <[email protected]>
36+
*/
37+
38+
39+
#include <iostream>
40+
#include <memory>
41+
#include <string>
42+
#include <ament_index_cpp/get_package_share_directory.hpp>
43+
#include "pixhawk_platform.hpp"
44+
#include "as2_core/mocks/aerial_platform/mock_aerial_platform.hpp"
45+
#include "as2_core/mocks/executor_thread_util/executor_thread_util.hpp"
46+
#include <as2_msgs/msg/platform_state_machine_event.hpp>
47+
48+
namespace as2_platform_pixhawk
49+
{
50+
std::shared_ptr<PixhawkPlatform> get_node(
51+
const std::string & name_space = "test_pixhawk_platform")
52+
{
53+
const std::string package_path =
54+
ament_index_cpp::get_package_share_directory("as2_platform_pixhawk");
55+
const std::string control_modes_config_file = package_path + "/config/control_modes.yaml";
56+
const std::string platform_config_file = package_path + "/config/platform_config_file.yaml";
57+
58+
std::vector<std::string> node_args = {
59+
"--ros-args",
60+
"-r",
61+
"__ns:=/" + name_space,
62+
"-p",
63+
"namespace:=" + name_space,
64+
"-p",
65+
"control_modes_file:=" + control_modes_config_file,
66+
"--params-file",
67+
platform_config_file,
68+
};
69+
70+
rclcpp::NodeOptions node_options;
71+
node_options.arguments(node_args);
72+
73+
return std::make_shared<PixhawkPlatform>(node_options);
74+
}
75+
76+
void spinForTime(
77+
double seconds, rclcpp::executors::SingleThreadedExecutor & executor,
78+
std::shared_ptr<as2::mock::PlatformMockNode> test_node)
79+
{
80+
// Current ros2 time
81+
auto start_time = test_node->getTime();
82+
while ((test_node->getTime() - start_time).seconds() < seconds) {
83+
// Spin
84+
executor.spin_some();
85+
86+
// Print state
87+
// test_node->printState(seconds * 0.5);
88+
89+
// Sleep for 10 ms
90+
std::this_thread::sleep_for(std::chrono::milliseconds(500));
91+
}
92+
return;
93+
}
94+
95+
void spinForTime(
96+
double seconds,
97+
std::shared_ptr<as2::mock::PlatformMockNode> test_node)
98+
{
99+
// Current ros2 time
100+
auto start_time = test_node->getTime();
101+
while ((test_node->getTime() - start_time).seconds() < seconds) {
102+
// Print state
103+
// test_node->printState(seconds * 0.5);
104+
105+
// Sleep for 10 ms
106+
std::this_thread::sleep_for(std::chrono::milliseconds(500));
107+
}
108+
return;
109+
}
110+
111+
int platform_test()
112+
{
113+
std::string ros_namespace = "test_pixhawk_platform";
114+
auto test_node = std::make_shared<as2::mock::PlatformMockNode>(ros_namespace);
115+
auto tello_node = get_node(ros_namespace);
116+
117+
// Executor
118+
rclcpp::executors::SingleThreadedExecutor::SharedPtr executor =
119+
std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
120+
121+
// Add nodes to executor
122+
executor->add_node(test_node);
123+
executor->add_node(tello_node);
124+
125+
// Executor thread
126+
as2::mock::ExecutorThreadUtil executor_thread_util(executor, 200.0);
127+
executor_thread_util.start();
128+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
129+
130+
// Enable test command send timer
131+
test_node->setCommandSendTimerState(true, 100.0);
132+
133+
std::string base_frame = as2::tf::generateTfName(
134+
test_node->get_namespace(), "base_link");
135+
136+
// Wait 2 seconds
137+
spinForTime(2.0, test_node);
138+
139+
// Arm
140+
if (!test_node->setArmingState(true, false)) {
141+
return -1;
142+
}
143+
spinForTime(0.5, test_node);
144+
145+
// Set offboard
146+
if (!test_node->setOffboardControl(true, false)) {
147+
return -1;
148+
}
149+
spinForTime(0.5, test_node);
150+
151+
// Send transition event TAKE_OFF
152+
as2_msgs::msg::PlatformStateMachineEvent takeoff_event;
153+
takeoff_event.event = as2_msgs::msg::PlatformStateMachineEvent::TAKE_OFF;
154+
if (!test_node->setPlatformStateMachineEvent(takeoff_event, false)) {
155+
return -1;
156+
}
157+
spinForTime(0.5, test_node);
158+
159+
// Set takeoff_twist actuator command
160+
geometry_msgs::msg::TwistStamped takeoff_twist;
161+
takeoff_twist.header.frame_id = base_frame;
162+
takeoff_twist.twist.linear.x = 0.0;
163+
takeoff_twist.twist.linear.y = 0.0;
164+
takeoff_twist.twist.linear.z = 0.5;
165+
takeoff_twist.twist.angular.x = 0.0;
166+
takeoff_twist.twist.angular.y = 0.0;
167+
takeoff_twist.twist.angular.z = 0.0;
168+
test_node->setCommandTwist(takeoff_twist);
169+
spinForTime(0.5, test_node);
170+
171+
// Set control mode to speed for takeoff
172+
as2_msgs::msg::ControlMode control_mode;
173+
control_mode.control_mode = as2_msgs::msg::ControlMode::SPEED;
174+
control_mode.yaw_mode = as2_msgs::msg::ControlMode::YAW_SPEED;
175+
control_mode.reference_frame = as2_msgs::msg::ControlMode::LOCAL_ENU_FRAME;
176+
if (!test_node->setControlMode(control_mode, false)) {
177+
return -1;
178+
}
179+
spinForTime(5.0, test_node);
180+
181+
// Send transition event TOOK_OFF
182+
as2_msgs::msg::PlatformStateMachineEvent tookoff_event;
183+
tookoff_event.event = as2_msgs::msg::PlatformStateMachineEvent::TOOK_OFF;
184+
if (!test_node->setPlatformStateMachineEvent(tookoff_event, false)) {
185+
return -1;
186+
}
187+
spinForTime(0.5, test_node);
188+
189+
// Hover
190+
geometry_msgs::msg::TwistStamped hover_twist;
191+
hover_twist.header.frame_id = base_frame;
192+
hover_twist.twist.linear.x = 0.0;
193+
hover_twist.twist.linear.y = 0.0;
194+
hover_twist.twist.linear.z = 0.0;
195+
hover_twist.twist.angular.x = 0.0;
196+
hover_twist.twist.angular.y = 0.0;
197+
hover_twist.twist.angular.z = 0.0;
198+
test_node->setCommandTwist(hover_twist);
199+
spinForTime(5.0, test_node);
200+
201+
// Move forward
202+
geometry_msgs::msg::TwistStamped forward_twist;
203+
forward_twist.header.frame_id = as2::tf::generateTfName(
204+
test_node->get_namespace(), base_frame);
205+
forward_twist.twist.linear.x = 0.5;
206+
forward_twist.twist.linear.y = 0.0;
207+
forward_twist.twist.linear.z = 0.0;
208+
forward_twist.twist.angular.x = 0.0;
209+
forward_twist.twist.angular.y = 0.0;
210+
forward_twist.twist.angular.z = 0.0;
211+
test_node->setCommandTwist(forward_twist);
212+
spinForTime(5.0, test_node);
213+
214+
// Move backward
215+
geometry_msgs::msg::TwistStamped backward_twist;
216+
backward_twist.header.frame_id = base_frame;
217+
backward_twist.twist.linear.x = -0.5;
218+
backward_twist.twist.linear.y = 0.0;
219+
backward_twist.twist.linear.z = 0.0;
220+
backward_twist.twist.angular.x = 0.0;
221+
backward_twist.twist.angular.y = 0.0;
222+
backward_twist.twist.angular.z = 0.0;
223+
test_node->setCommandTwist(backward_twist);
224+
spinForTime(5.0, test_node);
225+
226+
// Send transition event LAND
227+
as2_msgs::msg::PlatformStateMachineEvent land_event;
228+
land_event.event = as2_msgs::msg::PlatformStateMachineEvent::LAND;
229+
if (!test_node->setPlatformStateMachineEvent(land_event, false)) {
230+
return -1;
231+
}
232+
spinForTime(0.5, test_node);
233+
234+
// Set land_twist actuator command
235+
geometry_msgs::msg::TwistStamped land_twist;
236+
land_twist.header.frame_id = base_frame;
237+
land_twist.twist.linear.x = 0.0;
238+
land_twist.twist.linear.y = 0.0;
239+
land_twist.twist.linear.z = -0.5;
240+
land_twist.twist.angular.x = 0.0;
241+
land_twist.twist.angular.y = 0.0;
242+
land_twist.twist.angular.z = 0.0;
243+
test_node->setCommandTwist(land_twist);
244+
spinForTime(10.0, test_node);
245+
246+
// Send transition event LANDED
247+
as2_msgs::msg::PlatformStateMachineEvent landed_event;
248+
landed_event.event = as2_msgs::msg::PlatformStateMachineEvent::LANDED;
249+
if (!test_node->setPlatformStateMachineEvent(landed_event, false)) {
250+
return -1;
251+
}
252+
spinForTime(0.5, test_node);
253+
254+
// Send disarm command
255+
if (!test_node->setArmingState(false, false)) {
256+
return -1;
257+
}
258+
spinForTime(0.5, test_node);
259+
260+
// Clean
261+
executor_thread_util.stop();
262+
executor->remove_node(test_node);
263+
executor->remove_node(tello_node);
264+
265+
return 0;
266+
}
267+
} // namespace as2_platform_pixhawk
268+
269+
270+
int main(int argc, char * argv[])
271+
{
272+
rclcpp::init(argc, argv);
273+
auto result = as2_platform_pixhawk::platform_test();
274+
275+
rclcpp::shutdown();
276+
return result;
277+
}

0 commit comments

Comments
 (0)