forked from mavlink/MAVSDK
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement transition to fw as an action. (mavlink#150)
* Implementation of multi-copter to fixed-wing and vice versa. * Include an example and also implement async. * Make integration test. * Add more descriptive prints and comments. * Remove non-informative comments. * run make fix_style * deleted zero byte file (was by mistake still present)
- Loading branch information
Showing
8 changed files
with
374 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
cmake_minimum_required(VERSION 2.8.12) | ||
|
||
project(transition_vtol_fixed_wing) | ||
|
||
if(NOT MSVC) | ||
add_definitions("-std=c++11 -Wall -Wextra -Werror") | ||
else() | ||
add_definitions("-std=c++11 -WX -W2") | ||
set(platform_libs "Ws2_32.lib") | ||
endif() | ||
|
||
# Add DEBUG define for Debug target | ||
set(CMAKE_CXX_FLAGS_DEBUG "-DDEBUG") | ||
|
||
# This finds thread libs on Linux, Mac, and Windows. | ||
find_package(Threads REQUIRED) | ||
|
||
# Not needed if DroneCore installed system-wide | ||
include_directories( | ||
${CMAKE_SOURCE_DIR}/../../install/include | ||
) | ||
|
||
add_executable(transition_vtol_fixed_wing | ||
transition_vtol_fixed_wing.cpp | ||
) | ||
|
||
# Not needed if DroneCore installed system-wide | ||
if(MSVC) | ||
set(dronecore_lib "${CMAKE_SOURCE_DIR}/../../install/lib/dronecore.lib") | ||
else() | ||
set(dronecore_lib "${CMAKE_SOURCE_DIR}/../../install/lib/libdronecore.so") | ||
endif() | ||
|
||
target_link_libraries(transition_vtol_fixed_wing | ||
${dronecore_lib} # Remove/comment out this line if DroneCore used locally | ||
# dronecore # Uncomment/add this line if DroneCore installed system-wide | ||
${CMAKE_THREAD_LIBS_INIT} | ||
${platform_libs} | ||
) |
143 changes: 143 additions & 0 deletions
143
example/transition_vtol_fixed_wing/transition_vtol_fixed_wing.cpp
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,143 @@ | ||
|
||
#include <dronecore/dronecore.h> | ||
#include <iostream> | ||
#include <thread> | ||
#include <chrono> | ||
#include <cstdint> | ||
|
||
using std::this_thread::sleep_for; | ||
using std::chrono::milliseconds; | ||
using namespace dronecore; | ||
|
||
#define ERROR_CONSOLE_TEXT "\033[31m" //Turn text on console red | ||
#define TELEMETRY_CONSOLE_TEXT "\033[34m" //Turn text on console blue | ||
#define NORMAL_CONSOLE_TEXT "\033[0m" //Restore normal console colour | ||
|
||
int main(int /*argc*/, char ** /*argv*/) | ||
{ | ||
DroneCore dc; | ||
|
||
bool discovered_device = false; | ||
|
||
DroneCore::ConnectionResult connection_result = dc.add_udp_connection(); | ||
|
||
if (connection_result != DroneCore::ConnectionResult::SUCCESS) { | ||
std::cout << ERROR_CONSOLE_TEXT << "Connection failed: " | ||
<< DroneCore::connection_result_str(connection_result) | ||
<< NORMAL_CONSOLE_TEXT << std::endl; | ||
return 1; | ||
} | ||
|
||
std::cout << "Waiting to discover device..." << std::endl; | ||
dc.register_on_discover([&discovered_device](uint64_t uuid) { | ||
std::cout << "Discovered device with UUID: " << uuid << std::endl; | ||
discovered_device = true; | ||
}); | ||
|
||
// We usually receive heartbeats at 1Hz, therefore we should find a device after around 2 seconds. | ||
std::this_thread::sleep_for(std::chrono::seconds(2)); | ||
|
||
if (!discovered_device) { | ||
std::cout << ERROR_CONSOLE_TEXT << "No device found, exiting." << NORMAL_CONSOLE_TEXT << std::endl; | ||
return 1; | ||
} | ||
|
||
// We don't need to specify the UUID if it's only one device anyway. | ||
// If there were multiple, we could specify it with: | ||
// dc.device(uint64_t uuid); | ||
Device &device = dc.device(); | ||
|
||
// We want to listen to the altitude of the drone at 1 Hz. | ||
const Telemetry::Result set_rate_result = dc.device().telemetry().set_rate_position(1.0); | ||
if (set_rate_result != Telemetry::Result::SUCCESS) { | ||
std::cout << ERROR_CONSOLE_TEXT << "Setting rate failed:" << Telemetry::result_str( | ||
set_rate_result) << NORMAL_CONSOLE_TEXT << std::endl; | ||
return 1; | ||
} | ||
|
||
|
||
// Set up callback to monitor altitude while the vehicle is in flight | ||
device.telemetry().position_async([](Telemetry::Position position) { | ||
std::cout << TELEMETRY_CONSOLE_TEXT // set to blue | ||
<< "Altitude: " << position.relative_altitude_m << " m" | ||
<< NORMAL_CONSOLE_TEXT // set to default color again | ||
<< std::endl; | ||
}); | ||
|
||
|
||
// Check if vehicle is ready to arm | ||
if (device.telemetry().health_all_ok() != true) { | ||
std::cout << ERROR_CONSOLE_TEXT << "Vehicle not ready to arm" << NORMAL_CONSOLE_TEXT << std::endl; | ||
return 1; | ||
} | ||
|
||
// Arm vehicle | ||
std::cout << "Arming..." << std::endl; | ||
const Action::Result arm_result = device.action().arm(); | ||
|
||
if (arm_result != Action::Result::SUCCESS) { | ||
std::cout << ERROR_CONSOLE_TEXT << "Arming failed:" << Action::result_str( | ||
arm_result) << NORMAL_CONSOLE_TEXT << std::endl; | ||
return 1; | ||
} | ||
|
||
// Take off | ||
std::cout << "Taking off..." << std::endl; | ||
const Action::Result takeoff_result = device.action().takeoff(); | ||
if (takeoff_result != Action::Result::SUCCESS) { | ||
std::cout << ERROR_CONSOLE_TEXT << "Takeoff failed:" << Action::result_str( | ||
takeoff_result) << NORMAL_CONSOLE_TEXT << std::endl; | ||
return 1; | ||
} | ||
|
||
// Wait | ||
std::this_thread::sleep_for(std::chrono::seconds(10)); | ||
|
||
// Change to FW | ||
const Action::Result fw_result = device.action().transition_to_fixedwing(); | ||
|
||
if (fw_result != Action::Result::SUCCESS) { | ||
std::cout << ERROR_CONSOLE_TEXT << "Transition to fixed wing failed: " << Action::result_str( | ||
fw_result) << NORMAL_CONSOLE_TEXT << std::endl; | ||
//return 1; | ||
} | ||
|
||
// Wait | ||
std::this_thread::sleep_for(std::chrono::seconds(10)); | ||
|
||
// Change to VTOL | ||
const Action::Result mc_result = device.action().transition_to_multicopter(); | ||
if (mc_result != Action::Result::SUCCESS) { | ||
std::cout << ERROR_CONSOLE_TEXT << "Transition to multi copter failed:" << Action::result_str( | ||
mc_result) << NORMAL_CONSOLE_TEXT << std::endl; | ||
// return 1; | ||
} | ||
|
||
// Wait | ||
std::this_thread::sleep_for(std::chrono::seconds(5)); | ||
|
||
// Return to launch | ||
const Action::Result rtl_result = device.action().return_to_launch(); | ||
if (rtl_result != Action::Result::SUCCESS) { | ||
std::cout << ERROR_CONSOLE_TEXT << "Returning to launch failed:" << Action::result_str( | ||
rtl_result) << NORMAL_CONSOLE_TEXT << std::endl; | ||
// return 1; | ||
} | ||
|
||
// Wait | ||
std::this_thread::sleep_for(std::chrono::seconds(20)); | ||
|
||
// Land | ||
std::cout << "Landing..." << std::endl; | ||
const Action::Result land_result = device.action().land(); | ||
if (land_result != Action::Result::SUCCESS) { | ||
std::cout << ERROR_CONSOLE_TEXT << "Land failed:" << Action::result_str( | ||
land_result) << NORMAL_CONSOLE_TEXT << std::endl; | ||
// return 1; | ||
} | ||
|
||
// We are relying on auto-disarming but let's keep watching the telemetry for a bit longer. | ||
std::this_thread::sleep_for(std::chrono::seconds(5)); | ||
std::cout << "Finished..." << std::endl; | ||
return 0; | ||
} |
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 |
---|---|---|
|
@@ -27,6 +27,7 @@ list(APPEND integration_tests | |
mission_survey | ||
gimbal | ||
curl | ||
transition_multicopter_fixedwing | ||
) | ||
|
||
|
||
|
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,87 @@ | ||
#include <iostream> | ||
#include "integration_test_helper.h" | ||
#include "dronecore.h" | ||
|
||
using namespace dronecore; | ||
|
||
|
||
//static void connect(DroneCore); | ||
static void takeoff(Device &); | ||
static void takeoff_and_transition_to_fixedwing(); | ||
static void land_and_disarm(Device &); | ||
|
||
|
||
TEST_F(SitlTest, ActionSimpleTransition) | ||
{ | ||
takeoff_and_transition_to_fixedwing(); | ||
} | ||
|
||
void takeoff_and_transition_to_fixedwing() | ||
{ | ||
// Init & connect | ||
DroneCore dc; | ||
|
||
DroneCore::ConnectionResult ret = dc.add_udp_connection(); | ||
ASSERT_EQ(ret, DroneCore::ConnectionResult::SUCCESS); | ||
|
||
// Wait for device to connect via heartbeat. | ||
std::this_thread::sleep_for(std::chrono::seconds(2)); | ||
ASSERT_TRUE(dc.is_connected()); | ||
|
||
Device &device = dc.device(); | ||
|
||
// We need to takeoff first, otherwise we can't actually transition | ||
LogInfo() << "Taking off"; | ||
takeoff(device); | ||
|
||
LogInfo() << "Transitioning to fixedwing"; | ||
device.action().transition_to_fixedwing(); | ||
|
||
// Wait a little before the transition back to multicopter, | ||
// so we can actually see it fly | ||
std::this_thread::sleep_for(std::chrono::seconds(5)); | ||
|
||
LogInfo() << "Transitioning to multicopter"; | ||
device.action().transition_to_multicopter(); | ||
std::this_thread::sleep_for(std::chrono::seconds(5)); | ||
|
||
// Return safely to launch position so the next test | ||
// can start with a clean slate | ||
land_and_disarm(device); | ||
} | ||
|
||
void land_and_disarm(Device &device) | ||
{ | ||
device.action().return_to_launch(); | ||
|
||
// Wait until the vtol is disarmed. | ||
while (device.telemetry().armed()) { | ||
std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
} | ||
LogInfo() << "Disarmed, exiting."; | ||
} | ||
|
||
void takeoff(Device &device) | ||
{ | ||
while (!device.telemetry().health_all_ok()) { | ||
std::cout << "waiting for device to be ready" << std::endl; | ||
std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
} | ||
|
||
Action::Result action_ret = device.action().arm(); | ||
EXPECT_EQ(action_ret, Action::Result::SUCCESS); | ||
std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
|
||
float altitude_m = 10.0f; | ||
device.action().set_takeoff_altitude(altitude_m); | ||
|
||
action_ret = device.action().takeoff(); | ||
EXPECT_EQ(action_ret, Action::Result::SUCCESS); | ||
const int wait_time_s = 10; | ||
std::this_thread::sleep_for(std::chrono::seconds(wait_time_s)); | ||
|
||
|
||
EXPECT_GT(device.telemetry().position().relative_altitude_m, altitude_m - 0.25f); | ||
EXPECT_LT(device.telemetry().position().relative_altitude_m, altitude_m + 0.25f); | ||
} | ||
|
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
Oops, something went wrong.