Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server component and server plugin infrastructure #1733

Merged
merged 54 commits into from
May 12, 2022
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
6146ab2
WIP: add camera server
dlech Jan 14, 2022
b7e97c3
camera_server: implement take photo
dlech Feb 15, 2022
1213376
camera_server: improvements and fixes
dlech Feb 15, 2022
2cd305c
camera_server: use subscriptions as capability flags
dlech Feb 17, 2022
e97095a
camera_server: implement additional information fields
dlech Feb 17, 2022
d8bae15
camera_server: improve in_progress state
dlech Feb 17, 2022
90eb955
core: use CamelCase only
julianoes Apr 8, 2022
ad2f80b
core: refactoring for server components
julianoes Apr 8, 2022
4a9fb26
param system test working
julianoes Apr 15, 2022
509bbec
param system test mostly working
julianoes Apr 15, 2022
2f59f75
camera_server: workarounds for mavlink memcpy
julianoes Apr 16, 2022
8e09b09
camera_server: ignore duplicate commands
julianoes Apr 16, 2022
779ed21
action_server: fix heap corruption on destruction
julianoes Apr 17, 2022
0127475
system_tests: don't wait for timeouts
julianoes Apr 17, 2022
a3eaa5e
fixup style and rebase conflicts
julianoes Apr 18, 2022
5704df2
templates: fixup
julianoes Apr 21, 2022
8e9b7e0
templates: don't use Result::NoSystem for servers
julianoes Apr 26, 2022
5d702a2
Running auto-generation again
julianoes May 6, 2022
e4b0a40
Rebase and comment fixes
julianoes May 6, 2022
2d95ce4
workflows: run system_tests in CI
julianoes May 6, 2022
189c347
core: add missing header install
julianoes May 6, 2022
d6d01d5
core: use queue for subsciption callback
julianoes May 6, 2022
5697557
system_tests: add test for mission upload
julianoes May 6, 2022
45c2f64
core: mission transfer work is required
julianoes May 6, 2022
0240c2d
mission_raw_server: make copies of callbacks
julianoes May 6, 2022
676d6d1
core: forgot to install header
julianoes May 6, 2022
59d0357
workflows: path fix
julianoes May 6, 2022
17cf9b4
core: add some missing comments
julianoes May 6, 2022
0f57393
core: don't forget to lock components
julianoes May 8, 2022
8a6b9bf
mission_raw_server: unregister from messages
julianoes May 8, 2022
0218f81
examples: fix autopilot_server example
julianoes May 8, 2022
b06ddf2
examples: fix camera server
julianoes May 8, 2022
2d3686f
core: add missing docstring
julianoes May 8, 2022
46e3aa6
camera_server: fix MSVC warnings
julianoes May 8, 2022
d3c18be
core: remove redundant method
julianoes May 9, 2022
a219a25
core: make sure mavsdk sends heartbeats
julianoes May 9, 2022
617a7f0
system_tests: relax timeout requirements
julianoes May 9, 2022
d91b663
examples: add TODOs
julianoes May 9, 2022
5931e73
core: fix steps on server component init
julianoes May 9, 2022
fcb298d
workflows: trying to get version tags for macOS CI
julianoes May 9, 2022
fa4a034
core: fix various clang gwarnings
julianoes May 9, 2022
8b9eb5b
core: workaround to avoid deadlocks
julianoes May 9, 2022
d88f4e4
core: move intercept to MavsdkImpl
julianoes May 10, 2022
c0234b3
core/action_server: pass through shared state
julianoes May 10, 2022
d722098
action_server: copy callbacks before queueing
julianoes May 10, 2022
148d6e5
core: removed empty file
julianoes May 10, 2022
8f6806d
param_server: re-enable retrieve_all_server_params
julianoes May 10, 2022
f3a529a
core: update parameters after refactoring
julianoes May 10, 2022
837c546
core: add RequestMessageHandler to server impl
julianoes May 10, 2022
480ee4a
core: remove unused method declaration
julianoes May 10, 2022
48c938a
component_information: move test
julianoes May 12, 2022
c45e40b
integration_tests: enable call again
julianoes May 12, 2022
0d848a8
core: remove ununsed call
julianoes May 12, 2022
a62c249
core: remove commented out code
julianoes May 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ jobs:
run: cmake $superbuild $cmake_prefix_path -DCMAKE_BUILD_TYPE=Coverage -DASAN=ON -DWERROR=OFF -Bbuild -H.
- name: build
run: cmake --build build -j2
- name: test
- name: unit tests
run: ./build/src/unit_tests_runner
- name: system tests
run: ./build/src/system_tests/system_tests_runner
- name: run lcov
run: lcov --capture --directory . --no-external --exclude "*/third_party/*" --output-file lcov.info
- name: check size of lcov.info
Expand All @@ -65,8 +67,10 @@ jobs:
run: cmake -DCMAKE_BUILD_TYPE=Release -DSUPERBUILD=OFF -DWERROR=OFF -Bbuild/release -H.
- name: build
run: cmake --build build/release -j2
- name: test
- name: unit tests
run: ./build/release/src/unit_tests_runner
- name: system tests
run: ./build/release/src/system_tests/system_tests_runner

