mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-06-08 07:50:06 +08:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 58b0a1f90d | |||
| 8e71a96cf7 | |||
| 704c05c428 | |||
| 5c2c48f29d | |||
| 1fbe481a86 | |||
| 107393e6ad | |||
| 5824bdb5fb | |||
| 1c25698396 | |||
| f7af8f4528 | |||
| d9865a19ee | |||
| e0ff60e827 | |||
| d2539ed9f9 | |||
| ad82801583 | |||
| cb6094ab59 | |||
| ee1f316052 | |||
| a14de32d2e | |||
| a41d35b57f | |||
| debca7f517 | |||
| f29eb2ee32 |
@@ -26,14 +26,13 @@ jobs:
|
||||
name: Testing PX4 ${{ matrix.config.model }}
|
||||
runs-on: [runs-on,runner=4cpu-linux-x64,image=ubuntu22-full-x64,"run-id=${{ github.run_id }}",spot=false]
|
||||
container:
|
||||
image: px4io/px4-dev-simulation-focal:2021-09-08
|
||||
image: px4io/px4-dev:v1.16.0-rc1-258-g0369abd556
|
||||
options: --privileged --ulimit core=-1 --security-opt seccomp=unconfined
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- {model: "iris", latitude: "59.617693", longitude: "-151.145316", altitude: "48", build_type: "RelWithDebInfo" } # Alaska
|
||||
- {model: "tailsitter" , latitude: "29.660316", longitude: "-82.316658", altitude: "30", build_type: "RelWithDebInfo" } # Florida
|
||||
- {model: "quadx", latitude: "59.617693", longitude: "-151.145316", altitude: "48", build_type: "RelWithDebInfo" } # Alaska
|
||||
- {model: "standard_vtol", latitude: "47.397742", longitude: "8.545594", altitude: "488", build_type: "Coverage" } # Zurich
|
||||
|
||||
steps:
|
||||
@@ -74,19 +73,11 @@ jobs:
|
||||
- name: Cache Post-Run [px4_sitl_default]
|
||||
run: ccache -s
|
||||
|
||||
- name: Build SITL Gazebo
|
||||
env:
|
||||
PX4_CMAKE_BUILD_TYPE: ${{matrix.config.build_type}}
|
||||
run: make px4_sitl_default sitl_gazebo-classic
|
||||
|
||||
- name: Cache Post-Run [sitl_gazebo-classic]
|
||||
run: ccache -s
|
||||
|
||||
- name: Download MAVSDK
|
||||
run: wget "https://github.com/mavlink/MAVSDK/releases/download/v$(cat test/mavsdk_tests/MAVSDK_VERSION)/libmavsdk-dev_$(cat test/mavsdk_tests/MAVSDK_VERSION)_ubuntu20.04_amd64.deb"
|
||||
run: wget "https://github.com/mavlink/MAVSDK/releases/download/v$(cat test/mavsdk_tests/MAVSDK_VERSION)/libmavsdk-dev_$(cat test/mavsdk_tests/MAVSDK_VERSION)_ubuntu22.04_amd64.deb"
|
||||
|
||||
- name: Install MAVSDK
|
||||
run: dpkg -i "libmavsdk-dev_$(cat test/mavsdk_tests/MAVSDK_VERSION)_ubuntu20.04_amd64.deb"
|
||||
run: dpkg -i "libmavsdk-dev_$(cat test/mavsdk_tests/MAVSDK_VERSION)_ubuntu22.04_amd64.deb"
|
||||
|
||||
- name: Check PX4 Environment Variables
|
||||
env:
|
||||
@@ -102,9 +93,9 @@ jobs:
|
||||
env:
|
||||
PX4_CMAKE_BUILD_TYPE: ${{matrix.config.build_type}}
|
||||
DONT_RUN: 1
|
||||
run: make px4_sitl_default sitl_gazebo-classic mavsdk_tests
|
||||
run: make px4_sitl_default mavsdk_tests
|
||||
|
||||
- name: Cache Post-Run [px4_sitl_default sitl_gazebo-classic mavsdk_tests]
|
||||
- name: Cache Post-Run [px4_sitl_default mavsdk_tests]
|
||||
run: ccache -s
|
||||
|
||||
- name: Core Dump Settings
|
||||
@@ -118,7 +109,7 @@ jobs:
|
||||
PX4_HOME_LON: ${{matrix.config.longitude}}
|
||||
PX4_HOME_ALT: ${{matrix.config.altitude}}
|
||||
PX4_CMAKE_BUILD_TYPE: ${{matrix.config.build_type}}
|
||||
run: test/mavsdk_tests/mavsdk_test_runner.py --speed-factor 10 --abort-early --model ${{matrix.config.model}} test/mavsdk_tests/configs/sitl.json --verbose --force-color
|
||||
run: test/mavsdk_tests/mavsdk_test_runner.py --speed-factor 10 --abort-early --model ${{matrix.config.model}} test/mavsdk_tests/configs/sih-sitl.json --verbose --force-color
|
||||
timeout-minutes: 45
|
||||
|
||||
- name: Upload failed logs
|
||||
|
||||
@@ -429,16 +429,14 @@ rostest: px4_sitl_default
|
||||
@$(MAKE) --no-print-directory px4_sitl_default sitl_gazebo-classic
|
||||
|
||||
tests_integration: px4_sitl_default
|
||||
@$(MAKE) --no-print-directory px4_sitl_default sitl_gazebo-classic
|
||||
@$(MAKE) --no-print-directory px4_sitl_default mavsdk_tests
|
||||
@"$(SRC_DIR)"/test/mavsdk_tests/mavsdk_test_runner.py --speed-factor 20 test/mavsdk_tests/configs/sitl.json
|
||||
@"$(SRC_DIR)"/test/mavsdk_tests/mavsdk_test_runner.py --speed-factor 20 test/mavsdk_tests/configs/sih-sitl.json
|
||||
|
||||
tests_integration_coverage:
|
||||
@$(MAKE) clean
|
||||
@$(MAKE) --no-print-directory px4_sitl_default PX4_CMAKE_BUILD_TYPE=Coverage
|
||||
@$(MAKE) --no-print-directory px4_sitl_default sitl_gazebo-classic
|
||||
@$(MAKE) --no-print-directory px4_sitl_default mavsdk_tests
|
||||
@"$(SRC_DIR)"/test/mavsdk_tests/mavsdk_test_runner.py --speed-factor 20 test/mavsdk_tests/configs/sitl.json
|
||||
@"$(SRC_DIR)"/test/mavsdk_tests/mavsdk_test_runner.py --speed-factor 20 test/mavsdk_tests/configs/sih-sitl.json
|
||||
@mkdir -p coverage
|
||||
@lcov --directory build/px4_sitl_default --base-directory build/px4_sitl_default --gcov-tool gcov --capture -o coverage/lcov.info
|
||||
|
||||
|
||||
@@ -45,10 +45,10 @@ Install either from binaries or source:
|
||||
|
||||
## Run All PX4 Tests
|
||||
|
||||
To run all SITL tests as defined in [sitl.json](https://github.com/PX4/PX4-Autopilot/blob/main/test/mavsdk_tests/configs/sitl.json), do:
|
||||
To run all SITL tests using the SIH simulator as defined in [sih-sitl.json](https://github.com/PX4/PX4-Autopilot/blob/main/test/mavsdk_tests/configs/sih-sitl.json), do:
|
||||
|
||||
```sh
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sitl.json --speed-factor 10
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sih-sitl.json --speed-factor 10
|
||||
```
|
||||
|
||||
This will list all the tests and then run them sequentially.
|
||||
@@ -87,10 +87,10 @@ options:
|
||||
## Run a Single Test
|
||||
|
||||
Run a single test by specifying the `model` and test `case` as command line options.
|
||||
For example, to test flying a tailsitter in a mission you might run:
|
||||
For example, to test a multicopter mission using the SIH simulator:
|
||||
|
||||
```sh
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sitl.json --speed-factor 10 --model tailsitter --case 'Fly VTOL mission'
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sih-sitl.json --speed-factor 10 --model quadx --case 'Fly square Multicopter Missions including RTL'
|
||||
```
|
||||
|
||||
The easiest way to find out the current set of models and their associated test cases is to run all PX4 tests [as shown above](#run-all-px4-tests) (note, you can then cancel the build if you wish to test just one).
|
||||
|
||||
@@ -45,10 +45,10 @@ The tests need the MAVSDK C++ library installed system-wide (e.g. in `/usr/lib`
|
||||
|
||||
## 모든 PX4 테스트 실행
|
||||
|
||||
To run all SITL tests as defined in [sitl.json](https://github.com/PX4/PX4-Autopilot/blob/main/test/mavsdk_tests/configs/sitl.json), do:
|
||||
To run all SITL tests using the SIH simulator as defined in [sih-sitl.json](https://github.com/PX4/PX4-Autopilot/blob/main/test/mavsdk_tests/configs/sih-sitl.json), do:
|
||||
|
||||
```sh
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sitl.json --speed-factor 10
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sih-sitl.json --speed-factor 10
|
||||
```
|
||||
|
||||
This will list all the tests and then run them sequentially.
|
||||
@@ -87,10 +87,10 @@ options:
|
||||
## 단일 테스트 실행
|
||||
|
||||
Run a single test by specifying the `model` and test `case` as command line options.
|
||||
예를 들어, 임무에서 테일시터 비행을 테스트하려면, 다음을 실행합니다.
|
||||
For example, to test a multicopter mission using the SIH simulator:
|
||||
|
||||
```sh
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sitl.json --speed-factor 10 --model tailsitter --case 'Fly square Multicopter Missions including RTL'
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sih-sitl.json --speed-factor 10 --model quadx --case 'Fly square Multicopter Missions including RTL'
|
||||
```
|
||||
|
||||
The easiest way to find out the current set of models and their associated test cases is to run all PX4 tests [as shown above](#run-all-px4-tests) (note, you can then cancel the build if you wish to test just one).
|
||||
|
||||
@@ -45,10 +45,10 @@ The tests need the MAVSDK C++ library installed system-wide (e.g. in `/usr/lib`
|
||||
|
||||
## Запуск усіх PX4 тестів
|
||||
|
||||
To run all SITL tests as defined in [sitl.json](https://github.com/PX4/PX4-Autopilot/blob/main/test/mavsdk_tests/configs/sitl.json), do:
|
||||
To run all SITL tests using the SIH simulator as defined in [sih-sitl.json](https://github.com/PX4/PX4-Autopilot/blob/main/test/mavsdk_tests/configs/sih-sitl.json), do:
|
||||
|
||||
```sh
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sitl.json --speed-factor 10
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sih-sitl.json --speed-factor 10
|
||||
```
|
||||
|
||||
This will list all the tests and then run them sequentially.
|
||||
@@ -87,10 +87,10 @@ options:
|
||||
## Запуск одного тесту
|
||||
|
||||
Run a single test by specifying the `model` and test `case` as command line options.
|
||||
Наприклад, щоб протестувати керування хвостовиком у місії, ви можете виконати:
|
||||
For example, to test a multicopter mission using the SIH simulator:
|
||||
|
||||
```sh
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sitl.json --speed-factor 10 --model tailsitter --case 'Fly VTOL mission'
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sih-sitl.json --speed-factor 10 --model quadx --case 'Fly square Multicopter Missions including RTL'
|
||||
```
|
||||
|
||||
The easiest way to find out the current set of models and their associated test cases is to run all PX4 tests [as shown above](#run-all-px4-tests) (note, you can then cancel the build if you wish to test just one).
|
||||
|
||||
@@ -45,10 +45,10 @@ The tests need the MAVSDK C++ library installed system-wide (e.g. in `/usr/lib`
|
||||
|
||||
## 准备 PX4 源码
|
||||
|
||||
To run all SITL tests as defined in [sitl.json](https://github.com/PX4/PX4-Autopilot/blob/main/test/mavsdk_tests/configs/sitl.json), do:
|
||||
To run all SITL tests using the SIH simulator as defined in [sih-sitl.json](https://github.com/PX4/PX4-Autopilot/blob/main/test/mavsdk_tests/configs/sih-sitl.json), do:
|
||||
|
||||
```sh
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sitl.json --speed-factor 10
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sih-sitl.json --speed-factor 10
|
||||
```
|
||||
|
||||
This will list all the tests and then run them sequentially.
|
||||
@@ -87,10 +87,10 @@ options:
|
||||
## 关于实现的说明
|
||||
|
||||
Run a single test by specifying the `model` and test `case` as command line options.
|
||||
For example, to test flying a tailsitter in a mission you might run:
|
||||
For example, to test a multicopter mission using the SIH simulator:
|
||||
|
||||
```sh
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sitl.json --speed-factor 10 --model tailsitter --case 'Fly VTOL mission'
|
||||
test/mavsdk_tests/mavsdk_test_runner.py test/mavsdk_tests/configs/sih-sitl.json --speed-factor 10 --model quadx --case 'Fly square Multicopter Missions including RTL'
|
||||
```
|
||||
|
||||
The easiest way to find out the current set of models and their associated test cases is to run all PX4 tests [as shown above](#run-all-px4-tests) (note, you can then cancel the build if you wish to test just one).
|
||||
|
||||
@@ -2384,11 +2384,18 @@ Mavlink::task_main(int argc, char *argv[])
|
||||
/* main loop */
|
||||
px4_usleep(_main_loop_delay);
|
||||
|
||||
#if defined(ENABLE_LOCKSTEP_SCHEDULER)
|
||||
int lockstep_component = px4_lockstep_register_component();
|
||||
#endif
|
||||
|
||||
if (!should_transmit()) {
|
||||
check_requested_subscriptions();
|
||||
handleStatus();
|
||||
handleCommands();
|
||||
handleAndGetCurrentCommandAck();
|
||||
#if defined(ENABLE_LOCKSTEP_SCHEDULER)
|
||||
px4_lockstep_unregister_component(lockstep_component);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2520,6 +2527,10 @@ Mavlink::task_main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
perf_end(_loop_perf);
|
||||
|
||||
#if defined(ENABLE_LOCKSTEP_SCHEDULER)
|
||||
px4_lockstep_unregister_component(lockstep_component);
|
||||
#endif
|
||||
}
|
||||
|
||||
_receiver.stop();
|
||||
|
||||
@@ -503,6 +503,8 @@ MavlinkMissionManager::send()
|
||||
if (_mission_result_sub.update()) {
|
||||
const mission_result_s &mission_result = _mission_result_sub.get();
|
||||
|
||||
bool send_current = false;
|
||||
|
||||
if (_current_seq != mission_result.seq_current) {
|
||||
|
||||
_current_seq = mission_result.seq_current;
|
||||
@@ -511,7 +513,7 @@ MavlinkMissionManager::send()
|
||||
|
||||
if (mission_result.seq_total > 0) {
|
||||
if (mission_result.seq_current < mission_result.seq_total) {
|
||||
send_mission_current(_current_seq);
|
||||
send_current = true;
|
||||
|
||||
} else {
|
||||
_mavlink.send_statustext_critical("ERROR: wp index out of bounds\t");
|
||||
@@ -521,6 +523,16 @@ MavlinkMissionManager::send()
|
||||
}
|
||||
}
|
||||
|
||||
// Send MISSION_CURRENT when finished state changes (to notify MISSION_STATE_COMPLETE)
|
||||
if (_last_finished != mission_result.finished) {
|
||||
_last_finished = mission_result.finished;
|
||||
send_current = true;
|
||||
}
|
||||
|
||||
if (send_current) {
|
||||
send_mission_current(_current_seq);
|
||||
}
|
||||
|
||||
if (_last_reached != mission_result.seq_reached) {
|
||||
|
||||
_last_reached = mission_result.seq_reached;
|
||||
|
||||
@@ -132,6 +132,7 @@ private:
|
||||
static int32_t _current_seq; ///< Current item sequence in active mission
|
||||
|
||||
int32_t _last_reached{-1}; ///< Last reached waypoint in active mission (-1 means nothing reached)
|
||||
bool _last_finished{false}; ///< Last mission finished state
|
||||
|
||||
dm_item_t _transfer_dataman_id{DM_KEY_WAYPOINTS_OFFBOARD_1}; ///< Dataman storage ID for current transmission
|
||||
|
||||
|
||||
@@ -195,6 +195,9 @@ void Navigator::run()
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_LOCKSTEP_SCHEDULER)
|
||||
int lockstep_component = px4_lockstep_register_component();
|
||||
#endif
|
||||
perf_begin(_loop_perf);
|
||||
|
||||
orb_copy(ORB_ID(vehicle_local_position), _local_pos_sub, &_local_pos);
|
||||
@@ -933,6 +936,10 @@ void Navigator::run()
|
||||
_geofence.run();
|
||||
|
||||
perf_end(_loop_perf);
|
||||
|
||||
#if defined(ENABLE_LOCKSTEP_SCHEDULER)
|
||||
px4_lockstep_unregister_component(lockstep_component);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,57 @@ float SensorBaroSim::generate_wgn()
|
||||
return X;
|
||||
}
|
||||
|
||||
void SensorBaroSim::check_failure_injections()
|
||||
{
|
||||
vehicle_command_s vehicle_command;
|
||||
|
||||
while (_vehicle_command_sub.update(&vehicle_command)) {
|
||||
if (vehicle_command.command != vehicle_command_s::VEHICLE_CMD_INJECT_FAILURE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
bool supported = false;
|
||||
|
||||
const int failure_unit = static_cast<int>(vehicle_command.param1 + 0.5f);
|
||||
const int failure_type = static_cast<int>(vehicle_command.param2 + 0.5f);
|
||||
|
||||
if (failure_unit == vehicle_command_s::FAILURE_UNIT_SENSOR_BARO) {
|
||||
handled = true;
|
||||
|
||||
if (failure_type == vehicle_command_s::FAILURE_TYPE_OFF) {
|
||||
PX4_WARN("CMD_INJECT_FAILURE, baro off");
|
||||
supported = true;
|
||||
_baro_blocked = true;
|
||||
_baro_stuck = false;
|
||||
|
||||
} else if (failure_type == vehicle_command_s::FAILURE_TYPE_STUCK) {
|
||||
PX4_WARN("CMD_INJECT_FAILURE, baro stuck");
|
||||
supported = true;
|
||||
_baro_blocked = false;
|
||||
_baro_stuck = true;
|
||||
|
||||
} else if (failure_type == vehicle_command_s::FAILURE_TYPE_OK) {
|
||||
PX4_INFO("CMD_INJECT_FAILURE, baro ok");
|
||||
supported = true;
|
||||
_baro_blocked = false;
|
||||
_baro_stuck = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
vehicle_command_ack_s ack{};
|
||||
ack.command = vehicle_command.command;
|
||||
ack.from_external = false;
|
||||
ack.result = supported ?
|
||||
vehicle_command_ack_s::VEHICLE_CMD_RESULT_ACCEPTED :
|
||||
vehicle_command_ack_s::VEHICLE_CMD_RESULT_UNSUPPORTED;
|
||||
ack.timestamp = hrt_absolute_time();
|
||||
_command_ack_pub.publish(ack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SensorBaroSim::Run()
|
||||
{
|
||||
if (should_exit()) {
|
||||
@@ -105,6 +156,27 @@ void SensorBaroSim::Run()
|
||||
updateParams();
|
||||
}
|
||||
|
||||
check_failure_injections();
|
||||
|
||||
if (_baro_blocked) {
|
||||
perf_end(_loop_perf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_baro_stuck) {
|
||||
// Publish stuck (last known) values
|
||||
sensor_baro_s sensor_baro{};
|
||||
sensor_baro.timestamp_sample = hrt_absolute_time();
|
||||
sensor_baro.device_id = 6620172; // 6620172: DRV_BARO_DEVTYPE_BAROSIM, BUS: 1, ADDR: 4, TYPE: SIMULATION
|
||||
sensor_baro.pressure = _last_pressure;
|
||||
sensor_baro.temperature = _last_temperature;
|
||||
sensor_baro.timestamp = hrt_absolute_time();
|
||||
_sensor_baro_pub.publish(sensor_baro);
|
||||
|
||||
perf_end(_loop_perf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_vehicle_global_position_sub.updated()) {
|
||||
vehicle_global_position_s gpos;
|
||||
|
||||
@@ -161,6 +233,10 @@ void SensorBaroSim::Run()
|
||||
// calculate temperature in Celsius
|
||||
float temperature = temperature_local - 273.0f + _sim_baro_off_t.get();
|
||||
|
||||
// Store values for stuck mode
|
||||
_last_pressure = pressure;
|
||||
_last_temperature = temperature;
|
||||
|
||||
// publish
|
||||
sensor_baro_s sensor_baro{};
|
||||
sensor_baro.timestamp_sample = gpos.timestamp;
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
#include <uORB/SubscriptionInterval.hpp>
|
||||
#include <uORB/topics/parameter_update.h>
|
||||
#include <uORB/topics/sensor_baro.h>
|
||||
#include <uORB/topics/vehicle_command.h>
|
||||
#include <uORB/topics/vehicle_command_ack.h>
|
||||
#include <uORB/topics/vehicle_global_position.h>
|
||||
|
||||
using namespace time_literals;
|
||||
@@ -67,17 +69,25 @@ public:
|
||||
|
||||
private:
|
||||
void Run() override;
|
||||
void check_failure_injections();
|
||||
|
||||
// generate white Gaussian noise sample with std=1
|
||||
static float generate_wgn();
|
||||
|
||||
uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s};
|
||||
uORB::Subscription _vehicle_global_position_sub{ORB_ID(vehicle_global_position_groundtruth)};
|
||||
uORB::Subscription _vehicle_command_sub{ORB_ID(vehicle_command)};
|
||||
|
||||
uORB::Publication<vehicle_command_ack_s> _command_ack_pub{ORB_ID(vehicle_command_ack)};
|
||||
|
||||
bool _baro_blocked{false};
|
||||
bool _baro_stuck{false};
|
||||
bool _baro_rnd_use_last{false};
|
||||
double _baro_rnd_y2{0.0};
|
||||
float _baro_drift_pa_per_sec{0.0};
|
||||
float _baro_drift_pa{0.0};
|
||||
float _last_pressure{0.0f};
|
||||
float _last_temperature{0.0f};
|
||||
|
||||
hrt_abstime _last_update_time{0};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2021-2025 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
|
||||
@@ -87,6 +87,49 @@ float SensorGpsSim::generate_wgn()
|
||||
return X;
|
||||
}
|
||||
|
||||
void SensorGpsSim::check_failure_injections()
|
||||
{
|
||||
vehicle_command_s vehicle_command;
|
||||
|
||||
while (_vehicle_command_sub.update(&vehicle_command)) {
|
||||
if (vehicle_command.command != vehicle_command_s::VEHICLE_CMD_INJECT_FAILURE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
bool supported = false;
|
||||
|
||||
const int failure_unit = static_cast<int>(vehicle_command.param1 + 0.5f);
|
||||
const int failure_type = static_cast<int>(vehicle_command.param2 + 0.5f);
|
||||
|
||||
if (failure_unit == vehicle_command_s::FAILURE_UNIT_SENSOR_GPS) {
|
||||
handled = true;
|
||||
|
||||
if (failure_type == vehicle_command_s::FAILURE_TYPE_OFF) {
|
||||
PX4_WARN("CMD_INJECT_FAILURE, GPS off");
|
||||
supported = true;
|
||||
_gps_blocked = true;
|
||||
|
||||
} else if (failure_type == vehicle_command_s::FAILURE_TYPE_OK) {
|
||||
PX4_INFO("CMD_INJECT_FAILURE, GPS ok");
|
||||
supported = true;
|
||||
_gps_blocked = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
vehicle_command_ack_s ack{};
|
||||
ack.command = vehicle_command.command;
|
||||
ack.from_external = false;
|
||||
ack.result = supported ?
|
||||
vehicle_command_ack_s::VEHICLE_CMD_RESULT_ACCEPTED :
|
||||
vehicle_command_ack_s::VEHICLE_CMD_RESULT_UNSUPPORTED;
|
||||
ack.timestamp = hrt_absolute_time();
|
||||
_command_ack_pub.publish(ack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SensorGpsSim::Run()
|
||||
{
|
||||
if (should_exit()) {
|
||||
@@ -106,19 +149,26 @@ void SensorGpsSim::Run()
|
||||
updateParams();
|
||||
}
|
||||
|
||||
if (_vehicle_local_position_sub.updated() && _vehicle_global_position_sub.updated()) {
|
||||
check_failure_injections();
|
||||
|
||||
vehicle_local_position_s lpos{};
|
||||
_vehicle_local_position_sub.copy(&lpos);
|
||||
if (_gps_blocked) {
|
||||
perf_end(_loop_perf);
|
||||
return;
|
||||
}
|
||||
|
||||
vehicle_global_position_s gpos{};
|
||||
_vehicle_global_position_sub.copy(&gpos);
|
||||
if (_vehicle_local_position_groundtruth_sub.updated() && _vehicle_global_position_groundtruth_sub.updated()) {
|
||||
|
||||
double latitude = gpos.lat + math::degrees((double)generate_wgn() * 0.2 / CONSTANTS_RADIUS_OF_EARTH);
|
||||
double longitude = gpos.lon + math::degrees((double)generate_wgn() * 0.2 / CONSTANTS_RADIUS_OF_EARTH);
|
||||
double altitude = (double)(gpos.alt + (generate_wgn() * 0.5f));
|
||||
vehicle_local_position_s vehicle_local_position{};
|
||||
_vehicle_local_position_groundtruth_sub.copy(&vehicle_local_position);
|
||||
|
||||
Vector3f gps_vel = Vector3f{lpos.vx, lpos.vy, lpos.vz} + noiseGauss3f(0.06f, 0.077f, 0.158f);
|
||||
vehicle_global_position_s vehicle_global_position{};
|
||||
_vehicle_global_position_groundtruth_sub.copy(&vehicle_global_position);
|
||||
|
||||
double latitude = vehicle_global_position.lat + math::degrees((double)generate_wgn() * 0.2 / CONSTANTS_RADIUS_OF_EARTH);
|
||||
double longitude = vehicle_global_position.lon + math::degrees((double)generate_wgn() * 0.2 / CONSTANTS_RADIUS_OF_EARTH);
|
||||
double altitude = (double)(vehicle_global_position.alt + (generate_wgn() * 0.5f));
|
||||
|
||||
Vector3f gps_vel = Vector3f{vehicle_local_position.vx, vehicle_local_position.vy, vehicle_local_position.vz};// + noiseGauss3f(0.06f, 0.077f, 0.158f);
|
||||
|
||||
// device id
|
||||
device::Device::DeviceId device_id;
|
||||
@@ -150,7 +200,7 @@ void SensorGpsSim::Run()
|
||||
sensor_gps.vdop = 100.f;
|
||||
}
|
||||
|
||||
sensor_gps.timestamp_sample = gpos.timestamp_sample;
|
||||
sensor_gps.timestamp_sample = vehicle_global_position.timestamp_sample;
|
||||
sensor_gps.time_utc_usec = 0;
|
||||
sensor_gps.device_id = device_id.devid;
|
||||
sensor_gps.latitude_deg = latitude; // Latitude in degrees
|
||||
@@ -159,7 +209,7 @@ void SensorGpsSim::Run()
|
||||
sensor_gps.altitude_ellipsoid_m = altitude;
|
||||
sensor_gps.noise_per_ms = 0;
|
||||
sensor_gps.jamming_indicator = 0;
|
||||
sensor_gps.vel_m_s = sqrtf(gps_vel(0) * gps_vel(0) + gps_vel(1) * gps_vel(1)); // GPS ground speed, (metres/sec)
|
||||
sensor_gps.vel_m_s = Vector2f(gps_vel).length(); // GPS ground speed, (metres/sec)
|
||||
sensor_gps.vel_n_m_s = gps_vel(0);
|
||||
sensor_gps.vel_e_m_s = gps_vel(1);
|
||||
sensor_gps.vel_d_m_s = gps_vel(2);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2021-2025 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
|
||||
@@ -43,6 +43,8 @@
|
||||
#include <uORB/SubscriptionInterval.hpp>
|
||||
#include <uORB/topics/parameter_update.h>
|
||||
#include <uORB/topics/sensor_gps.h>
|
||||
#include <uORB/topics/vehicle_command.h>
|
||||
#include <uORB/topics/vehicle_command_ack.h>
|
||||
#include <uORB/topics/vehicle_global_position.h>
|
||||
#include <uORB/topics/vehicle_local_position.h>
|
||||
|
||||
@@ -67,6 +69,7 @@ public:
|
||||
|
||||
private:
|
||||
void Run() override;
|
||||
void check_failure_injections();
|
||||
|
||||
// generate white Gaussian noise sample with std=1
|
||||
static float generate_wgn();
|
||||
@@ -75,10 +78,14 @@ private:
|
||||
matrix::Vector3f noiseGauss3f(float stdx, float stdy, float stdz) { return matrix::Vector3f(generate_wgn() * stdx, generate_wgn() * stdy, generate_wgn() * stdz); }
|
||||
|
||||
uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s};
|
||||
uORB::Subscription _vehicle_global_position_sub{ORB_ID(vehicle_global_position_groundtruth)};
|
||||
uORB::Subscription _vehicle_local_position_sub{ORB_ID(vehicle_local_position_groundtruth)};
|
||||
uORB::Subscription _vehicle_global_position_groundtruth_sub{ORB_ID(vehicle_global_position_groundtruth)};
|
||||
uORB::Subscription _vehicle_local_position_groundtruth_sub{ORB_ID(vehicle_local_position_groundtruth)};
|
||||
uORB::Subscription _vehicle_command_sub{ORB_ID(vehicle_command)};
|
||||
|
||||
uORB::PublicationMulti<sensor_gps_s> _sensor_gps_pub{ORB_ID(sensor_gps)};
|
||||
uORB::Publication<vehicle_command_ack_s> _command_ack_pub{ORB_ID(vehicle_command_ack)};
|
||||
|
||||
bool _gps_blocked{false};
|
||||
|
||||
perf_counter_t _loop_perf{perf_alloc(PC_ELAPSED, MODULE_NAME": cycle")};
|
||||
|
||||
|
||||
@@ -87,6 +87,49 @@ float SensorMagSim::generate_wgn()
|
||||
return X;
|
||||
}
|
||||
|
||||
void SensorMagSim::check_failure_injections()
|
||||
{
|
||||
vehicle_command_s vehicle_command;
|
||||
|
||||
while (_vehicle_command_sub.update(&vehicle_command)) {
|
||||
if (vehicle_command.command != vehicle_command_s::VEHICLE_CMD_INJECT_FAILURE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
bool supported = false;
|
||||
|
||||
const int failure_unit = static_cast<int>(vehicle_command.param1 + 0.5f);
|
||||
const int failure_type = static_cast<int>(vehicle_command.param2 + 0.5f);
|
||||
|
||||
if (failure_unit == vehicle_command_s::FAILURE_UNIT_SENSOR_MAG) {
|
||||
handled = true;
|
||||
|
||||
if (failure_type == vehicle_command_s::FAILURE_TYPE_OFF) {
|
||||
PX4_WARN("CMD_INJECT_FAILURE, mag off");
|
||||
supported = true;
|
||||
_mag_blocked = true;
|
||||
|
||||
} else if (failure_type == vehicle_command_s::FAILURE_TYPE_OK) {
|
||||
PX4_INFO("CMD_INJECT_FAILURE, mag ok");
|
||||
supported = true;
|
||||
_mag_blocked = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
vehicle_command_ack_s ack{};
|
||||
ack.command = vehicle_command.command;
|
||||
ack.from_external = false;
|
||||
ack.result = supported ?
|
||||
vehicle_command_ack_s::VEHICLE_CMD_RESULT_ACCEPTED :
|
||||
vehicle_command_ack_s::VEHICLE_CMD_RESULT_UNSUPPORTED;
|
||||
ack.timestamp = hrt_absolute_time();
|
||||
_command_ack_pub.publish(ack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SensorMagSim::Run()
|
||||
{
|
||||
if (should_exit()) {
|
||||
@@ -106,6 +149,13 @@ void SensorMagSim::Run()
|
||||
updateParams();
|
||||
}
|
||||
|
||||
check_failure_injections();
|
||||
|
||||
if (_mag_blocked) {
|
||||
perf_end(_loop_perf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_vehicle_global_position_sub.updated()) {
|
||||
vehicle_global_position_s gpos;
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
#include <uORB/SubscriptionInterval.hpp>
|
||||
#include <uORB/topics/parameter_update.h>
|
||||
#include <uORB/topics/vehicle_attitude.h>
|
||||
#include <uORB/topics/vehicle_command.h>
|
||||
#include <uORB/topics/vehicle_command_ack.h>
|
||||
#include <uORB/topics/vehicle_global_position.h>
|
||||
|
||||
using namespace time_literals;
|
||||
@@ -67,6 +69,7 @@ public:
|
||||
|
||||
private:
|
||||
void Run() override;
|
||||
void check_failure_injections();
|
||||
|
||||
// generate white Gaussian noise sample with std=1
|
||||
static float generate_wgn();
|
||||
@@ -77,9 +80,14 @@ private:
|
||||
uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s};
|
||||
uORB::Subscription _vehicle_attitude_sub{ORB_ID(vehicle_attitude_groundtruth)};
|
||||
uORB::Subscription _vehicle_global_position_sub{ORB_ID(vehicle_global_position_groundtruth)};
|
||||
uORB::Subscription _vehicle_command_sub{ORB_ID(vehicle_command)};
|
||||
|
||||
uORB::Publication<vehicle_command_ack_s> _command_ack_pub{ORB_ID(vehicle_command_ack)};
|
||||
|
||||
PX4Magnetometer _px4_mag{197388, ROTATION_NONE}; // 197388: DRV_MAG_DEVTYPE_MAGSIM, BUS: 1, ADDR: 3, TYPE: SIMULATION
|
||||
|
||||
bool _mag_blocked{false};
|
||||
|
||||
bool _mag_earth_available{false};
|
||||
|
||||
matrix::Vector3f _mag_earth_pred{};
|
||||
|
||||
@@ -246,16 +246,17 @@ if(gazebo_FOUND)
|
||||
|
||||
add_custom_target(gazebo-classic DEPENDS gazebo-classic_iris) # alias
|
||||
add_custom_target(gazebo DEPENDS gazebo-classic_iris) # alias
|
||||
|
||||
# mavsdk tests currently depend on sitl_gazebo
|
||||
ExternalProject_Add(mavsdk_tests
|
||||
SOURCE_DIR ${PX4_SOURCE_DIR}/test/mavsdk_tests
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
|
||||
BINARY_DIR ${PX4_BINARY_DIR}/mavsdk_tests
|
||||
INSTALL_COMMAND ""
|
||||
USES_TERMINAL_CONFIGURE true
|
||||
USES_TERMINAL_BUILD true
|
||||
EXCLUDE_FROM_ALL true
|
||||
BUILD_ALWAYS 1
|
||||
)
|
||||
endif()
|
||||
|
||||
# mavsdk tests DO NOT depend on sitl_gazebo
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(mavsdk_tests
|
||||
SOURCE_DIR ${PX4_SOURCE_DIR}/test/mavsdk_tests
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
|
||||
BINARY_DIR ${PX4_BINARY_DIR}/mavsdk_tests
|
||||
INSTALL_COMMAND ""
|
||||
USES_TERMINAL_CONFIGURE true
|
||||
USES_TERMINAL_BUILD true
|
||||
EXCLUDE_FROM_ALL true
|
||||
BUILD_ALWAYS 1
|
||||
)
|
||||
|
||||
@@ -148,6 +148,22 @@ void Sih::lockstep_loop()
|
||||
|
||||
} else {
|
||||
px4_lockstep_wait_for_components();
|
||||
|
||||
// Wait for the control pipeline to produce new actuator outputs.
|
||||
// Without this, under CPU load the controllers may not run between
|
||||
// SIH iterations, causing stale actuator data and sluggish response.
|
||||
uint64_t wait_start_us = micros();
|
||||
constexpr uint64_t actuator_wait_timeout_us = 10'000'000; // 10s wall time
|
||||
|
||||
while (!_actuator_out_sub.updated() && !should_exit()) {
|
||||
if (micros() - wait_start_us > actuator_wait_timeout_us) {
|
||||
PX4_WARN("SIH lockstep: timed out waiting for actuator_outputs_sim");
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(100);
|
||||
}
|
||||
|
||||
current_wall_time_us = micros();
|
||||
sleep_time = math::max(0, rt_interval_us - (int)(current_wall_time_us - pre_compute_wall_time_us));
|
||||
}
|
||||
@@ -190,6 +206,91 @@ void Sih::realtime_loop()
|
||||
px4_sem_destroy(&_data_semaphore);
|
||||
}
|
||||
|
||||
void Sih::check_failure_injections()
|
||||
{
|
||||
vehicle_command_s vehicle_command;
|
||||
|
||||
while (_vehicle_command_sub.update(&vehicle_command)) {
|
||||
if (vehicle_command.command != vehicle_command_s::VEHICLE_CMD_INJECT_FAILURE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
bool supported = false;
|
||||
|
||||
const int failure_unit = static_cast<int>(vehicle_command.param1 + 0.5f);
|
||||
const int failure_type = static_cast<int>(vehicle_command.param2 + 0.5f);
|
||||
|
||||
if (failure_unit == vehicle_command_s::FAILURE_UNIT_SENSOR_AIRSPEED) {
|
||||
handled = true;
|
||||
|
||||
if (failure_type == vehicle_command_s::FAILURE_TYPE_OFF) {
|
||||
PX4_WARN("CMD_INJECT_FAILURE, airspeed off");
|
||||
supported = true;
|
||||
_airspeed_blocked = true;
|
||||
|
||||
} else if (failure_type == vehicle_command_s::FAILURE_TYPE_OK) {
|
||||
PX4_INFO("CMD_INJECT_FAILURE, airspeed ok");
|
||||
supported = true;
|
||||
_airspeed_blocked = false;
|
||||
}
|
||||
|
||||
} else if (failure_unit == vehicle_command_s::FAILURE_UNIT_SENSOR_DISTANCE_SENSOR) {
|
||||
handled = true;
|
||||
|
||||
if (failure_type == vehicle_command_s::FAILURE_TYPE_OFF) {
|
||||
PX4_WARN("CMD_INJECT_FAILURE, distance sensor off");
|
||||
supported = true;
|
||||
_distance_sensor_blocked = true;
|
||||
|
||||
} else if (failure_type == vehicle_command_s::FAILURE_TYPE_OK) {
|
||||
PX4_INFO("CMD_INJECT_FAILURE, distance sensor ok");
|
||||
supported = true;
|
||||
_distance_sensor_blocked = false;
|
||||
}
|
||||
|
||||
} else if (failure_unit == vehicle_command_s::FAILURE_UNIT_SENSOR_ACCEL) {
|
||||
handled = true;
|
||||
|
||||
if (failure_type == vehicle_command_s::FAILURE_TYPE_OFF) {
|
||||
PX4_WARN("CMD_INJECT_FAILURE, accel off");
|
||||
supported = true;
|
||||
_accel_blocked = true;
|
||||
|
||||
} else if (failure_type == vehicle_command_s::FAILURE_TYPE_OK) {
|
||||
PX4_INFO("CMD_INJECT_FAILURE, accel ok");
|
||||
supported = true;
|
||||
_accel_blocked = false;
|
||||
}
|
||||
|
||||
} else if (failure_unit == vehicle_command_s::FAILURE_UNIT_SENSOR_GYRO) {
|
||||
handled = true;
|
||||
|
||||
if (failure_type == vehicle_command_s::FAILURE_TYPE_OFF) {
|
||||
PX4_WARN("CMD_INJECT_FAILURE, gyro off");
|
||||
supported = true;
|
||||
_gyro_blocked = true;
|
||||
|
||||
} else if (failure_type == vehicle_command_s::FAILURE_TYPE_OK) {
|
||||
PX4_INFO("CMD_INJECT_FAILURE, gyro ok");
|
||||
supported = true;
|
||||
_gyro_blocked = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
vehicle_command_ack_s ack{};
|
||||
ack.command = vehicle_command.command;
|
||||
ack.from_external = false;
|
||||
ack.result = supported ?
|
||||
vehicle_command_ack_s::VEHICLE_CMD_RESULT_ACCEPTED :
|
||||
vehicle_command_ack_s::VEHICLE_CMD_RESULT_UNSUPPORTED;
|
||||
ack.timestamp = hrt_absolute_time();
|
||||
_command_ack_pub.publish(ack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sih::sensor_step()
|
||||
{
|
||||
// check for parameter updates
|
||||
@@ -203,6 +304,8 @@ void Sih::sensor_step()
|
||||
parameters_updated();
|
||||
}
|
||||
|
||||
check_failure_injections();
|
||||
|
||||
perf_begin(_loop_perf);
|
||||
|
||||
const hrt_abstime now = hrt_absolute_time();
|
||||
@@ -619,7 +722,7 @@ void Sih::reconstruct_sensors_signals(const hrt_abstime &time_now_us)
|
||||
Vector3f accel_noise;
|
||||
Vector3f gyro_noise;
|
||||
|
||||
if (_T_B.longerThan(FLT_EPSILON)) {
|
||||
if (false && _T_B.longerThan(FLT_EPSILON)) { // too much noise at least for the low update rate O.O
|
||||
accel_noise = noiseGauss3f(0.5f, 1.7f, 1.4f);
|
||||
gyro_noise = noiseGauss3f(0.14f, 0.07f, 0.03f);
|
||||
|
||||
@@ -636,12 +739,21 @@ void Sih::reconstruct_sensors_signals(const hrt_abstime &time_now_us)
|
||||
Vector3f gyro = _w_B + earth_spin_rate_B + gyro_noise;
|
||||
|
||||
// update IMU every iteration
|
||||
_px4_accel.update(time_now_us, accel(0), accel(1), accel(2));
|
||||
_px4_gyro.update(time_now_us, gyro(0), gyro(1), gyro(2));
|
||||
if (!_accel_blocked) {
|
||||
_px4_accel.update(time_now_us, accel(0), accel(1), accel(2));
|
||||
}
|
||||
|
||||
if (!_gyro_blocked) {
|
||||
_px4_gyro.update(time_now_us, gyro(0), gyro(1), gyro(2));
|
||||
}
|
||||
}
|
||||
|
||||
void Sih::send_airspeed(const hrt_abstime &time_now_us)
|
||||
{
|
||||
if (_airspeed_blocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: send differential pressure instead?
|
||||
airspeed_s airspeed{};
|
||||
airspeed.timestamp_sample = time_now_us;
|
||||
@@ -656,6 +768,10 @@ void Sih::send_airspeed(const hrt_abstime &time_now_us)
|
||||
|
||||
void Sih::send_dist_snsr(const hrt_abstime &time_now_us)
|
||||
{
|
||||
if (_distance_sensor_blocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
device::Device::DeviceId device_id;
|
||||
device_id.devid_s.bus_type = device::Device::DeviceBusType::DeviceBusType_SIMULATION;
|
||||
device_id.devid_s.bus = 0;
|
||||
|
||||
@@ -77,6 +77,8 @@
|
||||
#include <uORB/topics/distance_sensor.h>
|
||||
#include <uORB/topics/vehicle_angular_velocity.h>
|
||||
#include <uORB/topics/vehicle_attitude.h>
|
||||
#include <uORB/topics/vehicle_command.h>
|
||||
#include <uORB/topics/vehicle_command_ack.h>
|
||||
#include <uORB/topics/vehicle_global_position.h>
|
||||
#include <uORB/topics/vehicle_local_position.h>
|
||||
|
||||
@@ -117,6 +119,7 @@ public:
|
||||
|
||||
private:
|
||||
void parameters_updated();
|
||||
void check_failure_injections();
|
||||
|
||||
// simulated sensors
|
||||
PX4Accelerometer _px4_accel{1310988}; // 1310988: DRV_IMU_DEVTYPE_SIM, BUS: 1, ADDR: 1, TYPE: SIMULATION
|
||||
@@ -132,6 +135,14 @@ private:
|
||||
|
||||
uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s};
|
||||
uORB::Subscription _actuator_out_sub{ORB_ID(actuator_outputs)};
|
||||
uORB::Subscription _vehicle_command_sub{ORB_ID(vehicle_command)};
|
||||
|
||||
uORB::Publication<vehicle_command_ack_s> _command_ack_pub{ORB_ID(vehicle_command_ack)};
|
||||
|
||||
bool _airspeed_blocked{false};
|
||||
bool _distance_sensor_blocked{false};
|
||||
bool _accel_blocked{false};
|
||||
bool _gyro_blocked{false};
|
||||
|
||||
// hard constants
|
||||
static constexpr uint16_t NUM_ACTUATORS_MAX = 9;
|
||||
|
||||
@@ -212,7 +212,7 @@ PARAM_DEFINE_FLOAT(SIH_L_PITCH, 0.2f);
|
||||
* @increment 0.05
|
||||
* @group Simulation In Hardware
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(SIH_KDV, 1.0f);
|
||||
PARAM_DEFINE_FLOAT(SIH_KDV, 0.15f);
|
||||
|
||||
/**
|
||||
* First order angular damper coefficient
|
||||
|
||||
@@ -225,18 +225,10 @@ void AutopilotTester::wait_until_hovering()
|
||||
|
||||
void AutopilotTester::wait_until_altitude(float rel_altitude_m, std::chrono::seconds timeout, float delta)
|
||||
{
|
||||
auto prom = std::promise<void> {};
|
||||
auto fut = prom.get_future();
|
||||
|
||||
Telemetry::PositionHandle handle = _telemetry->subscribe_position([&prom, rel_altitude_m, delta, &handle,
|
||||
this](Telemetry::Position new_position) {
|
||||
if (fabs(rel_altitude_m - new_position.relative_altitude_m) <= delta) {
|
||||
_telemetry->unsubscribe_position(handle);
|
||||
prom.set_value();
|
||||
}
|
||||
});
|
||||
|
||||
REQUIRE(fut.wait_for(timeout) == std::future_status::ready);
|
||||
REQUIRE(poll_condition_with_timeout(
|
||||
[this, rel_altitude_m, delta]() {
|
||||
return fabs(rel_altitude_m + _telemetry->position_velocity_ned().position.down_m) <= delta;
|
||||
}, timeout));
|
||||
}
|
||||
|
||||
void AutopilotTester::wait_until_fixedwing(std::chrono::seconds timeout)
|
||||
@@ -441,7 +433,7 @@ void AutopilotTester::offboard_goto(const Offboard::PositionNedYaw &target, floa
|
||||
void AutopilotTester::check_mission_item_speed_above(int item_index, float min_speed_m_s)
|
||||
{
|
||||
|
||||
_telemetry->set_rate_velocity_ned(10);
|
||||
_telemetry->set_rate_velocity_ned(1);
|
||||
_telemetry->subscribe_velocity_ned([item_index, min_speed_m_s, this](Telemetry::VelocityNed velocity) {
|
||||
float horizontal = std::hypot(velocity.north_m_s, velocity.east_m_s);
|
||||
auto progress = _mission->mission_progress();
|
||||
@@ -640,16 +632,16 @@ void AutopilotTester::start_checking_altitude(const float max_deviation_m)
|
||||
std::array<float, 3> initial_position = get_current_position_ned();
|
||||
float target_altitude = initial_position[2];
|
||||
|
||||
_check_altitude_handle = _telemetry->subscribe_position([target_altitude, max_deviation_m,
|
||||
this](Telemetry::Position new_position) {
|
||||
const float current_deviation = fabs((-target_altitude) - new_position.relative_altitude_m);
|
||||
_check_altitude_handle = _telemetry->subscribe_position_velocity_ned([target_altitude, max_deviation_m,
|
||||
this](Telemetry::PositionVelocityNed new_position) {
|
||||
const float current_deviation = fabs(target_altitude - new_position.position.down_m);
|
||||
CHECK(current_deviation <= max_deviation_m);
|
||||
});
|
||||
}
|
||||
|
||||
void AutopilotTester::stop_checking_altitude()
|
||||
{
|
||||
_telemetry->unsubscribe_position(_check_altitude_handle);
|
||||
_telemetry->unsubscribe_position_velocity_ned(_check_altitude_handle);
|
||||
}
|
||||
|
||||
void AutopilotTester::check_tracks_mission_raw(float corridor_radius_m, bool reverse)
|
||||
@@ -871,22 +863,11 @@ bool AutopilotTester::ground_truth_horizontal_position_far_from(const Telemetry:
|
||||
|
||||
void AutopilotTester::start_and_wait_for_mission_sequence(int sequence_number)
|
||||
{
|
||||
auto prom = std::promise<void> {};
|
||||
auto fut = prom.get_future();
|
||||
|
||||
Mission::MissionProgressHandle handle = _mission->subscribe_mission_progress(
|
||||
[&prom, &handle, this, sequence_number](Mission::MissionProgress progress) {
|
||||
std::cout << time_str() << "Progress: " << progress.current << "/" << progress.total << std::endl;
|
||||
|
||||
if (progress.current >= sequence_number) {
|
||||
_mission->unsubscribe_mission_progress(handle);
|
||||
prom.set_value();
|
||||
}
|
||||
});
|
||||
|
||||
REQUIRE(_mission->start_mission() == Mission::Result::Success);
|
||||
|
||||
REQUIRE(fut.wait_for(std::chrono::seconds(60)) == std::future_status::ready);
|
||||
REQUIRE(poll_condition_with_timeout(
|
||||
[this, sequence_number]() {
|
||||
return _mission->mission_progress().current >= sequence_number;
|
||||
}, std::chrono::seconds(60)));
|
||||
}
|
||||
|
||||
void AutopilotTester::start_and_wait_for_mission_sequence_raw(int sequence_number)
|
||||
@@ -911,56 +892,29 @@ void AutopilotTester::start_and_wait_for_mission_sequence_raw(int sequence_numbe
|
||||
|
||||
void AutopilotTester::wait_for_flight_mode(Telemetry::FlightMode flight_mode, std::chrono::seconds timeout)
|
||||
{
|
||||
auto prom = std::promise<void> {};
|
||||
auto fut = prom.get_future();
|
||||
|
||||
Telemetry::FlightModeHandle handle = _telemetry->subscribe_flight_mode(
|
||||
[&prom, &handle, flight_mode, this](Telemetry::FlightMode new_flight_mode) {
|
||||
if (new_flight_mode == flight_mode) {
|
||||
_telemetry->unsubscribe_flight_mode(handle);
|
||||
prom.set_value();
|
||||
}
|
||||
});
|
||||
|
||||
REQUIRE(fut.wait_for(timeout) == std::future_status::ready);
|
||||
REQUIRE(poll_condition_with_timeout(
|
||||
[this, flight_mode]() {
|
||||
return _telemetry->flight_mode() == flight_mode;
|
||||
}, timeout));
|
||||
}
|
||||
|
||||
void AutopilotTester::wait_for_landed_state(Telemetry::LandedState landed_state, std::chrono::seconds timeout)
|
||||
{
|
||||
auto prom = std::promise<void> {};
|
||||
auto fut = prom.get_future();
|
||||
|
||||
Telemetry::LandedStateHandle handle = _telemetry->subscribe_landed_state(
|
||||
[&prom, &handle, landed_state, this](Telemetry::LandedState new_landed_state) {
|
||||
if (new_landed_state == landed_state) {
|
||||
_telemetry->unsubscribe_landed_state(handle);
|
||||
prom.set_value();
|
||||
}
|
||||
});
|
||||
|
||||
REQUIRE(fut.wait_for(timeout) == std::future_status::ready);
|
||||
REQUIRE(poll_condition_with_timeout(
|
||||
[this, landed_state]() {
|
||||
return _telemetry->landed_state() == landed_state;
|
||||
}, timeout));
|
||||
}
|
||||
|
||||
void AutopilotTester::wait_until_speed_lower_than(float speed, std::chrono::seconds timeout)
|
||||
{
|
||||
auto prom = std::promise<void> {};
|
||||
auto fut = prom.get_future();
|
||||
|
||||
Telemetry::PositionVelocityNedHandle handle = _telemetry->subscribe_position_velocity_ned(
|
||||
[&prom, &handle, speed, this](Telemetry::PositionVelocityNed position_velocity_ned) {
|
||||
std::array<float, 3> current_velocity;
|
||||
current_velocity[0] = position_velocity_ned.velocity.north_m_s;
|
||||
current_velocity[1] = position_velocity_ned.velocity.east_m_s;
|
||||
current_velocity[2] = position_velocity_ned.velocity.down_m_s;
|
||||
const float current_speed = norm(current_velocity);
|
||||
|
||||
if (current_speed <= speed) {
|
||||
_telemetry->unsubscribe_position_velocity_ned(handle);
|
||||
prom.set_value();
|
||||
}
|
||||
});
|
||||
|
||||
REQUIRE(fut.wait_for(timeout) == std::future_status::ready);
|
||||
REQUIRE(poll_condition_with_timeout(
|
||||
[this, speed]() {
|
||||
auto vel = _telemetry->position_velocity_ned().velocity;
|
||||
return std::sqrt(vel.north_m_s * vel.north_m_s +
|
||||
vel.east_m_s * vel.east_m_s +
|
||||
vel.down_m_s * vel.down_m_s) < speed;
|
||||
}, timeout));
|
||||
}
|
||||
|
||||
void AutopilotTester::wait_for_mission_finished(std::chrono::seconds timeout)
|
||||
|
||||
@@ -298,7 +298,7 @@ private:
|
||||
|
||||
Telemetry::GroundTruth _home{NAN, NAN, NAN};
|
||||
|
||||
mavsdk::Telemetry::PositionHandle _check_altitude_handle{};
|
||||
mavsdk::Telemetry::PositionVelocityNedHandle _check_altitude_handle{};
|
||||
|
||||
std::atomic<bool> _should_exit {false};
|
||||
std::thread _real_time_report_thread {};
|
||||
|
||||
+1
-5
@@ -1,18 +1,17 @@
|
||||
{
|
||||
"mode": "sitl",
|
||||
"simulator": "gazebo",
|
||||
"model_prefix": "gazebo-classic_",
|
||||
"mavlink_connection": "udpin://0.0.0.0:14540",
|
||||
"tests":
|
||||
[
|
||||
{
|
||||
"model": "iris",
|
||||
"vehicle": "iris",
|
||||
"test_filter": "[multicopter],[offboard],[offboard_attitude]",
|
||||
"timeout_min": 10
|
||||
},
|
||||
{
|
||||
"model": "iris",
|
||||
"vehicle": "iris",
|
||||
"test_filter": "[offboard_attitude]",
|
||||
"timeout_min": 10,
|
||||
"env": {
|
||||
@@ -22,19 +21,16 @@
|
||||
},
|
||||
{
|
||||
"model": "standard_vtol",
|
||||
"vehicle": "standard_vtol",
|
||||
"test_filter": "[vtol], [vtol_wind], [vtol_airspeed_fail]",
|
||||
"timeout_min": 10
|
||||
},
|
||||
{
|
||||
"model": "tailsitter",
|
||||
"vehicle": "tailsitter",
|
||||
"test_filter": "[vtol]",
|
||||
"timeout_min": 10
|
||||
},
|
||||
{
|
||||
"model": "typhoon_h480",
|
||||
"vehicle": "typhoon_h480",
|
||||
"test_filter": "[controlallocation]",
|
||||
"timeout_min": 10
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"mode": "sitl",
|
||||
"model_prefix": "sihsim_",
|
||||
"mavlink_connection": "udpin://0.0.0.0:14540",
|
||||
"tests":
|
||||
[
|
||||
{
|
||||
"model": "quadx",
|
||||
"test_filter": "[multicopter],[offboard],[offboard_attitude]",
|
||||
"timeout_min": 10
|
||||
},
|
||||
{
|
||||
"model": "quadx",
|
||||
"test_filter": "[offboard_attitude]",
|
||||
"timeout_min": 10,
|
||||
"env": {
|
||||
"PX4_PARAM_EKF2_EN": 0,
|
||||
"PX4_PARAM_ATT_EN": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "standard_vtol",
|
||||
"test_filter": "[vtol]",
|
||||
"timeout_min": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -168,7 +168,7 @@ class Px4Runner(Runner):
|
||||
os.path.join(workspace_dir, "test_data"),
|
||||
"-d"
|
||||
]
|
||||
self.env["PX4_SIM_MODEL"] = "gazebo-classic_" + self.model
|
||||
self.env["PX4_SIM_MODEL"] = model
|
||||
self.env["PX4_SIM_SPEED_FACTOR"] = str(speed_factor)
|
||||
self.debugger = debugger
|
||||
self.clear_rootfs()
|
||||
|
||||
@@ -302,7 +302,7 @@ class Tester:
|
||||
self.active_runners = []
|
||||
|
||||
if self.config['mode'] == 'sitl':
|
||||
if self.config['simulator'] == 'gazebo':
|
||||
if self.config.get('simulator') == 'gazebo':
|
||||
# Use RegEx to extract worldname.world from case name
|
||||
match = re.search(r'\((.*?\.world)\)', case)
|
||||
if match:
|
||||
@@ -313,7 +313,7 @@ class Tester:
|
||||
gzserver_runner = ph.GzserverRunner(
|
||||
os.getcwd(),
|
||||
log_dir,
|
||||
test['vehicle'],
|
||||
test['model'],
|
||||
case,
|
||||
self.get_max_speed_factor(test),
|
||||
self.verbose,
|
||||
@@ -324,7 +324,7 @@ class Tester:
|
||||
gzmodelspawn_runner = ph.GzmodelspawnRunner(
|
||||
os.getcwd(),
|
||||
log_dir,
|
||||
test['vehicle'],
|
||||
test['model'],
|
||||
case,
|
||||
self.verbose,
|
||||
self.build_dir)
|
||||
@@ -339,24 +339,23 @@ class Tester:
|
||||
self.verbose)
|
||||
self.active_runners.append(gzclient_runner)
|
||||
|
||||
# We must start the PX4 instance at the end, as starting
|
||||
# it in the beginning, then connecting Gazebo server freaks
|
||||
# out the PX4 (it needs to have data coming in when started),
|
||||
# and can lead to EKF to freak out, or the instance itself
|
||||
# to die unexpectedly.
|
||||
px4_runner = ph.Px4Runner(
|
||||
os.getcwd(),
|
||||
log_dir,
|
||||
test['model'],
|
||||
case,
|
||||
self.get_max_speed_factor(test),
|
||||
self.debugger,
|
||||
self.verbose,
|
||||
self.build_dir,
|
||||
self.tester_interface.rootfs_base_dirname())
|
||||
for env_key in test.get('env', []):
|
||||
px4_runner.env[env_key] = str(test['env'][env_key])
|
||||
self.active_runners.append(px4_runner)
|
||||
# Determine PX4_SIM_MODEL using model_prefix from config
|
||||
model_prefix = self.config.get('model_prefix', '')
|
||||
px4_model = model_prefix + test['model']
|
||||
|
||||
px4_runner = ph.Px4Runner(
|
||||
os.getcwd(),
|
||||
log_dir,
|
||||
px4_model,
|
||||
case,
|
||||
self.get_max_speed_factor(test),
|
||||
self.debugger,
|
||||
self.verbose,
|
||||
self.build_dir,
|
||||
self.tester_interface.rootfs_base_dirname())
|
||||
for env_key in test.get('env', []):
|
||||
px4_runner.env[env_key] = str(test['env'][env_key])
|
||||
self.active_runners.append(px4_runner)
|
||||
|
||||
self.active_runners.append(self.tester_interface.create_test_runner(
|
||||
os.getcwd(),
|
||||
|
||||
@@ -136,11 +136,9 @@ def is_everything_ready(config: Dict[str, str], build_dir: str) -> bool:
|
||||
result = False
|
||||
if not os.path.isfile(os.path.join(build_dir, 'bin/px4')):
|
||||
print("PX4 SITL is not built\n"
|
||||
"run `DONT_RUN=1 "
|
||||
"make px4_sitl gazebo mavsdk_tests` or "
|
||||
"`DONT_RUN=1 make px4_sitl_default gazebo mavsdk_tests`")
|
||||
"run `DONT_RUN=1 make px4_sitl_default mavsdk_tests`")
|
||||
result = False
|
||||
if config['simulator'] == 'gazebo':
|
||||
if config.get('simulator') == 'gazebo':
|
||||
if is_running('gzserver'):
|
||||
print("gzserver process already running\n"
|
||||
"run `killall gzserver` and try again")
|
||||
@@ -153,9 +151,7 @@ def is_everything_ready(config: Dict[str, str], build_dir: str) -> bool:
|
||||
if not os.path.isfile(os.path.join(build_dir,
|
||||
'mavsdk_tests/mavsdk_tests')):
|
||||
print("Test runner is not built\n"
|
||||
"run `DONT_RUN=1 "
|
||||
"make px4_sitl gazebo mavsdk_tests` or "
|
||||
"`DONT_RUN=1 make px4_sitl_default gazebo mavsdk_tests`")
|
||||
"run `DONT_RUN=1 make px4_sitl_default mavsdk_tests`")
|
||||
result = False
|
||||
|
||||
return result
|
||||
|
||||
@@ -40,8 +40,6 @@
|
||||
TEST_CASE("Takeoff and hold position", "[multicopter][vtol]")
|
||||
{
|
||||
const float takeoff_altitude = 10.f;
|
||||
const float altitude_tolerance = 0.2f;
|
||||
const int delay_seconds = 60.f;
|
||||
|
||||
AutopilotTester tester;
|
||||
tester.connect(connection_url);
|
||||
@@ -50,16 +48,20 @@ TEST_CASE("Takeoff and hold position", "[multicopter][vtol]")
|
||||
tester.set_takeoff_altitude(takeoff_altitude);
|
||||
tester.store_home();
|
||||
// The sleep here is necessary for the takeoff altitude to be applied properly
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
tester.sleep_for(std::chrono::seconds(1));
|
||||
|
||||
// Capture altitude before takeoff
|
||||
std::array<float, 3> initial_position = tester.get_current_position_ned();
|
||||
float ground_altitude = -initial_position[2];
|
||||
|
||||
// Takeoff
|
||||
tester.arm();
|
||||
tester.takeoff();
|
||||
tester.wait_until_hovering();
|
||||
tester.wait_until_altitude(takeoff_altitude, std::chrono::seconds(30), altitude_tolerance);
|
||||
tester.wait_until_altitude(ground_altitude + takeoff_altitude, std::chrono::seconds(15), 0.01f);
|
||||
|
||||
// Monitor altitude and fail if it exceeds the tolerance
|
||||
tester.start_checking_altitude(altitude_tolerance + 0.1);
|
||||
tester.start_checking_altitude(0.15);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(delay_seconds));
|
||||
tester.sleep_for(std::chrono::seconds(15));
|
||||
}
|
||||
|
||||
@@ -90,8 +90,9 @@ TEST_CASE("Fly straight Multicopter Mission", "[multicopter]")
|
||||
AutopilotTester::MissionOptions mission_options;
|
||||
mission_options.rtl_at_end = false;
|
||||
mission_options.fly_through = true;
|
||||
mission_options.leg_length_m = 40.0;
|
||||
tester.prepare_straight_mission(mission_options);
|
||||
tester.check_mission_item_speed_above(2, 4.0);
|
||||
tester.check_mission_item_speed_above(3, 4.0);
|
||||
tester.check_tracks_mission(5.f);
|
||||
tester.arm();
|
||||
tester.execute_mission();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"mode": "sitl",
|
||||
"simulator": "gazebo",
|
||||
"model_prefix": "gazebo-classic_",
|
||||
"tests":
|
||||
[
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user