-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
mavsdk_tests: Add integration tests for figure of 8
- Loading branch information
1 parent
8edd7ce
commit e3473a0
Showing
6 changed files
with
329 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
|
||
/**************************************************************************** | ||
* | ||
* Copyright (c) 2023 PX4 Development Team. All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions | ||
* are met: | ||
* | ||
* 1. Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* 2. Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in | ||
* the documentation and/or other materials provided with the | ||
* distribution. | ||
* 3. Neither the name PX4 nor the names of its contributors may be | ||
* used to endorse or promote products derived from this software | ||
* without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | ||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
* POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
****************************************************************************/ | ||
|
||
#include "autopilot_tester_figure_eight.h" | ||
|
||
#include <cmath> | ||
#include <float.h> | ||
#include <future> | ||
#include <vector> | ||
|
||
#include <mavsdk/plugins/mavlink_passthrough/mavlink_passthrough.h> | ||
#include <mavlink/development/mavlink_msg_figure_eight_execution_status.h> | ||
|
||
using namespace mavsdk::geometry; | ||
|
||
void AutopilotTesterFigureEight::execute_figure_eight() | ||
{ | ||
|
||
MavlinkPassthrough::CommandInt figure_eight_command; | ||
|
||
auto ct = get_coordinate_transformation(); | ||
const auto global_center = ct.global_from_local(_figure_eight.center); | ||
|
||
figure_eight_command.target_sysid = getMavlinkPassthrough()->get_target_sysid(); | ||
figure_eight_command.target_compid = getMavlinkPassthrough()->get_target_compid(); | ||
figure_eight_command.command = 35; // Figure eight command | ||
figure_eight_command.frame = MAV_FRAME_GLOBAL_INT; | ||
figure_eight_command.param1 = _figure_eight.major_axis; | ||
figure_eight_command.param2 = _figure_eight.minor_axis; | ||
figure_eight_command.param3 = NAN; | ||
figure_eight_command.param4 = _figure_eight.orientation; | ||
figure_eight_command.x = static_cast<int32_t>(global_center.latitude_deg * 1E7); | ||
figure_eight_command.y = static_cast<int32_t>(global_center.longitude_deg * 1E7); | ||
figure_eight_command.z = _figure_eight.alt; | ||
|
||
send_custom_mavlink_command(figure_eight_command); | ||
} | ||
|
||
void AutopilotTesterFigureEight::set_figure_eight(const double major_axis, const double minor_axis, | ||
const double orientation, const double home_offset_N, const double home_offset_E, const double rel_alt) | ||
{ | ||
_figure_eight.major_axis = major_axis; | ||
_figure_eight.minor_axis = minor_axis; | ||
_figure_eight.orientation = orientation; | ||
_figure_eight.alt = getHome().absolute_altitude_m + rel_alt; | ||
_figure_eight.center = {home_offset_N, home_offset_E}; | ||
} | ||
|
||
void AutopilotTesterFigureEight::check_tracks_figure_eight(std::chrono::seconds timeout, double corridor_radius_m) | ||
{ | ||
auto prom = std::promise<bool> {}; | ||
auto fut = prom.get_future(); | ||
|
||
const double cos_or = cos(_figure_eight.orientation); | ||
const double sin_or = sin(_figure_eight.orientation); | ||
|
||
std::vector<CoordinateTransformation::LocalCoordinate> figure_eight_point_of_interest; | ||
figure_eight_point_of_interest.push_back(_figure_eight.center); | ||
figure_eight_point_of_interest.push_back({_figure_eight.center.north_m + cos_or * (abs(_figure_eight.major_axis) - _figure_eight.minor_axis) - sin_or * (- _figure_eight.minor_axis), _figure_eight.center.east_m + sin_or * (abs(_figure_eight.major_axis) - _figure_eight.minor_axis) + cos_or * (- _figure_eight.minor_axis)}); | ||
figure_eight_point_of_interest.push_back({_figure_eight.center.north_m + cos_or * (abs(_figure_eight.major_axis)) - sin_or * 0., _figure_eight.center.east_m + sin_or * (abs(_figure_eight.major_axis)) + cos_or * 0.}); | ||
figure_eight_point_of_interest.push_back({_figure_eight.center.north_m + cos_or * (abs(_figure_eight.major_axis) - _figure_eight.minor_axis) - sin_or * (_figure_eight.minor_axis), _figure_eight.center.east_m + sin_or * (abs(_figure_eight.major_axis) - _figure_eight.minor_axis) + cos_or * (_figure_eight.minor_axis)}); | ||
figure_eight_point_of_interest.push_back({_figure_eight.center.north_m + cos_or * (-abs(_figure_eight.major_axis) + _figure_eight.minor_axis) - sin_or * (- _figure_eight.minor_axis), _figure_eight.center.east_m + sin_or * (-abs(_figure_eight.major_axis) + _figure_eight.minor_axis) + cos_or * (- _figure_eight.minor_axis)}); | ||
figure_eight_point_of_interest.push_back({_figure_eight.center.north_m + cos_or * (-abs(_figure_eight.major_axis)) - sin_or * 0., _figure_eight.center.east_m + sin_or * (-abs(_figure_eight.major_axis)) + cos_or * (0.)}); | ||
figure_eight_point_of_interest.push_back({_figure_eight.center.north_m + cos_or * (-abs(_figure_eight.major_axis) + _figure_eight.minor_axis) - sin_or * (+ _figure_eight.minor_axis), _figure_eight.center.east_m + sin_or * (-abs(_figure_eight.major_axis) + _figure_eight.minor_axis) + cos_or * (_figure_eight.minor_axis)}); | ||
|
||
std::vector<int32_t> order_to_fly; | ||
|
||
if (_figure_eight.major_axis > 0) { | ||
order_to_fly = std::vector<int32_t> {0, 1, 2, 3, 0, 4, 5, 6, 0}; | ||
|
||
} else { | ||
order_to_fly = std::vector<int32_t> {0, 3, 2, 1, 0, 6, 5, 4, 0}; | ||
} | ||
|
||
getTelemetry()->subscribe_position_velocity_ned([&figure_eight_point_of_interest, &prom, corridor_radius_m, | ||
&order_to_fly, this](Telemetry::PositionVelocityNed position_velocity_ned) { | ||
static size_t index{0}; | ||
int32_t close_index{-1}; | ||
|
||
for (size_t interest_point_index{0}; interest_point_index < figure_eight_point_of_interest.size(); | ||
interest_point_index++) { | ||
if ((abs(position_velocity_ned.position.north_m - figure_eight_point_of_interest[interest_point_index].north_m) < | ||
corridor_radius_m) && | ||
(abs(position_velocity_ned.position.east_m - figure_eight_point_of_interest[interest_point_index].east_m) < | ||
corridor_radius_m)) { | ||
close_index = static_cast<int32_t>(interest_point_index); | ||
break; | ||
} | ||
} | ||
|
||
if (close_index >= 0) { | ||
if (close_index == order_to_fly[index]) { // Still at the same point already found | ||
// Do nothing | ||
|
||
} else if (close_index == order_to_fly[index + 1]) { // reached the next expected point | ||
index++; | ||
|
||
} else { // reached an out of order point | ||
|
||
if (index > 0U) { // only set to false if we already hve passed the first center point | ||
getTelemetry()->subscribe_position_velocity_ned(nullptr); | ||
prom.set_value(false); | ||
} | ||
} | ||
} | ||
|
||
if (index + 1 == order_to_fly.size()) { | ||
getTelemetry()->subscribe_position_velocity_ned(nullptr); | ||
prom.set_value(true); | ||
} | ||
}); | ||
|
||
REQUIRE(fut.wait_for(timeout) == std::future_status::ready); | ||
CHECK(fut.get() == true); | ||
} | ||
|
||
void AutopilotTesterFigureEight::check_receive_execution_status(std::chrono::seconds timeout) | ||
{ | ||
auto prom = std::promise<void> {}; | ||
auto fut = prom.get_future(); | ||
|
||
auto ct = get_coordinate_transformation(); | ||
const auto global_center = ct.global_from_local(_figure_eight.center); | ||
|
||
add_mavlink_message_callback(MAVLINK_MSG_ID_FIGURE_EIGHT_EXECUTION_STATUS, [&prom, global_center, | ||
this](const mavlink_message_t &message) { | ||
add_mavlink_message_callback(MAVLINK_MSG_ID_FIGURE_EIGHT_EXECUTION_STATUS, nullptr); | ||
mavlink_figure_eight_execution_status_t status_message; | ||
|
||
mavlink_msg_figure_eight_execution_status_decode(&message, &status_message); | ||
CHECK(abs(status_message.major_radius - _figure_eight.major_axis) < 1E-4); | ||
CHECK(abs(status_message.minor_radius - _figure_eight.minor_axis) < 1E-4); | ||
CHECK(abs(status_message.orientation - _figure_eight.orientation) < 1E-7); | ||
CHECK(status_message.x == static_cast<int32_t>(global_center.latitude_deg * 1E7)); | ||
CHECK(status_message.y == static_cast<int32_t>(global_center.longitude_deg * 1E7)); | ||
CHECK(abs(status_message.z - _figure_eight.alt) < 1E-4); | ||
|
||
prom.set_value(); | ||
|
||
return true; | ||
}); | ||
|
||
REQUIRE(fut.wait_for(timeout) == std::future_status::ready); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/**************************************************************************** | ||
* | ||
* Copyright (c) 2023 PX4 Development Team. All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions | ||
* are met: | ||
* | ||
* 1. Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* 2. Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in | ||
* the documentation and/or other materials provided with the | ||
* distribution. | ||
* 3. Neither the name PX4 nor the names of its contributors may be | ||
* used to endorse or promote products derived from this software | ||
* without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | ||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
* POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
****************************************************************************/ | ||
|
||
#pragma once | ||
|
||
#include "autopilot_tester.h" | ||
|
||
#include <mavsdk/geometry.h> | ||
#include <mavsdk/mavsdk.h> | ||
#include <mavsdk/plugins/action/action.h> | ||
|
||
class AutopilotTesterFigureEight : public AutopilotTester | ||
{ | ||
public: | ||
AutopilotTesterFigureEight() = default; | ||
~AutopilotTesterFigureEight() = default; | ||
|
||
void set_figure_eight(double major_axis, double minor_axis, double orientation, double home_offset_N, | ||
double home_offset_E, double rel_alt); | ||
|
||
void execute_figure_eight(); | ||
void check_tracks_figure_eight(std::chrono::seconds timeout, double corridor_radius_m = 5.f); | ||
void check_receive_execution_status(std::chrono::seconds timeout); | ||
|
||
private: | ||
|
||
struct { | ||
double major_axis; | ||
double minor_axis; | ||
double orientation; | ||
CoordinateTransformation::LocalCoordinate center; | ||
double alt; | ||
} _figure_eight; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/**************************************************************************** | ||
* | ||
* Copyright (c) 2021 PX4 Development Team. All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions | ||
* are met: | ||
* | ||
* 1. Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* 2. Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in | ||
* the documentation and/or other materials provided with the | ||
* distribution. | ||
* 3. Neither the name PX4 nor the names of its contributors may be | ||
* used to endorse or promote products derived from this software | ||
* without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | ||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
* POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
****************************************************************************/ | ||
|
||
#include "autopilot_tester_figure_eight.h" | ||
|
||
#include <chrono> | ||
#include <thread> | ||
|
||
TEST_CASE("Figure eight execution clockwise", "[vtol]") | ||
{ | ||
AutopilotTesterFigureEight tester; | ||
tester.connect(connection_url); | ||
tester.wait_until_ready(); | ||
tester.store_home(); | ||
const float takeoff_altitude = 20.f; | ||
tester.set_takeoff_altitude(takeoff_altitude); | ||
tester.arm(); | ||
tester.takeoff(); | ||
tester.wait_until_hovering(); | ||
tester.wait_until_altitude(takeoff_altitude - 1.f, std::chrono::seconds(30)); | ||
tester.transition_to_fixedwing(); | ||
tester.wait_until_fixedwing(std::chrono::seconds(5)); | ||
std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
tester.set_figure_eight(150., 50., 0., 200., 0., 20.); | ||
tester.execute_figure_eight(); | ||
tester.check_tracks_figure_eight(std::chrono::seconds(60), 10.); | ||
// tester.check_receive_execution_status(std::chrono::seconds( | ||
// 5)); //TODO With mavsdk we can't subscribe to custom messages. Need to wait until messages are recognised by mavsdk | ||
} | ||
|
||
TEST_CASE("Figure eight execution counterclockwise", "[vtol]") | ||
{ | ||
AutopilotTesterFigureEight tester; | ||
tester.connect(connection_url); | ||
tester.wait_until_ready(); | ||
tester.store_home(); | ||
const float takeoff_altitude = 20.f; | ||
tester.set_takeoff_altitude(takeoff_altitude); | ||
tester.arm(); | ||
tester.takeoff(); | ||
tester.wait_until_hovering(); | ||
tester.wait_until_altitude(takeoff_altitude - 1.f, std::chrono::seconds(30)); | ||
tester.transition_to_fixedwing(); | ||
tester.wait_until_fixedwing(std::chrono::seconds(5)); | ||
std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
tester.set_figure_eight(-150., 50., 30.*M_PI / 180., 200., 0., 20.); | ||
tester.execute_figure_eight(); | ||
tester.check_tracks_figure_eight(std::chrono::seconds(60), 10.); | ||
// tester.check_receive_execution_status(std::chrono::seconds( | ||
// 5)); //TODO With mavsdk we can't subscribe to custom messages. Need to wait until messages are recognised by mavsdk. | ||
} |