ubuntu20-superbuild:
name: ubuntu-20.04 (mavsdk_server, superbuild)
Expand Down Expand Up @@ -97,8 +101,10 @@ jobs:
run: (cd examples && cmake -DCMAKE_BUILD_TYPE=Release -DWERROR=OFF -Bbuild -H.)
- name: build examples
run: (cd examples && cmake --build build -j2)
- name: test
- name: unit tests
run: ./build/release/src/unit_tests_runner
- name: system tests
run: ./build/release/src/system_tests/system_tests_runner
- name: test (mavsdk_server)
run: ./build/release/src/mavsdk_server/test/unit_tests_mavsdk_server
- name: test FTP server
Expand All @@ -124,8 +130,10 @@ jobs:
run: cmake -DSUPERBUILD=OFF -DHUNTER_ENABLED=ON -DCMAKE_TOOLCHAIN_FILE=$(pwd)/src/cmake/fpic_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_MAVSDK_SERVER=OFF -DBUILD_SHARED_LIBS=OFF -DMAVLINK_HEADERS=mavlink-headers/include -Bbuild -H.
- name: build
run: cmake --build build -j2
- name: run unit test
run: build/src/unit_tests_runner
- name: unit tests
run: ./build/src/unit_tests_runner
- name: system tests
run: ./build/src/system_tests/system_tests_runner

