Skip to content

Commit

Permalink
Merge pull request #1733 from mavlink/pr-component-camera-server
Browse files Browse the repository at this point in the history
Server component  and server plugin infrastructure
  • Loading branch information
julianoes authored May 12, 2022
2 parents a03ba2c + a62c249 commit bb6941d
Show file tree
Hide file tree
Showing 171 changed files with 13,663 additions and 2,070 deletions.
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");
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
1 change: 0 additions & 1 deletion src/integration_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ add_executable(integration_tests_runner
camera_take_photo_interval.cpp
camera_format.cpp
camera_test_helpers.cpp
component_information.cpp
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);

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

0 comments on commit bb6941d

Please sign in to comment.