Compare commits

..

4 Commits

Author SHA1 Message Date
Jacob Dahl 1af6f70d57 chore(tests): remove dead integration test utilities with zero references
- integrationtests/python_src/px4_it/util/manual_input.py: last meaningful change 2019, 0 refs
- integrationtests/python_src/px4_it/util/px4_test_helper.py: last meaningful change 2016, 0 refs
2026-03-18 01:11:10 -08:00
Jacob Dahl 47c8c53745 fix(lpe): remove stale comment referencing deleted fault_table.py 2026-03-18 01:11:03 -08:00
Jacob Dahl a3681de493 chore(ci): remove Jenkinsfile superseded by GitHub Actions
All Jenkinsfile functions are now covered by GitHub Actions:
- Metadata generation → docs-orchestrator.yml + metadata_sync.sh
- PX4-user_guide deploy → in-repo docs/ + docs-orchestrator.yml
- S3 upload → build_all_targets.yml artifacts job
- QGC metadata push → already broken (no metadata commits)
- uORB graphs → supported by metadata_sync.sh

Co-authored-by: mrpollo <317648+mrpollo@users.noreply.github.com>
2026-03-18 01:10:49 -08:00
Jacob Dahl e05eca20a4 chore(tools): remove dead scripts and files with zero references
Remove files that have zero references in the codebase and haven't been
meaningfully touched in years:

- Tools/stack_usage/avstack.pl: AVR stack checker (2017), wrong arch, 0 refs
- Tools/usb_serialload.py: USB serial load tester (2022), Python 2, 0 refs
- Tools/dist/vehicle_configs.xml: old vehicle configs (2015), deprecated mixer format, 0 refs
- Tools/models/sdp3x_pitot_model.py: SDP3x pitot model (2017), 0 refs
- Tools/Matlab/motors.m: MATLAB motor script (2015), 0 refs
- Tools/Matlab/plot_mag.m: MATLAB mag plotter (2015), 0 refs
- src/modules/local_position_estimator/fault_table.py: fault table gen (2018), LPE disabled, 0 refs
- integrationtests/python_src/px4_it/util/flight_path_assertion.py: old ROS1 util (2016), 0 refs
- integrationtests/python_src/px4_it/util/TODO.md: stale TODO (2016), 0 refs
- integrationtests/python_src/px4_it/dronekit/: DroneKit mission checker (2019), deprecated lib, 0 refs
- platforms/posix/src/px4/common/lockstep_scheduler/build-and-test.sh: standalone build (2019), replaced by CMake, 0 refs