ubuntu20-proto-check:
name: ubuntu-20.04 (proto check)
Expand Down Expand Up @@ -367,8 +375,10 @@ jobs:
run: cmake $superbuild $cmake_prefix_path -DCMAKE_BUILD_TYPE=Release -DBUILD_MAVSDK_SERVER=ON -DBUILD_SHARED_LIBS=OFF -DBUILD_STATIC_MAVSDK_SERVER=ON -DCMAKE_INSTALL_PREFIX=install -DWERROR=OFF -Bbuild/release -H.
- name: build
run: cmake --build build/release --target install -- -j2
- name: test
- name: unit tests
run: ./build/release/src/unit_tests_runner
- name: system tests
run: ./build/release/src/system_tests/system_tests_runner
- name: test (mavsdk_server)
run: ./build/release/src/mavsdk_server/test/unit_tests_mavsdk_server
- name: Upload as artefact
Expand Down Expand Up @@ -493,7 +503,7 @@ jobs:
path: ./build/macos/third_party/install
key: ${{ github.job }}-${{ matrix.name }}-${{ hashFiles('./third_party/**') }}
- name: fetch git tags for version
run: git fetch --tags
run: git fetch --prune --unshallow --tags
- name: disable superbuild on cache hit
if: steps.cache.outputs.cache-hit == 'true'
run: echo "superbuild=-DSUPERBUILD=OFF" >> $GITHUB_ENV && echo "cmake_prefix_path=-DCMAKE_PREFIX_PATH=$(pwd)/build/macos/third_party/install" >> $GITHUB_ENV
Expand All @@ -505,8 +515,10 @@ jobs:
run: cmake $superbuild $cmake_prefix_path -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=build/macos/install -DBUILD_MAVSDK_SERVER=ON -DBUILD_SHARED_LIBS=OFF -DMACOS_FRAMEWORK=${{ matrix.build-framework }} -DWERROR=OFF -Bbuild/macos -H.
- name: build
run: cmake --build build/macos -j2 --target install
- name: test (core)
- name: unit tests
run: ./build/macos/src/unit_tests_runner
- name: system tests
run: ./build/macos/src/system_tests/system_tests_runner
- name: test (mavsdk_server)
run: ./build/macos/src/mavsdk_server/test/unit_tests_mavsdk_server
- name: Upload framework as artefact
Expand Down Expand Up @@ -548,7 +560,7 @@ jobs:
path: ./build/${{ matrix.name }}/third_party/install
key: ${{ github.job }}-${{ matrix.name }}-${{ hashFiles('./third_party/**', './tools/ios.toolchain.cmake') }}
- name: fetch git tags for version
run: git fetch --tags
run: git fetch --prune --unshallow --tags
- name: disable superbuild on cache hit
if: steps.cache.outputs.cache-hit == 'true'
run: echo "superbuild=-DSUPERBUILD=OFF" >> $GITHUB_ENV && echo "cmake_prefix_path=-DCMAKE_PREFIX_PATH=$(pwd)/build/${{ matrix.name }}/third_party/install" >> $GITHUB_ENV
Expand Down
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ add_subdirectory(autopilot_server)
add_subdirectory(battery)
add_subdirectory(calibrate)
add_subdirectory(camera)
add_subdirectory(camera_server)
add_subdirectory(camera_settings)
add_subdirectory(fly_mission)
add_subdirectory(fly_multiple_drones)
Expand Down
43 changes: 10 additions & 33 deletions examples/autopilot_server/autopilot_server.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <future>

#include <iostream>
#include <thread>

#include <mavsdk/mavsdk.h>
#include <mavsdk/plugins/mavlink_passthrough/mavlink_passthrough.h>
#include <mavsdk/plugins/telemetry/telemetry.h>
Expand Down Expand Up @@ -68,36 +68,13 @@ int main(int argc, char** argv)
std::cout << "Connected autopilot server side!" << std::endl;
}

auto prom = std::promise<std::shared_ptr<mavsdk::System>>{};
auto fut = prom.get_future();
mavsdkTester.subscribe_on_new_system([&mavsdkTester, &prom]() {
std::cout << "Discovered MAVSDK GCS" << std::endl;
auto system = mavsdkTester.systems().back();
mavsdkTester.subscribe_on_new_system(nullptr);
prom.set_value(system);
});

std::cout << "Sleeping AP thread... " << std::endl;
for (auto i = 0; i < 3; i++) {
std::this_thread::sleep_for(std::chrono::seconds(5));
if (mavsdkTester.systems().size() == 0) {
std::cout << "No System Found from Autopilot, trying again in 5 secs..."
<< std::endl;
if (i == 2) {
std::cout << "No System found after three retries. Aborting..." << std::endl;
return;
}
} else {
std::cout << "Setting System" << std::endl;
break;
}
}
auto system = mavsdkTester.systems().back();
auto server_component =
mavsdkTester.server_component_by_type(Mavsdk::ServerComponentType::Autopilot);

// Create server plugins
auto paramServer = mavsdk::ParamServer{system};
auto telemServer = mavsdk::TelemetryServer{system};
auto actionServer = mavsdk::ActionServer{system};
auto paramServer = mavsdk::ParamServer{server_component};
auto telemServer = mavsdk::TelemetryServer{server_component};
auto actionServer = mavsdk::ActionServer{server_component};

// These are needed for MAVSDK at the moment
paramServer.provide_param_int("CAL_ACC0_ID", 1);
Expand All @@ -115,7 +92,7 @@ int main(int argc, char** argv)

// Create a mission raw server
// This will allow us to receive missions from a GCS
auto missionRawServer = mavsdk::MissionRawServer{system};
auto missionRawServer = mavsdk::MissionRawServer{server_component};
std::cout << "MissionRawServer created" << std::endl;

auto mission_prom = std::promise<MissionRawServer::MissionPlan>{};
Expand Down Expand Up @@ -214,9 +191,9 @@ int main(int argc, char** argv)
std::this_thread::sleep_for(std::chrono::seconds(5));

// Check for our custom param we have set in the server thread
auto res = param.get_param_int("my_param");
auto res = param.get_param_int("MY_PARAM");
if (res.first == mavsdk::Param::Result::Success) {
std::cout << "Found Param my_param: " << res.second << std::endl;
std::cout << "Found Param MY_PARAM: " << res.second << std::endl;
}

// Create a mission to send to our mission server
Expand Down Expand Up @@ -308,4 +285,4 @@ int main(int argc, char** argv)
}

return 0;
}
}
22 changes: 22 additions & 0 deletions examples/camera_server/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.10.2)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

project(camera_server)

add_executable(camera_server
camera_server.cpp
)

find_package(MAVSDK REQUIRED)

target_link_libraries(camera_server
MAVSDK::mavsdk
)

if(NOT MSVC)
add_compile_options(camera_server PRIVATE -Wall -Wextra)
else()
add_compile_options(camera_server PRIVATE -WX -W2)
endif()
102 changes: 102 additions & 0 deletions examples/camera_server/camera_server.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include <future>

#include <iostream>
#include <map>
#include <thread>
#include <mavsdk/mavsdk.h>
#include <mavsdk/plugins/camera/camera.h>
#include <mavsdk/plugins/camera_server/camera_server.h>

using namespace mavsdk;

using std::chrono::duration_cast;
using std::chrono::seconds;
using std::chrono::milliseconds;
using std::chrono::system_clock;
using std::this_thread::sleep_for;

int main(int argc, char** argv)
{
mavsdk::Mavsdk mavsdk;
mavsdk::Mavsdk::Configuration configuration(mavsdk::Mavsdk::Configuration::UsageType::Camera);
mavsdk.set_configuration(configuration);

// 14030 is the default camera port for PX4 SITL
// FIXME: the camera should probably initiate the connection and not just listen
auto result = mavsdk.add_any_connection("udp://:14030");
JonasVautherin marked this conversation as resolved.
Show resolved Hide resolved
if (result != mavsdk::ConnectionResult::Success) {
std::cerr << "Could not establish connection: " << result << std::endl;
return 1;
}
std::cout << "Created camera server connection" << std::endl;

auto camera_server = mavsdk::CameraServer{
mavsdk.server_component_by_type(mavsdk::Mavsdk::ServerComponentType::Camera)};

// First add all subscriptions. This defines the camera capabilities.

camera_server.subscribe_take_photo([&camera_server](int32_t index) {
camera_server.set_in_progress(true);

std::cout << "taking a picture (" << +index << ")..." << std::endl;

// TODO : actually capture image here
// simulating with delay
sleep_for(milliseconds(500));

// TODO: populate with telemetry data
auto position = CameraServer::Position{};
auto attitude = CameraServer::Quaternion{};

auto timestamp =
duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
auto success = true;

camera_server.set_in_progress(false);

camera_server.respond_take_photo(
mavsdk::CameraServer::TakePhotoFeedback::Ok,
mavsdk::CameraServer::CaptureInfo{
.position = position,
.attitude_quaternion = attitude,
.time_utc_us = static_cast<uint64_t>(timestamp),
.is_success = success,
.index = index,
.file_url = {},
});
});

// Then set the initial state of everything.

// TODO: this state is not guaranteed, e.g. a new system appears
// while a capture is in progress
camera_server.set_in_progress(false);

// Finally call set_information() to "activate" the camera plugin.

auto ret = camera_server.set_information({
.vendor_name = "MAVSDK",
.model_name = "Example Camera Server",
.firmware_version = "1.0.0",
.focal_length_mm = 3.0,
.horizontal_sensor_size_mm = 3.68,
.vertical_sensor_size_mm = 2.76,
.horizontal_resolution_px = 3280,
.vertical_resolution_px = 2464,
.lens_id = 0,
.definition_file_version = 0, // TODO: add this
.definition_file_uri = "", // TODO: implement this using MAVLink FTP
});

if (ret != CameraServer::Result::Success) {
std::cerr << "Failed to set camera info, exiting" << std::endl;
return 2;
}

while (true) {
// Wait forever?
sleep_for(seconds(1));
}

return 0;
}
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ if(BUILD_TESTS)
add_subdirectory(integration_tests)