Co-authored-by: dakejahl <37091262+dakejahl@users.noreply.github.com>
2026-03-18 01:10:42 -08:00
85 changed files with 1428 additions and 3876 deletions
+1
View File
@@ -150,6 +150,7 @@ Checks: '*,
-readability-convert-member-functions-to-static,
-readability-make-member-function-const,
-bugprone-implicit-widening-of-multiplication-result,
-bugprone-macro-parentheses,
-bugprone-multi-level-implicit-pointer-conversion,
-bugprone-signed-char-misuse,
-cppcoreguidelines-avoid-non-const-global-variables,
+1 -21
View File
@@ -16,13 +16,7 @@ git checkout -b mydescriptivebranchname
## Edit and build the code
The [developer guide](https://docs.px4.io/main/en/development/development.html) explains how to set up the development environment on Mac OS, Linux or Windows.
### Coding standards
All C/C++ code must follow the [PX4 coding style](https://docs.px4.io/main/en/contribute/code.html). Formatting is enforced by [astyle](http://astyle.sourceforge.net/) in CI (`make check_format`). Code quality checks run via [clang-tidy](https://clang.llvm.org/extra/clang-tidy/). Pull requests that fail either check will not be merged.
Python code is checked with [mypy](https://mypy-lang.org/) and [flake8](https://flake8.pycqa.org/).
The [developer guide](https://docs.px4.io/main/en/development/development.html) explains how to set up the development environment on Mac OS, Linux or Windows. Please take note of our [coding style](https://docs.px4.io/main/en/contribute/code.html) when editing files.
## Commit message convention
@@ -147,20 +141,6 @@ git push --force-with-lease
## Test your changes
PX4 is safety-critical software. All contributions must include adequate testing where practical:
- **New features** must include unit tests and/or integration tests that exercise the new functionality, where practical. Hardware-dependent changes that cannot be tested in SITL should include bench test or flight test evidence.
- **Bug fixes** must include a regression test where practical. When automated testing is not feasible (hardware-specific issues, race conditions, etc.), provide a link to a flight log demonstrating the fix and the reproduction steps for the original bug.
- **Reviewers** will verify that tests or test evidence exist before approving a pull request.
### Types of tests
| Test type | When to use | How to run |
|-----------|-------------|------------|
| **Unit tests** (gtest) | Module-level logic, math, parsing | `make tests` |
| **SITL integration tests** (MAVSDK) | Flight behavior, failsafes, missions | `test/mavsdk_tests/` |
| **Bench tests / flight logs** | Hardware-dependent changes | Upload logs to [Flight Review](https://logs.px4.io) |
Since we care about safety, we will regularly ask you for test results. Best is to do a test flight (or bench test where it applies) and upload the log file from it (on the microSD card in the logs directory) to Google Drive or Dropbox and share the link.
## Push your changes
Vendored
-268
View File
@@ -1,268 +0,0 @@
#!/usr/bin/env groovy
pipeline {
agent none
stages {
stage('Analysis') {
when {
anyOf {
branch 'main'
branch 'master' // should be removed, but in case there is something going on...
branch 'pr-jenkins' // for testing
}
}
parallel {
stage('Airframe') {
agent {
docker { image 'px4io/px4-dev-base-focal:2021-08-18' }
}
steps {
sh 'make distclean; git clean -ff -x -d .'
sh 'git fetch --all --tags'
sh 'make airframe_metadata'
dir('build/px4_sitl_default/docs') {
archiveArtifacts(artifacts: 'airframes.md, airframes.xml')
stash includes: 'airframes.md, airframes.xml', name: 'metadata_airframes'
}
}
post {
always {
sh 'make distclean; git clean -ff -x -d .'
}
}
}
stage('Parameter') {
agent {
docker { image 'px4io/px4-dev-base-focal:2021-08-18' }
}
steps {
sh 'make distclean; git clean -ff -x -d .'
sh 'git fetch --all --tags'
sh 'make parameters_metadata'
dir('build/px4_sitl_default/docs') {
archiveArtifacts(artifacts: 'parameters.md, parameters.xml, parameters.json.xz')
stash includes: 'parameters.md, parameters.xml, parameters.json.xz', name: 'metadata_parameters'
}
}
post {
always {
sh 'make distclean; git clean -ff -x -d .'
}
}
}
stage('Module') {
agent {
docker { image 'px4io/px4-dev-base-focal:2021-08-18' }
}
steps {
sh 'make distclean; git clean -ff -x -d .'
sh 'git fetch --all --tags'
sh 'make module_documentation'
dir('build/px4_sitl_default/docs') {
archiveArtifacts(artifacts: 'modules/*.md')
stash includes: 'modules/*.md', name: 'metadata_module_documentation'
}
}
post {
always {
sh 'make distclean; git clean -ff -x -d .'
}
}
}
stage('msg file docs') {
agent {
docker { image 'px4io/px4-dev-base-focal:2021-08-18' }
}
steps {
sh 'mkdir -p build/msg_docs; ./Tools/msg/generate_msg_docs.py -d build/msg_docs'
dir('build') {
archiveArtifacts(artifacts: 'msg_docs/*.md')
stash includes: 'msg_docs/*.md', name: 'msg_documentation'
}
}
post {
always {
sh 'make distclean; git clean -ff -x -d .'
}
}
}
stage('failsafe docs') {
agent {
docker { image 'px4io/px4-dev-nuttx-focal:2022-08-12' }
}
steps {
sh '''#!/bin/bash -l
echo $0;
git clone https://github.com/emscripten-core/emsdk.git _emscripten_sdk;
cd _emscripten_sdk;
git checkout 4.0.15;
./emsdk install latest;
./emsdk activate latest;
cd ..;
. ./_emscripten_sdk/emsdk_env.sh;
git fetch --all --tags;
make failsafe_web;
cd build/px4_sitl_default_failsafe_web;
mkdir -p failsafe_sim;
cp index.* parameters.json failsafe_sim;
'''
dir('build/px4_sitl_default_failsafe_web') {
archiveArtifacts(artifacts: 'failsafe_sim/*')
stash includes: 'failsafe_sim/*', name: 'failsafe_sim'
}
}
post {
always {
sh 'make distclean; git clean -ff -x -d .'
}
}
}
stage('uORB graphs') {
agent {
docker {
image 'px4io/px4-dev-nuttx-focal:2022-08-12'
args '-e CCACHE_BASEDIR=$WORKSPACE -v ${CCACHE_DIR}:${CCACHE_DIR}:rw'
}
}
steps {
sh 'export'
sh 'make distclean; git clean -ff -x -d .'
sh 'git fetch --all --tags'
sh 'make uorb_graphs'
dir('Tools/uorb_graph') {
archiveArtifacts(artifacts: 'graph_*.json')
stash includes: 'graph_*.json', name: 'uorb_graph'
}
}
post {
always {
sh 'make distclean; git clean -ff -x -d .'
}
}
}
} // parallel
} // stage: Generate Metadata
stage('Deploy') {
parallel {
stage('Userguide') {
agent {
docker { image 'px4io/px4-dev-base-focal:2021-08-18' }
}
steps {
sh('export')
unstash 'metadata_airframes'
unstash 'metadata_parameters'
unstash 'metadata_module_documentation'
unstash 'msg_documentation'
unstash 'failsafe_sim'
unstash 'uorb_graph'
withCredentials([usernamePassword(credentialsId: 'px4buildbot_github_personal_token', passwordVariable: 'GIT_PASS', usernameVariable: 'GIT_USER')]) {
sh('git clone https://${GIT_USER}:${GIT_PASS}@github.com/PX4/PX4-user_guide.git')
sh('cp airframes.md PX4-user_guide/en/airframes/airframe_reference.md')
sh('cp parameters.md PX4-user_guide/en/advanced_config/parameter_reference.md')
sh('cp -R modules/*.md PX4-user_guide/en/modules/')
sh('cp -R graph_*.json PX4-user_guide/public/middleware/') // vitepress
sh('cp -R msg_docs/*.md PX4-user_guide/en/msg_docs/')
sh('cp -R failsafe_sim/* PX4-user_guide/public/config/failsafe') // vitepress
sh('cd PX4-user_guide; git status; git add .; git commit -a -m "Update PX4 Firmware metadata `date`" || true')
sh('cd PX4-user_guide; git push origin main || true')
sh('rm -rf PX4-user_guide')
}
}
when {
anyOf {
branch 'main'
branch 'master' // should be removed, but in case there is something going on...
branch 'pr-jenkins' // for testing
}
}
options {
skipDefaultCheckout()
}
}
stage('QGroundControl') {
agent {
docker { image 'px4io/px4-dev-base-focal:2021-08-18' }
}
steps {
sh('export')
unstash 'metadata_airframes'
unstash 'metadata_parameters'
withCredentials([usernamePassword(credentialsId: 'px4buildbot_github_personal_token', passwordVariable: 'GIT_PASS', usernameVariable: 'GIT_USER')]) {
sh('git clone https://${GIT_USER}:${GIT_PASS}@github.com/mavlink/qgroundcontrol.git')
sh('cp airframes.xml qgroundcontrol/src/AutoPilotPlugins/PX4/AirframeFactMetaData.xml')
sh('cp parameters.xml qgroundcontrol/src/FirmwarePlugin/PX4/PX4ParameterFactMetaData.xml')
sh('cd qgroundcontrol; git status; git add .; git commit -a -m "Update PX4 Firmware metadata `date`" || true')
sh('cd qgroundcontrol; git push origin master || true')
sh('rm -rf qgroundcontrol')
}
}
when {
anyOf {
branch 'main'
branch 'master' // should be removed, but in case there is something going on...
branch 'pr-jenkins' // for testing
}
}
options {
skipDefaultCheckout()
}
}
stage('S3') {
agent {
docker { image 'px4io/px4-dev-base-focal:2021-08-18' }
}
steps {
sh('export')
unstash 'metadata_airframes'
unstash 'metadata_parameters'
sh('ls')
withAWS(credentials: 'px4_aws_s3_key', region: 'us-east-1') {
s3Upload(acl: 'PublicRead', bucket: 'px4-travis', file: 'airframes.xml', path: 'Firmware/master/')
s3Upload(acl: 'PublicRead', bucket: 'px4-travis', file: 'parameters.xml', path: 'Firmware/master/')
s3Upload(acl: 'PublicRead', bucket: 'px4-travis', file: 'parameters.json.xz', path: 'Firmware/master/')
}
}
when {
anyOf {
branch 'main'
branch 'master' // should be removed, but in case there is something going on...
branch 'pr-jenkins' // for testing
}
}
options {
skipDefaultCheckout()
}
}
} // parallel
} // stage: Generate Metadata
} // stages
environment {
CCACHE_DIR = '/tmp/ccache'
CI = true
GIT_AUTHOR_EMAIL = "bot@px4.io"
GIT_AUTHOR_NAME = "PX4BuildBot"
GIT_COMMITTER_EMAIL = "bot@px4.io"
GIT_COMMITTER_NAME = "PX4BuildBot"
}
options {
buildDiscarder(logRotator(numToKeepStr: '20', artifactDaysToKeepStr: '30'))
timeout(time: 90, unit: 'MINUTES')
}
}
@@ -44,6 +44,8 @@ param set-default FW_T_SINK_MIN 3
param set-default FW_W_EN 1
param set-default FD_ESCS_EN 0
param set-default MIS_TAKEOFF_ALT 30
param set-default NAV_ACC_RAD 15
@@ -104,3 +104,4 @@ param set-default VT_FWD_THRUST_EN 4
param set-default VT_PITCH_MIN -5
param set-default VT_F_TRANS_THR 1
param set-default VT_TYPE 2
param set-default FD_ESCS_EN 0
@@ -26,6 +26,7 @@ param set-default SENS_EN_GPSSIM 1
param set-default SENS_EN_BAROSIM 1
param set-default SENS_EN_MAGSIM 1
param set-default COM_ARM_CHK_ESCS 0 # We don't have ESCs
param set-default FD_ESCS_EN 0 # We don't have ESCs - but maybe we need this later?
# Set proper failsafes
param set-default COM_ACT_FAIL_ACT 0
@@ -28,6 +28,7 @@ param set-default SIM_GZ_EN 1
param set-default SENS_EN_MAGSIM 1
param set-default COM_ARM_CHK_ESCS 0 # We don't have ESCs
param set-default FD_ESCS_EN 0
param set-default CA_AIRFRAME 14
param set-default MAV_TYPE 45
@@ -28,6 +28,7 @@ param set-default SIM_GZ_EN 1
param set-default SENS_EN_MAGSIM 1
param set-default COM_ARM_CHK_ESCS 0 # We don't have ESCs
param set-default FD_ESCS_EN 0
param set-default CA_AIRFRAME 14
param set-default MAV_TYPE 45
+12 -28
View File
@@ -2,40 +2,24 @@
## Supported Versions
The following versions receive security updates:
The following is a list of versions the development team is currently supporting.
| Version | Supported |
| ------- | ------------------ |
| 1.16.x | :white_check_mark: |
| < 1.16 | :x: |
| 1.4.x | :white_check_mark: |
| 1.3.3 | :white_check_mark: |
| < 1.3 | :x: |
## Reporting a Vulnerability
We receive security vulnerability reports through GitHub Security Advisories.
We currently only receive security vulnerability reports through GitHub.
To begin a report, go to the [PX4/PX4-Autopilot](https://github.com/PX4/PX4-Autopilot) repository
and click on the **Security** tab. If you are on mobile, click the **...** dropdown menu, then click **Security**.
To begin a report, please go to the top-level repository, for example, PX4/PX4-Autopilot,
and click on the Security tab. If you are on mobile, click the ... dropdown menu, and then click Security.
Click **Report a Vulnerability** to open the advisory form. Fill in the advisory details form.
Make sure your title is descriptive and the description contains all relevant details needed
to verify the issue. We welcome logs, screenshots, photos, and videos.
Click Report a Vulnerability to open the advisory form. Fill in the advisory details form.
Make sure your title is descriptive, and the development team can find all of the relevant details needed
to verify on the description box. We recommend you add as much data as possible. We welcome logs,
screenshots, photos, and videos, anything that can help us verify and identify the issues being reported.
At the bottom of the form, click **Submit report**.
## Response Process
1. **Acknowledgment**: The maintainer team will acknowledge your report within **7 days**.
2. **Triage**: We will assess severity and impact and communicate next steps.
3. **Disclosure**: We coordinate disclosure with the reporter. We follow responsible disclosure practices and will credit reporters in the advisory unless they request anonymity.
If you do not receive acknowledgment within 7 days, please follow up by emailing the [release managers](MAINTAINERS.md).
## Secure Development Practices
The PX4 development team applies the following practices to reduce security risk:
- **Code review**: All changes require peer review before merging.
- **Static analysis**: [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) runs on every pull request with warnings treated as errors.
- **Fuzzing**: A daily fuzzing pipeline using [Google fuzztest](https://github.com/google/fuzztest) tests MAVLink message handling and GNSS driver protocol parsing.
- **Input validation**: All external inputs (MAVLink messages, RC signals, sensor data) are validated against expected ranges before use.
- **Compiler hardening**: Builds use `-Wall -Werror`, stack protectors, and other hardening flags where supported by the target platform.
At the bottom of the form, click Submit report. The maintainer team will be notified and will get back to you ASAP.
-58
View File
@@ -1,58 +0,0 @@
clear all;
close all;
% Measurement data
% 1045 propeller
% Robbe Roxxy Motor (1100 kV, data collected in 2010)
data = [ 45, 7.4;...
38, 5.6;...
33, 4.3;...
26, 3.0;...
18, 2.0;...
10, 1.0 ];
% Normalize the data, as we're operating later
% anyways in normalized units
data(:,1) = data(:,1) ./ max(data(:,1));
data(:,2) = data(:,2) ./ max(data(:,2));
% Fit a 2nd degree polygon to the data and
% print the x2, x1, x0 coefficients
p = polyfit(data(:,2), data(:,1),2)
% Override the first coffefficient for testing
% purposes
pf = 0.62;
% Generate plotting data
px1 = linspace(0, max(data(:,2)));
py1 = polyval(p, px1);
pyt = zeros(size(data, 1), 1);
corr = zeros(size(data, 1), 1);
% Actual code test
% the two lines below are the ones needed to be ported to C:
% pf: Power factor parameter.
% px1(i): The current normalized motor command (-1..1)
% corr(i): The required correction. The motor speed is:
% px1(i)
for i=1:size(px1, 2)
% The actual output throttle
pyt(i) = -pf * (px1(i) * px1(i)) + (1 + pf) * px1(i);
% Solve for input throttle
% y = -p * x^2 + (1+p) * x;
%
end
plot(data(:,2), data(:,1), '*r');
hold on;
plot(px1, py1, '*b');
hold on;
plot([0 px1(end)], [0 py1(end)], '-k');
hold on;
plot(px1, pyt, '-b');
hold on;
plot(px1, corr, '-m');
-77
View File
@@ -1,77 +0,0 @@
%
% Tool for plotting mag data
%
% Reference values:
% telem> [cal] mag #0 off: x:0.15 y:0.07 z:0.14 Ga
% MATLAB: x:0.1581 y: 0.0701 z: 0.1439 Ga
% telem> [cal] mag #0 scale: x:1.10 y:0.97 z:1.02
% MATLAB: 0.5499, 0.5190, 0.4907
%
% telem> [cal] mag #1 off: x:-0.18 y:0.11 z:-0.09 Ga
% MATLAB: x:-0.1827 y:0.1147 z:-0.0848 Ga
% telem> [cal] mag #1 scale: x:1.00 y:1.00 z:1.00
% MATLAB: 0.5122, 0.5065, 0.4915
%
%
% User-guided values:
%
% telem> [cal] mag #0 off: x:0.12 y:0.09 z:0.14 Ga
% telem> [cal] mag #0 scale: x:0.88 y:0.99 z:0.95
% telem> [cal] mag #1 off: x:-0.18 y:0.11 z:-0.09 Ga
% telem> [cal] mag #1 scale: x:1.00 y:1.00 z:1.00
close all;
clear all;
plot_scale = 0.8;
xmax = plot_scale;
xmin = -xmax;
ymax = plot_scale;
ymin = -ymax;
zmax = plot_scale;
zmin = -zmax;
mag0_raw = load('../../mag0_raw3.csv');
mag1_raw = load('../../mag1_raw3.csv');
mag0_cal = load('../../mag0_cal3.csv');
mag1_cal = load('../../mag1_cal3.csv');
fm0r = figure();
mag0_x_scale = 0.88;
mag0_y_scale = 0.99;
mag0_z_scale = 0.95;
plot3(mag0_raw(:,1), mag0_raw(:,2), mag0_raw(:,3), '*r');
[mag0_raw_center, mag0_raw_radii, evecs, pars ] = ellipsoid_fit( [mag0_raw(:,1) mag0_raw(:,2) mag0_raw(:,3)] );
mag0_raw_center
mag0_raw_radii
axis([xmin xmax ymin ymax zmin zmax])
viscircles([mag0_raw_center(1), mag0_raw_center(2)], [mag0_raw_radii(1)]);
fm1r = figure();
plot3(mag1_raw(:,1), mag1_raw(:,2), mag1_raw(:,3), '*r');
[center, radii, evecs, pars ] = ellipsoid_fit( [mag1_raw(:,1) mag1_raw(:,2) mag1_raw(:,3)] );
center
radii
axis([xmin xmax ymin ymax zmin zmax])
fm0c = figure();
plot3(mag0_cal(:,1) .* mag0_x_scale, mag0_cal(:,2) .* mag0_y_scale, mag0_cal(:,3) .* mag0_z_scale, '*b');
[mag0_cal_center, mag0_cal_radii, evecs, pars ] = ellipsoid_fit( [mag1_raw(:,1) .* mag0_x_scale mag1_raw(:,2) .* mag0_y_scale mag1_raw(:,3) .* mag0_z_scale] );
mag0_cal_center
mag0_cal_radii
axis([xmin xmax ymin ymax zmin zmax])
viscircles([0, 0], [mag0_cal_radii(3)]);
fm1c = figure();
plot3(mag1_cal(:,1), mag1_cal(:,2), mag1_cal(:,3), '*b');
axis([xmin xmax ymin ymax zmin zmax])
[center, radii, evecs, pars ] = ellipsoid_fit( [mag1_raw(:,1) mag1_raw(:,2) mag1_raw(:,3)] );
viscircles([0, 0], [radii(3)]);
mag0_x_scale_matlab = 1 / (mag0_cal_radii(1) / mag0_raw_radii(1))
mag0_y_scale_matlab = 1 / (mag0_cal_radii(2) / mag0_raw_radii(2))
mag0_z_scale_matlab = 1 / (mag0_cal_radii(3) / mag0_raw_radii(3))
-23
View File
@@ -1,23 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<vehicle_configs>
<vehicle class="multirotor" rotors="4" geometry="x" propeller_diameter="8" weight="1.0" id="4010">
<title>Standard 8" Prop Quadrotor (x)</title>
<short_desc>Standard quadrotor configuration in x configuration for 8-" propellers</short_desc>
<mixer>/etc/mixers/quad_x.main.mix</mixer>
</vehicle>
<vehicle class="multirotor" rotors="4" geometry="+" propeller_diameter="8" weight="1.0" id="5001">
<title>Standard 8" Prop Quadrotor (+)</title>
<short_desc>Standard quadrotor configuration in + configuration for 8-" propellers</short_desc>
<mixer>/etc/mixers/quad_+.main.mix</mixer>
</vehicle>
<vehicle class="multirotor" rotors="4" geometry="x" propeller_diameter="10" weight="1.5" id="4011">
<title>Standard 8" Prop Quadrotor (x)</title>
<short_desc>Standard quadrotor configuration in x configuration for 8-" propellers</short_desc>
<mixer>/etc/mixers/quad_x.main.mix</mixer>
</vehicle>
<vehicle class="fixed_wing" wingspan="0.85" elevons="yes" ailerons="no" rudder="no" weight="1.5" id="3033">
<title>Zeta Science Wing Wing Z-84</title>
<short_desc>Configuration for a small flying wing.</short_desc>
<mixer>/etc/mixers/wingwing.main.mix</mixer>
</vehicle>
</vehicle_configs>
-110
View File
@@ -1,110 +0,0 @@
"""
Copyright (c) 2017, Sensirion AG
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Sensirion AG nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
# formula for metal pitot tube with round tip as here: https://drotek.com/shop/2986-large_default/sdp3x-airspeed-sensor-kit-sdp31.jpg
# and tubing as provided by px4/drotek (1.5 mm diameter)
import numpy as np
import matplotlib.pyplot as plt
P_cal=96600. #Pa
P_amb=96600. #dummy-value, use absolute pressure sensor!!
## differential pressure, sensor values in Pascal
dp_SDP33_raw=np.linspace(0,80,100)
dp_SDP33=dp_SDP33_raw*P_cal/P_amb
## total length tube in mm = length dynamic port+ length static port; compensation only valid for inner diameter of 1.5mm
l_tube=450
## densitiy air in kg/m3
rho_air=1.29
## flow through sensor
flow_SDP33=(300.805 - 300.878/(0.00344205*dp_SDP33**0.68698 + 1))*1.29/rho_air
## additional dp through pitot tube
dp_Pitot=(0.0032*flow_SDP33**2 + 0.0123*flow_SDP33+1.)*1.29/rho_air
## pressure drop through tube
dp_Tube=(flow_SDP33*0.674)/450*l_tube*rho_air/1.29
## speed at pitot-tube tip due to flow through sensor
dv=0.125*flow_SDP33
## sum of all pressure drops
dp_tot=dp_SDP33+dp_Tube+dp_Pitot
## computed airspeed without correction for inflow-speed at tip of pitot-tube
airspeed_uncorrected=np.sqrt(2*dp_tot/rho_air)
## corrected airspeed
airspeed_corrected=airspeed_uncorrected+dv
## just to compare to value without compensation
airspeed_raw=np.sqrt(2*dp_SDP33/rho_air)
plt.figure()
plt.plot(dp_SDP33,airspeed_corrected)
plt.xlabel('differential pressure raw value [Pa]')
plt.ylabel('airspeed_corrected [m/s]')
plt.show()
##plt.figure()
##plt.plot(dp_SDP33,airspeed_corrected/airspeed_raw)
##plt.xlabel('differential pressure raw value [Pa]')
##plt.ylabel('correction factor [-]')
##plt.show()
##
##
##
##plt.figure()
##plt.plot(airspeed_corrected,(airspeed_corrected-airspeed_raw)/airspeed_corrected)
##plt.xlabel('airspeed [m/s]')
##plt.ylabel('relative error [-]')
##plt.show()
-251
View File
@@ -1,251 +0,0 @@
#!/usr/bin/perl -w
# avstack.pl: AVR stack checker
# Copyright (C) 2013 Daniel Beer <dlbeer@gmail.com>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all
# copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
# Usage
# -----
#
# This script requires that you compile your code with -fstack-usage.
# This results in GCC generating a .su file for each .o file. Once you
# have these, do:
#
# ./avstack.pl <object files>
#
# This will disassemble .o files to construct a call graph, and read
# frame size information from .su. The call graph is traced to find, for
# each function:
#
# - Call height: the maximum call height of any callee, plus 1
# (defined to be 1 for any function which has no callees).
#
# - Inherited frame: the maximum *inherited* frame of any callee, plus
# the GCC-calculated frame size of the function in question.
#
# Using these two pieces of information, we calculate a cost (estimated
# peak stack usage) for calling the function. Functions are then listed
# on stdout in decreasing order of cost.
#
# Functions which are recursive are marked with an 'R' to the left of
# them. Their cost is calculated for a single level of recursion.
#
# The peak stack usage of your entire program can usually be estimated
# as the stack cost of "main", plus the maximum stack cost of any
# interrupt handler which might execute.
use strict;
# Configuration: set these as appropriate for your architecture/project.
my $objdump = "arm-none-eabi-objdump";
my $call_cost = 4;
# First, we need to read all object and corresponding .su files. We're
# gathering a mapping of functions to callees and functions to frame
# sizes. We're just parsing at this stage -- callee name resolution
# comes later.
my %frame_size; # "func@file" -> size
my %call_graph; # "func@file" -> {callees}
my %addresses; # "addr@file" -> "func@file"
my %global_name; # "func" -> "func@file"
my %ambiguous; # "func" -> 1
foreach (@ARGV) {
# Disassemble this object file to obtain a callees. Sources in the
# call graph are named "func@file". Targets in the call graph are
# named either "offset@file" or "funcname". We also keep a list of
# the addresses and names of each function we encounter.
my $objfile = $_;
my $source;
open(DISASSEMBLY, "$objdump -dr $objfile|") ||
die "Can't disassemble $objfile";
while (<DISASSEMBLY>) {
chomp;
if (/^([0-9a-fA-F]+) <(.*)>:/) {
my $a = $1;
my $name = $2;
$source = "$name\@$objfile";
$call_graph{$source} = {};
$ambiguous{$name} = 1 if defined($global_name{$name});
$global_name{$name} = "$name\@$objfile";
$a =~ s/^0*//;
$addresses{"$a\@$objfile"} = "$name\@$objfile";
}
if (/: R_[A-Za-z0-9_]+_CALL[ \t]+(.*)/) {
my $t = $1;
if ($t eq ".text") {
$t = "\@$objfile";
} elsif ($t =~ /^\.text\+0x(.*)$/) {
$t = "$1\@$objfile";
}
$call_graph{$source}->{$t} = 1;
}
}
close(DISASSEMBLY);
# Extract frame sizes from the corresponding .su file.
if ($objfile =~ /^(.*).obj$/) {
my $sufile = "$1.su";
open(SUFILE, "<$sufile") || die "Can't open $sufile";
while (<SUFILE>) {
$frame_size{"$1\@$objfile"} = $2 + $call_cost
if /^.*:([^\t ]+)[ \t]+([0-9]+)/;
}
close(SUFILE);
}
}
# In this step, we enumerate each list of callees in the call graph and
# try to resolve the symbols. We omit ones we can't resolve, but keep a
# set of them anyway.
my %unresolved;
foreach (keys %call_graph) {
my $from = $_;
my $callees = $call_graph{$from};
my %resolved;
foreach (keys %$callees) {
my $t = $_;
if (defined($addresses{$t})) {
$resolved{$addresses{$t}} = 1;
} elsif (defined($global_name{$t})) {
$resolved{$global_name{$t}} = 1;
warn "Ambiguous resolution: $t" if defined ($ambiguous{$t});
} elsif (defined($call_graph{$t})) {
$resolved{$t} = 1;
} else {
$unresolved{$t} = 1;
}
}
$call_graph{$from} = \%resolved;
}
# Create fake edges and nodes to account for dynamic behaviour.
$call_graph{"INTERRUPT"} = {};
foreach (keys %call_graph) {
$call_graph{"INTERRUPT"}->{$_} = 1 if /^__vector_/;
}
# Trace the call graph and calculate, for each function:
#
# - inherited frames: maximum inherited frame of callees, plus own
# frame size.
# - height: maximum height of callees, plus one.
# - recursion: is the function called recursively (including indirect
# recursion)?
my %has_caller;
my %visited;
my %total_cost;
my %call_depth;
sub trace {
my $f = shift;
if ($visited{$f}) {
$visited{$f} = "R" if $visited{$f} eq "?";
return;
}
$visited{$f} = "?";
my $max_depth = 0;
my $max_frame = 0;
my $targets = $call_graph{$f} || die "Unknown function: $f";
if (defined($targets)) {
foreach (keys %$targets) {
my $t = $_;
$has_caller{$t} = 1;
trace($t);
my $is = $total_cost{$t};
my $d = $call_depth{$t};
$max_frame = $is if $is > $max_frame;
$max_depth = $d if $d > $max_depth;
}
}
$call_depth{$f} = $max_depth + 1;
$total_cost{$f} = $max_frame + ($frame_size{$f} || 0);
$visited{$f} = " " if $visited{$f} eq "?";
}
foreach (keys %call_graph) { trace $_; }
# Now, print results in a nice table.
printf " %-30s %8s %8s %8s\n",
"Func", "Cost", "Frame", "Height";
print "------------------------------------";
print "------------------------------------\n";
my $max_iv = 0;
my $main = 0;
foreach (sort { $total_cost{$b} <=> $total_cost{$a} } keys %visited) {
my $name = $_;
if (/^(.*)@(.*)$/) {
$name = $1 unless $ambiguous{$name};
}
my $tag = $visited{$_};
my $cost = $total_cost{$_};
$name = $_ if $ambiguous{$name};
$tag = ">" unless $has_caller{$_};
if (/^__vector_/) {
$max_iv = $cost if $cost > $max_iv;
} elsif (/^main@/) {
$main = $cost;
}
if ($ambiguous{$name}) { $name = $_; }
printf "%s %-30s %8d %8d %8d\n", $tag, $name, $cost,
$frame_size{$_} || 0, $call_depth{$_};
}
print "\n";
print "Peak execution estimate (main + worst-case IV):\n";
printf " main = %d, worst IV = %d, total = %d\n",
$total_cost{$global_name{"main"}},
$total_cost{"INTERRUPT"},
$total_cost{$global_name{"main"}} + $total_cost{"INTERRUPT"};
print "\n";
print "The following functions were not resolved:\n";
foreach (keys %unresolved) { print " $_\n"; }
-55
View File
@@ -1,55 +0,0 @@
import serial, time
port = serial.Serial('/dev/ttyACM0', baudrate=57600, timeout=2)
data = '01234567890123456789012345678901234567890123456789'
#data = 'hellohello'
outLine = 'echo %s\n' % data
port.write('\n\n\n')
port.write('free\n')
line = port.readline(80)
while line != '':
print(line)
line = port.readline(80)
i = 0
bytesOut = 0
bytesIn = 0
startTime = time.time()
lastPrint = startTime
while True:
bytesOut += port.write(outLine)
line = port.readline(80)
bytesIn += len(line)
# check command line echo
if (data not in line):
print('command error %d: %s' % (i,line))
#break
# read echo output
line = port.readline(80)
if (data not in line):
print('echo output error %d: %s' % (i,line))
#break
bytesIn += len(line)
#print('%d: %s' % (i,line))
#print('%d: bytesOut: %d, bytesIn: %d' % (i, bytesOut, bytesIn))
elapsedT = time.time() - lastPrint
if (time.time() - lastPrint >= 5):
outRate = bytesOut / elapsedT
inRate = bytesIn / elapsedT
usbRate = (bytesOut + bytesIn) / elapsedT
lastPrint = time.time()
print('elapsed time: %f' % (time.time() - startTime))
print('data rates (bytes/sec): out: %f, in: %f, total: %f' % (outRate, inRate, usbRate))
bytesOut = 0
bytesIn = 0
i += 1
#if (i > 2): break
@@ -2,7 +2,7 @@
#
# Stack: PX4 Pro
# Vehicle: Amovlab F410
# Version: 1.15.4
# Version: 1.15.4
# Git Revision: 99c40407ff000000
#
# Vehicle-Id Component-Id Name Value Type
@@ -479,6 +479,11 @@
1 1 EKF2_WIND_NSD 0.050000000745058060 9
1 1 EV_TSK_RC_LOSS 0 6
1 1 EV_TSK_STAT_DIS 0 6
1 1 FD_ACT_EN 1 6
1 1 FD_ACT_MOT_C2T 2.000000000000000000 9
1 1 FD_ACT_MOT_THR 0.200000002980232239 9
1 1 FD_ACT_MOT_TOUT 100 6
1 1 FD_ESCS_EN 1 6
1 1 FD_EXT_ATS_EN 0 6
1 1 FD_EXT_ATS_TRIG 1900 6
1 1 FD_FAIL_P 60 6
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

-1
View File
@@ -759,7 +759,6 @@
- [Receiving Messages](mavlink/receiving_messages.md)
- [Custom MAVLink Messages](mavlink/custom_messages.md)
- [Message Signing](mavlink/message_signing.md)
- [Security Hardening](mavlink/security_hardening.md)
- [Protocols/Microservices](mavlink/protocols.md)
- [Standard Modes Protocol](mavlink/standard_modes.md)
- [uXRCE-DDS (PX4-ROS 2/DDS Bridge)](middleware/uxrce_dds.md)
File diff suppressed because it is too large Load Diff
+1
View File
@@ -413,6 +413,7 @@ They recommend sensors, power systems, and other components from the same manufa
- [Holybro Pixhawk 6X Wiring Quickstart](../assembly/quick_start_pixhawk6x.md)
- [Holybro Pixhawk 5X Wiring Quickstart](../assembly/quick_start_pixhawk5x.md)
- [Holybro Pixhawk 4 Wiring Quickstart](../assembly/quick_start_pixhawk4.md)
- [Holybro Pixhawk 4 Mini (Discontinued) Wiring Quickstart](../assembly/quick_start_pixhawk4_mini.md)
- [Holybro Durandal Wiring Quickstart](../assembly/quick_start_durandal.md)
- [Holybro Pix32 v5 Wiring Quickstart](../assembly/quick_start_holybro_pix32_v5.md)
- [Cube Wiring Quickstart](../assembly/quick_start_cube.md) (All cube variants)
@@ -0,0 +1,161 @@
# _Pixhawk 4 Mini_ Wiring Quick Start
:::warning
PX4 does not manufacture this (or any) autopilot.
Contact the [manufacturer](https://holybro.com/) for hardware support or compliance issues.
:::
This quick start guide shows how to power the [_Pixhawk<sup>&reg;</sup> 4 Mini_](../flight_controller/pixhawk4_mini.md) flight controller and connect its most important peripherals.
![Pixhawk4 mini](../../assets/flight_controller/pixhawk4mini/pixhawk4mini_iso_1.png)
## Wiring Chart Overview
The image below shows where to connect the most important sensors and peripherals (except for motors and servos).
![*Pixhawk 4 Mini* Wiring Overview](../../assets/flight_controller/pixhawk4mini/pixhawk4mini_wiring_overview.png)
:::tip
More information about available ports can be found here: [_Pixhawk 4 Mini_ > Interfaces](../flight_controller/pixhawk4_mini.md#interfaces).
:::
## Mount and Orient Controller
_Pixhawk 4 Mini_ should be mounted on your frame using vibration-damping foam pads (included in the kit).
It should be positioned as close to your vehicles center of gravity as possible, oriented top-side up with the arrow pointing towards the front of the vehicle.
![*Pixhawk 4 Mini* Orientation](../../assets/flight_controller/pixhawk4mini/pixhawk4mini_orientation.png)
::: info
If the controller cannot be mounted in the recommended/default orientation (e.g. due to space constraints) you will need to configure the autopilot software with the orientation that you actually used: [Flight Controller Orientation](../config/flight_controller_orientation.md).
:::
## GPS + Compass + Buzzer + Safety Switch + LED
Attach the provided GPS with integrated compass, safety switch, buzzer, and LED to the **GPS MODULE** port. The GPS/Compass should be [mounted on the frame](../assembly/mount_gps_compass.md) as far away from other electronics as possible, with the direction marker towards the front of the vehicle (separating the compass from other electronics will reduce interference).
![Connect compass/GPS to Pixhawk 4](../../assets/flight_controller/pixhawk4mini/pixhawk4mini_gps.png)
::: info
The GPS module's integrated safety switch is enabled _by default_ (when enabled, PX4 will not let you arm the vehicle).
To disable the safety press and hold the safety switch for 1 second.
You can press the safety switch again to enable safety and disarm the vehicle (this can be useful if, for whatever reason, you are unable to disarm the vehicle from your remote control or ground station).
:::
## Power
The Power Management Board (PMB) serves the purpose of a power module as well as a power distribution board.
In addition to providing regulated power to _Pixhawk 4 Mini_ and the ESCs, it sends information to the autopilot about the batterys voltage and current draw.
Connect the output of the PMB that comes with the kit to the **POWER** port of the _Pixhawk 4 Mini_ using a 6-wire cable.
The connections of the PMB, including power supply and signal connections to the ESCs and servos, are explained in the image below.
![Pixhawk 4 - Power Management Board](../../assets/flight_controller/pixhawk4mini/pixhawk4mini_power_management.png)
::: info
The image above only shows the connection of a single ESC and a single servo.
Connect the remaining ESCs and servos similarly.
:::
| Pin(s) or Connector | Function |
| ------------------- | -------------------------------------------------------------------------- |
| B+ | Connect to ESC B+ to power the ESC |
| GND | Connect to ESC Ground |
| PWR | JST-GH 6-pin Connector, 5V 3A output<br> connect to _Pixhawk 4 Mini_ POWER |
| BAT | Power Input, connect to 2~12s LiPo Battery |
The pinout of the _Pixhawk 4 Mini_ **POWER** port is shown below.
The `CURRENT` signal should carry an analog voltage from 0-3.3V for 0-120A as default.
The `VOLTAGE` signal should carry an analog voltage from 0-3.3V for 0-60V as default.
The VCC lines have to offer at least 3A continuous and should default to 5.1V. A lower voltage of 5V is still acceptable, but discouraged.
| Pin | Signal | Volt |
| -------- | ------- | ----- |
| 1(red) | VCC | +5V |
| 2(black) | VCC | +5V |
| 3(black) | CURRENT | +3.3V |
| 4(black) | VOLTAGE | +3.3V |
| 5(black) | GND | GND |
| 6(black) | GND | GND |
::: info
If using a plane or rover, the 8 pin power (+) rail of **MAIN OUT** will need to be separately powered in order to drive servos for rudders, elevons, etc.
To do this, the power rail needs to be connected to a BEC equipped ESC, a standalone 5V BEC, or a 2S LiPo battery.
Be careful with the voltage of servo you are going to use here.
:::
<!--In the future, when Pixhawk 4 kit is available, add wiring images/videos for different airframes.-->
::: info
Using the Power Module that comes with the kit you will need to configure the _Number of Cells_ in the [Power Settings](https://docs.qgroundcontrol.com/master/en/qgc-user-guide/setup_view/power.html) but you won't need to calibrate the _voltage divider_.
You will have to update the _voltage divider_ if you are using any other power module (e.g. the one from the Pixracer).
:::
## Radio Control
A remote control (RC) radio system is required if you want to _manually_ control your vehicle (PX4 does not require a radio system for autonomous flight modes).
You will need to [select a compatible transmitter/receiver](../getting_started/rc_transmitter_receiver.md) and then _bind_ them so that they communicate (read the instructions that come with your specific transmitter/receiver).
The instructions below show how to connect the different types of receivers to _Pixhawk 4 Mini_:
- Spektrum/DSM or S.BUS receivers connect to the **DSM/SBUS RC** input.
![Pixhawk 4 Mini - Radio port for Spektrum receivers](../../assets/flight_controller/pixhawk4mini/pixhawk4mini_rc_dsmsbus.png)
- PPM receivers connect to the **PPM RC** input port.
![Pixhawk 4 Mini - Radio port for PPM receivers](../../assets/flight_controller/pixhawk4mini/pixhawk4mini_rc_ppm.png)
- PPM and PWM receivers that have an _individual wire for each channel_ must connect to the **PPM RC** port _via a PPM encoder_ [like this one](https://www.getfpv.com/radios/radio-accessories/holybro-ppm-encoder-module.html) (PPM-Sum receivers use a single signal wire for all channels).
For more information about selecting a radio system, receiver compatibility, and binding your transmitter/receiver pair, see: [Remote Control Transmitters & Receivers](../getting_started/rc_transmitter_receiver.md).
## Telemetry Radio (Optional)
Telemetry radios may be used to communicate and control a vehicle in flight from a ground station (for example, you can direct the UAV to a particular position, or upload a new mission).
The vehicle-based radio should be connected to the **TELEM1** port as shown below (if connected to this port, no further configuration is required).
The other radio is connected to your ground station computer or mobile device (usually by USB).
![Pixhawk 4 Mini Telemetry](../../assets/flight_controller/pixhawk4mini/pixhawk4mini_telemetry.png)
## microSD Card (Optional)
SD cards are highly recommended as they are needed to [log and analyse flight details](../getting_started/flight_reporting.md), to run missions, and to use UAVCAN-bus hardware.
Insert the card (included in the kit) into _Pixhawk 4 Mini_ as shown below.
![Pixhawk 4 Mini SD Card](../../assets/flight_controller/pixhawk4mini/pixhawk4mini_sdcard.png)
:::tip
For more information see [Basic Concepts > SD Cards (Removable Memory)](../getting_started/px4_basic_concepts.md#sd-cards-removable-memory).
:::
## Motors
Motors/servos are connected to the **MAIN OUT** ports in the order specified for your vehicle in the [Airframe Reference](../airframes/airframe_reference.md). See [_Pixhawk 4 Mini_ > Supported Platforms](../flight_controller/pixhawk4_mini.md#supported-platforms) for more information.
::: info
This reference lists the output port to motor/servo mapping for all supported air and ground frames (if your frame is not listed in the reference then use a "generic" airframe of the correct type).
:::
:::warning
The mapping is not consistent across frames (e.g. you can't rely on the throttle being on the same output for all plane frames).
Make sure to use the correct mapping for your vehicle.
:::
## Other Peripherals
The wiring and configuration of optional/less common components is covered within the topics for individual [peripherals](../peripherals/index.md).
## Configuration
General configuration information is covered in: [Autopilot Configuration](../config/index.md).
QuadPlane specific configuration is covered here: [QuadPlane VTOL Configuration](../config_vtol/vtol_quad_configuration.md)
<!-- Nice to have detailed wiring infographic and instructions for different vehicle types. -->
## Further information
- [_Pixhawk 4 Mini_](../flight_controller/pixhawk4_mini.md)
@@ -28,7 +28,7 @@ In addition you will need:
The _Kopis 2_ comes preinstalled with Betaflight.
Before loading PX4 firmware you must first install the PX4 bootloader.
Download the [kakutef7_bl.hex](https://raw.githubusercontent.com/PX4/PX4-Autopilot/release/1.17/docs/assets/flight_controller/kakutef7/kakutef7_bl_0b3fbe2da0.hex?download=true) bootloader binary and read [PX4 Bootloader Flashing onto Betaflight Systems](../advanced_config/bootloader_update_from_betaflight.md) for flashing instructions.
Instructions for installing the bootloader can be found in the [Kakute F7](../flight_controller/kakutef7.md#bootloader) topic (this is the flight controller board on the _Kopis 2_).
:::tip
You can always [reinstall Betaflight](../advanced_config/bootloader_update_from_betaflight.md#reinstall-betaflight) later if you want!
+9 -3
View File
@@ -23,10 +23,16 @@ The sections below outline/link to the wiring and system console information for
### Board-Specific Wiring
The System Console UART pinouts/debug ports are typically documented in the affected [autopilot overview pages](../flight_controller/index.md).
For example, see [mRo Pixhawk](../flight_controller/mro_pixhawk.md#console-port) and [Pixracer](../flight_controller/pixracer.md#debug-port).
The System Console UART pinouts/debug ports are typically documented in [autopilot overview pages](../flight_controller/index.md) (some are linked below):
### Pixhawk Debug Port {#pixhawk_debug_port}
- [3DR Pixhawk v1 Flight Controller](../flight_controller/pixhawk.md#console-port) (also applies to
[mRo Pixhawk](../flight_controller/mro_pixhawk.md#debug-ports), [Holybro pix32](../flight_controller/holybro_pix32.md#debug-port))
- [Pixhawk 3](../flight_controller/pixhawk3_pro.md#debug-port)
- [Pixracer](../flight_controller/pixracer.md#debug-port)
<a id="pixhawk_debug_port"></a>
### Pixhawk Debug Port
Pixhawk flight controllers usually come with a [Pixhawk Connector Standard Debug Port](../debug/swd_debug.md#pixhawk-connector-standard-debug-ports) which will be either the 10 pin [Pixhawk Debug Full](../debug/swd_debug.md#pixhawk-debug-full) or 6 pin [Pixhawk Debug Mini](../debug/swd_debug.md#pixhawk-debug-mini) port.
@@ -14,11 +14,10 @@ They are listed because you may be using them in an existing drone, and because
- _CUAV Pixhack v3_ (FMUv3) — last published in [PX4 v1.15](https://docs.px4.io/v1.15/en/flight_controller/pixhack_v3) <!-- 202603 removed doc -->
- _Aerotenna OcPoC-Zynq Mini_ — last published in [PX4v1.11](https://docs.px4.io/v1.11/en/flight_controller/ocpoc_zynq#aerotenna-ocpoc-zynq-mini-flight-controller) <!-- 202603 removed doc -->
- _Holybro Pixhawk 4 Mini_ (FMUv5) -— last published in [PX4 v1.16](https://docs.px4.io/v1.16/en/flight_controller/pixhawk4_mini) <!-- 202603 removed doc -->
- _Holybro Kakute F7_ — Marked as discontinued in PX4 v1.15.
Last published in [PX4 v1.17](https://docs.px4.io/v1.17/en/flight_controller/kakutef7). <!-- 202603 removed doc -->
- _Holybro Pixhawk Mini_ (FMUv3) — last published in [PX4 v1.16](https://docs.px4.io/v1.16/en/flight_controller/pixhawk_mini) <!-- 202603 removed doc -->
- _Holybro Kakute F7_ — last published in [PX4 v1.15](https://docs.px4.io/v1.15/en/flight_controller/kakutef7) <!-- 202603 removed doc -->
- _Holybro Pixhawk Mini_ (FMUv3) — last published in [PX4 v1.15](https://docs.px4.io/v1.15/en/flight_controller/pixhawk_mini) <!-- 202603 removed doc -->
- _Holybro Pixfalcon_ (Pixhawk FMUv2) — last published in [PX4 v1.16](https://docs.px4.io/v1.16/en/flight_controller/pixfalcon) <!-- Discontinued around v1.15/2024. -->
- _Holybro Pix32_ (FMUv2) — last published in [PX4 v1.16](https://docs.px4.io/v1.16/en/flight_controller/holybro_pix32) <!-- 202603 removed doc -->
- _Holybro Pix32_ (FMUv2) — last published in [PX4 v1.15](https://docs.px4.io/v1.15/en/flight_controller/holybro_pix32) <!-- 202603 removed doc -->
- _ModalAI VOXL Flight_ — last published in [PX4 v1.16](https://docs.px4.io/v1.16/en/flight_controller/modalai_voxl_flight) <!-- 202603 removed doc -->
- _ModalAI Flight Core v1_ — last published in [PX4 v1.11](https://docs.px4.io/v1.11/en/flight_controller/modalai_fc_v1) <!-- 202603 removed doc -->
- _mRobotics-X2.1_ (FMUv2) — last published in [PX4 v1.16](https://docs.px4.io/v1.16/en/flight_controller/mro_x2.1) <!-- 202507 removed doc -->
+2 -163
View File
@@ -75,172 +75,11 @@ make px4_fmu-v3_default
## Debug Ports
### Console Port
The [PX4 System Console](../debug/system_console.md) runs on the port labeled [SERIAL4/5](#serial-4-5-port).
::: tip
A convenient way to connect to the console is to use a [Zubax BugFace BF1](https://github.com/Zubax/bugface_bf1), as it comes with connectors that can be used with several different Pixhawk devices.
Simply connect the 6-pos DF13 1:1 cable on the [Zubax BugFace BF1](https://github.com/Zubax/bugface_bf1) to the Pixhawk `SERIAL4/5` port.
![Zubax BugFace BF1](../../assets/flight_controller/mro/dronecode_probe.jpg)
:::
The pinout is standard serial pinout, designed to connect to a [3.3V FTDI](https://www.digikey.com/en/products/detail/TTL-232R-3V3/768-1015-ND/1836393) cable (5V tolerant).
| 3DR Pixhawk 1 | | FTDI | |
| ------------- | --------- | ---- | ---------------- |
| 1 | +5V (red) | | N/C |
| 2 | S4 Tx | | N/C |
| 3 | S4 Rx | | N/C |
| 4 | S5 Tx | 5 | FTDI RX (yellow) |
| 5 | S5 Rx | 4 | FTDI TX (orange) |
| 6 | GND | 1 | FTDI GND (black) |
The wiring for an FTDI cable to a 6-pos DF13 1:1 connector is shown in the figure below.
![Console Connector](../../assets/flight_controller/mro/console_connector.jpg)
The complete wiring is shown below.
![Console Debug](../../assets/flight_controller/mro/console_debug.jpg)
::: info
For information on how to _use_ the console see: [System Console](../debug/system_console.md).
:::
### SWD Port
The [SWD](../debug/swd_debug.md) (JTAG) ports are hidden under the cover (which must be removed for hardware debugging).
There are separate ports for FMU and IO, as highlighted below.
![Pixhawk SWD](../../assets/flight_controller/mro/pixhawk_swd.jpg)
The ports are ARM 10-pin JTAG connectors, which you will probably have to solder.
The pinout for the ports is shown below (the square markers in the corners above indicates pin 1).
![ARM 10-Pin connector pinout](../../assets/flight_controller/mro/arm_10pin_jtag_connector_pinout.jpg)
::: info
All Pixhawk FMUv2 boards have a similar SWD port.
:::
See [3DR Pixhawk 1 > Debug Ports](../flight_controller/pixhawk.md#debug-ports)
## Pinouts
#### TELEM1, TELEM2 ports
| Pin | Signal | Volt |
| ------- | --------- | ----- |
| 1 (red) | VCC | +5V |
| 2 (blk) | TX (OUT) | +3.3V |
| 3 (blk) | RX (IN) | +3.3V |
| 4 (blk) | CTS (IN) | +3.3V |
| 5 (blk) | RTS (OUT) | +3.3V |
| 6 (blk) | GND | GND |
#### GPS port
| Pin | Signal | Volt |
| ------- | -------- | ----- |
| 1 (red) | VCC | +5V |
| 2 (blk) | TX (OUT) | +3.3V |
| 3 (blk) | RX (IN) | +3.3V |
| 4 (blk) | CAN2 TX | +3.3V |
| 5 (blk) | CAN2 RX | +3.3V |
| 6 (blk) | GND | GND |
#### SERIAL 4/5 port
Due to space constraints two ports are on one connector.
| Pin | Signal | Volt |
| ------- | ------- | ----- |
| 1 (red) | VCC | +5V |
| 2 (blk) | TX (#4) | +3.3V |
| 3 (blk) | RX (#4) | +3.3V |
| 4 (blk) | TX (#5) | +3.3V |
| 5 (blk) | RX (#5) | +3.3V |
| 6 (blk) | GND | GND |
#### ADC 6.6V
| Pin | Signal | Volt |
| ------- | ------ | ----------- |
| 1 (red) | VCC | +5V |
| 2 (blk) | ADC IN | up to +6.6V |
| 3 (blk) | GND | GND |
#### ADC 3.3V
| Pin | Signal | Volt |
| ------- | ------ | ----------- |
| 1 (red) | VCC | +5V |
| 2 (blk) | ADC IN | up to +3.3V |
| 3 (blk) | GND | GND |
| 4 (blk) | ADC IN | up to +3.3V |
| 5 (blk) | GND | GND |
#### I2C
| Pin | Signal | Volt |
| ------- | ------ | -------------- |
| 1 (red) | VCC | +5V |
| 2 (blk) | SCL | +3.3 (pullups) |
| 3 (blk) | SDA | +3.3 (pullups) |
| 4 (blk) | GND | GND |
#### CAN
| Pin | Signal | Volt |
| ------- | ------ | ---- |
| 1 (red) | VCC | +5V |
| 2 (blk) | CAN_H | +12V |
| 3 (blk) | CAN_L | +12V |
| 4 (blk) | GND | GND |
#### SPI
| Pin | Signal | Volt |
| ------- | ------------ | ---- |
| 1 (red) | VCC | +5V |
| 2 (blk) | SPI_EXT_SCK | +3.3 |
| 3 (blk) | SPI_EXT_MISO | +3.3 |
| 4 (blk) | SPI_EXT_MOSI | +3.3 |
| 5 (blk) | !SPI_EXT_NSS | +3.3 |
| 6 (blk) | !GPIO_EXT | +3.3 |
| 7 (blk) | GND | GND |
#### POWER
| Pin | Signal | Volt |
| ------- | ------- | ----- |
| 1 (red) | VCC | +5V |
| 2 (blk) | VCC | +5V |
| 3 (blk) | CURRENT | +3.3V |
| 4 (blk) | VOLTAGE | +3.3V |
| 5 (blk) | GND | GND |
| 6 (blk) | GND | GND |
#### SWITCH
| Pin | Signal | Volt |
| ------- | -------------- | ----- |
| 1 (red) | VCC | +3.3V |
| 2 (blk) | !IO_LED_SAFETY | GND |
| 3 (blk) | SAFETY | GND |
## Serial Port Mapping
| UART | Device | Port |
| ------ | ---------- | --------------------- |
| UART1 | /dev/ttyS0 | IO debug |
| USART2 | /dev/ttyS1 | TELEM1 (flow control) |
| USART3 | /dev/ttyS2 | TELEM2 (flow control) |
| UART4 | |
| UART7 | CONSOLE |
| UART8 | SERIAL4 |
<!-- Note: Got ports using https://github.com/PX4/PX4-user_guide/pull/672#issuecomment-598198434 -->
See [3DR Pixhawk 1 > Pinouts](../flight_controller/pixhawk.md#pinouts)
## Serial Port Mapping
+3 -3
View File
@@ -93,8 +93,8 @@ Order from [Holybro](https://holybro.com/products/pixhawk-6c-mini).
## Assembly/Setup
The Pixhawk 6C Mini's ports are very similar to the Pixhawk 4 Mini's ports.
Please refer to the [Pixhawk 4 Mini Wiring Quick Start](https://docs.px4.io/v1.16/en/assembly/quick_start_pixhawk4_mini) (Discontinued) as it provides instructions on how to assemble required/important peripherals including GPS, Power Module etc.
The Pixhawk 4 Mini's port is very similar to the Pixhawk 6C Mini's port.
Please refer to the [Pixhawk 4 Mini Wiring Quick Start](../assembly/quick_start_pixhawk4_mini.md) as it provides instructions on how to assemble required/important peripherals including GPS, Power Module etc.
## Pinouts
@@ -199,7 +199,7 @@ The complete set of supported configurations can be seen in the [Airframes Refer
## See Also
- [Holybro Docs](https://docs.holybro.com/) (Holybro)
- [Pixhawk 6C Wiring QuickStart](../assembly/quick_start_pixhawk6c.md)
- [Pixhawk 4 Mini Wiring Quick Start](../assembly/quick_start_pixhawk4_mini.md) (and [Pixhawk 6C Wiring QuickStart](../assembly/quick_start_pixhawk6c.md))
- [PM02 Power Module](../power_module/holybro_pm02.md)
- [PM06 Power Module](../power_module/holybro_pm06_pixhawk4mini_power_module.md)
- [PM07 Power Module](../power_module/holybro_pm07_pixhawk4_power_module.md)
@@ -169,7 +169,7 @@ As we have no ground or positive BEC voltage connections we connect our `PWM` ES
### GPS / External Magnetometer
I took the GPS cable which fits the connector of the used GPS and came with the Pixracer set.
Sadly the pin assignment was completely wrong and I rewired the connector again using tweezers according to the [3DR Pixhawk Mini user manual](https://docs.px4.io/v1.16/en/flight_controller/pixhawk_mini#connector-pin-assignments-pin-outs) GPS port.
Sadly the pin assignment was completely wrong and I rewired the connector again using tweezers according to the [3DR Pixhawk Mini user manual](../flight_controller/pixhawk_mini.md#connector-pin-assignments-pin-outs) GPS port.
#### Pixracer GPS/I2C Port
-4
View File
@@ -14,10 +14,6 @@ It also links instructions for how you can add PX4 support for:
- [Message Signing](../mavlink/message_signing.md)
- [Protocols/Microservices](../mavlink/protocols.md)
::: warning
MAVLink messages are unauthenticated by default. Without [message signing](../mavlink/message_signing.md) enabled, any device that can send MAVLink messages to the vehicle can execute commands including shell access, file operations, and flight termination. Production deployments must enable signing and follow the [Security Hardening](../mavlink/security_hardening.md) guide.
:::
::: info
We do not yet cover _command_ handling and sending, or how to implement your own microservices.
:::
-84
View File
@@ -1,84 +0,0 @@
# MAVLink Security Hardening for Production Deployments
<Badge type="tip" text="PX4 v1.17" />
MAVLink is an open communication protocol designed for lightweight, low-latency communication between drones and ground stations.
By default, all MAVLink messages are unauthenticated.
This is intentional for development and testing, but **production deployments must enable [message signing](message_signing.md)** to prevent unauthorized access.
::: warning
Without message signing enabled, any device that can send MAVLink messages to the vehicle (via radio, network, or serial) can execute any command, including shell access, file operations, parameter changes, mission uploads, arming, and flight termination.
:::
## What Is at Risk
When MAVLink signing is not enabled, an attacker within communication range can:
| Capability | MAVLink mechanism |
| ---------------------------- | ------------------------------------------------ |
| Execute shell commands | `SERIAL_CONTROL` with `SERIAL_CONTROL_DEV_SHELL` |
| Read, write, or delete files | MAVLink FTP protocol |
| Change any flight parameter | `PARAM_SET` / `PARAM_EXT_SET` |
| Upload or overwrite missions | Mission protocol |
| Arm or disarm motors | `MAV_CMD_COMPONENT_ARM_DISARM` |
| Terminate flight (crash) | `MAV_CMD_DO_FLIGHTTERMINATION` |
| Trigger emergency landing | Spoofed `BATTERY_STATUS` |
| Reboot the vehicle | `MAV_CMD_PREFLIGHT_REBOOT_SHUTDOWN` |
All of these are standard MAVLink capabilities used by ground control stations.
Without signing, there is no distinction between a legitimate GCS and an unauthorized sender.
## Hardening Checklist
### 1. Enable Message Signing
Message signing provides cryptographic authentication for all MAVLink communication.
See [Message Signing](message_signing.md) for full details.
Steps:
1. Connect the vehicle via **USB** (key provisioning only works over USB).
2. Provision a 32-byte secret key using the [SETUP_SIGNING](https://mavlink.io/en/messages/common.html#SETUP_SIGNING) message.
3. Set [MAV_SIGN_CFG](../advanced_config/parameter_reference.md#MAV_SIGN_CFG) to **1** (signing enabled on all links except USB) or **2** (signing on all links including USB).
4. Provision the same key on all ground control stations and companion computers that need to communicate with the vehicle.
5. Verify that unsigned messages from unknown sources are rejected.
::: info
`MAV_SIGN_CFG=1` is recommended for most deployments.
This enforces signing on telemetry radios and network links while allowing unsigned access over USB for maintenance.
USB connections require physical access to the vehicle, which provides equivalent security to physical key access.
:::
### 2. Secure Physical Access
- Protect access to the SD card. The signing key is stored at `/mavlink/mavlink-signing-key.bin` and can be read or removed by anyone with physical access.
- USB connections bypass signing when `MAV_SIGN_CFG=1`. Ensure USB ports are not exposed in deployed configurations.
### 3. Secure Network Links
- Do not expose MAVLink UDP/TCP ports to untrusted networks or the internet.
- Place MAVLink communication links behind firewalls or VPNs.
- Segment MAVLink networks from business or public networks.
- When using companion computers, audit which network interfaces MAVLink is bound to.
### 4. Understand the Limitations
- **No encryption**: Message signing provides authentication and integrity, but messages are sent in plaintext. An eavesdropper can read telemetry and commands but cannot forge them.
- **Allowlisted messages**: A small set of [safety-critical messages](message_signing.md#unsigned-message-allowlist) (RADIO_STATUS, ADSB_VEHICLE, COLLISION) are always accepted unsigned.
- **Key management**: There is no automatic key rotation. Keys must be reprovisioned manually via USB if compromised.
## Integrator Responsibility
PX4 is open-source flight controller firmware used by manufacturers and system integrators to build commercial and custom drone platforms.
Securing the communication links for a specific deployment is the responsibility of the system integrator.
This includes:
- Choosing appropriate radio hardware and link security
- Enabling and managing MAVLink message signing
- Restricting network access to MAVLink interfaces
- Applying firmware updates that address security issues
- Evaluating whether the default configuration meets the security requirements of the target application
PX4 provides the tools for securing MAVLink communication.
Integrators must enable and configure them for their deployment context.
+188 -188
View File
@@ -95,202 +95,202 @@ They are not build into the module, and hence are neither published or subscribe
::: details See messages
- [LandingTargetPose](../msg_docs/LandingTargetPose.md)
- [DeviceInformation](../msg_docs/DeviceInformation.md)
- [ParameterSetUsedRequest](../msg_docs/ParameterSetUsedRequest.md)
- [Mission](../msg_docs/Mission.md)
- [VehicleMagnetometer](../msg_docs/VehicleMagnetometer.md)
- [InternalCombustionEngineControl](../msg_docs/InternalCombustionEngineControl.md)
- [VehicleLocalPositionSetpoint](../msg_docs/VehicleLocalPositionSetpoint.md)
- [LedControl](../msg_docs/LedControl.md)
- [GimbalDeviceInformation](../msg_docs/GimbalDeviceInformation.md)
- [LoggerStatus](../msg_docs/LoggerStatus.md)
- [VehicleAcceleration](../msg_docs/VehicleAcceleration.md)
- [DebugVect](../msg_docs/DebugVect.md)
- [PositionControllerLandingStatus](../msg_docs/PositionControllerLandingStatus.md)
- [EscReport](../msg_docs/EscReport.md)
- [AirspeedWind](../msg_docs/AirspeedWind.md)
- [GimbalManagerSetAttitude](../msg_docs/GimbalManagerSetAttitude.md)
- [EstimatorSensorBias](../msg_docs/EstimatorSensorBias.md)
- [EstimatorBias3d](../msg_docs/EstimatorBias3d.md)
- [EscStatus](../msg_docs/EscStatus.md)
- [TaskStackInfo](../msg_docs/TaskStackInfo.md)
- [MountOrientation](../msg_docs/MountOrientation.md)
- [Cpuload](../msg_docs/Cpuload.md)
- [RaptorStatus](../msg_docs/RaptorStatus.md)
- [ActuatorOutputs](../msg_docs/ActuatorOutputs.md)
- [MavlinkLog](../msg_docs/MavlinkLog.md)
- [DronecanNodeStatus](../msg_docs/DronecanNodeStatus.md)
- [GainCompression](../msg_docs/GainCompression.md)
- [ActuatorTest](../msg_docs/ActuatorTest.md)
- [ButtonEvent](../msg_docs/ButtonEvent.md)
- [HeaterStatus](../msg_docs/HeaterStatus.md)
- [CanInterfaceStatus](../msg_docs/CanInterfaceStatus.md)
- [NavigatorMissionItem](../msg_docs/NavigatorMissionItem.md)
- [GeneratorStatus](../msg_docs/GeneratorStatus.md)
- [OrbTest](../msg_docs/OrbTest.md)
- [NormalizedUnsignedSetpoint](../msg_docs/NormalizedUnsignedSetpoint.md)
- [FollowTarget](../msg_docs/FollowTarget.md)
- [ActuatorServosTrim](../msg_docs/ActuatorServosTrim.md)
- [QshellReq](../msg_docs/QshellReq.md)
- [UavcanParameterValue](../msg_docs/UavcanParameterValue.md)
- [TecsStatus](../msg_docs/TecsStatus.md)
- [Vtx](../msg_docs/Vtx.md)
- [SensorGyro](../msg_docs/SensorGyro.md)
- [VehicleAngularVelocity](../msg_docs/VehicleAngularVelocity.md)
- [FollowTargetStatus](../msg_docs/FollowTargetStatus.md)
- [GpioIn](../msg_docs/GpioIn.md)
- [DatamanResponse](../msg_docs/DatamanResponse.md)
- [FollowTargetEstimator](../msg_docs/FollowTargetEstimator.md)
- [GimbalControls](../msg_docs/GimbalControls.md)
- [TakeoffStatus](../msg_docs/TakeoffStatus.md)
- [OpenDroneIdSystem](../msg_docs/OpenDroneIdSystem.md)
- [RtlTimeEstimate](../msg_docs/RtlTimeEstimate.md)
- [SensorMag](../msg_docs/SensorMag.md)
- [VehicleImuStatus](../msg_docs/VehicleImuStatus.md)
- [VehicleCommandAckV0](../msg_docs/VehicleCommandAckV0.md)
- [QshellRetval](../msg_docs/QshellRetval.md)
- [SensorGnssStatus](../msg_docs/SensorGnssStatus.md)
- [RcChannels](../msg_docs/RcChannels.md)
- [InternalCombustionEngineStatus](../msg_docs/InternalCombustionEngineStatus.md)
- [RtlStatus](../msg_docs/RtlStatus.md)
- [OrbTestMedium](../msg_docs/OrbTestMedium.md)
- [Rpm](../msg_docs/Rpm.md)
- [PwmInput](../msg_docs/PwmInput.md)
- [OpenDroneIdSelfId](../msg_docs/OpenDroneIdSelfId.md)
- [SensorUwb](../msg_docs/SensorUwb.md)
- [AirspeedValidatedV0](../msg_docs/AirspeedValidatedV0.md)
- [SensorGnssRelative](../msg_docs/SensorGnssRelative.md)
- [ParameterSetValueRequest](../msg_docs/ParameterSetValueRequest.md)
- [ManualControlSwitches](../msg_docs/ManualControlSwitches.md)
- [RegisterExtComponentReplyV0](../msg_docs/RegisterExtComponentReplyV0.md)
- [OrbTestLarge](../msg_docs/OrbTestLarge.md)
- [EstimatorAidSource3d](../msg_docs/EstimatorAidSource3d.md)
- [ArmingCheckReplyV0](../msg_docs/ArmingCheckReplyV0.md)
- [GpioRequest](../msg_docs/GpioRequest.md)
- [DebugValue](../msg_docs/DebugValue.md)
- [FlightPhaseEstimation](../msg_docs/FlightPhaseEstimation.md)
- [VelocityLimits](../msg_docs/VelocityLimits.md)
- [SensorCorrection](../msg_docs/SensorCorrection.md)
- [IridiumsbdStatus](../msg_docs/IridiumsbdStatus.md)
- [BatteryInfo](../msg_docs/BatteryInfo.md)
- [FixedWingLateralGuidanceStatus](../msg_docs/FixedWingLateralGuidanceStatus.md)
- [GpioOut](../msg_docs/GpioOut.md)
- [TiltrotorExtraControls](../msg_docs/TiltrotorExtraControls.md)
- [GimbalManagerInformation](../msg_docs/GimbalManagerInformation.md)
- [EstimatorInnovations](../msg_docs/EstimatorInnovations.md)
- [YawEstimatorStatus](../msg_docs/YawEstimatorStatus.md)
- [VehicleLocalPositionV0](../msg_docs/VehicleLocalPositionV0.md)
- [RcParameterMap](../msg_docs/RcParameterMap.md)
- [TakeoffStatus](../msg_docs/TakeoffStatus.md)
- [UlogStreamAck](../msg_docs/UlogStreamAck.md)
- [GimbalDeviceSetAttitude](../msg_docs/GimbalDeviceSetAttitude.md)
- [EstimatorAidSource1d](../msg_docs/EstimatorAidSource1d.md)
- [ParameterSetUsedRequest](../msg_docs/ParameterSetUsedRequest.md)
- [IrlockReport](../msg_docs/IrlockReport.md)
- [PowerButtonState](../msg_docs/PowerButtonState.md)
- [GimbalManagerSetManualControl](../msg_docs/GimbalManagerSetManualControl.md)
- [MissionResult](../msg_docs/MissionResult.md)
- [TuneControl](../msg_docs/TuneControl.md)
- [WheelEncoders](../msg_docs/WheelEncoders.md)
- [FailureDetectorStatus](../msg_docs/FailureDetectorStatus.md)
- [RegisterExtComponentRequestV0](../msg_docs/RegisterExtComponentRequestV0.md)
- [EstimatorGpsStatus](../msg_docs/EstimatorGpsStatus.md)
- [HealthReport](../msg_docs/HealthReport.md)
- [MavlinkLog](../msg_docs/MavlinkLog.md)
- [NavigatorStatus](../msg_docs/NavigatorStatus.md)
- [DistanceSensorModeChangeRequest](../msg_docs/DistanceSensorModeChangeRequest.md)
- [CellularStatus](../msg_docs/CellularStatus.md)
- [LandingGearWheel](../msg_docs/LandingGearWheel.md)
- [ActuatorControlsStatus](../msg_docs/ActuatorControlsStatus.md)
- [SensorGyroFft](../msg_docs/SensorGyroFft.md)
- [VehicleRoi](../msg_docs/VehicleRoi.md)
- [OpenDroneIdOperatorId](../msg_docs/OpenDroneIdOperatorId.md)
- [PpsCapture](../msg_docs/PpsCapture.md)
- [GimbalManagerStatus](../msg_docs/GimbalManagerStatus.md)
- [VehicleStatusV0](../msg_docs/VehicleStatusV0.md)
- [ActuatorArmed](../msg_docs/ActuatorArmed.md)
- [DifferentialPressure](../msg_docs/DifferentialPressure.md)
- [ParameterUpdate](../msg_docs/ParameterUpdate.md)
- [ActionRequest](../msg_docs/ActionRequest.md)
- [LaunchDetectionStatus](../msg_docs/LaunchDetectionStatus.md)
- [ParameterResetRequest](../msg_docs/ParameterResetRequest.md)
- [RoverSpeedStatus](../msg_docs/RoverSpeedStatus.md)
- [InputRc](../msg_docs/InputRc.md)
- [VehicleConstraints](../msg_docs/VehicleConstraints.md)
- [TuneControl](../msg_docs/TuneControl.md)
- [VehicleAngularAccelerationSetpoint](../msg_docs/VehicleAngularAccelerationSetpoint.md)
- [AutotuneAttitudeControlStatus](../msg_docs/AutotuneAttitudeControlStatus.md)
- [DebugArray](../msg_docs/DebugArray.md)
- [ControlAllocatorStatus](../msg_docs/ControlAllocatorStatus.md)
- [RoverRateStatus](../msg_docs/RoverRateStatus.md)
- [VehicleAcceleration](../msg_docs/VehicleAcceleration.md)
- [SatelliteInfo](../msg_docs/SatelliteInfo.md)
- [DebugArray](../msg_docs/DebugArray.md)
- [CanInterfaceStatus](../msg_docs/CanInterfaceStatus.md)
- [EstimatorInnovations](../msg_docs/EstimatorInnovations.md)
- [VehicleImu](../msg_docs/VehicleImu.md)
- [EstimatorBias](../msg_docs/EstimatorBias.md)
- [QshellReq](../msg_docs/QshellReq.md)
- [GimbalDeviceInformation](../msg_docs/GimbalDeviceInformation.md)
- [VehicleOpticalFlow](../msg_docs/VehicleOpticalFlow.md)
- [SensorHygrometer](../msg_docs/SensorHygrometer.md)
- [PositionControllerLandingStatus](../msg_docs/PositionControllerLandingStatus.md)
- [GpioRequest](../msg_docs/GpioRequest.md)
- [Airspeed](../msg_docs/Airspeed.md)
- [PositionControllerStatus](../msg_docs/PositionControllerStatus.md)
- [Rpm](../msg_docs/Rpm.md)
- [Mission](../msg_docs/Mission.md)
- [GimbalManagerInformation](../msg_docs/GimbalManagerInformation.md)
- [SensorGyroFft](../msg_docs/SensorGyroFft.md)
- [GeofenceStatus](../msg_docs/GeofenceStatus.md)
- [DatamanRequest](../msg_docs/DatamanRequest.md)
- [Gripper](../msg_docs/Gripper.md)
- [SystemPower](../msg_docs/SystemPower.md)
- [GimbalManagerStatus](../msg_docs/GimbalManagerStatus.md)
- [MavlinkTunnel](../msg_docs/MavlinkTunnel.md)
- [AirspeedValidatedV0](../msg_docs/AirspeedValidatedV0.md)
- [ActionRequest](../msg_docs/ActionRequest.md)
- [MissionResult](../msg_docs/MissionResult.md)
- [FailureDetectorStatus](../msg_docs/FailureDetectorStatus.md)
- [LedControl](../msg_docs/LedControl.md)
- [SensorAirflow](../msg_docs/SensorAirflow.md)
- [GeneratorStatus](../msg_docs/GeneratorStatus.md)
- [GpsDump](../msg_docs/GpsDump.md)
- [EstimatorGpsStatus](../msg_docs/EstimatorGpsStatus.md)
- [SensorGyro](../msg_docs/SensorGyro.md)
- [EstimatorAidSource3d](../msg_docs/EstimatorAidSource3d.md)
- [ActuatorArmed](../msg_docs/ActuatorArmed.md)
- [SensorSelection](../msg_docs/SensorSelection.md)
- [LaunchDetectionStatus](../msg_docs/LaunchDetectionStatus.md)
- [RaptorInput](../msg_docs/RaptorInput.md)
- [Ekf2Timestamps](../msg_docs/Ekf2Timestamps.md)
- [ParameterSetValueResponse](../msg_docs/ParameterSetValueResponse.md)
- [FixedWingRunwayControl](../msg_docs/FixedWingRunwayControl.md)
- [FixedWingLateralGuidanceStatus](../msg_docs/FixedWingLateralGuidanceStatus.md)
- [PurePursuitStatus](../msg_docs/PurePursuitStatus.md)
- [RadioStatus](../msg_docs/RadioStatus.md)
- [ButtonEvent](../msg_docs/ButtonEvent.md)
- [EstimatorStatus](../msg_docs/EstimatorStatus.md)
- [FollowTarget](../msg_docs/FollowTarget.md)
- [UavcanParameterValue](../msg_docs/UavcanParameterValue.md)
- [PowerMonitor](../msg_docs/PowerMonitor.md)
- [SensorsStatusImu](../msg_docs/SensorsStatusImu.md)
- [NeuralControl](../msg_docs/NeuralControl.md)
- [TecsStatus](../msg_docs/TecsStatus.md)
- [VehicleStatusV0](../msg_docs/VehicleStatusV0.md)
- [FixedWingLateralStatus](../msg_docs/FixedWingLateralStatus.md)
- [FollowTargetStatus](../msg_docs/FollowTargetStatus.md)
- [GeofenceResult](../msg_docs/GeofenceResult.md)
- [AirspeedWind](../msg_docs/AirspeedWind.md)
- [NavigatorMissionItem](../msg_docs/NavigatorMissionItem.md)
- [Cpuload](../msg_docs/Cpuload.md)
- [SensorCorrection](../msg_docs/SensorCorrection.md)
- [PositionSetpoint](../msg_docs/PositionSetpoint.md)
- [SensorAccel](../msg_docs/SensorAccel.md)
- [VehicleAttitudeSetpointV0](../msg_docs/VehicleAttitudeSetpointV0.md)
- [ParameterSetValueRequest](../msg_docs/ParameterSetValueRequest.md)
- [HoverThrustEstimate](../msg_docs/HoverThrustEstimate.md)
- [AdcReport](../msg_docs/AdcReport.md)
- [ArmingCheckReplyV0](../msg_docs/ArmingCheckReplyV0.md)
- [DatamanResponse](../msg_docs/DatamanResponse.md)
- [ActuatorOutputs](../msg_docs/ActuatorOutputs.md)
- [GainCompression](../msg_docs/GainCompression.md)
- [HeaterStatus](../msg_docs/HeaterStatus.md)
- [VehicleGlobalPositionV0](../msg_docs/VehicleGlobalPositionV0.md)
- [VehicleRoi](../msg_docs/VehicleRoi.md)
- [RtlStatus](../msg_docs/RtlStatus.md)
- [EstimatorStates](../msg_docs/EstimatorStates.md)
- [Event](../msg_docs/Event.md)
- [EstimatorEventFlags](../msg_docs/EstimatorEventFlags.md)
- [MagWorkerData](../msg_docs/MagWorkerData.md)
- [ConfigOverridesV0](../msg_docs/ConfigOverridesV0.md)
- [YawEstimatorStatus](../msg_docs/YawEstimatorStatus.md)
- [GpioConfig](../msg_docs/GpioConfig.md)
- [MagnetometerBiasEstimate](../msg_docs/MagnetometerBiasEstimate.md)
- [IridiumsbdStatus](../msg_docs/IridiumsbdStatus.md)
- [LandingTargetPose](../msg_docs/LandingTargetPose.md)
- [DebugValue](../msg_docs/DebugValue.md)
- [VehicleOpticalFlowVel](../msg_docs/VehicleOpticalFlowVel.md)
- [WheelEncoders](../msg_docs/WheelEncoders.md)
- [ActuatorControlsStatus](../msg_docs/ActuatorControlsStatus.md)
- [Px4ioStatus](../msg_docs/Px4ioStatus.md)
- [CameraStatus](../msg_docs/CameraStatus.md)
- [LogMessage](../msg_docs/LogMessage.md)
- [PositionControllerStatus](../msg_docs/PositionControllerStatus.md)
- [SensorBaro](../msg_docs/SensorBaro.md)
- [SensorAccelFifo](../msg_docs/SensorAccelFifo.md)
- [SensorHygrometer](../msg_docs/SensorHygrometer.md)
- [PositionSetpoint](../msg_docs/PositionSetpoint.md)
- [VehicleAngularAccelerationSetpoint](../msg_docs/VehicleAngularAccelerationSetpoint.md)
- [GpsDump](../msg_docs/GpsDump.md)
- [GpioConfig](../msg_docs/GpioConfig.md)
- [GeofenceStatus](../msg_docs/GeofenceStatus.md)
- [EstimatorEventFlags](../msg_docs/EstimatorEventFlags.md)
- [SensorPreflightMag](../msg_docs/SensorPreflightMag.md)
- [VehicleOpticalFlow](../msg_docs/VehicleOpticalFlow.md)
- [PurePursuitStatus](../msg_docs/PurePursuitStatus.md)
- [GeofenceResult](../msg_docs/GeofenceResult.md)
- [EstimatorBias](../msg_docs/EstimatorBias.md)
- [SystemPower](../msg_docs/SystemPower.md)
- [EventV0](../msg_docs/EventV0.md)
- [CameraCapture](../msg_docs/CameraCapture.md)
- [RoverSpeedStatus](../msg_docs/RoverSpeedStatus.md)
- [HomePositionV0](../msg_docs/HomePositionV0.md)
- [VehicleGlobalPositionV0](../msg_docs/VehicleGlobalPositionV0.md)
- [Px4ioStatus](../msg_docs/Px4ioStatus.md)
- [EstimatorStates](../msg_docs/EstimatorStates.md)
- [FixedWingRunwayControl](../msg_docs/FixedWingRunwayControl.md)
- [FigureEightStatus](../msg_docs/FigureEightStatus.md)
- [InputRc](../msg_docs/InputRc.md)
- [Ekf2Timestamps](../msg_docs/Ekf2Timestamps.md)
- [LandingTargetInnovations](../msg_docs/LandingTargetInnovations.md)
- [UavcanParameterRequest](../msg_docs/UavcanParameterRequest.md)
- [DatamanRequest](../msg_docs/DatamanRequest.md)
- [ParameterResetRequest](../msg_docs/ParameterResetRequest.md)
- [VehicleConstraints](../msg_docs/VehicleConstraints.md)
- [VehicleAttitudeSetpointV0](../msg_docs/VehicleAttitudeSetpointV0.md)
- [FixedWingLateralStatus](../msg_docs/FixedWingLateralStatus.md)
- [RoverAttitudeStatus](../msg_docs/RoverAttitudeStatus.md)
- [NeuralControl](../msg_docs/NeuralControl.md)
- [DebugKeyValue](../msg_docs/DebugKeyValue.md)
- [GimbalDeviceSetAttitude](../msg_docs/GimbalDeviceSetAttitude.md)
- [EstimatorStatus](../msg_docs/EstimatorStatus.md)
- [ArmingCheckRequestV0](../msg_docs/ArmingCheckRequestV0.md)
- [TrajectorySetpoint6dof](../msg_docs/TrajectorySetpoint6dof.md)
- [ParameterSetValueResponse](../msg_docs/ParameterSetValueResponse.md)
- [MagnetometerBiasEstimate](../msg_docs/MagnetometerBiasEstimate.md)
- [CameraTrigger](../msg_docs/CameraTrigger.md)
- [PowerButtonState](../msg_docs/PowerButtonState.md)
- [ConfigOverridesV0](../msg_docs/ConfigOverridesV0.md)
- [VehicleStatusV1](../msg_docs/VehicleStatusV1.md)
- [AdcReport](../msg_docs/AdcReport.md)
- [SensorsStatus](../msg_docs/SensorsStatus.md)
- [UlogStreamAck](../msg_docs/UlogStreamAck.md)
- [UlogStream](../msg_docs/UlogStream.md)
- [SensorGyroFifo](../msg_docs/SensorGyroFifo.md)
- [BatteryStatusV0](../msg_docs/BatteryStatusV0.md)
- [SensorAccel](../msg_docs/SensorAccel.md)
- [PowerMonitor](../msg_docs/PowerMonitor.md)
- [OrbitStatus](../msg_docs/OrbitStatus.md)
- [RateCtrlStatus](../msg_docs/RateCtrlStatus.md)
- [MavlinkTunnel](../msg_docs/MavlinkTunnel.md)
- [Airspeed](../msg_docs/Airspeed.md)
- [EstimatorAidSource2d](../msg_docs/EstimatorAidSource2d.md)
- [EstimatorAidSource1d](../msg_docs/EstimatorAidSource1d.md)
- [RadioStatus](../msg_docs/RadioStatus.md)
- [VehicleOpticalFlowVel](../msg_docs/VehicleOpticalFlowVel.md)
- [VehicleAirData](../msg_docs/VehicleAirData.md)
- [SensorAirflow](../msg_docs/SensorAirflow.md)
- [Ping](../msg_docs/Ping.md)
- [MagWorkerData](../msg_docs/MagWorkerData.md)
- [FuelTankStatus](../msg_docs/FuelTankStatus.md)
- [GpsInjectData](../msg_docs/GpsInjectData.md)
- [Event](../msg_docs/Event.md)
- [OpenDroneIdArmStatus](../msg_docs/OpenDroneIdArmStatus.md)
- [HoverThrustEstimate](../msg_docs/HoverThrustEstimate.md)
- [RcParameterMap](../msg_docs/RcParameterMap.md)
- [Gripper](../msg_docs/Gripper.md)
- [SensorsStatusImu](../msg_docs/SensorsStatusImu.md)
- [VehicleImu](../msg_docs/VehicleImu.md)
- [SensorSelection](../msg_docs/SensorSelection.md)
- [EstimatorSelectorStatus](../msg_docs/EstimatorSelectorStatus.md)
- [IrlockReport](../msg_docs/IrlockReport.md)
- [GpioOut](../msg_docs/GpioOut.md)
- [VehicleImuStatus](../msg_docs/VehicleImuStatus.md)
- [SensorMag](../msg_docs/SensorMag.md)
- [QshellRetval](../msg_docs/QshellRetval.md)
- [SensorTemp](../msg_docs/SensorTemp.md)
- [RaptorInput](../msg_docs/RaptorInput.md)
- [DebugVect](../msg_docs/DebugVect.md)
- [EstimatorAidSource2d](../msg_docs/EstimatorAidSource2d.md)
- [ActuatorTest](../msg_docs/ActuatorTest.md)
- [VelocityLimits](../msg_docs/VelocityLimits.md)
- [ControlAllocatorStatus](../msg_docs/ControlAllocatorStatus.md)
- [SensorBaro](../msg_docs/SensorBaro.md)
- [Ping](../msg_docs/Ping.md)
- [RtlTimeEstimate](../msg_docs/RtlTimeEstimate.md)
- [DistanceSensorModeChangeRequest](../msg_docs/DistanceSensorModeChangeRequest.md)
- [UavcanParameterRequest](../msg_docs/UavcanParameterRequest.md)
- [UlogStream](../msg_docs/UlogStream.md)
- [VehicleMagnetometer](../msg_docs/VehicleMagnetometer.md)
- [EstimatorSelectorStatus](../msg_docs/EstimatorSelectorStatus.md)
- [EstimatorSensorBias](../msg_docs/EstimatorSensorBias.md)
- [VehicleLocalPositionSetpoint](../msg_docs/VehicleLocalPositionSetpoint.md)
- [SensorUwb](../msg_docs/SensorUwb.md)
- [SensorAccelFifo](../msg_docs/SensorAccelFifo.md)
- [FuelTankStatus](../msg_docs/FuelTankStatus.md)
- [SensorsStatus](../msg_docs/SensorsStatus.md)
- [BatteryInfo](../msg_docs/BatteryInfo.md)
- [EscReport](../msg_docs/EscReport.md)
- [LoggerStatus](../msg_docs/LoggerStatus.md)
- [SensorGnssStatus](../msg_docs/SensorGnssStatus.md)
- [ParameterUpdate](../msg_docs/ParameterUpdate.md)
- [Vtx](../msg_docs/Vtx.md)
- [InternalCombustionEngineStatus](../msg_docs/InternalCombustionEngineStatus.md)
- [VehicleLocalPositionV0](../msg_docs/VehicleLocalPositionV0.md)
- [LandingGearWheel](../msg_docs/LandingGearWheel.md)
- [TrajectorySetpoint6dof](../msg_docs/TrajectorySetpoint6dof.md)
- [SensorGyroFifo](../msg_docs/SensorGyroFifo.md)
- [LandingTargetInnovations](../msg_docs/LandingTargetInnovations.md)
- [ActuatorServosTrim](../msg_docs/ActuatorServosTrim.md)
- [VehicleAngularVelocity](../msg_docs/VehicleAngularVelocity.md)
- [RaptorStatus](../msg_docs/RaptorStatus.md)
- [GimbalControls](../msg_docs/GimbalControls.md)
- [TaskStackInfo](../msg_docs/TaskStackInfo.md)
- [OpenDroneIdArmStatus](../msg_docs/OpenDroneIdArmStatus.md)
- [OpenDroneIdSelfId](../msg_docs/OpenDroneIdSelfId.md)
- [ManualControlSwitches](../msg_docs/ManualControlSwitches.md)
- [VehicleAirData](../msg_docs/VehicleAirData.md)
- [CameraCapture](../msg_docs/CameraCapture.md)
- [EscStatus](../msg_docs/EscStatus.md)
- [RegisterExtComponentRequestV0](../msg_docs/RegisterExtComponentRequestV0.md)
- [RoverAttitudeStatus](../msg_docs/RoverAttitudeStatus.md)
- [CellularStatus](../msg_docs/CellularStatus.md)
- [RateCtrlStatus](../msg_docs/RateCtrlStatus.md)
- [FollowTargetEstimator](../msg_docs/FollowTargetEstimator.md)
- [DronecanNodeStatus](../msg_docs/DronecanNodeStatus.md)
- [EventV0](../msg_docs/EventV0.md)
- [InternalCombustionEngineControl](../msg_docs/InternalCombustionEngineControl.md)
- [FlightPhaseEstimation](../msg_docs/FlightPhaseEstimation.md)
- [VehicleCommandAckV0](../msg_docs/VehicleCommandAckV0.md)
- [FigureEightStatus](../msg_docs/FigureEightStatus.md)
- [RoverRateStatus](../msg_docs/RoverRateStatus.md)
- [OrbitStatus](../msg_docs/OrbitStatus.md)
- [PwmInput](../msg_docs/PwmInput.md)
- [PpsCapture](../msg_docs/PpsCapture.md)
- [HomePositionV0](../msg_docs/HomePositionV0.md)
- [HealthReport](../msg_docs/HealthReport.md)
- [DifferentialPressure](../msg_docs/DifferentialPressure.md)
- [VehicleStatusV1](../msg_docs/VehicleStatusV1.md)
- [NormalizedUnsignedSetpoint](../msg_docs/NormalizedUnsignedSetpoint.md)
- [ArmingCheckRequestV0](../msg_docs/ArmingCheckRequestV0.md)
- [RcChannels](../msg_docs/RcChannels.md)
- [SensorGnssRelative](../msg_docs/SensorGnssRelative.md)
- [OrbTest](../msg_docs/OrbTest.md)
- [MountOrientation](../msg_docs/MountOrientation.md)
- [GimbalManagerSetAttitude](../msg_docs/GimbalManagerSetAttitude.md)
- [GpsInjectData](../msg_docs/GpsInjectData.md)
- [CameraTrigger](../msg_docs/CameraTrigger.md)
- [RegisterExtComponentReplyV0](../msg_docs/RegisterExtComponentReplyV0.md)
- [GpioIn](../msg_docs/GpioIn.md)
- [OrbTestMedium](../msg_docs/OrbTestMedium.md)
- [OpenDroneIdSystem](../msg_docs/OpenDroneIdSystem.md)
- [DeviceInformation](../msg_docs/DeviceInformation.md)
- [EstimatorBias3d](../msg_docs/EstimatorBias3d.md)
- [TiltrotorExtraControls](../msg_docs/TiltrotorExtraControls.md)
- [SensorPreflightMag](../msg_docs/SensorPreflightMag.md)
- [DebugKeyValue](../msg_docs/DebugKeyValue.md)
:::
+6 -6
View File
@@ -22,11 +22,11 @@ Published by the vehicle's allocation and consumed by the ESC protocol drivers e
## Constants
| Name | Type | Value | Description |
| --------------------------------------------------------------- | -------- | ----- | --------------------------------- |
| Name | Type | Value | Description |
| --------------------------------------------------------------- | -------- | ----- | ----------- |
| <a id="#MESSAGE_VERSION"></a> MESSAGE_VERSION | `uint32` | 0 |
| <a id="#ACTUATOR_FUNCTION_MOTOR1"></a> ACTUATOR_FUNCTION_MOTOR1 | `uint8` | 101 | output_functions.yaml Motor.start |
| <a id="#NUM_CONTROLS"></a> NUM_CONTROLS | `uint8` | 12 | output_functions.yaml Motor.count |
| <a id="#ACTUATOR_FUNCTION_MOTOR1"></a> ACTUATOR_FUNCTION_MOTOR1 | `uint8` | 101 |
| <a id="#NUM_CONTROLS"></a> NUM_CONTROLS | `uint8` | 12 |
## Source Message
@@ -47,9 +47,9 @@ uint64 timestamp_sample # [us] Sampling timestamp of the data this control respo
uint16 reversible_flags # [-] Bitset indicating which motors are configured to be reversible
uint8 ACTUATOR_FUNCTION_MOTOR1 = 101 # output_functions.yaml Motor.start
uint8 ACTUATOR_FUNCTION_MOTOR1 = 101
uint8 NUM_CONTROLS = 12 # output_functions.yaml Motor.count
uint8 NUM_CONTROLS = 12
float32[12] control # [@range -1, 1] Normalized thrust. Where 1 means maximum positive thrust, -1 maximum negative (if not supported by the output, <0 maps to NaN). NaN maps to disarmed (stop the motors)
```
+23 -2
View File
@@ -29,7 +29,17 @@ pageClass: is-wide-page
| Name | Type | Value | Description |
| --------------------------------------------------------------------------- | ------- | ----- | ---------------------------------------------------------------------------- |
| <a id="#ACTUATOR_FUNCTION_MOTOR1"></a> ACTUATOR_FUNCTION_MOTOR1 | `uint8` | 101 |
| <a id="#ACTUATOR_FUNCTION_MOTOR_MAX"></a> ACTUATOR_FUNCTION_MOTOR_MAX | `uint8` | 112 | output_functions.yaml Motor.start + Motor.count - 1 |
| <a id="#ACTUATOR_FUNCTION_MOTOR2"></a> ACTUATOR_FUNCTION_MOTOR2 | `uint8` | 102 |
| <a id="#ACTUATOR_FUNCTION_MOTOR3"></a> ACTUATOR_FUNCTION_MOTOR3 | `uint8` | 103 |
| <a id="#ACTUATOR_FUNCTION_MOTOR4"></a> ACTUATOR_FUNCTION_MOTOR4 | `uint8` | 104 |
| <a id="#ACTUATOR_FUNCTION_MOTOR5"></a> ACTUATOR_FUNCTION_MOTOR5 | `uint8` | 105 |
| <a id="#ACTUATOR_FUNCTION_MOTOR6"></a> ACTUATOR_FUNCTION_MOTOR6 | `uint8` | 106 |
| <a id="#ACTUATOR_FUNCTION_MOTOR7"></a> ACTUATOR_FUNCTION_MOTOR7 | `uint8` | 107 |
| <a id="#ACTUATOR_FUNCTION_MOTOR8"></a> ACTUATOR_FUNCTION_MOTOR8 | `uint8` | 108 |
| <a id="#ACTUATOR_FUNCTION_MOTOR9"></a> ACTUATOR_FUNCTION_MOTOR9 | `uint8` | 109 |
| <a id="#ACTUATOR_FUNCTION_MOTOR10"></a> ACTUATOR_FUNCTION_MOTOR10 | `uint8` | 110 |
| <a id="#ACTUATOR_FUNCTION_MOTOR11"></a> ACTUATOR_FUNCTION_MOTOR11 | `uint8` | 111 |
| <a id="#ACTUATOR_FUNCTION_MOTOR12"></a> ACTUATOR_FUNCTION_MOTOR12 | `uint8` | 112 |
| <a id="#FAILURE_OVER_CURRENT"></a> FAILURE_OVER_CURRENT | `uint8` | 0 | (1 << 0) |
| <a id="#FAILURE_OVER_VOLTAGE"></a> FAILURE_OVER_VOLTAGE | `uint8` | 1 | (1 << 1) |
| <a id="#FAILURE_MOTOR_OVER_TEMPERATURE"></a> FAILURE_MOTOR_OVER_TEMPERATURE | `uint8` | 2 | (1 << 2) |
@@ -62,8 +72,19 @@ uint8 esc_cmdcount # Counter of number of commands
uint8 esc_state # State of ESC - depend on Vendor
uint8 actuator_function # actuator output function (one of Motor1...MotorN)
uint8 ACTUATOR_FUNCTION_MOTOR1 = 101
uint8 ACTUATOR_FUNCTION_MOTOR_MAX = 112 # output_functions.yaml Motor.start + Motor.count - 1
uint8 ACTUATOR_FUNCTION_MOTOR2 = 102
uint8 ACTUATOR_FUNCTION_MOTOR3 = 103
uint8 ACTUATOR_FUNCTION_MOTOR4 = 104
uint8 ACTUATOR_FUNCTION_MOTOR5 = 105
uint8 ACTUATOR_FUNCTION_MOTOR6 = 106
uint8 ACTUATOR_FUNCTION_MOTOR7 = 107
uint8 ACTUATOR_FUNCTION_MOTOR8 = 108
uint8 ACTUATOR_FUNCTION_MOTOR9 = 109
uint8 ACTUATOR_FUNCTION_MOTOR10 = 110
uint8 ACTUATOR_FUNCTION_MOTOR11 = 111
uint8 ACTUATOR_FUNCTION_MOTOR12 = 112
uint16 failures # Bitmask to indicate the internal ESC faults
int8 esc_power # Applied power 0-100 in % (negative values reserved)
@@ -26,8 +26,6 @@ This power module has integrated power distribution board and provides regulated
## Wiring/Connections
![pm06_pin_map](../../assets/hardware/power_module/holybro_pm06/pm06_pin_map.jpg)
Wiring and connection examples can be found in: [Pixhawk 4 Mini > Power](../assembly/quick_start_pixhawk4_mini.md#power).
This image shows the wiring and connections for the [Pixhawk 4 Mini](https://docs.px4.io/v1.16/en/assembly/quick_start_pixhawk4_mini#power) (discontinued).
![Pixhawk 4 - Power Management Board](../../assets/hardware/power_module/holybro_pm06/pixhawk4mini_power_management.png)
<img src="../../assets/hardware/power_module/holybro_pm06/pm06_pin_map.jpg" width="450px" title="pm06" />
-4
View File
@@ -27,9 +27,5 @@
},
"devDependencies": {
"prettier": "^3.2.0"
},
"resolutions": {
"markdown-it": "^14.1.1",
"esbuild": "^0.25.0"
}
}
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
+445 -487
View File
File diff suppressed because it is too large Load Diff
@@ -1,229 +0,0 @@
#!/usr/bin/env python
################################################################################################
# @File MissionCheck.py
# Automated mission loading, execution and monitoring
# for Continuous Integration
#
# @author Sander Smeets <sander@droneslab.com>
#
# Code partly based on DroneKit (c) Copyright 2015-2016, 3D Robotics.
################################################################################################
################################################################################################
# Settings
################################################################################################
from __future__ import print_function
connection_string = '127.0.0.1:14540'
import_mission_filename = 'VTOL_TAKEOFF.mission'
max_execution_time = 200
alt_acceptance_radius = 5
################################################################################################
# Init
################################################################################################
# Import DroneKit-Python
from dronekit import connect, Command, VehicleMode
from pymavlink import mavutil
import time, sys, argparse, json
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--connect", help="connection string")
parser.add_argument("-f", "--filename", help="mission filename")
parser.add_argument("-t", "--timeout", help="execution timeout", type=float)
parser.add_argument("-a", "--altrad", help="altitude acceptance radius", type=float)
args = parser.parse_args()
if args.connect:
connection_string = args.connect
if args.filename:
import_mission_filename = args.filename
if args.timeout:
max_execution_time = args.timeout
if args.altrad:
alt_acceptance_radius = args.altrad
mission_failed = False
MAV_MODE_AUTO = 4
# start time counter
start_time = time.time()
elapsed_time = time.time() - start_time
# Connect to the Vehicle
print("Connecting")
vehicle = connect(connection_string, wait_ready=True)
while not vehicle.system_status.state == "STANDBY" or vehicle.gps_0.fix_type < 3:
if time.time() - start_time > 20:
print("FAILED: SITL did not reach standby with GPS fix within 20 seconds")
sys.exit(98)
print("Waiting for vehicle to initialise... %s " % vehicle.system_status.state)
time.sleep(1)
# Display basic vehicle state
print(" Type: %s" % vehicle._vehicle_type)
print(" Armed?: %s" % vehicle.armed)
print(" System status: %s" % vehicle.system_status.state)
print(" GPS: %s" % vehicle.gps_0)
print(" Alt: %s" % vehicle.location.global_relative_frame.alt)
################################################################################################
# Functions
################################################################################################
def read_mission_json(f):
d = json.load(f)
current = True
missionlist=[]
for wp in d['items']:
cmd = Command( 0, 0, 0, int(wp['frame']), int(wp['command']), current, int(wp['autoContinue']), float(wp['param1']), float(wp['param2']), float(wp['param3']), float(wp['param4']), float(wp['coordinate'][0]), float(wp['coordinate'][1]), float(wp['coordinate'][2]))
missionlist.append(cmd)
if current:
current = False
return missionlist
def upload_mission(aFileName):
"""
Upload a mission from a file.
"""
#Read mission from file
with open(aFileName) as f:
missionlist = read_mission_json(f)
#Clear existing mission from vehicle
cmds = vehicle.commands
cmds.clear()
#Add new mission to vehicle
for command in missionlist:
cmds.add(command)
print(' Uploaded mission with %s items' % len(missionlist))
vehicle.commands.upload()
return missionlist
################################################################################################
# Listeners
################################################################################################
current_sequence = -1
current_sequence_changed = False
current_landed_state = -1
home_position_set = False
#Create a message listener for mission sequence number
@vehicle.on_message('MISSION_CURRENT')
def listener(self, name, mission_current):
global current_sequence, current_sequence_changed
if (current_sequence != mission_current.seq):
current_sequence = mission_current.seq;
current_sequence_changed = True
print('current mission sequence: %s' % mission_current.seq)
#Create a message listener for mission sequence number
@vehicle.on_message('EXTENDED_SYS_STATE')
def listener(self, name, extended_sys_state):
global current_landed_state
if (current_landed_state != extended_sys_state.landed_state):
current_landed_state = extended_sys_state.landed_state;
#Create a message listener for home position fix
@vehicle.on_message('HOME_POSITION')
def listener(self, name, home_position):
global home_position_set
home_position_set = True
################################################################################################
# Start mission test
################################################################################################
while not home_position_set:
if time.time() - start_time > 30:
print("FAILED: getting home position 30 seconds")
sys.exit(98)
print("Waiting for home position...")
time.sleep(1)
#Upload mission from file
missionlist = upload_mission(import_mission_filename)
time.sleep(2)
# set mission mode
vehicle.mode = VehicleMode("MISSION")
time.sleep(1)
# Arm vehicle
vehicle.armed = True
while not vehicle.system_status.state == "ACTIVE":
if time.time() - start_time > 30:
print("FAILED: vehicle did not arm within 30 seconds")
sys.exit(98)
print("Waiting for vehicle to arm...")
time.sleep(1)
# Wait for completion of mission items
while (current_sequence < len(missionlist)-1 and elapsed_time < max_execution_time):
time.sleep(.2)
if current_sequence > 0 and current_sequence_changed:
if missionlist[current_sequence-1].z - alt_acceptance_radius > vehicle.location.global_relative_frame.alt or missionlist[current_sequence-1].z + alt_acceptance_radius < vehicle.location.global_relative_frame.alt:
print("waypoint %s out of bounds altitude %s gps altitude: %s" % (current_sequence, missionlist[current_sequence-1].z, vehicle.location.global_relative_frame.alt))
mission_failed = True
current_sequence_changed = False
elapsed_time = time.time() - start_time
if elapsed_time < max_execution_time:
print("Mission items have been executed")
# wait for the vehicle to have landed
while (current_landed_state != 1 and elapsed_time < max_execution_time):
time.sleep(1)
elapsed_time = time.time() - start_time
if elapsed_time < max_execution_time:
print("Vehicle has landed")
# Disarm vehicle
vehicle.armed = False
# count elapsed time
elapsed_time = time.time() - start_time
# Close vehicle object before exiting script
vehicle.close()
time.sleep(2)
# Validate time constraint
if elapsed_time <= max_execution_time and not mission_failed:
print("Mission succesful time elapsed %s" % elapsed_time)
sys.exit(0)
if elapsed_time > max_execution_time:
print("Mission FAILED to execute within %s seconds" % max_execution_time)
sys.exit(99)
if mission_failed:
print("Mission FAILED out of bounds")
sys.exit(100)
print("Mission FAILED something strange happened")
sys.exit(101)
@@ -1,89 +0,0 @@
{
"MAV_AUTOPILOT": 12,
"complexItems": [
],
"groundStation": "QGroundControl",
"items": [
{
"autoContinue": true,
"command": 84,
"coordinate": [
47.397510528564453,
8.5502662658691406,
10
],
"frame": 3,
"id": 1,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
47.395450592041016,
8.5501842498779297,
10
],
"frame": 3,
"id": 2,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 16,
"coordinate": [
47.395420809467687,
8.5456138849258423,
10
],
"frame": 3,
"id": 3,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
{
"autoContinue": true,
"command": 85,
"coordinate": [
47.397735595703125,
8.5456113815307617,
10
],
"frame": 3,
"id": 4,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
}
],
"plannedHomePosition": {
"autoContinue": true,
"command": 16,
"coordinate": [
47.39659309387207,
8.5479388236999512,
0
],
"frame": 0,
"id": 0,
"param1": 0,
"param2": 0,
"param3": 0,
"param4": 0,
"type": "missionItem"
},
"version": "1.0"
}
@@ -1 +0,0 @@
TODO: Adopt to new SITL
@@ -1,197 +0,0 @@
#!/usr/bin/env python
#***************************************************************************
#
# Copyright (c) 2015 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#***************************************************************************/
#
# @author Andreas Antener <andreas@uaventure.com>
#
import rospy
import threading
from px4.msg import vehicle_local_position
from gazebo_msgs.srv import SpawnModel
from gazebo_msgs.srv import SetModelState
from gazebo_msgs.srv import DeleteModel
from geometry_msgs.msg import Pose
from geometry_msgs.msg import Twist
from numpy import linalg
import numpy as np
#
# Helper to test if vehicle stays on expected flight path.
#
class FlightPathAssertion(threading.Thread):
#
# Arguments
# - positions: tuple of tuples in the form (x, y, z, heading)
#
# TODO: yaw validation
# TODO: fail main test thread
#
def __init__(self, positions, tunnelRadius=1, yaw_offset=0.2):
threading.Thread.__init__(self)
rospy.Subscriber("vehicle_local_position", vehicle_local_position, self.position_callback)
self.spawn_model = rospy.ServiceProxy('/gazebo/spawn_sdf_model', SpawnModel)
self.set_model_state = rospy.ServiceProxy('/gazebo/set_model_state', SetModelState)
self.delete_model = rospy.ServiceProxy('/gazebo/delete_model', DeleteModel)
self.positions = positions
self.tunnel_radius = tunnelRadius
self.yaw_offset = yaw_offset
self.has_pos = False
self.should_stop = False
self.center = positions[0]
self.end_of_segment = False
self.failed = False
self.local_position = vehicle_local_position
def position_callback(self, data):
self.has_pos = True
self.local_position = data
def spawn_indicator(self):
self.delete_model("indicator")
xml = (
"<?xml version='1.0'?>" +
"<sdf version='1.4'>" +
"<model name='indicator'>" +
"<static>true</static>" +
"<link name='link'>" +
"<visual name='visual'>" +
"<transparency>0.7</transparency>" +
"<geometry>" +
"<sphere>" +
"<radius>%f</radius>" +
"</sphere>" +
"</geometry>" +
"<material>" +
"<ambient>1 0 0 0.5</ambient>" +
"<diffuse>1 0 0 0.5</diffuse>" +
"</material>" +
"</visual>" +
"</link>" +
"</model>" +
"</sdf>") % self.tunnel_radius
self.spawn_model("indicator", xml, "", Pose(), "")
def position_indicator(self):
state = SetModelState()
state.model_name = "indicator"
pose = Pose()
pose.position.x = self.center[0]
pose.position.y = (-1) * self.center[1]
pose.position.z = (-1) * self.center[2]
state.pose = pose
state.twist = Twist()
state.reference_frame = ""
self.set_model_state(state)
def distance_to_line(self, a, b, pos):
v = b - a
w = pos - a
c1 = np.dot(w, v)
if c1 <= 0: # before a
self.center = a
return linalg.norm(pos - a)
c2 = np.dot(v, v)
if c2 <= c1: # after b
self.center = b
self.end_of_segment = True
return linalg.norm(pos - b)
x = c1 / c2
l = a + x * v
self.center = l
return linalg.norm(pos - l)
def stop(self):
self.should_stop = True
def run(self):
rate = rospy.Rate(10) # 10hz
self.spawn_indicator()
current = 0
count = 0
while not self.should_stop:
if self.has_pos:
# calculate distance to line segment between first two points
# if distances > tunnel_radius
# exit with error
# advance current pos if not on the line anymore or distance to next point < tunnel_radius
# exit if current pos is now the last position
self.position_indicator()
pos = np.array((self.local_position.x,
self.local_position.y,
self.local_position.z))
a_pos = np.array((self.positions[current][0],
self.positions[current][1],
self.positions[current][2]))
b_pos = np.array((self.positions[current + 1][0],
self.positions[current + 1][1],
self.positions[current + 1][2]))
dist = self.distance_to_line(a_pos, b_pos, pos)
b_dist = linalg.norm(pos - b_pos)
rospy.logdebug("distance to line: %f, distance to end: %f" % (dist, b_dist))
if dist > self.tunnel_radius:
msg = "left tunnel at position (%f, %f, %f)" % (self.local_position.x, self.local_position.y, self.local_position.z)
rospy.logerr(msg)
self.failed = True
break
if self.end_of_segment or b_dist < self.tunnel_radius:
rospy.loginfo("next segment")
self.end_of_segment = False
current = current + 1
if current == len(self.positions) - 1:
rospy.loginfo("no more positions")
break
rate.sleep()
count = count + 1
if count > 10 and not self.has_pos: # no position after 1 sec
rospy.logerr("no position")
self.failed = True
break
@@ -1,168 +0,0 @@
#!/usr/bin/env python
#***************************************************************************
#
# Copyright (c) 2015 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#***************************************************************************/
#
# @author Andreas Antener <andreas@uaventure.com>
#
import rospy
from px4.msg import manual_control_setpoint
from px4.msg import offboard_control_mode
from mav_msgs.msg import CommandAttitudeThrust
from std_msgs.msg import Header
#
# Manual input control helper
#
class ManualInput(object):
def __init__(self):
rospy.init_node('test_node', anonymous=True)
self.pub_mcsp = rospy.Publisher('manual_control_setpoint', manual_control_setpoint, queue_size=10)
self.pub_off = rospy.Publisher('offboard_control_mode', offboard_control_mode, queue_size=10)
def arm(self):
rate = rospy.Rate(10) # 10hz
att = CommandAttitudeThrust()
att.header = Header()
pos = manual_control_setpoint()
pos.x = 0
pos.z = 0
pos.y = 0
pos.r = 0
pos.mode_switch = 3
pos.return_switch = 3
pos.posctl_switch = 3
pos.loiter_switch = 3
pos.acro_switch = 0
pos.offboard_switch = 3
count = 0
while not rospy.is_shutdown() and count < 5:
rospy.loginfo("zeroing")
time = rospy.get_rostime().now()
pos.timestamp = time.secs * 1e6 + time.nsecs / 1000
self.pub_mcsp.publish(pos)
rate.sleep()
count = count + 1
pos.r = 1
count = 0
while not rospy.is_shutdown() and count < 5:
rospy.loginfo("arming")
time = rospy.get_rostime().now()
pos.timestamp = time.secs * 1e6 + time.nsecs / 1000
self.pub_mcsp.publish(pos)
rate.sleep()
count = count + 1
def posctl(self):
rate = rospy.Rate(10) # 10hz
# triggers posctl
pos = manual_control_setpoint()
pos.x = 0
pos.z = 0
pos.y = 0
pos.r = 0
pos.mode_switch = 2
pos.return_switch = 3
pos.posctl_switch = 1
pos.loiter_switch = 3
pos.acro_switch = 0
pos.offboard_switch = 3
count = 0
while not rospy.is_shutdown() and count < 5:
rospy.loginfo("triggering posctl")
time = rospy.get_rostime().now()
pos.timestamp = time.secs * 1e6 + time.nsecs / 1000
self.pub_mcsp.publish(pos)
rate.sleep()
count = count + 1
def offboard_attctl(self):
self.offboard(False, False, True, True, True, True)
def offboard_posctl(self):
self.offboard(False, False, True, False, True, True)
# Trigger offboard and set offboard control mode before
def offboard(self, ignore_thrust=False, ignore_attitude=False, ignore_bodyrate=True,
ignore_position=False, ignore_velocity=True, ignore_acceleration_force=True):
rate = rospy.Rate(10) # 10hz
mode = offboard_control_mode()
mode.ignore_thrust = ignore_thrust
mode.ignore_attitude = ignore_attitude
mode.ignore_bodyrate_x = ignore_bodyrate
mode.ignore_bodyrate_y = ignore_bodyrate
mode.ignore_bodyrate_z = ignore_bodyrate
mode.ignore_position = ignore_position
mode.ignore_velocity = ignore_velocity
mode.ignore_acceleration_force = ignore_acceleration_force
count = 0
while not rospy.is_shutdown() and count < 5:
rospy.loginfo("setting offboard mode")
time = rospy.get_rostime().now()
mode.timestamp = time.secs * 1e6 + time.nsecs / 1000
self.pub_off.publish(mode)
rate.sleep()
count = count + 1
# triggers offboard
pos = manual_control_setpoint()
pos.x = 0
pos.z = 0
pos.y = 0
pos.r = 0
pos.mode_switch = 3
pos.return_switch = 3
pos.posctl_switch = 3
pos.loiter_switch = 3
pos.acro_switch = 0
pos.offboard_switch = 1
count = 0
while not rospy.is_shutdown() and count < 5:
rospy.loginfo("triggering offboard")
time = rospy.get_rostime().now()
pos.timestamp = time.secs * 1e6 + time.nsecs / 1000
self.pub_mcsp.publish(pos)
rate.sleep()
count = count + 1
@@ -1,110 +0,0 @@
#!/usr/bin/env python
#***************************************************************************
#
# Copyright (c) 2015 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#***************************************************************************/
#
# @author Andreas Antener <andreas@uaventure.com>
#
PKG = 'px4'
import unittest
import rospy
import rosbag
from px4.msg import vehicle_local_position
from px4.msg import vehicle_attitude_setpoint
from px4.msg import vehicle_attitude
from px4.msg import vehicle_local_position_setpoint
from threading import Condition
#
# Test helper
#
class PX4TestHelper(object):
def __init__(self, test_name):
self.test_name = test_name
def setUp(self):
self.condition = Condition()
self.closed = False
rospy.init_node('test_node', anonymous=True)
self.bag = rosbag.Bag(self.test_name + '.bag', 'w', compression="lz4")
self.sub_vlp = rospy.Subscriber("iris/vehicle_local_position",
vehicle_local_position, self.vehicle_position_callback)
self.sub_vasp = rospy.Subscriber("iris/vehicle_attitude_setpoint",
vehicle_attitude_setpoint, self.vehicle_attitude_setpoint_callback)
self.sub_va = rospy.Subscriber("iris/vehicle_attitude",
vehicle_attitude, self.vehicle_attitude_callback)
self.sub_vlps = rospy.Subscriber("iris/vehicle_local_position_setpoint",
vehicle_local_position_setpoint, self.vehicle_local_position_setpoint_callback)
def tearDown(self):
try:
self.condition.acquire()
self.closed = True
self.sub_vlp.unregister()
self.sub_vasp.unregister()
self.sub_va.unregister()
self.sub_vlps.unregister()
self.bag.close()
finally:
self.condition.release()
def vehicle_position_callback(self, data):
self.bag_write('px4/vehicle_local_position', data)
def vehicle_attitude_setpoint_callback(self, data):
self.bag_write('px4/vehicle_attitude_setpoint', data)
def vehicle_attitude_callback(self, data):
self.bag_write('px4/vehicle_attitude', data)
def vehicle_local_position_setpoint_callback(self, data):
self.bag_write('px4/vehicle_local_position_setpoint', data)
def bag_write(self, topic, data):
try:
self.condition.acquire()
if not self.closed:
self.bag.write(topic, data)
else:
rospy.logwarn("Trying to write to bag but it's already closed")
finally:
self.condition.release()
+12 -1
View File
@@ -11,8 +11,19 @@ uint8 esc_cmdcount # Counter of number of commands
uint8 esc_state # State of ESC - depend on Vendor
uint8 actuator_function # actuator output function (one of Motor1...MotorN)
uint8 ACTUATOR_FUNCTION_MOTOR1 = 101
uint8 ACTUATOR_FUNCTION_MOTOR_MAX = 112 # output_functions.yaml Motor.start + Motor.count - 1
uint8 ACTUATOR_FUNCTION_MOTOR2 = 102
uint8 ACTUATOR_FUNCTION_MOTOR3 = 103
uint8 ACTUATOR_FUNCTION_MOTOR4 = 104
uint8 ACTUATOR_FUNCTION_MOTOR5 = 105
uint8 ACTUATOR_FUNCTION_MOTOR6 = 106
uint8 ACTUATOR_FUNCTION_MOTOR7 = 107
uint8 ACTUATOR_FUNCTION_MOTOR8 = 108
uint8 ACTUATOR_FUNCTION_MOTOR9 = 109
uint8 ACTUATOR_FUNCTION_MOTOR10 = 110
uint8 ACTUATOR_FUNCTION_MOTOR11 = 111
uint8 ACTUATOR_FUNCTION_MOTOR12 = 112
uint16 failures # Bitmask to indicate the internal ESC faults
int8 esc_power # Applied power 0-100 in % (negative values reserved)
+2 -2
View File
@@ -10,7 +10,7 @@ uint64 timestamp_sample # [us] Sampling timestamp of the data this control respo
uint16 reversible_flags # [-] Bitset indicating which motors are configured to be reversible
uint8 ACTUATOR_FUNCTION_MOTOR1 = 101 # output_functions.yaml Motor.start
uint8 ACTUATOR_FUNCTION_MOTOR1 = 101
uint8 NUM_CONTROLS = 12 # output_functions.yaml Motor.count
uint8 NUM_CONTROLS = 12
float32[12] control # [@range -1, 1] Normalized thrust. Where 1 means maximum positive thrust, -1 maximum negative (if not supported by the output, <0 maps to NaN). NaN maps to disarmed (stop the motors)
@@ -645,7 +645,7 @@ int uORBTest::UnitTest::test_wrap_around()
}
#define CHECK_COPY(i_got, i_correct) \
orb_copy(ORB_ID(orb_test_medium_wrap_around), sfd, &u); \
if ((i_got) != (i_correct)) { \
if (i_got != i_correct) { \
return test_fail("got wrong element from the queue (got %i, should be %i)", i_got, i_correct); \
}
@@ -875,7 +875,7 @@ int uORBTest::UnitTest::test_queue()
}
#define CHECK_COPY(i_got, i_correct) \
orb_copy(ORB_ID(orb_test_medium_queue), sfd, &u); \
if ((i_got) != (i_correct)) { \
if (i_got != i_correct) { \
return test_fail("got wrong element from the queue (got %i, should be %i)", i_got, i_correct); \
}
@@ -1,11 +0,0 @@
#!/usr/bin/env bash
set -e
rm -rf build
(mkdir -p build && cd build && CXX=g++ cmake .. && make -j8 && time $@ ./test/lockstep_scheduler_test)
rm -rf build
(mkdir -p build && cd build && CXX=clang++ cmake .. && make -j8 && time $@ ./test/lockstep_scheduler_test)
rm -rf build
@@ -88,7 +88,7 @@ typedef enum : int32_t {
TRIGGER_MODE_DISTANCE_ON_CMD
} trigger_mode_t;
#define commandParamToInt(n) static_cast<int>((n) >= 0 ? (n) + 0.5f : (n) - 0.5f)
#define commandParamToInt(n) static_cast<int>(n >= 0 ? n + 0.5f : n - 0.5f)
class CameraTrigger final : public px4::ScheduledWorkItem
{
@@ -232,9 +232,6 @@ class SourceParser(object):
# start waiting for the next part - long comment.
if state == "wait-short-end":
state = "wait-long"
if state == "wait-long-end":
# Long description includes empty lines
long_desc += "\n"
else:
m = self.re_comment_tag.match(comment_content)
if m:
+2 -2
View File
@@ -51,8 +51,8 @@
# define debug(fmt, args...) do { } while(0)
#endif
#define CODER_CHECK(_c) do { if ((_c)->dead) { PX4_ERR("coder dead"); return -1; }} while(0)
#define CODER_KILL(_c, _reason) do { PX4_ERR("killed: %s", _reason); (_c)->dead = true; return -1; } while(0)
#define CODER_CHECK(_c) do { if (_c->dead) { PX4_ERR("coder dead"); return -1; }} while(0)
#define CODER_KILL(_c, _reason) do { PX4_ERR("killed: %s", _reason); _c->dead = true; return -1; } while(0)
static int
read_x(bson_decoder_t decoder, void *p, size_t s)
+1 -1
View File
@@ -46,7 +46,7 @@
#include <errno.h>
#define BEAT_TIME_CONVERSION_MS (60 * 1000 * 4)
#define BEAT_TIME_CONVERSION_US (BEAT_TIME_CONVERSION_MS * 1000)
#define BEAT_TIME_CONVERSION_US BEAT_TIME_CONVERSION_MS * 1000
#define BEAT_TIME_CONVERSION BEAT_TIME_CONVERSION_US
// semitone offsets from C for the characters 'A'-'G'
+1 -1
View File
@@ -2016,7 +2016,7 @@ void Commander::run()
_vehicle_status.timestamp = hrt_absolute_time();
_vehicle_status_pub.publish(_vehicle_status);
_failure_detector.publishStatus(_health_and_arming_checks.getEscArmStatus(), _health_and_arming_checks.getMotorFailureMask());
_failure_detector.publishStatus();
}
checkWorkerThread();
@@ -109,9 +109,6 @@ public:
const failsafe_flags_s &failsafeFlags() const { return _failsafe_flags; }
uint16_t getMotorFailureMask() const {return _esc_checks.getMotorFailureMask(); }
bool getEscArmStatus() const { return _esc_checks.getEscArmStatus(); }
#ifndef CONSTRAINED_FLASH
ExternalChecks &externalChecks() { return _external_checks; }
#endif
@@ -37,13 +37,13 @@ void ArmPermissionChecks::checkAndReport(const Context &context, Report &reporte
{
if (_param_com_armable.get() < 1) {
/* EVENT
* @description
* Vehicle is in safety configuration and denies arming.
*
* <profile name="dev">
* This check can be configured via <param>COM_ARMABLE</param> parameter.
* </profile>
*/
* @description
* Vehicle is in safety configuration and denies arming.
*
* <profile name="dev">
* This check can be configured via <param>COM_ARMABLE</param> parameter.
* </profile>
*/
reporter.armingCheckFailure(NavModes::All, health_component_t::system,
events::ID("check_armable_configuration"),
events::Log::Error, "Vehicle is in safety configuration");
@@ -211,13 +211,13 @@ void BatteryChecks::checkAndReport(const Context &context, Report &reporter)
// This is declared critical so QGC displays a yellow box and reads "low battery" out loud making the user aware
/* EVENT
* @description
* The lowest battery state of charge is below the low threshold.
*
* <profile name="dev">
* Can be configured with <param>BAT_LOW_THR</param>.
* </profile>
*/
* @description
* The lowest battery state of charge is below the low threshold.
*
* <profile name="dev">
* Can be configured with <param>BAT_LOW_THR</param>.
* </profile>
*/
reporter.armingCheckFailure(affected_modes, health_component_t::battery, events::ID("check_battery_low"),
events::Log::Critical, "Low battery");
@@ -229,13 +229,13 @@ void BatteryChecks::checkAndReport(const Context &context, Report &reporter)
case battery_status_s::WARNING_CRITICAL:
/* EVENT
* @description
* The lowest battery state of charge is below the critical threshold.
*
* <profile name="dev">
* Can be configured with <param>BAT_CRIT_THR</param> and from when to disalow arming with <param>COM_ARM_BAT_MIN</param>.
* </profile>
*/
* @description
* The lowest battery state of charge is below the critical threshold.
*
* <profile name="dev">
* Can be configured with <param>BAT_CRIT_THR</param> and from when to disalow arming with <param>COM_ARM_BAT_MIN</param>.
* </profile>
*/
reporter.armingCheckFailure(affected_modes, health_component_t::battery, events::ID("check_battery_critical"),
events::Log::Critical, "Critical battery");
@@ -247,13 +247,13 @@ void BatteryChecks::checkAndReport(const Context &context, Report &reporter)
case battery_status_s::WARNING_EMERGENCY:
/* EVENT
* @description
* The lowest battery state of charge is below the emergency threshold.
*
* <profile name="dev">
* Can be configured with <param>BAT_EMERGEN_THR</param>.
* </profile>
*/
* @description
* The lowest battery state of charge is below the emergency threshold.
*
* <profile name="dev">
* Can be configured with <param>BAT_EMERGEN_THR</param>.
* </profile>
*/
reporter.armingCheckFailure(affected_modes, health_component_t::battery, events::ID("check_battery_emergency"),
events::Log::Emergency, "Emergency battery level");
@@ -62,6 +62,7 @@ static constexpr const char *esc_fault_reason_str(esc_fault_reason_t esc_fault_r
case esc_fault_reason_t::esc_warn_temp: return "over temperature";
case esc_fault_reason_t::esc_over_temp: return "critical temperature";
}
return "";
@@ -71,31 +72,19 @@ static constexpr const char *esc_fault_reason_str(esc_fault_reason_t esc_fault_r
void EscChecks::checkAndReport(const Context &context, Report &reporter)
{
const hrt_abstime now = hrt_absolute_time();
const hrt_abstime esc_telemetry_timeout =
700_ms; // Some DShot ESCs are unresponsive for ~550ms during their initialization, so we use a timeout higher than that
esc_status_s esc_status;
// Run motor status checks even when no new ESC data arrives (to detect timeouts)
if (_esc_status_sub.copy(&esc_status)) {
if (esc_status.esc_count <= 0) {
return;
}
if (_esc_status_sub.copy(&esc_status) && (now < esc_status.timestamp + esc_telemetry_timeout)) {
uint16_t mask = 0;
if (_param_com_arm_chk_escs.get() > 0) {
mask |= checkEscOnline(context, reporter, esc_status, now);
mask |= checkEscStatus(context, reporter, esc_status);
}
if (_param_fd_act_en.get() > 0) {
updateEscsStatus(context, reporter, esc_status, now);
mask |= checkMotorStatus(context, reporter, esc_status, now);
}
_motor_failure_mask = mask;
checkEscStatus(context, reporter, esc_status);
reporter.setIsPresent(health_component_t::motors_escs);
reporter.failsafeFlags().fd_motor_failure = (mask != 0);
} else if ((_param_com_arm_chk_escs.get() > 0) && now > _start_time + 3_s) { // Allow ESCs to init
} else if (_param_com_arm_chk_escs.get()
&& now - _start_time > 5_s) { // Wait a bit after startup to allow esc's to init
/* EVENT
* @description
* <profile name="dev">
@@ -111,240 +100,83 @@ void EscChecks::checkAndReport(const Context &context, Report &reporter)
}
}
uint16_t EscChecks::checkEscOnline(const Context &context, Report &reporter, const esc_status_s &esc_status, hrt_abstime now)
void EscChecks::checkEscStatus(const Context &context, Report &reporter, const esc_status_s &esc_status)
{
// Check if one or more the ESCs are offline
uint16_t mask = 0;
char esc_fail_msg[esc_status_s::CONNECTED_ESC_MAX * 6 + 1] = "";
const NavModes required_modes = _param_com_arm_chk_escs.get() ? NavModes::All : NavModes::None;
for (int esc_index = 0; esc_index < esc_status_s::CONNECTED_ESC_MAX; esc_index++) {
if (!math::isInRange(esc_status.esc[esc_index].actuator_function,
esc_report_s::ACTUATOR_FUNCTION_MOTOR1, esc_report_s::ACTUATOR_FUNCTION_MOTOR_MAX)) {
continue; // Skip unmapped ESC status entries
}
if (esc_status.esc_count > 0) {
// Check if one or more the ESCs are offline
char esc_fail_msg[50];
esc_fail_msg[0] = '\0';
const bool timeout = now > esc_status.esc[esc_index].timestamp + ESC_TIMEOUT_US;
const bool is_offline = (esc_status.esc_online_flags & (1 << esc_index)) == 0;
for (int i = 0; i < esc_status_s::CONNECTED_ESC_MAX; ++i) {
const bool mapped = math::isInRange(esc_status.esc[i].actuator_function, actuator_motors_s::ACTUATOR_FUNCTION_MOTOR1,
uint8_t(actuator_motors_s::ACTUATOR_FUNCTION_MOTOR1 + actuator_motors_s::NUM_CONTROLS - 1));
const bool offline = (esc_status.esc_online_flags & (1 << i)) == 0;
// Set failure bits for this motor
if (timeout || is_offline) {
mask |= (1u << esc_index);
uint8_t esc_nr = esc_index + 1;
/* EVENT
* @description
* <profile name="dev">
* This check can be configured via <param>COM_ARM_CHK_ESCS</param> parameter.
* </profile>
*/
reporter.healthFailure<uint8_t>(NavModes::All, health_component_t::motors_escs, events::ID("check_escs_offline"),
events::Log::Critical, "ESC {1} offline", esc_nr);
snprintf(esc_fail_msg + strlen(esc_fail_msg), sizeof(esc_fail_msg) - strlen(esc_fail_msg), "ESC%d ", esc_nr);
esc_fail_msg[sizeof(esc_fail_msg) - 1] = '\0';
}
}
if (reporter.mavlink_log_pub() && esc_fail_msg[0] != '\0') {
mavlink_log_critical(reporter.mavlink_log_pub(), "%soffline. %s\t", esc_fail_msg, context.isArmed() ? "Land now!" : "");
}
return mask;
}
uint16_t EscChecks::checkEscStatus(const Context &context, Report &reporter, const esc_status_s &esc_status)
{
uint16_t mask = 0;
for (int esc_index = 0; esc_index < esc_status_s::CONNECTED_ESC_MAX; esc_index++) {
if (!math::isInRange(esc_status.esc[esc_index].actuator_function,
esc_report_s::ACTUATOR_FUNCTION_MOTOR1, esc_report_s::ACTUATOR_FUNCTION_MOTOR_MAX)) {
continue; // Skip unmapped ESC status entries
}
const uint8_t actuator_function_index = esc_status.esc[esc_index].actuator_function - esc_report_s::ACTUATOR_FUNCTION_MOTOR1;
if (esc_status.esc[esc_index].failures == 0) {
continue;
} else {
mask |= (1u << actuator_function_index); // Set bit in mask
}
for (uint8_t fault_index = 0; fault_index <= static_cast<uint8_t>(esc_fault_reason_t::_max); fault_index++) {
if (!(esc_status.esc[esc_index].failures & (1 << fault_index))) {
continue;
}
esc_fault_reason_t fault_reason_index = static_cast<esc_fault_reason_t>(fault_index);
const char *user_action = "";
events::px4::enums::suggested_action_t action = events::px4::enums::suggested_action_t::none;
if (context.isArmed()) {
if (fault_reason_index == esc_fault_reason_t::motor_warn_temp
|| fault_reason_index == esc_fault_reason_t::esc_warn_temp
|| fault_reason_index == esc_fault_reason_t::over_rpm) {
user_action = "Reduce throttle";
action = events::px4::enums::suggested_action_t::reduce_throttle;
} else {
user_action = "Land now!";
action = events::px4::enums::suggested_action_t::land;
}
}
/* EVENT
* @description
* {3}
*
* <profile name="dev">
* This check can be configured via <param>COM_ARM_CHK_ESCS</param> parameter.
* </profile>
*/
reporter.healthFailure<uint8_t, events::px4::enums::esc_fault_reason_t, events::px4::enums::suggested_action_t>(
NavModes::All, health_component_t::motors_escs, events::ID("check_failure_detector_arm_esc"),
events::Log::Critical, "ESC {1}: {2}", esc_index + 1, fault_reason_index, action);
if (reporter.mavlink_log_pub()) {
mavlink_log_emergency(reporter.mavlink_log_pub(), "ESC%d: %s. %s \t", esc_index + 1,
esc_fault_reason_str(fault_reason_index), user_action);
}
}
}
return mask;
}
uint16_t EscChecks::checkMotorStatus(const Context &context, Report &reporter, const esc_status_s &esc_status, hrt_abstime now)
{
uint16_t mask = 0;
// Only check while armed
if (context.status().arming_state == vehicle_status_s::ARMING_STATE_ARMED) {
actuator_motors_s actuator_motors{};
_actuator_motors_sub.copy(&actuator_motors);
// Check individual ESC reports
for (uint8_t i = 0; i < esc_status_s::CONNECTED_ESC_MAX; i++) {
if (!math::isInRange(esc_status.esc[i].actuator_function,
esc_report_s::ACTUATOR_FUNCTION_MOTOR1, esc_report_s::ACTUATOR_FUNCTION_MOTOR_MAX)) {
continue; // Skip unmapped ESC status entries
}
const uint8_t actuator_function_index = esc_status.esc[i].actuator_function - esc_report_s::ACTUATOR_FUNCTION_MOTOR1;
const float current = esc_status.esc[i].esc_current;
// First wait for ESC telemetry reporting non-zero current. Before that happens, don't check it.
if (current > FLT_EPSILON) {
_esc_has_reported_current[i] = true;
}
if (!_esc_has_reported_current[i]) {
continue;
}
// Current limits
float thrust = 0.f;
if (PX4_ISFINITE(actuator_motors.control[actuator_function_index])) {
// Normalized motor thrust commands before thrust model factor is applied, NAN means motor is turned off -> 0 thrust
thrust = fabsf(actuator_motors.control[actuator_function_index]);
}
bool current_too_low = current < (thrust * _param_motfail_c2t.get()) - _param_motfail_low_off.get();
bool current_too_high = current > (thrust * _param_motfail_c2t.get()) + _param_motfail_high_off.get();
_esc_undercurrent_hysteresis[i].set_hysteresis_time_from(false, _param_motfail_time.get() * 1_s);
_esc_overcurrent_hysteresis[i].set_hysteresis_time_from(false, _param_motfail_time.get() * 1_s);
if (!_esc_undercurrent_hysteresis[i].get_state()) {
// Only set, never clear mid-air: stopping the motor in response could make it appear healthy again
_esc_undercurrent_hysteresis[i].set_state_and_update(current_too_low, now);
}
if (!_esc_overcurrent_hysteresis[i].get_state()) {
// Only set, never clear mid-air: stopping the motor in response could make it appear healthy again
_esc_overcurrent_hysteresis[i].set_state_and_update(current_too_high, now);
}
mask |= (static_cast<uint16_t>(_esc_undercurrent_hysteresis[i].get_state()) << actuator_function_index);
mask |= (static_cast<uint16_t>(_esc_overcurrent_hysteresis[i].get_state()) << actuator_function_index);
if (_esc_undercurrent_hysteresis[i].get_state()) {
if (mapped && offline) {
/* EVENT
* @description
* <profile name="dev">
* This check can be configured via <param>FD_ACT_EN</param> parameter.
* </profile>
*/
reporter.healthFailure<uint8_t>(NavModes::All, health_component_t::motors_escs,
events::ID("check_motor_undercurrent"),
events::Log::Critical, "Motor {1} undercurrent detected", actuator_function_index + 1);
if (reporter.mavlink_log_pub()) {
mavlink_log_critical(reporter.mavlink_log_pub(), "Motor failure: Motor %d undercurrent detected",
actuator_function_index + 1);
}
* @description
* <profile name="dev">
* This check can be configured via <param>COM_ARM_CHK_ESCS</param> parameter.
* </profile>
*/
reporter.healthFailure<uint8_t>(required_modes, health_component_t::motors_escs, events::ID("check_escs_offline"),
events::Log::Critical, "ESC {1} offline", i + 1);
snprintf(esc_fail_msg + strlen(esc_fail_msg), sizeof(esc_fail_msg) - strlen(esc_fail_msg), "ESC%d ", i + 1);
esc_fail_msg[sizeof(esc_fail_msg) - 1] = '\0';
}
}
if (_esc_overcurrent_hysteresis[i].get_state()) {
/* EVENT
* @description
* <profile name="dev">
* This check can be configured via <param>FD_ACT_EN</param> parameter.
* </profile>
*/
reporter.healthFailure<uint8_t>(NavModes::All, health_component_t::motors_escs,
events::ID("check_motor_overcurrent"),
events::Log::Critical, "Motor {1} overcurrent detected", actuator_function_index + 1);
if ((esc_fail_msg[0] != '\0') && reporter.mavlink_log_pub()) {
mavlink_log_critical(reporter.mavlink_log_pub(), "%soffline. %s\t", esc_fail_msg, context.isArmed() ? "Land now!" : "");
}
if (reporter.mavlink_log_pub()) {
mavlink_log_critical(reporter.mavlink_log_pub(), "Motor failure: Motor %d overcurrent detected",
actuator_function_index + 1);
for (int index = 0; index < esc_status_s::CONNECTED_ESC_MAX; ++index) {
if (esc_status.esc[index].failures != 0) {
for (uint8_t fault_index = 0; fault_index <= static_cast<uint8_t>(esc_fault_reason_t::_max); fault_index++) {
if (esc_status.esc[index].failures & (1 << fault_index)) {
esc_fault_reason_t fault_reason_index = static_cast<esc_fault_reason_t>(fault_index);
const char *user_action = "";
events::px4::enums::suggested_action_t action = events::px4::enums::suggested_action_t::none;
if (context.isArmed()) {
if (fault_reason_index == esc_fault_reason_t::motor_warn_temp
|| fault_reason_index == esc_fault_reason_t::esc_warn_temp) {
user_action = "Reduce throttle";
action = events::px4::enums::suggested_action_t::reduce_throttle;
} else {
user_action = "Land now!";
action = events::px4::enums::suggested_action_t::land;
}
}
uint8_t motor_index = esc_status.esc[index].actuator_function - actuator_motors_s::ACTUATOR_FUNCTION_MOTOR1 + 1;
/* EVENT
* @description
* {3}
*
* <profile name="dev">
* This check can be configured via <param>COM_ARM_CHK_ESCS</param> parameter.
* </profile>
*/
reporter.healthFailure<uint8_t, events::px4::enums::esc_fault_reason_t, events::px4::enums::suggested_action_t>(
required_modes, health_component_t::motors_escs, events::ID("check_escs_fault"),
events::Log::Critical, "ESC {1}: {2}", motor_index, fault_reason_index, action);
if (reporter.mavlink_log_pub()) {
mavlink_log_emergency(reporter.mavlink_log_pub(), "ESC%d: %s. %s \t", motor_index,
esc_fault_reason_str(fault_reason_index), user_action);
}
}
}
}
}
} else { // Disarmed
for (uint8_t i = 0; i < esc_status_s::CONNECTED_ESC_MAX; ++i) {
_esc_undercurrent_hysteresis[i].set_state_and_update(false, now);
_esc_overcurrent_hysteresis[i].set_state_and_update(false, now);
}
}
return mask;
}
void EscChecks::updateEscsStatus(const Context &context, Report &reporter, const esc_status_s &esc_status, hrt_abstime now)
{
if (context.status().arming_state == vehicle_status_s::ARMING_STATE_ARMED) {
const int limited_esc_count = math::min(esc_status.esc_count, esc_status_s::CONNECTED_ESC_MAX);
const int all_escs_armed_mask = (1 << limited_esc_count) - 1;
const bool is_all_escs_armed = (all_escs_armed_mask == esc_status.esc_armed_flags);
_esc_arm_hysteresis.set_hysteresis_time_from(false, ESC_TIMEOUT_US);
_esc_arm_hysteresis.set_state_and_update(!is_all_escs_armed, now);
if (_esc_arm_hysteresis.get_state()) {
/* EVENT
* @description
* <profile name="dev">
* This check can be configured via <param>COM_ARM_CHK_ESCS</param> parameter.
* </profile>
*/
reporter.healthFailure(NavModes::All, health_component_t::motors_escs,
events::ID("check_escs_not_all_armed"),
events::Log::Critical, "Not all ESCs are armed");
if (reporter.mavlink_log_pub()) {
mavlink_log_critical(reporter.mavlink_log_pub(), "ESC failure: Not all ESCs are armed. Land now!");
}
reporter.failsafeFlags().fd_esc_arming_failure = true;
}
} else {
// reset ESC bitfield
_esc_arm_hysteresis.set_state_and_update(false, now);
reporter.failsafeFlags().fd_esc_arming_failure = false;
}
}
@@ -35,11 +35,8 @@
#include "../Common.hpp"
#include <lib/hysteresis/hysteresis.h>
#include <uORB/Subscription.hpp>
#include <uORB/topics/actuator_motors.h>
#include <uORB/topics/esc_status.h>
#include <uORB/topics/failure_detector_status.h>
class EscChecks : public HealthAndArmingCheckBase
{
@@ -49,33 +46,14 @@ public:
void checkAndReport(const Context &context, Report &reporter) override;
uint16_t getMotorFailureMask() const { return _motor_failure_mask; }
bool getEscArmStatus() const { return _esc_arm_hysteresis.get_state(); }
private:
uint16_t checkEscOnline(const Context &context, Report &reporter, const esc_status_s &esc_status, hrt_abstime now);
uint16_t checkEscStatus(const Context &context, Report &reporter, const esc_status_s &esc_status);
uint16_t checkMotorStatus(const Context &context, Report &reporter, const esc_status_s &esc_status, hrt_abstime now);
void updateEscsStatus(const Context &context, Report &reporter, const esc_status_s &esc_status, hrt_abstime now);
static constexpr hrt_abstime ESC_TIMEOUT_US = 300_ms;
void checkEscStatus(const Context &context, Report &reporter, const esc_status_s &esc_status);
uORB::Subscription _esc_status_sub{ORB_ID(esc_status)};
uORB::Subscription _actuator_motors_sub{ORB_ID(actuator_motors)};
const hrt_abstime _start_time{hrt_absolute_time()};
uint16_t _motor_failure_mask = 0;
bool _esc_has_reported_current[esc_status_s::CONNECTED_ESC_MAX] {};
systemlib::Hysteresis _esc_undercurrent_hysteresis[esc_status_s::CONNECTED_ESC_MAX];
systemlib::Hysteresis _esc_overcurrent_hysteresis[esc_status_s::CONNECTED_ESC_MAX];
systemlib::Hysteresis _esc_arm_hysteresis;
DEFINE_PARAMETERS_CUSTOM_PARENT(HealthAndArmingCheckBase,
(ParamBool<px4::params::COM_ARM_CHK_ESCS>) _param_com_arm_chk_escs,
(ParamBool<px4::params::FD_ACT_EN>) _param_fd_act_en,
(ParamFloat<px4::params::MOTFAIL_C2T>) _param_motfail_c2t,
(ParamFloat<px4::params::MOTFAIL_TIME>) _param_motfail_time,
(ParamFloat<px4::params::MOTFAIL_LOW_OFF>) _param_motfail_low_off,
(ParamFloat<px4::params::MOTFAIL_HIGH_OFF>) _param_motfail_high_off);
(ParamBool<px4::params::COM_ARM_CHK_ESCS>) _param_com_arm_chk_escs
)
};
@@ -98,6 +98,27 @@ void FailureDetectorChecks::checkAndReport(const Context &context, Report &repor
(vehicle_status_s::FAILURE_ROLL | vehicle_status_s::FAILURE_PITCH | vehicle_status_s::FAILURE_ALT |
vehicle_status_s::FAILURE_EXT);
reporter.failsafeFlags().fd_esc_arming_failure = context.status().failure_detector_status &
vehicle_status_s::FAILURE_ARM_ESC;
if (reporter.failsafeFlags().fd_esc_arming_failure) {
/* EVENT
* @description
* One or more ESCs failed to arm.
*
* <profile name="dev">
* This check can be configured via <param>FD_ESCS_EN</param> parameter.
* </profile>
*/
reporter.healthFailure(NavModes::All, health_component_t::motors_escs, events::ID("check_failure_detector_arm_esc"),
events::Log::Critical, "ESC failure");
if (reporter.mavlink_log_pub()) {
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: ESC failure detected");
}
}
reporter.failsafeFlags().fd_imbalanced_prop = context.status().failure_detector_status &
vehicle_status_s::FAILURE_IMBALANCED_PROP;
@@ -117,4 +138,22 @@ void FailureDetectorChecks::checkAndReport(const Context &context, Report &repor
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: Imbalanced propeller detected");
}
}
reporter.failsafeFlags().fd_motor_failure = context.status().failure_detector_status & vehicle_status_s::FAILURE_MOTOR;
if (reporter.failsafeFlags().fd_motor_failure) {
/* EVENT
* @description
* <profile name="dev">
* This check can be configured via <param>FD_ACT_EN</param> parameter.
* </profile>
*/
reporter.healthFailure(NavModes::All, health_component_t::motors_escs, events::ID("check_failure_detector_motor"),
events::Log::Critical, "Motor failure detected");
if (reporter.mavlink_log_pub()) {
mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: Motor failure detected");
}
}
}
@@ -80,9 +80,9 @@ void FlightTimeChecks::checkAndReport(const Context &context, Report &reporter)
}
/* EVENT
* @description
* Maximal flight time warning (less than 1min remaining)
*/
* @description
* Maximal flight time warning (less than 1min remaining)
*/
events::send<int16_t>(events::ID("commander_max_flight_time_warning_seconds"), events::Log::Warning,
"Approaching max flight time (system will RTL in {1} seconds)", floored_remaining_flight_time_sec);
@@ -97,9 +97,9 @@ void FlightTimeChecks::checkAndReport(const Context &context, Report &reporter)
}
/* EVENT
* @description
* Maximal flight time warning (more than 1min remaining)
*/
* @description
* Maximal flight time warning (more than 1min remaining)
*/
events::send<int16_t>(events::ID("commander_max_flight_time_warning_minutes"), events::Log::Warning,
"Approaching max flight time (system will RTL in {1} minutes)", floored_remaining_flight_time_min);
}
@@ -51,11 +51,11 @@ void GeofenceChecks::checkAndReport(const Context &context, Report &reporter)
if (geofence_result.geofence_max_dist_triggered) {
/* EVENT
* @description
* <profile name="dev">
* This check can be configured via <param>GF_ACTION</param> and <param>GF_MAX_HOR_DIST</param> parameters.
* </profile>
*/
* @description
* <profile name="dev">
* This check can be configured via <param>GF_ACTION</param> and <param>GF_MAX_HOR_DIST</param> parameters.
* </profile>
*/
reporter.armingCheckFailure(NavModes::All, health_component_t::system,
events::ID("check_gf_violation_max_hor_dist"),
events::Log::Error, "Geofence violation: exceeding maximum distance to Home");
@@ -67,11 +67,11 @@ void GeofenceChecks::checkAndReport(const Context &context, Report &reporter)
if (geofence_result.geofence_max_alt_triggered) {
/* EVENT
* @description
* <profile name="dev">
* This check can be configured via <param>GF_ACTION</param> and <param>GF_MAX_VER_DIST</param> parameters.
* </profile>
*/
* @description
* <profile name="dev">
* This check can be configured via <param>GF_ACTION</param> and <param>GF_MAX_VER_DIST</param> parameters.
* </profile>
*/
reporter.armingCheckFailure(NavModes::All, health_component_t::system,
events::ID("check_gf_violation_max_alt"),
events::Log::Error, "Geofence violation: exceeding maximum altitude above Home");
@@ -83,11 +83,11 @@ void GeofenceChecks::checkAndReport(const Context &context, Report &reporter)
if (geofence_result.geofence_custom_fence_triggered) {
/* EVENT
* @description
* <profile name="dev">
* This check can be configured via <param>GF_ACTION</param> parameter.
* </profile>
*/
* @description
* <profile name="dev">
* This check can be configured via <param>GF_ACTION</param> parameter.
* </profile>
*/
reporter.armingCheckFailure(NavModes::All, health_component_t::system,
events::ID("check_gf_violation_custom_gf"),
events::Log::Error, "Geofence violation: approaching or outside geofence");
@@ -1,104 +0,0 @@
/****************************************************************************
*
* Copyright (c) 2026 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Enable Actuator Failure check
*
* If enabled, the HealthAndArmingChecks will verify that for motors, a minimum amount of ESC current per throttle
* level is being consumed.
* Otherwise this indicates an motor failure.
* This check only works for ESCs that report current consumption.
*
* @boolean
*
* @group Motor Failure
*/
PARAM_DEFINE_INT32(FD_ACT_EN, 0);
/**
* Motor Failure Current/Throttle Scale
*
* Determines the slope between expected steady state current and linearized, normalized thrust command.
* E.g. FD_ACT_MOT_C2T A represents the expected steady state current at 100%.
* FD_ACT_LOW_OFF and FD_ACT_HIGH_OFF offset the threshold from that slope.
*
* @group Motor Failure
* @min 0.0
* @max 50.0
* @unit A/%
* @decimal 2
* @increment 1
*/
PARAM_DEFINE_FLOAT(MOTFAIL_C2T, 35.f);
/**
* Undercurrent motor failure limit offset
*
* threshold = FD_ACT_MOT_C2T * thrust - FD_ACT_LOW_OFF
*
* @group Motor Failure
* @min 0
* @max 30
* @unit A
* @decimal 2
* @increment 1
*/
PARAM_DEFINE_FLOAT(MOTFAIL_LOW_OFF, 10.f);
/**
* Overcurrent motor failure limit offset
*
* threshold = FD_ACT_MOT_C2T * thrust + FD_ACT_HIGH_OFF
*
* @group Motor Failure
* @min 0
* @max 30
* @unit A
* @decimal 2
* @increment 1
*/
PARAM_DEFINE_FLOAT(MOTFAIL_HIGH_OFF, 10.f);
/**
* Motor Failure Hysteresis Time
*
* Motor failure only triggers after current thresholds are exceeded for this time.
*
* @group Motor Failure
* @unit s
* @min 0.01
* @max 10
* @decimal 2
* @increment 1
*/
PARAM_DEFINE_FLOAT(MOTFAIL_TIME, 1.f);
@@ -39,7 +39,6 @@
*/
#include "FailureDetector.hpp"
#include "../HealthAndArmingChecks/HealthAndArmingChecks.hpp"
using namespace time_literals;
@@ -68,6 +67,21 @@ bool FailureDetector::update(const vehicle_status_s &vehicle_status, const vehic
_failure_detector_status.flags.ext = false;
}
// esc_status subscriber is shared between subroutines
esc_status_s esc_status;
if (_esc_status_sub.update(&esc_status)) {
_failure_injector.manipulateEscStatus(esc_status);
if (_param_escs_en.get()) {
updateEscsStatus(vehicle_status, esc_status);
}
if (_param_fd_act_en.get()) {
updateMotorStatus(vehicle_status, esc_status);
}
}
if (_param_fd_imb_prop_thr.get() > 0) {
updateImbalancedPropStatus();
}
@@ -75,19 +89,19 @@ bool FailureDetector::update(const vehicle_status_s &vehicle_status, const vehic
return _failure_detector_status.value != status_prev.value;
}
void FailureDetector::publishStatus(bool esc_arm_status, uint16_t motor_failure_mask)
void FailureDetector::publishStatus()
{
failure_detector_status_s failure_detector_status{};
failure_detector_status.fd_roll = _failure_detector_status.flags.roll;
failure_detector_status.fd_pitch = _failure_detector_status.flags.pitch;
failure_detector_status.fd_alt = _failure_detector_status.flags.alt;
failure_detector_status.fd_ext = _failure_detector_status.flags.ext;
failure_detector_status.fd_arm_escs = esc_arm_status || (motor_failure_mask != 0);
failure_detector_status.fd_arm_escs = _failure_detector_status.flags.arm_escs;
failure_detector_status.fd_battery = _failure_detector_status.flags.battery;
failure_detector_status.fd_imbalanced_prop = _failure_detector_status.flags.imbalanced_prop;
failure_detector_status.fd_motor = (motor_failure_mask != 0);
failure_detector_status.fd_motor = _failure_detector_status.flags.motor;
failure_detector_status.imbalanced_prop_metric = _imbalanced_prop_lpf.getState();
failure_detector_status.motor_failure_mask = motor_failure_mask;
failure_detector_status.motor_failure_mask = _motor_failure_mask;
failure_detector_status.motor_stop_mask = _failure_injector.getMotorStopMask();
failure_detector_status.timestamp = hrt_absolute_time();
_failure_detector_status_pub.publish(failure_detector_status);
@@ -158,6 +172,34 @@ void FailureDetector::updateExternalAtsStatus()
}
}
void FailureDetector::updateEscsStatus(const vehicle_status_s &vehicle_status, const esc_status_s &esc_status)
{
hrt_abstime now = hrt_absolute_time();
if (vehicle_status.arming_state == vehicle_status_s::ARMING_STATE_ARMED) {
const int limited_esc_count = math::min(esc_status.esc_count, esc_status_s::CONNECTED_ESC_MAX);
const int all_escs_armed_mask = (1 << limited_esc_count) - 1;
const bool is_all_escs_armed = (all_escs_armed_mask == esc_status.esc_armed_flags);
bool is_esc_failure = !is_all_escs_armed;
for (int i = 0; i < limited_esc_count; i++) {
is_esc_failure = is_esc_failure || (esc_status.esc[i].failures > 0);
}
_esc_failure_hysteresis.set_hysteresis_time_from(false, 300_ms);
_esc_failure_hysteresis.set_state_and_update(is_esc_failure, now);
if (_esc_failure_hysteresis.get_state()) {
_failure_detector_status.flags.arm_escs = true;
}
} else {
// reset ESC bitfield
_esc_failure_hysteresis.set_state_and_update(false, now);
_failure_detector_status.flags.arm_escs = false;
}
}
void FailureDetector::updateImbalancedPropStatus()
{
@@ -216,3 +258,82 @@ void FailureDetector::updateImbalancedPropStatus()
}
}
}
void FailureDetector::updateMotorStatus(const vehicle_status_s &vehicle_status, const esc_status_s &esc_status)
{
// 1. Telemetry times out -> communication or power lost on that ESC
// 2. Too low current draw compared to commanded thrust
// Overvoltage, overcurrent do not have checks yet esc_report.failures are handled separately
const hrt_abstime now = hrt_absolute_time();
// Only check while armed
if (vehicle_status.arming_state == vehicle_status_s::ARMING_STATE_ARMED) {
actuator_motors_s actuator_motors{};
_actuator_motors_sub.copy(&actuator_motors);
// Check individual ESC reports
for (uint8_t i = 0; i < esc_status_s::CONNECTED_ESC_MAX; ++i) {
// Map the esc status index to the actuator function index
const uint8_t actuator_function_index =
esc_status.esc[i].actuator_function - actuator_motors_s::ACTUATOR_FUNCTION_MOTOR1;
if (actuator_function_index >= actuator_motors_s::NUM_CONTROLS) {
continue; // Invalid mapping
}
const bool timeout = now > esc_status.esc[i].timestamp + 300_ms;
const float current = esc_status.esc[i].esc_current;
// First wait for ESC telemetry reporting non-zero current. Before that happens, don't check it.
if (current > FLT_EPSILON) {
_esc_has_reported_current[i] = true;
}
if (!_esc_has_reported_current[i]) {
continue;
}
_motor_failure_mask &= ~(1u << actuator_function_index); // Reset bit in mask to accumulate failures again
_motor_failure_mask |= (static_cast<uint16_t>(timeout) << actuator_function_index); // Telemetry timeout
// Current limits
float thrust = 0.f;
if (PX4_ISFINITE(actuator_motors.control[actuator_function_index])) {
// Normalized motor thrust commands before thrust model factor is applied, NAN means motor is turned off -> 0 thrust
thrust = fabsf(actuator_motors.control[actuator_function_index]);
}
bool thrust_above_threshold = thrust > _param_fd_act_mot_thr.get();
bool current_too_low = current < (thrust * _param_fd_act_mot_c2t.get()) - _param_fd_act_low_off.get();
bool current_too_high = current > (thrust * _param_fd_act_mot_c2t.get()) + _param_fd_act_high_off.get();
_esc_undercurrent_hysteresis[i].set_hysteresis_time_from(false, _param_fd_act_mot_tout.get() * 1_ms);
_esc_overcurrent_hysteresis[i].set_hysteresis_time_from(false, _param_fd_act_mot_tout.get() * 1_ms);
if (!_esc_undercurrent_hysteresis[i].get_state()) {
// Do not clear mid operation because a reaction could be to stop the motor and that would be conidered healthy again
_esc_undercurrent_hysteresis[i].set_state_and_update(thrust_above_threshold && current_too_low && !timeout, now);
}
if (!_esc_overcurrent_hysteresis[i].get_state()) {
// Do not clear mid operation because a reaction could be to stop the motor and that would be conidered healthy again
_esc_overcurrent_hysteresis[i].set_state_and_update(current_too_high && !timeout, now);
}
_motor_failure_mask |= (static_cast<uint16_t>(_esc_undercurrent_hysteresis[i].get_state()) << actuator_function_index);
_motor_failure_mask |= (static_cast<uint16_t>(_esc_overcurrent_hysteresis[i].get_state()) << actuator_function_index);
}
_failure_detector_status.flags.motor = (_motor_failure_mask != 0u);
} else { // Disarmed
for (uint8_t i = 0; i < esc_status_s::CONNECTED_ESC_MAX; ++i) {
_esc_undercurrent_hysteresis[i].set_state_and_update(false, now);
_esc_overcurrent_hysteresis[i].set_state_and_update(false, now);
}
_failure_detector_status.flags.motor = false;
}
}
@@ -53,6 +53,8 @@
// subscriptions
#include <uORB/Publication.hpp>
#include <uORB/Subscription.hpp>
#include <uORB/topics/actuator_motors.h>
#include <uORB/topics/esc_status.h>
#include <uORB/topics/failure_detector_status.h>
#include <uORB/topics/pwm_input.h>
#include <uORB/topics/sensor_selection.h>
@@ -68,8 +70,10 @@ union failure_detector_status_u {
uint16_t pitch : 1;
uint16_t alt : 1;
uint16_t ext : 1;
uint16_t arm_escs : 1;
uint16_t battery : 1;
uint16_t imbalanced_prop : 1;
uint16_t motor : 1;
} flags;
uint16_t value {0};
};
@@ -85,11 +89,13 @@ public:
bool update(const vehicle_status_s &vehicle_status, const vehicle_control_mode_s &vehicle_control_mode);
const failure_detector_status_u &getStatus() const { return _failure_detector_status; }
void publishStatus(bool esc_arm_status, uint16_t motor_failure_mask);
void publishStatus();
private:
void updateAttitudeStatus(const vehicle_status_s &vehicle_status);
void updateExternalAtsStatus();
void updateEscsStatus(const vehicle_status_s &vehicle_status, const esc_status_s &esc_status);
void updateMotorStatus(const vehicle_status_s &vehicle_status, const esc_status_s &esc_status);
void updateImbalancedPropStatus();
failure_detector_status_u _failure_detector_status{};
@@ -97,17 +103,25 @@ private:
systemlib::Hysteresis _roll_failure_hysteresis{false};
systemlib::Hysteresis _pitch_failure_hysteresis{false};
systemlib::Hysteresis _ext_ats_failure_hysteresis{false};
systemlib::Hysteresis _esc_failure_hysteresis{false};
static constexpr float _imbalanced_prop_lpf_time_constant{5.f};
AlphaFilter<float> _imbalanced_prop_lpf{};
uint32_t _selected_accel_device_id{0};
hrt_abstime _imu_status_timestamp_prev{0};
// Motor failure check
bool _esc_has_reported_current[esc_status_s::CONNECTED_ESC_MAX] {}; // true if ESC reported non-zero current before (some never report any)
systemlib::Hysteresis _esc_undercurrent_hysteresis[esc_status_s::CONNECTED_ESC_MAX];
systemlib::Hysteresis _esc_overcurrent_hysteresis[esc_status_s::CONNECTED_ESC_MAX];
uint16_t _motor_failure_mask = 0; // actuator function indexed
uORB::Subscription _vehicle_attitude_sub{ORB_ID(vehicle_attitude)};
uORB::Subscription _esc_status_sub{ORB_ID(esc_status)}; // TODO: multi-instance
uORB::Subscription _pwm_input_sub{ORB_ID(pwm_input)};
uORB::Subscription _sensor_selection_sub{ORB_ID(sensor_selection)};
uORB::Subscription _vehicle_imu_status_sub{ORB_ID(vehicle_imu_status)};
uORB::Subscription _actuator_motors_sub{ORB_ID(actuator_motors)};
uORB::Publication<failure_detector_status_s> _failure_detector_status_pub{ORB_ID(failure_detector_status)};
@@ -120,6 +134,15 @@ private:
(ParamFloat<px4::params::FD_FAIL_P_TTRI>) _param_fd_fail_p_ttri,
(ParamBool<px4::params::FD_EXT_ATS_EN>) _param_fd_ext_ats_en,
(ParamInt<px4::params::FD_EXT_ATS_TRIG>) _param_fd_ext_ats_trig,
(ParamInt<px4::params::FD_IMB_PROP_THR>) _param_fd_imb_prop_thr
(ParamInt<px4::params::FD_ESCS_EN>) _param_escs_en,
(ParamInt<px4::params::FD_IMB_PROP_THR>) _param_fd_imb_prop_thr,
// Actuator failure
(ParamBool<px4::params::FD_ACT_EN>) _param_fd_act_en,
(ParamFloat<px4::params::FD_ACT_MOT_THR>) _param_fd_act_mot_thr,
(ParamFloat<px4::params::FD_ACT_MOT_C2T>) _param_fd_act_mot_c2t,
(ParamInt<px4::params::FD_ACT_MOT_TOUT>) _param_fd_act_mot_tout,
(ParamFloat<px4::params::FD_ACT_LOW_OFF>) _param_fd_act_low_off,
(ParamFloat<px4::params::FD_ACT_HIGH_OFF>) _param_fd_act_high_off
)
};
@@ -39,6 +39,9 @@
* @author Mathieu Bresciani <brescianimathieu@gmail.com>
*/
#include <px4_platform_common/px4_config.h>
#include <parameters/param.h>
/**
* FailureDetector Max Roll
*
@@ -127,6 +130,18 @@ PARAM_DEFINE_INT32(FD_EXT_ATS_EN, 0);
*/
PARAM_DEFINE_INT32(FD_EXT_ATS_TRIG, 1900);
/**
* Enable checks on ESCs that report their arming state.
*
* If enabled, failure detector will verify that all the ESCs have successfully armed when the vehicle has transitioned to the armed state.
* Timeout for receiving an acknowledgement from the ESCs is 0.3s, if no feedback is received the failure detector will auto disarm the vehicle.
*
* @boolean
*
* @group Failure Detector
*/
PARAM_DEFINE_INT32(FD_ESCS_EN, 1);
/**
* Imbalanced propeller check threshold
*
@@ -141,3 +156,89 @@ PARAM_DEFINE_INT32(FD_EXT_ATS_TRIG, 1900);
* @group Failure Detector
*/
PARAM_DEFINE_INT32(FD_IMB_PROP_THR, 30);
/**
* Enable Actuator Failure check
*
* If enabled, failure detector will verify that for motors, a minimum amount of ESC current per throttle
* level is being consumed.
* Otherwise this indicates an motor failure.
*
* @boolean
* @reboot_required true
*
* @group Failure Detector
*/
PARAM_DEFINE_INT32(FD_ACT_EN, 0);
/**
* Motor Failure Thrust Threshold
*
* Failure detection per motor only triggers above this thrust value.
* Set to 1 to disable the detection.
*
* @group Failure Detector
* @unit norm
* @min 0.0
* @max 1.0
* @decimal 2
* @increment 0.01
*/
PARAM_DEFINE_FLOAT(FD_ACT_MOT_THR, 0.2f);
/**
* Motor Failure Current/Throttle Scale
*
* Determines the slope between expected steady state current and linearized, normalized thrust command.
* E.g. FD_ACT_MOT_C2T A represents the expected steady state current at 100%.
* FD_ACT_LOW_OFF and FD_ACT_HIGH_OFF offset the threshold from that slope.
*
* @group Failure Detector
* @min 0.0
* @max 50.0
* @unit A/%
* @decimal 2
* @increment 1
*/
PARAM_DEFINE_FLOAT(FD_ACT_MOT_C2T, 35.f);
/**
* Motor Failure Hysteresis Time
*
* Motor failure only triggers after current thresholds are exceeded for this time.
*
* @group Failure Detector
* @unit ms
* @min 10
* @max 10000
* @increment 100
*/
PARAM_DEFINE_INT32(FD_ACT_MOT_TOUT, 1000);
/**
* Undercurrent motor failure limit offset
*
* threshold = FD_ACT_MOT_C2T * thrust - FD_ACT_LOW_OFF
*
* @group Failure Detector
* @min 0
* @max 30
* @unit A
* @decimal 2
* @increment 1
*/
PARAM_DEFINE_FLOAT(FD_ACT_LOW_OFF, 10.f);
/**
* Overcurrent motor failure limit offset
*
* threshold = FD_ACT_MOT_C2T * thrust + FD_ACT_HIGH_OFF
*
* @group Failure Detector
* @min 0
* @max 30
* @unit A
* @decimal 2
* @increment 1
*/
PARAM_DEFINE_FLOAT(FD_ACT_HIGH_OFF, 10.f);
@@ -1,5 +1,6 @@
matplotlib==3.5.1
numpy==1.22.2
numpy==1.21.5
numpy_quaternion==2022.4.3
pyulog==0.9.0
scipy==1.8.0
+2 -4
View File
@@ -92,10 +92,8 @@ parameters:
by this parameter. The range sensor and vision options should only be used
when for operation over a flat surface as the local NED origin will move
up and down with ground level.
If GPS is set as reference and EKF2_GPS_CTRL is not 0, the GPS altitude is
still used to initiaize the bias of the other height sensors, regardless of
the altitude fusion bit in EKF2_GPS_CTRL.
If GPS is set as reference but altitude fusion is disabled in EKF2_GPS_CTRL,
the GPS altitude is still used to initiaize the bias of the other height sensors.
type: enum
values:
0: Barometric pressure
@@ -49,7 +49,6 @@ static const size_t N_DIST_SUBS = 4;
// for fault detection
// chi squared distribution, false alarm probability 0.0001
// see fault_table.py
// note skip 0 index so we can use degree of freedom as index
static const float BETA_TABLE[7] = {0,
8.82050518214,
@@ -1,13 +0,0 @@
#!/usr/bin/env python
from __future__ import print_function
import pylab as pl
import scipy.optimize
from scipy.stats import chi2
for fa_rate in 1.0/pl.array([1e1, 1e2, 1e4, 1e6, 1e9]):
print(fa_rate)
for df in range(1,7):
f_eq = lambda x: ((1- fa_rate) - chi2.cdf(x, df))**2
res = scipy.optimize.minimize(f_eq, df)
assert res['success']
print('\t', res.x[0])
+24 -26
View File
@@ -522,16 +522,9 @@ bool MavlinkLogHandler::log_entry_from_id(uint16_t log_id, LogEntry *entry)
return found_entry;
}
void MavlinkLogHandler::delete_all_logs(const char *dir, unsigned depth)
void MavlinkLogHandler::delete_all_logs(const char *dir)
{
// Log structure is log/yyyy-mm-dd/file.ulg (2 levels). Cap recursion to prevent stack overflow.
static constexpr unsigned MAX_DEPTH = 3;
if (depth >= MAX_DEPTH) {
PX4_DEBUG("Max depth reached: %s", dir);
return;
}
//-- Open log directory
DIR *dp = opendir(dir);
if (dp == nullptr) {
@@ -541,29 +534,34 @@ void MavlinkLogHandler::delete_all_logs(const char *dir, unsigned depth)
struct dirent *result = nullptr;
while ((result = readdir(dp))) {
if (strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0) {
continue;
// no more entries?
if (result == nullptr) {
break;
}
char filepath[PX4_MAX_FILEPATH];
int ret = snprintf(filepath, sizeof(filepath), "%s/%s", dir, result->d_name);
bool path_is_ok = (ret > 0) && (ret < (int)sizeof(filepath));
if (result->d_type == PX4LOG_DIRECTORY && result->d_name[0] != '.') {
char filepath[PX4_MAX_FILEPATH];
int ret = snprintf(filepath, sizeof(filepath), "%s/%s", dir, result->d_name);
bool path_is_ok = (ret > 0) && (ret < (int)sizeof(filepath));
if (!path_is_ok) {
continue;
}
if (path_is_ok) {
delete_all_logs(filepath);
if (result->d_type == PX4LOG_DIRECTORY) {
delete_all_logs(filepath, depth + 1);
if (rmdir(filepath)) {
PX4_DEBUG("Error removing %s", filepath);
if (rmdir(filepath)) {
PX4_DEBUG("Error removing %s", filepath);
}
}
}
} else {
if (unlink(filepath)) {
PX4_DEBUG("Error unlinking %s", filepath);
if (result->d_type == PX4LOG_REGULAR_FILE) {
char filepath[PX4_MAX_FILEPATH];
int ret = snprintf(filepath, sizeof(filepath), "%s/%s", dir, result->d_name);
bool path_is_ok = (ret > 0) && (ret < (int)sizeof(filepath));
if (path_is_ok) {
if (unlink(filepath)) {
PX4_DEBUG("Error unlinking %s", filepath);
}
}
}
}
+1 -1
View File
@@ -96,7 +96,7 @@ private:
bool log_entry_from_id(uint16_t log_id, LogEntry *entry);
// Log erase
void delete_all_logs(const char *dir, unsigned depth = 0);
void delete_all_logs(const char *dir);
private:
+2 -2
View File
@@ -102,8 +102,8 @@ private:
_interface[i].esc_online_flags = 0;
for (int j = 0; j < esc_status_s::CONNECTED_ESC_MAX; j++) {
bool is_motor = math::isInRange(esc.esc[j].actuator_function,
esc_report_s::ACTUATOR_FUNCTION_MOTOR1, esc_report_s::ACTUATOR_FUNCTION_MOTOR_MAX);
bool is_motor = ((int)esc.esc[j].actuator_function >= esc_report_s::ACTUATOR_FUNCTION_MOTOR1) &&
((int)esc.esc[j].actuator_function <= esc_report_s::ACTUATOR_FUNCTION_MOTOR12);
if (is_motor) {
// Map OutputFunction number to index
+2 -2
View File
@@ -84,8 +84,8 @@ private:
if (_esc_status_subs[i].update(&esc)) {
for (int j = 0; j < esc_status_s::CONNECTED_ESC_MAX; j++) {
const bool is_motor = math::isInRange(esc.esc[j].actuator_function,
esc_report_s::ACTUATOR_FUNCTION_MOTOR1, esc_report_s::ACTUATOR_FUNCTION_MOTOR_MAX);
bool is_motor = ((int)esc.esc[j].actuator_function >= esc_report_s::ACTUATOR_FUNCTION_MOTOR1) &&
((int)esc.esc[j].actuator_function <= esc_report_s::ACTUATOR_FUNCTION_MOTOR12);
if (is_motor) {
// Map OutputFunction number to index
@@ -118,7 +118,6 @@ else()
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/generate_dds_topics.py
--client-outdir ${CMAKE_CURRENT_BINARY_DIR}
--dds-topics-file ${CMAKE_CURRENT_SOURCE_DIR}/dds_topics.yaml
--whitelist-file ${CMAKE_CURRENT_SOURCE_DIR}/safety_whitelist.yaml
--template_file ${CMAKE_CURRENT_SOURCE_DIR}/dds_topics.h.em
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/generate_dds_topics.py
+3 -45
View File
@@ -180,10 +180,8 @@ struct RcvTopicsPubs {
@[ end for]@
uint32_t num_payload_received{};
bool _allow_publishing{false};
bool init(uxrSession *session, uxrStreamId reliable_out_stream_id, uxrStreamId reliable_in_stream_id, uxrStreamId best_effort_in_stream_id, uxrObjectId participant_id, const char *client_namespace);
void allow_publishing(bool enabled) { _allow_publishing = enabled; }
};
static void on_topic_update(uxrSession *session, uxrObjectId object_id, uint16_t request_id, uxrStreamId stream_id,
@@ -198,17 +196,10 @@ static void on_topic_update(uxrSession *session, uxrObjectId object_id, uint16_t
case @(idx)+ (65535U / 32U) + 1: {
@(sub['simple_base_type'])_s data;
@[ if sub['topic_simple'] in whitelist_topics]@
if (ucdr_deserialize_@(sub['simple_base_type'])(*ub, data, time_offset_us)) {
//print_message(ORB_ID(@(sub['simple_base_type'])), data);
pubs->@(sub['topic_simple'])_pub.publish(data);
}
@[ else]@
if (pubs->_allow_publishing && ucdr_deserialize_@(sub['simple_base_type'])(*ub, data, time_offset_us)) {
//print_message(ORB_ID(@(sub['simple_base_type'])), data);
pubs->@(sub['topic_simple'])_pub.publish(data);
}
@[ end if]@
}
break;
@@ -217,10 +208,9 @@ static void on_topic_update(uxrSession *session, uxrObjectId object_id, uint16_t
case @(idx + len(subscriptions))+ (65535U / 32U) + 1: {
@(sub['simple_base_type'])_s data;
if (ucdr_deserialize_@(sub['simple_base_type'])(*ub, data, time_offset_us)) {
//print_message(ORB_ID(@(sub['simple_base_type'])), data);
@[ if sub.get('route_field')]@
@[ if sub['topic_simple'] in whitelist_topics]@
if (ucdr_deserialize_@(sub['simple_base_type'])(*ub, data, time_offset_us)) {
//print_message(ORB_ID(@(sub['simple_base_type'])), data);
int instance = -1;
for (uint8_t i = 0; i < pubs->@(sub['topic_simple'])_demux.num_assigned; i++) {
@@ -238,42 +228,10 @@ static void on_topic_update(uxrSession *session, uxrObjectId object_id, uint16_t
if (instance >= 0) {
pubs->@(sub['topic_simple'])_pubs[instance].publish(data);
}
}
@[ else]@
if (pubs->_allow_publishing && ucdr_deserialize_@(sub['simple_base_type'])(*ub, data, time_offset_us)) {
//print_message(ORB_ID(@(sub['simple_base_type'])), data);
int instance = -1;
for (uint8_t i = 0; i < pubs->@(sub['topic_simple'])_demux.num_assigned; i++) {
if (pubs->@(sub['topic_simple'])_demux.assigned_ids[i] == data.@(sub['route_field'])) {
instance = i;
break;
}
}
if (instance < 0 && pubs->@(sub['topic_simple'])_demux.num_assigned < @(sub['max_instances'])) {
instance = pubs->@(sub['topic_simple'])_demux.num_assigned++;
pubs->@(sub['topic_simple'])_demux.assigned_ids[instance] = data.@(sub['route_field']);
}
if (instance >= 0) {
pubs->@(sub['topic_simple'])_pubs[instance].publish(data);
}
}
@[ end if]@
@[ else]@
@[ if sub['topic_simple'] in whitelist_topics]@
if (ucdr_deserialize_@(sub['simple_base_type'])(*ub, data, time_offset_us)) {
//print_message(ORB_ID(@(sub['simple_base_type'])), data);
pubs->@(sub['topic_simple'])_pub.publish(data);
}
@[ else]@
if (pubs->_allow_publishing && ucdr_deserialize_@(sub['simple_base_type'])(*ub, data, time_offset_us)) {
//print_message(ORB_ID(@(sub['simple_base_type'])), data);
pubs->@(sub['topic_simple'])_pub.publish(data);
}
@[ end if]@
@[ end if]@
}
}
break;
@@ -51,9 +51,6 @@ parser.add_argument("-t", "--template_file", dest='template_file', type=str,
parser.add_argument("-u", "--client-outdir", dest='clientdir', type=str,
help="Client output dir, by default using relative path 'src/modules/uxrce_dds_client'", default=None)
parser.add_argument("-w", "--whitelist-file", dest='whitelist_file', type=str,
help="Whitelist topics file path for topics that publish regardless of _allow_publishing flag",
default=None)
if len(sys.argv) <= 1:
parser.print_usage()
@@ -141,15 +138,6 @@ merged_em_globals['subscriptions_multi'] = subs_multi
merged_em_globals['type_includes'] = sorted(set(all_type_includes))
# Load whitelist topics that should not be fail-safed
whitelist_topics = set()
if args.whitelist_file and os.path.exists(args.whitelist_file):
with open(args.whitelist_file, 'r') as f:
whitelist_data = yaml.safe_load(f)
if whitelist_data and '__whitelist' in whitelist_data:
whitelist_topics = set(whitelist_data['__whitelist'])
merged_em_globals['whitelist_topics'] = whitelist_topics
# run interpreter
ofile = open(output_file, 'w')
-11
View File
@@ -153,14 +153,3 @@ parameters:
category: System
reboot_required: true
default: 0
UXRCE_DDS_SAFE:
description:
short: Enables offboard safety protection
long: |
If disable, allows offboard passthrough
even in non-offboard modes.
type: boolean
category: System
reboot_required: true
default: 1
@@ -1,4 +0,0 @@
module_name: uxrce_dds_client
__whitelist:
- vehicle_command
@@ -374,8 +374,6 @@ bool UxrceddsClient::setupSession(uxrSession *session)
}
_connected = true;
_safe_dds_mode = _param_uxrce_dds_safe.get();
return true;
}
@@ -653,16 +651,6 @@ void UxrceddsClient::run()
int bytes_available = 0;
// Update vehicle status to check for offboard mode
vehicle_status_s vehicle_status{};
_vehicle_status_sub.copy(&vehicle_status);
_offboard_mode_enabled = (vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_OFFBOARD);
// Allow publish from DDS to uORB if:
// - _param_uxrce_dds_safe is false , regardless of offboard mode
// - _param_uxrce_dds_safe is true AND offboard mode is enabled
_pubs->allow_publishing(!_safe_dds_mode || (_safe_dds_mode && _offboard_mode_enabled));
if (ioctl(_fd, FIONREAD, (unsigned long)&bytes_available) == OK) {
if (bytes_available > 10) {
orb_poll_timeout_ms = 0;
@@ -41,7 +41,6 @@
#include <uORB/topics/message_format_request.h>
#include <uORB/topics/message_format_response.h>
#include <uORB/Subscription.hpp>
#include <uORB/topics/vehicle_status.h>
#include <lib/timesync/Timesync.hpp>
@@ -139,7 +138,6 @@ private:
uORB::Publication<message_format_response_s> _message_format_response_pub{ORB_ID(message_format_response)};
uORB::Subscription _message_format_request_sub{ORB_ID(message_format_request)};
uORB::Subscription _vehicle_status_sub{ORB_ID(vehicle_status)};
/** Synchronizes the system clock if the time is off by more than 5 seconds */
void syncSystemClock(uxrSession *session);
@@ -204,8 +202,6 @@ private:
bool _connected{false};
bool _session_created{false};
bool _timesync_converged{false};
bool _offboard_mode_enabled{false};
bool _safe_dds_mode{true};
Timesync _timesync{timesync_status_s::SOURCE_PROTOCOL_DDS};
@@ -220,7 +216,6 @@ private:
(ParamInt<px4::params::UXRCE_DDS_SYNCT>) _param_uxrce_dds_synct,
(ParamInt<px4::params::UXRCE_DDS_TX_TO>) _param_uxrce_dds_tx_to,
(ParamInt<px4::params::UXRCE_DDS_RX_TO>) _param_uxrce_dds_rx_to,
(ParamInt<px4::params::UXRCE_DDS_FLCTRL>) _param_uxrce_dds_flctrl,
(ParamInt<px4::params::UXRCE_DDS_SAFE>) _param_uxrce_dds_safe
(ParamInt<px4::params::UXRCE_DDS_FLCTRL>) _param_uxrce_dds_flctrl
)
};