include(cmake/unit_tests.cmake)

add_subdirectory(system_tests)
endif()

if (BUILD_MAVSDK_SERVER)
Expand Down
2 changes: 1 addition & 1 deletion src/integration_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ add_executable(integration_tests_runner
camera_take_photo_interval.cpp
camera_format.cpp
camera_test_helpers.cpp
component_information.cpp
#component_information.cpp
JonasVautherin marked this conversation as resolved.
Show resolved Hide resolved
connection.cpp
follow_me.cpp
geofence_inclusion.cpp
Expand Down
46 changes: 30 additions & 16 deletions src/integration_tests/camera_take_photo.cpp
Original file line number Diff line number Diff line change
@@ -1,43 +1,57 @@
#include <iostream>
#include <functional>
#include <vector>
#include <atomic>
#include <future>
#include "integration_test_helper.h"
#include "mavsdk.h"
#include "system.h"
#include "camera_test_helpers.h"
#include "plugins/camera/camera.h"
#include "plugins/camera_server/camera_server.h"

using namespace mavsdk;

static void receive_capture_info(Camera::CaptureInfo capture_info, bool& received_capture_info);

TEST(CameraTest, TakePhotoSingle)
{
Mavsdk mavsdk;
Mavsdk mavsdk_groundstation;
mavsdk_groundstation.set_configuration(
Mavsdk::Configuration{Mavsdk::Configuration::UsageType::GroundStation});

ConnectionResult ret = mavsdk.add_udp_connection();
ASSERT_EQ(ret, ConnectionResult::Success);
Mavsdk mavsdk_camera;
mavsdk_camera.set_configuration(
Mavsdk::Configuration{Mavsdk::Configuration::UsageType::Camera});

ASSERT_EQ(mavsdk_groundstation.add_any_connection("udp://:17000"), ConnectionResult::Success);
ASSERT_EQ(mavsdk_camera.add_any_connection("udp://127.0.0.1:17000"), ConnectionResult::Success);

auto camera_server =
CameraServer{mavsdk_camera.server_component_by_type(Mavsdk::ServerComponentType::Camera)};
camera_server.subscribe_take_photo([&camera_server](int32_t index) {
LogInfo() << "Let's take photo " << index;

CameraServer::CaptureInfo info;
info.index = index;
info.is_success = true;

camera_server.respond_take_photo(CameraServer::TakePhotoFeedback::Ok, info);
});

// Wait for system to connect via heartbeat.
std::this_thread::sleep_for(std::chrono::seconds(2));

auto system = mavsdk.systems().at(0);
ASSERT_EQ(mavsdk_groundstation.systems().size(), 1);
auto system = mavsdk_groundstation.systems().at(0);
ASSERT_TRUE(system->has_camera());
auto camera = std::make_shared<Camera>(system);

std::this_thread::sleep_for(std::chrono::seconds(1));
auto camera = Camera{system};

// We want to take the picture in photo mode.
EXPECT_EQ(camera->set_mode(Camera::Mode::Photo), Camera::Result::Success);
// EXPECT_EQ(camera.set_mode(Camera::Mode::Photo), Camera::Result::Success);
JonasVautherin marked this conversation as resolved.
Show resolved Hide resolved

bool received_capture_info = false;
camera->subscribe_capture_info([&received_capture_info](Camera::CaptureInfo capture_info) {
camera.subscribe_capture_info([&received_capture_info](Camera::CaptureInfo capture_info) {
receive_capture_info(capture_info, received_capture_info);
});

EXPECT_EQ(camera->take_photo(), Camera::Result::Success);
std::this_thread::sleep_for(std::chrono::seconds(5));
EXPECT_EQ(camera.take_photo(), Camera::Result::Success);
std::this_thread::sleep_for(std::chrono::seconds(1));
EXPECT_TRUE(received_capture_info);
}

Expand Down
Loading