diff --git a/.github/workflows/dev_container.yml b/.github/workflows/dev_container.yml
index f64d29b684..b3f9542ead 100644
--- a/.github/workflows/dev_container.yml
+++ b/.github/workflows/dev_container.yml
@@ -96,6 +96,6 @@ jobs:
platforms: |
linux/amd64
provenance: mode=max
- push: true
+ push: ${{ github.event_name != 'pull_request' }}
cache-from: type=s3,blobs_prefix=cache/${{ github.repository }}/,manifests_prefix=cache/${{ github.repository }}/,region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }}
cache-to: type=s3,blobs_prefix=cache/${{ github.repository }}/,manifests_prefix=cache/${{ github.repository }}/,region=${{ env.RUNS_ON_AWS_REGION }},bucket=${{ env.RUNS_ON_S3_BUCKET_CACHE }},mode=max
diff --git a/.github/workflows/flash_analysis.yml b/.github/workflows/flash_analysis.yml
index 8ab97fdda8..da37dfa32d 100644
--- a/.github/workflows/flash_analysis.yml
+++ b/.github/workflows/flash_analysis.yml
@@ -1,5 +1,10 @@
name: FLASH usage analysis
+permissions:
+ contents: read
+ pull-requests: write
+ issues: write
+
on:
push:
branches:
@@ -83,59 +88,63 @@ jobs:
echo '${{ steps.bloaty-step.outputs.bloaty-summary-map }}' >> $GITHUB_OUTPUT
echo "$EOF" >> $GITHUB_OUTPUT
- post_pr_comment:
- name: Publish Results
- runs-on: [runs-on,runner=1cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
- needs: [analyze_flash]
- env:
- V5X-SUMMARY-MAP-ABS: ${{ fromJSON(fromJSON(needs.analyze_flash.outputs.px4_fmu-v5x-bloaty-summary-map).vm-absolute) }}
- V5X-SUMMARY-MAP-PERC: ${{ fromJSON(fromJSON(needs.analyze_flash.outputs.px4_fmu-v5x-bloaty-summary-map).vm-percentage) }}
- V6X-SUMMARY-MAP-ABS: ${{ fromJSON(fromJSON(needs.analyze_flash.outputs.px4_fmu-v6x-bloaty-summary-map).vm-absolute) }}
- V6X-SUMMARY-MAP-PERC: ${{ fromJSON(fromJSON(needs.analyze_flash.outputs.px4_fmu-v6x-bloaty-summary-map).vm-percentage) }}
- if: ${{ github.event.pull_request }}
- steps:
- - name: Find Comment
- uses: peter-evans/find-comment@v3
- id: fc
- with:
- issue-number: ${{ github.event.pull_request.number }}
- comment-author: 'github-actions[bot]'
- body-includes: FLASH Analysis
+ # TODO:
+ # This part of the workflow is causing errors, we should find a way to fix this and enable this test again
+ # Track this issue https://github.com/PX4/PX4-Autopilot/issues/24408
+ #
+ #post_pr_comment:
+ #name: Publish Results
+ #runs-on: [runs-on,runner=1cpu-linux-x64,image=ubuntu24-full-x64,"run-id=${{ github.run_id }}",spot=false]
+ #needs: [analyze_flash]
+ #env:
+ #V5X-SUMMARY-MAP-ABS: ${{ fromJSON(fromJSON(needs.analyze_flash.outputs.px4_fmu-v5x-bloaty-summary-map).vm-absolute) }}
+ #V5X-SUMMARY-MAP-PERC: ${{ fromJSON(fromJSON(needs.analyze_flash.outputs.px4_fmu-v5x-bloaty-summary-map).vm-percentage) }}
+ #V6X-SUMMARY-MAP-ABS: ${{ fromJSON(fromJSON(needs.analyze_flash.outputs.px4_fmu-v6x-bloaty-summary-map).vm-absolute) }}
+ #V6X-SUMMARY-MAP-PERC: ${{ fromJSON(fromJSON(needs.analyze_flash.outputs.px4_fmu-v6x-bloaty-summary-map).vm-percentage) }}
+ #if: ${{ github.event.pull_request }}
+ #steps:
+ #- name: Find Comment
+ #uses: peter-evans/find-comment@v3
+ #id: fc
+ #with:
+ #issue-number: ${{ github.event.pull_request.number }}
+ #comment-author: 'github-actions[bot]'
+ #body-includes: FLASH Analysis
- - name: Set Build Time
- id: bt
- run: |
- echo "timestamp=$(date +'%Y-%m-%dT%H:%M:%S')" >> $GITHUB_OUTPUT
+ #- name: Set Build Time
+ #id: bt
+ #run: |
+ #echo "timestamp=$(date +'%Y-%m-%dT%H:%M:%S')" >> $GITHUB_OUTPUT
- - name: Create or update comment
- # This can't be moved to the job-level conditions, as GH actions don't allow a job-level if condition to access the env.
- if: |
- steps.fc.outputs.comment-id != '' ||
- env.V5X-SUMMARY-MAP-ABS >= fromJSON(env.MIN_FLASH_POS_DIFF_FOR_COMMENT) ||
- env.V5X-SUMMARY-MAP-ABS <= fromJSON(env.MIN_FLASH_NEG_DIFF_FOR_COMMENT) ||
- env.V6X-SUMMARY-MAP-ABS >= fromJSON(env.MIN_FLASH_POS_DIFF_FOR_COMMENT) ||
- env.V6X-SUMMARY-MAP-ABS <= fromJSON(env.MIN_FLASH_NEG_DIFF_FOR_COMMENT)
- uses: peter-evans/create-or-update-comment@v4
- with:
- comment-id: ${{ steps.fc.outputs.comment-id }}
- issue-number: ${{ github.event.pull_request.number }}
- body: |
- ## 🔎 FLASH Analysis
-
- px4_fmu-v5x [Total VM Diff: ${{ env.V5X-SUMMARY-MAP-ABS }} byte (${{ env.V5X-SUMMARY-MAP-PERC}} %)]
+ #- name: Create or update comment
+ ## This can't be moved to the job-level conditions, as GH actions don't allow a job-level if condition to access the env.
+ #if: |
+ #steps.fc.outputs.comment-id != '' ||
+ #env.V5X-SUMMARY-MAP-ABS >= fromJSON(env.MIN_FLASH_POS_DIFF_FOR_COMMENT) ||
+ #env.V5X-SUMMARY-MAP-ABS <= fromJSON(env.MIN_FLASH_NEG_DIFF_FOR_COMMENT) ||
+ #env.V6X-SUMMARY-MAP-ABS >= fromJSON(env.MIN_FLASH_POS_DIFF_FOR_COMMENT) ||
+ #env.V6X-SUMMARY-MAP-ABS <= fromJSON(env.MIN_FLASH_NEG_DIFF_FOR_COMMENT)
+ #uses: peter-evans/create-or-update-comment@v4
+ #with:
+ #comment-id: ${{ steps.fc.outputs.comment-id }}
+ #issue-number: ${{ github.event.pull_request.number }}
+ #body: |
+ ### 🔎 FLASH Analysis
+ #
+ #px4_fmu-v5x [Total VM Diff: ${{ env.V5X-SUMMARY-MAP-ABS }} byte (${{ env.V5X-SUMMARY-MAP-PERC}} %)]
- ```
- ${{ needs.analyze_flash.outputs.px4_fmu-v5x-bloaty-output }}
- ```
-
+ #```
+ #${{ needs.analyze_flash.outputs.px4_fmu-v5x-bloaty-output }}
+ #```
+ #
-
- px4_fmu-v6x [Total VM Diff: ${{ env.V6X-SUMMARY-MAP-ABS }} byte (${{ env.V6X-SUMMARY-MAP-PERC }} %)]
+ #
+ #px4_fmu-v6x [Total VM Diff: ${{ env.V6X-SUMMARY-MAP-ABS }} byte (${{ env.V6X-SUMMARY-MAP-PERC }} %)]
- ```
- ${{ needs.analyze_flash.outputs.px4_fmu-v6x-bloaty-output }}
- ```
-
+ #```
+ #${{ needs.analyze_flash.outputs.px4_fmu-v6x-bloaty-output }}
+ #```
+ #
- **Updated: _${{ steps.bt.outputs.timestamp }}_**
- edit-mode: replace
+ #**Updated: _${{ steps.bt.outputs.timestamp }}_**
+ #edit-mode: replace
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 55362b1425..75fc8afb67 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -99,7 +99,7 @@
#
#=============================================================================
-cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
set(PX4_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE FILEPATH "PX4 source directory" FORCE)
set(PX4_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE FILEPATH "PX4 binary directory" FORCE)
diff --git a/Jenkinsfile b/Jenkinsfile
index 9e9f5787c8..fb092cd83d 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -235,9 +235,9 @@ pipeline {
sh('rm -f px4_msgs/srv/*.srv')
sh('rm -f px4_msgs/srv/versioned/*.srv')
sh('cp msg/*.msg px4_msgs/msg/')
- sh('mkdir -p px4_msgs/msg/versioned && cp msg/versioned/*.msg px4_msgs/msg/versioned/')
+ sh('cp msg/versioned/*.msg px4_msgs/msg/ || true')
sh('cp srv/*.srv px4_msgs/srv/')
- sh('mkdir -p px4_msgs/srv/versioned && cp srv/versioned/*.srv px4_msgs/srv/versioned/')
+ sh('cp srv/versioned/*.srv px4_msgs/srv/ || true')
sh('cd px4_msgs; git status; git add .; git commit -a -m "Update message definitions `date`" || true')
sh('cd px4_msgs; git push origin main || true')
sh('rm -rf px4_msgs')
diff --git a/Kconfig b/Kconfig
index f9f2e5e8ec..20ee4a2266 100644
--- a/Kconfig
+++ b/Kconfig
@@ -73,13 +73,6 @@ menu "Toolchain"
help
relative path to the ROMFS root directory
- config BOARD_ROOTFSDIR
- string "Root directory"
- depends on PLATFORM_POSIX
- default "."
- help
- Configure the root directory in the file system for PX4 files
-
config BOARD_IO
string "IO board name"
default "px4_io-v2_default"
diff --git a/MAINTAINERS.md b/MAINTAINERS.md
new file mode 100644
index 0000000000..426852e7b2
--- /dev/null
+++ b/MAINTAINERS.md
@@ -0,0 +1,42 @@
+Maintainers
+===========
+
+See [the documentation on Maintainers](https://docs.px4.io/main/en/contribute/maintainers.html) to learn about the role of the maintainers and the process to become one.
+
+**Active Maintainers**
+
+| Name | Sector | GitHub | Chat | email
+|-------------------------|--------|--------|------|----------------
+| Lorenz Meier | Founder | [LorenzMeier][LorenzMeier] | |
+| Daniel Agar | Architecture | [dagar][dagar] | daniel_agar |
+| Beat Küng | Architecture | [bkueng][bkueng] | beatkueng |
+| Ramón Roche | CI / Testing | [mrpollo][mrpollo] | rroche |
+| Mathieu Bresciani | State Estimation | [bresch][bresch] | mbresch |
+| Paul Riseborough | State Estimation | [priseborough][priseborough] | |
+| David Sidrane | RTOS / NuttX | [davids5][davids5] | david_s5 |
+| Jayoung Lim | Simulation | [Jaeyoung-Lim][Jaeyoung-Lim] | jaeyounglim. |
+| Beniamino Pozzan | ROS 2 | [beniaminopozzan][beniaminopozzan] | beniaminopozzan |
+| Matthias Grob | Multirotor | [MaEtUgR][MaEtUgR] | maetugr |
+| Silvan Fuhrer | Fixed-Wing / VTOL | [sfuhrer][sfuhrer] | sfuhrer |
+| Christian Friedrich | Rover | [chfriedrich98][chfriedrich98] | christian982564 |
+| Pedro Roque | Spacecraft | [Pedro-Roque][Pedro-Roque] | .pedroroque |
+
+
+**Documentation Maintainers**
+
+| Name | GitHub | Chat | email
+|------|--------|------|----------------------
+| Hamish Willee | [hamishwillee][hamishwillee] | hamishwillee |
+
+**Release Managers**
+
+| Name | GitHub | Chat | email
+|------|--------|------|----------------------
+| Ramón Roche | [mrpollo][mrpollo] | rroche |
+| Daniel Agar | [dagar][dagar] | daniel_agar |
+
+**Retired Maintainers**
+
+| Name | GitHub | Chat | email
+|------|--------|------|----------------------
+| | | |
diff --git a/Makefile b/Makefile
index f549e4c8ce..cfd87b6e23 100644
--- a/Makefile
+++ b/Makefile
@@ -404,7 +404,7 @@ check_newlines:
# Testing
# --------------------------------------------------------------------
-.PHONY: tests tests_coverage tests_mission tests_mission_coverage tests_offboard tests_avoidance
+.PHONY: tests tests_coverage tests_mission tests_mission_coverage tests_offboard
.PHONY: rostest python_coverage
tests:
@@ -457,10 +457,6 @@ tests_offboard: rostest
@"$(SRC_DIR)"/test/rostest_px4_run.sh mavros_posix_tests_offboard_posctl.test
@"$(SRC_DIR)"/test/rostest_px4_run.sh mavros_posix_tests_offboard_rpyrt_ctl.test
-tests_avoidance: rostest
- @"$(SRC_DIR)"/test/rostest_avoidance_run.sh mavros_posix_test_avoidance.test
- @"$(SRC_DIR)"/test/rostest_avoidance_run.sh mavros_posix_test_safe_landing.test
-
python_coverage:
@mkdir -p "$(SRC_DIR)"/build/python_coverage
@cd "$(SRC_DIR)"/build/python_coverage && cmake "$(SRC_DIR)" $(CMAKE_ARGS) -G"$(PX4_CMAKE_GENERATOR)" -DCONFIG=px4_sitl_default -DPYTHON_COVERAGE=ON
diff --git a/README.md b/README.md
index aef9e8f8a5..8353f3add6 100644
--- a/README.md
+++ b/README.md
@@ -17,17 +17,19 @@ PX4 is highly portable, OS-independent and supports Linux, NuttX and MacOS out o
* [VTOL](https://docs.px4.io/main/en/frames_vtol/)
* [Autogyro](https://docs.px4.io/main/en/frames_autogyro/)
* [Rover](https://docs.px4.io/main/en/frames_rover/)
- * many more experimental types (Blimps, Boats, Submarines, High altitude balloons, etc)
+ * many more experimental types (Blimps, Boats, Submarines, High Altitude Balloons, Spacecraft, etc)
* Releases: [Downloads](https://github.com/PX4/PX4-Autopilot/releases)
+## Releases
+
+Release notes and supporting information for PX4 releases can be found on the [Developer Guide](https://docs.px4.io/main/en/releases/).
## Building a PX4 based drone, rover, boat or robot
-The [PX4 User Guide](https://docs.px4.io/main/en/) explains how to assemble [supported vehicles](https://docs.px4.io/main/en/airframes/airframe_reference.html) and fly drones with PX4.
-See the [forum and chat](https://docs.px4.io/main/en/#getting-help) if you need help!
+The [PX4 User Guide](https://docs.px4.io/main/en/) explains how to assemble [supported vehicles](https://docs.px4.io/main/en/airframes/airframe_reference.html) and fly drones with PX4. See the [forum and chat](https://docs.px4.io/main/en/#getting-help) if you need help!
-## Changing code and contributing
+## Changing Code and Contributing
This [Developer Guide](https://docs.px4.io/main/en/development/development.html) is for software developers who want to modify the flight stack and middleware (e.g. to add new flight modes), hardware integrators who want to support new flight controller boards and peripherals, and anyone who wants to get PX4 working on a new (unsupported) airframe/vehicle.
@@ -35,7 +37,7 @@ Developers should read the [Guide for Contributions](https://docs.px4.io/main/en
See the [forum and chat](https://docs.px4.io/main/en/#getting-help) if you need help!
-### Weekly Dev Call
+## Weekly Dev Call
The PX4 Dev Team syncs up on a [weekly dev call](https://docs.px4.io/main/en/contribute/).
@@ -44,96 +46,17 @@ The PX4 Dev Team syncs up on a [weekly dev call](https://docs.px4.io/main/en/con
## Maintenance Team
-Note: This is the source of truth for the active maintainers of PX4 ecosystem.
+See the latest list of maintainers on [MAINTAINERS](MAINTAINERS.md) file at the root of the project.
-| Sector | Maintainer |
-|---|---|
-| Founder | [Lorenz Meier](https://github.com/LorenzMeier) |
-| Architecture | [Daniel Agar](https://github.com/dagar) / [Beat Küng](https://github.com/bkueng)|
-| State Estimation | [Mathieu Bresciani](https://github.com/bresch) / [Paul Riseborough](https://github.com/priseborough) |
-| OS/NuttX | [David Sidrane](https://github.com/davids5) |
-| Drivers | [Daniel Agar](https://github.com/dagar) |
-| Simulation | [Jaeyoung Lim](https://github.com/Jaeyoung-Lim) |
-| ROS2 | [Beniamino Pozzan](https://github.com/beniaminopozzan) |
-| Community QnA Call | [Ramon Roche](https://github.com/mrpollo) |
-| [Documentation](https://docs.px4.io/main/en/) | [Hamish Willee](https://github.com/hamishwillee) |
-
-| Vehicle Type | Maintainer |
-|---|---|
-| Multirotor | [Matthias Grob](https://github.com/MaEtUgR) |
-| Fixed Wing | [Thomas Stastny](https://github.com/tstastny) |
-| Hybrid VTOL | [Silvan Fuhrer](https://github.com/sfuhrer) |
-| Rover | [Christian Friedrich](https://github.com/chfriedrich98) |
-| Boat | x |
-
-
-See also [maintainers list](https://px4.io/community/maintainers/) (px4.io) and the [contributors list](https://github.com/PX4/PX4-Autopilot/graphs/contributors) (Github). However it may be not up to date.
+For the latest stats on contributors please see the latest stats for the Dronecode ecosystem in our project dashboard under [LFX Insights](https://insights.lfx.linuxfoundation.org/foundation/dronecode). For information on how to update your profile and affiliations please see the following support link on how to [Complete Your LFX Profile](https://docs.linuxfoundation.org/lfx/my-profile/complete-your-lfx-profile). Dronecode publishes a yearly snapshot of contributions and achievements on its [website under the Reports section](https://dronecode.org).
## Supported Hardware
-Pixhawk standard boards and proprietary boards are shown below (discontinued boards aren't listed).
-
-For the most up to date information, please visit [PX4 user Guide > Autopilot Hardware](https://docs.px4.io/main/en/flight_controller/).
-
-### Pixhawk Standard Boards
-
-These boards fully comply with Pixhawk Standard, and are maintained by the PX4-Autopilot maintainers and Dronecode team
-
-* FMUv6X and FMUv6C
- * [CUAV Pixahwk V6X (FMUv6X)](https://docs.px4.io/main/en/flight_controller/cuav_pixhawk_v6x.html)
- * [Holybro Pixhawk 6X (FMUv6X)](https://docs.px4.io/main/en/flight_controller/pixhawk6x.html)
- * [Holybro Pixhawk 6C (FMUv6C)](https://docs.px4.io/main/en/flight_controller/pixhawk6c.html)
- * [Holybro Pix32 v6 (FMUv6C)](https://docs.px4.io/main/en/flight_controller/holybro_pix32_v6.html)
-* FMUv5 and FMUv5X (STM32F7, 2019/20)
- * [Pixhawk 4 (FMUv5)](https://docs.px4.io/main/en/flight_controller/pixhawk4.html)
- * [Pixhawk 4 mini (FMUv5)](https://docs.px4.io/main/en/flight_controller/pixhawk4_mini.html)
- * [CUAV V5+ (FMUv5)](https://docs.px4.io/main/en/flight_controller/cuav_v5_plus.html)
- * [CUAV V5 nano (FMUv5)](https://docs.px4.io/main/en/flight_controller/cuav_v5_nano.html)
- * [Auterion Skynode (FMUv5X)](https://docs.auterion.com/avionics/skynode)
-* FMUv4 (STM32F4, 2015)
- * [Pixracer](https://docs.px4.io/main/en/flight_controller/pixracer.html)
- * [Pixhawk 3 Pro](https://docs.px4.io/main/en/flight_controller/pixhawk3_pro.html)
-* FMUv3 (STM32F4, 2014)
- * [Pixhawk 2](https://docs.px4.io/main/en/flight_controller/pixhawk-2.html)
- * [Pixhawk Mini](https://docs.px4.io/main/en/flight_controller/pixhawk_mini.html)
- * [CUAV Pixhack v3](https://docs.px4.io/main/en/flight_controller/pixhack_v3.html)
-* FMUv2 (STM32F4, 2013)
- * [Pixhawk](https://docs.px4.io/main/en/flight_controller/pixhawk.html)
-
-### Manufacturer supported
-
-These boards are maintained to be compatible with PX4-Autopilot by the Manufacturers.
-
-* [ARK Electronics ARKV6X](https://docs.px4.io/main/en/flight_controller/ark_v6x.html)
-* [CubePilot Cube Orange+](https://docs.px4.io/main/en/flight_controller/cubepilot_cube_orangeplus.html)
-* [CubePilot Cube Orange](https://docs.px4.io/main/en/flight_controller/cubepilot_cube_orange.html)
-* [CubePilot Cube Yellow](https://docs.px4.io/main/en/flight_controller/cubepilot_cube_yellow.html)
-* [Holybro Durandal](https://docs.px4.io/main/en/flight_controller/durandal.html)
-* [Airmind MindPX V2.8](http://www.mindpx.net/assets/accessories/UserGuide_MindPX.pdf)
-* [Airmind MindRacer V1.2](http://mindpx.net/assets/accessories/mindracer_user_guide_v1.2.pdf)
-* [Holybro Kakute F7](https://docs.px4.io/main/en/flight_controller/kakutef7.html)
-
-### Community supported
-
-These boards don't fully comply industry standards, and thus is solely maintained by the PX4 public community members.
-
-### Experimental
-
-These boards are not maintained by PX4 team nor Manufacturer, and is not guaranteed to be compatible with up to date PX4 releases.
-
-* [Raspberry PI with Navio 2](https://docs.px4.io/main/en/flight_controller/raspberry_pi_navio2.html)
-* [Bitcraze Crazyflie 2.0](https://docs.px4.io/main/en/complete_vehicles/crazyflie2.html)
-
-## Project Roadmap
-
-**Note: Outdated**
-
-A high level project roadmap is available [here](https://github.com/orgs/PX4/projects/25).
+For the most up to date information, please visit [PX4 User Guide > Autopilot Hardware](https://docs.px4.io/main/en/flight_controller/).
## Project Governance
The PX4 Autopilot project including all of its trademarks is hosted under [Dronecode](https://www.dronecode.org/), part of the Linux Foundation.
-
-
+
diff --git a/src/modules/rover_mecanum/RoverMecanumGuidance/CMakeLists.txt b/ROMFS/performance-test/CMakeLists.txt
similarity index 88%
rename from src/modules/rover_mecanum/RoverMecanumGuidance/CMakeLists.txt
rename to ROMFS/performance-test/CMakeLists.txt
index a15f489245..56c6235ee2 100644
--- a/src/modules/rover_mecanum/RoverMecanumGuidance/CMakeLists.txt
+++ b/ROMFS/performance-test/CMakeLists.txt
@@ -1,6 +1,6 @@
############################################################################
#
-# Copyright (c) 2024 PX4 Development Team. All rights reserved.
+# Copyright (c) 2025 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -31,8 +31,4 @@
#
############################################################################
-px4_add_library(RoverMecanumGuidance
- RoverMecanumGuidance.cpp
-)
-
-target_include_directories(RoverMecanumGuidance PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+add_subdirectory(init.d)
diff --git a/src/lib/bezier/CMakeLists.txt b/ROMFS/performance-test/init.d/CMakeLists.txt
similarity index 90%
rename from src/lib/bezier/CMakeLists.txt
rename to ROMFS/performance-test/init.d/CMakeLists.txt
index f069fff591..8a08b20ab2 100644
--- a/src/lib/bezier/CMakeLists.txt
+++ b/ROMFS/performance-test/init.d/CMakeLists.txt
@@ -1,6 +1,6 @@
############################################################################
#
-# Copyright (c) 2018 PX4 Development Team. All rights reserved.
+# Copyright (c) 2025 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -31,9 +31,6 @@
#
############################################################################
-px4_add_library(bezier
- BezierQuad.cpp
- BezierN.cpp
+px4_add_romfs_files(
+ rcS
)
-
-px4_add_unit_gtest(SRC BezierNTest.cpp LINKLIBS bezier)
diff --git a/ROMFS/performance-test/init.d/rcS b/ROMFS/performance-test/init.d/rcS
new file mode 100644
index 0000000000..d79fe58c76
--- /dev/null
+++ b/ROMFS/performance-test/init.d/rcS
@@ -0,0 +1,68 @@
+#!/bin/sh
+# Un comment and use set +e to ignore and set -e to enable 'exit on error control'
+set +e
+# Un comment the line below to help debug scripts by printing a trace of the script commands
+#set -x
+# PX4FMU startup script.
+#
+# NOTE: environment variable references:
+# If the dollar sign ('$') is followed by a left bracket ('{') then the
+# variable name is terminated with the right bracket character ('}').
+# Otherwise, the variable name goes to the end of the argument.
+#
+#
+# NOTE: COMMENT LINES ARE REMOVED BEFORE STORED IN ROMFS.
+#
+#------------------------------------------------------------------------------
+set R /
+
+#
+# Print full system version.
+#
+ver all
+
+#
+# Set the parameter file the board supports params on
+# MTD device.
+#
+if mft query -q -k MTD -s MTD_PARAMETERS -v /fs/mtd_params
+then
+ set PARAM_FILE /fs/mtd_params
+fi
+
+#
+# Load parameters.
+#
+# if the board has a storage for (factory) calibration data
+if mft query -q -k MTD -s MTD_CALDATA -v /fs/mtd_caldata
+then
+ param load /fs/mtd_caldata
+fi
+
+#
+# Load parameters.
+#
+param select $PARAM_FILE
+if ! param load
+then
+ param reset_all
+fi
+
+#
+# Try to mount the microSD card.
+#
+mount -t vfat /dev/mmcsd0 /fs/microsd
+if [ $? = 0 ]
+then
+ echo "SD card mounted at /fs/microsd"
+else
+ echo "No SD card found"
+fi
+
+unset R
+
+echo ""
+echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+echo "!!!!!! This is the PERFORMANCE TESTING firmware! WARNs and ERRORs are expected! !!!!!"
+echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+echo ""
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/1014_gazebo-classic_iris_obs_avoid b/ROMFS/px4fmu_common/init.d-posix/airframes/1014_gazebo-classic_iris_obs_avoid
deleted file mode 100644
index 8221969873..0000000000
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/1014_gazebo-classic_iris_obs_avoid
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-#
-# @name 3DR Iris Quadrotor SITL (Obstacle Avoidance)
-#
-# @type Quadrotor Wide
-#
-
-. ${R}etc/init.d/rc.mc_defaults
-
-
-param set-default CA_AIRFRAME 0
-
-param set-default CA_ROTOR_COUNT 4
-param set-default CA_ROTOR0_PX 0.1515
-param set-default CA_ROTOR0_PY 0.245
-param set-default CA_ROTOR0_KM 0.05
-param set-default CA_ROTOR1_PX -0.1515
-param set-default CA_ROTOR1_PY -0.1875
-param set-default CA_ROTOR1_KM 0.05
-param set-default CA_ROTOR2_PX 0.1515
-param set-default CA_ROTOR2_PY -0.245
-param set-default CA_ROTOR2_KM -0.05
-param set-default CA_ROTOR3_PX -0.1515
-param set-default CA_ROTOR3_PY 0.1875
-param set-default CA_ROTOR3_KM -0.05
-
-param set-default PWM_MAIN_FUNC1 101
-param set-default PWM_MAIN_FUNC2 102
-param set-default PWM_MAIN_FUNC3 103
-param set-default PWM_MAIN_FUNC4 104
-
-param set-default COM_OBS_AVOID 1
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/1014_gazebo-classic_iris_obs_avoid.post b/ROMFS/px4fmu_common/init.d-posix/airframes/1014_gazebo-classic_iris_obs_avoid.post
deleted file mode 100644
index 64b8ce8b19..0000000000
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/1014_gazebo-classic_iris_obs_avoid.post
+++ /dev/null
@@ -1,2 +0,0 @@
-# shellcheck disable=SC2154
-mavlink start -x -u 14558 -r 4000000 -m onboard -o 14541 -p # add mavlink stream for SDK
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/4001_gz_x500 b/ROMFS/px4fmu_common/init.d-posix/airframes/4001_gz_x500
index bca3feddfb..2add7a5cb4 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/4001_gz_x500
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/4001_gz_x500
@@ -13,10 +13,6 @@ PX4_SIM_MODEL=${PX4_SIM_MODEL:=x500}
param set-default SIM_GZ_EN 1
-param set-default SENS_EN_GPSSIM 1
-param set-default SENS_EN_BAROSIM 0
-param set-default SENS_EN_MAGSIM 1
-
param set-default CA_AIRFRAME 0
param set-default CA_ROTOR_COUNT 4
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/4003_gz_rc_cessna b/ROMFS/px4fmu_common/init.d-posix/airframes/4003_gz_rc_cessna
index 04fc1acfd8..96dd5fa151 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/4003_gz_rc_cessna
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/4003_gz_rc_cessna
@@ -12,13 +12,8 @@ PX4_SIM_MODEL=${PX4_SIM_MODEL:=rc_cessna}
param set-default SIM_GZ_EN 1
-param set-default SENS_EN_GPSSIM 1
-param set-default SENS_EN_BAROSIM 0
-param set-default SENS_EN_MAGSIM 1
param set-default SENS_EN_ARSPDSIM 1
-
-
param set-default FW_LND_ANG 8
param set-default NPFG_PERIOD 12
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/4004_gz_standard_vtol b/ROMFS/px4fmu_common/init.d-posix/airframes/4004_gz_standard_vtol
index 96bb25d69a..5bd432abde 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/4004_gz_standard_vtol
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/4004_gz_standard_vtol
@@ -13,9 +13,6 @@ PX4_SIM_MODEL=${PX4_SIM_MODEL:=standard_vtol}
param set-default SIM_GZ_EN 1
-param set-default SENS_EN_GPSSIM 1
-param set-default SENS_EN_BAROSIM 0
-param set-default SENS_EN_MAGSIM 1
param set-default SENS_EN_ARSPDSIM 1
# TODO: Enable motor failure detection when the
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/4006_gz_px4vision b/ROMFS/px4fmu_common/init.d-posix/airframes/4006_gz_px4vision
index 65d290e0cc..4370a677ed 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/4006_gz_px4vision
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/4006_gz_px4vision
@@ -14,12 +14,7 @@ PX4_SIM_MODEL=${PX4_SIM_MODEL:=px4vision}
param set-default SIM_GZ_EN 1
-param set-default SENS_EN_GPSSIM 1
-param set-default SENS_EN_BAROSIM 0
-param set-default SENS_EN_MAGSIM 1
-
# Commander Parameters
-param set-default COM_OBS_AVOID 0
param set-default COM_DISARM_LAND 0.5
# EKF2 parameters
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/4008_gz_advanced_plane b/ROMFS/px4fmu_common/init.d-posix/airframes/4008_gz_advanced_plane
index 5d5c50df33..8ac407bac4 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/4008_gz_advanced_plane
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/4008_gz_advanced_plane
@@ -11,8 +11,6 @@ PX4_SIM_MODEL=${PX4_SIM_MODEL:=advanced_plane}
param set-default SIM_GZ_EN 1
-param set-default SENS_EN_GPSSIM 1
-param set-default SENS_EN_MAGSIM 1
param set-default SENS_EN_ARSPDSIM 1
param set-default FW_LND_ANG 8
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/4009_gz_r1_rover b/ROMFS/px4fmu_common/init.d-posix/airframes/4009_gz_r1_rover
index 3f96dad5f8..2d36aed7ce 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/4009_gz_r1_rover
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/4009_gz_r1_rover
@@ -11,35 +11,39 @@ PX4_SIM_MODEL=${PX4_SIM_MODEL:=r1_rover}
param set-default SIM_GZ_EN 1 # Gazebo bridge
-# Rover parameters
+param set-default NAV_ACC_RAD 0.5
+
+# Differential Parameters
param set-default RD_WHEEL_TRACK 0.3
-param set-default RD_MAX_ACCEL 5
-param set-default RD_MAX_DECEL 10
-param set-default RD_MAX_JERK 30
param set-default RD_MAX_THR_YAW_R 1.5
-param set-default RD_YAW_RATE_P 0.25
-param set-default RD_YAW_RATE_I 0.01
-param set-default RD_YAW_P 5
-param set-default RD_YAW_I 0.1
-param set-default RD_MAX_SPEED 2
-param set-default RD_MAX_THR_SPD 2.15
-param set-default RD_SPEED_P 0.1
-param set-default RD_SPEED_I 0.01
-param set-default RD_MAX_YAW_RATE 180
param set-default RD_TRANS_DRV_TRN 0.349066
param set-default RD_TRANS_TRN_DRV 0.174533
-param set-default RD_MAX_YAW_ACCEL 1000
-# Pure pursuit parameters
-param set-default PP_LOOKAHD_MAX 30
-param set-default PP_LOOKAHD_MIN 2
+# Rover Control Parameters
+param set-default RO_ACCEL_LIM 5
+param set-default RO_DECEL_LIM 10
+param set-default RO_JERK_LIM 30
+param set-default RO_MAX_THR_SPEED 2.1
+
+# Rover Rate Control Parameters
+param set-default RO_YAW_RATE_I 0.01
+param set-default RO_YAW_RATE_P 0.25
+param set-default RO_YAW_RATE_LIM 180
+param set-default RO_YAW_ACCEL_LIM 120
+param set-default RO_YAW_DECEL_LIM 1000
+
+# Rover Attitude Control Parameters
+param set-default RO_YAW_P 5
+
+# Rover Position Control Parameters
+param set-default RO_SPEED_LIM 2
+param set-default RO_SPEED_I 0.5
+param set-default RO_SPEED_P 1
+
+# Pure Pursuit parameters
param set-default PP_LOOKAHD_GAIN 1
-
-# Simulated sensors
-param set-default SENS_EN_GPSSIM 1
-param set-default SENS_EN_BAROSIM 0
-param set-default SENS_EN_MAGSIM 1
-param set-default SENS_EN_ARSPDSIM 0
+param set-default PP_LOOKAHD_MAX 10
+param set-default PP_LOOKAHD_MIN 1
# Actuator mapping
param set-default SIM_GZ_WH_FUNC1 101 # right wheel
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/4011_gz_lawnmower b/ROMFS/px4fmu_common/init.d-posix/airframes/4011_gz_lawnmower
index 0fec76b5c4..83f387b56e 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/4011_gz_lawnmower
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/4011_gz_lawnmower
@@ -11,11 +11,6 @@ PX4_SIM_MODEL=${PX4_SIM_MODEL:=lawnmower}
param set-default SIM_GZ_EN 1 # Gazebo bridge
-# Simulated sensors
-param set-default SENS_EN_GPSSIM 1
-param set-default SENS_EN_BAROSIM 0
-param set-default SENS_EN_MAGSIM 1
-param set-default SENS_EN_ARSPDSIM 0
# We can arm and drive in manual mode when it slides and GPS check fails:
param set-default COM_ARM_WO_GPS 1
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/4012_gz_rover_ackermann b/ROMFS/px4fmu_common/init.d-posix/airframes/4012_gz_rover_ackermann
index cd870caabb..9c24991fcf 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/4012_gz_rover_ackermann
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/4012_gz_rover_ackermann
@@ -44,12 +44,6 @@ param set-default PP_LOOKAHD_GAIN 1
param set-default PP_LOOKAHD_MAX 10
param set-default PP_LOOKAHD_MIN 1
-# Simulated sensors
-param set-default SENS_EN_GPSSIM 1
-param set-default SENS_EN_BAROSIM 0
-param set-default SENS_EN_MAGSIM 1
-param set-default SENS_EN_ARSPDSIM 0
-
# Wheels
param set-default SIM_GZ_WH_FUNC1 101
param set-default SIM_GZ_WH_MIN1 0
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/4015_gz_r1_rover_mecanum b/ROMFS/px4fmu_common/init.d-posix/airframes/4015_gz_r1_rover_mecanum
index e252b3cfa0..45f80383e8 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/4015_gz_r1_rover_mecanum
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/4015_gz_r1_rover_mecanum
@@ -11,34 +11,41 @@ PX4_SIM_MODEL=${PX4_SIM_MODEL:=r1_rover_mecanum}
param set-default SIM_GZ_EN 1 # Gazebo bridge
-# Rover parameters
-param set-default RM_WHEEL_TRACK 0.3
-param set-default RM_YAW_RATE_I 0.1
-param set-default RM_YAW_RATE_P 0.1
-param set-default RM_MAX_ACCEL 3
-param set-default RM_MAX_DECEL 5
-param set-default RM_MAX_JERK 5
-param set-default RM_MAX_SPEED 2
-param set-default RM_MAX_THR_SPD 2.2
-param set-default RM_MAX_THR_YAW_R 1.2
-param set-default RM_YAW_P 5
-param set-default RM_YAW_I 0.1
-param set-default RM_MAX_YAW_RATE 120
-param set-default RM_MAX_YAW_ACCEL 240
-param set-default RM_MISS_VEL_GAIN 1
-param set-default RM_SPEED_I 0.01
-param set-default RM_SPEED_P 0.1
+param set-default NAV_ACC_RAD 0.5
-# Pure pursuit parameters
+# Mecanum Parameters
+param set-default RM_WHEEL_TRACK 0.3
+param set-default RM_MAX_THR_YAW_R 1.2
+param set-default RM_MISS_SPD_GAIN 1
+
+# Rover Control Parameters
+param set-default RO_ACCEL_LIM 3
+param set-default RO_DECEL_LIM 5
+param set-default RO_JERK_LIM 30
+param set-default RO_MAX_THR_SPEED 2.1
+
+# Rover Rate Control Parameters
+param set-default RO_YAW_RATE_I 0.1
+param set-default RO_YAW_RATE_P 0.1
+param set-default RO_YAW_RATE_LIM 120
+param set-default RO_YAW_ACCEL_LIM 240
+param set-default RO_YAW_DECEL_LIM 1000
+
+# Rover Attitude Control Parameters
+param set-default RO_YAW_P 5
+
+# Rover Position Control Parameters
+param set-default RO_SPEED_LIM 2
+param set-default RO_SPEED_I 0.5
+param set-default RO_SPEED_P 1
+
+# Pure Pursuit parameters
+param set-default PP_LOOKAHD_GAIN 0.5
param set-default PP_LOOKAHD_MAX 10
param set-default PP_LOOKAHD_MIN 1
-param set-default PP_LOOKAHD_GAIN 0.5
# Simulated sensors
-param set-default SENS_EN_GPSSIM 1
-param set-default SENS_EN_BAROSIM 0
param set-default SENS_EN_MAGSIM 1
-param set-default SENS_EN_ARSPDSIM 0
# Actuator mapping
param set-default SIM_GZ_WH_FUNC1 102 # right wheel front
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/4018_gz_quadtailsitter b/ROMFS/px4fmu_common/init.d-posix/airframes/4018_gz_quadtailsitter
index 9856b1bf27..bced062c1e 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/4018_gz_quadtailsitter
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/4018_gz_quadtailsitter
@@ -13,12 +13,6 @@ PX4_SIM_MODEL=${PX4_SIM_MODEL:=quadtailsitter}
param set-default SIM_GZ_EN 1 # Gazebo bridge
-param set-default SENS_EN_GPSSIM 1
-param set-default SENS_EN_BAROSIM 0
-param set-default SENS_EN_MAGSIM 1
-param set-default SENS_EN_ARSPDSIM 0
-
-
param set-default MAV_TYPE 20
param set-default CA_AIRFRAME 4
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/4020_gz_tiltrotor b/ROMFS/px4fmu_common/init.d-posix/airframes/4020_gz_tiltrotor
index c798650b54..ff7805cb77 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/4020_gz_tiltrotor
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/4020_gz_tiltrotor
@@ -13,11 +13,6 @@ PX4_SIM_MODEL=${PX4_SIM_MODEL:=tiltrotor}
param set-default SIM_GZ_EN 1 # Gazebo bridge
-param set-default SENS_EN_GPSSIM 1
-param set-default SENS_EN_BAROSIM 0
-param set-default SENS_EN_MAGSIM 1
-param set-default SENS_EN_ARSPDSIM 0
-
param set-default MAV_TYPE 21
param set-default CA_AIRFRAME 3
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/4021_gz_x500_flow b/ROMFS/px4fmu_common/init.d-posix/airframes/4021_gz_x500_flow
new file mode 100644
index 0000000000..5f0aababbd
--- /dev/null
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/4021_gz_x500_flow
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# @name Gazebo x500 with downward optical flow and distance sensor
+#
+# @type Quadrotor
+#
+
+PX4_SIM_MODEL=${PX4_SIM_MODEL:=x500_flow}
+
+. ${R}etc/init.d-posix/airframes/4001_gz_x500
+
+echo "Disabling Sim GPS"
+param set-default SYS_HAS_GPS 0
+param set-default SIM_GPS_USED 0
+param set-default EKF2_GPS_CTRL 0
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/71002_gz_spacecraft_2d b/ROMFS/px4fmu_common/init.d-posix/airframes/71002_gz_spacecraft_2d
index 480454d72b..4cc0a02e41 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/71002_gz_spacecraft_2d
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/71002_gz_spacecraft_2d
@@ -15,8 +15,6 @@ PX4_SIM_MODEL=${PX4_SIM_MODEL:=spacecraft_2d}
param set-default SIM_GZ_EN 1
-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?
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/8011_gz_omnicopter b/ROMFS/px4fmu_common/init.d-posix/airframes/8011_gz_omnicopter
index b43b61025c..be7a32431b 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/8011_gz_omnicopter
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/8011_gz_omnicopter
@@ -83,9 +83,6 @@ param set-default CA_ROTOR7_AY -0.211325
param set-default CA_ROTOR7_AZ -0.57735
param set-default SIM_GZ_EN 1
-param set-default SENS_EN_GPSSIM 1
-param set-default SENS_EN_BAROSIM 0
-param set-default SENS_EN_MAGSIM 1
param set-default SIM_GZ_EC_FUNC1 101
param set-default SIM_GZ_EC_FUNC2 102
diff --git a/ROMFS/px4fmu_common/init.d-posix/airframes/CMakeLists.txt b/ROMFS/px4fmu_common/init.d-posix/airframes/CMakeLists.txt
index 94f2f4d39a..b4e107799f 100644
--- a/ROMFS/px4fmu_common/init.d-posix/airframes/CMakeLists.txt
+++ b/ROMFS/px4fmu_common/init.d-posix/airframes/CMakeLists.txt
@@ -39,8 +39,6 @@ px4_add_romfs_files(
1012_gazebo-classic_iris_rplidar
1013_gazebo-classic_iris_vision
1013_gazebo-classic_iris_vision.post
- 1014_gazebo-classic_iris_obs_avoid
- 1014_gazebo-classic_iris_obs_avoid.post
1015_gazebo-classic_iris_depth_camera
1016_gazebo-classic_iris_downward_depth_camera
1017_gazebo-classic_iris_opt_flow_mockup
@@ -93,6 +91,7 @@ px4_add_romfs_files(
4018_gz_quadtailsitter
4019_gz_x500_gimbal
4020_gz_tiltrotor
+ 4021_gz_x500_flow
6011_gazebo-classic_typhoon_h480
6011_gazebo-classic_typhoon_h480.post
diff --git a/ROMFS/px4fmu_common/init.d-posix/px4-rc.simulator b/ROMFS/px4fmu_common/init.d-posix/px4-rc.simulator
index fd0954744e..b396115491 100644
--- a/ROMFS/px4fmu_common/init.d-posix/px4-rc.simulator
+++ b/ROMFS/px4fmu_common/init.d-posix/px4-rc.simulator
@@ -73,13 +73,13 @@ elif [ "$PX4_SIMULATOR" = "gz" ] || [ "$(param show -q SIM_GZ_EN)" = "1" ]; then
exit 1
fi
- # look for running ${gz_command} gazebo world
+ # Look for an already running world
gz_world=$( ${gz_command} topic -l | grep -m 1 -e "^/world/.*/clock" | sed 's/\/world\///g; s/\/clock//g' )
# shellcheck disable=SC2153
if [ -z "${gz_world}" ] && [ -n "${PX4_GZ_WORLD}" ]; then
- # source generated gz_env.sh for GZ_SIM_RESOURCE_PATH
+ # Setup gz environment variables
if [ -f ./gz_env.sh ]; then
. ./gz_env.sh
@@ -87,62 +87,125 @@ elif [ "$PX4_SIMULATOR" = "gz" ] || [ "$(param show -q SIM_GZ_EN)" = "1" ]; then
. ../gz_env.sh
fi
- echo "INFO [init] starting gazebo with world: ${PX4_GZ_WORLDS}/${PX4_GZ_WORLD}.sdf"
+ echo "INFO [init] Starting gazebo with world: ${PX4_GZ_WORLDS}/${PX4_GZ_WORLD}.sdf"
- ${gz_command} ${gz_sub_command} --verbose=1 -r -s "${PX4_GZ_WORLDS}/${PX4_GZ_WORLD}.sdf" &
+ ${gz_command} ${gz_sub_command} --verbose=${GZ_VERBOSE:=1} -r -s "${PX4_GZ_WORLDS}/${PX4_GZ_WORLD}.sdf" &
if [ -z "${HEADLESS}" ]; then
- # HEADLESS not set, starting gui
- ${gz_command} ${gz_sub_command} -g &
+ echo "INFO [init] Starting gz gui"
+ ${gz_command} ${gz_sub_command} -g > /dev/null 2>&1 &
fi
-
else
- # Gazebo is already running, do not start the simulator, nor the GUI
+ # Gazebo is already running
echo "INFO [init] gazebo already running world: ${gz_world}"
PX4_GZ_WORLD=${gz_world}
fi
+
else
echo "INFO [init] Standalone PX4 launch, waiting for Gazebo"
fi
- # start gz_bridge
+ # Start gz_bridge - either spawn a model or connect to existing one
if [ -n "${PX4_SIM_MODEL#*gz_}" ] && [ -z "${PX4_GZ_MODEL_NAME}" ]; then
- # model specified, gz_bridge will spawn model
+ # Spawn a model
+ MODEL_NAME="${PX4_SIM_MODEL#*gz_}"
+ MODEL_NAME_INSTANCE="${MODEL_NAME}_${px4_instance}"
+ POSE_ARG=""
if [ -n "${PX4_GZ_MODEL_POSE}" ]; then
- # model pose provided: [x, y, z, roll, pitch, yaw]
+ pos_x=$(echo "${PX4_GZ_MODEL_POSE}" | awk -F',' '{print $1}')
+ pos_y=$(echo "${PX4_GZ_MODEL_POSE}" | awk -F',' '{print $2}')
+ pos_z=$(echo "${PX4_GZ_MODEL_POSE}" | awk -F',' '{print $3}')
+ pos_x=${pos_x:-0}
+ pos_y=${pos_y:-0}
+ pos_z=${pos_z:-0}
- # Clean potential input line formatting.
- model_pose="$( echo "${PX4_GZ_MODEL_POSE}" | sed -e 's/^[ \t]*//; s/[ \t]*$//; s/,/ /g; s/ / /g; s/ /,/g' )"
- echo "INFO [init] PX4_GZ_MODEL_POSE set, spawning at: ${model_pose}"
-
- else
- # model pose not provided, origin will be used
-
- echo "WARN [init] PX4_GZ_MODEL_POSE not set, spawning at origin."
- model_pose="0,0,0,0,0,0"
+ POSE_ARG=", pose: { position: { x: ${pos_x}, y: ${pos_y}, z: ${pos_z} } }"
+ echo "INFO [init] Spawning model at position: ${pos_x} ${pos_y} ${pos_z}"
fi
- # start gz bridge with pose arg.
- if ! gz_bridge start -p "${model_pose}" -m "${PX4_SIM_MODEL#*gz_}" -w "${PX4_GZ_WORLD}" -i "${px4_instance}"; then
+ echo "INFO [init] Spawning model"
+ # Spawn model
+ ${gz_command} service -s "/world/${PX4_GZ_WORLD}/create" --reqtype gz.msgs.EntityFactory \
+ --reptype gz.msgs.Boolean --timeout 5000 \
+ --req "sdf_filename: \"${PX4_GZ_MODELS}/${MODEL_NAME}\", name: \"${MODEL_NAME_INSTANCE}\", allow_renaming: false${POSE_ARG}" > /dev/null 2>&1
+
+ # Start gz_bridge
+ if ! gz_bridge start -w "${PX4_GZ_WORLD}" -n "${MODEL_NAME_INSTANCE}"; then
echo "ERROR [init] gz_bridge failed to start and spawn model"
exit 1
fi
- elif [ -n "${PX4_GZ_MODEL_NAME}" ]; then
- # model name specificed, gz_bridge will attach to existing model
+ # Set physics parameters for faster-than-realtime simulation if needed
+ check_scene_info() {
+ SERVICE_INFO=$(${gz_command} service -i --service "/world/${PX4_GZ_WORLD}/scene/info" 2>&1)
+ if echo "$SERVICE_INFO" | grep -q "Service providers"; then
+ return 0
+ else
+ return 1
+ fi
+ }
+ ATTEMPTS=30
+ while [ $ATTEMPTS -gt 0 ]; do
+ if check_scene_info; then
+ echo "INFO [init] Gazebo world is ready"
+ break
+ fi
+ ATTEMPTS=$((ATTEMPTS-1))
+ if [ $ATTEMPTS -eq 0 ]; then
+ echo "ERROR [init] Timed out waiting for Gazebo world"
+ exit 1
+ fi
+ echo "INFO [init] Waiting for Gazebo world..."
+ sleep 1
+ done
+
+ if [ -n "${PX4_SIM_SPEED_FACTOR}" ]; then
+ echo "INFO [init] Setting simulation speed factor: ${PX4_SIM_SPEED_FACTOR}"
+ ${gz_command} service -s "/world/${PX4_GZ_WORLD}/set_physics" --reqtype gz.msgs.Physics \
+ --reptype gz.msgs.Boolean --timeout 5000 \
+ --req "real_time_factor: ${PX4_SIM_SPEED_FACTOR}" > /dev/null 2>&1
+ fi
+
+
+ # Set up camera to follow the model if requested
+ if [ -n "${PX4_GZ_FOLLOW}" ]; then
+
+ # Wait for model to spawn
+ sleep 1
+
+ echo "INFO [init] Setting camera to follow ${MODEL_NAME_INSTANCE}"
+
+ # Set camera to follow the model
+ ${gz_command} service -s "/gui/follow" --reqtype gz.msgs.StringMsg \
+ --reptype gz.msgs.Boolean --timeout 5000 \
+ --req "data: \"${MODEL_NAME_INSTANCE}\"" > /dev/null 2>&1
+
+ # Set default camera offset if not specified
+ follow_x=${PX4_GZ_FOLLOW_OFFSET_X:--2.0}
+ follow_y=${PX4_GZ_FOLLOW_OFFSET_Y:--2.0}
+ follow_z=${PX4_GZ_FOLLOW_OFFSET_Z:-2.0}
+
+ # Set camera offset
+ ${gz_command} service -s "/gui/follow/offset" --reqtype gz.msgs.Vector3d \
+ --reptype gz.msgs.Boolean --timeout 5000 \
+ --req "x: ${follow_x}, y: ${follow_y}, z: ${follow_z}" > /dev/null 2>&1
+
+ echo "INFO [init] Camera follow offset set to ${follow_x}, ${follow_y}, ${follow_z}"
+ fi
+
+ elif [ -n "${PX4_GZ_MODEL_NAME}" ]; then
+ # Connect to existing model
echo "INFO [init] PX4_GZ_MODEL_NAME set, PX4 will attach to existing model"
- if ! gz_bridge start -n "${PX4_GZ_MODEL_NAME}" -w "${PX4_GZ_WORLD}"; then
+ if ! gz_bridge start -w "${PX4_GZ_WORLD}" -n "${PX4_GZ_MODEL_NAME}"; then
echo "ERROR [init] gz_bridge failed to start and attach to existing model"
exit 1
fi
-
else
- echo "ERROR [init] failed to pass only PX4_GZ_MODEL_NAME or PX4_SIM_MODEL"
+ echo "ERROR [init] failed to pass either PX4_GZ_MODEL_NAME or PX4_SIM_MODEL"
exit 1
fi
-
# Start the sensor simulator modules
if param compare -s SENS_EN_BAROSIM 1
then
diff --git a/ROMFS/px4fmu_common/init.d-posix/rcS b/ROMFS/px4fmu_common/init.d-posix/rcS
index ef2907deb7..c53dbbd46a 100644
--- a/ROMFS/px4fmu_common/init.d-posix/rcS
+++ b/ROMFS/px4fmu_common/init.d-posix/rcS
@@ -337,6 +337,11 @@ then
payload_deliverer start
fi
+if param compare -s ICE_EN 1
+then
+ internal_combustion_engine_control start
+fi
+
#user defined mavlink streams for instances can be in PATH
. px4-rc.mavlink
diff --git a/ROMFS/px4fmu_common/init.d/airframes/4016_holybro_px4vision b/ROMFS/px4fmu_common/init.d/airframes/4016_holybro_px4vision
index d60de46e7b..9b86703c31 100644
--- a/ROMFS/px4fmu_common/init.d/airframes/4016_holybro_px4vision
+++ b/ROMFS/px4fmu_common/init.d/airframes/4016_holybro_px4vision
@@ -12,7 +12,6 @@
. ${R}etc/init.d/rc.mc_defaults
# Commander Parameters
-param set-default COM_OBS_AVOID 1
param set-default COM_DISARM_LAND 0.5
# EKF2 parameters
diff --git a/ROMFS/px4fmu_common/init.d/airframes/4020_holybro_px4vision_v1_5 b/ROMFS/px4fmu_common/init.d/airframes/4020_holybro_px4vision_v1_5
index c9c3e5843a..e63a9eef01 100644
--- a/ROMFS/px4fmu_common/init.d/airframes/4020_holybro_px4vision_v1_5
+++ b/ROMFS/px4fmu_common/init.d/airframes/4020_holybro_px4vision_v1_5
@@ -12,7 +12,6 @@
. ${R}etc/init.d/rc.mc_defaults
# Commander Parameters
-param set-default COM_OBS_AVOID 1
param set-default COM_DISARM_LAND 0.5
# EKF2 parameters
diff --git a/ROMFS/px4fmu_common/init.d/airframes/50001_aion_robotics_r1_rover b/ROMFS/px4fmu_common/init.d/airframes/50001_aion_robotics_r1_rover
index 57a3644dae..45b35ffeaa 100644
--- a/ROMFS/px4fmu_common/init.d/airframes/50001_aion_robotics_r1_rover
+++ b/ROMFS/px4fmu_common/init.d/airframes/50001_aion_robotics_r1_rover
@@ -21,26 +21,37 @@ param set-default RBCLW_FUNC1 101
param set-default RBCLW_FUNC2 102
param set-default RBCLW_REV 1 # reverse right wheels
-# Rover parameters
+
+param set-default NAV_ACC_RAD 0.5
+
+# Differential Parameters
param set-default RD_WHEEL_TRACK 0.3
-param set-default RD_MAX_ACCEL 3
-param set-default RD_MAX_DECEL 4
-param set-default RD_MAX_JERK 5
-param set-default RD_MAX_SPEED 1.6
-param set-default RD_MAX_THR_SPD 1.9
param set-default RD_MAX_THR_YAW_R 0.7
-param set-default RD_MAX_YAW_ACCEL 600
-param set-default RD_MAX_YAW_RATE 250
-param set-default RD_SPEED_P 0.1
-param set-default RD_SPEED_I 0.01
param set-default RD_TRANS_DRV_TRN 0.785398
param set-default RD_TRANS_TRN_DRV 0.139626
-param set-default RD_YAW_P 5
-param set-default RD_YAW_I 0.1
-param set-default RD_YAW_RATE_P 0.1
-param set-default RD_YAW_RATE_I 0.01
-# Pure pursuit parameters
+# Rover Control Parameters
+param set-default RO_ACCEL_LIM 3
+param set-default RO_DECEL_LIM 4
+param set-default RO_JERK_LIM 5
+param set-default RO_MAX_THR_SPEED 1.9
+
+# Rover Rate Control Parameters
+param set-default RO_YAW_RATE_I 0.01
+param set-default RO_YAW_RATE_P 0.1
+param set-default RO_YAW_RATE_LIM 250
+param set-default RO_YAW_ACCEL_LIM 600
+param set-default RO_YAW_DECEL_LIM 600
+
+# Rover Attitude Control Parameters
+param set-default RO_YAW_P 5
+
+# Rover Position Control Parameters
+param set-default RO_SPEED_LIM 1.6
+param set-default RO_SPEED_I 0.01
+param set-default RO_SPEED_P 0.1
+
+# Pure Pursuit parameters
+param set-default PP_LOOKAHD_GAIN 1
param set-default PP_LOOKAHD_MAX 10
param set-default PP_LOOKAHD_MIN 1
-param set-default PP_LOOKAHD_GAIN 1
diff --git a/ROMFS/px4fmu_common/init.d/rcS b/ROMFS/px4fmu_common/init.d/rcS
index 807a26ed03..9131f83e96 100644
--- a/ROMFS/px4fmu_common/init.d/rcS
+++ b/ROMFS/px4fmu_common/init.d/rcS
@@ -488,11 +488,14 @@ else
rc_input start $RC_INPUT_ARGS
# Manages USB interface
- if ! cdcacm_autostart start
+ if param greater -s SYS_USB_AUTO -1
then
- sercon
- echo "Starting MAVLink on /dev/ttyACM0"
- mavlink start -d /dev/ttyACM0
+ if ! cdcacm_autostart start
+ then
+ sercon
+ echo "Starting MAVLink on /dev/ttyACM0"
+ mavlink start -d /dev/ttyACM0
+ fi
fi
#
@@ -555,6 +558,11 @@ else
payload_deliverer start
fi
+ if param compare -s ICE_EN 1
+ then
+ internal_combustion_engine_control start
+ fi
+
#
# Optional board supplied extras: rc.board_extras
#
diff --git a/Tools/HIL/run_tests.py b/Tools/HIL/run_tests.py
index 3e79c70227..0d9c5f5d1b 100755
--- a/Tools/HIL/run_tests.py
+++ b/Tools/HIL/run_tests.py
@@ -136,9 +136,6 @@ class TestHardwareMethods(unittest.TestCase):
def test_atomic_bitset(self):
self.assertTrue(do_test(self.TEST_DEVICE, self.TEST_BAUDRATE, "atomic_bitset"))
- def test_bezier(self):
- self.assertTrue(do_test(self.TEST_DEVICE, self.TEST_BAUDRATE, "bezier"))
-
def test_bitset(self):
self.assertTrue(do_test(self.TEST_DEVICE, self.TEST_BAUDRATE, "bitset"))
diff --git a/Tools/ci/check_msg_versioning.sh b/Tools/ci/check_msg_versioning.sh
index c10d4819c2..37c593d277 100755
--- a/Tools/ci/check_msg_versioning.sh
+++ b/Tools/ci/check_msg_versioning.sh
@@ -26,6 +26,15 @@ do
# - Incrementing the version
# - An old .msg version exists
# - A translation header exists and is included
+
+ # Ignore changes to comments or constants
+ content_a=$(git show "${BASE_COMMIT}:${file}" | grep -o '^[^#]*' | grep -v =)
+ content_b=$(git show "${HEAD_COMMIT}:${file}" | grep -o '^[^#]*' | grep -v =)
+ if [ "${content_a}" == "${content_b}" ]; then
+ echo "No version update required for ${file}"
+ continue
+ fi
+
diff=$(git --no-pager diff --no-color --diff-filter=M "${BASE_COMMIT}"..."${HEAD_COMMIT}" -- "${file}")
old_version=$(echo "${diff}" | sed -n 's/^-uint32 MESSAGE_VERSION = \([0-9]*\).*/\1/p')
new_version=$(echo "${diff}" | sed -n 's/^+uint32 MESSAGE_VERSION = \([0-9]*\).*/\1/p')
diff --git a/Tools/ci/generate_board_targets_json.py b/Tools/ci/generate_board_targets_json.py
index 218862cecd..5749a988d1 100755
--- a/Tools/ci/generate_board_targets_json.py
+++ b/Tools/ci/generate_board_targets_json.py
@@ -69,7 +69,7 @@ def process_target(px4board_file, target_name):
group = None
if px4board_file.endswith("default.px4board") or \
- px4board_file.endswith("recovery.px4board") or \
+ px4board_file.endswith("performance-test.px4board") or \
px4board_file.endswith("bootloader.px4board"):
kconf.load_config(px4board_file, replace=True)
else: # Merge config with default.px4board
diff --git a/Tools/copy_to_ros_ws.sh b/Tools/copy_to_ros_ws.sh
index ef663aaaa9..48fcaa0d1f 100755
--- a/Tools/copy_to_ros_ws.sh
+++ b/Tools/copy_to_ros_ws.sh
@@ -29,6 +29,5 @@ then
rm -rf "${PX4_MSGS_DIR}"/srv/*.srv
fi
cp -ar "${PX4_SRC_DIR}"/msg/*.msg "${PX4_MSGS_DIR}"/msg
-mkdir -p "${PX4_MSGS_DIR}"/msg/versioned
-cp -ar "${PX4_SRC_DIR}"/msg/versioned/*.msg "${PX4_MSGS_DIR}"/msg/versioned
+cp -ar "${PX4_SRC_DIR}"/msg/versioned/*.msg "${PX4_MSGS_DIR}"/msg
cp -ar "${PX4_SRC_DIR}"/srv/*.srv "${PX4_MSGS_DIR}"/srv
diff --git a/Tools/docker_run.sh b/Tools/docker_run.sh
index c78b9cc7e1..46888cd066 100755
--- a/Tools/docker_run.sh
+++ b/Tools/docker_run.sh
@@ -47,6 +47,7 @@ CCACHE_DIR=${HOME}/.ccache
mkdir -p "${CCACHE_DIR}"
docker run -it --rm -w "${SRC_DIR}" \
+ --user="$(id -u):$(id -g)" \
--env=AWS_ACCESS_KEY_ID \
--env=AWS_SECRET_ACCESS_KEY \
--env=BRANCH_NAME \
@@ -54,7 +55,6 @@ docker run -it --rm -w "${SRC_DIR}" \
--env=CI \
--env=CODECOV_TOKEN \
--env=COVERALLS_REPO_TOKEN \
- --env=LOCAL_USER_ID="$(id -u)" \
--env=PX4_ASAN \
--env=PX4_MSAN \
--env=PX4_TSAN \
diff --git a/Tools/kconfig/allyesconfig.py b/Tools/kconfig/allyesconfig.py
index 2c0f58d75a..e432c52ec0 100644
--- a/Tools/kconfig/allyesconfig.py
+++ b/Tools/kconfig/allyesconfig.py
@@ -74,6 +74,7 @@ exception_list_sitl = [
'SYSTEMCMDS_I2CDETECT', # Not supported in SITL
'SYSTEMCMDS_DMESG', # Not supported in SITL
'SYSTEMCMDS_USB_CONNECTED', # Not supported in SITL
+ 'SYSTEMCMDS_MFT_CFG', # Not supported in SITL
'MODULES_SPACECRAFT', # Clashes with Control Allocation (mom's spaghetti code)
]
diff --git a/Tools/px_uploader.py b/Tools/px_uploader.py
index 34f3be05ca..6d8c7c69dc 100755
--- a/Tools/px_uploader.py
+++ b/Tools/px_uploader.py
@@ -708,7 +708,7 @@ class uploader:
# https://github.com/PX4/Firmware/blob/master/src/drivers/boards/common/stm32/board_mcu_version.c#L125-L144
if self.fw_maxsize > fw.property('image_maxsize') and not force:
- raise RuntimeError(f"Board can accept larger flash images ({self.fw_maxsize} bytes) than board config ({fw.property('image_maxsize')} bytes). Please use the correct board configuration to avoid lacking critical functionality.")
+ print(f"WARNING: Board can accept larger flash images ({self.fw_maxsize} bytes) than board config ({fw.property('image_maxsize')} bytes)")
else:
# If we're still on bootloader v4 on a Pixhawk, we don't know if we
# have the silicon errata and therefore need to flash px4_fmu-v2
diff --git a/Tools/setup/docker-entrypoint.sh b/Tools/setup/docker-entrypoint.sh
index 1094587c1c..0412558902 100755
--- a/Tools/setup/docker-entrypoint.sh
+++ b/Tools/setup/docker-entrypoint.sh
@@ -1,6 +1,5 @@
#!/bin/bash
-echo "[docker-entrypoint.sh] Starting entrypoint"
# Start virtual X server in the background
# - DISPLAY default is :99, set in dockerfile
# - Users can override with `-e DISPLAY=` in `docker run` command to avoid
@@ -17,17 +16,4 @@ if [ -n "${ROS_DISTRO}" ]; then
source "/opt/ros/$ROS_DISTRO/setup.bash"
fi
-echo "[docker-entrypoint.sh] Working Directory: ${pwd}"
-
-# Use the LOCAL_USER_ID if passed in at runtime
-if [ -n "${LOCAL_USER_ID}" ]; then
- echo "[docker-entrypoint.sh] Starting with: $LOCAL_USER_ID:user"
- # modify existing user's id
- usermod -u $LOCAL_USER_ID user
-
- # run as user
- # exec gosu user "$@"
- exec "$@"
-else
- exec "$@"
-fi
+exec "$@"
diff --git a/Tools/setup/ubuntu.sh b/Tools/setup/ubuntu.sh
index 434b2a81cd..e641a82da3 100755
--- a/Tools/setup/ubuntu.sh
+++ b/Tools/setup/ubuntu.sh
@@ -116,6 +116,7 @@ if [[ $INSTALL_NUTTX == "true" ]]; then
binutils-dev \
bison \
build-essential \
+ curl \
flex \
g++-multilib \
gcc-arm-none-eabi \
diff --git a/Tools/simulation/gz b/Tools/simulation/gz
index db4af69088..6c18846a4c 160000
--- a/Tools/simulation/gz
+++ b/Tools/simulation/gz
@@ -1 +1 @@
-Subproject commit db4af69088cccef4549cf3a5c195d5cd97d6b36a
+Subproject commit 6c18846a4c7f9fe786840a29bf4e3237f908611b
diff --git a/boards/ark/can-gps/init/rc.board_defaults b/boards/ark/can-gps/init/rc.board_defaults
index 13e16a24f1..3d085fe527 100644
--- a/boards/ark/can-gps/init/rc.board_defaults
+++ b/boards/ark/can-gps/init/rc.board_defaults
@@ -4,7 +4,7 @@
#------------------------------------------------------------------------------
param set-default CBRK_IO_SAFETY 0
-param set-default MBE_ENABLE 1
+param set-default MBE_ENABLE 0
param set-default SENS_IMU_CLPNOTI 0
safety_button start
diff --git a/boards/ark/can-rtk-gps/init/rc.board_defaults b/boards/ark/can-rtk-gps/init/rc.board_defaults
index 99b30c747f..85d6a92063 100644
--- a/boards/ark/can-rtk-gps/init/rc.board_defaults
+++ b/boards/ark/can-rtk-gps/init/rc.board_defaults
@@ -7,7 +7,7 @@ param set-default CBRK_IO_SAFETY 0
param set-default CANNODE_SUB_MBD 1
param set-default CANNODE_SUB_RTCM 1
param set-default GPS_1_GNSS 63
-param set-default MBE_ENABLE 1
+param set-default MBE_ENABLE 0
param set-default SENS_IMU_CLPNOTI 0
safety_button start
diff --git a/boards/ark/cannode/init/rc.board_defaults b/boards/ark/cannode/init/rc.board_defaults
index 7d149ce5ad..9fe7db23e0 100644
--- a/boards/ark/cannode/init/rc.board_defaults
+++ b/boards/ark/cannode/init/rc.board_defaults
@@ -3,6 +3,7 @@
# board specific defaults
#------------------------------------------------------------------------------
+param set-default MBE_ENABLE 0
param set-default SENS_IMU_CLPNOTI 0
pwm_out start
diff --git a/boards/ark/pi6x/nuttx-config/bootloader/defconfig b/boards/ark/pi6x/nuttx-config/bootloader/defconfig
index 745251793b..bba1ad3f39 100644
--- a/boards/ark/pi6x/nuttx-config/bootloader/defconfig
+++ b/boards/ark/pi6x/nuttx-config/bootloader/defconfig
@@ -32,7 +32,7 @@ CONFIG_BOARD_LOOPSPERMSEC=95150
CONFIG_BOARD_RESET_ON_ASSERT=2
CONFIG_CDCACM=y
CONFIG_CDCACM_IFLOWCONTROL=y
-CONFIG_CDCACM_PRODUCTID=0x0039
+CONFIG_CDCACM_PRODUCTID=0x003A
CONFIG_CDCACM_PRODUCTSTR="ARK BL Pi6X.x"
CONFIG_CDCACM_RXBUFSIZE=600
CONFIG_CDCACM_TXBUFSIZE=12000
diff --git a/boards/ark/pi6x/nuttx-config/nsh/defconfig b/boards/ark/pi6x/nuttx-config/nsh/defconfig
index 0e944e53c9..57ff449302 100644
--- a/boards/ark/pi6x/nuttx-config/nsh/defconfig
+++ b/boards/ark/pi6x/nuttx-config/nsh/defconfig
@@ -76,7 +76,7 @@ CONFIG_BOARD_RESET_ON_ASSERT=2
CONFIG_BUILTIN=y
CONFIG_CDCACM=y
CONFIG_CDCACM_IFLOWCONTROL=y
-CONFIG_CDCACM_PRODUCTID=0x0039
+CONFIG_CDCACM_PRODUCTID=0x003A
CONFIG_CDCACM_PRODUCTSTR="ARK Pi6X.x"
CONFIG_CDCACM_RXBUFSIZE=600
CONFIG_CDCACM_TXBUFSIZE=12000
diff --git a/boards/ark/septentrio-gps/init/rc.board_defaults b/boards/ark/septentrio-gps/init/rc.board_defaults
index 0db1234ce9..6ae5883882 100644
--- a/boards/ark/septentrio-gps/init/rc.board_defaults
+++ b/boards/ark/septentrio-gps/init/rc.board_defaults
@@ -6,7 +6,7 @@
param set-default CBRK_IO_SAFETY 0
param set-default CANNODE_SUB_MBD 1
param set-default CANNODE_SUB_RTCM 1
-param set-default MBE_ENABLE 1
+param set-default MBE_ENABLE 0
param set-default SENS_IMU_CLPNOTI 0
safety_button start
diff --git a/boards/ark/teseo-gps/init/rc.board_defaults b/boards/ark/teseo-gps/init/rc.board_defaults
index 610b5b418f..c765117f40 100644
--- a/boards/ark/teseo-gps/init/rc.board_defaults
+++ b/boards/ark/teseo-gps/init/rc.board_defaults
@@ -6,7 +6,7 @@
param set-default CBRK_IO_SAFETY 0
param set-default CANNODE_SUB_MBD 1
param set-default CANNODE_SUB_RTCM 1
-param set-default MBE_ENABLE 1
+param set-default MBE_ENABLE 0
param set-default SENS_IMU_CLPNOTI 0
tone_alarm start
diff --git a/boards/bitcraze/crazyflie/syslink/syslink_main.h b/boards/bitcraze/crazyflie/syslink/syslink_main.h
index a54859508d..8bf97b1c6e 100644
--- a/boards/bitcraze/crazyflie/syslink/syslink_main.h
+++ b/boards/bitcraze/crazyflie/syslink/syslink_main.h
@@ -139,7 +139,7 @@ private:
// nrf chip schedules battery updates with SYSLINK_SEND_PERIOD_MS
static constexpr uint32_t SYSLINK_BATTERY_STATUS_INTERVAL_US = 10_ms;
- Battery _battery{1, nullptr, SYSLINK_BATTERY_STATUS_INTERVAL_US, battery_status_s::BATTERY_SOURCE_POWER_MODULE};
+ Battery _battery{1, nullptr, SYSLINK_BATTERY_STATUS_INTERVAL_US, battery_status_s::SOURCE_POWER_MODULE};
int32_t _rssi;
battery_state _bstate;
diff --git a/boards/modalai/voxl2-slpi/default.px4board b/boards/modalai/voxl2-slpi/default.px4board
index db58d4e28a..1aec34124a 100644
--- a/boards/modalai/voxl2-slpi/default.px4board
+++ b/boards/modalai/voxl2-slpi/default.px4board
@@ -13,6 +13,7 @@ CONFIG_DRIVERS_MAGNETOMETER_QMC5883L=y
CONFIG_DRIVERS_POWER_MONITOR_VOXLPM=y
CONFIG_DRIVERS_QSHELL_QURT=y
CONFIG_DRIVERS_RC_CRSF_RC=y
+CONFIG_DRIVERS_VOXL2_IO=y
CONFIG_MODULES_COMMANDER=y
CONFIG_MODULES_CONTROL_ALLOCATOR=y
CONFIG_MODULES_EKF2=y
diff --git a/boards/modalai/voxl2-slpi/src/drivers/ghst_rc/ghst_rc.cpp b/boards/modalai/voxl2-slpi/src/drivers/ghst_rc/ghst_rc.cpp
index e213179922..9ad45c1389 100644
--- a/boards/modalai/voxl2-slpi/src/drivers/ghst_rc/ghst_rc.cpp
+++ b/boards/modalai/voxl2-slpi/src/drivers/ghst_rc/ghst_rc.cpp
@@ -207,15 +207,15 @@ void GhstRc::Run()
if (new_bytes > 0) {
_bytes_rx += new_bytes;
- int8_t ghst_rssi = -1;
- bool rc_updated = ghst_parse(cycle_timestamp, &_rcs_buf[0], new_bytes, &_raw_rc_values[0], &ghst_rssi,
+ ghstLinkStatistics_t link_stats = { .rssi_pct = -1, .rssi_dbm = NAN, .link_quality = 0 };
+ bool rc_updated = ghst_parse(cycle_timestamp, &_rcs_buf[0], new_bytes, &_raw_rc_values[0], &link_stats,
&_raw_rc_count, GHST_MAX_NUM_CHANNELS);
if (rc_updated) {
_last_packet_seen = time_now_us;
// we have a new GHST frame. Publish it.
_rc_in.input_source = input_rc_s::RC_INPUT_SOURCE_PX4FMU_GHST;
- fill_rc_in(_raw_rc_count, _raw_rc_values, cycle_timestamp, false, false, 0, ghst_rssi);
+ fill_rc_in(_raw_rc_count, _raw_rc_values, cycle_timestamp, false, false, 0, link_stats.rssi_pct);
// ghst telemetry works on fmu-v5
// on other Pixhawk (-related) boards we cannot write to the RC UART
diff --git a/boards/modalai/voxl2/default.px4board b/boards/modalai/voxl2/default.px4board
index 20860e3fce..63023ff4b9 100644
--- a/boards/modalai/voxl2/default.px4board
+++ b/boards/modalai/voxl2/default.px4board
@@ -1,7 +1,7 @@
CONFIG_PLATFORM_POSIX=y
CONFIG_BOARD_LINUX_TARGET=y
CONFIG_BOARD_TOOLCHAIN="aarch64-linux-gnu"
-CONFIG_BOARD_ROOTFSDIR="/data/px4"
+CONFIG_BOARD_ROOT_PATH="/data/px4"
CONFIG_DRIVERS_ACTUATORS_VOXL_ESC=y
CONFIG_DRIVERS_GPS=y
CONFIG_DRIVERS_OSD_MSP_OSD=y
diff --git a/boards/px4/fmu-v5x/performance-test.px4board b/boards/px4/fmu-v5x/performance-test.px4board
new file mode 100644
index 0000000000..5e69dd7ae3
--- /dev/null
+++ b/boards/px4/fmu-v5x/performance-test.px4board
@@ -0,0 +1,31 @@
+CONFIG_BOARD_TOOLCHAIN="arm-none-eabi"
+CONFIG_BOARD_ARCHITECTURE="cortex-m7"
+CONFIG_BOARD_ETHERNET=y
+CONFIG_BOARD_SERIAL_GPS1="/dev/ttyS0"
+CONFIG_BOARD_SERIAL_GPS2="/dev/ttyS7"
+CONFIG_BOARD_SERIAL_TEL1="/dev/ttyS6"
+CONFIG_BOARD_SERIAL_TEL2="/dev/ttyS4"
+CONFIG_BOARD_SERIAL_TEL3="/dev/ttyS1"
+CONFIG_BOARD_SERIAL_EXT2="/dev/ttyS3"
+CONFIG_BOARD_ROMFSROOT="performance-test"
+CONFIG_DRIVERS_ADC_BOARD_ADC=y
+CONFIG_SYSTEMCMDS_DMESG=y
+CONFIG_SYSTEMCMDS_GPIO=y
+CONFIG_SYSTEMCMDS_HARDFAULT_LOG=y
+CONFIG_SYSTEMCMDS_I2CDETECT=y
+CONFIG_SYSTEMCMDS_LED_CONTROL=y
+CONFIG_SYSTEMCMDS_MFT=y
+CONFIG_SYSTEMCMDS_MTD=y
+CONFIG_SYSTEMCMDS_MFT_CFG=y
+CONFIG_SYSTEMCMDS_PARAM=y
+CONFIG_SYSTEMCMDS_PERF=y
+CONFIG_SYSTEMCMDS_REBOOT=y
+CONFIG_SYSTEMCMDS_SD_BENCH=y
+CONFIG_SYSTEMCMDS_SD_STRESS=y
+CONFIG_SYSTEMCMDS_SERIAL_TEST=y
+CONFIG_SYSTEMCMDS_SYSTEM_TIME=y
+CONFIG_SYSTEMCMDS_TOP=y
+CONFIG_SYSTEMCMDS_TOPIC_LISTENER=y
+CONFIG_SYSTEMCMDS_UORB=y
+CONFIG_SYSTEMCMDS_VER=y
+CONFIG_SYSTEMCMDS_WORK_QUEUE=y
diff --git a/boards/px4/fmu-v6x/performance-test.px4board b/boards/px4/fmu-v6x/performance-test.px4board
new file mode 100644
index 0000000000..5e69dd7ae3
--- /dev/null
+++ b/boards/px4/fmu-v6x/performance-test.px4board
@@ -0,0 +1,31 @@
+CONFIG_BOARD_TOOLCHAIN="arm-none-eabi"
+CONFIG_BOARD_ARCHITECTURE="cortex-m7"
+CONFIG_BOARD_ETHERNET=y
+CONFIG_BOARD_SERIAL_GPS1="/dev/ttyS0"
+CONFIG_BOARD_SERIAL_GPS2="/dev/ttyS7"
+CONFIG_BOARD_SERIAL_TEL1="/dev/ttyS6"
+CONFIG_BOARD_SERIAL_TEL2="/dev/ttyS4"
+CONFIG_BOARD_SERIAL_TEL3="/dev/ttyS1"
+CONFIG_BOARD_SERIAL_EXT2="/dev/ttyS3"
+CONFIG_BOARD_ROMFSROOT="performance-test"
+CONFIG_DRIVERS_ADC_BOARD_ADC=y
+CONFIG_SYSTEMCMDS_DMESG=y
+CONFIG_SYSTEMCMDS_GPIO=y
+CONFIG_SYSTEMCMDS_HARDFAULT_LOG=y
+CONFIG_SYSTEMCMDS_I2CDETECT=y
+CONFIG_SYSTEMCMDS_LED_CONTROL=y
+CONFIG_SYSTEMCMDS_MFT=y
+CONFIG_SYSTEMCMDS_MTD=y
+CONFIG_SYSTEMCMDS_MFT_CFG=y
+CONFIG_SYSTEMCMDS_PARAM=y
+CONFIG_SYSTEMCMDS_PERF=y
+CONFIG_SYSTEMCMDS_REBOOT=y
+CONFIG_SYSTEMCMDS_SD_BENCH=y
+CONFIG_SYSTEMCMDS_SD_STRESS=y
+CONFIG_SYSTEMCMDS_SERIAL_TEST=y
+CONFIG_SYSTEMCMDS_SYSTEM_TIME=y
+CONFIG_SYSTEMCMDS_TOP=y
+CONFIG_SYSTEMCMDS_TOPIC_LISTENER=y
+CONFIG_SYSTEMCMDS_UORB=y
+CONFIG_SYSTEMCMDS_VER=y
+CONFIG_SYSTEMCMDS_WORK_QUEUE=y
diff --git a/boards/px4/sitl/default.px4board b/boards/px4/sitl/default.px4board
index b0b7a8a2b3..8eb8ebec8c 100644
--- a/boards/px4/sitl/default.px4board
+++ b/boards/px4/sitl/default.px4board
@@ -50,7 +50,9 @@ CONFIG_MODULES_ROVER_MECANUM=y
CONFIG_MODULES_ROVER_POS_CONTROL=y
CONFIG_MODULES_SENSORS=y
CONFIG_COMMON_SIMULATION=y
+CONFIG_MODULES_SIMULATION_GZ_MSGS=y
CONFIG_MODULES_SIMULATION_GZ_BRIDGE=y
+CONFIG_MODULES_SIMULATION_GZ_PLUGINS=y
CONFIG_MODULES_SIMULATION_SENSOR_AGP_SIM=y
CONFIG_MODULES_TEMPERATURE_COMPENSATION=y
CONFIG_MODULES_UUV_ATT_CONTROL=y
diff --git a/cmake/kconfig.cmake b/cmake/kconfig.cmake
index 7eaaa00d67..a5c79ad131 100644
--- a/cmake/kconfig.cmake
+++ b/cmake/kconfig.cmake
@@ -35,7 +35,7 @@ if(EXISTS ${BOARD_DEFCONFIG})
# Depend on BOARD_DEFCONFIG so that we reconfigure on config change
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${BOARD_DEFCONFIG})
- if(${LABEL} MATCHES "default" OR ${LABEL} MATCHES "recovery" OR ${LABEL} MATCHES "bootloader" OR ${LABEL} MATCHES "canbootloader")
+ if(${LABEL} MATCHES "default" OR ${LABEL} MATCHES "performance-test" OR ${LABEL} MATCHES "bootloader" OR ${LABEL} MATCHES "canbootloader")
# Generate boardconfig from saved defconfig
execute_process(
COMMAND ${CMAKE_COMMAND} -E env ${COMMON_KCONFIG_ENV_SETTINGS}
diff --git a/integrationtests/python_src/px4_it/mavros/missions/avoidance.plan b/integrationtests/python_src/px4_it/mavros/missions/avoidance.plan
deleted file mode 100644
index 1698c6b2bc..0000000000
--- a/integrationtests/python_src/px4_it/mavros/missions/avoidance.plan
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "fileType": "Plan",
- "geoFence": {
- "circles": [
- ],
- "polygons": [
- ],
- "version": 2
- },
- "groundStation": "QGroundControl",
- "mission": {
- "cruiseSpeed": 15,
- "firmwareType": 12,
- "hoverSpeed": 5,
- "items": [
- {
- "AMSLAltAboveTerrain": null,
- "Altitude": 4,
- "AltitudeMode": 0,
- "autoContinue": true,
- "command": 22,
- "doJumpId": 1,
- "frame": 3,
- "params": [
- 0,
- 0,
- 0,
- null,
- 47.3977432,
- 8.5456085,
- 4
- ],
- "type": "SimpleItem"
- },
- {
- "AMSLAltAboveTerrain": null,
- "Altitude": 4,
- "AltitudeMode": 0,
- "autoContinue": true,
- "command": 16,
- "doJumpId": 2,
- "frame": 3,
- "params": [
- 0,
- 0,
- 0,
- null,
- 47.3977432,
- 8.5458765,
- 4
- ],
- "type": "SimpleItem"
- },
- {
- "AMSLAltAboveTerrain": null,
- "Altitude": -1,
- "AltitudeMode": 0,
- "autoContinue": true,
- "command": 21,
- "doJumpId": 3,
- "frame": 3,
- "params": [
- 0,
- 0,
- 0,
- null,
- 47.3977432,
- 8.5458812,
- -1
- ],
- "type": "SimpleItem"
- }
- ],
- "plannedHomePosition": [
- 47.3977419,
- 8.5458854,
- 487.923
- ],
- "vehicleType": 2,
- "version": 2
- },
- "rallyPoints": {
- "points": [
- ],
- "version": 2
- },
- "version": 1
-}
diff --git a/msg/Airspeed.msg b/msg/Airspeed.msg
index aaed7b72ca..bc673cf0aa 100644
--- a/msg/Airspeed.msg
+++ b/msg/Airspeed.msg
@@ -5,6 +5,4 @@ float32 indicated_airspeed_m_s # indicated airspeed in m/s
float32 true_airspeed_m_s # true filtered airspeed in m/s
-float32 air_temperature_celsius # air temperature in degrees Celsius, -1000 if unknown
-
float32 confidence # confidence value from 0 to 1 for this sensor
diff --git a/msg/Buffer128.msg b/msg/Buffer128.msg
deleted file mode 100644
index 4ff939a87d..0000000000
--- a/msg/Buffer128.msg
+++ /dev/null
@@ -1,8 +0,0 @@
-uint64 timestamp # time since system start (microseconds)
-
-uint8 len # length of data
-uint32 MAX_BUFLEN = 128
-
-uint8[128] data # data
-
-# TOPICS voxl2_io_data
diff --git a/msg/CMakeLists.txt b/msg/CMakeLists.txt
index 51c9325413..8ef4407504 100644
--- a/msg/CMakeLists.txt
+++ b/msg/CMakeLists.txt
@@ -48,7 +48,6 @@ set(msg_files
AirspeedValidated.msg
AirspeedWind.msg
AutotuneAttitudeControlStatus.msg
- Buffer128.msg
ButtonEvent.msg
CameraCapture.msg
CameraStatus.msg
@@ -114,6 +113,7 @@ set(msg_files
HeaterStatus.msg
HoverThrustEstimate.msg
InputRc.msg
+ InternalCombustionEngineControl.msg
InternalCombustionEngineStatus.msg
IridiumsbdStatus.msg
IrlockReport.msg
@@ -173,17 +173,11 @@ set(msg_files
RcParameterMap.msg
RoverAttitudeSetpoint.msg
RoverAttitudeStatus.msg
- RoverVelocityStatus.msg
RoverRateSetpoint.msg
RoverRateStatus.msg
RoverSteeringSetpoint.msg
RoverThrottleSetpoint.msg
- RoverDifferentialGuidanceStatus.msg
- RoverDifferentialSetpoint.msg
- RoverDifferentialStatus.msg
- RoverMecanumGuidanceStatus.msg
- RoverMecanumSetpoint.msg
- RoverMecanumStatus.msg
+ RoverVelocityStatus.msg
Rpm.msg
RtlStatus.msg
RtlTimeEstimate.msg
@@ -214,8 +208,6 @@ set(msg_files
TelemetryStatus.msg
TiltrotorExtraControls.msg
TimesyncStatus.msg
- TrajectoryBezier.msg
- TrajectoryWaypoint.msg
TransponderReport.msg
TuneControl.msg
UavcanParameterRequest.msg
@@ -235,8 +227,6 @@ set(msg_files
VehicleRoi.msg
VehicleThrustSetpoint.msg
VehicleTorqueSetpoint.msg
- VehicleTrajectoryBezier.msg
- VehicleTrajectoryWaypoint.msg
VelocityLimits.msg
WheelEncoders.msg
Wind.msg
diff --git a/msg/GimbalManagerSetAttitude.msg b/msg/GimbalManagerSetAttitude.msg
index d88acca8b6..e1a174fd0b 100644
--- a/msg/GimbalManagerSetAttitude.msg
+++ b/msg/GimbalManagerSetAttitude.msg
@@ -20,3 +20,5 @@ float32[4] q
float32 angular_velocity_x
float32 angular_velocity_y
float32 angular_velocity_z
+
+uint8 ORB_QUEUE_LENGTH = 2
diff --git a/msg/InternalCombustionEngineControl.msg b/msg/InternalCombustionEngineControl.msg
new file mode 100644
index 0000000000..08b4198e01
--- /dev/null
+++ b/msg/InternalCombustionEngineControl.msg
@@ -0,0 +1,8 @@
+uint64 timestamp # time since system start (microseconds)
+
+bool ignition_on # activate/deactivate ignition (Spark Plug)
+float32 throttle_control # [0,1] - Motor should idle with 0. Includes slew rate if enabled.
+float32 choke_control # [0,1] - 1 fully closes the air inlet.
+float32 starter_engine_control # [0,1] - control value for electric starter motor.
+
+uint8 user_request # user intent for the ICE being on/off
diff --git a/msg/MavlinkTunnel.msg b/msg/MavlinkTunnel.msg
index 16934a9522..140bca5a1b 100644
--- a/msg/MavlinkTunnel.msg
+++ b/msg/MavlinkTunnel.msg
@@ -18,3 +18,6 @@ uint8 target_system # System ID (can be 0 for broadcast, but this is discou
uint8 target_component # Component ID (can be 0 for broadcast, but this is discouraged)
uint8 payload_length # Length of the data transported in payload
uint8[128] payload # Data itself
+
+# Topic aliases for known payload types
+# TOPICS mavlink_tunnel esc_serial_passthru
diff --git a/msg/PositionControllerStatus.msg b/msg/PositionControllerStatus.msg
index 7237351fd0..44ec5412ba 100644
--- a/msg/PositionControllerStatus.msg
+++ b/msg/PositionControllerStatus.msg
@@ -7,6 +7,4 @@ float32 target_bearing # Bearing angle from aircraft to current target [rad]
float32 xtrack_error # Signed track error [m]
float32 wp_dist # Distance to active (next) waypoint [m]
float32 acceptance_radius # Current horizontal acceptance radius [m]
-float32 yaw_acceptance # Yaw acceptance error[rad]
-float32 altitude_acceptance # Current vertical acceptance error [m]
uint8 type # Current (applied) position setpoint type (see PositionSetpoint.msg)
diff --git a/msg/RoverDifferentialGuidanceStatus.msg b/msg/RoverDifferentialGuidanceStatus.msg
deleted file mode 100644
index ce3d375111..0000000000
--- a/msg/RoverDifferentialGuidanceStatus.msg
+++ /dev/null
@@ -1,7 +0,0 @@
-uint64 timestamp # time since system start (microseconds)
-
-float32 lookahead_distance # [m] Lookahead distance of pure the pursuit controller
-float32 heading_error_deg # [deg] Heading error of the pure pursuit controller
-uint8 state_machine # Driving state of the rover [0: SPOT_TURNING, 1: DRIVING, 2: GOAL_REACHED]
-
-# TOPICS rover_differential_guidance_status
diff --git a/msg/RoverDifferentialSetpoint.msg b/msg/RoverDifferentialSetpoint.msg
deleted file mode 100644
index 100cc6b3cd..0000000000
--- a/msg/RoverDifferentialSetpoint.msg
+++ /dev/null
@@ -1,9 +0,0 @@
-uint64 timestamp # time since system start (microseconds)
-
-float32 forward_speed_setpoint # [m/s] Desired forward speed for the rover
-float32 forward_speed_setpoint_normalized # [-1, 1] Normalized forward speed for the rover
-float32 yaw_rate_setpoint # [rad/s] Desired yaw rate for the rover (Overriden by yaw controller if yaw_setpoint is used)
-float32 speed_diff_setpoint_normalized # [-1, 1] Normalized speed difference between the left and right wheels
-float32 yaw_setpoint # [rad] Desired yaw (heading) for the rover
-
-# TOPICS rover_differential_setpoint
diff --git a/msg/RoverDifferentialStatus.msg b/msg/RoverDifferentialStatus.msg
deleted file mode 100644
index 767474fb5b..0000000000
--- a/msg/RoverDifferentialStatus.msg
+++ /dev/null
@@ -1,14 +0,0 @@
-uint64 timestamp # time since system start (microseconds)
-
-float32 measured_forward_speed # [m/s] Measured speed in body x direction. Forwards: positiv, Backwards: negativ
-float32 adjusted_forward_speed_setpoint # [m/s] Speed setpoint after applying slew rate
-float32 measured_yaw # [rad] Measured yaw
-float32 adjusted_yaw_setpoint # [rad] Yaw setpoint after applying slew rate
-float32 clyaw_yaw_rate_setpoint # [rad/s] Yaw rate setpoint output by the closed loop yaw controller
-float32 measured_yaw_rate # [rad/s] Measured yaw rate
-float32 adjusted_yaw_rate_setpoint # [rad/s] Yaw rate setpoint from the closed loop yaw controller
-float32 pid_yaw_integral # Integral of the PID for the closed loop yaw controller
-float32 pid_yaw_rate_integral # Integral of the PID for the closed loop yaw rate controller
-float32 pid_throttle_integral # Integral of the PID for the closed loop speed controller
-
-# TOPICS rover_differential_status
diff --git a/msg/RoverMecanumGuidanceStatus.msg b/msg/RoverMecanumGuidanceStatus.msg
deleted file mode 100644
index fba920033b..0000000000
--- a/msg/RoverMecanumGuidanceStatus.msg
+++ /dev/null
@@ -1,7 +0,0 @@
-uint64 timestamp # time since system start (microseconds)
-
-float32 lookahead_distance # [m] Lookahead distance of pure the pursuit controller
-float32 heading_error # [rad] Heading error of the pure pursuit controller
-float32 desired_speed # [m/s] Desired velocity magnitude (speed)
-
-# TOPICS rover_mecanum_guidance_status
diff --git a/msg/RoverMecanumSetpoint.msg b/msg/RoverMecanumSetpoint.msg
deleted file mode 100644
index 0cc9415be1..0000000000
--- a/msg/RoverMecanumSetpoint.msg
+++ /dev/null
@@ -1,11 +0,0 @@
-uint64 timestamp # time since system start (microseconds)
-
-float32 forward_speed_setpoint # [m/s] Desired forward speed
-float32 forward_speed_setpoint_normalized # [-1, 1] Desired normalized forward speed
-float32 lateral_speed_setpoint # [m/s] Desired lateral speed
-float32 lateral_speed_setpoint_normalized # [-1, 1] Desired normalized lateral speed
-float32 yaw_rate_setpoint # [rad/s] Desired yaw rate
-float32 speed_diff_setpoint_normalized # [-1, 1] Normalized speed difference between the left and right wheels
-float32 yaw_setpoint # [rad] Desired yaw (heading)
-
-# TOPICS rover_mecanum_setpoint
diff --git a/msg/RoverMecanumStatus.msg b/msg/RoverMecanumStatus.msg
deleted file mode 100644
index 7547fd5be6..0000000000
--- a/msg/RoverMecanumStatus.msg
+++ /dev/null
@@ -1,17 +0,0 @@
-uint64 timestamp # time since system start (microseconds)
-
-float32 measured_forward_speed # [m/s] Measured speed in body x direction. Positiv: forwards, Negativ: backwards
-float32 adjusted_forward_speed_setpoint # [m/s] Speed setpoint after applying slew rate
-float32 measured_lateral_speed # [m/s] Measured speed in body y direction. Positiv: right, Negativ: left
-float32 adjusted_lateral_speed_setpoint # [m/s] Speed setpoint after applying slew rate
-float32 measured_yaw_rate # [rad/s] Measured yaw rate
-float32 clyaw_yaw_rate_setpoint # [rad/s] Yaw rate setpoint output by the closed loop yaw controller
-float32 adjusted_yaw_rate_setpoint # [rad/s] Yaw rate setpoint from the closed loop yaw controller
-float32 measured_yaw # [rad] Measured yaw
-float32 adjusted_yaw_setpoint # [rad] Yaw setpoint after applying slew rate
-float32 pid_yaw_rate_integral # Integral of the PID for the closed loop yaw rate controller
-float32 pid_yaw_integral # Integral of the PID for the closed loop yaw controller
-float32 pid_forward_throttle_integral # Integral of the PID for the closed loop forward speed controller
-float32 pid_lateral_throttle_integral # Integral of the PID for the closed loop lateral speed controller
-
-# TOPICS rover_mecanum_status
diff --git a/msg/SensorOpticalFlow.msg b/msg/SensorOpticalFlow.msg
index ce7e8bf08c..ed6a3cfefb 100644
--- a/msg/SensorOpticalFlow.msg
+++ b/msg/SensorOpticalFlow.msg
@@ -3,7 +3,7 @@ uint64 timestamp_sample
uint32 device_id # unique device ID for the sensor that does not change between power cycles
-float32[2] pixel_flow # (radians) optical flow in radians where a positive value is produced by a RH rotation about the body axis
+float32[2] pixel_flow # (radians) optical flow in radians where a positive value is produced by a RH rotation of the sensor about the body axis
float32[3] delta_angle # (radians) accumulated gyro radians where a positive value is produced by a RH rotation about the body axis. Set to NaN if flow sensor does not have 3-axis gyro data.
bool delta_angle_available
diff --git a/msg/TelemetryStatus.msg b/msg/TelemetryStatus.msg
index 48d85f934d..b2b3920a36 100644
--- a/msg/TelemetryStatus.msg
+++ b/msg/TelemetryStatus.msg
@@ -51,13 +51,11 @@ bool heartbeat_type_open_drone_id # MAV_TYPE_ODID
bool heartbeat_component_telemetry_radio # MAV_COMP_ID_TELEMETRY_RADIO
bool heartbeat_component_log # MAV_COMP_ID_LOG
bool heartbeat_component_osd # MAV_COMP_ID_OSD
-bool heartbeat_component_obstacle_avoidance # MAV_COMP_ID_OBSTACLE_AVOIDANCE
bool heartbeat_component_vio # MAV_COMP_ID_VISUAL_INERTIAL_ODOMETRY
bool heartbeat_component_pairing_manager # MAV_COMP_ID_PAIRING_MANAGER
bool heartbeat_component_udp_bridge # MAV_COMP_ID_UDP_BRIDGE
bool heartbeat_component_uart_bridge # MAV_COMP_ID_UART_BRIDGE
# Misc component health
-bool avoidance_system_healthy
bool open_drone_id_system_healthy
bool parachute_system_healthy
diff --git a/msg/TrajectoryBezier.msg b/msg/TrajectoryBezier.msg
deleted file mode 100644
index e3d9d4e0ff..0000000000
--- a/msg/TrajectoryBezier.msg
+++ /dev/null
@@ -1,8 +0,0 @@
-# Bezier Trajectory description. See also Mavlink TRAJECTORY msg
-# The topic trajectory_bezier describe each waypoint defined in vehicle_trajectory_bezier
-
-uint64 timestamp # time since system start (microseconds)
-
-float32[3] position # local position x,y,z (metres)
-float32 yaw # yaw angle (rad)
-float32 delta # time it should take to get to this waypoint, if this is the final waypoint (seconds)
diff --git a/msg/TrajectoryWaypoint.msg b/msg/TrajectoryWaypoint.msg
deleted file mode 100644
index 6ea9bae4d3..0000000000
--- a/msg/TrajectoryWaypoint.msg
+++ /dev/null
@@ -1,13 +0,0 @@
-# Waypoint Trajectory description. See also Mavlink TRAJECTORY msg
-# The topic trajectory_waypoint describe each waypoint defined in vehicle_trajectory_waypoint
-
-uint64 timestamp # time since system start (microseconds)
-
-float32[3] position
-float32[3] velocity
-float32[3] acceleration
-float32 yaw
-float32 yaw_speed
-
-bool point_valid
-uint8 type
diff --git a/msg/VehicleAirData.msg b/msg/VehicleAirData.msg
index 59ca5e5c8d..41e5358ae8 100644
--- a/msg/VehicleAirData.msg
+++ b/msg/VehicleAirData.msg
@@ -6,10 +6,10 @@ uint64 timestamp_sample # the timestamp of the raw data (microseconds)
uint32 baro_device_id # unique device ID for the selected barometer
float32 baro_alt_meter # Altitude above MSL calculated from temperature compensated baro sensor data using an ISA corrected for sea level pressure SENS_BARO_QNH.
-float32 baro_temp_celcius # Temperature in degrees Celsius
float32 baro_pressure_pa # Absolute pressure in Pascals
+float32 ambient_temperature # Abient temperature in degrees Celsius
+uint8 temperature_source # Source of temperature data: 0: Default Temperature (15°C), 1: External Baro, 2: Airspeed
float32 rho # air density
-float32 eas2tas # equivalent airspeed to true airspeed conversion factor
uint8 calibration_count # Calibration changed counter. Monotonically increases whenever calibration changes.
diff --git a/msg/VehicleOpticalFlow.msg b/msg/VehicleOpticalFlow.msg
index 13bdb57bbf..23472b4c97 100644
--- a/msg/VehicleOpticalFlow.msg
+++ b/msg/VehicleOpticalFlow.msg
@@ -7,7 +7,7 @@ uint32 device_id # unique device ID for the sensor that does not c
float32[2] pixel_flow # (radians) accumulated optical flow in radians where a positive value is produced by a RH rotation about the body axis
-float32[3] delta_angle # (radians) accumulated gyro radians where a positive value is produced by a RH rotation about the body axis. (NAN if unavailable)
+float32[3] delta_angle # (radians) accumulated gyro radians where a positive value is produced by a RH rotation of the sensor about the body axis. (NAN if unavailable)
float32 distance_m # (meters) Distance to the center of the flow field (NAN if unavailable)
diff --git a/msg/VehicleTrajectoryBezier.msg b/msg/VehicleTrajectoryBezier.msg
deleted file mode 100644
index d4bf99b469..0000000000
--- a/msg/VehicleTrajectoryBezier.msg
+++ /dev/null
@@ -1,18 +0,0 @@
-# Vehicle Waypoints Trajectory description. See also MAVLink MAV_TRAJECTORY_REPRESENTATION msg
-# The topic vehicle_trajectory_bezier is used to send a smooth flight path from the
-# companion computer / avoidance module to the position controller.
-
-uint64 timestamp # time since system start (microseconds)
-
-uint8 POINT_0 = 0
-uint8 POINT_1 = 1
-uint8 POINT_2 = 2
-uint8 POINT_3 = 3
-uint8 POINT_4 = 4
-
-uint8 NUMBER_POINTS = 5
-
-TrajectoryBezier[5] control_points
-uint8 bezier_order
-
-# TOPICS vehicle_trajectory_bezier
diff --git a/msg/VehicleTrajectoryWaypoint.msg b/msg/VehicleTrajectoryWaypoint.msg
deleted file mode 100644
index 6bff1cec84..0000000000
--- a/msg/VehicleTrajectoryWaypoint.msg
+++ /dev/null
@@ -1,21 +0,0 @@
-# Vehicle Waypoints Trajectory description. See also MAVLink MAV_TRAJECTORY_REPRESENTATION msg
-# The topic vehicle_trajectory_waypoint_desired is used to send the user desired waypoints from the position controller to the companion computer / avoidance module.
-# The topic vehicle_trajectory_waypoint is used to send the adjusted waypoints from the companion computer / avoidance module to the position controller.
-
-uint64 timestamp # time since system start (microseconds)
-
-uint8 MAV_TRAJECTORY_REPRESENTATION_WAYPOINTS = 0
-
-uint8 type # Type from MAV_TRAJECTORY_REPRESENTATION enum.
-
-uint8 POINT_0 = 0
-uint8 POINT_1 = 1
-uint8 POINT_2 = 2
-uint8 POINT_3 = 3
-uint8 POINT_4 = 4
-
-uint8 NUMBER_POINTS = 5
-
-TrajectoryWaypoint[5] waypoints
-
-# TOPICS vehicle_trajectory_waypoint vehicle_trajectory_waypoint_desired
diff --git a/msg/px4_msgs_old/msg/VehicleStatusV0.msg b/msg/px4_msgs_old/msg/VehicleStatusV0.msg
new file mode 100644
index 0000000000..a347dfce3d
--- /dev/null
+++ b/msg/px4_msgs_old/msg/VehicleStatusV0.msg
@@ -0,0 +1,140 @@
+# Encodes the system state of the vehicle published by commander
+
+uint32 MESSAGE_VERSION = 0
+
+uint64 timestamp # time since system start (microseconds)
+
+uint64 armed_time # Arming timestamp (microseconds)
+uint64 takeoff_time # Takeoff timestamp (microseconds)
+
+uint8 arming_state
+uint8 ARMING_STATE_DISARMED = 1
+uint8 ARMING_STATE_ARMED = 2
+
+uint8 latest_arming_reason
+uint8 latest_disarming_reason
+uint8 ARM_DISARM_REASON_TRANSITION_TO_STANDBY = 0
+uint8 ARM_DISARM_REASON_STICK_GESTURE = 1
+uint8 ARM_DISARM_REASON_RC_SWITCH = 2
+uint8 ARM_DISARM_REASON_COMMAND_INTERNAL = 3
+uint8 ARM_DISARM_REASON_COMMAND_EXTERNAL = 4
+uint8 ARM_DISARM_REASON_MISSION_START = 5
+uint8 ARM_DISARM_REASON_SAFETY_BUTTON = 6
+uint8 ARM_DISARM_REASON_AUTO_DISARM_LAND = 7
+uint8 ARM_DISARM_REASON_AUTO_DISARM_PREFLIGHT = 8
+uint8 ARM_DISARM_REASON_KILL_SWITCH = 9
+uint8 ARM_DISARM_REASON_LOCKDOWN = 10
+uint8 ARM_DISARM_REASON_FAILURE_DETECTOR = 11
+uint8 ARM_DISARM_REASON_SHUTDOWN = 12
+uint8 ARM_DISARM_REASON_UNIT_TEST = 13
+
+uint64 nav_state_timestamp # time when current nav_state activated
+
+uint8 nav_state_user_intention # Mode that the user selected (might be different from nav_state in a failsafe situation)
+
+uint8 nav_state # Currently active mode
+uint8 NAVIGATION_STATE_MANUAL = 0 # Manual mode
+uint8 NAVIGATION_STATE_ALTCTL = 1 # Altitude control mode
+uint8 NAVIGATION_STATE_POSCTL = 2 # Position control mode
+uint8 NAVIGATION_STATE_AUTO_MISSION = 3 # Auto mission mode
+uint8 NAVIGATION_STATE_AUTO_LOITER = 4 # Auto loiter mode
+uint8 NAVIGATION_STATE_AUTO_RTL = 5 # Auto return to launch mode
+uint8 NAVIGATION_STATE_POSITION_SLOW = 6
+uint8 NAVIGATION_STATE_FREE5 = 7
+uint8 NAVIGATION_STATE_FREE4 = 8
+uint8 NAVIGATION_STATE_FREE3 = 9
+uint8 NAVIGATION_STATE_ACRO = 10 # Acro mode
+uint8 NAVIGATION_STATE_FREE2 = 11
+uint8 NAVIGATION_STATE_DESCEND = 12 # Descend mode (no position control)
+uint8 NAVIGATION_STATE_TERMINATION = 13 # Termination mode
+uint8 NAVIGATION_STATE_OFFBOARD = 14
+uint8 NAVIGATION_STATE_STAB = 15 # Stabilized mode
+uint8 NAVIGATION_STATE_FREE1 = 16
+uint8 NAVIGATION_STATE_AUTO_TAKEOFF = 17 # Takeoff
+uint8 NAVIGATION_STATE_AUTO_LAND = 18 # Land
+uint8 NAVIGATION_STATE_AUTO_FOLLOW_TARGET = 19 # Auto Follow
+uint8 NAVIGATION_STATE_AUTO_PRECLAND = 20 # Precision land with landing target
+uint8 NAVIGATION_STATE_ORBIT = 21 # Orbit in a circle
+uint8 NAVIGATION_STATE_AUTO_VTOL_TAKEOFF = 22 # Takeoff, transition, establish loiter
+uint8 NAVIGATION_STATE_EXTERNAL1 = 23
+uint8 NAVIGATION_STATE_EXTERNAL2 = 24
+uint8 NAVIGATION_STATE_EXTERNAL3 = 25
+uint8 NAVIGATION_STATE_EXTERNAL4 = 26
+uint8 NAVIGATION_STATE_EXTERNAL5 = 27
+uint8 NAVIGATION_STATE_EXTERNAL6 = 28
+uint8 NAVIGATION_STATE_EXTERNAL7 = 29
+uint8 NAVIGATION_STATE_EXTERNAL8 = 30
+uint8 NAVIGATION_STATE_MAX = 31
+
+uint8 executor_in_charge # Current mode executor in charge (0=Autopilot)
+
+uint32 valid_nav_states_mask # Bitmask for all valid nav_state values
+uint32 can_set_nav_states_mask # Bitmask for all modes that a user can select
+
+# Bitmask of detected failures
+uint16 failure_detector_status
+uint16 FAILURE_NONE = 0
+uint16 FAILURE_ROLL = 1 # (1 << 0)
+uint16 FAILURE_PITCH = 2 # (1 << 1)
+uint16 FAILURE_ALT = 4 # (1 << 2)
+uint16 FAILURE_EXT = 8 # (1 << 3)
+uint16 FAILURE_ARM_ESC = 16 # (1 << 4)
+uint16 FAILURE_BATTERY = 32 # (1 << 5)
+uint16 FAILURE_IMBALANCED_PROP = 64 # (1 << 6)
+uint16 FAILURE_MOTOR = 128 # (1 << 7)
+
+uint8 hil_state
+uint8 HIL_STATE_OFF = 0
+uint8 HIL_STATE_ON = 1
+
+# If it's a VTOL, then the value will be VEHICLE_TYPE_ROTARY_WING while flying as a multicopter, and VEHICLE_TYPE_FIXED_WING when flying as a fixed-wing
+uint8 vehicle_type
+uint8 VEHICLE_TYPE_UNKNOWN = 0
+uint8 VEHICLE_TYPE_ROTARY_WING = 1
+uint8 VEHICLE_TYPE_FIXED_WING = 2
+uint8 VEHICLE_TYPE_ROVER = 3
+uint8 VEHICLE_TYPE_AIRSHIP = 4
+
+uint8 FAILSAFE_DEFER_STATE_DISABLED = 0
+uint8 FAILSAFE_DEFER_STATE_ENABLED = 1
+uint8 FAILSAFE_DEFER_STATE_WOULD_FAILSAFE = 2 # Failsafes deferred, but would trigger a failsafe
+
+bool failsafe # true if system is in failsafe state (e.g.:RTL, Hover, Terminate, ...)
+bool failsafe_and_user_took_over # true if system is in failsafe state but the user took over control
+uint8 failsafe_defer_state # one of FAILSAFE_DEFER_STATE_*
+
+# Link loss
+bool gcs_connection_lost # datalink to GCS lost
+uint8 gcs_connection_lost_counter # counts unique GCS connection lost events
+bool high_latency_data_link_lost # Set to true if the high latency data link (eg. RockBlock Iridium 9603 telemetry module) is lost
+
+# VTOL flags
+bool is_vtol # True if the system is VTOL capable
+bool is_vtol_tailsitter # True if the system performs a 90° pitch down rotation during transition from MC to FW
+bool in_transition_mode # True if VTOL is doing a transition
+bool in_transition_to_fw # True if VTOL is doing a transition from MC to FW
+
+# MAVLink identification
+uint8 system_type # system type, contains mavlink MAV_TYPE
+uint8 system_id # system id, contains MAVLink's system ID field
+uint8 component_id # subsystem / component id, contains MAVLink's component ID field
+
+bool safety_button_available # Set to true if a safety button is connected
+bool safety_off # Set to true if safety is off
+
+bool power_input_valid # set if input power is valid
+bool usb_connected # set to true (never cleared) once telemetry received from usb link
+
+bool open_drone_id_system_present
+bool open_drone_id_system_healthy
+
+bool parachute_system_present
+bool parachute_system_healthy
+
+bool avoidance_system_required # Set to true if avoidance system is enabled via COM_OBS_AVOID parameter
+bool avoidance_system_valid # Status of the obstacle avoidance system
+
+bool rc_calibration_in_progress
+bool calibration_enabled
+
+bool pre_flight_checks_pass # true if all checks necessary to arm pass
diff --git a/msg/translation_node/translations/all_translations.h b/msg/translation_node/translations/all_translations.h
index 2b3c2030b4..4369a3c58a 100644
--- a/msg/translation_node/translations/all_translations.h
+++ b/msg/translation_node/translations/all_translations.h
@@ -9,3 +9,5 @@
//#include "example_translation_direct_v1.h"
//#include "example_translation_multi_v2.h"
//#include "example_translation_service_v1.h"
+
+#include "translation_vehicle_status_v1.h"
diff --git a/msg/translation_node/translations/translation_vehicle_status_v1.h b/msg/translation_node/translations/translation_vehicle_status_v1.h
new file mode 100644
index 0000000000..2041b013d8
--- /dev/null
+++ b/msg/translation_node/translations/translation_vehicle_status_v1.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+ * Copyright (c) 2025 PX4 Development Team.
+ * SPDX-License-Identifier: BSD-3-Clause
+ ****************************************************************************/
+#pragma once
+
+// Translate VehicleStatus v0 <--> v1
+#include
+#include
+
+class VehicleStatusV1Translation {
+public:
+ using MessageOlder = px4_msgs_old::msg::VehicleStatusV0;
+ static_assert(MessageOlder::MESSAGE_VERSION == 0);
+
+ using MessageNewer = px4_msgs::msg::VehicleStatus;
+ static_assert(MessageNewer::MESSAGE_VERSION == 1);
+
+ static constexpr const char* kTopic = "fmu/out/vehicle_status";
+
+ static void fromOlder(const MessageOlder &msg_older, MessageNewer &msg_newer) {
+ // Set msg_newer from msg_older
+ msg_newer.timestamp = msg_older.timestamp;
+ msg_newer.armed_time = msg_older.armed_time;
+ msg_newer.takeoff_time = msg_older.takeoff_time;
+ msg_newer.arming_state = msg_older.arming_state;
+ msg_newer.latest_arming_reason = msg_older.latest_arming_reason;
+ msg_newer.latest_disarming_reason = msg_older.latest_disarming_reason;
+ msg_newer.nav_state_timestamp = msg_older.nav_state_timestamp;
+ msg_newer.nav_state_user_intention = msg_older.nav_state_user_intention;
+ msg_newer.nav_state = msg_older.nav_state;
+ msg_newer.executor_in_charge = msg_older.executor_in_charge;
+ msg_newer.valid_nav_states_mask = msg_older.valid_nav_states_mask;
+ msg_newer.can_set_nav_states_mask = msg_older.can_set_nav_states_mask;
+ msg_newer.failure_detector_status = msg_older.failure_detector_status;
+ msg_newer.hil_state = msg_older.hil_state;
+ msg_newer.vehicle_type = msg_older.vehicle_type;
+ msg_newer.failsafe = msg_older.failsafe;
+ msg_newer.failsafe_and_user_took_over = msg_older.failsafe_and_user_took_over;
+ msg_newer.failsafe_defer_state = msg_older.failsafe_defer_state;
+ msg_newer.gcs_connection_lost = msg_older.gcs_connection_lost;
+ msg_newer.gcs_connection_lost_counter = msg_older.gcs_connection_lost_counter;
+ msg_newer.high_latency_data_link_lost = msg_older.high_latency_data_link_lost;
+ msg_newer.is_vtol = msg_older.is_vtol;
+ msg_newer.is_vtol_tailsitter = msg_older.is_vtol_tailsitter;
+ msg_newer.in_transition_mode = msg_older.in_transition_mode;
+ msg_newer.in_transition_to_fw = msg_older.in_transition_to_fw;
+ msg_newer.system_type = msg_older.system_type;
+ msg_newer.system_id = msg_older.system_id;
+ msg_newer.component_id = msg_older.component_id;
+ msg_newer.safety_button_available = msg_older.safety_button_available;
+ msg_newer.safety_off = msg_older.safety_off;
+ msg_newer.power_input_valid = msg_older.power_input_valid;
+ msg_newer.usb_connected = msg_older.usb_connected;
+ msg_newer.open_drone_id_system_present = msg_older.open_drone_id_system_present;
+ msg_newer.open_drone_id_system_healthy = msg_older.open_drone_id_system_healthy;
+ msg_newer.parachute_system_present = msg_older.parachute_system_present;
+ msg_newer.parachute_system_healthy = msg_older.parachute_system_healthy;
+ msg_newer.rc_calibration_in_progress = msg_older.rc_calibration_in_progress;
+ msg_newer.calibration_enabled = msg_older.calibration_enabled;
+ msg_newer.pre_flight_checks_pass = msg_older.pre_flight_checks_pass;
+ }
+
+ static void toOlder(const MessageNewer &msg_newer, MessageOlder &msg_older) {
+ // Set msg_older from msg_newer
+ msg_older.timestamp = msg_newer.timestamp;
+ msg_older.armed_time = msg_newer.armed_time;
+ msg_older.takeoff_time = msg_newer.takeoff_time;
+ msg_older.arming_state = msg_newer.arming_state;
+ msg_older.latest_arming_reason = msg_newer.latest_arming_reason;
+ msg_older.latest_disarming_reason = msg_newer.latest_disarming_reason;
+ msg_older.nav_state_timestamp = msg_newer.nav_state_timestamp;
+ msg_older.nav_state_user_intention = msg_newer.nav_state_user_intention;
+ msg_older.nav_state = msg_newer.nav_state;
+ msg_older.executor_in_charge = msg_newer.executor_in_charge;
+ msg_older.valid_nav_states_mask = msg_newer.valid_nav_states_mask;
+ msg_older.can_set_nav_states_mask = msg_newer.can_set_nav_states_mask;
+ msg_older.failure_detector_status = msg_newer.failure_detector_status;
+ msg_older.hil_state = msg_newer.hil_state;
+ msg_older.vehicle_type = msg_newer.vehicle_type;
+ msg_older.failsafe = msg_newer.failsafe;
+ msg_older.failsafe_and_user_took_over = msg_newer.failsafe_and_user_took_over;
+ msg_older.failsafe_defer_state = msg_newer.failsafe_defer_state;
+ msg_older.gcs_connection_lost = msg_newer.gcs_connection_lost;
+ msg_older.gcs_connection_lost_counter = msg_newer.gcs_connection_lost_counter;
+ msg_older.high_latency_data_link_lost = msg_newer.high_latency_data_link_lost;
+ msg_older.is_vtol = msg_newer.is_vtol;
+ msg_older.is_vtol_tailsitter = msg_newer.is_vtol_tailsitter;
+ msg_older.in_transition_mode = msg_newer.in_transition_mode;
+ msg_older.in_transition_to_fw = msg_newer.in_transition_to_fw;
+ msg_older.system_type = msg_newer.system_type;
+ msg_older.system_id = msg_newer.system_id;
+ msg_older.component_id = msg_newer.component_id;
+ msg_older.safety_button_available = msg_newer.safety_button_available;
+ msg_older.safety_off = msg_newer.safety_off;
+ msg_older.power_input_valid = msg_newer.power_input_valid;
+ msg_older.usb_connected = msg_newer.usb_connected;
+ msg_older.open_drone_id_system_present = msg_newer.open_drone_id_system_present;
+ msg_older.open_drone_id_system_healthy = msg_newer.open_drone_id_system_healthy;
+ msg_older.parachute_system_present = msg_newer.parachute_system_present;
+ msg_older.parachute_system_healthy = msg_newer.parachute_system_healthy;
+ msg_older.avoidance_system_required = false;
+ msg_older.avoidance_system_valid = false;
+ msg_older.rc_calibration_in_progress = msg_newer.rc_calibration_in_progress;
+ msg_older.calibration_enabled = msg_newer.calibration_enabled;
+ msg_older.pre_flight_checks_pass = msg_newer.pre_flight_checks_pass;
+ }
+};
+
+REGISTER_TOPIC_TRANSLATION_DIRECT(VehicleStatusV1Translation);
diff --git a/msg/versioned/ArmingCheckReply.msg b/msg/versioned/ArmingCheckReply.msg
index 1a1aaa5183..4c1616d849 100644
--- a/msg/versioned/ArmingCheckReply.msg
+++ b/msg/versioned/ArmingCheckReply.msg
@@ -6,7 +6,6 @@ uint8 request_id
uint8 registration_id
uint8 HEALTH_COMPONENT_INDEX_NONE = 0
-uint8 HEALTH_COMPONENT_INDEX_AVOIDANCE = 19
uint8 health_component_index # HEALTH_COMPONENT_INDEX_*
bool health_component_is_present
diff --git a/msg/versioned/BatteryStatus.msg b/msg/versioned/BatteryStatus.msg
index 9838786f3f..852db501df 100644
--- a/msg/versioned/BatteryStatus.msg
+++ b/msg/versioned/BatteryStatus.msg
@@ -12,9 +12,9 @@ float32 time_remaining_s # predicted time in seconds remaining until battery i
float32 temperature # Temperature of the battery in degrees Celcius, NaN if unknown
uint8 cell_count # Number of cells, 0 if unknown
-uint8 BATTERY_SOURCE_POWER_MODULE = 0
-uint8 BATTERY_SOURCE_EXTERNAL = 1
-uint8 BATTERY_SOURCE_ESCS = 2
+uint8 SOURCE_POWER_MODULE = 0
+uint8 SOURCE_EXTERNAL = 1
+uint8 SOURCE_ESCS = 2
uint8 source # Battery source
uint8 priority # Zero based priority is the connection on the Power Controller V1..Vn AKA BrickN-1
uint16 capacity # actual capacity of the battery
@@ -34,26 +34,26 @@ bool is_powering_off # Power off event imminent indication, false if unknown
bool is_required # Set if the battery is explicitly required before arming
-uint8 BATTERY_WARNING_NONE = 0 # no battery low voltage warning active
-uint8 BATTERY_WARNING_LOW = 1 # warning of low voltage
-uint8 BATTERY_WARNING_CRITICAL = 2 # critical voltage, return / abort immediately
-uint8 BATTERY_WARNING_EMERGENCY = 3 # immediate landing required
-uint8 BATTERY_WARNING_FAILED = 4 # the battery has failed completely
-uint8 BATTERY_STATE_UNHEALTHY = 6 # Battery is diagnosed to be defective or an error occurred, usage is discouraged / prohibited. Possible causes (faults) are listed in faults field.
-uint8 BATTERY_STATE_CHARGING = 7 # Battery is charging
+uint8 WARNING_NONE = 0 # no battery low voltage warning active
+uint8 WARNING_LOW = 1 # warning of low voltage
+uint8 WARNING_CRITICAL = 2 # critical voltage, return / abort immediately
+uint8 WARNING_EMERGENCY = 3 # immediate landing required
+uint8 WARNING_FAILED = 4 # the battery has failed completely
+uint8 STATE_UNHEALTHY = 6 # Battery is diagnosed to be defective or an error occurred, usage is discouraged / prohibited. Possible causes (faults) are listed in faults field.
+uint8 STATE_CHARGING = 7 # Battery is charging
-uint8 BATTERY_FAULT_DEEP_DISCHARGE = 0 # Battery has deep discharged
-uint8 BATTERY_FAULT_SPIKES = 1 # Voltage spikes
-uint8 BATTERY_FAULT_CELL_FAIL= 2 # One or more cells have failed
-uint8 BATTERY_FAULT_OVER_CURRENT = 3 # Over-current
-uint8 BATTERY_FAULT_OVER_TEMPERATURE = 4 # Over-temperature
-uint8 BATTERY_FAULT_UNDER_TEMPERATURE = 5 # Under-temperature fault
-uint8 BATTERY_FAULT_INCOMPATIBLE_VOLTAGE = 6 # Vehicle voltage is not compatible with this battery (batteries on same power rail should have similar voltage).
-uint8 BATTERY_FAULT_INCOMPATIBLE_FIRMWARE = 7 # Battery firmware is not compatible with current autopilot firmware
-uint8 BATTERY_FAULT_INCOMPATIBLE_MODEL = 8 # Battery model is not supported by the system
-uint8 BATTERY_FAULT_HARDWARE_FAILURE = 9 # hardware problem
-uint8 BATTERY_FAULT_FAILED_TO_ARM = 10 # Battery had a problem while arming
-uint8 BATTERY_FAULT_COUNT = 11 # Counter - keep it as last element!
+uint8 FAULT_DEEP_DISCHARGE = 0 # Battery has deep discharged
+uint8 FAULT_SPIKES = 1 # Voltage spikes
+uint8 FAULT_CELL_FAIL= 2 # One or more cells have failed
+uint8 FAULT_OVER_CURRENT = 3 # Over-current
+uint8 FAULT_OVER_TEMPERATURE = 4 # Over-temperature
+uint8 FAULT_UNDER_TEMPERATURE = 5 # Under-temperature fault
+uint8 FAULT_INCOMPATIBLE_VOLTAGE = 6 # Vehicle voltage is not compatible with this battery (batteries on same power rail should have similar voltage).
+uint8 FAULT_INCOMPATIBLE_FIRMWARE = 7 # Battery firmware is not compatible with current autopilot firmware
+uint8 FAULT_INCOMPATIBLE_MODEL = 8 # Battery model is not supported by the system
+uint8 FAULT_HARDWARE_FAILURE = 9 # hardware problem
+uint8 FAULT_FAILED_TO_ARM = 10 # Battery had a problem while arming
+uint8 FAULT_COUNT = 11 # Counter - keep it as last element!
uint16 faults # Smart battery supply status/fault flags (bitmask) for health indication.
uint8 warning # Current battery warning
diff --git a/msg/versioned/VehicleStatus.msg b/msg/versioned/VehicleStatus.msg
index 6f3938a0af..7ad58bc785 100644
--- a/msg/versioned/VehicleStatus.msg
+++ b/msg/versioned/VehicleStatus.msg
@@ -1,6 +1,6 @@
# Encodes the system state of the vehicle published by commander
-uint32 MESSAGE_VERSION = 0
+uint32 MESSAGE_VERSION = 1
uint64 timestamp # time since system start (microseconds)
@@ -87,15 +87,14 @@ uint8 hil_state
uint8 HIL_STATE_OFF = 0
uint8 HIL_STATE_ON = 1
-# If it's a VTOL, then the value will be VEHICLE_TYPE_ROTARY_WING while flying as a multicopter, and VEHICLE_TYPE_FIXED_WING when flying as a fixed-wing
+# Current vehicle locomotion method. A vehicle can have different methods (e.g. VTOL transitions from RW to FW method)
uint8 vehicle_type
-uint8 VEHICLE_TYPE_UNKNOWN = 0
-uint8 VEHICLE_TYPE_ROTARY_WING = 1
-uint8 VEHICLE_TYPE_FIXED_WING = 2
-uint8 VEHICLE_TYPE_ROVER = 3
-uint8 VEHICLE_TYPE_AIRSHIP = 4
+uint8 VEHICLE_TYPE_ROTARY_WING = 0
+uint8 VEHICLE_TYPE_FIXED_WING = 1
+uint8 VEHICLE_TYPE_ROVER = 2
uint8 VEHICLE_TYPE_BOAT = 5
+
uint8 FAILSAFE_DEFER_STATE_DISABLED = 0
uint8 FAILSAFE_DEFER_STATE_ENABLED = 1
uint8 FAILSAFE_DEFER_STATE_WOULD_FAILSAFE = 2 # Failsafes deferred, but would trigger a failsafe
@@ -132,9 +131,6 @@ bool open_drone_id_system_healthy
bool parachute_system_present
bool parachute_system_healthy
-bool avoidance_system_required # Set to true if avoidance system is enabled via COM_OBS_AVOID parameter
-bool avoidance_system_valid # Status of the obstacle avoidance system
-
bool rc_calibration_in_progress
bool calibration_enabled
diff --git a/platforms/common/include/px4_platform_common/defines.h b/platforms/common/include/px4_platform_common/defines.h
index 3b420f95f1..eba5e944d9 100644
--- a/platforms/common/include/px4_platform_common/defines.h
+++ b/platforms/common/include/px4_platform_common/defines.h
@@ -97,7 +97,7 @@ __BEGIN_DECLS
extern long PX4_TICKS_PER_SEC;
__END_DECLS
-#define PX4_ROOTFSDIR CONFIG_BOARD_ROOTFSDIR
+#define PX4_ROOTFSDIR CONFIG_BOARD_ROOT_PATH
// Qurt doesn't have an SD card for storage
#ifndef __PX4_QURT
diff --git a/platforms/nuttx/NuttX/nuttx b/platforms/nuttx/NuttX/nuttx
index 9a213327fb..205b3100f8 160000
--- a/platforms/nuttx/NuttX/nuttx
+++ b/platforms/nuttx/NuttX/nuttx
@@ -1 +1 @@
-Subproject commit 9a213327fbb2dab252185d468fb29348e1833d8c
+Subproject commit 205b3100f8f63944a45faa5cfb5d3f86e904ee59
diff --git a/platforms/posix/cmake/sitl_tests.cmake b/platforms/posix/cmake/sitl_tests.cmake
index bf69b6a7ce..fdd8a5300e 100644
--- a/platforms/posix/cmake/sitl_tests.cmake
+++ b/platforms/posix/cmake/sitl_tests.cmake
@@ -5,7 +5,6 @@
# tests command arguments
set(tests
atomic_bitset
- bezier
bitset
bson
dataman
diff --git a/src/drivers/actuators/voxl_esc/voxl_esc.cpp b/src/drivers/actuators/voxl_esc/voxl_esc.cpp
index f5568d7eeb..89aebcbbaf 100644
--- a/src/drivers/actuators/voxl_esc/voxl_esc.cpp
+++ b/src/drivers/actuators/voxl_esc/voxl_esc.cpp
@@ -47,7 +47,7 @@ VoxlEsc::VoxlEsc() :
_mixing_output{"VOXL_ESC", VOXL_ESC_OUTPUT_CHANNELS, *this, MixingOutput::SchedulingPolicy::Auto, false, false},
_cycle_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": cycle")),
_output_update_perf(perf_alloc(PC_INTERVAL, MODULE_NAME": output update interval")),
- _battery(1, nullptr, _battery_report_interval, battery_status_s::BATTERY_SOURCE_POWER_MODULE)
+ _battery(1, nullptr, _battery_report_interval, battery_status_s::SOURCE_POWER_MODULE)
{
_device = VOXL_ESC_DEFAULT_PORT;
@@ -90,13 +90,13 @@ VoxlEsc::~VoxlEsc()
int VoxlEsc::init()
{
- PX4_INFO("VOXL_ESC: Starting VOXL ESC driver");
+ PX4_ERR("Starting VOXL ESC driver");
/* Getting initial parameter values */
int ret = update_params();
if (ret != OK) {
- PX4_ERR("VOXL_ESC: Failed to update params during init");
+ PX4_ERR("Failed to update params during init");
return ret;
}
@@ -124,13 +124,13 @@ int VoxlEsc::device_init()
// Open serial port
if (!_uart_port.isOpen()) {
- PX4_INFO("VOXL_ESC: Opening UART ESC device %s, baud rate %" PRIi32, _device, _parameters.baud_rate);
+ PX4_ERR("Opening UART ESC device %s, baud rate %" PRIi32, _device, _parameters.baud_rate);
#ifndef __PX4_QURT
//warn user that unless DMA is enabled for UART RX, data can be lost due to high frequency of per char cpu interrupts
//at least at 2mbit, there are definitely losses, did not test other baud rates to find the cut off
if (_parameters.baud_rate > 250000) {
- PX4_WARN("VOXL_ESC: Baud rate is too high for non-DMA based UART, this can lead to loss of RX data");
+ PX4_WARN("Baud rate is too high for non-DMA based UART, this can lead to loss of RX data");
}
#endif
@@ -165,7 +165,7 @@ int VoxlEsc::device_init()
}
// Detect ESCs
- PX4_INFO("VOXL_ESC: Detecting ESCs...");
+ PX4_ERR("Detecting ESCs...");
qc_esc_packet_init(&_fb_packet);
//request extended version info from each ESC and wait for reply
@@ -174,7 +174,7 @@ int VoxlEsc::device_init()
cmd.len = qc_esc_create_extended_version_request_packet(esc_id, cmd.buf, sizeof(cmd.buf));
if (_uart_port.write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("VOXL_ESC: Could not write version request packet to UART port");
+ PX4_ERR("Could not write version request packet to UART port");
return -1;
}
@@ -201,17 +201,17 @@ int VoxlEsc::device_init()
QC_ESC_EXTENDED_VERSION_INFO ver;
memcpy(&ver, _fb_packet.buffer, packet_size);
- PX4_INFO("VOXL_ESC: \tESC ID : %i", ver.id);
- PX4_INFO("VOXL_ESC: \tBoard Type : %i: %s", ver.hw_version, board_id_to_name(ver.hw_version));
+ PX4_ERR("\tESC ID : %i", ver.id);
+ PX4_ERR("\tBoard Type : %i: %s", ver.hw_version, board_id_to_name(ver.hw_version));
uint8_t *u = &ver.unique_id[0];
- PX4_INFO("VOXL_ESC: \tUnique ID : 0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
- u[11], u[10], u[9], u[8], u[7], u[6], u[5], u[4], u[3], u[2], u[1], u[0]);
+ PX4_ERR("\tUnique ID : 0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ u[11], u[10], u[9], u[8], u[7], u[6], u[5], u[4], u[3], u[2], u[1], u[0]);
- PX4_INFO("VOXL_ESC: \tFirmware : version %4d, hash %.12s", ver.sw_version, ver.firmware_git_version);
- PX4_INFO("VOXL_ESC: \tBootloader : version %4d, hash %.12s", ver.bootloader_version, ver.bootloader_git_version);
- PX4_INFO("VOXL_ESC: \tReply time : %" PRIu32 "us", (uint32_t)response_time);
- PX4_INFO("VOXL_ESC:");
+ PX4_ERR("\tFirmware : version %4d, hash %.12s", ver.sw_version, ver.firmware_git_version);
+ PX4_ERR("\tBootloader : version %4d, hash %.12s", ver.bootloader_version, ver.bootloader_git_version);
+ PX4_ERR("\tReply time : %" PRIu32 "us", (uint32_t)response_time);
+ PX4_INFO("");
if (ver.id == esc_id) {
memcpy(&_version_info[esc_id], &ver, sizeof(ver));
@@ -223,7 +223,7 @@ int VoxlEsc::device_init()
}
if (!got_response) {
- PX4_ERR("VOXL_ESC: ESC %d version info response timeout", esc_id);
+ PX4_ERR("ESC %d version info response timeout", esc_id);
}
}
@@ -232,7 +232,7 @@ int VoxlEsc::device_init()
for (int esc_id = 0; esc_id < VOXL_ESC_OUTPUT_CHANNELS; esc_id++) {
if (_version_info[esc_id].sw_version == 0) {
- PX4_ERR("VOXL_ESC: ESC ID %d was not detected", esc_id);
+ PX4_ERR("ESC ID %d was not detected", esc_id);
esc_detection_fault = true;
}
}
@@ -240,7 +240,7 @@ int VoxlEsc::device_init()
//check the firmware hashes to make sure they are the same. Firmware hash has 8 chars plus optional "*"
for (int esc_id = 1; esc_id < VOXL_ESC_OUTPUT_CHANNELS; esc_id++) {
if (strncmp(_version_info[0].firmware_git_version, _version_info[esc_id].firmware_git_version, 9) != 0) {
- PX4_ERR("VOXL_ESC: ESC %d Firmware hash does not match ESC 0 firmware hash: (%.12s) != (%.12s)",
+ PX4_ERR("ESC %d Firmware hash does not match ESC 0 firmware hash: (%.12s) != (%.12s)",
esc_id, _version_info[esc_id].firmware_git_version, _version_info[0].firmware_git_version);
esc_detection_fault = true;
}
@@ -256,13 +256,13 @@ int VoxlEsc::device_init()
}
if (esc_detection_fault) {
- PX4_ERR("VOXL_ESC: Critical error during ESC initialization");
+ PX4_ERR("Critical error during ESC initialization");
return -1;
}
- PX4_INFO("VOXL_ESC: Use extened rpm packet : %d", _extended_rpm);
+ PX4_ERR("Use extened rpm packet : %d", _extended_rpm);
- PX4_INFO("VOXL_ESC: All ESCs successfully detected");
+ PX4_ERR("All ESCs successfully detected");
_device_initialized = true;
@@ -309,45 +309,53 @@ int VoxlEsc::load_params(voxl_esc_params_t *params, ch_assign_t *map)
param_get(param_find("VOXL_ESC_T_WARN"), ¶ms->esc_warn_temp_threshold);
param_get(param_find("VOXL_ESC_T_OVER"), ¶ms->esc_over_temp_threshold);
+ param_get(param_find("VOXL_ESC_GPIO_CH"), ¶ms->gpio_ctl_channel);
+
if (params->rpm_min >= params->rpm_max) {
- PX4_ERR("VOXL_ESC: Invalid parameter VOXL_ESC_RPM_MIN. Please verify parameters.");
+ PX4_ERR("Invalid parameter VOXL_ESC_RPM_MIN. Please verify parameters.");
params->rpm_min = 0;
ret = PX4_ERROR;
}
if (params->turtle_motor_percent < 0 || params->turtle_motor_percent > 100) {
- PX4_ERR("VOXL_ESC: Invalid parameter VOXL_ESC_T_PERC. Please verify parameters.");
+ PX4_ERR("Invalid parameter VOXL_ESC_T_PERC. Please verify parameters.");
params->turtle_motor_percent = 0;
ret = PX4_ERROR;
}
if (params->turtle_motor_deadband < 0 || params->turtle_motor_deadband > 100) {
- PX4_ERR("VOXL_ESC: Invalid parameter VOXL_ESC_T_DEAD. Please verify parameters.");
+ PX4_ERR("Invalid parameter VOXL_ESC_T_DEAD. Please verify parameters.");
params->turtle_motor_deadband = 0;
ret = PX4_ERROR;
}
if (params->turtle_motor_expo < 0 || params->turtle_motor_expo > 100) {
- PX4_ERR("VOXL_ESC: Invalid parameter VOXL_ESC_T_EXPO. Please verify parameters.");
+ PX4_ERR("Invalid parameter VOXL_ESC_T_EXPO. Please verify parameters.");
params->turtle_motor_expo = 0;
ret = PX4_ERROR;
}
if (params->turtle_stick_minf < 0.0f || params->turtle_stick_minf > 100.0f) {
- PX4_ERR("VOXL_ESC: Invalid parameter VOXL_ESC_T_MINF. Please verify parameters.");
+ PX4_ERR("Invalid parameter VOXL_ESC_T_MINF. Please verify parameters.");
params->turtle_stick_minf = 0.0f;
ret = PX4_ERROR;
}
if (params->turtle_cosphi < 0.0f || params->turtle_cosphi > 100.0f) {
- PX4_ERR("VOXL_ESC: Invalid parameter VOXL_ESC_T_COSP. Please verify parameters.");
+ PX4_ERR("Invalid parameter VOXL_ESC_T_COSP. Please verify parameters.");
params->turtle_cosphi = 0.0f;
ret = PX4_ERROR;
}
+ if (params->gpio_ctl_channel < 0 || params->gpio_ctl_channel > 6) {
+ PX4_ERR("Invalid parameter VOXL_ESC_GPIO_CH. Please verify parameters.");
+ params->gpio_ctl_channel = 0;
+ ret = PX4_ERROR;
+ }
+
for (int i = 0; i < VOXL_ESC_OUTPUT_CHANNELS; i++) {
if (params->function_map[i] < (int)OutputFunction::Motor1 || params->function_map[i] > (int)OutputFunction::Motor4) {
- PX4_ERR("VOXL_ESC: Invalid parameter VOXL_ESC_FUNCX. Only supports motors 1-4. Please verify parameters.");
+ PX4_ERR("Invalid parameter VOXL_ESC_FUNCX. Only supports motors 1-4. Please verify parameters.");
params->function_map[i] = 0;
ret = PX4_ERROR;
@@ -365,7 +373,7 @@ int VoxlEsc::load_params(voxl_esc_params_t *params, ch_assign_t *map)
if (params->motor_map[i] == VOXL_ESC_OUTPUT_DISABLED ||
params->motor_map[i] < -(VOXL_ESC_OUTPUT_CHANNELS) ||
params->motor_map[i] > VOXL_ESC_OUTPUT_CHANNELS) {
- PX4_ERR("VOXL_ESC: Invalid parameter VOXL_ESC_MOTORX. Please verify parameters.");
+ PX4_ERR("Invalid parameter VOXL_ESC_MOTORX. Please verify parameters.");
params->motor_map[i] = 0;
ret = PX4_ERROR;
}
@@ -471,9 +479,8 @@ int VoxlEsc::parse_response(uint8_t *buf, uint8_t len, bool print_feedback)
uint32_t voltage = fb.voltage;
int32_t current = fb.current * 8;
int32_t temperature = fb.temperature / 100;
- PX4_INFO("VOXL_ESC: [%" PRId64 "] ID_RAW=%d ID=%d, RPM=%5d, PWR=%3d%%, V=%5dmV, I=%+5dmA, T=%+3dC", tnow, (int)id,
- motor_idx + 1,
- (int)rpm, (int)power, (int)voltage, (int)current, (int)temperature);
+ PX4_ERR("[%" PRId64 "] ID_RAW=%d ID=%d, RPM=%5d, PWR=%3d%%, V=%5dmV, I=%+5dmA, T=%+3dC", tnow, (int)id,
+ motor_idx + 1, (int)rpm, (int)power, (int)voltage, (int)current, (int)temperature);
}
_esc_chans[id].rate_meas = fb.rpm;
@@ -541,24 +548,24 @@ int VoxlEsc::parse_response(uint8_t *buf, uint8_t len, bool print_feedback)
QC_ESC_VERSION_INFO ver;
memcpy(&ver, _fb_packet.buffer, packet_size);
- PX4_INFO("VOXL_ESC: ESC ID: %i", ver.id);
- PX4_INFO("VOXL_ESC: HW Version: %i", ver.hw_version);
- PX4_INFO("VOXL_ESC: SW Version: %i", ver.sw_version);
- PX4_INFO("VOXL_ESC: Unique ID: %i", (int)ver.unique_id);
+ PX4_ERR("ESC ID: %i", ver.id);
+ PX4_ERR("HW Version: %i", ver.hw_version);
+ PX4_ERR("SW Version: %i", ver.sw_version);
+ PX4_ERR("Unique ID: %i", (int)ver.unique_id);
} else if (packet_type == ESC_PACKET_TYPE_VERSION_EXT_RESPONSE && packet_size == sizeof(QC_ESC_EXTENDED_VERSION_INFO)) {
QC_ESC_EXTENDED_VERSION_INFO ver;
memcpy(&ver, _fb_packet.buffer, packet_size);
- PX4_INFO("VOXL_ESC: \tESC ID : %i", ver.id);
- PX4_INFO("VOXL_ESC: \tBoard : %i", ver.hw_version);
- PX4_INFO("VOXL_ESC: \tSW Version : %i", ver.sw_version);
+ PX4_ERR("\tESC ID : %i", ver.id);
+ PX4_ERR("\tBoard : %i", ver.hw_version);
+ PX4_ERR("\tSW Version : %i", ver.sw_version);
uint8_t *u = &ver.unique_id[0];
- PX4_INFO("VOXL_ESC: \tUnique ID : 0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
- u[11], u[10], u[9], u[8], u[7], u[6], u[5], u[4], u[3], u[2], u[1], u[0]);
+ PX4_ERR("\tUnique ID : 0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ u[11], u[10], u[9], u[8], u[7], u[6], u[5], u[4], u[3], u[2], u[1], u[0]);
- PX4_INFO("VOXL_ESC: \tFirmware : version %4d, hash %.12s", ver.sw_version, ver.firmware_git_version);
- PX4_INFO("VOXL_ESC: \tBootloader : version %4d, hash %.12s", ver.bootloader_version, ver.bootloader_git_version);
+ PX4_ERR("\tFirmware : version %4d, hash %.12s", ver.sw_version, ver.firmware_git_version);
+ PX4_ERR("\tBootloader : version %4d, hash %.12s", ver.bootloader_version, ver.bootloader_git_version);
} else if (packet_type == ESC_PACKET_TYPE_FB_POWER_STATUS && packet_size == sizeof(QC_ESC_FB_POWER_STATUS)) {
QC_ESC_FB_POWER_STATUS packet;
@@ -671,7 +678,7 @@ int VoxlEsc::custom_command(int argc, char *argv[])
}
if (!is_running()) {
- PX4_INFO("VOXL_ESC:Not running");
+ PX4_INFO("Not running");
return -1;
}
@@ -730,7 +737,7 @@ int VoxlEsc::custom_command(int argc, char *argv[])
if (!strcmp(verb, "reset")) {
if (esc_id < VOXL_ESC_OUTPUT_CHANNELS) {
- PX4_INFO("VOXL_ESC: Reset ESC: %i", esc_id);
+ PX4_ERR("Reset ESC: %i", esc_id);
cmd.len = qc_esc_create_reset_packet(esc_id, cmd.buf, sizeof(cmd.buf));
cmd.response = false;
return get_instance()->send_cmd_thread_safe(&cmd);
@@ -742,7 +749,7 @@ int VoxlEsc::custom_command(int argc, char *argv[])
} else if (!strcmp(verb, "version")) {
if (esc_id < VOXL_ESC_OUTPUT_CHANNELS) {
- PX4_INFO("VOXL_ESC: Request version for ESC: %i", esc_id);
+ PX4_ERR("Request version for ESC: %i", esc_id);
cmd.len = qc_esc_create_version_request_packet(esc_id, cmd.buf, sizeof(cmd.buf));
cmd.response = true;
cmd.resp_delay_us = 2000;
@@ -755,7 +762,7 @@ int VoxlEsc::custom_command(int argc, char *argv[])
} else if (!strcmp(verb, "version-ext")) {
if (esc_id < VOXL_ESC_OUTPUT_CHANNELS) {
- PX4_INFO("VOXL_ESC: Request extended version for ESC: %i", esc_id);
+ PX4_ERR("Request extended version for ESC: %i", esc_id);
cmd.len = qc_esc_create_extended_version_request_packet(esc_id, cmd.buf, sizeof(cmd.buf));
cmd.response = true;
cmd.resp_delay_us = 5000;
@@ -768,7 +775,7 @@ int VoxlEsc::custom_command(int argc, char *argv[])
} else if (!strcmp(verb, "tone")) {
if (esc_id < VOXL_ESC_OUTPUT_CHANNELS) {
- PX4_INFO("VOXL_ESC: Request tone for ESC mask: %i", esc_id);
+ PX4_ERR("Request tone for ESC mask: %i", esc_id);
cmd.len = qc_esc_create_sound_packet(period, duration, power, esc_id, cmd.buf, sizeof(cmd.buf));
cmd.response = false;
return get_instance()->send_cmd_thread_safe(&cmd);
@@ -782,7 +789,7 @@ int VoxlEsc::custom_command(int argc, char *argv[])
if (led_mask <= 0x0FFF) {
get_instance()->_led_rsc.test = true;
get_instance()->_led_rsc.breath_en = false;
- PX4_INFO("VOXL_ESC: Request LED control for ESCs with mask: %i", led_mask);
+ PX4_ERR("Request LED control for ESCs with mask: %i", led_mask);
get_instance()->_esc_chans[0].led = (led_mask & 0x0007);
get_instance()->_esc_chans[1].led = (led_mask & 0x0038) >> 3;
@@ -797,7 +804,7 @@ int VoxlEsc::custom_command(int argc, char *argv[])
} else if (!strcmp(verb, "rpm")) {
if (esc_id < VOXL_ESC_OUTPUT_CHANNELS) {
- PX4_INFO("VOXL_ESC: Request RPM for ESC ID: %i - RPM: %i", esc_id, rate);
+ PX4_ERR("Request RPM for ESC ID: %i - RPM: %i", esc_id, rate);
int16_t rate_req[VOXL_ESC_OUTPUT_CHANNELS] = {0, 0, 0, 0};
uint8_t id_fb = 0;
@@ -831,8 +838,8 @@ int VoxlEsc::custom_command(int argc, char *argv[])
cmd.repeat_delay_us = repeat_delay_us;
cmd.print_feedback = true;
- PX4_INFO("VOXL_ESC: Feedback id debug: %i", id_fb);
- PX4_INFO("VOXL_ESC: Sending UART ESC RPM command %i", rate);
+ PX4_ERR("Feedback id debug: %i", id_fb);
+ PX4_ERR("Sending UART ESC RPM command %i", rate);
return get_instance()->send_cmd_thread_safe(&cmd);
@@ -843,7 +850,7 @@ int VoxlEsc::custom_command(int argc, char *argv[])
} else if (!strcmp(verb, "pwm")) {
if (esc_id < VOXL_ESC_OUTPUT_CHANNELS) {
- PX4_INFO("VOXL_ESC: Request PWM for ESC ID: %i - PWM: %i", esc_id, rate);
+ PX4_ERR("Request PWM for ESC ID: %i - PWM: %i", esc_id, rate);
int16_t rate_req[VOXL_ESC_OUTPUT_CHANNELS] = {0, 0, 0, 0};
uint8_t id_fb = 0;
@@ -876,8 +883,8 @@ int VoxlEsc::custom_command(int argc, char *argv[])
cmd.repeat_delay_us = repeat_delay_us;
cmd.print_feedback = true;
- PX4_INFO("VOXL_ESC: Feedback id debug: %i", id_fb);
- PX4_INFO("VOXL_ESC: Sending UART ESC power command %i", rate);
+ PX4_ERR("Feedback id debug: %i", id_fb);
+ PX4_ERR("Sending UART ESC power command %i", rate);
return get_instance()->send_cmd_thread_safe(&cmd);
@@ -1242,14 +1249,58 @@ bool VoxlEsc::updateOutputs(bool stop_motors, uint16_t outputs[MAX_ACTUATORS],
_extended_rpm);
if (_uart_port.write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("VOXL_ESC: Failed to send packet");
+ PX4_ERR("Failed to send packet");
return false;
}
+ // Track and manage gpio command writes
+ bool write_gpio_command = false;
+
+ if (_gpio_ctl_en) {
+ if (_gpio_ctl_high != _prev_gpio_ctl_high) {
+ _gpio_write_counter = 0;
+ }
+
+ if (_gpio_write_counter < 10) {
+ write_gpio_command = true;
+ _gpio_write_counter++;
+ }
+
+ _prev_gpio_ctl_high = _gpio_ctl_high;
+
+ if (write_gpio_command) {
+ Command gpio_cmd;
+ const int ESC_PACKET_TYPE_GPIO_CMD = 15;
+ uint8_t data[5];
+
+ int esc_id = 0; // In future un-hardcode
+ int val = 0;
+
+ if (_gpio_ctl_high) {
+ val = 1;
+ }
+
+ data[0] = esc_id; // esc id
+ data[1] = 80; // 01010000 : pin F0
+ data[2] = 0; // 0: output, 1: input
+ data[3] = val; //cmd LSB
+ data[4] = 0; // cmd MSB
+
+ // type, data, size
+ gpio_cmd.len = qc_esc_create_packet(ESC_PACKET_TYPE_GPIO_CMD, (uint8_t *) & (data[0]), 5, gpio_cmd.buf,
+ sizeof(gpio_cmd.buf));
+
+ if (_uart_port.write(gpio_cmd.buf, gpio_cmd.len) != gpio_cmd.len) {
+ PX4_ERR("Failed to send gpio packet");
+ return false;
+ }
+ }
+
+ }
+
// increment ESC id from which to request feedback in round robin order
_fb_idx = (_fb_idx + 1) % VOXL_ESC_OUTPUT_CHANNELS;
-
/*
* Here we read and parse response from ESCs. Since the latest command has just been sent out,
* the response packet we may read here is probabaly from previous iteration, but it is totally ok.
@@ -1283,20 +1334,18 @@ bool VoxlEsc::updateOutputs(bool stop_motors, uint16_t outputs[MAX_ACTUATORS],
_esc_status_pub.publish(_esc_status);
- // If any extra external modal io data has been received then
- // send it over as well
- while (_voxl2_io_data_sub.updated()) {
- buffer128_s io_data{};
- _voxl2_io_data_sub.copy(&io_data);
+ uint8_t num_writes = 0;
- // PX4_INFO("Got Modal IO data: %u bytes", io_data.len);
- // PX4_INFO(" 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x",
- // io_data.data[0], io_data.data[1], io_data.data[2], io_data.data[3],
- // io_data.data[4], io_data.data[5], io_data.data[6], io_data.data[7]);
- if (_uart_port.write(io_data.data, io_data.len) != io_data.len) {
- PX4_ERR("VOXL_ESC: Failed to send modal io data to esc");
+ while (_esc_serial_passthru_sub.updated() && (num_writes < 4)) {
+ mavlink_tunnel_s uart_passthru{};
+ _esc_serial_passthru_sub.copy(&uart_passthru);
+
+ if (_uart_port.write(uart_passthru.payload, uart_passthru.payload_length) != uart_passthru.payload_length) {
+ PX4_ERR("Failed to send mavlink tunnel data to esc");
return false;
}
+
+ num_writes++;
}
perf_count(_output_update_perf);
@@ -1308,7 +1357,7 @@ bool VoxlEsc::updateOutputs(bool stop_motors, uint16_t outputs[MAX_ACTUATORS],
void VoxlEsc::Run()
{
if (should_exit()) {
- PX4_ERR("VOXL_ESC: Stopping the module");
+ PX4_ERR("Stopping the module");
ScheduleClear();
_mixing_output.unregister();
@@ -1328,12 +1377,12 @@ void VoxlEsc::Run()
int dev_init_ret = device_init();
if (dev_init_ret != 0) {
- PX4_WARN("VOXL_ESC: Failed to initialize device, retries left %d", retries_left);
+ PX4_WARN("Failed to initialize device, retries left %d", retries_left);
}
}
if (!_device_initialized) {
- PX4_ERR("VOXL_ESC: Failed to initialize device, exiting the module");
+ PX4_ERR("Failed to initialize device, exiting the module");
ScheduleClear();
_mixing_output.unregister();
exit_and_cleanup();
@@ -1374,11 +1423,12 @@ void VoxlEsc::Run()
update_leds(_led_rsc.mode, _led_rsc.control);
}
- if (_parameters.mode > 0) {
- /* if turtle mode enabled, we go straight to the sticks, no mix */
- if (_manual_control_setpoint_sub.updated()) {
+ /* check whether sticks have been updated */
+ if (_manual_control_setpoint_sub.updated()) {
+ _manual_control_setpoint_sub.copy(&_manual_control_setpoint);
- _manual_control_setpoint_sub.copy(&_manual_control_setpoint);
+ // if turtle mode enabled, we go straight to the sticks, no mix
+ if (_parameters.mode > 0) {
if (!_outputs_on) {
@@ -1400,6 +1450,45 @@ void VoxlEsc::Run()
}
}
+ // check if gpio control is enabled
+ if (_parameters.gpio_ctl_channel > 0) {
+
+ _gpio_ctl_en = true;
+ float gpio_setpoint = VOXL_ESC_GPIO_CTL_DISABLED_SETPOINT;
+
+ switch (_parameters.gpio_ctl_channel) {
+ case VOXL_ESC_GPIO_CTL_AUX1:
+ gpio_setpoint = _manual_control_setpoint.aux1;
+ break;
+
+ case VOXL_ESC_GPIO_CTL_AUX2:
+ gpio_setpoint = _manual_control_setpoint.aux2;
+ break;
+
+ case VOXL_ESC_GPIO_CTL_AUX3:
+ gpio_setpoint = _manual_control_setpoint.aux3;
+ break;
+
+ case VOXL_ESC_GPIO_CTL_AUX4:
+ gpio_setpoint = _manual_control_setpoint.aux4;
+ break;
+
+ case VOXL_ESC_GPIO_CTL_AUX5:
+ gpio_setpoint = _manual_control_setpoint.aux5;
+ break;
+
+ case VOXL_ESC_GPIO_CTL_AUX6:
+ gpio_setpoint = _manual_control_setpoint.aux6;
+ break;
+ }
+
+ if (gpio_setpoint > VOXL_ESC_GPIO_CTL_THRESHOLD) {
+ _gpio_ctl_high = false;
+
+ } else {
+ _gpio_ctl_high = true;
+ }
+ }
}
if (!_outputs_on) {
@@ -1431,19 +1520,19 @@ void VoxlEsc::Run()
} else {
if (_current_cmd.retries == 0) {
_current_cmd.clear();
- PX4_ERR("VOXL_ESC: Failed to send command, errno: %i", errno);
+ PX4_ERR("Failed to send command, errno: %i", errno);
} else {
_current_cmd.retries--;
- PX4_ERR("VOXL_ESC: Failed to send command, errno: %i", errno);
+ PX4_ERR("Failed to send command, errno: %i", errno);
}
}
px4_usleep(_current_cmd.repeat_delay_us);
} while (_current_cmd.repeats-- > 0);
- PX4_INFO("VOXL_ESC: RX packet count: %d", (int)_rx_packet_count);
- PX4_INFO("VOXL_ESC: CRC error count: %d", (int)_rx_crc_error_count);
+ PX4_ERR("RX packet count: %d", (int)_rx_packet_count);
+ PX4_ERR("CRC error count: %d", (int)_rx_crc_error_count);
} else {
Command *new_cmd = _pending_cmd.load();
@@ -1547,9 +1636,11 @@ void VoxlEsc::print_params()
PX4_INFO("Params: VOXL_ESC_VLOG: %" PRId32, _parameters.verbose_logging);
PX4_INFO("Params: VOXL_ESC_PUB_BST: %" PRId32, _parameters.publish_battery_status);
-
+
PX4_INFO("Params: VOXL_ESC_T_WARN: %" PRId32, _parameters.esc_warn_temp_threshold);
PX4_INFO("Params: VOXL_ESC_T_OVER: %" PRId32, _parameters.esc_over_temp_threshold);
+
+ PX4_INFO("Params: VOXL_ESC_GPIO_CH: %" PRId32, _parameters.gpio_ctl_channel);
}
int VoxlEsc::print_status()
diff --git a/src/drivers/actuators/voxl_esc/voxl_esc.hpp b/src/drivers/actuators/voxl_esc/voxl_esc.hpp
index d894cb9326..c28d1e1ab9 100644
--- a/src/drivers/actuators/voxl_esc/voxl_esc.hpp
+++ b/src/drivers/actuators/voxl_esc/voxl_esc.hpp
@@ -49,7 +49,7 @@
#include
#include
#include
-#include
+#include
#include
@@ -129,17 +129,24 @@ private:
static constexpr uint32_t VOXL_ESC_MODE_TURTLE_AUX1 = 1;
static constexpr uint32_t VOXL_ESC_MODE_TURTLE_AUX2 = 2;
- static constexpr uint16_t VOXL_ESC_EXT_RPM =
- 39; // minimum firmware version for extended RPM command support
- static constexpr uint16_t VOXL_ESC_RPM_MAX = INT16_MAX -
- 1; // 32K, Limit max standard range RPM to prevent overflow (rpm packet packing function accepts int32_t)
- static constexpr uint16_t VOXL_ESC_RPM_MAX_EXT = UINT16_MAX -
- 5; // 65K, Limit max extended range RPM to prevent overflow (rpm packet packing function accepts int32_t)
+ // minimum firmware version for extended RPM command support
+ static constexpr uint16_t VOXL_ESC_EXT_RPM = 39;
+ // 32K, Limit max standard range RPM to prevent overflow (rpm packet packing function accepts int32_t)
+ static constexpr uint16_t VOXL_ESC_RPM_MAX = INT16_MAX - 1;
+ // 65K, Limit max extended range RPM to prevent overflow (rpm packet packing function accepts int32_t)
+ static constexpr uint16_t VOXL_ESC_RPM_MAX_EXT = UINT16_MAX - 5;
static constexpr uint16_t VOXL_ESC_NUM_INIT_RETRIES = 3;
- //static constexpr uint16_t max_pwm(uint16_t pwm) { return math::min(pwm, VOXL_ESC_PWM_MAX); }
- //static constexpr uint16_t max_rpm(uint16_t rpm) { return math::min(rpm, VOXL_ESC_RPM_MAX); }
+ static constexpr float VOXL_ESC_GPIO_CTL_DISABLED_SETPOINT = -0.1f;
+ static constexpr float VOXL_ESC_GPIO_CTL_THRESHOLD = 0.0f;
+
+ static constexpr uint32_t VOXL_ESC_GPIO_CTL_AUX1 = 1;
+ static constexpr uint32_t VOXL_ESC_GPIO_CTL_AUX2 = 2;
+ static constexpr uint32_t VOXL_ESC_GPIO_CTL_AUX3 = 3;
+ static constexpr uint32_t VOXL_ESC_GPIO_CTL_AUX4 = 4;
+ static constexpr uint32_t VOXL_ESC_GPIO_CTL_AUX5 = 5;
+ static constexpr uint32_t VOXL_ESC_GPIO_CTL_AUX6 = 6;
Serial _uart_port{};
@@ -161,6 +168,7 @@ private:
int32_t publish_battery_status{0};
int32_t esc_warn_temp_threshold{0};
int32_t esc_over_temp_threshold{0};
+ int32_t gpio_ctl_channel{0};
} voxl_esc_params_t;
struct EscChan {
@@ -205,7 +213,7 @@ private:
uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)};
uORB::Subscription _actuator_test_sub{ORB_ID(actuator_test)};
uORB::Subscription _led_update_sub{ORB_ID(led_control)};
- uORB::Subscription _voxl2_io_data_sub{ORB_ID(voxl2_io_data)};
+ uORB::Subscription _esc_serial_passthru_sub{ORB_ID(esc_serial_passthru)};
uORB::Publication _outputs_debug_pub{ORB_ID(actuator_outputs_debug)};
uORB::Publication _esc_status_pub{ORB_ID(esc_status)};
@@ -224,6 +232,11 @@ private:
int32_t _rpm_fullscale{0};
manual_control_setpoint_s _manual_control_setpoint{};
+ int32_t _gpio_write_counter{0};
+ bool _gpio_ctl_en{false};
+ bool _gpio_ctl_high{true};
+ bool _prev_gpio_ctl_high{true};
+
uint16_t _cmd_id{0};
Command _current_cmd;
px4::atomic _pending_cmd{nullptr};
diff --git a/src/drivers/actuators/voxl_esc/voxl_esc_params.c b/src/drivers/actuators/voxl_esc/voxl_esc_params.c
index 2752d9d744..b0526ecf1f 100644
--- a/src/drivers/actuators/voxl_esc/voxl_esc_params.c
+++ b/src/drivers/actuators/voxl_esc/voxl_esc_params.c
@@ -262,3 +262,17 @@ PARAM_DEFINE_INT32(VOXL_ESC_T_WARN, 0);
* @max 200
*/
PARAM_DEFINE_INT32(VOXL_ESC_T_OVER, 0);
+
+
+/**
+ * GPIO Control Channel
+ *
+ *
+ * @reboot_required true
+ *
+ * @group VOXL ESC
+ * @value 0 - Disabled
+ * @min 0
+ * @max 6
+ */
+PARAM_DEFINE_INT32(VOXL_ESC_GPIO_CH, 0);
diff --git a/src/drivers/adc/ads1115/ADS1115.cpp b/src/drivers/adc/ads1115/ADS1115.cpp
index 5ce4ae3504..25c8e92956 100644
--- a/src/drivers/adc/ads1115/ADS1115.cpp
+++ b/src/drivers/adc/ads1115/ADS1115.cpp
@@ -42,18 +42,7 @@ int ADS1115::init()
return ret;
}
- uint8_t config[2] = {};
- config[0] = CONFIG_HIGH_OS_NOACT | CONFIG_HIGH_MUX_P0NG | CONFIG_HIGH_PGA_6144 | CONFIG_HIGH_MODE_SS;
- config[1] = CONFIG_LOW_DR_250SPS | CONFIG_LOW_COMP_MODE_TRADITIONAL | CONFIG_LOW_COMP_POL_RESET |
- CONFIG_LOW_COMP_LAT_NONE | CONFIG_LOW_COMP_QU_DISABLE;
- ret = writeReg(ADDRESSPOINTER_REG_CONFIG, config, 2);
-
- if (ret != PX4_OK) {
- PX4_ERR("writeReg failed (%i)", ret);
- return ret;
- }
-
- setChannel(ADS1115::A0); // prepare for the first measure.
+ readChannel(Channel::A0); // prepare for the first measure.
ScheduleOnInterval(SAMPLE_INTERVAL / 4, SAMPLE_INTERVAL / 4);
@@ -62,152 +51,69 @@ int ADS1115::init()
int ADS1115::probe()
{
- uint8_t buf[2] = {};
- int ret = readReg(ADDRESSPOINTER_REG_CONFIG, buf, 2);
+ // The ADS1115 has no ID register, so we read out the threshold registers
+ // and check their default values. We cannot use the config register, as
+ // this is changed by this driver. Note the default value is in BE.
+ static constexpr uint32_t DEFAULT{0xFF7F0080};
+ union {
+ struct {
+ uint8_t low[2];
+ uint8_t high[2];
+ } parts;
+ uint32_t threshold{};
+ };
+ int ret = readReg(ADDRESSPOINTER_REG_LO_THRESH, parts.low, 2);
if (ret != PX4_OK) {
- DEVICE_DEBUG("readReg failed (%i)", ret);
+ DEVICE_DEBUG("lo_thresh read failed (%i)", ret);
return ret;
}
- if (buf[0] != CONFIG_RESET_VALUE_HIGH || buf[1] != CONFIG_RESET_VALUE_LOW) {
- DEVICE_DEBUG("ADS1115 not found");
- return PX4_ERROR;
+ ret = readReg(ADDRESSPOINTER_REG_HI_THRESH, parts.high, 2);
+
+ if (ret != PX4_OK) {
+ DEVICE_DEBUG("hi_thresh read failed (%i)", ret);
+ return ret;
}
- return PX4_OK;
+ if (threshold == DEFAULT) {
+ return PX4_OK;
+ }
+
+ DEVICE_DEBUG("ADS1115 not found");
+ return PX4_ERROR;
}
-int ADS1115::setChannel(ADS1115::ChannelSelection ch)
+int ADS1115::readChannel(ADS1115::Channel ch)
{
- uint8_t buf[2] = {};
- uint8_t next_mux_reg = CONFIG_HIGH_MUX_P0NG;
-
- switch (ch) {
- case A0:
- next_mux_reg = CONFIG_HIGH_MUX_P0NG;
- break;
-
- case A1:
- next_mux_reg = CONFIG_HIGH_MUX_P1NG;
- break;
-
- case A2:
- next_mux_reg = CONFIG_HIGH_MUX_P2NG;
- break;
-
- case A3:
- next_mux_reg = CONFIG_HIGH_MUX_P3NG;
- break;
-
- default:
- assert(false);
- break;
- }
-
- buf[0] = CONFIG_HIGH_OS_START_SINGLE | next_mux_reg | CONFIG_HIGH_PGA_6144 | CONFIG_HIGH_MODE_SS;
+ uint8_t buf[2];
+ buf[0] = CONFIG_HIGH_OS_START_SINGLE | uint8_t(ch) | CONFIG_HIGH_PGA_6144 | CONFIG_HIGH_MODE_SS;
buf[1] = CONFIG_LOW_DR_250SPS | CONFIG_LOW_COMP_MODE_TRADITIONAL | CONFIG_LOW_COMP_POL_RESET |
CONFIG_LOW_COMP_LAT_NONE | CONFIG_LOW_COMP_QU_DISABLE;
return writeReg(ADDRESSPOINTER_REG_CONFIG, buf, 2); // must write whole register to take effect
}
-bool ADS1115::isSampleReady()
+int ADS1115::isSampleReady()
{
uint8_t buf[1] = {0x00};
- if (readReg(ADDRESSPOINTER_REG_CONFIG, buf, 1) != 0) { return false; } // Pull config register
+ if (readReg(ADDRESSPOINTER_REG_CONFIG, buf, 1) != PX4_OK) { return -1; } // Pull config register
- return (buf[0] & (uint8_t) 0x80);
+ return (buf[0] & (uint8_t) 0x80) ? 1 : 0;
}
-ADS1115::ChannelSelection ADS1115::getMeasurement(int16_t *value)
+ADS1115::Channel ADS1115::getMeasurement(int16_t *value)
{
uint8_t buf[2] = {0x00};
- readReg(ADDRESSPOINTER_REG_CONFIG, buf, 1); // Pull config register
- ChannelSelection channel;
- switch ((buf[0] & (uint8_t) 0x70) >> 4) {
- case 0x04:
- channel = A0;
- break;
+ if (readReg(ADDRESSPOINTER_REG_CONFIG, buf, 1) != PX4_OK) { return Channel::Invalid; }
- case 0x05:
- channel = A1;
- break;
+ const auto channel{Channel(buf[0] & CONFIG_HIGH_MUX_P3NG)};
- case 0x06:
- channel = A2;
- break;
+ if (readReg(ADDRESSPOINTER_REG_CONVERSATION, buf, 2) != PX4_OK) { return Channel::Invalid; }
- case 0x07:
- channel = A3;
- break;
+ *value = int16_t((buf[0] << 8) | buf[1]);
- default:
- return Invalid;
- }
-
- readReg(ADDRESSPOINTER_REG_CONVERSATION, buf, 2);
- uint16_t raw_adc_val = buf[0] * 256 + buf[1];
-
- if (raw_adc_val & (uint16_t) 0x8000) { // Negetive value
- raw_adc_val = ~raw_adc_val + 1; // 2's complement
- *value = -raw_adc_val;
-
- } else {
- *value = raw_adc_val;
- }
-
- return channel;
-}
-
-ADS1115::ChannelSelection ADS1115::cycleMeasure(int16_t *value)
-{
- uint8_t buf[2] = {0x00};
- readReg(ADDRESSPOINTER_REG_CONFIG, buf, 1); // Pull config register
- ChannelSelection channel;
- uint8_t next_mux_reg = CONFIG_HIGH_MUX_P0NG;
-
- switch ((buf[0] & (uint8_t) 0x70) >> 4) {
- case 0x04:
- channel = A0;
- next_mux_reg = CONFIG_HIGH_MUX_P1NG;
- break;
-
- case 0x05:
- channel = A1;
- next_mux_reg = CONFIG_HIGH_MUX_P2NG;
- break;
-
- case 0x06:
- channel = A2;
- next_mux_reg = CONFIG_HIGH_MUX_P3NG;
- break;
-
- case 0x07:
- channel = A3;
- next_mux_reg = CONFIG_HIGH_MUX_P0NG;
- break;
-
- default:
- return Invalid;
- }
-
- readReg(ADDRESSPOINTER_REG_CONVERSATION, buf, 2);
- uint16_t raw_adc_val = buf[0] * 256 + buf[1];
-
- if (raw_adc_val & (uint16_t) 0x8000) { // Negetive value
- raw_adc_val = ~raw_adc_val + 1; // 2's complement
- *value = -raw_adc_val;
-
- } else {
- *value = raw_adc_val;
- }
-
- buf[0] = CONFIG_HIGH_OS_START_SINGLE | next_mux_reg | CONFIG_HIGH_PGA_6144 | CONFIG_HIGH_MODE_SS;
- buf[1] = CONFIG_LOW_DR_250SPS | CONFIG_LOW_COMP_MODE_TRADITIONAL | CONFIG_LOW_COMP_POL_RESET |
- CONFIG_LOW_COMP_LAT_NONE | CONFIG_LOW_COMP_QU_DISABLE;
- writeReg(ADDRESSPOINTER_REG_CONFIG, buf, 2); // must write whole register to take effect
return channel;
}
diff --git a/src/drivers/adc/ads1115/ADS1115.h b/src/drivers/adc/ads1115/ADS1115.h
index 79a31198c9..634a659df8 100644
--- a/src/drivers/adc/ads1115/ADS1115.h
+++ b/src/drivers/adc/ads1115/ADS1115.h
@@ -93,9 +93,6 @@
#define CONFIG_LOW_COMP_QU_AFTER4 0x02
#define CONFIG_LOW_COMP_QU_DISABLE 0x03
-#define CONFIG_RESET_VALUE_HIGH 0x85
-#define CONFIG_RESET_VALUE_LOW 0x83
-
using namespace time_literals;
/*
@@ -127,35 +124,39 @@ protected:
private:
- uORB::PublicationMulti _to_adc_report{ORB_ID(adc_report)};
+ uORB::PublicationMulti _to_adc_report{ORB_ID(adc_report)};
- static const hrt_abstime SAMPLE_INTERVAL{50_ms};
+ static const hrt_abstime SAMPLE_INTERVAL{50_ms};
adc_report_s _adc_report{};
- perf_counter_t _cycle_perf;
+ perf_counter_t _cycle_perf;
+ perf_counter_t _comms_errors;
- int _channel_cycle_count{0};
+ uint8_t _channel_cycle_mask{0};
- bool _reported_ready_last_cycle{false};
+ static constexpr uint8_t MAX_READY_COUNTER{20};
+ uint8_t _ready_counter{MAX_READY_COUNTER};
// ADS1115 logic part
- enum ChannelSelection {
- Invalid = -1, A0 = 0, A1, A2, A3
+ enum class Channel : uint8_t {
+ A0 = CONFIG_HIGH_MUX_P0NG,
+ A1 = CONFIG_HIGH_MUX_P1NG,
+ A2 = CONFIG_HIGH_MUX_P2NG,
+ A3 = CONFIG_HIGH_MUX_P3NG,
+ Invalid = 0xff,
};
- /* set multiplexer to specific channel */
- int setChannel(ChannelSelection ch);
- /* return true if sample result is valid */
- bool isSampleReady();
+ constexpr unsigned ch2u(Channel ch) { return (unsigned(ch) >> 4) & 0b11u; }
+ constexpr Channel u2ch(unsigned ch) { return Channel((ch << 4) | CONFIG_HIGH_MUX_P0NG); }
+ // Set the channel and start a conversion
+ int readChannel(Channel ch);
+ // return 1 if sample result is valid else 0 or -1 if I2C transaction failed
+ int isSampleReady();
/*
* get adc sample. return the channel being measured.
* Invalid indicates sample failure.
*/
- ChannelSelection getMeasurement(int16_t *value);
- /*
- * get adc sample and automatically switch to next channel and start another measurement
- */
- ChannelSelection cycleMeasure(int16_t *value);
+ Channel getMeasurement(int16_t *value);
int readReg(uint8_t addr, uint8_t *buf, size_t len);
diff --git a/src/drivers/adc/ads1115/ads1115_main.cpp b/src/drivers/adc/ads1115/ads1115_main.cpp
index 2132082c66..1967b58263 100644
--- a/src/drivers/adc/ads1115/ads1115_main.cpp
+++ b/src/drivers/adc/ads1115/ads1115_main.cpp
@@ -45,7 +45,8 @@
ADS1115::ADS1115(const I2CSPIDriverConfig &config) :
I2C(config),
I2CSPIDriver(config),
- _cycle_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": single-sample"))
+ _cycle_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": single-sample")),
+ _comms_errors(perf_alloc(PC_COUNT, MODULE_NAME": comms errors"))
{
_adc_report.device_id = this->get_device_id();
_adc_report.resolution = 32768;
@@ -61,6 +62,7 @@ ADS1115::~ADS1115()
{
ScheduleClear();
perf_free(_cycle_perf);
+ perf_free(_comms_errors);
}
void ADS1115::exit_and_cleanup()
@@ -77,56 +79,55 @@ void ADS1115::RunImpl()
perf_begin(_cycle_perf);
- _adc_report.timestamp = hrt_absolute_time();
+ const int ready = isSampleReady();
- if (isSampleReady()) { // whether ADS1115 is ready to be read or not
- if (!_reported_ready_last_cycle) {
- PX4_INFO("ADS1115: reported ready");
- _reported_ready_last_cycle = true;
+ if (ready == 1) {
+ // I2C transaction success and status register reported conversion as finished
+ if (_ready_counter == 0) { PX4_INFO("ADS1115: reported ready"); }
+
+ if (_ready_counter < MAX_READY_COUNTER) { _ready_counter++; }
+
+ int16_t value;
+ Channel ch = getMeasurement(&value);
+
+ if (ch != Channel::Invalid) {
+ // Store current readings and mark channel as read
+ const unsigned index{ch2u(ch)};
+ _adc_report.channel_id[index] = index;
+ _adc_report.raw_data[index] = value;
+ _channel_cycle_mask |= 1u << index;
+
+ } else {
+ // we will retry the same channel again
+ perf_count(_comms_errors);
}
- int16_t buf;
- ADS1115::ChannelSelection ch = cycleMeasure(&buf);
- ++_channel_cycle_count;
+ // Find the next unread channel in the bitmask
+ uint8_t next_index{0};
- switch (ch) {
- case ADS1115::A0:
- _adc_report.channel_id[0] = 0;
- _adc_report.raw_data[0] = buf;
- break;
+ for (; next_index < 4 && (_channel_cycle_mask & (1u << next_index)); next_index++) {}
- case ADS1115::A1:
- _adc_report.channel_id[1] = 1;
- _adc_report.raw_data[1] = buf;
- break;
+ readChannel(u2ch(next_index));
- case ADS1115::A2:
- _adc_report.channel_id[2] = 2;
- _adc_report.raw_data[2] = buf;
- break;
-
- case ADS1115::A3:
- _adc_report.channel_id[3] = 3;
- _adc_report.raw_data[3] = buf;
- break;
-
- default:
- PX4_DEBUG("ADS1115: undefined behaviour");
- setChannel(ADS1115::A0);
- --_channel_cycle_count;
- break;
- }
-
- if (_channel_cycle_count == 4) { // ADS1115 has 4 channels
- _channel_cycle_count = 0;
+ if (_channel_cycle_mask == 0b1111) {
+ _channel_cycle_mask = 0;
_to_adc_report.publish(_adc_report);
}
- } else {
- if (_reported_ready_last_cycle) {
- _reported_ready_last_cycle = false;
- PX4_ERR("ADS1115: not ready. Device lost?");
- }
+ } else if (ready == 0) {
+ // I2C transaction success but status register reported conversion still in progress
+ perf_count(_comms_errors);
+ // Reset the channel to unstick the device
+ readChannel(Channel::A0);
+
+ } else if (ready == -1) {
+ if (_ready_counter == 1) { PX4_ERR("ADS1115: device lost"); }
+
+ if (_ready_counter > 0) { _ready_counter--; }
+
+ perf_count(_comms_errors);
+ // Reset the channel to unstick the device
+ readChannel(Channel::A0);
}
perf_end(_cycle_perf);
@@ -151,7 +152,7 @@ parameter, and is disabled by default.
If enabled, internal ADCs are not used.
)DESCR_STR");
-
+
PRINT_MODULE_USAGE_NAME("ads1115", "driver");
PRINT_MODULE_USAGE_COMMAND("start");
PRINT_MODULE_USAGE_PARAMS_I2C_SPI_DRIVER(true, false);
@@ -163,6 +164,7 @@ void ADS1115::print_status()
{
I2CSPIDriverBase::print_status();
perf_print_counter(_cycle_perf);
+ perf_print_counter(_comms_errors);
}
extern "C" int ads1115_main(int argc, char *argv[])
diff --git a/src/drivers/batt_smbus/batt_smbus.cpp b/src/drivers/batt_smbus/batt_smbus.cpp
index b9059f5445..da47a50905 100644
--- a/src/drivers/batt_smbus/batt_smbus.cpp
+++ b/src/drivers/batt_smbus/batt_smbus.cpp
@@ -172,19 +172,19 @@ void BATT_SMBUS::RunImpl()
// Check if max lifetime voltage delta is greater than allowed.
if (_lifetime_max_delta_cell_voltage > BATT_CELL_VOLTAGE_THRESHOLD_FAILED) {
- new_report.warning = battery_status_s::BATTERY_WARNING_CRITICAL;
+ new_report.warning = battery_status_s::WARNING_CRITICAL;
} else if (new_report.remaining > _low_thr) {
- new_report.warning = battery_status_s::BATTERY_WARNING_NONE;
+ new_report.warning = battery_status_s::WARNING_NONE;
} else if (new_report.remaining > _crit_thr) {
- new_report.warning = battery_status_s::BATTERY_WARNING_LOW;
+ new_report.warning = battery_status_s::WARNING_LOW;
} else if (new_report.remaining > _emergency_thr) {
- new_report.warning = battery_status_s::BATTERY_WARNING_CRITICAL;
+ new_report.warning = battery_status_s::WARNING_CRITICAL;
} else {
- new_report.warning = battery_status_s::BATTERY_WARNING_EMERGENCY;
+ new_report.warning = battery_status_s::WARNING_EMERGENCY;
}
new_report.interface_error = perf_event_count(_interface->_interface_errors);
diff --git a/src/drivers/distance_sensor/lightware_laser_i2c/lightware_laser_i2c.cpp b/src/drivers/distance_sensor/lightware_laser_i2c/lightware_laser_i2c.cpp
index 614d408a5e..825cbdf97f 100644
--- a/src/drivers/distance_sensor/lightware_laser_i2c/lightware_laser_i2c.cpp
+++ b/src/drivers/distance_sensor/lightware_laser_i2c/lightware_laser_i2c.cpp
@@ -143,7 +143,7 @@ private:
)
uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)};
uORB::Subscription _vehicle_status_sub{ORB_ID(vehicle_status)};
- typeof(px4::msg::VehicleStatus::vehicle_type) _vehicle_type{px4::msg::VehicleStatus::VEHICLE_TYPE_UNKNOWN};
+ typeof(px4::msg::VehicleStatus::vehicle_type) _vehicle_type{px4::msg::VehicleStatus::VEHICLE_TYPE_ROTARY_WING};
uORB::Subscription _dist_sense_mode_change_sub{ORB_ID(distance_sensor_mode_change_request)};
typeof(px4::msg::DistanceSensorModeChangeRequest::request_on_off) _req_mode{px4::msg::DistanceSensorModeChangeRequest::REQUEST_OFF};
bool _restriction{false};
diff --git a/src/drivers/distance_sensor/ulanding_radar/AerotennaULanding.cpp b/src/drivers/distance_sensor/ulanding_radar/AerotennaULanding.cpp
index 6558aef348..ffd2c81a7a 100644
--- a/src/drivers/distance_sensor/ulanding_radar/AerotennaULanding.cpp
+++ b/src/drivers/distance_sensor/ulanding_radar/AerotennaULanding.cpp
@@ -125,10 +125,15 @@ int AerotennaULanding::collect()
index--;
}
+
+ } else {
+ return -EAGAIN;
}
if (!checksum_passed) {
- return -EAGAIN;
+ perf_count(_comms_errors);
+ perf_end(_sample_perf);
+ return -EBADMSG;
}
_px4_rangefinder.update(timestamp_sample, distance_m);
diff --git a/src/drivers/distance_sensor/ulanding_radar/AerotennaULanding.hpp b/src/drivers/distance_sensor/ulanding_radar/AerotennaULanding.hpp
index dc133254bf..98d1c0ab90 100644
--- a/src/drivers/distance_sensor/ulanding_radar/AerotennaULanding.hpp
+++ b/src/drivers/distance_sensor/ulanding_radar/AerotennaULanding.hpp
@@ -56,7 +56,7 @@
using namespace time_literals;
-#define ULANDING_MEASURE_INTERVAL 10_ms
+#define ULANDING_MEASURE_INTERVAL 12_ms
#define ULANDING_MAX_DISTANCE 50.0f
#define ULANDING_MIN_DISTANCE 0.315f
#define ULANDING_VERSION 1
diff --git a/src/drivers/gps/gps.cpp b/src/drivers/gps/gps.cpp
index aeeba755e3..ba6f24070f 100644
--- a/src/drivers/gps/gps.cpp
+++ b/src/drivers/gps/gps.cpp
@@ -547,8 +547,13 @@ void GPS::handleInjectDataTopic()
for (int instance = 0; instance < _orb_inject_data_sub.size(); instance++) {
const bool exists = _orb_inject_data_sub[instance].advertised();
- if (exists) {
- if (_orb_inject_data_sub[instance].copy(&msg)) {
+ if (exists && _orb_inject_data_sub[instance].copy(&msg)) {
+ /* Don't select the own RTCM instance. In case it has a lower
+ * instance number, it will be selected and will be rejected
+ * later in the code, resulting in no RTCM injection at all.
+ */
+ if (msg.device_id != get_device_id()) {
+ // Only use the message if it is up to date
if ((hrt_absolute_time() - msg.timestamp) < 5_s) {
// Remember that we already did a copy on this instance.
already_copied = true;
diff --git a/src/drivers/imu/invensense/mpu6000/InvenSense_MPU6000_registers.hpp b/src/drivers/imu/invensense/mpu6000/InvenSense_MPU6000_registers.hpp
index 768f4a3de9..b53a6dab43 100644
--- a/src/drivers/imu/invensense/mpu6000/InvenSense_MPU6000_registers.hpp
+++ b/src/drivers/imu/invensense/mpu6000/InvenSense_MPU6000_registers.hpp
@@ -41,6 +41,7 @@
#pragma once
#include
+#include
// TODO: move to a central header
static constexpr uint8_t Bit0 = (1 << 0);
diff --git a/src/drivers/power_monitor/ina220/ina220.cpp b/src/drivers/power_monitor/ina220/ina220.cpp
index 305d1a61a2..c8f52bf71c 100644
--- a/src/drivers/power_monitor/ina220/ina220.cpp
+++ b/src/drivers/power_monitor/ina220/ina220.cpp
@@ -52,7 +52,7 @@ INA220::INA220(const I2CSPIDriverConfig &config, int battery_index) :
_collection_errors(perf_alloc(PC_COUNT, "ina220_collection_err")),
_measure_errors(perf_alloc(PC_COUNT, "ina220_measurement_err")),
_ch_type((PM_CH_TYPE)config.custom2),
- _battery(battery_index, this, INA220_SAMPLE_INTERVAL_US, battery_status_s::BATTERY_SOURCE_POWER_MODULE)
+ _battery(battery_index, this, INA220_SAMPLE_INTERVAL_US, battery_status_s::SOURCE_POWER_MODULE)
{
float fvalue = MAX_CURRENT;
_max_current = fvalue;
diff --git a/src/drivers/power_monitor/ina226/ina226.cpp b/src/drivers/power_monitor/ina226/ina226.cpp
index 2c117caf1d..f61a7c7b79 100644
--- a/src/drivers/power_monitor/ina226/ina226.cpp
+++ b/src/drivers/power_monitor/ina226/ina226.cpp
@@ -49,7 +49,7 @@ INA226::INA226(const I2CSPIDriverConfig &config, int battery_index) :
_comms_errors(perf_alloc(PC_COUNT, "ina226_com_err")),
_collection_errors(perf_alloc(PC_COUNT, "ina226_collection_err")),
_measure_errors(perf_alloc(PC_COUNT, "ina226_measurement_err")),
- _battery(battery_index, this, INA226_SAMPLE_INTERVAL_US, battery_status_s::BATTERY_SOURCE_POWER_MODULE)
+ _battery(battery_index, this, INA226_SAMPLE_INTERVAL_US, battery_status_s::SOURCE_POWER_MODULE)
{
float fvalue = MAX_CURRENT;
_max_current = fvalue;
diff --git a/src/drivers/power_monitor/ina228/ina228.cpp b/src/drivers/power_monitor/ina228/ina228.cpp
index 8c0207b3f2..6505a7d65e 100644
--- a/src/drivers/power_monitor/ina228/ina228.cpp
+++ b/src/drivers/power_monitor/ina228/ina228.cpp
@@ -49,7 +49,7 @@ INA228::INA228(const I2CSPIDriverConfig &config, int battery_index) :
_comms_errors(perf_alloc(PC_COUNT, "ina228_com_err")),
_collection_errors(perf_alloc(PC_COUNT, "ina228_collection_err")),
_measure_errors(perf_alloc(PC_COUNT, "ina228_measurement_err")),
- _battery(battery_index, this, INA228_SAMPLE_INTERVAL_US, battery_status_s::BATTERY_SOURCE_POWER_MODULE)
+ _battery(battery_index, this, INA228_SAMPLE_INTERVAL_US, battery_status_s::SOURCE_POWER_MODULE)
{
float fvalue = MAX_CURRENT;
_max_current = fvalue;
diff --git a/src/drivers/power_monitor/ina238/ina238.cpp b/src/drivers/power_monitor/ina238/ina238.cpp
index b46b277a84..ff3f193385 100644
--- a/src/drivers/power_monitor/ina238/ina238.cpp
+++ b/src/drivers/power_monitor/ina238/ina238.cpp
@@ -45,7 +45,7 @@ INA238::INA238(const I2CSPIDriverConfig &config, int battery_index) :
_sample_perf(perf_alloc(PC_ELAPSED, "ina238_read")),
_comms_errors(perf_alloc(PC_COUNT, "ina238_com_err")),
_collection_errors(perf_alloc(PC_COUNT, "ina238_collection_err")),
- _battery(battery_index, this, INA238_SAMPLE_INTERVAL_US, battery_status_s::BATTERY_SOURCE_POWER_MODULE)
+ _battery(battery_index, this, INA238_SAMPLE_INTERVAL_US, battery_status_s::SOURCE_POWER_MODULE)
{
float fvalue = DEFAULT_MAX_CURRENT;
_max_current = fvalue;
diff --git a/src/drivers/power_monitor/voxlpm/voxlpm.cpp b/src/drivers/power_monitor/voxlpm/voxlpm.cpp
index 5fa109d57d..51a496bd6d 100644
--- a/src/drivers/power_monitor/voxlpm/voxlpm.cpp
+++ b/src/drivers/power_monitor/voxlpm/voxlpm.cpp
@@ -54,7 +54,7 @@ VOXLPM::VOXLPM(const I2CSPIDriverConfig &config) :
_sample_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": sample")),
_comms_errors(perf_alloc(PC_COUNT, MODULE_NAME": comms_errors")),
_ch_type((VOXLPM_CH_TYPE)config.custom1),
- _battery(1, this, _meas_interval_us, battery_status_s::BATTERY_SOURCE_POWER_MODULE)
+ _battery(1, this, _meas_interval_us, battery_status_s::SOURCE_POWER_MODULE)
{
}
diff --git a/src/drivers/rc/ghst_rc/GhstRc.cpp b/src/drivers/rc/ghst_rc/GhstRc.cpp
index 1960c84ce6..1aa3c23e89 100644
--- a/src/drivers/rc/ghst_rc/GhstRc.cpp
+++ b/src/drivers/rc/ghst_rc/GhstRc.cpp
@@ -34,6 +34,7 @@
#include "GhstRc.hpp"
#include
+#include
GhstRc::GhstRc(const char *device) :
ModuleParams(nullptr),
@@ -174,16 +175,18 @@ void GhstRc::Run()
if (newBytes > 0) {
uint16_t raw_rc_values[input_rc_s::RC_INPUT_MAX_CHANNELS] {};
uint16_t raw_rc_count = 0;
- int8_t ghst_rssi = -1;
+ ghstLinkStatistics_t link_stats = { .rssi_pct = -1, .rssi_dbm = NAN, .link_quality = 0 };
- if (ghst_parse(cycle_timestamp, &rcs_buf[0], newBytes, &raw_rc_values[0], &ghst_rssi,
+ if (ghst_parse(cycle_timestamp, &rcs_buf[0], newBytes, &raw_rc_values[0], &link_stats,
&raw_rc_count, input_rc_s::RC_INPUT_MAX_CHANNELS)
) {
// we have a new GHST frame. Publish it.
input_rc_s input_rc{};
input_rc.timestamp_last_signal = cycle_timestamp;
input_rc.channel_count = math::constrain(raw_rc_count, (uint16_t)0, (uint16_t)input_rc_s::RC_INPUT_MAX_CHANNELS);
- input_rc.rssi = ghst_rssi;
+ input_rc.rssi = link_stats.rssi_pct;
+ input_rc.link_quality = link_stats.link_quality;
+ input_rc.rssi_dbm = link_stats.rssi_dbm;
input_rc.input_source = input_rc_s::RC_INPUT_SOURCE_PX4FMU_GHST;
unsigned valid_chans = 0;
@@ -200,13 +203,11 @@ void GhstRc::Run()
if (valid_chans == 0) {
input_rc.rssi = 0;
+ // can't force link quality to zero here, receiver takes care of this
}
input_rc.rc_lost = (valid_chans == 0);
- input_rc.link_quality = -1;
- input_rc.rssi_dbm = NAN;
-
input_rc.timestamp = hrt_absolute_time();
_input_rc_pub.publish(input_rc);
perf_count(_publish_interval_perf);
diff --git a/src/drivers/rc_input/RCInput.cpp b/src/drivers/rc_input/RCInput.cpp
index 12cd1ab0bf..538cb9d8ed 100644
--- a/src/drivers/rc_input/RCInput.cpp
+++ b/src/drivers/rc_input/RCInput.cpp
@@ -762,14 +762,15 @@ void RCInput::Run()
// parse new data
if (newBytes > 0) {
- int8_t ghst_rssi = -1;
- rc_updated = ghst_parse(cycle_timestamp, &_rcs_buf[0], newBytes, &_raw_rc_values[0], &ghst_rssi,
+ ghstLinkStatistics_t link_stats = { .rssi_pct = -1, .rssi_dbm = NAN, .link_quality = 0 };
+
+ rc_updated = ghst_parse(cycle_timestamp, &_rcs_buf[0], newBytes, &_raw_rc_values[0], &link_stats,
&_raw_rc_count, input_rc_s::RC_INPUT_MAX_CHANNELS);
if (rc_updated) {
// we have a new GHST frame. Publish it.
_input_rc.input_source = input_rc_s::RC_INPUT_SOURCE_PX4FMU_GHST;
- int32_t valid_chans = fill_rc_in(_raw_rc_count, _raw_rc_values, cycle_timestamp, false, false, 0, ghst_rssi);
+ int32_t valid_chans = fill_rc_in(_raw_rc_count, _raw_rc_values, cycle_timestamp, false, false, 0, link_stats.rssi_pct);
// ghst telemetry works on fmu-v5
// on other Pixhawk (-related) boards we cannot write to the RC UART
diff --git a/src/drivers/rpm_capture/rpm_capture_params.c b/src/drivers/rpm_capture/rpm_capture_params.c
index 13bd3fb7a7..5402d089ab 100644
--- a/src/drivers/rpm_capture/rpm_capture_params.c
+++ b/src/drivers/rpm_capture/rpm_capture_params.c
@@ -32,9 +32,9 @@
****************************************************************************/
/**
- * RPM Capture Enable
+ * RPM capture enable
*
- * Enables the RPM capture module on FMU channel 5.
+ * Enables the RPM capture module to estimate RPM from pulses detected on a PWM pin configured as "RPM Input".
*
* @boolean
* @group System
diff --git a/src/drivers/smart_battery/batmon/batmon.cpp b/src/drivers/smart_battery/batmon/batmon.cpp
index 9061a6d3e4..ed424c1e18 100644
--- a/src/drivers/smart_battery/batmon/batmon.cpp
+++ b/src/drivers/smart_battery/batmon/batmon.cpp
@@ -199,19 +199,19 @@ void Batmon::RunImpl()
// TODO: This critical setting should be set with BMS info or through a paramter
// Setting a hard coded BATT_CELL_VOLTAGE_THRESHOLD_FAILED may not be appropriate
//if (_lifetime_max_delta_cell_voltage > BATT_CELL_VOLTAGE_THRESHOLD_FAILED) {
- // new_report.warning = battery_status_s::BATTERY_WARNING_CRITICAL;
+ // new_report.warning = battery_status_s::WARNING_CRITICAL;
if (new_report.remaining > _low_thr) {
- new_report.warning = battery_status_s::BATTERY_WARNING_NONE;
+ new_report.warning = battery_status_s::WARNING_NONE;
} else if (new_report.remaining > _crit_thr) {
- new_report.warning = battery_status_s::BATTERY_WARNING_LOW;
+ new_report.warning = battery_status_s::WARNING_LOW;
} else if (new_report.remaining > _emergency_thr) {
- new_report.warning = battery_status_s::BATTERY_WARNING_CRITICAL;
+ new_report.warning = battery_status_s::WARNING_CRITICAL;
} else {
- new_report.warning = battery_status_s::BATTERY_WARNING_EMERGENCY;
+ new_report.warning = battery_status_s::WARNING_EMERGENCY;
}
new_report.interface_error = perf_event_count(_interface->_interface_errors);
diff --git a/src/drivers/telemetry/hott/messages.cpp b/src/drivers/telemetry/hott/messages.cpp
index 3be05d87a3..364d5005a7 100644
--- a/src/drivers/telemetry/hott/messages.cpp
+++ b/src/drivers/telemetry/hott/messages.cpp
@@ -150,7 +150,7 @@ build_eam_response(uint8_t *buffer, size_t *size)
msg.eam_sensor_id = EAM_SENSOR_ID;
msg.sensor_text_id = EAM_SENSOR_TEXT_ID;
- msg.temperature1 = (uint8_t)(airdata.baro_temp_celcius + 20);
+ msg.temperature1 = (uint8_t)(airdata.ambient_temperature + 20);
msg.temperature2 = msg.temperature1 - BOARD_TEMP_OFFSET_DEG;
msg.main_voltage_L = (uint8_t)(battery.voltage_v * 10);
diff --git a/src/drivers/uavcan/sensors/airspeed.cpp b/src/drivers/uavcan/sensors/airspeed.cpp
index e62b29d5ea..2127817fd0 100644
--- a/src/drivers/uavcan/sensors/airspeed.cpp
+++ b/src/drivers/uavcan/sensors/airspeed.cpp
@@ -104,7 +104,6 @@ UavcanAirspeedBridge::ias_sub_cb(const
report.timestamp = hrt_absolute_time();
report.indicated_airspeed_m_s = msg.indicated_airspeed;
report.true_airspeed_m_s = _last_tas_m_s;
- report.air_temperature_celsius = _last_outside_air_temp_k + atmosphere::kAbsoluteNullCelsius;
publish(msg.getSrcNodeID().get(), &report);
}
diff --git a/src/drivers/uavcan/sensors/battery.cpp b/src/drivers/uavcan/sensors/battery.cpp
index 77698cff16..0c8528670f 100644
--- a/src/drivers/uavcan/sensors/battery.cpp
+++ b/src/drivers/uavcan/sensors/battery.cpp
@@ -44,7 +44,7 @@ UavcanBatteryBridge::UavcanBatteryBridge(uavcan::INode &node) :
ModuleParams(nullptr),
_sub_battery(node),
_sub_battery_aux(node),
- _warning(battery_status_s::BATTERY_WARNING_NONE),
+ _warning(battery_status_s::WARNING_NONE),
_last_timestamp(0)
{
}
@@ -215,14 +215,14 @@ void
UavcanBatteryBridge::determineWarning(float remaining)
{
// propagate warning state only if the state is higher, otherwise remain in current warning state
- if (remaining < _param_bat_emergen_thr.get() || (_warning == battery_status_s::BATTERY_WARNING_EMERGENCY)) {
- _warning = battery_status_s::BATTERY_WARNING_EMERGENCY;
+ if (remaining < _param_bat_emergen_thr.get() || (_warning == battery_status_s::WARNING_EMERGENCY)) {
+ _warning = battery_status_s::WARNING_EMERGENCY;
- } else if (remaining < _param_bat_crit_thr.get() || (_warning == battery_status_s::BATTERY_WARNING_CRITICAL)) {
- _warning = battery_status_s::BATTERY_WARNING_CRITICAL;
+ } else if (remaining < _param_bat_crit_thr.get() || (_warning == battery_status_s::WARNING_CRITICAL)) {
+ _warning = battery_status_s::WARNING_CRITICAL;
- } else if (remaining < _param_bat_low_thr.get() || (_warning == battery_status_s::BATTERY_WARNING_LOW)) {
- _warning = battery_status_s::BATTERY_WARNING_LOW;
+ } else if (remaining < _param_bat_low_thr.get() || (_warning == battery_status_s::WARNING_LOW)) {
+ _warning = battery_status_s::WARNING_LOW;
}
}
diff --git a/src/drivers/uavcan/sensors/battery.hpp b/src/drivers/uavcan/sensors/battery.hpp
index ceb6222da0..a27ad64505 100644
--- a/src/drivers/uavcan/sensors/battery.hpp
+++ b/src/drivers/uavcan/sensors/battery.hpp
@@ -107,10 +107,10 @@ private:
static_assert(battery_status_s::MAX_INSTANCES <= BATTERY_INDEX_4, "Battery array too big");
- Battery battery1 = {BATTERY_INDEX_1, this, SAMPLE_INTERVAL_US, battery_status_s::BATTERY_SOURCE_EXTERNAL};
- Battery battery2 = {BATTERY_INDEX_2, this, SAMPLE_INTERVAL_US, battery_status_s::BATTERY_SOURCE_EXTERNAL};
- Battery battery3 = {BATTERY_INDEX_3, this, SAMPLE_INTERVAL_US, battery_status_s::BATTERY_SOURCE_EXTERNAL};
- Battery battery4 = {BATTERY_INDEX_4, this, SAMPLE_INTERVAL_US, battery_status_s::BATTERY_SOURCE_EXTERNAL};
+ Battery battery1 = {BATTERY_INDEX_1, this, SAMPLE_INTERVAL_US, battery_status_s::SOURCE_EXTERNAL};
+ Battery battery2 = {BATTERY_INDEX_2, this, SAMPLE_INTERVAL_US, battery_status_s::SOURCE_EXTERNAL};
+ Battery battery3 = {BATTERY_INDEX_3, this, SAMPLE_INTERVAL_US, battery_status_s::SOURCE_EXTERNAL};
+ Battery battery4 = {BATTERY_INDEX_4, this, SAMPLE_INTERVAL_US, battery_status_s::SOURCE_EXTERNAL};
Battery *_battery[battery_status_s::MAX_INSTANCES] = { &battery1, &battery2, &battery3, &battery4 };
};
diff --git a/src/drivers/uavcannode/Publishers/RangeSensorMeasurement.hpp b/src/drivers/uavcannode/Publishers/RangeSensorMeasurement.hpp
index 129bd32c21..134caea21a 100644
--- a/src/drivers/uavcannode/Publishers/RangeSensorMeasurement.hpp
+++ b/src/drivers/uavcannode/Publishers/RangeSensorMeasurement.hpp
@@ -100,10 +100,12 @@ public:
}
// reading_type
- if (dist.current_distance >= dist.max_distance) {
+ const float tolerance = 1e-6;
+
+ if (dist.current_distance > dist.max_distance) {
range_sensor.reading_type = uavcan::equipment::range_sensor::Measurement::READING_TYPE_TOO_FAR;
- } else if (dist.current_distance <= dist.min_distance) {
+ } else if (dist.current_distance < dist.min_distance - tolerance) {
range_sensor.reading_type = uavcan::equipment::range_sensor::Measurement::READING_TYPE_TOO_CLOSE;
} else if (dist.signal_quality != 0) {
diff --git a/src/drivers/voxl2_io/CMakeLists.txt b/src/drivers/voxl2_io/CMakeLists.txt
index 57a5f4af21..b6e3d8a3c2 100644
--- a/src/drivers/voxl2_io/CMakeLists.txt
+++ b/src/drivers/voxl2_io/CMakeLists.txt
@@ -37,15 +37,12 @@ px4_add_module(
SRCS
voxl2_io_crc16.c
voxl2_io_crc16.h
- voxl2_io_serial.cpp
- voxl2_io_serial.hpp
voxl2_io_packet.c
voxl2_io_packet.h
voxl2_io_packet_types.h
voxl2_io.cpp
voxl2_io.hpp
DEPENDS
- rc
px4_work_queue
mixer_module
MODULE_CONFIG
diff --git a/src/drivers/voxl2_io/module.yaml b/src/drivers/voxl2_io/module.yaml
index 021305e955..86dc48ca58 100644
--- a/src/drivers/voxl2_io/module.yaml
+++ b/src/drivers/voxl2_io/module.yaml
@@ -1,12 +1,12 @@
module_name: VOXL2 IO Output
actuator_output:
- config_parameters:
- - param: 'VOXL2_IO_MIN'
- label: 'PWM min value'
- - param: 'VOXL2_IO_MAX'
- label: 'PWM max value'
+# config_parameters:
+# - param: 'VOXL2_IO_MIN'
+# label: 'PWM min value'
+# - param: 'VOXL2_IO_MAX'
+# label: 'PWM max value'
output_groups:
- param_prefix: VOXL2_IO
group_label: 'PWMs'
channel_label: 'PWM Channel'
- num_channels: 4
+ num_channels: 8
diff --git a/src/drivers/voxl2_io/voxl2_io.cpp b/src/drivers/voxl2_io/voxl2_io.cpp
index 352b474906..3461c99a4b 100644
--- a/src/drivers/voxl2_io/voxl2_io.cpp
+++ b/src/drivers/voxl2_io/voxl2_io.cpp
@@ -33,8 +33,6 @@
#include "voxl2_io.hpp"
-#include
-
Voxl2IO::Voxl2IO() :
OutputModuleInterface(MODULE_NAME, px4::serial_port_to_wq(VOXL2_IO_DEFAULT_PORT)),
@@ -43,69 +41,81 @@ Voxl2IO::Voxl2IO() :
_output_update_perf(perf_alloc(PC_INTERVAL, MODULE_NAME": output update interval"))
{
_mixing_output.setMaxNumOutputs(VOXL2_IO_OUTPUT_CHANNELS);
- _uart_port = new Voxl2IoSerial();
- voxl2_io_packet_init(&_sbus_packet);
+ voxl2_io_packet_init(&_voxl2_io_packet);
+
+ //set low rate scheduling interval to 200hz so that RC can be updated even if all actuators are disabled
+ //otherwise, the default low rate scheduling interval is 300ms and RC packets are delayed and lost
+ _mixing_output.setLowrateSchedulingInterval(5_ms);
}
Voxl2IO::~Voxl2IO()
{
- /* make sure servos are off */
- stop_all_pwms();
-
- if (_uart_port) {
- _uart_port->uart_close();
- _uart_port = nullptr;
- }
+ _uart_port.close();
perf_free(_cycle_perf);
perf_free(_output_update_perf);
}
-
int Voxl2IO::init()
{
+ PX4_INFO("VOXL2_IO: Driver starting");
+
int ret = PX4_OK;
- /* Open serial port in this thread */
- if (!_uart_port->is_open()) {
- if (_uart_port->uart_open((const char *)_device, _parameters.baud_rate) == PX4_OK) {
- /* Send PWM config to M0065... pwm_min and pwm_max */
- PX4_INFO("Opened UART connection to M0065 device on port %s", _device);
-
- } else {
- PX4_ERR("Failed opening device");
- return PX4_ERROR;
- }
- }
-
- /* Verify connectivity and protocol version number */
- if (get_version_info() < 0) {
- PX4_ERR("Failed to detect voxl2_io protocol version.");
- return PX4_ERROR;
-
- } else {
- if (_version_info.sw_version == VOXL2_IO_SW_PROTOCOL_VERSION
- && _version_info.hw_version == VOXL2_IO_HW_PROTOCOL_VERSION) {
- PX4_INFO("Detected M0065 protocol version. SW: %u HW: %u", _version_info.sw_version, _version_info.hw_version);
-
- } else {
- PX4_ERR("Detected incorrect M0065 protocol version. SW: %u HW: %u", _version_info.sw_version, _version_info.hw_version);
- return PX4_ERROR;
- }
- }
-
- /* Getting initial parameter values */
+ // Getting initial parameter values
ret = update_params();
if (ret != OK) {
+ PX4_ERR("VOXL2_IO: Failed to update params during init");
return ret;
}
- /* Send PWM MIN/MAX to M0065 */
- update_pwm_config();
+ // Print initial param values
+ print_params();
- ScheduleOnInterval(_current_update_interval);
- // ScheduleNow();
+ PX4_INFO("VOXL2_IO: ");
+
+ // Open serial port
+ if (!_uart_port.isOpen()) {
+ PX4_INFO("VOXL2_IO: Opening UART ESC device %s, baud rate %" PRIi32, _device, _parameters.baud_rate);
+
+ // Configure UART port
+ if (! _uart_port.setPort(_device)) {
+ PX4_ERR("Error configuring serial device on port %s", _device);
+ return -1;
+ }
+
+ if (! _uart_port.setBaudrate(_parameters.baud_rate)) {
+ PX4_ERR("Error setting baudrate to %d on %s", (int) _parameters.baud_rate, _device);
+ return -1;
+ }
+
+ // Open the UART. If this is successful then the UART is ready to use.
+ if (! _uart_port.open()) {
+ PX4_ERR("Error opening serial device %s", _device);
+ return -1;
+ }
+ }
+
+ // Detect M0065 board
+ ret = get_version_info();
+
+ if (ret != 0) {
+ PX4_ERR("VOXL2_IO: Could not detect the board");
+ PX4_ERR("VOXL2_IO: Driver initialization failed. Exiting");
+
+ if (_uart_port.open()) {
+ PX4_INFO("VOXL2_IO: Closing uart port");
+ _uart_port.close();
+ }
+
+ return -1;
+ }
+
+ //ScheduleOnInterval(_current_update_interval);
+ ScheduleNow();
+
+ PX4_INFO("VOXL2_IO: Driver initialization succeeded");
return ret;
}
@@ -117,11 +127,10 @@ int Voxl2IO::update_params()
ret = load_params(&_parameters);
if (ret == PX4_OK) {
- _mixing_output.setAllDisarmedValues(VOXL2_IO_MIXER_DISARMED);
+ _mixing_output.setAllDisarmedValues(_parameters.pwm_dis);
_mixing_output.setAllFailsafeValues(VOXL2_IO_MIXER_FAILSAFE);
- _mixing_output.setAllMinValues(VOXL2_IO_MIXER_MIN);
- _mixing_output.setAllMaxValues(VOXL2_IO_MIXER_MAX);
- _pwm_fullscale = _parameters.pwm_max - _parameters.pwm_min;
+ _mixing_output.setAllMinValues(_parameters.pwm_min);
+ _mixing_output.setAllMaxValues(_parameters.pwm_max);
}
return ret;
@@ -130,196 +139,159 @@ int Voxl2IO::update_params()
int Voxl2IO::load_params(voxl2_io_params_t *params)
{
int ret = PX4_OK;
- int32_t max = params->pwm_max;
- int32_t min = params->pwm_min;
// initialize out
for (int i = 0; i < VOXL2_IO_OUTPUT_CHANNELS; i++) {
params->function_map[i] = (int)OutputFunction::Disabled;
}
- /* UART config, PWM mode, and RC protocol*/
+ // UART config, PWM mode, and RC protocol
param_get(param_find("VOXL2_IO_BAUD"), ¶ms->baud_rate);
- param_get(param_find("RC_INPUT_PROTO"), ¶ms->param_rc_input_proto);
+ //param_get(param_find("RC_INPUT_PROTO"), ¶ms->param_rc_input_proto);
- /* PWM min, max, and failsafe values*/
+ // PWM min, max, and failsafe values
param_get(param_find("VOXL2_IO_MIN"), ¶ms->pwm_min);
param_get(param_find("VOXL2_IO_MAX"), ¶ms->pwm_max);
+ param_get(param_find("VOXL2_IO_DIS"), ¶ms->pwm_dis);
+ param_get(param_find("VOXL2_IO_CMIN"), ¶ms->pwm_cal_min);
+ param_get(param_find("VOXL2_IO_CMAX"), ¶ms->pwm_cal_max);
- /* PWM output functions */
+ // PWM output functions
+ //0: disabled, 1: constant min, 2: constant max
+ //101-112: motors, 201-208: servos, 402: RC Roll, 403: RC Pitch, 404: RC Throttle,
+ //405: RC Yaw, 406: RC Flaps, 407-412: RC AUX 1-6, 420-422: Gimbal RPY
param_get(param_find("VOXL2_IO_FUNC1"), ¶ms->function_map[0]);
param_get(param_find("VOXL2_IO_FUNC2"), ¶ms->function_map[1]);
param_get(param_find("VOXL2_IO_FUNC3"), ¶ms->function_map[2]);
param_get(param_find("VOXL2_IO_FUNC4"), ¶ms->function_map[3]);
+ param_get(param_find("VOXL2_IO_FUNC5"), ¶ms->function_map[4]);
+ param_get(param_find("VOXL2_IO_FUNC6"), ¶ms->function_map[5]);
+ param_get(param_find("VOXL2_IO_FUNC7"), ¶ms->function_map[6]);
+ param_get(param_find("VOXL2_IO_FUNC8"), ¶ms->function_map[7]);
- /* Validate PWM min and max values */
+ // Validate PWM min and max values
if (params->pwm_min > params->pwm_max) {
- PX4_ERR("Invalid parameter VOXL2_IO_MIN. Please verify parameters.");
+ PX4_ERR("VOXL2_IO: Invalid parameter VOXL2_IO_MIN. Please verify parameters.");
params->pwm_min = 0;
ret = PX4_ERROR;
}
- if (ret == PX4_OK && _uart_port->is_open() && (max != params->pwm_max || min != params->pwm_min)) {
- PX4_INFO("Updating PWM params load_params");
- update_pwm_config();
- }
-
return ret;
}
-void Voxl2IO::update_pwm_config()
-{
- Command cmd;
- uint8_t data[VOXL2_IO_BOARD_CONFIG_SIZE] = {static_cast((_parameters.pwm_min & 0xFF00) >> 8), static_cast(_parameters.pwm_min & 0xFF),
- static_cast((_parameters.pwm_max & 0xFF00) >> 8), static_cast(_parameters.pwm_max & 0xFF)
- };
- cmd.len = voxl2_io_create_packet(VOXL2_IO_PACKET_TYPE_CONFIG_BOARD_REQUEST, data, VOXL2_IO_BOARD_CONFIG_SIZE, cmd.buf,
- sizeof(cmd.buf));
-
- if (_uart_port->uart_write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("Failed to send config packet");
-
- } else {
- _bytes_sent += cmd.len;
- _packets_sent++;
- }
-}
-
int Voxl2IO::get_version_info()
{
- int res = 0 ;
- int header = -1 ;
- int info_packet = -1;
- int read_retries = 3;
- int read_succeeded = 0;
+ PX4_INFO("VOXL2_IO: Detecting M0065 board...");
+ voxl2_io_packet_init(&_voxl2_io_packet);
+
Command cmd;
+ cmd.len = voxl2_io_create_extended_version_request_packet(0, cmd.buf, sizeof(cmd.buf));
- /* Request protocol version info from M0065 */
- cmd.len = voxl2_io_create_version_request_packet(0, cmd.buf, VOXL2_IO_VERSION_INFO_SIZE);
+ int retries_left = _board_detect_retries;
+ bool got_response = false;
- if (_uart_port->uart_write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("Failed to send version info packet");
+ while ((got_response == false) && (retries_left > 0)) {
+ retries_left--;
+
+ //send the version request command to the board
+ if (_uart_port.write(cmd.buf, cmd.len) != cmd.len) {
+ PX4_ERR("VOXL2_IO: Could not write version request packet to UART port");
+ return -1;
+ }
- } else {
_bytes_sent += cmd.len;
_packets_sent++;
- }
- /* Read response */
- px4_usleep(10000);
- memset(&_read_buf, 0x00, READ_BUF_SIZE);
- res = _uart_port->uart_read(_read_buf, READ_BUF_SIZE);
+ hrt_abstime t_request = hrt_absolute_time();
+ hrt_abstime t_timeout = 50000; //50ms timeout for version info response
- while (read_retries) {
- if (res) {
- /* Get index of packer header */
- for (int index = 0; index < READ_BUF_SIZE; ++index) {
- if (_read_buf[index] == VOXL2_IO_PACKET_TYPE_VERSION_RESPONSE) {
- info_packet = index;
- break;
- }
- if (_read_buf[index] == VOXL2_IO_PACKET_HEADER) {
- header = index;
+ //wait for the response to come back
+ while ((!got_response) && (hrt_elapsed_time(&t_request) < t_timeout)) {
+ px4_usleep(500); //sleep a bit while waiting for the board to respond
+
+ int nread = _uart_port.read(_read_buf, sizeof(_read_buf));
+
+ for (int i = 0; i < nread; i++) {
+ int16_t parse_ret = voxl2_io_packet_process_char(_read_buf[i], &_voxl2_io_packet);
+
+ if (parse_ret > 0) {
+ hrt_abstime response_time = hrt_elapsed_time(&t_request);
+ //PX4_INFO("got packet of length %i",ret);
+ _packets_received++;
+ uint8_t packet_type = voxl2_io_packet_get_type(&_voxl2_io_packet);
+ uint8_t packet_size = voxl2_io_packet_get_size(&_voxl2_io_packet);
+
+ if (packet_type == VOXL2_IO_PACKET_TYPE_VERSION_EXT_RESPONSE && packet_size == sizeof(VOXL2_IO_EXTENDED_VERSION_INFO)) {
+ VOXL2_IO_EXTENDED_VERSION_INFO ver;
+ memcpy(&ver, _voxl2_io_packet.buffer, packet_size);
+
+ PX4_INFO("VOXL2_IO: \tVOXL2_IO ID: %i", ver.id);
+ PX4_INFO("VOXL2_IO: \tBoard Type : %i: %s", ver.hw_version, board_id_to_name(ver.hw_version).c_str());
+
+ uint8_t *u = &ver.unique_id[0];
+ PX4_INFO("VOXL2_IO: \tUnique ID : 0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ u[11], u[10], u[9], u[8], u[7], u[6], u[5], u[4], u[3], u[2], u[1], u[0]);
+
+ PX4_INFO("VOXL2_IO: \tFirmware : version %4d, hash %.12s", ver.sw_version, ver.firmware_git_version);
+ PX4_INFO("VOXL2_IO: \tBootloader : version %4d, hash %.12s", ver.bootloader_version, ver.bootloader_git_version);
+ PX4_INFO("VOXL2_IO: \tReply time : %uus", (uint32_t)response_time);
+
+ //we requested response from ID 0, so it should match
+ if (ver.id != 0) {
+ PX4_ERR("VOXL2_IO: Invalid id: %d", ver.id);
+ }
+
+ //check HW (board version)
+ else if (ver.hw_version != VOXL2_IO_HW_VERSION) {
+ PX4_ERR("VOXL2_IO: Invalid HW version : %d (expected %d)", ver.hw_version, VOXL2_IO_HW_VERSION);
+ return -1;
+ }
+
+ //check firmware version running on the board
+ else if (ver.sw_version != VOXL2_IO_SW_VERSION) {
+ PX4_ERR("VOXL2_IO: Invalid FW version : %d (expected %d)", ver.sw_version, VOXL2_IO_SW_VERSION);
+ return -1;
+
+ } else {
+ got_response = true;
+ memcpy(&_version_info, &ver, sizeof(_version_info)); //store the version info only if it is valid
+ }
+ }
}
}
- /* Try again in a bit if packet header not present yet... */
- if (header == -1 || info_packet == -1) {
- if (_debug && header == -1) { PX4_ERR("Failed to find voxl2_io packet header, trying again... retries left: %i", read_retries); }
-
- if (_debug && info_packet == -1) { PX4_ERR("Failed to find version info packet header, trying again... retries left: %i", read_retries); }
-
- read_retries--;
- flush_uart_rx();
-
- if (_uart_port->uart_write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("Failed to send version info packet");
-
- } else {
- _bytes_sent += cmd.len;
- _packets_sent++;
- px4_usleep(2000);
- }
-
- continue;
- }
-
- /* Check if we got a valid packet...*/
- if (parse_response(&_read_buf[header], (uint8_t)VOXL2_IO_VERSION_INFO_SIZE)) {
- if (_debug) {
- PX4_ERR("Error parsing version info packet");
- PX4_INFO_RAW("[%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x]\n",
- _read_buf[header + 0], _read_buf[header + 1], _read_buf[header + 2], _read_buf[header + 3], _read_buf[header + 4],
- _read_buf[header + 5],
- _read_buf[header + 6], _read_buf[header + 7], _read_buf[header + 8], _read_buf[header + 9], _read_buf[header + 10],
- _read_buf[header + 11],
- _read_buf[header + 12], _read_buf[header + 13], _read_buf[header + 14], _read_buf[header + 15], _read_buf[header + 16],
- _read_buf[header + 17],
- _read_buf[header + 18], _read_buf[header + 19], _read_buf[header + 20], _read_buf[header + 21], _read_buf[header + 22],
- _read_buf[header + 23],
- _read_buf[header + 24], _read_buf[header + 25], _read_buf[header + 26], _read_buf[header + 27], _read_buf[header + 28],
- _read_buf[header + 29]
- );
- }
-
- read_retries--;
- flush_uart_rx();
-
- if (_uart_port->uart_write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("Failed to send version info packet");
-
- } else {
- _bytes_sent += cmd.len;
- _packets_sent++;
- px4_usleep(2000);
- }
-
- break;
-
- } else {
- memcpy(&_version_info, &_read_buf[header], sizeof(VOXL2_IO_VERSION_INFO));
- read_succeeded = 1;
+ //break out of the loop waiting for a response
+ if (got_response) {
break;
}
+ }
- } else {
- read_retries--;
- if (_uart_port->uart_write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("Failed to send version info packet");
-
- } else {
- _bytes_sent += cmd.len;
- _packets_sent++;
- px4_usleep(2000);
- }
+ if (!got_response) {
+ PX4_ERR("VOXL2_IO: Board version info response timeout (%d retries left)", retries_left);
}
}
- if (! read_succeeded) {
- return -EIO;
- }
-
- return 0;
+ return (got_response == true ? 0 : -1);
}
bool Voxl2IO::updateOutputs(bool stop_motors, uint16_t outputs[input_rc_s::RC_INPUT_MAX_CHANNELS],
unsigned num_outputs, unsigned num_control_groups_updated)
{
- /* Stop Mixer while ESCs are being calibrated */
+ // Stop Mixer while ESCs are being calibrated
if (_outputs_disabled) {
return 0;
}
+ //PX4_INFO("VOXL2_IO: Mixer output: %u, %u, %u, %u", outputs[0], outputs[1], outputs[2], outputs[3]);
+
//in Run() we call _mixing_output.update(), which calls MixingOutput::limitAndUpdateOutputs which calls _interface.updateOutputs (this function)
//So, if Run() is blocked by a custom command, this function will not be called until Run is running again
- int16_t _rate_req[VOXL2_IO_OUTPUT_CHANNELS] = {0, 0, 0, 0};
- uint8_t _led_req[VOXL2_IO_OUTPUT_CHANNELS] = {0, 0, 0, 0};
- int32_t _fb_idx = -1;
+ uint32_t output_cmds[VOXL2_IO_OUTPUT_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
if (num_outputs != VOXL2_IO_OUTPUT_CHANNELS) {
- PX4_ERR("Num outputs != VOXL2_IO_OUTPUT_CHANNELS!");
+ PX4_ERR("VOXL2_IO: Num outputs != VOXL2_IO_OUTPUT_CHANNELS!");
return false;
}
@@ -333,43 +305,20 @@ bool Voxl2IO::updateOutputs(bool stop_motors, uint16_t outputs[input_rc_s::RC_IN
_pwm_on = true;
}
- if (!_pwm_on || stop_motors) {
- _rate_req[i] = 0;
+ //Do we even need this condition? mixer should handle stopping motors anyway by sending the disable command, right?
+ if (0) { //(!_pwm_on || stop_motors) {
+ output_cmds[i] = _parameters.pwm_dis * MIXER_OUTPUT_TO_CMD_SCALE; //0; //convert to ns
} else {
- _rate_req[i] = outputs[i];
+ output_cmds[i] = ((uint32_t)outputs[i]) * MIXER_OUTPUT_TO_CMD_SCALE; //convert to ns
}
-
- _pwm_values[i] = _rate_req[i];
}
Command cmd;
- cmd.len = voxl2_io_create_pwm_packet4_fb(_rate_req[0], _rate_req[1], _rate_req[2], _rate_req[3],
- _led_req[0], _led_req[1], _led_req[2], _led_req[3],
- _fb_idx, cmd.buf, sizeof(cmd.buf));
+ cmd.len = voxl2_io_create_hires_pwm_packet(output_cmds, VOXL2_IO_OUTPUT_CHANNELS, cmd.buf, sizeof(cmd.buf));
- if (_pwm_on && _debug) {
- PX4_INFO("Mixer outputs");
- PX4_INFO("[%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u]",
- outputs[0], outputs[1], outputs[2], outputs[3], outputs[4], outputs[5],
- outputs[6], outputs[7], outputs[8], outputs[9], outputs[10], outputs[11],
- outputs[12], outputs[13], outputs[14], outputs[15], outputs[16], outputs[17]
- );
-
- // Debug messages for PWM 400Hz values sent to M0065
- uint16_t tics_1 = (_parameters.pwm_min + (_pwm_fullscale * ((double)outputs[0] / VOXL2_IO_MIXER_MAX))) * VOXL2_IO_TICS;
- PX4_INFO("\tPWM CH1: %hu::%uus::%u tics", outputs[0], tics_1 / 24, tics_1);
- uint16_t tics_2 = (_parameters.pwm_min + (_pwm_fullscale * ((double)outputs[1] / VOXL2_IO_MIXER_MAX))) * VOXL2_IO_TICS;
- PX4_INFO("\tPWM CH2: %u::%uus::%u tics", outputs[1], tics_2 / 24, tics_2);
- uint16_t tics_3 = (_parameters.pwm_min + (_pwm_fullscale * ((double)outputs[2] / VOXL2_IO_MIXER_MAX))) * VOXL2_IO_TICS;
- PX4_INFO("\tPWM CH3: %u::%uus::%u tics", outputs[2], tics_3 / 24, tics_3);
- uint16_t tics_4 = (_parameters.pwm_min + (_pwm_fullscale * ((double)outputs[3] / VOXL2_IO_MIXER_MAX))) * VOXL2_IO_TICS;
- PX4_INFO("\tPWM CH4: %u::%uus::%u tics", outputs[3], tics_4 / 24, tics_4);
- PX4_INFO("");
- }
-
- if (_uart_port->uart_write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("Failed to send packet");
+ if (_uart_port.write(cmd.buf, cmd.len) != cmd.len) {
+ PX4_ERR("VOXL2_IO: Failed to send packet");
return false;
} else {
@@ -377,40 +326,39 @@ bool Voxl2IO::updateOutputs(bool stop_motors, uint16_t outputs[input_rc_s::RC_IN
_packets_sent++;
}
+ //if (_pwm_on && _debug){
+ if (_debug) {
+ PX4_INFO("VOXL2_IO: Mixer outputs: [%u, %u, %u, %u, %u, %u, %u, %u]",
+ outputs[0], outputs[1], outputs[2], outputs[3],
+ outputs[4], outputs[5], outputs[6], outputs[7]);
+ }
+
perf_count(_output_update_perf);
return true;
}
-int Voxl2IO::flush_uart_rx()
-{
- while (_uart_port->uart_read(_read_buf, sizeof(_read_buf)) > 0) {}
-
- return 0;
-}
-
static bool valid_port(int port)
{
- if (port == 2 || port == 6 || port == 7) { return true; }
+ if (port == 2 || port == 6 || port == 7) {
+ return true;
+ }
return false;
}
+/*
int Voxl2IO::parse_response(uint8_t *buf, uint8_t len)
{
for (int i = 0; i < len; i++) {
- int16_t ret = voxl2_io_packet_process_char(buf[i], &_sbus_packet);
+ int16_t ret = voxl2_io_packet_process_char(buf[i], &_voxl2_io_packet);
if (ret > 0) {
- uint8_t packet_type = voxl2_io_packet_get_type(&_sbus_packet);
- uint8_t packet_size = voxl2_io_packet_get_size(&_sbus_packet);
+ uint8_t packet_type = voxl2_io_packet_get_type(&_voxl2_io_packet);
+ uint8_t packet_size = voxl2_io_packet_get_size(&_voxl2_io_packet);
if (packet_type == VOXL2_IO_PACKET_TYPE_RC_DATA_RAW && packet_size == VOXL2_IO_SBUS_FRAME_SIZE) {
return 0;
-
- } else if (packet_type == VOXL2_IO_PACKET_TYPE_VERSION_RESPONSE && packet_size == sizeof(VOXL2_IO_VERSION_INFO)) {
- return 0;
-
} else {
return -1;
}
@@ -418,36 +366,31 @@ int Voxl2IO::parse_response(uint8_t *buf, uint8_t len)
} else { //parser error
switch (ret) {
case VOXL2_IO_ERROR_BAD_CHECKSUM:
- if (_pwm_on && _debug) { PX4_WARN("BAD packet checksum"); }
-
+ if(_pwm_on && _debug) PX4_WARN("VOXL2_IO: BAD packet checksum");
break;
case VOXL2_IO_ERROR_BAD_LENGTH:
- if (_pwm_on && _debug) { PX4_WARN("BAD packet length"); }
-
+ if(_pwm_on && _debug) PX4_WARN("VOXL2_IO: BAD packet length");
break;
case VOXL2_IO_ERROR_BAD_HEADER:
- if (_pwm_on && _debug) { PX4_WARN("BAD packet header"); }
-
+ if(_pwm_on && _debug) PX4_WARN("VOXL2_IO: BAD packet header");
break;
case VOXL2_IO_NO_PACKET:
- // if(_pwm_on) PX4_WARN("NO packet");
+ // if(_pwm_on) PX4_WARN("VOXL2_IO: NO packet");
break;
default:
- if (_pwm_on && _debug) { PX4_WARN("Unknown error: %i", ret); }
-
+ if(_pwm_on && _debug) PX4_WARN("VOXL2_IO: Unknown error: %i", ret);
break;
}
-
- return ret;
}
}
return 0;
}
+*/
void Voxl2IO::fill_rc_in(uint16_t raw_rc_count_local,
uint16_t raw_rc_values_local[input_rc_s::RC_INPUT_MAX_CHANNELS],
@@ -455,6 +398,8 @@ void Voxl2IO::fill_rc_in(uint16_t raw_rc_count_local,
unsigned frame_drops, int rssi, input_rc_s &input_rc)
{
// fill rc_in struct for publishing
+ memset(&input_rc, 0, sizeof(input_rc)); //zero out the struct first
+
input_rc.channel_count = raw_rc_count_local;
if (input_rc.channel_count > input_rc_s::RC_INPUT_MAX_CHANNELS) {
@@ -474,9 +419,9 @@ void Voxl2IO::fill_rc_in(uint16_t raw_rc_count_local,
_raw_rc_values[i] = UINT16_MAX;
}
- input_rc.timestamp = now;
+ input_rc.timestamp = now;
input_rc.timestamp_last_signal = input_rc.timestamp;
- input_rc.rc_ppm_frame_length = 0;
+ input_rc.rc_ppm_frame_length = 0;
/* fake rssi if no value was provided */
if (rssi == -1) {
@@ -494,131 +439,98 @@ void Voxl2IO::fill_rc_in(uint16_t raw_rc_count_local,
_sbus_frame_drops++;
}
- input_rc.rc_failsafe = failsafe;
- input_rc.rc_lost = input_rc.rc_failsafe;
- input_rc.rc_lost_frame_count = _sbus_frame_drops;
+ input_rc.rssi_dbm = 0.0f;
+ input_rc.rc_failsafe = failsafe;
+ input_rc.rc_lost = input_rc.rc_failsafe;
+ input_rc.rc_lost_frame_count = _sbus_frame_drops;
input_rc.rc_total_frame_count = ++_sbus_total_frames;
}
-int Voxl2IO::receive_sbus()
+
+int Voxl2IO::parse_sbus_packet(uint8_t *raw_data, uint32_t data_len)
{
- int res = 0;
- int header = -1;
- int read_retries = 3;
- int read_succeeded = 0;
- voxl2_io_packet_init(&_sbus_packet);
+ input_rc_s input_rc;
+ uint16_t num_values;
+ bool sbus_failsafe = false;
+ bool sbus_frame_drop = false;
+ uint16_t max_channels = sizeof(_raw_rc_values) / sizeof(_raw_rc_values[0]);
+ hrt_abstime t_now = hrt_absolute_time();
- while (read_retries) {
- memset(&_read_buf, 0x00, READ_BUF_SIZE);
- res = _uart_port->uart_read(_read_buf, READ_BUF_SIZE);
- if (res) {
- /* Get index of packer header */
- for (int index = 0; index < READ_BUF_SIZE; ++index) {
- if (_read_buf[index] == VOXL2_IO_PACKET_HEADER) {
- header = index;
- break;
- }
- }
+ bool rc_updated = sbus_parse(t_now, raw_data, data_len, _raw_rc_values, &num_values,
+ &sbus_failsafe, &sbus_frame_drop, &_sbus_frame_drops, max_channels);
- /* Try again in a bit if packet header not present yet... */
- if (header == -1) {
- if (_debug) { PX4_ERR("Failed to find SBUS packet header, trying again... retries left: %i", read_retries); }
+ if (rc_updated) {
+ //if (_pwm_on && _debug){
+ if (_debug) {
+ //PX4_INFO("VOXL2_IO: Decoded packet, header pos: %i", header);
+ PX4_INFO("VOXL2_IO: [%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u]",
+ _raw_rc_values[0], _raw_rc_values[1], _raw_rc_values[2],
+ _raw_rc_values[3], _raw_rc_values[4], _raw_rc_values[5],
+ _raw_rc_values[6], _raw_rc_values[7], _raw_rc_values[8],
+ _raw_rc_values[9], _raw_rc_values[10], _raw_rc_values[11],
+ _raw_rc_values[12], _raw_rc_values[13], _raw_rc_values[14],
+ _raw_rc_values[15], _raw_rc_values[16], _raw_rc_values[17]
+ );
- read_retries--;
- continue;
- }
-
- /* Check if we got a valid packet...*/
- if (parse_response(&_read_buf[header], (uint8_t)VOXL2_IO_SBUS_FRAME_SIZE)) {
- if (_pwm_on && _debug) {
- PX4_ERR("Error parsing QC RAW SBUS packet");
- PX4_INFO_RAW("[%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x]\n",
- _read_buf[header + 0], _read_buf[header + 1], _read_buf[header + 2], _read_buf[header + 3], _read_buf[header + 4],
- _read_buf[header + 5],
- _read_buf[header + 6], _read_buf[header + 7], _read_buf[header + 8], _read_buf[header + 9], _read_buf[header + 10],
- _read_buf[header + 11],
- _read_buf[header + 12], _read_buf[header + 13], _read_buf[header + 14], _read_buf[header + 15], _read_buf[header + 16],
- _read_buf[header + 17],
- _read_buf[header + 18], _read_buf[header + 19], _read_buf[header + 20], _read_buf[header + 21], _read_buf[header + 22],
- _read_buf[header + 23],
- _read_buf[header + 24], _read_buf[header + 25], _read_buf[header + 26], _read_buf[header + 27], _read_buf[header + 28],
- _read_buf[header + 29]
- );
- }
-
- read_retries--;
- break;
- }
-
- input_rc_s input_rc;
- uint16_t num_values;
- bool sbus_failsafe = false;
- bool sbus_frame_drop = false;
- uint16_t max_channels = sizeof(_raw_rc_values) / sizeof(_raw_rc_values[0]);
- hrt_abstime now = hrt_absolute_time();
- bool rc_updated = sbus_parse(now, &_read_buf[header + SBUS_PAYLOAD], SBUS_FRAME_SIZE, _raw_rc_values, &num_values,
- &sbus_failsafe, &sbus_frame_drop, &_sbus_frame_drops, max_channels);
-
- if (rc_updated) {
- if (_pwm_on && _debug) {
- PX4_INFO("Decoded packet, header pos: %i", header);
- PX4_INFO("[%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u]",
- _raw_rc_values[0], _raw_rc_values[1], _raw_rc_values[2],
- _raw_rc_values[3], _raw_rc_values[4], _raw_rc_values[5],
- _raw_rc_values[6], _raw_rc_values[7], _raw_rc_values[8],
- _raw_rc_values[9], _raw_rc_values[10], _raw_rc_values[11],
- _raw_rc_values[12], _raw_rc_values[13], _raw_rc_values[14],
- _raw_rc_values[15], _raw_rc_values[16], _raw_rc_values[17]
- );
- }
-
- input_rc.input_source = input_rc_s::RC_INPUT_SOURCE_PX4IO_SBUS;
- fill_rc_in(num_values, _raw_rc_values, now, sbus_frame_drop, sbus_failsafe, _sbus_frame_drops, -1, input_rc);
-
- if (!input_rc.rc_lost && !input_rc.rc_failsafe) {
- _rc_last_valid = input_rc.timestamp;
- }
-
- input_rc.timestamp_last_signal = _rc_last_valid;
- _rc_pub.publish(input_rc);
-
- _bytes_received += res;
- _packets_received++;
- read_succeeded = 1;
- break;
-
- } else if (_pwm_on && _debug) {
- PX4_ERR("Failed to decode SBUS packet, header pos: %i", header);
-
- if (sbus_frame_drop) {
- PX4_WARN("SBUS frame dropped");
- }
-
- PX4_ERR("[%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x]",
- _read_buf[header + 0], _read_buf[header + 1], _read_buf[header + 2], _read_buf[header + 3], _read_buf[header + 4],
- _read_buf[header + 5],
- _read_buf[header + 6], _read_buf[header + 7], _read_buf[header + 8], _read_buf[header + 9], _read_buf[header + 10],
- _read_buf[header + 11],
- _read_buf[header + 12], _read_buf[header + 13], _read_buf[header + 14], _read_buf[header + 15], _read_buf[header + 16],
- _read_buf[header + 17],
- _read_buf[header + 18], _read_buf[header + 19], _read_buf[header + 20], _read_buf[header + 21], _read_buf[header + 22],
- _read_buf[header + 23],
- _read_buf[header + 24], _read_buf[header + 25], _read_buf[header + 26], _read_buf[header + 27], _read_buf[header + 28],
- _read_buf[header + 29]
- );
+ if (sbus_frame_drop) {
+ PX4_WARN("VOXL2_IO: SBUS frame dropped");
}
}
- read_retries--;
+ input_rc.input_source = input_rc_s::RC_INPUT_SOURCE_PX4IO_SBUS;
+ fill_rc_in(num_values, _raw_rc_values, t_now, sbus_frame_drop, sbus_failsafe, _sbus_frame_drops, -1, input_rc);
+
+ if (!input_rc.rc_lost && !input_rc.rc_failsafe) {
+ _rc_last_valid_time = input_rc.timestamp;
+ }
+
+ input_rc.timestamp_last_signal = _rc_last_valid_time;
+ _rc_pub.publish(input_rc);
+
+ if (_rc_mode == RC_MODE::SCAN) {
+ PX4_INFO("VOXL2_IO: Detected VOXL2 IO SBUS RC");
+ _rc_mode = RC_MODE::SBUS;
+ }
}
- if (! read_succeeded) {
- _new_packet = false;
- return -EIO;
+ return 0;
+}
+
+
+int Voxl2IO::receive_uart_packets()
+{
+ int nread = _uart_port.read(_read_buf, READ_BUF_SIZE);
+
+ if (nread > 0) {
+ if (_debug) {
+ PX4_INFO("VOXL2_IO: receive_uart_packets read %d bytes", nread);
+ }
+
+ _bytes_received += nread;
+
+ for (int i = 0; i < nread; i++) {
+ int16_t parse_ret = voxl2_io_packet_process_char(_read_buf[i], &_voxl2_io_packet);
+
+ if (parse_ret > 0) {
+ _packets_received++;
+
+ uint8_t packet_type = voxl2_io_packet_get_type(&_voxl2_io_packet);
+ uint8_t packet_size = voxl2_io_packet_get_size(&_voxl2_io_packet);
+
+ if (packet_type == VOXL2_IO_PACKET_TYPE_RC_DATA_RAW && packet_size == VOXL2_IO_SBUS_FRAME_SIZE) {
+
+ //parse SBUS packet only if configured to do so
+ if ((_rc_mode == RC_MODE::SCAN) || (_rc_mode == RC_MODE::SBUS)) {
+ parse_sbus_packet(&_voxl2_io_packet.buffer[SBUS_PAYLOAD], SBUS_FRAME_SIZE);
+ }
+ }
+
+ //parse other packets (future use)
+ }
+ }
}
- _new_packet = true;
return 0;
}
@@ -635,26 +547,14 @@ void Voxl2IO::Run()
perf_begin(_cycle_perf);
- /* Handle RC */
- if (_rc_mode == RC_MODE::SCAN) {
- if (receive_sbus() == PX4_OK) {
- PX4_INFO("Found M0065 SBUS RC.");
- _rc_mode = RC_MODE::SBUS;
- } // Add more cases here for other protocols in the future..
-
- } else if (_rc_mode == RC_MODE::SBUS) {
- receive_sbus();
- }
-
- /* Only update outputs if we have new values from RC */
- if (_new_packet || _rc_mode == RC_MODE::EXTERNAL) {
- _mixing_output.update(); //calls MixingOutput::limitAndUpdateOutputs which calls updateOutputs in this module
- _new_packet = false;
- }
+ _mixing_output.update(); //calls MixingOutput::limitAndUpdateOutputs which calls updateOutputs in this module
/* update PWM status if armed or if disarmed PWM values are set */
_pwm_on = _mixing_output.armed().armed;
+ //receive packets from voxl_io board
+ receive_uart_packets();
+
/* check for parameter updates */
if (!_pwm_on && _parameter_update_sub.updated()) {
/* clear update */
@@ -665,48 +565,6 @@ void Voxl2IO::Run()
update_params();
}
- /* Don't process commands if pwm on */
- if (!_pwm_on) {
- if (_current_cmd.valid()) {
- PX4_INFO("sending %d commands with delay %dus", _current_cmd.repeats, _current_cmd.repeat_delay_us);
- flush_uart_rx();
-
- do {
- PX4_INFO("CMDs left %d", _current_cmd.repeats);
-
- if (_uart_port->uart_write(_current_cmd.buf, _current_cmd.len) == _current_cmd.len) {
- if (_current_cmd.repeats == 0) {
- _current_cmd.clear();
- }
-
-
- } else {
- _bytes_sent += _current_cmd.len;
- _packets_sent++;
-
- if (_current_cmd.retries == 0) {
- _current_cmd.clear();
- PX4_ERR("Failed to send command, errno: %i", errno);
-
- } else {
- _current_cmd.retries--;
- PX4_ERR("Failed to send command, errno: %i", errno);
- }
- }
-
- px4_usleep(_current_cmd.repeat_delay_us);
- } while (_current_cmd.repeats-- > 0);
-
- } else {
- Command *new_cmd = _pending_cmd.load();
-
- if (new_cmd) {
- _current_cmd = *new_cmd;
- _pending_cmd.store(nullptr);
- }
- }
- }
-
/* check at end of cycle (updateSubscriptions() can potentially change to a different WorkQueue thread) */
_mixing_output.updateSubscriptions(true);
perf_end(_cycle_perf);
@@ -728,17 +586,17 @@ int Voxl2IO::task_spawn(int argc, char *argv[])
while ((ch = px4_getopt(argc - 1, argv, "vdep:", &myoptind, &myoptarg)) != EOF) {
switch (ch) {
case 'v':
- PX4_INFO("Verbose mode enabled");
+ PX4_INFO("VOXL2_IO: Verbose mode enabled");
get_instance()->_debug = true;
break;
case 'd':
- PX4_INFO("M0065 PWM outputs disabled");
+ PX4_INFO("VOXL2_IO: M0065 PWM outputs disabled");
get_instance()->_outputs_disabled = true;
break;
case 'e':
- PX4_INFO("M0065 using external RC");
+ PX4_INFO("VOXL2_IO: M0065 using external RC");
get_instance()->_rc_mode = RC_MODE::EXTERNAL;
break;
@@ -747,7 +605,7 @@ int Voxl2IO::task_spawn(int argc, char *argv[])
snprintf(get_instance()->_device, 2, "%s", myoptarg);
} else {
- PX4_ERR("Bad UART port number: %s (must be 2, 6, or 7).", myoptarg);
+ PX4_ERR("VOXL2_IO: Bad UART port number: %s (must be 2, 6, or 7).", myoptarg);
_object.store(nullptr);
_task_id = -1;
return PX4_ERROR;
@@ -756,7 +614,7 @@ int Voxl2IO::task_spawn(int argc, char *argv[])
break;
default:
- print_usage("Unknown command, parsing flags");
+ print_usage("VOXL2_IO: Unknown command, parsing flags");
break;
}
}
@@ -766,7 +624,7 @@ int Voxl2IO::task_spawn(int argc, char *argv[])
}
} else {
- PX4_ERR("alloc failed");
+ PX4_ERR("VOXL2_IO: alloc failed");
}
_object.store(nullptr);
@@ -776,280 +634,131 @@ int Voxl2IO::task_spawn(int argc, char *argv[])
}
-bool Voxl2IO::stop_all_pwms()
-{
- int16_t _rate_req[VOXL2_IO_OUTPUT_CHANNELS] = {0, 0, 0, 0};
- int16_t _led_req[VOXL2_IO_OUTPUT_CHANNELS] = {0, 0, 0, 0};
- uint8_t _fb_idx = 0;
-
- Command cmd;
- cmd.len = voxl2_io_create_pwm_packet4_fb(_rate_req[0], _rate_req[1], _rate_req[2], _rate_req[3],
- _led_req[0], _led_req[1], _led_req[2], _led_req[3],
- _fb_idx, cmd.buf, sizeof(cmd.buf));
-
- if (_uart_port->uart_write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("Failed to send packet");
- return false;
-
- } else {
- _bytes_sent += cmd.len;
- _packets_sent++;
- }
-
- return true;
-}
-
-int Voxl2IO::send_cmd_thread_safe(Command *cmd)
-{
- cmd->id = _cmd_id++;
- _pending_cmd.store(cmd);
-
- /* wait until main thread processed it */
- while (_pending_cmd.load()) {
- px4_usleep(1000);
- }
-
- return 0;
-}
-
int Voxl2IO::calibrate_escs()
{
- /* Disable outputs so Mixer isn't being a PITA while we calibrate */
+ // Disable outputs so Mixer isn't being a PITA while we calibrate
_outputs_disabled = true;
Command cmd;
- int32_t fb_idx = -1;
- uint8_t data[VOXL2_IO_ESC_CAL_SIZE] {0};
- cmd.len = voxl2_io_create_packet(VOXL2_IO_PACKET_TYPE_TUNE_CONFIG, data, VOXL2_IO_ESC_CAL_SIZE, cmd.buf,
- sizeof(cmd.buf));
- if (_uart_port->uart_write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("ESC Calibration failed: Failed to send PWM OFF packet");
- _outputs_disabled = false;
- return -1;
+ PX4_INFO("VOXL2_IO: PWM ESC calibration is starting!");
+
+ // Give user 10 seconds to plug in PWM cable for ESCs
+ PX4_INFO("VOXL2_IO: MIN PWM used for ESC Calibration : %" PRId32, _parameters.pwm_cal_min);
+ PX4_INFO("VOXL2_IO: MAX PWM used for ESC Calibration : %" PRId32, _parameters.pwm_cal_max);
+ PX4_INFO("VOXL2_IO:");
+ PX4_INFO("VOXL2_IO: Connect your ESCs! (Calibration will start in ~10 seconds)");
+
+ px4_usleep(10000000);
+
+ uint32_t max_pwm_cmds[VOXL2_IO_OUTPUT_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
+ uint32_t min_pwm_cmds[VOXL2_IO_OUTPUT_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+ for (int idx = 0; idx < VOXL2_IO_OUTPUT_CHANNELS; idx++) {
+ //only send out calibration pulse if the actuator is a motor
+ if ((_parameters.function_map[idx] >= 101) && (_parameters.function_map[idx] <= 112)) {
+ max_pwm_cmds[idx] = _parameters.pwm_cal_max * MIXER_OUTPUT_TO_CMD_SCALE;
+ min_pwm_cmds[idx] = _parameters.pwm_cal_min * MIXER_OUTPUT_TO_CMD_SCALE;
+ }
}
- /* Give user 10 seconds to plug in PWM cable for ESCs */
- PX4_INFO("Disconnected and reconnect your ESCs! (Calibration will start in ~10 seconds)");
- hrt_abstime start_cal = hrt_absolute_time();
-
- while (hrt_elapsed_time(&start_cal) < 10000000) {
- continue;
+ if (_debug) {
+ PX4_INFO("VOXL2_IO: Scaled max pwms: %u %u %u %u %u %u %u %u",
+ max_pwm_cmds[0], max_pwm_cmds[1], max_pwm_cmds[2], max_pwm_cmds[3],
+ max_pwm_cmds[4], max_pwm_cmds[5], max_pwm_cmds[6], max_pwm_cmds[7]);
}
- /* PWM MAX 3 seconds */
- PX4_INFO("Writing PWM MAX for 3 seconds!");
- int16_t max_pwm[4] {VOXL2_IO_MIXER_MAX, VOXL2_IO_MIXER_MAX, VOXL2_IO_MIXER_MAX, VOXL2_IO_MIXER_MAX};
+ hrt_abstime start;
- if (_debug) { PX4_INFO("%i %i %i %i", max_pwm[0], max_pwm[1], max_pwm[2], max_pwm[3]); }
+ // Send PWM max every 2.5ms for 5 seconds
+ PX4_INFO("VOXL2_IO: Sending PWM MAX (%dus) for 5 seconds!", _parameters.pwm_cal_max);
+ cmd.len = voxl2_io_create_hires_pwm_packet(max_pwm_cmds, VOXL2_IO_OUTPUT_CHANNELS, cmd.buf, sizeof(cmd.buf));
+ start = hrt_absolute_time();
- int16_t led_cmd[4] {0, 0, 0, 0};
- cmd.len = voxl2_io_create_pwm_packet4_fb(max_pwm[0], max_pwm[1], max_pwm[2], max_pwm[3],
- led_cmd[0], led_cmd[1], led_cmd[2], led_cmd[3],
- fb_idx, cmd.buf, sizeof(cmd.buf));
+ while (hrt_elapsed_time(&start) < 5000000) {
+ if (_uart_port.write(cmd.buf, cmd.len) != cmd.len) {
+ PX4_ERR("VOXL2_IO: ESC Calibration failed: Failed to send PWM MAX packet");
+ _outputs_disabled = false;
+ return -1;
+ }
- if (_uart_port->uart_write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("ESC Calibration failed: Failed to send PWM MAX packet");
- _outputs_disabled = false;
- return -1;
-
- } else {
- cmd.clear();
+ px4_usleep(2500);
}
- hrt_abstime start_pwm_max = hrt_absolute_time();
+ // Send PWM min every 2.5ms for 5 seconds
+ PX4_INFO("VOXL2_IO: Sending PWM MIN (%dus) for 5 seconds!", _parameters.pwm_cal_min);
- while (hrt_elapsed_time(&start_pwm_max) < 3000000) {
- continue;
+ if (_debug) {
+ PX4_INFO("VOXL2_IO: Scaled min pwms: %u %u %u %u %u %u %u %u",
+ min_pwm_cmds[0], min_pwm_cmds[1], min_pwm_cmds[2], min_pwm_cmds[3],
+ min_pwm_cmds[4], min_pwm_cmds[5], min_pwm_cmds[6], min_pwm_cmds[7]);
}
- /* PWM MIN 4 seconds */
- PX4_INFO("Writing PWM MIN for 4 seconds!");
- int16_t min_pwm[4] {VOXL2_IO_MIXER_MIN, VOXL2_IO_MIXER_MIN, VOXL2_IO_MIXER_MIN, VOXL2_IO_MIXER_MIN};
+ cmd.len = voxl2_io_create_hires_pwm_packet(min_pwm_cmds, VOXL2_IO_OUTPUT_CHANNELS, cmd.buf, sizeof(cmd.buf));
- if (_debug) { PX4_INFO("%i %i %i %i", min_pwm[0], min_pwm[1], min_pwm[2], min_pwm[3]); }
- cmd.len = voxl2_io_create_pwm_packet4_fb(min_pwm[0], min_pwm[1], min_pwm[2], min_pwm[3],
- led_cmd[0], led_cmd[1], led_cmd[2], led_cmd[3],
- fb_idx, cmd.buf, sizeof(cmd.buf));
+ start = hrt_absolute_time();
- if (_uart_port->uart_write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("ESC Calibration failed: Failed to send PWM MIN packet");
- _outputs_disabled = false;
- return -1;
+ while (hrt_elapsed_time(&start) < 5000000) {
+ if (_uart_port.write(cmd.buf, cmd.len) != cmd.len) {
+ PX4_ERR("VOXL2_IO: ESC Calibration failed: Failed to send PWM MIN packet");
+ _outputs_disabled = false;
+ return -1;
+ }
+
+ px4_usleep(2500);
}
- hrt_abstime start_pwm_min = hrt_absolute_time();
-
- while (hrt_elapsed_time(&start_pwm_min) < 4000000) {
- continue;
- }
-
- PX4_INFO("ESC Calibration complete");
+ PX4_INFO("VOXL2_IO: Waiting 5 seconds to finish the calibration (no PWM output)");
+ px4_usleep(5000000);
+ PX4_INFO("VOXL2_IO: ESC Calibration complete");
_outputs_disabled = false;
return 0;
}
int Voxl2IO::custom_command(int argc, char *argv[])
{
- int myoptind = 0;
- int ch;
- const char *myoptarg = nullptr;
-
- Command cmd;
- uint8_t output_channel = 0xF;
- int16_t rate = 0;
-
- uint32_t repeat_count = 100;
- uint32_t repeat_delay_us = 10000;
-
const char *verb = argv[argc - 1];
- if ((strcmp(verb, "pwm")) == 0 && argc < 3) {
- return print_usage("pwm command: missing args");
-
- } else if (argc < 1) {
+ if (argc < 1) {
return print_usage("unknown command: missing args");
}
- PX4_INFO("Executing the following command: %s", verb);
+ PX4_INFO("VOXL2_IO: Executing the following command: %s", verb);
- /* start the FMU if not running */
+ /* start if not running */
if (!strcmp(verb, "start")) {
if (!is_running()) {
return Voxl2IO::task_spawn(argc, argv);
}
- }
- if (!strcmp(verb, "status")) {
- if (!is_running()) {
- PX4_INFO("Not running");
- return -1;
- }
-
- return get_instance()->print_status();
+ PX4_INFO("VOXL2_IO: Already running");
+ return 0;
}
if (!is_running()) {
- PX4_INFO("Not running");
+ PX4_INFO("VOXL2_IO: Not running");
return -1;
}
+ if (!strcmp(verb, "status")) {
+ return get_instance()->print_status();
+ }
+
+
if (!strcmp(verb, "calibrate_escs")) {
if (get_instance()->_outputs_disabled) {
- PX4_WARN("Can't calibrate ESCs while outputs are disabled.");
+ PX4_WARN("VOXL2_IO: Can't calibrate ESCs while outputs are disabled.");
return -1;
}
return get_instance()->calibrate_escs();
}
- while ((ch = px4_getopt(argc, argv, "c:n:t:r:p:", &myoptind, &myoptarg)) != EOF) {
- switch (ch) {
- case 'c':
- output_channel = atoi(myoptarg);
-
- if (output_channel > VOXL2_IO_OUTPUT_CHANNELS - 1) {
- char reason[50];
- sprintf(reason, "Bad channel value: %d. Must be 0-%d.", output_channel, VOXL2_IO_OUTPUT_CHANNELS - 1);
- print_usage(reason);
- return 0;
- }
-
- break;
-
- case 'n':
- repeat_count = atoi(myoptarg);
-
- if (repeat_count < 1) {
- print_usage("bad repeat_count");
- return 0;
- }
-
- break;
-
- case 't':
- repeat_delay_us = atoi(myoptarg);
-
- if (repeat_delay_us < 1) {
- print_usage("bad repeat delay");
- return 0;
- }
-
- break;
-
- case 'r':
- rate = atoi(myoptarg);
- break;
-
- case 'p':
- if (valid_port(atoi(myoptarg))) {
- snprintf(get_instance()->_device, 2, "%s", myoptarg);
-
- } else {
- PX4_ERR("Bad UART port number: %s (must be 2, 6, or 7).", myoptarg);
- return 0;
- }
-
- break;
-
- default:
- print_usage("Unknown command, parsing flags");
- return 0;
- }
- }
-
- if (!strcmp(verb, "pwm")) {
- PX4_INFO("Output channel: %i", output_channel);
- PX4_INFO("Repeat count: %i", repeat_count);
- PX4_INFO("Repeat delay (us): %i", repeat_delay_us);
- PX4_INFO("Rate: %i", rate);
-
- if (output_channel < VOXL2_IO_OUTPUT_CHANNELS) {
- PX4_INFO("Request PWM for Output Channel: %i - PWM: %i", output_channel, rate);
- int16_t rate_req[VOXL2_IO_OUTPUT_CHANNELS] = {0, 0, 0, 0};
- uint8_t id_fb = 0;
-
- if (output_channel ==
- 0xFF) { //WARNING: this condition is not possible due to check 'if (esc_id < MODAL_IO_OUTPUT_CHANNELS)'.
- rate_req[0] = rate;
- rate_req[1] = rate;
- rate_req[2] = rate;
- rate_req[3] = rate;
-
- } else {
- rate_req[output_channel] = rate;
- id_fb = output_channel;
- }
-
- cmd.len = voxl2_io_create_pwm_packet4_fb(rate_req[0], rate_req[1], rate_req[2], rate_req[3],
- 0, 0, 0, 0,
- id_fb, cmd.buf, sizeof(cmd.buf));
-
- cmd.response = false;
- cmd.repeats = repeat_count;
- cmd.resp_delay_us = 1000;
- cmd.repeat_delay_us = repeat_delay_us;
- cmd.print_feedback = false;
-
- PX4_INFO("feedback id debug: %i", id_fb);
- PX4_INFO("Sending UART M0065 power command %i", rate);
-
- if (get_instance()->_uart_port->uart_write(cmd.buf, cmd.len) != cmd.len) {
- PX4_ERR("Failed to send packet: stop PWMs");
- return -1;
-
- } else {
- get_instance()->_bytes_sent += cmd.len;
- get_instance()->_packets_sent++;
- }
-
- } else {
- print_usage("Invalid Output Channel, use 0-3");
- return 0;
- }
+ if (!strcmp(verb, "enable_debug")) {
+ get_instance()->_debug = true;
}
return print_usage("unknown custom command");
@@ -1057,22 +766,20 @@ int Voxl2IO::custom_command(int argc, char *argv[])
int Voxl2IO::print_status()
{
- PX4_INFO("Max update rate: %u Hz", 1000000 / _current_update_interval);
- PX4_INFO("PWM Rate: 400 Hz"); // Only support 400 Hz for now
- PX4_INFO("Outputs on: %s", _pwm_on ? "yes" : "no");
- PX4_INFO("FW version: v%u.%u", _version_info.sw_version, _version_info.hw_version);
- PX4_INFO("RC Type: SBUS"); // Only support SBUS through M0065 for now
- PX4_INFO("RC Connected: %s", hrt_absolute_time() - _rc_last_valid > 500000 ? "no" : "yes");
- PX4_INFO("RC Packets Received: %" PRIu16, _sbus_total_frames);
- PX4_INFO("UART port: %s", _device);
- PX4_INFO("UART open: %s", _uart_port->is_open() ? "yes" : "no");
- PX4_INFO("Packets sent: %" PRIu32, _packets_sent);
- PX4_INFO("");
- PX4_INFO("Params: VOXL2_IO_BAUD: %" PRId32, _parameters.baud_rate);
- PX4_INFO("Params: VOXL2_IO_FUNC1: %" PRId32, _parameters.function_map[0]);
- PX4_INFO("Params: VOXL2_IO_FUNC2: %" PRId32, _parameters.function_map[1]);
- PX4_INFO("Params: VOXL2_IO_FUNC3: %" PRId32, _parameters.function_map[2]);
- PX4_INFO("Params: VOXL2_IO_FUNC4: %" PRId32, _parameters.function_map[3]);
+ //PX4_INFO("VOXL2_IO: Max update rate: %u Hz", 1000000/_current_update_interval);
+ //PX4_INFO("VOXL2_IO: PWM Rate: 400 Hz"); // Only support 400 Hz for now
+ PX4_INFO("VOXL2_IO: Outputs on : %s", _pwm_on ? "yes" : "no");
+ PX4_INFO("VOXL2_IO: SW version : %u", _version_info.sw_version);
+ PX4_INFO("VOXL2_IO: HW version : %u: %s", _version_info.hw_version,
+ board_id_to_name(_version_info.hw_version).c_str());
+ PX4_INFO("VOXL2_IO: RC Type : SBUS"); // Only support SBUS through M0065 for now
+ PX4_INFO("VOXL2_IO: RC Connected : %s", hrt_absolute_time() - _rc_last_valid_time > 500000 ? "no" : "yes");
+ PX4_INFO("VOXL2_IO: RC Packets Rxd : %" PRIu16, _sbus_total_frames);
+ PX4_INFO("VOXL2_IO: UART port : %s", _device);
+ PX4_INFO("VOXL2_IO: UART open : %s", _uart_port.open() ? "yes" : "no");
+ PX4_INFO("VOXL2_IO: Packets sent : %" PRIu32, _packets_sent);
+ PX4_INFO("VOXL2_IO: ");
+ print_params();
perf_print_counter(_cycle_perf);
perf_print_counter(_output_update_perf);
@@ -1103,17 +810,49 @@ px4io driver is used for main ones.
PRINT_MODULE_USAGE_PARAM_FLAG('e', "Disable RC", false);
PRINT_MODULE_USAGE_PARAM_INT('p', 2, 2, 7, "UART port", false);
PRINT_MODULE_USAGE_COMMAND_DESCR("calibrate_escs", "Calibrate ESCs min/max range");
- PRINT_MODULE_USAGE_COMMAND_DESCR("calibrate_escs", "Calibrate ESCs min/max range");
- PRINT_MODULE_USAGE_COMMAND_DESCR("pwm", "Open-Loop PWM test control request");
- PRINT_MODULE_USAGE_PARAM_INT('c', 0, 0, 3, "PWM OUTPUT Channel, 0-3", false);
- PRINT_MODULE_USAGE_PARAM_INT('r', 0, 0, 800, "Duty Cycle value, 0 to 800", false);
- PRINT_MODULE_USAGE_PARAM_INT('n', 100, 0, 1<<31, "Command repeat count, 0 to INT_MAX", false);
- PRINT_MODULE_USAGE_PARAM_INT('t', 10000, 0, 1<<31, "Delay between repeated commands (microseconds), 0 to INT_MAX", false);
+ PRINT_MODULE_USAGE_COMMAND_DESCR("enable_debug", "Enables driver debugging");
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
return 0;
}
+std::string Voxl2IO::board_id_to_name(int board_id)
+{
+ switch(board_id){
+ case 31: return std::string("ModalAi 4-in-1 ESC V2 RevB (M0049)");
+ case 32: return std::string("Blheli32 4-in-1 ESC Type A (Tmotor F55A PRO F051)");
+ case 33: return std::string("Blheli32 4-in-1 ESC Type B (Tmotor F55A PRO G071)");
+ case 34: return std::string("ModalAi 4-in-1 ESC (M0117-1)");
+ case 35: return std::string("ModalAi I/O Expander (M0065)");
+ case 36: return std::string("ModalAi 4-in-1 ESC (M0117-3)");
+ case 37: return std::string("ModalAi 4-in-1 ESC (M0134-1)");
+ case 38: return std::string("ModalAi 4-in-1 ESC (M0134-3)");
+ case 39: return std::string("ModalAi 4-in-1 ESC (M0129-1)");
+ case 40: return std::string("ModalAi 4-in-1 ESC (M0129-3)");
+ case 41: return std::string("ModalAi 4-in-1 ESC (M0134-6)");
+ case 42: return std::string("ModalAi 4-in-1 ESC (M0138-1)");
+ default: return std::string("Unknown Board");
+ }
+}
+
+void Voxl2IO::print_params()
+{
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_BAUD : %" PRId32, _parameters.baud_rate);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_FUNC1 : %" PRId32, _parameters.function_map[0]);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_FUNC2 : %" PRId32, _parameters.function_map[1]);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_FUNC3 : %" PRId32, _parameters.function_map[2]);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_FUNC4 : %" PRId32, _parameters.function_map[3]);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_FUNC5 : %" PRId32, _parameters.function_map[4]);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_FUNC6 : %" PRId32, _parameters.function_map[5]);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_FUNC7 : %" PRId32, _parameters.function_map[6]);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_FUNC8 : %" PRId32, _parameters.function_map[7]);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_DIS : %" PRId32, _parameters.pwm_dis);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_MIN : %" PRId32, _parameters.pwm_min);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_MAX : %" PRId32, _parameters.pwm_max);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_CMIN : %" PRId32, _parameters.pwm_cal_min);
+ PX4_INFO("VOXL2_IO: Params: VOXL2_IO_CMAX : %" PRId32, _parameters.pwm_cal_max);
+}
+
extern "C" __EXPORT int voxl2_io_main(int argc, char *argv[]);
int voxl2_io_main(int argc, char *argv[])
diff --git a/src/drivers/voxl2_io/voxl2_io.hpp b/src/drivers/voxl2_io/voxl2_io.hpp
index 6ac46251bc..b3458456a0 100644
--- a/src/drivers/voxl2_io/voxl2_io.hpp
+++ b/src/drivers/voxl2_io/voxl2_io.hpp
@@ -35,6 +35,7 @@
#include
#include
+#include
#include
@@ -49,16 +50,17 @@
#include
#include
#include
+#include
#include
#include
#include
#include
-#include "voxl2_io_serial.hpp"
-
#include "voxl2_io_packet.h"
#include "voxl2_io_packet_types.h"
+using namespace device;
+
using namespace time_literals;
class Voxl2IO final : public ModuleBase, public OutputModuleInterface
@@ -85,8 +87,8 @@ public:
virtual int init();
- void update_pwm_config();
int get_version_info();
+ void print_params();
struct Command {
uint16_t id = 0;
@@ -105,8 +107,8 @@ public:
void clear() { len = 0; }
};
- int send_cmd_thread_safe(Command *cmd);
- int receive_sbus();
+ int receive_uart_packets();
+ int parse_sbus_packet(uint8_t *raw_data, uint32_t data_len);
void fill_rc_in(uint16_t raw_rc_count_local,
uint16_t raw_rc_values_local[input_rc_s::RC_INPUT_MAX_CHANNELS],
@@ -114,53 +116,42 @@ public:
unsigned frame_drops, int rssi, input_rc_s &input_rc);
private:
void Run() override;
- bool stop_all_pwms();
/* PWM Parameters */
- static constexpr uint32_t VOXL2_IO_CONFIG = 0; // Default to off
- static constexpr uint32_t VOXL2_IO_BOARD_CONFIG_SIZE = 4; // PWM_MIN, PWM_MAX, 4 bytes
- static constexpr uint32_t VOXL2_IO_ESC_CAL_SIZE = 1;
- static constexpr uint32_t VOXL2_IO_DEFAULT_BAUD = 921600;
- static constexpr uint16_t VOXL2_IO_OUTPUT_CHANNELS = 4;
- static constexpr uint16_t VOXL2_IO_OUTPUT_DISABLED = 0;
-
- static constexpr uint32_t VOXL2_IO_WRITE_WAIT_US = 200;
- static constexpr uint32_t VOXL2_IO_DISCONNECT_TIMEOUT_US = 500000;
-
- static constexpr uint16_t DISARMED_VALUE = 0;
-
- static constexpr uint16_t VOXL2_IO_MIXER_MIN = 0;
- static constexpr uint16_t VOXL2_IO_MIXER_MAX = 800;
- static constexpr uint16_t VOXL2_IO_MIXER_FAILSAFE = 0;
- static constexpr uint16_t VOXL2_IO_MIXER_DISARMED = 0;
-
- static constexpr int32_t VOXL2_IO_DEFAULT_MIN = 1000;
- static constexpr int32_t VOXL2_IO_DEFAULT_MAX = 2000;
- static constexpr int32_t VOXL2_IO_DEFAULT_FAILSAFE = 900;
- static constexpr int32_t VOXL2_IO_TICS = 24; // 24 tics per us on M0065 timer clks
+ static constexpr uint32_t VOXL2_IO_DEFAULT_BAUD = 921600;
+ static constexpr uint16_t VOXL2_IO_OUTPUT_CHANNELS = 8;
+ static constexpr uint16_t VOXL2_IO_MIXER_FAILSAFE =
+ UINT16_MAX; //this will tell mixer to use the default failsafe depending on the function
/* SBUS */
static constexpr uint16_t VOXL2_IO_SBUS_FRAME_SIZE = 30;
static constexpr uint16_t SBUS_PAYLOAD = 3;
+ //packet packing function accepts pulse width in nanoseconds
+ //assuming the mixer outputs in microseconds, need to convert
+ static constexpr uint32_t MIXER_OUTPUT_TO_CMD_SCALE = 1000; //standard pwm
+ //static constexpr uint32_t MIXER_OUTPUT_TO_CMD_SCALE = 125; //oneshot125
+
/* M0065 version info */
- static constexpr uint16_t VOXL2_IO_VERSION_INFO_SIZE = 6;
- static constexpr uint16_t VOXL2_IO_SW_PROTOCOL_VERSION = 1;
- static constexpr uint16_t VOXL2_IO_HW_PROTOCOL_VERSION = 35;
- VOXL2_IO_VERSION_INFO _version_info;
+ static constexpr uint16_t VOXL2_IO_SW_VERSION = 2;
+ static constexpr uint16_t VOXL2_IO_HW_VERSION = 35; //this is the version of the HW
+ int _board_detect_retries{3};
+ VOXL2_IO_EXTENDED_VERSION_INFO _version_info;
/* Module update interval */
static constexpr unsigned _current_update_interval{4000}; // 250 Hz
typedef struct {
- int32_t config{VOXL2_IO_CONFIG};
int32_t baud_rate{VOXL2_IO_DEFAULT_BAUD};
- int32_t pwm_min{VOXL2_IO_DEFAULT_MIN};
- int32_t pwm_max{VOXL2_IO_DEFAULT_MAX};
- int32_t pwm_failsafe{VOXL2_IO_DEFAULT_FAILSAFE};
- int32_t param_rc_input_proto{0};
+ int32_t pwm_min{0};
+ int32_t pwm_max{0};
+ int32_t pwm_dis{0};
+ int32_t pwm_cal_min{0};
+ int32_t pwm_cal_max{0};
+ //int32_t pwm_failsafe{VOXL2_IO_DEFAULT_FAILSAFE};
+ //int32_t param_rc_input_proto{0};
int32_t param_rc_rssi_pwm_chan{0};
- int32_t function_map[VOXL2_IO_OUTPUT_CHANNELS] {0, 0, 0, 0};
+ int32_t function_map[VOXL2_IO_OUTPUT_CHANNELS] {0, 0, 0, 0, 0, 0, 0, 0};
int32_t verbose_logging{0};
} voxl2_io_params_t;
voxl2_io_params_t _parameters;
@@ -179,20 +170,18 @@ private:
SCAN
} _rc_mode{RC_MODE::SCAN};
- /* QUP7, VOXL2 J19, /dev/slpi-uart-7*/
char _device[10] {VOXL2_IO_DEFAULT_PORT};
- Voxl2IoSerial *_uart_port;
+ Serial _uart_port{};
/* Mixer output */
MixingOutput _mixing_output;
/* RC input */
- VOXL2_IOPacket _sbus_packet;
- uint64_t _rc_last_valid;
+ VOXL2_IOPacket _voxl2_io_packet;
+ uint64_t _rc_last_valid_time;
uint16_t _raw_rc_values[input_rc_s::RC_INPUT_MAX_CHANNELS] {UINT16_MAX};
- unsigned _sbus_frame_drops{0};
- uint16_t _sbus_total_frames{0};
- bool _new_packet{false};
+ unsigned int _sbus_frame_drops{0};
+ uint32_t _sbus_total_frames{0};
/* Publications */
uORB::PublicationMulti _rc_pub{ORB_ID(input_rc)};
@@ -201,17 +190,12 @@ private:
uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)};
bool _pwm_on{false};
- int32_t _pwm_fullscale{0};
- int16_t _pwm_values[VOXL2_IO_OUTPUT_CHANNELS] = {0, 0, 0, 0};
bool _outputs_disabled{false};
perf_counter_t _cycle_perf;
perf_counter_t _output_update_perf;
bool _debug{false};
- uint16_t _cmd_id{0};
- Command _current_cmd;
- px4::atomic _pending_cmd{nullptr};
static const uint8_t READ_BUF_SIZE = 128;
uint8_t _read_buf[READ_BUF_SIZE];
@@ -220,9 +204,8 @@ private:
uint32_t _packets_sent{0};
uint32_t _packets_received{0};
- int parse_response(uint8_t *buf, uint8_t len);
int load_params(voxl2_io_params_t *params);
int update_params();
- int flush_uart_rx();
int calibrate_escs();
+ std::string board_id_to_name(int board_id);
};
diff --git a/src/drivers/voxl2_io/voxl2_io_packet.c b/src/drivers/voxl2_io/voxl2_io_packet.c
index 3de26acbfe..99340fa974 100644
--- a/src/drivers/voxl2_io/voxl2_io_packet.c
+++ b/src/drivers/voxl2_io/voxl2_io_packet.c
@@ -150,6 +150,32 @@ int32_t voxl2_io_create_rpm_packet4_fb(int16_t rpm0, int16_t rpm1, int16_t rpm2,
return voxl2_io_create_packet(VOXL2_IO_PACKET_TYPE_RPM_CMD, (uint8_t *) & (data[0]), 10, out, out_size);
}
+typedef struct {
+ uint8_t command_type;
+ //uint8_t channel_offset;
+ uint16_t vals[8]; //could be 1,2,4,6,8
+} __attribute__((__packed__)) pwm_hires_cmd_t;
+
+pwm_hires_cmd_t hires_cmd;
+
+int32_t voxl2_io_create_hires_pwm_packet(uint32_t *pwm_val_ns, uint32_t cmd_cnt, uint8_t *out, uint16_t out_size)
+{
+ if (cmd_cnt > 8) {
+ return -1;
+ }
+
+ hires_cmd.command_type = 0;
+ //hires_cmd.channel_offset = 0;
+
+ //resolution of commands in the packet is 0.05us = 50ns
+ for (uint32_t idx = 0; idx < cmd_cnt; idx++) {
+ hires_cmd.vals[idx] = pwm_val_ns[idx] / 50;
+ }
+
+ return voxl2_io_create_packet(VOXL2_IO_PACKET_TYPE_PWM_HIRES_CMD, (uint8_t *) &hires_cmd, (cmd_cnt * 2 + 1), out,
+ out_size);
+}
+
int32_t voxl2_io_create_packet(uint8_t type, uint8_t *data, uint16_t size, uint8_t *out, uint16_t out_size)
{
uint16_t packet_size = size + 5;
diff --git a/src/drivers/voxl2_io/voxl2_io_packet.h b/src/drivers/voxl2_io/voxl2_io_packet.h
index 7e6237017f..1c4d242814 100644
--- a/src/drivers/voxl2_io/voxl2_io_packet.h
+++ b/src/drivers/voxl2_io/voxl2_io_packet.h
@@ -213,6 +213,9 @@ int32_t voxl2_io_create_rpm_packet4(int16_t rpm0, int16_t rpm1, int16_t rpm2, in
uint8_t led0, uint8_t led1, uint8_t led2, uint8_t led3,
uint8_t *out, uint16_t out_size);
+int32_t voxl2_io_create_hires_pwm_packet(uint32_t *pwm_val_ns, uint32_t cmd_cnt, uint8_t *out, uint16_t out_size);
+
+
// Create a packet for sending closed-loop RPM command and LED command to 4 ESCs, also request feedback from one ESC (with id=fb_id)
// Return value is the length of generated packet (if positive), otherwise error code
int32_t voxl2_io_create_rpm_packet4_fb(int16_t rpm0, int16_t rpm1, int16_t rpm2, int16_t rpm3,
diff --git a/src/drivers/voxl2_io/voxl2_io_packet_types.h b/src/drivers/voxl2_io/voxl2_io_packet_types.h
index 150982eca4..12766fb0ef 100644
--- a/src/drivers/voxl2_io/voxl2_io_packet_types.h
+++ b/src/drivers/voxl2_io/voxl2_io_packet_types.h
@@ -46,6 +46,7 @@
#define VOXL2_IO_PACKET_TYPE_SOUND_CMD 3
#define VOXL2_IO_PACKET_TYPE_STEP_CMD 4
#define VOXL2_IO_PACKET_TYPE_LED_CMD 5
+#define VOXL2_IO_PACKET_TYPE_PWM_HIRES_CMD 6
#define VOXL2_IO_PACKET_TYPE_RESET_CMD 10
#define VOXL2_IO_PACKET_TYPE_SET_ID_CMD 11
#define VOXL2_IO_PACKET_TYPE_SET_DIR_CMD 12
diff --git a/src/drivers/voxl2_io/voxl2_io_params.c b/src/drivers/voxl2_io/voxl2_io_params.c
index 704cca989e..ac99723b8d 100644
--- a/src/drivers/voxl2_io/voxl2_io_params.c
+++ b/src/drivers/voxl2_io/voxl2_io_params.c
@@ -32,34 +32,73 @@
****************************************************************************/
/**
- * UART M0065 baud rate
+ * VOXL2_IO UART baud rate
*
- * Default rate is 921600, which is used for communicating with M0065.
+ * Default rate is 921600, which is used for communicating with VOXL2_IO board
*
* @group VOXL2 IO
* @unit bit/s
*/
PARAM_DEFINE_INT32(VOXL2_IO_BAUD, 921600);
+
/**
- * M0065 PWM Min
+ * VOXL2_IO Disabled PWM
*
- * Minimum duration (microseconds) for M0065 PWM
+ * Pulse duration in disabled state (microseconds) for VOXL2_IO board
*
* @min 0
* @max 2000
* @group VOXL2 IO
* @unit us
*/
-PARAM_DEFINE_INT32(VOXL2_IO_MIN, 1000);
+PARAM_DEFINE_INT32(VOXL2_IO_DIS, 1000);
/**
- * M0065 PWM Max
+ * VOXL2_IO Min PWM
*
- * Maximum duration (microseconds) for M0065 PWM
+ * Minimum duration (microseconds) for VOXL2_IO board
+ *
+ * @min 0
+ * @max 2000
+ * @group VOXL2 IO
+ * @unit us
+ */
+
+PARAM_DEFINE_INT32(VOXL2_IO_MIN, 1100);
+
+/**
+ * VOXL2_IO Max PWM
+ *
+ * Maximum duration (microseconds) for VOXL2_IO board
* @min 0
* @max 2000
* @group VOXL2 IO
* @unit us
*/
PARAM_DEFINE_INT32(VOXL2_IO_MAX, 2000);
+
+
+/**
+ * VOXL2_IO Calibration Min PWM
+ *
+ * Minimum duration (microseconds) for VOXL2_IO board
+ *
+ * @min 0
+ * @max 2000
+ * @group VOXL2 IO
+ * @unit us
+ */
+
+PARAM_DEFINE_INT32(VOXL2_IO_CMIN, 1050);
+
+/**
+ * VOXL2_IO Calibration Max PWM
+ *
+ * Maximum duration (microseconds) for VOXL2_IO board
+ * @min 0
+ * @max 2000
+ * @group VOXL2 IO
+ * @unit us
+ */
+PARAM_DEFINE_INT32(VOXL2_IO_CMAX, 2000);
diff --git a/src/drivers/voxl2_io/voxl2_io_serial.cpp b/src/drivers/voxl2_io/voxl2_io_serial.cpp
deleted file mode 100644
index cee0923ece..0000000000
--- a/src/drivers/voxl2_io/voxl2_io_serial.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-/****************************************************************************
- *
- * Copyright (c) 2020 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.
- *
- ****************************************************************************/
-
-#include "string.h"
-#include "voxl2_io_serial.hpp"
-
-Voxl2IoSerial::Voxl2IoSerial()
-{
-}
-
-Voxl2IoSerial::~Voxl2IoSerial()
-{
- if (_uart_fd >= 0) {
- uart_close();
- }
-}
-
-int Voxl2IoSerial::uart_open(const char *dev, speed_t speed)
-{
- if (_uart_fd >= 0) {
- PX4_ERR("Port in use: %s (%i)", dev, errno);
- return -1;
- }
-
- /* Open UART */
-#ifdef __PX4_QURT
- _uart_fd = qurt_uart_open(dev, speed);
-#else
- _uart_fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
-#endif
-
- if (_uart_fd < 0) {
- PX4_ERR("Error opening port: %s (%i)", dev, errno);
- return -1;
- }
-
-#ifndef __PX4_QURT
- /* Back up the original UART configuration to restore it after exit */
- int termios_state;
-
- if ((termios_state = tcgetattr(_uart_fd, &_orig_cfg)) < 0) {
- PX4_ERR("Error configuring port: tcgetattr %s: %d", dev, termios_state);
- uart_close();
- return -1;
- }
-
- /* Fill the struct for the new configuration */
- tcgetattr(_uart_fd, &_cfg);
-
- /* Disable output post-processing */
- _cfg.c_oflag &= ~OPOST;
-
- _cfg.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
- _cfg.c_cflag &= ~CSIZE;
- _cfg.c_cflag |= CS8; /* 8-bit characters */
- _cfg.c_cflag &= ~PARENB; /* no parity bit */
- _cfg.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
- _cfg.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
-
- /* setup for non-canonical mode */
- _cfg.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
- _cfg.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
-
- if (cfsetispeed(&_cfg, speed) < 0 || cfsetospeed(&_cfg, speed) < 0) {
- PX4_ERR("Error configuring port: %s: %d (cfsetispeed, cfsetospeed)", dev, termios_state);
- uart_close();
- return -1;
- }
-
- if ((termios_state = tcsetattr(_uart_fd, TCSANOW, &_cfg)) < 0) {
- PX4_ERR("Error configuring port: %s (tcsetattr)", dev);
- uart_close();
- return -1;
- }
-
-#endif
-
- _speed = speed;
-
- return 0;
-}
-
-int Voxl2IoSerial::uart_set_baud(speed_t speed)
-{
-#ifndef __PX4_QURT
-
- if (_uart_fd < 0) {
- return -1;
- }
-
- if (cfsetispeed(&_cfg, speed) < 0) {
- return -1;
- }
-
- if (tcsetattr(_uart_fd, TCSANOW, &_cfg) < 0) {
- return -1;
- }
-
- _speed = speed;
-
- return 0;
-#endif
-
- return -1;
-}
-
-int Voxl2IoSerial::uart_close()
-{
-#ifndef __PX4_QURT
-
- if (_uart_fd < 0) {
- PX4_ERR("invalid state for closing");
- return -1;
- }
-
- if (tcsetattr(_uart_fd, TCSANOW, &_orig_cfg)) {
- PX4_ERR("failed restoring uart to original state");
- }
-
- if (close(_uart_fd)) {
- PX4_ERR("error closing uart");
- }
-
-#endif
-
- _uart_fd = -1;
-
- return 0;
-}
-
-int Voxl2IoSerial::uart_write(FAR void *buf, size_t len)
-{
- if (_uart_fd < 0 || buf == NULL) {
- PX4_ERR("invalid state for writing or buffer");
- return -1;
- }
-
-#ifdef __PX4_QURT
- return qurt_uart_write(_uart_fd, (const char *) buf, len);
-#else
- return write(_uart_fd, buf, len);
-#endif
-}
-
-int Voxl2IoSerial::uart_read(FAR void *buf, size_t len)
-{
- if (_uart_fd < 0 || buf == NULL) {
- PX4_ERR("invalid state for reading or buffer");
- return -1;
- }
-
-#ifdef __PX4_QURT
-#define ASYNC_UART_READ_WAIT_US 2000
- // The UART read on SLPI is via an asynchronous service so specify a timeout
- // for the return. The driver will poll periodically until the read comes in
- // so this may block for a while. However, it will timeout if no read comes in.
- return qurt_uart_read(_uart_fd, (char *) buf, len, ASYNC_UART_READ_WAIT_US);
-#else
- return read(_uart_fd, buf, len);
-#endif
-}
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index 1075ad4cd6..a9396caa1f 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -34,9 +34,7 @@
add_subdirectory(adsb EXCLUDE_FROM_ALL)
add_subdirectory(airspeed EXCLUDE_FROM_ALL)
add_subdirectory(atmosphere EXCLUDE_FROM_ALL)
-add_subdirectory(avoidance EXCLUDE_FROM_ALL)
add_subdirectory(battery EXCLUDE_FROM_ALL)
-add_subdirectory(bezier EXCLUDE_FROM_ALL)
add_subdirectory(button EXCLUDE_FROM_ALL)
add_subdirectory(cdev EXCLUDE_FROM_ALL)
add_subdirectory(cdrstream EXCLUDE_FROM_ALL)
diff --git a/src/lib/avoidance/ObstacleAvoidance.cpp b/src/lib/avoidance/ObstacleAvoidance.cpp
deleted file mode 100644
index f818f068a0..0000000000
--- a/src/lib/avoidance/ObstacleAvoidance.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-/****************************************************************************
- *
- * Copyright (c) 2019 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.
- *
- ****************************************************************************/
-
-/**
- * @file ObstacleAvoidance.cpp
- */
-
-#include "ObstacleAvoidance.hpp"
-#include "bezier/BezierN.hpp"
-
-using namespace matrix;
-using namespace time_literals;
-
-/** Timeout in us for trajectory data to get considered invalid */
-static constexpr uint64_t TRAJECTORY_STREAM_TIMEOUT_US = 500_ms;
-/** If Flighttask fails, keep 0.5 seconds the current setpoint before going into failsafe land */
-static constexpr uint64_t TIME_BEFORE_FAILSAFE = 500_ms;
-static constexpr uint64_t Z_PROGRESS_TIMEOUT_US = 2_s;
-
-ObstacleAvoidance::ObstacleAvoidance(ModuleParams *parent) :
- ModuleParams(parent)
-{
- _desired_waypoint = empty_trajectory_waypoint;
- _failsafe_position.setNaN();
- _avoidance_point_not_valid_hysteresis.set_hysteresis_time_from(false, TIME_BEFORE_FAILSAFE);
- _no_progress_z_hysteresis.set_hysteresis_time_from(false, Z_PROGRESS_TIMEOUT_US);
-
-}
-
-void ObstacleAvoidance::injectAvoidanceSetpoints(Vector3f &pos_sp, Vector3f &vel_sp, float &yaw_sp,
- float &yaw_speed_sp)
-{
- _sub_vehicle_status.update();
- _sub_vehicle_trajectory_waypoint.update();
- _sub_vehicle_trajectory_bezier.update();
-
- const auto &wp_msg = _sub_vehicle_trajectory_waypoint.get();
- const auto &bezier_msg = _sub_vehicle_trajectory_bezier.get();
-
- const bool wp_msg_timeout = hrt_elapsed_time((hrt_abstime *)&wp_msg.timestamp) > TRAJECTORY_STREAM_TIMEOUT_US;
- const bool bezier_msg_timeout = hrt_elapsed_time((hrt_abstime *)&bezier_msg.timestamp) > hrt_abstime(
- bezier_msg.control_points[bezier_msg.bezier_order - 1].delta * 1e6f);
- const bool avoidance_data_timeout = wp_msg_timeout && bezier_msg_timeout;
-
- const bool avoidance_point_valid = wp_msg.waypoints[vehicle_trajectory_waypoint_s::POINT_0].point_valid;
- const bool avoidance_bezier_valid = bezier_msg.bezier_order > 0;
-
- _avoidance_point_not_valid_hysteresis.set_state_and_update(!avoidance_point_valid
- && !avoidance_bezier_valid, hrt_absolute_time());
-
- const bool avoidance_invalid = (avoidance_data_timeout || _avoidance_point_not_valid_hysteresis.get_state());
-
- if ((_sub_vehicle_status.get().nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER) && avoidance_invalid) {
- // if in nav_state LOITER and avoidance isn't healthy, don't inject setpoints from avoidance system
- return;
- }
-
- if (avoidance_invalid) {
- if (_avoidance_activated) {
- // Invalid point received: deactivate
- PX4_WARN("Obstacle Avoidance system failed, loitering");
- _publishVehicleCmdDoLoiter();
- _avoidance_activated = false;
- }
-
- if (!_failsafe_position.isAllFinite()) {
- // save vehicle position when entering failsafe
- _failsafe_position = _position;
- }
-
- pos_sp = _failsafe_position;
- vel_sp.setNaN();
- yaw_sp = NAN;
- yaw_speed_sp = NAN;
-
- // Do nothing further - wait until activation
- return;
-
- } else if (!_avoidance_activated) {
- // First setpoint has been received: activate
- PX4_INFO("Obstacle Avoidance system activated");
- _failsafe_position.setNaN();
- _avoidance_activated = true;
- }
-
- if (avoidance_point_valid && !wp_msg_timeout) {
- const auto &point0 = wp_msg.waypoints[vehicle_trajectory_waypoint_s::POINT_0];
- pos_sp = Vector3f(point0.position);
- vel_sp = Vector3f(point0.velocity);
-
- if (!_ext_yaw_active) {
- // inject yaw setpoints only if weathervane isn't active
- yaw_sp = point0.yaw;
- yaw_speed_sp = point0.yaw_speed;
- }
-
- } else if (avoidance_bezier_valid && !bezier_msg_timeout) {
- float yaw = NAN, yaw_speed = NAN;
- _generateBezierSetpoints(pos_sp, vel_sp, yaw, yaw_speed);
-
- if (!_ext_yaw_active) {
- // inject yaw setpoints only if weathervane isn't active
- yaw_sp = yaw;
- yaw_speed_sp = yaw_speed;
- }
- }
-}
-
-void ObstacleAvoidance::_generateBezierSetpoints(matrix::Vector3f &position, matrix::Vector3f &velocity,
- float &yaw, float &yaw_velocity)
-{
- const auto &msg = _sub_vehicle_trajectory_bezier.get();
- int bezier_order = msg.bezier_order;
- matrix::Vector3f bezier_points[bezier_order];
- float bezier_yaws[bezier_order];
-
- for (int i = 0; i < bezier_order; i++) {
- bezier_points[i] = Vector3f(msg.control_points[i].position);
- bezier_yaws[i] = msg.control_points[i].yaw;
- }
-
- const float duration_s = msg.control_points[bezier_order - 1].delta;
- const hrt_abstime now = hrt_absolute_time();
- const hrt_abstime start = msg.timestamp;
- const hrt_abstime end = start + hrt_abstime(duration_s * 1e6f);
-
- float T = NAN;
-
- if (bezier::calculateT(start, end, now, T) &&
- bezier::calculateBezierPosVel(bezier_points, bezier_order, T, position, velocity) &&
- bezier::calculateBezierYaw(bezier_yaws, bezier_order, T, yaw, yaw_velocity)
- ) {
- // translate bezier velocities T [0;1] into real velocities m/s
- yaw_velocity /= duration_s;
- velocity /= duration_s;
-
- } else {
- PX4_WARN("Obstacle Avoidance system failed, bad trajectory");
- }
-}
-
-
-void ObstacleAvoidance::updateAvoidanceDesiredWaypoints(const Vector3f &curr_wp, const float curr_yaw,
- const float curr_yawspeed, const Vector3f &next_wp, const float next_yaw, const float next_yawspeed,
- const bool ext_yaw_active, const int wp_type)
-{
- _desired_waypoint.timestamp = hrt_absolute_time();
- _desired_waypoint.type = vehicle_trajectory_waypoint_s::MAV_TRAJECTORY_REPRESENTATION_WAYPOINTS;
- _curr_wp = curr_wp;
- _ext_yaw_active = ext_yaw_active;
-
- curr_wp.copyTo(_desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_1].position);
- Vector3f(NAN, NAN, NAN).copyTo(_desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_1].velocity);
- Vector3f(NAN, NAN, NAN).copyTo(_desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_1].acceleration);
-
- _desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_1].yaw = curr_yaw;
- _desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_1].yaw_speed = curr_yawspeed;
- _desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_1].point_valid = true;
- _desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_1].type = wp_type;
-
- next_wp.copyTo(_desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_2].position);
- Vector3f(NAN, NAN, NAN).copyTo(_desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_2].velocity);
- Vector3f(NAN, NAN, NAN).copyTo(_desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_2].acceleration);
-
- _desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_2].yaw = next_yaw;
- _desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_2].yaw_speed = next_yawspeed;
- _desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_2].point_valid = true;
-}
-
-void ObstacleAvoidance::updateAvoidanceDesiredSetpoints(const Vector3f &pos_sp, const Vector3f &vel_sp, const int type)
-{
- pos_sp.copyTo(_desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_0].position);
- vel_sp.copyTo(_desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_0].velocity);
- _desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_0].type = type;
- _desired_waypoint.waypoints[vehicle_trajectory_waypoint_s::POINT_0].point_valid = true;
-
- _pub_traj_wp_avoidance_desired.publish(_desired_waypoint);
-
- _desired_waypoint = empty_trajectory_waypoint;
-}
-
-void ObstacleAvoidance::checkAvoidanceProgress(const Vector3f &pos, const Vector3f &prev_wp,
- float target_acceptance_radius, const Vector2f &closest_pt)
-{
- _position = pos;
- position_controller_status_s pos_control_status = {};
- pos_control_status.timestamp = hrt_absolute_time();
-
- // vector from previous triplet to current target
- Vector2f prev_to_target = Vector2f(_curr_wp - prev_wp);
- // vector from previous triplet to the vehicle projected position on the line previous-target triplet
- Vector2f prev_to_closest_pt = closest_pt - Vector2f(prev_wp);
- // fraction of the previous-tagerget line that has been flown
- const float prev_curr_travelled = prev_to_closest_pt.length() / prev_to_target.length();
-
- Vector2f pos_to_target = Vector2f(_curr_wp - _position);
-
- if (prev_curr_travelled > 1.0f) {
- // if the vehicle projected position on the line previous-target is past the target waypoint,
- // increase the target acceptance radius such that navigator will update the triplets
- pos_control_status.acceptance_radius = pos_to_target.length() + 0.5f;
- }
-
- const float pos_to_target_z = fabsf(_curr_wp(2) - _position(2));
-
- bool no_progress_z = (pos_to_target_z > _prev_pos_to_target_z);
- _no_progress_z_hysteresis.set_state_and_update(no_progress_z, hrt_absolute_time());
-
- if (pos_to_target.length() < target_acceptance_radius && pos_to_target_z > _param_nav_mc_alt_rad.get()
- && _no_progress_z_hysteresis.get_state()) {
- // vehicle above or below the target waypoint
- pos_control_status.altitude_acceptance = pos_to_target_z + 0.5f;
- }
-
- _prev_pos_to_target_z = pos_to_target_z;
-
- // do not check for waypoints yaw acceptance in navigator
- pos_control_status.yaw_acceptance = NAN;
-
- _pub_pos_control_status.publish(pos_control_status);
-}
-
-void ObstacleAvoidance::_publishVehicleCmdDoLoiter()
-{
- vehicle_command_s command{};
- command.timestamp = hrt_absolute_time();
- command.command = vehicle_command_s::VEHICLE_CMD_DO_SET_MODE;
- command.param1 = (float)1; // base mode
- command.param3 = (float)0; // sub mode
- command.target_system = 1;
- command.target_component = 1;
- command.source_system = 1;
- command.source_component = 1;
- command.confirmation = false;
- command.from_external = false;
- command.param2 = (float)PX4_CUSTOM_MAIN_MODE_AUTO;
- command.param3 = (float)PX4_CUSTOM_SUB_MODE_AUTO_LOITER;
-
- // publish the vehicle command
- _pub_vehicle_command.publish(command);
-}
diff --git a/src/lib/avoidance/ObstacleAvoidance.hpp b/src/lib/avoidance/ObstacleAvoidance.hpp
deleted file mode 100644
index 8a27ffbbf1..0000000000
--- a/src/lib/avoidance/ObstacleAvoidance.hpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/****************************************************************************
- *
- * Copyright (c) 2019 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.
- *
- ****************************************************************************/
-
-/**
- * @file ObstacleAvoidance.hpp
- * This class is used to inject the setpoints of an obstacle avoidance system
- * into the FlightTasks
- *
- * @author Martina Rivizzigno
- */
-
-#pragma once
-
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include
-
-const vehicle_trajectory_waypoint_s empty_trajectory_waypoint = {0, 0, {0, 0, 0, 0, 0, 0, 0},
- { {0, {NAN, NAN, NAN}, {NAN, NAN, NAN}, {NAN, NAN, NAN}, NAN, NAN, false, UINT8_MAX, {0, 0}},
- {0, {NAN, NAN, NAN}, {NAN, NAN, NAN}, {NAN, NAN, NAN}, NAN, NAN, false, UINT8_MAX, {0, 0}},
- {0, {NAN, NAN, NAN}, {NAN, NAN, NAN}, {NAN, NAN, NAN}, NAN, NAN, false, UINT8_MAX, {0, 0}},
- {0, {NAN, NAN, NAN}, {NAN, NAN, NAN}, {NAN, NAN, NAN}, NAN, NAN, false, UINT8_MAX, {0, 0}},
- {0, {NAN, NAN, NAN}, {NAN, NAN, NAN}, {NAN, NAN, NAN}, NAN, NAN, false, UINT8_MAX, {0, 0}}
- }
-};
-
-class ObstacleAvoidance : public ModuleParams
-{
-public:
- ObstacleAvoidance(ModuleParams *parent);
- ~ObstacleAvoidance() = default;
-
- /**
- * Inject setpoints from obstacle avoidance system into FlightTasks.
- * @param pos_sp, position setpoint
- * @param vel_sp, velocity setpoint
- * @param yaw_sp, yaw setpoint
- * @param yaw_speed_sp, yaw speed setpoint
- */
- void injectAvoidanceSetpoints(matrix::Vector3f &pos_sp, matrix::Vector3f &vel_sp, float &yaw_sp, float &yaw_speed_sp);
-
- /**
- * Updates the desired waypoints to send to the obstacle avoidance system. These messages don't have any direct impact on the flight.
- * @param curr_wp, current position triplet
- * @param curr_yaw, current yaw triplet
- * @param curr_yawspeed, current yaw speed triplet
- * @param next_wp, next position triplet
- * @param next_yaw, next yaw triplet
- * @param next_yawspeed, next yaw speed triplet
- * @param wp_type, current triplet type
- */
- void updateAvoidanceDesiredWaypoints(const matrix::Vector3f &curr_wp, const float curr_yaw, const float curr_yawspeed,
- const matrix::Vector3f &next_wp, const float next_yaw, const float next_yawspeed, const bool ext_yaw_active,
- const int wp_type);
- /**
- * Updates the desired setpoints to send to the obstacle avoidance system.
- * @param pos_sp, desired position setpoint computed by the active FlightTask
- * @param vel_sp, desired velocity setpoint computed by the active FlightTask
- * @param type, current triplet type
- */
- void updateAvoidanceDesiredSetpoints(const matrix::Vector3f &pos_sp, const matrix::Vector3f &vel_sp, const int type);
-
- /**
- * Checks the vehicle progress between previous and current position waypoint of the triplet.
- * @param pos, vehicle position
- * @param prev_wp, previous position triplet
- * @param target_acceptance_radius, current position triplet xy acceptance radius
- * @param closest_pt, closest point to the vehicle on the line previous-current position triplet
- */
- void checkAvoidanceProgress(const matrix::Vector3f &pos, const matrix::Vector3f &prev_wp,
- float target_acceptance_radius, const matrix::Vector2f &closest_pt);
-
-protected:
-
- uORB::SubscriptionData _sub_vehicle_trajectory_bezier{ORB_ID(vehicle_trajectory_bezier)}; /**< vehicle trajectory waypoint subscription */
- uORB::SubscriptionData _sub_vehicle_trajectory_waypoint{ORB_ID(vehicle_trajectory_waypoint)}; /**< vehicle trajectory waypoint subscription */
- uORB::SubscriptionData _sub_vehicle_status{ORB_ID(vehicle_status)}; /**< vehicle status subscription */
-
- vehicle_trajectory_waypoint_s _desired_waypoint{}; /**< desired vehicle trajectory waypoint to be sent to OA */
-
- uORB::Publication _pub_traj_wp_avoidance_desired{ORB_ID(vehicle_trajectory_waypoint_desired)}; /**< trajectory waypoint desired publication */
- uORB::Publication _pub_pos_control_status{ORB_ID(position_controller_status)}; /**< position controller status publication */
- uORB::Publication _pub_vehicle_command{ORB_ID(vehicle_command)}; /**< vehicle command do publication */
-
- matrix::Vector3f _curr_wp = {}; /**< current position triplet */
- matrix::Vector3f _position = {}; /**< current vehicle position */
- matrix::Vector3f _failsafe_position = {}; /**< vehicle position when entered in failsafe */
-
- bool _avoidance_activated{false}; /**< true after the first avoidance setpoint is received */
-
- systemlib::Hysteresis _avoidance_point_not_valid_hysteresis{false}; /**< becomes true if the companion doesn't start sending valid setpoints */
- systemlib::Hysteresis _no_progress_z_hysteresis{false}; /**< becomes true if the vehicle is not making progress towards the z component of the goal */
-
- float _prev_pos_to_target_z = -1.f; /**< z distance to the goal */
-
- bool _ext_yaw_active = false; /**< true, if external yaw handling is active */
-
- /**
- * Publishes vehicle command.
- */
- void _publishVehicleCmdDoLoiter();
- void _generateBezierSetpoints(matrix::Vector3f &position, matrix::Vector3f &velocity, float &yaw, float &yaw_velocity);
-
- DEFINE_PARAMETERS(
- (ParamFloat) _param_nav_mc_alt_rad /**< Acceptance radius for multicopter altitude */
- );
-
-};
diff --git a/src/lib/avoidance/ObstacleAvoidanceTest.cpp b/src/lib/avoidance/ObstacleAvoidanceTest.cpp
deleted file mode 100644
index 008a8758a9..0000000000
--- a/src/lib/avoidance/ObstacleAvoidanceTest.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/****************************************************************************
- *
- * Copyright (C) 2019 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.
- *
- ****************************************************************************/
-
-#include
-#include
-#include
-
-
-using namespace matrix;
-// to run: make tests TESTFILTER=ObstacleAvoidance
-
-class ObstacleAvoidanceTest : public ::testing::Test
-{
-public:
- Vector3f pos_sp;
- Vector3f vel_sp;
- float yaw_sp = 0.123f;
- float yaw_speed_sp = NAN;
- void SetUp() override
-
- {
- param_control_autosave(false);
- param_reset_all();
- pos_sp = Vector3f(1.f, 1.2f, 0.1f);
- vel_sp = Vector3f(0.3f, 0.4f, 0.1f);
- }
-};
-
-class TestObstacleAvoidance : public ::ObstacleAvoidance
-{
-public:
- TestObstacleAvoidance() : ObstacleAvoidance(nullptr) {}
- void paramsChanged() {ObstacleAvoidance::updateParamsImpl();}
- void test_setPosition(Vector3f &pos) {_position = pos;}
-};
-
-TEST_F(ObstacleAvoidanceTest, instantiation) { ObstacleAvoidance oa(nullptr); }
-
-TEST_F(ObstacleAvoidanceTest, oa_enabled_healthy)
-{
- // GIVEN: the flight controller setpoints from FlightTaskAuto and a vehicle_trajectory_waypoint message coming
- // from offboard
- TestObstacleAvoidance oa;
-
- vehicle_trajectory_waypoint_s message = empty_trajectory_waypoint;
- message.timestamp = hrt_absolute_time();
- message.type = vehicle_trajectory_waypoint_s::MAV_TRAJECTORY_REPRESENTATION_WAYPOINTS;
- message.waypoints[vehicle_trajectory_waypoint_s::POINT_0].position[0] = 2.6f;
- message.waypoints[vehicle_trajectory_waypoint_s::POINT_0].position[1] = 2.4f;
- message.waypoints[vehicle_trajectory_waypoint_s::POINT_0].position[2] = 2.7f;
- message.waypoints[vehicle_trajectory_waypoint_s::POINT_0].yaw = 0.23f;
- message.waypoints[vehicle_trajectory_waypoint_s::POINT_0].point_valid = true;
-
- // GIVEN: and we publish the vehicle_trajectory_waypoint message and vehicle status message
- uORB::Publication vehicle_trajectory_waypoint_pub{ORB_ID(vehicle_trajectory_waypoint)};
- vehicle_trajectory_waypoint_pub.publish(message);
-
- vehicle_status_s vehicle_status{};
- vehicle_status.nav_state = vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION;
- uORB::Publication vehicle_status_pub{ORB_ID(vehicle_status)};
- vehicle_status_pub.publish(vehicle_status);
-
- // WHEN: we inject the vehicle_trajectory_waypoint in the interface
- oa.injectAvoidanceSetpoints(pos_sp, vel_sp, yaw_sp, yaw_speed_sp);
-
- // THEN: the setpoints should be injected
- EXPECT_FLOAT_EQ(message.waypoints[vehicle_trajectory_waypoint_s::POINT_0].position[0], pos_sp(0));
- EXPECT_FLOAT_EQ(message.waypoints[vehicle_trajectory_waypoint_s::POINT_0].position[1], pos_sp(1));
- EXPECT_FLOAT_EQ(message.waypoints[vehicle_trajectory_waypoint_s::POINT_0].position[2], pos_sp(2));
- EXPECT_TRUE(vel_sp.isAllNan());
- EXPECT_FLOAT_EQ(message.waypoints[vehicle_trajectory_waypoint_s::POINT_0].yaw, yaw_sp);
- EXPECT_FALSE(PX4_ISFINITE(yaw_speed_sp));
-}
-
-TEST_F(ObstacleAvoidanceTest, oa_enabled_healthy_bezier)
-{
- // GIVEN: the flight controller setpoints from FlightTaskAuto and a vehicle_trajectory_waypoint message coming
- // from offboard
- TestObstacleAvoidance oa;
-
- vehicle_trajectory_bezier_s message {};
- message.timestamp = hrt_absolute_time();
- message.bezier_order = 2;
- message.control_points[vehicle_trajectory_bezier_s::POINT_0].position[0] = 2.6f;
- message.control_points[vehicle_trajectory_bezier_s::POINT_0].position[1] = 2.4f;
- message.control_points[vehicle_trajectory_bezier_s::POINT_0].position[2] = 2.7f;
- message.control_points[vehicle_trajectory_bezier_s::POINT_0].yaw = 0.23f;
- message.control_points[vehicle_trajectory_bezier_s::POINT_0].delta = NAN;
- message.control_points[vehicle_trajectory_bezier_s::POINT_1].position[0] = 2.6f;
- message.control_points[vehicle_trajectory_bezier_s::POINT_1].position[1] = 2.4f;
- message.control_points[vehicle_trajectory_bezier_s::POINT_1].position[2] = 3.7f;
- message.control_points[vehicle_trajectory_bezier_s::POINT_1].yaw = 0.23f;
- message.control_points[vehicle_trajectory_bezier_s::POINT_1].delta = 0.5f;
-
- // GIVEN: and we publish the vehicle_trajectory_waypoint message and vehicle status message
- uORB::Publication vehicle_trajectory_bezier_pub{ORB_ID(vehicle_trajectory_bezier)};
- vehicle_trajectory_bezier_pub.publish(message);
-
- vehicle_status_s vehicle_status{};
- vehicle_status.nav_state = vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION;
- uORB::Publication vehicle_status_pub{ORB_ID(vehicle_status)};
- vehicle_status_pub.publish(vehicle_status);
-
- // WHEN: we inject the vehicle_trajectory_waypoint in the interface
- oa.injectAvoidanceSetpoints(pos_sp, vel_sp, yaw_sp, yaw_speed_sp);
-
- // THEN: the setpoints should be injected
- EXPECT_FLOAT_EQ(2.6f, pos_sp(0));
- EXPECT_FLOAT_EQ(2.4f, pos_sp(1));
- EXPECT_LT(2.7f, pos_sp(2));
- EXPECT_GT(2.8f, pos_sp(2)); // probably only a tiny bit above 2.7, but let's not have flakey tests
- EXPECT_FLOAT_EQ(vel_sp.xy().norm(), 0);
- EXPECT_FLOAT_EQ(vel_sp(2), (3.7f - 2.7f) / 0.5f);
- EXPECT_FLOAT_EQ(0.23, yaw_sp);
- EXPECT_FLOAT_EQ(yaw_speed_sp, 0);
-}
-
-TEST_F(ObstacleAvoidanceTest, oa_enabled_not_healthy)
-{
- // GIVEN: the flight controller setpoints from FlightTaskAuto and a vehicle_trajectory_waypoint message
- TestObstacleAvoidance oa;
-
- vehicle_trajectory_waypoint_s message = empty_trajectory_waypoint;
- Vector3f pos(3.1f, 4.7f, 5.2f);
- oa.test_setPosition(pos);
-
- // GIVEN: and we publish the vehicle_trajectory_waypoint message and vehicle_status
- uORB::Publication vehicle_trajectory_waypoint_pub{ORB_ID(vehicle_trajectory_waypoint)};
- vehicle_trajectory_waypoint_pub.publish(message);
-
- vehicle_status_s vehicle_status{};
- vehicle_status.nav_state = vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION;
- uORB::Publication vehicle_status_pub{ORB_ID(vehicle_status)};
- vehicle_status_pub.publish(vehicle_status);
-
- // WHEN: we inject the vehicle_trajectory_waypoint in the interface
- oa.injectAvoidanceSetpoints(pos_sp, vel_sp, yaw_sp, yaw_speed_sp);
-
- // THEN: the setpoints shouldn't be injected
- EXPECT_FLOAT_EQ(pos(0), pos_sp(0));
- EXPECT_FLOAT_EQ(pos(1), pos_sp(1));
- EXPECT_FLOAT_EQ(pos(2), pos_sp(2));
- EXPECT_TRUE(vel_sp.isAllNan());
- EXPECT_FALSE(PX4_ISFINITE(yaw_sp));
- EXPECT_FALSE(PX4_ISFINITE(yaw_speed_sp));
-}
-
-TEST_F(ObstacleAvoidanceTest, oa_desired)
-{
- // GIVEN: the flight controller setpoints from FlightTaskAuto and the waypoints from FLightTaskAuto
- TestObstacleAvoidance oa;
-
- pos_sp = Vector3f(1.f, 1.2f, NAN);
- vel_sp = Vector3f(NAN, NAN, 0.7f);
- int type = 4;
- Vector3f curr_wp(1.f, 1.2f, 5.0f);
- float curr_yaw = 1.02f;
- float curr_yawspeed = NAN;
- Vector3f next_wp(11.f, 1.2f, 5.0f);
- float next_yaw = 0.82f;
- float next_yawspeed = NAN;
- bool ext_yaw_active = false;
-
- // WHEN: we inject the setpoints and waypoints in the interface
- oa.updateAvoidanceDesiredWaypoints(curr_wp, curr_yaw, curr_yawspeed, next_wp, next_yaw, next_yawspeed, ext_yaw_active,
- type);
- oa.updateAvoidanceDesiredSetpoints(pos_sp, vel_sp, type);
-
- // WHEN: we subscribe to the uORB message out of the interface
- uORB::SubscriptionData _sub_traj_wp_avoidance_desired{ORB_ID(vehicle_trajectory_waypoint_desired)};
-
- // THEN: we expect the setpoints in POINT_0 and waypoints in POINT_1 and POINT_2
- EXPECT_FLOAT_EQ(pos_sp(0),
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_0].position[0]);
- EXPECT_FLOAT_EQ(pos_sp(1),
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_0].position[1]);
- EXPECT_FALSE(PX4_ISFINITE(
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_0].position[2]));
- EXPECT_FALSE(PX4_ISFINITE(
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_0].velocity[0]));
- EXPECT_FALSE(PX4_ISFINITE(
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_0].velocity[1]));
- EXPECT_FLOAT_EQ(vel_sp(2),
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_0].velocity[2]);
- EXPECT_EQ(type, _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_0].type);
- EXPECT_TRUE(_sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_0].point_valid);
-
- EXPECT_FLOAT_EQ(curr_wp(0),
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_1].position[0]);
- EXPECT_FLOAT_EQ(curr_wp(1),
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_1].position[1]);
- EXPECT_FLOAT_EQ(curr_wp(2),
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_1].position[2]);
- EXPECT_FLOAT_EQ(curr_yaw, _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_1].yaw);
- EXPECT_FALSE(PX4_ISFINITE(
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_1].yaw_speed));
- EXPECT_EQ(type, _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_1].type);
- EXPECT_TRUE(_sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_1].point_valid);
-
- EXPECT_FLOAT_EQ(next_wp(0),
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_2].position[0]);
- EXPECT_FLOAT_EQ(next_wp(1),
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_2].position[1]);
- EXPECT_FLOAT_EQ(next_wp(2),
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_2].position[2]);
- EXPECT_FLOAT_EQ(next_yaw, _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_2].yaw);
- EXPECT_FALSE(PX4_ISFINITE(
- _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_2].yaw_speed));
- EXPECT_EQ(UINT8_MAX, _sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_2].type);
- EXPECT_TRUE(_sub_traj_wp_avoidance_desired.get().waypoints[vehicle_trajectory_waypoint_s::POINT_2].point_valid);
-
-}
diff --git a/src/lib/battery/battery.cpp b/src/lib/battery/battery.cpp
index 21421d592d..10dbb93a68 100644
--- a/src/lib/battery/battery.cpp
+++ b/src/lib/battery/battery.cpp
@@ -307,16 +307,16 @@ void Battery::estimateStateOfCharge()
uint8_t Battery::determineWarning(float state_of_charge)
{
if (state_of_charge < _params.emergen_thr) {
- return battery_status_s::BATTERY_WARNING_EMERGENCY;
+ return battery_status_s::WARNING_EMERGENCY;
} else if (state_of_charge < _params.crit_thr) {
- return battery_status_s::BATTERY_WARNING_CRITICAL;
+ return battery_status_s::WARNING_CRITICAL;
} else if (state_of_charge < _params.low_thr) {
- return battery_status_s::BATTERY_WARNING_LOW;
+ return battery_status_s::WARNING_LOW;
} else {
- return battery_status_s::BATTERY_WARNING_NONE;
+ return battery_status_s::WARNING_NONE;
}
}
@@ -327,7 +327,7 @@ uint16_t Battery::determineFaults()
if ((_params.n_cells > 0)
&& (_voltage_v > (_params.n_cells * _params.v_charged * 1.05f))) {
// Reported as a "spike" since "over-voltage" does not exist in MAV_BATTERY_FAULT
- faults |= (1 << battery_status_s::BATTERY_FAULT_SPIKES);
+ faults |= (1 << battery_status_s::FAULT_SPIKES);
}
return faults;
diff --git a/src/lib/battery/battery.h b/src/lib/battery/battery.h
index 64649c3c08..baf6e5ecd6 100644
--- a/src/lib/battery/battery.h
+++ b/src/lib/battery/battery.h
@@ -175,7 +175,7 @@ private:
float _state_of_charge_volt_based{-1.f}; // [0,1]
float _state_of_charge{-1.f}; // [0,1]
float _scale{1.f};
- uint8_t _warning{battery_status_s::BATTERY_WARNING_NONE};
+ uint8_t _warning{battery_status_s::WARNING_NONE};
hrt_abstime _last_timestamp{0};
bool _armed{false};
bool _vehicle_status_is_fw{false};
diff --git a/src/lib/bezier/BezierN.cpp b/src/lib/bezier/BezierN.cpp
deleted file mode 100644
index 0d30aebd88..0000000000
--- a/src/lib/bezier/BezierN.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-/****************************************************************************
- *
- * Copyright (c) 2020 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.
- *
- ****************************************************************************/
-/**
- * @file BezierN.cpp
- * Bezier function
- *
- * @author Julian Kent
- */
-
-#include
-#include
-
-namespace
-{
-
-/*
- * Generic in-place bezier implementation. Leaves result in first element.
- *
- */
-template
-void calculateBezier(matrix::Vector *positions, int N, Scalar t, Scalar one_minus_t)
-{
- for (int bezier_order = 1; bezier_order < N; bezier_order++) {
- for (int i = 0; i < N - bezier_order; i++) {
- positions[i] = positions[i] * one_minus_t + positions[i + 1] * t;
- }
- }
-}
-}
-
-namespace bezier
-{
-
-bool calculateBezierPosVel(const matrix::Vector3f *positions, int N, float t,
- matrix::Vector3f &position, matrix::Vector3f &velocity)
-{
- if (positions == nullptr || N == 0 || t < 0 || t > 1) {
- return false;
- }
-
- using Df = matrix::Dual;
- using Vector3Df = matrix::Vector3;
-
- Vector3Df intermediates[N];
-
- for (int i = 0; i < N; i++) {
- for (int j = 0; j < 3; j++) {
- intermediates[i](j) = positions[i](j);
- }
- }
-
- Df dual_t(t, 0); // derivative with respect to time
- calculateBezier(intermediates, N, dual_t, Df(1) - dual_t);
-
- position = matrix::collectReals(intermediates[0]);
- velocity = matrix::collectDerivatives(intermediates[0]);
-
- return true;
-}
-
-bool calculateBezierPosVelAcc(const matrix::Vector3f *positions, int N, float t,
- matrix::Vector3f &position, matrix::Vector3f &velocity, matrix::Vector3f &acceleration)
-{
- if (positions == nullptr || N == 0 || t < 0 || t > 1) {
- return false;
- }
-
- using Df = matrix::Dual;
- using DDf = matrix::Dual;
- using Vector3DDf = matrix::Vector3;
-
- Vector3DDf intermediates[N];
-
- for (int i = 0; i < N; i++) {
- for (int j = 0; j < 3; j++) {
- intermediates[i](j) = Df(positions[i](j));
- }
- }
-
- DDf dual_t(Df(t, 0), 0); // 1st and 2nd derivative with respect to time
- calculateBezier(intermediates, N, dual_t, Df(1) - dual_t);
-
- position = matrix::collectReals(matrix::collectReals(intermediates[0]));
- velocity = matrix::collectReals(matrix::collectDerivatives(intermediates[0]));
- acceleration = matrix::collectDerivatives(matrix::collectDerivatives(intermediates[0]));
-
- return true;
-}
-
-bool calculateBezierYaw(const float *setpoints, int N, float t, float &yaw_setpoint, float &yaw_vel_setpoint)
-{
- if (setpoints == nullptr || N == 0 || t < 0 || t > 1) {
- return false;
- }
-
-
- using Df = matrix::Dual;
- using Vector1Df = matrix::Vector;
-
- Vector1Df intermediates[N];
-
- // all yaw setpoints are wrapped relative to the starting yaw
- const float offset = setpoints[0];
-
- for (int i = 0; i < N; i++) {
- intermediates[i](0) = matrix::wrap_pi(setpoints[i] - offset);
- }
-
- Df dual_t (t, 0); // derivative with respect to time
- calculateBezier(intermediates, N, dual_t, Df(1) - dual_t);
-
- Df result = intermediates[0](0);
- yaw_setpoint = matrix::wrap_pi(result.value + offset);
- yaw_vel_setpoint = result.derivative(0);
-
- return true;
-}
-
-bool calculateT(int64_t start_time, int64_t end_time, int64_t now, float &T)
-{
- if (now < start_time || end_time < now) {
- return false;
- }
-
- int64_t total_duration = end_time - start_time;
- int64_t elapsed_duration = now - start_time;
-
- T = (float) elapsed_duration / (float) total_duration;
-
- return true;
-}
-
-}
diff --git a/src/lib/bezier/BezierNTest.cpp b/src/lib/bezier/BezierNTest.cpp
deleted file mode 100644
index b08a40fd62..0000000000
--- a/src/lib/bezier/BezierNTest.cpp
+++ /dev/null
@@ -1,325 +0,0 @@
-/****************************************************************************
- *
- * Copyright (C) 2019 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.
- *
- ****************************************************************************/
-
-/**
- * Test code for the Velocity Smoothing library
- * Run this test only using make tests TESTFILTER=BezierN
- *
- * @author Julian Kent
- */
-
-#include
-#include
-
-#include "BezierN.hpp"
-
-TEST(BezierN_calculateBezier, checks_validity)
-{
- matrix::Vector3f points[10];
- matrix::Vector3f a, b;
- EXPECT_FALSE(bezier::calculateBezierPosVel(nullptr, 10, 0.5f, a, b));
- EXPECT_FALSE(bezier::calculateBezierPosVel(points, 0, 0.5f, a, b));
- EXPECT_FALSE(bezier::calculateBezierPosVel(points, 10, -0.5f, a, b));
- EXPECT_FALSE(bezier::calculateBezierPosVel(points, 10, 1.5f, a, b));
-}
-
-TEST(BezierN_calculateBezier, checks_validity_accel)
-{
- matrix::Vector3f points[10];
- matrix::Vector3f a, b, c;
- EXPECT_FALSE(bezier::calculateBezierPosVelAcc(nullptr, 10, 0.5f, a, b, c));
- EXPECT_FALSE(bezier::calculateBezierPosVelAcc(points, 0, 0.5f, a, b, c));
- EXPECT_FALSE(bezier::calculateBezierPosVelAcc(points, 10, -0.5f, a, b, c));
- EXPECT_FALSE(bezier::calculateBezierPosVelAcc(points, 10, 1.5f, a, b, c));
-}
-
-TEST(BezierN_calculateBezier, work_1_point)
-{
- // GIVEN: a single point bezier curve
- matrix::Vector3f points[2] = {matrix::Vector3f(1, 2, 3), matrix::Vector3f(NAN, NAN, NAN)};
- matrix::Vector3f pos, vel;
- pos *= NAN;
- vel *= NAN;
-
- // WHEN: we get the half-way point
- EXPECT_TRUE(bezier::calculateBezierPosVel(points, 1, 0.5f, pos, vel));
-
- // THEN: it should be the same as the point, and the velocity should be 0
- EXPECT_EQ((pos - points[0]).norm(), 0.f);
- EXPECT_EQ(vel.norm(), 0.f);
-}
-
-TEST(BezierN_calculateBezier, works_2_points)
-{
- // GIVEN: a 2-point bezier curve
- matrix::Vector3f points[3] = {matrix::Vector3f(1, 2, 3), matrix::Vector3f(5, 0, 1), matrix::Vector3f(NAN, NAN, NAN)};
- matrix::Vector3f pos, vel;
- pos *= NAN;
- vel *= NAN;
-
- // WHEN: we get the half-way point
- EXPECT_TRUE(bezier::calculateBezierPosVel(points, 2, 0.5f, pos, vel));
-
- // THEN: the position should be the mid-point between the start and end, and velocity should be the length
- EXPECT_EQ((pos - matrix::Vector3f(3, 1, 2)).norm(), 0.f);
- EXPECT_FLOAT_EQ((vel - (points[1] - points[0])).norm(), 0.f);
-
- // WHEN: we get the beginning point
- EXPECT_TRUE(bezier::calculateBezierPosVel(points, 2, 0.f, pos, vel));
-
- // THEN: the position should be the first point, and the velocity should still be the length
- EXPECT_EQ((pos - points[0]).norm(), 0.f);
- EXPECT_FLOAT_EQ((vel - (points[1] - points[0])).norm(), 0.f);
-
- // WHEN: we get the end point
- EXPECT_TRUE(bezier::calculateBezierPosVel(points, 2, 1.f, pos, vel));
-
- // THEN: the position should be the first point, and the velocity should still be the length
- EXPECT_EQ((pos - points[1]).norm(), 0.f);
- EXPECT_FLOAT_EQ((vel - (points[1] - points[0])).norm(), 0.f);
-}
-
-TEST(BezierN_calculateBezier, works_3_points_zero_accel)
-{
- // GIVEN: 3 points bezier, evenly spaced in a straight line
- matrix::Vector3f points[4] = {matrix::Vector3f(1, 2, 3), matrix::Vector3f(5, 0, 1), matrix::Vector3f(9, -2, -1), matrix::Vector3f(NAN, NAN, NAN)};
- matrix::Vector3f pos, vel;
- pos *= NAN;
- vel *= NAN;
-
- // WHEN: we get the half-way point
- EXPECT_TRUE(bezier::calculateBezierPosVel(points, 3, 0.5f, pos, vel));
-
- // THEN: it should be the middle point, with velocity of 1st to last
- EXPECT_FLOAT_EQ((pos - points[1]).norm(), 0.f);
- EXPECT_FLOAT_EQ((vel - (points[2] - points[0])).norm(), 0.f);
-
- matrix::Vector3f pos2, vel2, accel2;
-
- // WHEN: we use the accel interface
- EXPECT_TRUE(bezier::calculateBezierPosVelAcc(points, 3, 0.5f, pos2, vel2, accel2));
-
- // THEN: it should give same position, velocity as the non-accel interface, and zero accel (since this curve is 0 accel)
- EXPECT_FLOAT_EQ((pos2 - pos).norm(), 0.f);
- EXPECT_FLOAT_EQ((vel2 - vel).norm(), 0.f);
- EXPECT_FLOAT_EQ(accel2.norm(), 0.f);
-
- // WHEN: we check at the beginning
- EXPECT_TRUE(bezier::calculateBezierPosVel(points, 3, 0.f, pos, vel));
- EXPECT_TRUE(bezier::calculateBezierPosVelAcc(points, 3, 0.f, pos2, vel2, accel2));
-
- // THEN: it should be the starting point and same velocity
- EXPECT_FLOAT_EQ((pos - points[0]).norm(), 0.f);
- EXPECT_FLOAT_EQ((vel - (points[2] - points[0])).norm(), 0.f);
- EXPECT_FLOAT_EQ((pos2 - pos).norm(), 0.f);
- EXPECT_FLOAT_EQ((vel2 - vel).norm(), 0.f);
- EXPECT_FLOAT_EQ(accel2.norm(), 0.f);
-
- // WHEN: we check at the end
- EXPECT_TRUE(bezier::calculateBezierPosVel(points, 3, 1.f, pos, vel));
- EXPECT_TRUE(bezier::calculateBezierPosVelAcc(points, 3, 1.f, pos2, vel2, accel2));
-
- // THEN: it should be the ending point and same velocity
- EXPECT_FLOAT_EQ((pos - points[2]).norm(), 0.f);
- EXPECT_FLOAT_EQ((vel - (points[2] - points[0])).norm(), 0.f);
- EXPECT_FLOAT_EQ((pos2 - pos).norm(), 0.f);
- EXPECT_FLOAT_EQ((vel2 - vel).norm(), 0.f);
- EXPECT_FLOAT_EQ(accel2.norm(), 0.f);
-}
-
-TEST(BezierN_calculateBezier, works_3_points_accel)
-{
- // GIVEN: 3 points bezier, in a curve
- matrix::Vector3f points[4] = {matrix::Vector3f(1, 2, 3), matrix::Vector3f(5, 0, 1), matrix::Vector3f(19, -8, 1), matrix::Vector3f(NAN, NAN, NAN)};
- matrix::Vector3f pos, vel;
- pos *= NAN;
- vel *= NAN;
-
- matrix::Vector3f pos2;
- pos2 *= NAN;
-
- matrix::Vector3f accel_start, accel_mid, accel_end;
- matrix::Vector3f vel_start, vel_mid, vel_end;
-
-
- // WHEN: we check at the beginning
- EXPECT_TRUE(bezier::calculateBezierPosVel(points, 3, 0.f, pos, vel));
- EXPECT_TRUE(bezier::calculateBezierPosVelAcc(points, 3, 0.f, pos2, vel_start, accel_start));
-
- // THEN: it should give same position, velocity as the non-accel interface, and non-zero accel
- EXPECT_FLOAT_EQ((pos2 - pos).norm(), 0.f);
- EXPECT_FLOAT_EQ((vel_start - vel).norm(), 0.f);
- EXPECT_GT(accel_start.norm(), 0.f);
-
- // WHEN: we use the accel interface to get the half-way point
- EXPECT_TRUE(bezier::calculateBezierPosVel(points, 3, 0.5f, pos, vel));
- EXPECT_TRUE(bezier::calculateBezierPosVelAcc(points, 3, 0.5f, pos2, vel_mid, accel_mid));
-
- // THEN: the values should matche between accel and non-accel version
- EXPECT_FLOAT_EQ((pos2 - pos).norm(), 0.f);
- EXPECT_FLOAT_EQ((vel_mid - vel).norm(), 0.f);
-
- // AND: the accel should be the same as the start
- EXPECT_FLOAT_EQ((accel_mid - accel_start).norm(), 0.f);
-
-
- // WHEN: we check at the end
- EXPECT_TRUE(bezier::calculateBezierPosVel(points, 3, 1.f, pos, vel));
- EXPECT_TRUE(bezier::calculateBezierPosVelAcc(points, 3, 1.f, pos2, vel_end, accel_end));
-
- // THEN: it should be the ending point, and accel should match
- EXPECT_FLOAT_EQ((pos - points[2]).norm(), 0.f);
- EXPECT_FLOAT_EQ((pos2 - pos).norm(), 0.f);
- EXPECT_FLOAT_EQ((vel_end - vel).norm(), 0.f);
- EXPECT_FLOAT_EQ((accel_end - accel_start).norm(), 0.f);
-
- // FINALLY: mid point velocity should be average of start and end velocity
- EXPECT_FLOAT_EQ((vel_mid - 0.5f * (vel_start + vel_end)).norm(), 0.f);
-}
-
-TEST(BezierN_calculateBezierYaw, checks_validity)
-{
- float points[10];
- float a, b;
- EXPECT_FALSE(bezier::calculateBezierYaw(nullptr, 10, 0.5f, a, b));
- EXPECT_FALSE(bezier::calculateBezierYaw(points, 0, 0.5f, a, b));
- EXPECT_FALSE(bezier::calculateBezierYaw(points, 10, -0.5f, a, b));
- EXPECT_FALSE(bezier::calculateBezierYaw(points, 10, 1.5f, a, b));
-}
-
-TEST(BezierN_calculateBezierYaw, work_1_point)
-{
- // GIVEN: a single yaw point
- float points[2] = {M_PI / 2, NAN};
- float yaw, yaw_speed;
-
- // WHEN: we use it as a 1-point bezier curve
- EXPECT_TRUE(bezier::calculateBezierYaw(points, 1, 0.5f, yaw, yaw_speed));
-
- // THEN: it should have that same value, and the velocity should be 0
- EXPECT_FLOAT_EQ(yaw, M_PI / 2);
- EXPECT_FLOAT_EQ(yaw_speed, 0);
-}
-
-TEST(BezierN_calculateBezierYaw, work_2_points)
-{
- // GIVEN: a single yaw point
- float points[3] = {0, M_PI / 2, NAN};
- float yaw, yaw_speed;
-
- // WHEN: we get the beginning
- EXPECT_TRUE(bezier::calculateBezierYaw(points, 2, 0.f, yaw, yaw_speed));
-
- // THEN: it should have the beginning value, and the velocity should be the difference between first and last
- EXPECT_FLOAT_EQ(yaw, 0);
- EXPECT_FLOAT_EQ(yaw_speed, M_PI / 2);
-
- // WHEN: we get the middle
- EXPECT_TRUE(bezier::calculateBezierYaw(points, 2, 0.5f, yaw, yaw_speed));
-
- // THEN: it should have the beginning value, and the velocity should be the difference between first and last
- EXPECT_FLOAT_EQ(yaw, M_PI / 4);
- EXPECT_FLOAT_EQ(yaw_speed, M_PI / 2);
-
- // WHEN: we get the end
- EXPECT_TRUE(bezier::calculateBezierYaw(points, 2, 1.f, yaw, yaw_speed));
-
- // THEN: it should have the beginning value, and the velocity should be the difference between first and last
- EXPECT_FLOAT_EQ(yaw, M_PI / 2);
- EXPECT_FLOAT_EQ(yaw_speed, M_PI / 2);
-}
-
-TEST(BezierN_calculateBezierYaw, work_2_points_wrap)
-{
- // GIVEN: 2 yaw points on either side of the +- PI wrap line
- float points[3] = {-M_PI + 0.1, M_PI - 0.1, NAN};
- float yaw, yaw_speed;
-
- // WHEN: we get the beginning
- EXPECT_TRUE(bezier::calculateBezierYaw(points, 2, 0.f, yaw, yaw_speed));
-
- // THEN: it should have the beginning value, and the velocity should be the wrapped distance between first and last
- EXPECT_FLOAT_EQ(yaw, -M_PI + 0.1);
- EXPECT_NEAR(yaw_speed, -0.2, 1e-6f);
-
- // WHEN: we get the middle
- EXPECT_TRUE(bezier::calculateBezierYaw(points, 2, 0.5f, yaw, yaw_speed));
-
- // THEN: it should have the wrapped middle value, and the velocity should be the wrapped distance between first and last
- EXPECT_FLOAT_EQ(matrix::wrap_pi(yaw - float(M_PI)), 0);
- EXPECT_NEAR(yaw_speed, -0.2, 1e-6f);
-
- // WHEN: we get the end
- EXPECT_TRUE(bezier::calculateBezierYaw(points, 2, 1.f, yaw, yaw_speed));
-
- // THEN: it should have the end value, and the velocity should be the wrapped distance between first and last
- EXPECT_FLOAT_EQ(yaw, M_PI - 0.1);
- EXPECT_NEAR(yaw_speed, -0.2, 1e-6f);
-}
-
-
-TEST(BezierN_calculateT, rejects_bad_timestamps)
-{
- float f = NAN;
- EXPECT_FALSE(bezier::calculateT(100, 1000, 99, f));
- EXPECT_FALSE(bezier::calculateT(100, 1000, 1001, f));
- EXPECT_FALSE(bezier::calculateT(1001, 1000, 1001, f));
-}
-
-
-TEST(BezierN_calculateT, begin_middle_end)
-{
- float f = NAN;
- EXPECT_TRUE(bezier::calculateT(100, 1000, 100, f));
- EXPECT_FLOAT_EQ(f, 0.f);
-
- EXPECT_TRUE(bezier::calculateT(100, 1000, 550, f));
- EXPECT_FLOAT_EQ(f, 0.5f);
-
- EXPECT_TRUE(bezier::calculateT(100, 1000, 1000, f));
- EXPECT_FLOAT_EQ(f, 1.f);
-}
-
-TEST(BezierN_calculateT, giant_offset)
-{
- int64_t offset = 0xFFFFFFFFFFFF; // 48 bit max
- float f = NAN;
- EXPECT_TRUE(bezier::calculateT(offset + 100, offset + 1000, offset + 100, f));
- EXPECT_FLOAT_EQ(f, 0.f);
-
- EXPECT_TRUE(bezier::calculateT(offset + 100, offset + 1000, offset + 550, f));
- EXPECT_FLOAT_EQ(f, 0.5f);
-
- EXPECT_TRUE(bezier::calculateT(offset + 100, offset + 1000, offset + 1000, f));
- EXPECT_FLOAT_EQ(f, 1.f);
-}
diff --git a/src/lib/bezier/BezierQuad.cpp b/src/lib/bezier/BezierQuad.cpp
deleted file mode 100644
index 61309cc496..0000000000
--- a/src/lib/bezier/BezierQuad.cpp
+++ /dev/null
@@ -1,223 +0,0 @@
-/****************************************************************************
- *
- * Copyright (c) 2018 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.
- *
- ****************************************************************************/
-/**
- * @file BezierQuad.cpp
- * Bezier function
- *
- * @author Dennis Mannhart
- */
-
-// The header includes this implementation, so in order to have this library shared with other
-// .cpp files and avoid duplication of constants, we need to prevent including it twice
-#ifndef BEZIER_QUAD_CPP
-#define BEZIER_QUAD_CPP
-
-
-#include "BezierQuad.hpp"
-
-namespace bezier
-{
-static constexpr double GOLDEN_RATIO = 1.6180339887; //(sqrt(5)+1)/2
-static constexpr double RESOLUTION = 0.0001; //End criterion for golden section search
-
-template
-void BezierQuad::setBezier(const Vector3_t &pt0, const Vector3_t &ctrl, const Vector3_t &pt1,
- Tp duration)
-{
- _pt0 = pt0;
- _ctrl = ctrl;
- _pt1 = pt1;
- _duration = duration;
- _cached_resolution = (Tp)(-1);
-}
-
-template
-void BezierQuad::getBezier(Vector3_t &pt0, Vector3_t &ctrl, Vector3_t &pt1)
-{
- pt0 = _pt0;
- ctrl = _ctrl;
- pt1 = _pt1;
-}
-
-template
-matrix::Vector BezierQuad::getPoint(const Tp t)
-{
- return (_pt0 * ((Tp)1 - t / _duration) * ((Tp)1 - t / _duration) + _ctrl * (Tp)2 * ((
- Tp)1 - t / _duration) * t / _duration + _pt1 *
- t / _duration * t / _duration);
-}
-
-template
-matrix::Vector BezierQuad::getVelocity(const Tp t)
-{
- return (((_ctrl - _pt0) * _duration + (_pt0 - _ctrl * (Tp)2 + _pt1) * t) * (Tp)2 / (_duration * _duration));
-}
-
-template
-matrix::Vector BezierQuad::getAcceleration()
-{
- return ((_pt0 - _ctrl * (Tp)2 + _pt1) * (Tp)2 / (_duration * _duration));
-}
-
-template
-void BezierQuad::getStates(Vector3_t &point, Vector3_t &vel, Vector3_t &acc, const Tp time)
-{
- point = getPoint(time);
- vel = getVelocity(time);
- acc = getAcceleration();
-}
-
-template
-void BezierQuad::getStatesClosest(Vector3_t &point, Vector3_t &vel, Vector3_t &acc,
- const Vector3_t pose)
-{
- // get t that corresponds to point closest on bezier point
- Tp t = _goldenSectionSearch(pose);
-
- // get states corresponding to t
- getStates(point, vel, acc, t);
-
-}
-
-template
-void BezierQuad::setBezFromVel(const Vector3_t &ctrl, const Vector3_t &vel0, const Vector3_t &vel1,
- const Tp duration)
-{
- // update bezier points
- _ctrl = ctrl;
- _duration = duration;
- _pt0 = _ctrl - vel0 * _duration / (Tp)2;
- _pt1 = _ctrl + vel1 * _duration / (Tp)2;
- _cached_resolution = (Tp)(-1);
-}
-
-template
-Tp BezierQuad::getArcLength(const Tp resolution)
-{
- // we don't need to recompute arc length if:
- // 1. _cached_resolution is up to date; 2. _cached_resolution is smaller than desired resolution (= more accurate)
- if ((_cached_resolution > (Tp)0) && (_cached_resolution <= resolution)) {
- return _cached_arc_length;
- }
-
- // get number of elements
- int n = (int)(roundf(_duration / resolution));
-
- // check if n is even
- if (n % 2 == 1) {
- n += 1;
- }
-
- // step size
- Tp h = (_duration) / n;
-
- // get integration
- _cached_arc_length = (Tp)0;
- Vector3_t y;
-
- for (int i = 1; i < n; i++) {
-
- y = getVelocity(h * i);
-
- if (i % 2 == 1) {
- _cached_arc_length += (Tp)4 * y.length();
-
- } else {
- _cached_arc_length += (Tp)2 * y.length();
- }
- }
-
- // velocity length at start and end points
- Tp y0 = getVelocity((Tp)0).length();
- Tp yn = getVelocity(_duration).length();
-
- // 1/3 simpsons rule
- _cached_arc_length = h / (Tp)3 * (y0 + yn + _cached_arc_length);
-
- // update cache
- _cached_resolution = resolution;
-
- return _cached_arc_length;
-}
-
-template
-Tp BezierQuad::getDistToClosestPoint(const Vector3_t &pose)
-{
- // get t that corresponds to point closest on bezier point
- Tp t = _goldenSectionSearch(pose);
-
- // get closest point
- Vector3_t point = getPoint(t);
- return (pose - point).length();
-}
-
-template
-Tp BezierQuad::_goldenSectionSearch(const Vector3_t &pose)
-{
- Tp a, b, c, d;
- a = (Tp)0; // represents most left point
- b = _duration * (Tp)1; // represents most right point
-
- c = b - (b - a) / GOLDEN_RATIO;
- d = a + (b - a) / GOLDEN_RATIO;
-
- while (fabsf(c - d) > RESOLUTION) {
- if (_getDistanceSquared(c, pose) < _getDistanceSquared(d, pose)) {
- b = d;
-
- } else {
- a = c;
- }
-
- c = b - (b - a) / GOLDEN_RATIO;
- d = a + (b - a) / GOLDEN_RATIO;
- }
-
- return (b + a) / (Tp)2;
-}
-
-template
-Tp BezierQuad::_getDistanceSquared(const Tp t, const Vector3_t &pose)
-{
- // get point on bezier
- Vector3_t vec = getPoint(t);
-
- // get vector from point to pose
- vec = vec - pose;
-
- // norm squared
- return (vec * vec);
-}
-}
-
-#endif
diff --git a/src/lib/bezier/BezierQuad.hpp b/src/lib/bezier/BezierQuad.hpp
deleted file mode 100644
index 5aebe94b7b..0000000000
--- a/src/lib/bezier/BezierQuad.hpp
+++ /dev/null
@@ -1,210 +0,0 @@
-/****************************************************************************
- *
- * Copyright (C) 2018 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.
- *
- ****************************************************************************/
-
-/**
- * @file BezierQuad.hpp
- *
- * Quadratic bezier lib
- *
- * A quadratic bezier function/spline is completely defined by three 3D points in space and a time scaling factor.
- * pt0 and pt1 define the start and end points of the spline. ctrl point is a point in space that effects the curvature
- * of the spline. The time scaling factor (= duration) defines the time it takes to travel along the spline from pt0 to
- * pt1.
- * A bezier spline is a continuous function from which position, velocity and acceleration can be extracted. For a given spline,
- * acceleration stays constant.
- */
-
-
-#pragma once
-
-#include
-
-namespace bezier
-{
-template
-class BezierQuad
-{
-public:
-
- using Vector3_t = matrix::Vector;
-
- /**
- * Empty constructor
- */
- BezierQuad() :
- _pt0(Vector3_t()), _ctrl(Vector3_t()), _pt1(Vector3_t()), _duration(1.0f) {}
-
- /**
- * Constructor from array
- */
- BezierQuad(const Tp pt0[3], const Tp ctrl[3], const Tp pt1[3], Tp duration = 1.0f) :
- _pt0(Vector3_t(pt0)), _ctrl(Vector3_t(ctrl)), _pt1(Vector3_t(pt1)), _duration(duration) {}
-
- /**
- * Constructor from vector
- */
- BezierQuad(const Vector3_t &pt0, const Vector3_t &ctrl, const Vector3_t &pt1,
- Tp duration = 1.0f):
- _pt0(pt0), _ctrl(ctrl), _pt1(pt1), _duration(duration) {}
-
-
- /*
- * Get bezier points
- */
- void getBezier(Vector3_t &pt0, Vector3_t &ctrl, Vector3_t &pt1);
-
- /*
- * Return pt0
- */
- Vector3_t getPt0() {return _pt0;}
-
- /*
- * Return ctrl
- */
- Vector3_t getCtrl() {return _ctrl;}
-
- /*
- * Return pt1
- */
- Vector3_t getPt1() {return _pt1;}
-
- /**
- * Set new bezier points and duration
- */
- void setBezier(const Vector3_t &pt0, const Vector3_t &ctrl, const Vector3_t &pt1,
- Tp duration = (Tp)1);
-
- /*
- * Set duration
- *
- * @param time is the total time it takes to travel along the bezier spline.
- */
- void setDuration(const Tp time) {_duration = time;}
-
- /**
- * Return point on bezier point corresponding to time t
- *
- * @param t is a time in seconds in between [0, duration]
- * @return a point on bezier
- */
- Vector3_t getPoint(const Tp t);
-
- /*
- * Distance to closest point given a position
- *
- * @param pose is a position in 3D space from which distance to bezier is computed.
- * @return distance to closest point on bezier
- */
- Tp getDistToClosestPoint(const Vector3_t &pose);
-
- /*
- * Return velocity on bezier corresponding to time t
- *
- * @param t is a time in seconds in between [0, duration]
- * @return velocity vector at time t
- */
- Vector3_t getVelocity(const Tp t);
-
- /*
- * Return acceleration on bezier corresponding to time t
- *
- * @return constant acceleration of bezier
- */
- Vector3_t getAcceleration();
-
- /*
- * Get all states on bezier corresponding to time t
- */
- void getStates(Vector3_t &point, Vector3_t &vel, Vector3_t &acc, const Tp t);
-
- /*
- * Get states on bezier which are closest to pose in space
- *
- * @param point is a posiiton on the spline that is closest to a given pose
- * @param vel is the velocity at that given point
- * @param acc is the acceleration for that spline
- * @param pose represent a position in space from which closest point is computed
- */
- void getStatesClosest(Vector3_t &point, Vector3_t &vel, Vector3_t &acc,
- const Vector3_t pose);
-
- /*
- * Compute bezier from velocity at bezier end points and ctrl point
- *
- * The bezier end points are fully defined by a given control point ctrl, the duration and
- * the desired velocity vectors at the end points.
- */
- void setBezFromVel(const Vector3_t &ctrl, const Vector3_t &vel0, const Vector3_t &vel1,
- const Tp duration = (Tp)1);
-
- /*
- * Return the arc length of a bezier spline
- *
- * The arc length is computed with simpsons integration.
- * @param resolution in meters.
- */
- Tp getArcLength(const Tp resolution);
-
-private:
-
- Vector3_t _pt0; /**< Bezier starting point */
- Vector3_t _ctrl; /**< Bezier control point */
- Vector3_t _pt1; /**< bezier end point */
- Tp _duration = (Tp)1; /**< Total time to travle along spline */
-
- Tp _cached_arc_length = (Tp)0; /**< The saved arc length of the spline */
- Tp _cached_resolution = (Tp)(-1); /**< The resolution used to compute the arc length.
- Negative number means that cache is not up to date. */
-
- /*
- * Golden section search
- */
- Tp _goldenSectionSearch(const Vector3_t &pose);
-
- /*
- * Get squared distance from 3D pose in space and a point on bezier.
- *
- * @param t is the time in between [0, duration] that defines a point on the bezier.
- * @param pose is a 3D pose in space.
- */
- Tp _getDistanceSquared(const Tp t, const Vector3_t &pose);
-
-
-};
-
-using BezierQuad_f = BezierQuad;
-using BezierQuad_d = BezierQuad;
-}
-
-// include implementation
-#include "BezierQuad.cpp"
diff --git a/src/lib/drivers/device/qurt/I2C.cpp b/src/lib/drivers/device/qurt/I2C.cpp
index c2b70f66d3..a459dbbe81 100644
--- a/src/lib/drivers/device/qurt/I2C.cpp
+++ b/src/lib/drivers/device/qurt/I2C.cpp
@@ -55,7 +55,16 @@ I2C::_config_i2c_bus_func_t I2C::_config_i2c_bus = NULL;
I2C::_set_i2c_address_func_t I2C::_set_i2c_address = NULL;
I2C::_i2c_transfer_func_t I2C::_i2c_transfer = NULL;
-pthread_mutex_t I2C::_mutex = PTHREAD_MUTEX_INITIALIZER;
+// There is a mutex per I2C bus. A mutex isn't required with normal
+// use since per bus I2C accesses are made via work item tied to a per bus thread.
+// But it is here anyways in case someone decides to use the bus in some different
+// custom code that has a separate thread.
+struct I2C::_bus_mutex_t I2C::_bus_mutex[I2C::MAX_I2C_BUS] = {
+ {1, PTHREAD_MUTEX_INITIALIZER},
+ {2, PTHREAD_MUTEX_INITIALIZER},
+ {4, PTHREAD_MUTEX_INITIALIZER},
+ {5, PTHREAD_MUTEX_INITIALIZER}
+};
I2C::I2C(uint8_t device_type, const char *name, const int bus, const uint16_t address, const uint32_t frequency) :
CDev(name, nullptr),
@@ -91,10 +100,27 @@ I2C::init()
goto out;
}
- pthread_mutex_lock(&_mutex);
+ if (_mutex == nullptr) {
+ for (int i = 0; i < MAX_I2C_BUS; i++) {
+ if (get_device_bus() == _bus_mutex[i]._bus) {
+ _mutex = &_bus_mutex[i]._mutex;
+ break;
+ }
+ }
+
+ if (_mutex == nullptr) {
+ PX4_ERR("NULL i2c bus mutex");
+ goto out;
+
+ } else {
+ PX4_INFO("Set up I2C bus mutex for bus %d", get_device_bus());
+ }
+ }
+
+ pthread_mutex_lock(_mutex);
// Open the actual I2C device
_i2c_fd = _config_i2c_bus(get_device_bus(), get_device_address(), _frequency);
- pthread_mutex_unlock(&_mutex);
+ pthread_mutex_unlock(_mutex);
if (_i2c_fd == PX4_ERROR) {
PX4_ERR("i2c init failed");
@@ -131,9 +157,9 @@ I2C::set_device_address(int address)
if ((_i2c_fd != PX4_ERROR) && (_set_i2c_address != NULL)) {
PX4_INFO("Set i2c address 0x%x, fd %d", address, _i2c_fd);
- pthread_mutex_lock(&_mutex);
+ pthread_mutex_lock(_mutex);
_set_i2c_address(_i2c_fd, address);
- pthread_mutex_unlock(&_mutex);
+ pthread_mutex_unlock(_mutex);
Device::set_device_address(address);
}
@@ -150,9 +176,9 @@ I2C::transfer(const uint8_t *send, const unsigned send_len, uint8_t *recv, const
do {
// PX4_INFO("transfer out %p/%u in %p/%u", send, send_len, recv, recv_len);
- pthread_mutex_lock(&_mutex);
+ pthread_mutex_lock(_mutex);
ret = _i2c_transfer(_i2c_fd, send, send_len, recv, recv_len);
- pthread_mutex_unlock(&_mutex);
+ pthread_mutex_unlock(_mutex);
if (ret != PX4_ERROR) { break; }
diff --git a/src/lib/drivers/device/qurt/I2C.hpp b/src/lib/drivers/device/qurt/I2C.hpp
index 7f1d59bc0a..ccf5e1f5df 100644
--- a/src/lib/drivers/device/qurt/I2C.hpp
+++ b/src/lib/drivers/device/qurt/I2C.hpp
@@ -124,10 +124,18 @@ protected:
private:
uint32_t _frequency{0};
int _i2c_fd{-1};
+ pthread_mutex_t *_mutex{nullptr};
+
+ static const int MAX_I2C_BUS{4};
+
static _config_i2c_bus_func_t _config_i2c_bus;
static _set_i2c_address_func_t _set_i2c_address;
static _i2c_transfer_func_t _i2c_transfer;
- static pthread_mutex_t _mutex;
+
+ static struct _bus_mutex_t {
+ int _bus;
+ pthread_mutex_t _mutex{PTHREAD_MUTEX_INITIALIZER};
+ } _bus_mutex[MAX_I2C_BUS];
};
} // namespace device
diff --git a/src/lib/mixer_module/CMakeLists.txt b/src/lib/mixer_module/CMakeLists.txt
index 783dfe3dde..3a1581118b 100644
--- a/src/lib/mixer_module/CMakeLists.txt
+++ b/src/lib/mixer_module/CMakeLists.txt
@@ -48,6 +48,7 @@ px4_add_library(mixer_module
functions/FunctionConstantMax.hpp
functions/FunctionConstantMin.hpp
functions/FunctionGimbal.hpp
+ functions/FunctionICEngineControl.hpp
functions/FunctionLandingGear.hpp
functions/FunctionManualRC.hpp
functions/FunctionMotors.hpp
diff --git a/src/lib/avoidance/ObstacleAvoidance_dummy.hpp b/src/lib/mixer_module/functions/FunctionICEngineControl.hpp
similarity index 54%
rename from src/lib/avoidance/ObstacleAvoidance_dummy.hpp
rename to src/lib/mixer_module/functions/FunctionICEngineControl.hpp
index 7831c919fd..0609f5cc94 100644
--- a/src/lib/avoidance/ObstacleAvoidance_dummy.hpp
+++ b/src/lib/mixer_module/functions/FunctionICEngineControl.hpp
@@ -1,6 +1,6 @@
/****************************************************************************
*
- * Copyright (c) 2020 PX4 Development Team. All rights reserved.
+ * Copyright (c) 2025 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,63 +31,53 @@
*
****************************************************************************/
-/**
- * @file ObstacleAvoidance_dummy.hpp
- * This is a dummy class to reduce flash space for when obstacle avoidance is not required
- *
- * @author Julian Kent
- */
-
#pragma once
-#include
-#include
+#include "FunctionProviderBase.hpp"
+#include
-#include
-
-
-class ObstacleAvoidance
+/**
+ * Functions: ICE...
+ */
+class FunctionICEControl : public FunctionProviderBase
{
public:
- ObstacleAvoidance(void *) {} // takes void* argument to be compatible with ModuleParams constructor
-
-
- void injectAvoidanceSetpoints(matrix::Vector3f &pos_sp, matrix::Vector3f &vel_sp, float &yaw_sp,
- float &yaw_speed_sp)
+ FunctionICEControl()
{
- notify_dummy();
- };
-
- void updateAvoidanceDesiredWaypoints(const matrix::Vector3f &curr_wp, const float curr_yaw,
- const float curr_yawspeed,
- const matrix::Vector3f &next_wp, const float next_yaw, const float next_yawspeed, const bool ext_yaw_active,
- const int wp_type)
- {
- notify_dummy();
- };
-
- void updateAvoidanceDesiredSetpoints(const matrix::Vector3f &pos_sp, const matrix::Vector3f &vel_sp,
- const int type)
- {
- notify_dummy();
+ resetAllToDisarmedValue();
}
+ static FunctionProviderBase *allocate(const Context &context) { return new FunctionICEControl(); }
- void checkAvoidanceProgress(const matrix::Vector3f &pos, const matrix::Vector3f &prev_wp,
- float target_acceptance_radius, const matrix::Vector2f &closest_pt)
+ void update() override
{
- notify_dummy();
- };
+ internal_combustion_engine_control_s internal_combustion_engine_control;
-protected:
-
- bool _logged_error = false;
- void notify_dummy()
- {
- if (!_logged_error) {
- PX4_ERR("Dummy avoidance library called!");
- _logged_error = true;
+ // map [0, 1] to [-1, 1] which is the interface for non-motor PWM channels
+ if (_internal_combustion_engine_control_sub.update(&internal_combustion_engine_control)) {
+ _data[0] = internal_combustion_engine_control.ignition_on * 2.f - 1.f;
+ _data[1] = internal_combustion_engine_control.throttle_control * 2.f - 1.f;
+ _data[2] = internal_combustion_engine_control.choke_control * 2.f - 1.f;
+ _data[3] = internal_combustion_engine_control.starter_engine_control * 2.f - 1.f;
}
}
+
+ float value(OutputFunction func) override { return _data[(int)func - (int)OutputFunction::IC_Engine_Ignition]; }
+
+private:
+ static constexpr int num_data_points = 4;
+
+ void resetAllToDisarmedValue()
+ {
+ for (int i = 0; i < num_data_points; ++i) {
+ _data[i] = NAN;
+ }
+ }
+
+ static_assert(num_data_points == (int)OutputFunction::IC_Engine_Starter - (int)OutputFunction::IC_Engine_Ignition + 1,
+ "number of functions mismatch");
+
+ uORB::Subscription _internal_combustion_engine_control_sub{ORB_ID(internal_combustion_engine_control)};
+ float _data[num_data_points] {};
};
diff --git a/src/lib/mixer_module/mixer_module.cpp b/src/lib/mixer_module/mixer_module.cpp
index 45f56ab540..56a2d61356 100644
--- a/src/lib/mixer_module/mixer_module.cpp
+++ b/src/lib/mixer_module/mixer_module.cpp
@@ -64,6 +64,7 @@ static const FunctionProvider all_function_providers[] = {
{OutputFunction::Gripper, &FunctionGripper::allocate},
{OutputFunction::RC_Roll, OutputFunction::RC_AUXMax, &FunctionManualRC::allocate},
{OutputFunction::Gimbal_Roll, OutputFunction::Gimbal_Yaw, &FunctionGimbal::allocate},
+ {OutputFunction::IC_Engine_Ignition, OutputFunction::IC_Engine_Starter, &FunctionICEControl::allocate},
};
MixingOutput::MixingOutput(const char *param_prefix, uint8_t max_num_outputs, OutputModuleInterface &interface,
diff --git a/src/lib/mixer_module/mixer_module.hpp b/src/lib/mixer_module/mixer_module.hpp
index ff400ca6d5..c55b72da4e 100644
--- a/src/lib/mixer_module/mixer_module.hpp
+++ b/src/lib/mixer_module/mixer_module.hpp
@@ -40,6 +40,7 @@
#include "functions/FunctionConstantMin.hpp"
#include "functions/FunctionGimbal.hpp"
#include "functions/FunctionGripper.hpp"
+#include "functions/FunctionICEngineControl.hpp"
#include "functions/FunctionLandingGear.hpp"
#include "functions/FunctionLandingGearWheel.hpp"
#include "functions/FunctionManualRC.hpp"
diff --git a/src/lib/mixer_module/output_functions.yaml b/src/lib/mixer_module/output_functions.yaml
index a9965a5454..52543add97 100644
--- a/src/lib/mixer_module/output_functions.yaml
+++ b/src/lib/mixer_module/output_functions.yaml
@@ -38,6 +38,11 @@ functions:
Landing_Gear_Wheel: 440
+ IC_Engine_Ignition: 450
+ IC_Engine_Throttle: 451
+ IC_Engine_Choke: 452
+ IC_Engine_Starter: 453
+
# Add your own here:
#MyCustomFunction: 10000
diff --git a/src/lib/parameters/CMakeLists.txt b/src/lib/parameters/CMakeLists.txt
index b87e652cad..81b609080a 100644
--- a/src/lib/parameters/CMakeLists.txt
+++ b/src/lib/parameters/CMakeLists.txt
@@ -62,6 +62,10 @@ if(DISABLE_PARAMS_MODULE_SCOPING)
# allow those timer configurations to be skipped.
if ((${PX4_BOARD_NAME} MATCHES "MODALAI_VOXL2") AND (file_path MATCHES pwm_out))
message(STATUS "Skipping pwm file path ${file_path} for VOXL2")
+ # Spacecraft has duplicate parameter names which kills the VOXL 2 build. VOXL 2 does not
+ # support the spacecraft module so we skip adding the parameters.
+ elseif ((${PX4_BOARD_NAME} MATCHES "MODALAI_VOXL2") AND (file_path MATCHES spacecraft))
+ message(STATUS "Skipping spacecraft file path ${file_path} for VOXL2")
else()
list(APPEND module_config_files "${file_path}")
endif()
diff --git a/src/lib/parameters/flashparams/flashfs32.c b/src/lib/parameters/flashparams/flashfs32.c
index 848623b261..25e97d2563 100644
--- a/src/lib/parameters/flashparams/flashfs32.c
+++ b/src/lib/parameters/flashparams/flashfs32.c
@@ -1128,6 +1128,11 @@ int parameter_flashfs_init(sector_descriptor_t *fconfig, uint8_t *buffer, uint16
if (pf == NULL) {
// Parameters can't be found, assume sector is corrupt or empty
rv = parameter_flashfs_erase();
+
+ // A positive return value means flash space has been erased successfully.
+ if (rv > 0) {
+ rv = 0;
+ }
}
return rv;
diff --git a/src/lib/rc/ghst.cpp b/src/lib/rc/ghst.cpp
index a0bce68718..306004059c 100644
--- a/src/lib/rc/ghst.cpp
+++ b/src/lib/rc/ghst.cpp
@@ -56,6 +56,7 @@
#include
#include
#include
+#include
// TODO: include RSSI dBm to percentage conversion for ghost receiver
#include "spektrum_rssi.h"
@@ -77,8 +78,8 @@ enum class ghst_parser_state_t : uint8_t {
synced
};
-// only RSSI frame contains value of RSSI, if it is not received, send last received RSSI
-static int8_t ghst_rssi = -1;
+// only RSSI frame contains value of RSSI, if it is not received, send last received RSSI/LQ
+static ghstLinkStatistics_t last_link_stats = { .rssi_pct = -1, .rssi_dbm = NAN, .link_quality = 0 };
static ghst_frame_t &ghst_frame = rc_decode_buf.ghst_frame;
static uint32_t current_frame_position = 0U;
@@ -89,7 +90,8 @@ static uint16_t prev_rc_vals[GHST_MAX_NUM_CHANNELS];
/**
* parse the current ghst_frame buffer
*/
-static bool ghst_parse_buffer(uint16_t *values, int8_t *rssi, uint16_t *num_values, uint16_t max_channels);
+static bool ghst_parse_buffer(uint16_t *values, ghstLinkStatistics_t *link_stats, uint16_t *num_values,
+ uint16_t max_channels);
int ghst_config(int uart_fd)
{
@@ -114,7 +116,7 @@ static uint16_t convert_channel_value(unsigned chan_value);
bool ghst_parse(const uint64_t now, const uint8_t *frame, unsigned len, uint16_t *values,
- int8_t *rssi, uint16_t *num_values, uint16_t max_channels)
+ ghstLinkStatistics_t *link_stats, uint16_t *num_values, uint16_t max_channels)
{
bool success = false;
uint8_t *ghst_frame_ptr = (uint8_t *)&ghst_frame;
@@ -145,7 +147,7 @@ bool ghst_parse(const uint64_t now, const uint8_t *frame, unsigned len, uint16_t
len -= current_len;
frame += current_len;
- if (ghst_parse_buffer(values, rssi, num_values, max_channels)) {
+ if (ghst_parse_buffer(values, link_stats, num_values, max_channels)) {
success = true;
}
}
@@ -182,7 +184,8 @@ static uint16_t convert_channel_value(unsigned int chan_value)
return converted_chan_value;
}
-static bool ghst_parse_buffer(uint16_t *values, int8_t *rssi, uint16_t *num_values, uint16_t max_channels)
+static bool ghst_parse_buffer(uint16_t *values, ghstLinkStatistics_t *link_stats, uint16_t *num_values,
+ uint16_t max_channels)
{
uint8_t *ghst_frame_ptr = (uint8_t *)&ghst_frame;
@@ -299,13 +302,16 @@ static bool ghst_parse_buffer(uint16_t *values, int8_t *rssi, uint16_t *num_valu
} else if (ghst_frame.type == static_cast(ghstFrameType::frameTypeRssi)) {
const ghstPayloadRssi_t *const rssiValues = (ghstPayloadRssi_t *)&ghst_frame.payload;
// TODO: call function for RSSI dBm to percentage conversion for ghost receiver
- ghst_rssi = spek_dbm_to_percent(static_cast(rssiValues->rssidBm));
+ last_link_stats.rssi_pct = spek_dbm_to_percent(static_cast
+ (rssiValues->rssidBm)); // rssidBm sign inverted (90 = -90dBm)
+ last_link_stats.rssi_dbm = -rssiValues->rssidBm;
+ last_link_stats.link_quality = rssiValues->lq; // 0 - 100
} else {
GHST_DEBUG("Frame type: %u", ghst_frame.type);
}
- *rssi = ghst_rssi;
+ *link_stats = last_link_stats;
memcpy(prev_rc_vals, values, sizeof(uint16_t) * GHST_MAX_NUM_CHANNELS);
diff --git a/src/lib/rc/ghst.hpp b/src/lib/rc/ghst.hpp
index 6f5a4f4664..c8fbc407c5 100644
--- a/src/lib/rc/ghst.hpp
+++ b/src/lib/rc/ghst.hpp
@@ -106,6 +106,13 @@ typedef struct {
int txPowerdBm: 8; // Tx power [dBm]
} __attribute__((__packed__)) ghstPayloadRssi_t;
+// Link statistics for internal transport
+typedef struct {
+ int8_t rssi_pct;
+ float rssi_dbm;
+ int8_t link_quality;
+} ghstLinkStatistics_t;
+
/**
* Configure an UART port to be used for GHST
* @param uart_fd UART file descriptor
@@ -127,7 +134,7 @@ __EXPORT int ghst_config(int uart_fd);
* @return true if channels successfully decoded
*/
__EXPORT bool ghst_parse(const uint64_t now, const uint8_t *frame, unsigned len, uint16_t *values,
- int8_t *rssi, uint16_t *num_values, uint16_t max_channels);
+ ghstLinkStatistics_t *link_stats, uint16_t *num_values, uint16_t max_channels);
/**
diff --git a/src/lib/rc/rc_tests/RCTest.cpp b/src/lib/rc/rc_tests/RCTest.cpp
index 1997c19e85..4612673b92 100644
--- a/src/lib/rc/rc_tests/RCTest.cpp
+++ b/src/lib/rc/rc_tests/RCTest.cpp
@@ -159,7 +159,7 @@ bool RCTest::ghstTest()
uint16_t rc_values[max_channels];
uint16_t num_values = 0;
int line_counter = 1;
- int8_t ghst_rssi = -1;
+ ghstLinkStatistics_t link_stats;
ghst_config(uart_fd);
while (fgets(line, line_size, fp) != nullptr) {
@@ -186,7 +186,7 @@ bool RCTest::ghstTest()
// Pipe the data into the parser
hrt_abstime now = hrt_absolute_time();
- bool result = ghst_parse(now, frame, frame_len, rc_values, &ghst_rssi, &num_values, max_channels);
+ bool result = ghst_parse(now, frame, frame_len, rc_values, &link_stats, &num_values, max_channels);
if (result) {
has_decoded_values = true;
diff --git a/src/lib/rover_control/RoverControl.cpp b/src/lib/rover_control/RoverControl.cpp
index 7b0864a428..0eafcaa9f8 100644
--- a/src/lib/rover_control/RoverControl.cpp
+++ b/src/lib/rover_control/RoverControl.cpp
@@ -48,26 +48,24 @@ float throttleControl(SlewRate &motor_setpoint, const float throttle_setp
if (accelerating && max_accel > FLT_EPSILON && max_thr_spd > FLT_EPSILON) { // Acceleration slew rate
motor_setpoint.setSlewRate(max_accel / max_thr_spd);
+ motor_setpoint.update(throttle_setpoint, dt);
// Reinitialize slew rate if current value is closer to setpoint than post slew rate value
if (fabsf(motor_setpoint.getState() - current_motor_setpoint) > fabsf(throttle_setpoint -
current_motor_setpoint)) {
- motor_setpoint.setForcedValue(current_motor_setpoint);
+ motor_setpoint.setForcedValue(throttle_setpoint);
}
- motor_setpoint.update(throttle_setpoint, dt);
-
} else if (!accelerating && max_decel > FLT_EPSILON && max_thr_spd > FLT_EPSILON) { // Deceleration slew rate
motor_setpoint.setSlewRate(max_decel / max_thr_spd);
+ motor_setpoint.update(throttle_setpoint, dt);
// Reinitialize slew rate if current value is closer to setpoint than post slew rate value
if (fabsf(motor_setpoint.getState() - current_motor_setpoint) > fabsf(throttle_setpoint -
current_motor_setpoint)) {
- motor_setpoint.setForcedValue(current_motor_setpoint);
+ motor_setpoint.setForcedValue(throttle_setpoint);
}
- motor_setpoint.update(throttle_setpoint, dt);
-
} else { // Fallthrough if slew rate parameters are not configured
motor_setpoint.setForcedValue(throttle_setpoint);
}
@@ -88,14 +86,13 @@ float attitudeControl(SlewRateYaw &adjusted_yaw_setpoint, PID &pid_yaw,
if (yaw_slew_rate > FLT_EPSILON) { // Apply slew rate if configured
adjusted_yaw_setpoint.setSlewRate(yaw_slew_rate);
+ adjusted_yaw_setpoint.update(yaw_setpoint, dt);
// Reinitialize slew rate if current value is closer to setpoint than post slew rate value
if (fabsf(wrap_pi(adjusted_yaw_setpoint.getState() - vehicle_yaw)) > fabsf(wrap_pi(yaw_setpoint - vehicle_yaw))) {
- adjusted_yaw_setpoint.setForcedValue(vehicle_yaw);
+ adjusted_yaw_setpoint.setForcedValue(yaw_setpoint);
}
- adjusted_yaw_setpoint.update(yaw_setpoint, dt);
-
} else {
adjusted_yaw_setpoint.setForcedValue(yaw_setpoint);
}
@@ -118,26 +115,24 @@ float speedControl(SlewRate &speed_with_rate_limit, PID &pid_speed, const
// Apply acceleration and deceleration limit
if (fabsf(speed_setpoint) >= fabsf(vehicle_speed) && max_accel > FLT_EPSILON) {
speed_with_rate_limit.setSlewRate(max_accel);
+ speed_with_rate_limit.update(speed_setpoint, dt);
// Reinitialize slew rate if current value is closer to setpoint than post slew rate value
if (fabsf(speed_with_rate_limit.getState() - vehicle_speed) > fabsf(
speed_setpoint - vehicle_speed)) {
- speed_with_rate_limit.setForcedValue(vehicle_speed);
+ speed_with_rate_limit.setForcedValue(speed_setpoint);
}
- speed_with_rate_limit.update(speed_setpoint, dt);
-
} else if (fabsf(speed_setpoint) < fabsf(vehicle_speed) && max_decel > FLT_EPSILON) {
speed_with_rate_limit.setSlewRate(max_decel);
+ speed_with_rate_limit.update(speed_setpoint, dt);
// Reinitialize slew rate if current value is closer to setpoint than post slew rate value
if (fabsf(speed_with_rate_limit.getState() - vehicle_speed) > fabsf(
speed_setpoint - vehicle_speed)) {
- speed_with_rate_limit.setForcedValue(vehicle_speed);
+ speed_with_rate_limit.setForcedValue(speed_setpoint);
}
- speed_with_rate_limit.update(speed_setpoint, dt);
-
} else { // Fallthrough if slew rate is not configured
speed_with_rate_limit.setForcedValue(speed_setpoint);
}
@@ -153,12 +148,72 @@ float speedControl(SlewRate &speed_with_rate_limit, PID &pid_speed, const
}
// Feedback control
- pid_speed.setSetpoint(speed_with_rate_limit.getState());
- forward_speed_normalized += pid_speed.update(vehicle_speed, dt);
+ if (fabsf(speed_with_rate_limit.getState()) > FLT_EPSILON) {
+ pid_speed.setSetpoint(speed_with_rate_limit.getState());
+ forward_speed_normalized += pid_speed.update(vehicle_speed, dt);
+
+ } else {
+ pid_speed.resetIntegral();
+ }
+
return math::constrain(forward_speed_normalized, -1.f, 1.f);
}
+float rateControl(SlewRate &adjusted_yaw_rate_setpoint, PID &pid_yaw_rate, const float yaw_rate_setpoint,
+ const float vehicle_yaw_rate, const float max_thr_yaw_r, const float max_yaw_accel, const float max_yaw_decel,
+ const float wheel_track, const float dt)
+{
+ // Apply acceleration and deceleration limit
+ if (fabsf(yaw_rate_setpoint) >= fabsf(vehicle_yaw_rate) && max_yaw_accel > FLT_EPSILON) {
+ adjusted_yaw_rate_setpoint.setSlewRate(max_yaw_accel);
+ adjusted_yaw_rate_setpoint.update(yaw_rate_setpoint, dt);
+
+ // Reinitialize slew rate if current value is closer to setpoint than post slew rate value
+ if (fabsf(adjusted_yaw_rate_setpoint.getState() - vehicle_yaw_rate) > fabsf(
+ yaw_rate_setpoint - vehicle_yaw_rate)) {
+ adjusted_yaw_rate_setpoint.setForcedValue(yaw_rate_setpoint);
+ }
+
+
+ } else if (fabsf(yaw_rate_setpoint) < fabsf(vehicle_yaw_rate) && max_yaw_decel > FLT_EPSILON) {
+ adjusted_yaw_rate_setpoint.setSlewRate(max_yaw_decel);
+ adjusted_yaw_rate_setpoint.update(yaw_rate_setpoint, dt);
+
+ // Reinitialize slew rate if current value is closer to setpoint than post slew rate value
+ if (fabsf(adjusted_yaw_rate_setpoint.getState() - vehicle_yaw_rate) > fabsf(
+ yaw_rate_setpoint - vehicle_yaw_rate)) {
+ adjusted_yaw_rate_setpoint.setForcedValue(yaw_rate_setpoint);
+ }
+
+
+ } else { // Fallthrough if slew rate is not configured
+ adjusted_yaw_rate_setpoint.setForcedValue(yaw_rate_setpoint);
+ }
+
+ // Transform yaw rate into speed difference
+ float speed_diff_normalized{0.f};
+
+ if (wheel_track > FLT_EPSILON && max_thr_yaw_r > FLT_EPSILON) { // Feedforward
+ const float speed_diff = adjusted_yaw_rate_setpoint.getState() * wheel_track /
+ 2.f;
+ speed_diff_normalized = math::interpolate(speed_diff, -max_thr_yaw_r,
+ max_thr_yaw_r, -1.f, 1.f);
+ }
+
+ // Feedback control
+ if (fabsf(adjusted_yaw_rate_setpoint.getState()) > FLT_EPSILON) {
+ pid_yaw_rate.setSetpoint(adjusted_yaw_rate_setpoint.getState());
+ speed_diff_normalized += pid_yaw_rate.update(vehicle_yaw_rate, dt);
+
+ } else {
+ pid_yaw_rate.resetIntegral();
+ }
+
+
+ return math::constrain(speed_diff_normalized, -1.f, 1.f);
+}
+
void globalToLocalSetpointTriplet(Vector2f &curr_wp_ned, Vector2f &prev_wp_ned, Vector2f &next_wp_ned,
position_setpoint_triplet_s position_setpoint_triplet, Vector2f &curr_pos_ned, Vector2d &home_pos,
MapProjection &global_ned_proj_ref)
diff --git a/src/lib/rover_control/RoverControl.hpp b/src/lib/rover_control/RoverControl.hpp
index 7f76710225..1196e04650 100644
--- a/src/lib/rover_control/RoverControl.hpp
+++ b/src/lib/rover_control/RoverControl.hpp
@@ -92,6 +92,25 @@ float attitudeControl(SlewRateYaw &adjusted_yaw_setpoint, PID &pid_yaw, f
float speedControl(SlewRate &speed_with_rate_limit, PID &pid_speed, float speed_setpoint,
float vehicle_speed, float max_accel, float max_decel, float max_thr_speed, float dt);
+/**
+ * Applies yaw acceleration slew rate to a yaw rate setpoint and calculates the necessary speed diff setpoint
+ * using a feedforward term and/or a PID controller.
+ * Note: This function is only for rovers that control the rate through a speed difference between the left/right wheels.
+ * @param adjusted_yaw_rate_setpoint Yaw rate setpoint with applied slew rate [-1, 1] (Updated by this function).
+ * @param pid_yaw_rate Yaw rate PID (Updated by this function).
+ * @param yaw_rate_setpoint Yaw rate setpoint [rad/s].
+ * @param vehicle_yaw_rate Measured vehicle yaw rate [rad/s].
+ * @param max_thr_yaw_r Yaw rate turning left/right wheels at max speed in opposite directions [m/s].
+ * @param max_yaw_accel Maximum allowed yaw acceleration [rad/s^2].
+ * @param max_yaw_decel Maximum allowed yaw deceleration [rad/s^2].
+ * @param wheel_track Distance from the center of the right wheel to the center of the left wheel [m].
+ * @param dt Time since last update [s].
+ * @return Normalized speed difference setpoint [-1, 1].
+ */
+float rateControl(SlewRate &adjusted_yaw_rate_setpoint, PID &pid_yaw_rate,
+ float yaw_rate_setpoint, float vehicle_yaw_rate, float max_thr_yaw_r, float max_yaw_accel, float max_yaw_decel,
+ float wheel_track, float dt);
+
/**
* Projects positionSetpointTriplet waypoints from global to ned frame.
* @param curr_wp_ned Current waypoint in NED frame (Updated by this function)
diff --git a/src/lib/rover_control/module.yaml b/src/lib/rover_control/module.yaml
deleted file mode 100644
index 8450a03b06..0000000000
--- a/src/lib/rover_control/module.yaml
+++ /dev/null
@@ -1,191 +0,0 @@
-module_name: Rover Control
-
-parameters:
- - group: Rover Control
- definitions:
- RO_MAX_THR_SPEED:
- description:
- short: Speed the rover drives at maximum throttle
- long: Used to linearly map speeds [m/s] to throttle values [-1. 1].
- type: float
- unit: m/s
- min: 0
- max: 100
- increment: 0.01
- decimal: 2
- default: 0
-
- RO_ACCEL_LIM:
- description:
- short: Acceleration limit
- long: |
- Set to -1 to disable.
- For mecanum rovers this limit is used for longitudinal and lateral acceleration.
- type: float
- unit: m/s^2
- min: -1
- max: 100
- increment: 0.01
- decimal: 2
- default: -1
-
- RO_DECEL_LIM:
- description:
- short: Deceleration limit
- long: |
- Set to -1 to disable.
- Note that if it is disabled the rover will not slow down when approaching waypoints in auto modes.
- For mecanum rovers this limit is used for longitudinal and lateral deceleration.
- type: float
- unit: m/s^2
- min: -1
- max: 100
- increment: 0.01
- decimal: 2
- default: -1
-
- RO_JERK_LIM:
- description:
- short: Jerk limit
- long: |
- Set to -1 to disable.
- Note that if it is disabled the rover will not slow down when approaching waypoints in auto modes.
- For mecanum rovers this limit is used for longitudinal and lateral jerk.
- type: float
- unit: m/s^3
- min: -1
- max: 100
- increment: 0.01
- decimal: 2
- default: -1
-
- RO_YAW_RATE_TH:
- description:
- short: Yaw rate measurement threshold
- long: The minimum threshold for the yaw rate measurement not to be interpreted as zero.
- type: float
- unit: deg/s
- min: 0
- max: 100
- increment: 0.01
- decimal: 2
- default: 3
-
- RO_SPEED_TH:
- description:
- short: Speed measurement threshold
- long: The minimum threshold for the speed measurement not to be interpreted as zero.
- type: float
- unit: m/s
- min: 0
- max: 100
- increment: 0.01
- decimal: 2
- default: 0.1
-
- RO_YAW_STICK_DZ:
- description:
- short: Yaw stick deadzone
- long: Percentage of stick input range that will be interpreted as zero around the stick centered value.
- type: float
- min: 0
- max: 1
- increment: 0.01
- decimal: 2
- default: 0.1
-
- - group: Rover Rate Control
- definitions:
- RO_YAW_RATE_P:
- description:
- short: Proportional gain for closed loop yaw rate controller
- type: float
- min: 0
- max: 100
- increment: 0.01
- decimal: 3
- default: 0
-
- RO_YAW_RATE_I:
- description:
- short: Integral gain for closed loop yaw rate controller
- type: float
- min: 0
- max: 100
- increment: 0.01
- decimal: 3
- default: 0
-
- RO_YAW_RATE_LIM:
- description:
- short: Yaw rate limit
- long: |
- Used to cap yaw rate setpoints and map controller inputs to yaw rate setpoints
- in Acro, Stabilized and Position mode.
- type: float
- unit: deg/s
- min: 0
- max: 10000
- increment: 0.01
- decimal: 2
- default: 0
-
- RO_YAW_ACCEL_LIM:
- description:
- short: Yaw acceleration limit
- long: Set to -1 to disable.
- type: float
- unit: deg/s^2
- min: -1
- max: 10000
- increment: 0.01
- decimal: 2
- default: -1
-
- - group: Rover Attitude Control
- definitions:
- RO_YAW_P:
- description:
- short: Proportional gain for closed loop yaw controller
- type: float
- min: 0
- max: 100
- increment: 0.01
- decimal: 3
- default: 0
-
- - group: Rover Velocity Control
- definitions:
- RO_SPEED_P:
- description:
- short: Proportional gain for ground speed controller
- type: float
- min: 0
- max: 100
- increment: 0.01
- decimal: 2
- default: 0
-
- RO_SPEED_I:
- description:
- short: Integral gain for ground speed controller
- type: float
- min: 0
- max: 100
- increment: 0.001
- decimal: 3
- default: 0
-
- RO_SPEED_LIM:
- description:
- short: Speed limit
- long: |
- Used to cap speed setpoints and map controller inputs to speed setpoints
- in Position mode.
- type: float
- unit: m/s
- min: -1
- max: 100
- increment: 0.01
- decimal: 2
- default: -1
diff --git a/src/lib/rover_control/rovercontrol_params.c b/src/lib/rover_control/rovercontrol_params.c
new file mode 100644
index 0000000000..adee1a69d5
--- /dev/null
+++ b/src/lib/rover_control/rovercontrol_params.c
@@ -0,0 +1,255 @@
+/****************************************************************************
+ *
+ * Copyright (c) 2025 PX4 Development Team. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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.
+ *
+ ****************************************************************************/
+
+/**
+ * @file rovercontrol_params.c
+ *
+ * Parameters defined by the rover control lib.
+ */
+
+/**
+ * Yaw stick deadzone
+ *
+ * Percentage of stick input range that will be interpreted as zero around the stick centered value.
+ *
+ * @min 0
+ * @max 1
+ * @increment 0.01
+ * @decimal 2
+ * @group Rover Rate Control
+ */
+PARAM_DEFINE_FLOAT(RO_YAW_STICK_DZ, 0.1f);
+
+/**
+ * Yaw rate measurement threshold
+ *
+ * The minimum threshold for the yaw rate measurement not to be interpreted as zero.
+ *
+ * @unit deg/s
+ * @min 0
+ * @max 100
+ * @increment 0.01
+ * @decimal 2
+ * @group Rover Rate Control
+ */
+PARAM_DEFINE_FLOAT(RO_YAW_RATE_TH, 3.f);
+
+/**
+ * Proportional gain for closed loop yaw rate controller
+ *
+ * @min 0
+ * @max 100
+ * @increment 0.01
+ * @decimal 3
+ * @group Rover Rate Control
+ */
+PARAM_DEFINE_FLOAT(RO_YAW_RATE_P, 0.f);
+
+/**
+ * Integral gain for closed loop yaw rate controller
+ *
+ * @min 0
+ * @max 100
+ * @increment 0.01
+ * @decimal 3
+ * @group Rover Rate Control
+ */
+PARAM_DEFINE_FLOAT(RO_YAW_RATE_I, 0.f);
+
+/**
+ * Yaw rate limit
+ *
+ * Used to cap yaw rate setpoints and map controller inputs to yaw rate setpoints
+ * in Acro, Stabilized and Position mode.
+ *
+ * @unit deg/s
+ * @min 0
+ * @max 10000
+ * @increment 0.01
+ * @decimal 2
+ * @group Rover Rate Control
+ */
+PARAM_DEFINE_FLOAT(RO_YAW_RATE_LIM, 0.f);
+
+/**
+ * Yaw acceleration limit
+ *
+ * Used to cap how quickly the magnitude of yaw rate setpoints can increase.
+ * Set to -1 to disable.
+ *
+ * @unit deg/s^2
+ * @min -1
+ * @max 10000
+ * @increment 0.01
+ * @decimal 2
+ * @group Rover Rate Control
+ */
+PARAM_DEFINE_FLOAT(RO_YAW_ACCEL_LIM, -1.f);
+
+/**
+ * Yaw deceleration limit
+ *
+ * Used to cap how quickly the magnitude of yaw rate setpoints can decrease.
+ * Set to -1 to disable.
+ *
+ * @unit deg/s^2
+ * @min -1
+ * @max 10000
+ * @increment 0.01
+ * @decimal 2
+ * @group Rover Rate Control
+ */
+PARAM_DEFINE_FLOAT(RO_YAW_DECEL_LIM, -1.f);
+
+/**
+ * Proportional gain for closed loop yaw controller
+ *
+ * @min 0
+ * @max 100
+ * @increment 0.01
+ * @decimal 3
+ * @group Rover Attitude Control
+ */
+PARAM_DEFINE_FLOAT(RO_YAW_P, 0.f);
+
+/**
+ * Speed the rover drives at maximum throttle
+ *
+ * Used to linearly map speeds [m/s] to throttle values [-1. 1].
+ *
+ * @min 0
+ * @max 100
+ * @unit m/s
+ * @increment 0.01
+ * @decimal 2
+ * @group Rover Velocity Control
+ */
+PARAM_DEFINE_FLOAT(RO_MAX_THR_SPEED, 0.f);
+
+/**
+ * Proportional gain for ground speed controller
+ *
+ * @min 0
+ * @max 100
+ * @increment 0.01
+ * @decimal 2
+ * @group Rover Velocity Control
+ */
+PARAM_DEFINE_FLOAT(RO_SPEED_P, 0.f);
+
+/**
+ * Integral gain for ground speed controller
+ *
+ * @min 0
+ * @max 100
+ * @increment 0.001
+ * @decimal 3
+ * @group Rover Velocity Control
+ */
+PARAM_DEFINE_FLOAT(RO_SPEED_I, 0.f);
+
+/**
+ * Speed limit
+ *
+ * Used to cap speed setpoints and map controller inputs to speed setpoints in Position mode.
+ *
+ * @unit m/s
+ * @min -1
+ * @max 100
+ * @increment 0.01
+ * @decimal 2
+ * @group Rover Velocity Control
+ */
+PARAM_DEFINE_FLOAT(RO_SPEED_LIM, -1.f);
+
+/**
+ * Acceleration limit
+ *
+ * Set to -1 to disable.
+ * For mecanum rovers this limit is used for longitudinal and lateral acceleration.
+ *
+ * @unit m/s^2
+ * @min -1
+ * @max 100
+ * @increment 0.01
+ * @decimal 2
+ * @group Rover Velocity Control
+ */
+PARAM_DEFINE_FLOAT(RO_ACCEL_LIM, -1.f);
+
+/**
+ * Deceleration limit
+ *
+ * Set to -1 to disable.
+ * Note that if it is disabled the rover will not slow down when approaching waypoints in auto modes.
+ * For mecanum rovers this limit is used for longitudinal and lateral deceleration.
+ *
+ * @unit m/s^2
+ * @min -1
+ * @max 100
+ * @increment 0.01
+ * @decimal 2
+ * @group Rover Velocity Control
+ */
+PARAM_DEFINE_FLOAT(RO_DECEL_LIM, -1.f);
+
+/**
+ * Jerk limit
+ *
+ * Set to -1 to disable.
+ * Note that if it is disabled the rover will not slow down when approaching waypoints in auto modes.
+ * For mecanum rovers this limit is used for longitudinal and lateral jerk.
+ *
+ * @unit m/s^3
+ * @min -1
+ * @max 100
+ * @increment 0.01
+ * @decimal 2
+ * @group Rover Velocity Control
+ */
+PARAM_DEFINE_FLOAT(RO_JERK_LIM, -1.f);
+
+/**
+ * Speed measurement threshold
+ *
+ * Set to -1 to disable.
+ * The minimum threshold for the speed measurement not to be interpreted as zero.
+ *
+ * @unit m/s
+ * @min 0
+ * @max 100
+ * @increment 0.01
+ * @decimal 2
+ * @group Rover Velocity Control
+ */
+PARAM_DEFINE_FLOAT(RO_SPEED_TH, 0.1f);
diff --git a/src/lib/rtl/rtl_time_estimator.h b/src/lib/rtl/rtl_time_estimator.h
index 8c8519cd9b..7ca79fba1f 100644
--- a/src/lib/rtl/rtl_time_estimator.h
+++ b/src/lib/rtl/rtl_time_estimator.h
@@ -116,7 +116,7 @@ private:
float _time_estimate{0.f}; /**< Accumulated time estimate [s] */
bool _is_valid{false}; /**< Checks if time estimate is valid */
- uint8_t _vehicle_type{vehicle_status_s::VEHICLE_TYPE_UNKNOWN}; /**< the defined vehicle type to use for the calculation*/
+ uint8_t _vehicle_type{vehicle_status_s::VEHICLE_TYPE_ROTARY_WING}; /**< the defined vehicle type to use for the calculation*/
DEFINE_PARAMETERS(
(ParamFloat) _param_rtl_time_factor, /**< Safety factory for safe time estimate */
diff --git a/src/lib/sensor_calibration/Magnetometer.hpp b/src/lib/sensor_calibration/Magnetometer.hpp
index 8d328e7a7d..5f9dd72d43 100644
--- a/src/lib/sensor_calibration/Magnetometer.hpp
+++ b/src/lib/sensor_calibration/Magnetometer.hpp
@@ -85,6 +85,7 @@ public:
int8_t calibration_index() const { return _calibration_index; }
uint32_t device_id() const { return _device_id; }
bool enabled() const { return (_priority > 0); }
+ void disable() { _priority = 0; }
bool external() const { return _external; }
const matrix::Vector3f &offset() const { return _offset; }
const int32_t &priority() const { return _priority; }
diff --git a/src/lib/systemlib/system_params.c b/src/lib/systemlib/system_params.c
index d396039f3f..644e849d9d 100644
--- a/src/lib/systemlib/system_params.c
+++ b/src/lib/systemlib/system_params.c
@@ -240,6 +240,18 @@ PARAM_DEFINE_INT32(SYS_HAS_NUM_ASPD, 0);
*/
PARAM_DEFINE_INT32(SYS_HAS_NUM_DIST, 0);
+/**
+ * Number of optical flow sensors required to be available
+ *
+ * The preflight check will fail if fewer than this number of optical flow sensors with valid data are present.
+ *
+ * @group System
+ * @min 0
+ * @max 1
+ */
+
+PARAM_DEFINE_INT32(SYS_HAS_NUM_OF, 0);
+
/**
* Enable factory calibration mode
*
diff --git a/src/modules/airspeed_selector/airspeed_selector_main.cpp b/src/modules/airspeed_selector/airspeed_selector_main.cpp
index f8012529e1..03b9d48574 100644
--- a/src/modules/airspeed_selector/airspeed_selector_main.cpp
+++ b/src/modules/airspeed_selector/airspeed_selector_main.cpp
@@ -388,7 +388,7 @@ AirspeedModule::Run()
input_data.airspeed_indicated_raw = airspeed_raw.indicated_airspeed_m_s;
input_data.airspeed_true_raw = airspeed_raw.true_airspeed_m_s;
input_data.airspeed_timestamp = airspeed_raw.timestamp;
- input_data.air_temperature_celsius = airspeed_raw.air_temperature_celsius;
+ input_data.air_temperature_celsius = _vehicle_air_data.ambient_temperature;
if (_in_takeoff_situation) {
// set flag to false if either speed is above stall speed,
diff --git a/src/modules/battery_status/battery_status.cpp b/src/modules/battery_status/battery_status.cpp
index 1d104e4087..8d92ad251b 100644
--- a/src/modules/battery_status/battery_status.cpp
+++ b/src/modules/battery_status/battery_status.cpp
@@ -137,9 +137,9 @@ private:
BatteryStatus::BatteryStatus() :
ModuleParams(nullptr),
ScheduledWorkItem(MODULE_NAME, px4::wq_configurations::hp_default),
- _battery1(1, this, SAMPLE_INTERVAL_US, battery_status_s::BATTERY_SOURCE_POWER_MODULE, 0),
+ _battery1(1, this, SAMPLE_INTERVAL_US, battery_status_s::SOURCE_POWER_MODULE, 0),
#if BOARD_NUMBER_BRICKS > 1
- _battery2(2, this, SAMPLE_INTERVAL_US, battery_status_s::BATTERY_SOURCE_POWER_MODULE, 1),
+ _battery2(2, this, SAMPLE_INTERVAL_US, battery_status_s::SOURCE_POWER_MODULE, 1),
#endif
_loop_perf(perf_alloc(PC_ELAPSED, MODULE_NAME))
{
diff --git a/src/modules/commander/Commander.cpp b/src/modules/commander/Commander.cpp
index e303077a90..6d89c3f45e 100644
--- a/src/modules/commander/Commander.cpp
+++ b/src/modules/commander/Commander.cpp
@@ -574,8 +574,7 @@ transition_result_t Commander::arm(arm_disarm_reason_t calling_reason, bool run_
if (!_vehicle_control_mode.flag_control_climb_rate_enabled &&
!_failsafe_flags.manual_control_signal_lost && !_is_throttle_low
- && _vehicle_status.vehicle_type != vehicle_status_s::VEHICLE_TYPE_ROVER
- && _vehicle_status.vehicle_type != vehicle_status_s::VEHICLE_TYPE_BOAT) {
+ && !is_ground_vehicle(_vehicle_status)) {
mavlink_log_critical(&_mavlink_log_pub, "Arming denied: high throttle\t");
events::send(events::ID("commander_arm_denied_throttle_high"), {events::Log::Critical, events::LogInternal::Info},
@@ -700,7 +699,7 @@ Commander::Commander() :
_vehicle_status.system_id = 1;
_vehicle_status.component_id = 1;
_vehicle_status.system_type = 0;
- _vehicle_status.vehicle_type = vehicle_status_s::VEHICLE_TYPE_UNKNOWN;
+ _vehicle_status.vehicle_type = vehicle_status_s::VEHICLE_TYPE_ROTARY_WING;
_vehicle_status.nav_state = _user_mode_intention.get();
_vehicle_status.nav_state_user_intention = _user_mode_intention.get();
_vehicle_status.nav_state_timestamp = hrt_absolute_time();
@@ -1708,7 +1707,7 @@ void Commander::executeActionRequest(const action_request_s &action_request)
case action_request_s::ACTION_SWITCH_MODE:
- if (!_user_mode_intention.change(action_request.mode, ModeChangeSource::User, true)) {
+ if (!_user_mode_intention.change(action_request.mode, ModeChangeSource::User, false)) {
printRejectMode(action_request.mode);
}
@@ -1729,8 +1728,6 @@ void Commander::updateParameters()
_vehicle_status.system_type = value_int32;
}
- _vehicle_status.avoidance_system_required = _param_com_obs_avoid.get();
-
_auto_disarm_killed.set_hysteresis_time_from(false, _param_com_kill_disarm.get() * 1_s);
const bool is_rotary = is_rotary_wing(_vehicle_status) || (is_vtol(_vehicle_status)
@@ -1813,9 +1810,6 @@ void Commander::run()
_status_changed = true;
}
- /* Update OA parameter */
- _vehicle_status.avoidance_system_required = _param_com_obs_avoid.get();
-
handlePowerButtonState();
systemPowerUpdate();
@@ -1908,8 +1902,7 @@ void Commander::run()
_actuator_armed.armed = isArmed();
_actuator_armed.prearmed = getPrearmState();
_actuator_armed.ready_to_arm = _vehicle_status.pre_flight_checks_pass || isArmed();
- _actuator_armed.lockdown = ((_vehicle_status.nav_state == _vehicle_status.NAVIGATION_STATE_TERMINATION)
- || (_vehicle_status.hil_state == vehicle_status_s::HIL_STATE_ON)
+ _actuator_armed.lockdown = ((_vehicle_status.hil_state == vehicle_status_s::HIL_STATE_ON)
|| _multicopter_throw_launch.isThrowLaunchInProgress());
// _actuator_armed.manual_lockdown // action_request_s::ACTION_KILL
_actuator_armed.force_failsafe = (_vehicle_status.nav_state == _vehicle_status.NAVIGATION_STATE_TERMINATION);
@@ -2212,13 +2205,13 @@ void Commander::updateTunes()
} else if (!_vehicle_status.usb_connected &&
(_vehicle_status.hil_state != vehicle_status_s::HIL_STATE_ON) &&
- (_battery_warning == battery_status_s::BATTERY_WARNING_CRITICAL)) {
+ (_battery_warning == battery_status_s::WARNING_CRITICAL)) {
/* play tune on battery critical */
set_tune(tune_control_s::TUNE_ID_BATTERY_WARNING_FAST);
} else if ((_vehicle_status.hil_state != vehicle_status_s::HIL_STATE_ON) &&
- (_battery_warning == battery_status_s::BATTERY_WARNING_LOW)) {
+ (_battery_warning == battery_status_s::WARNING_LOW)) {
/* play tune on battery warning */
set_tune(tune_control_s::TUNE_ID_BATTERY_WARNING_SLOW);
@@ -2512,10 +2505,10 @@ void Commander::control_status_leds(bool changed, const uint8_t battery_warning)
if (_vehicle_status.failsafe) {
led_color = led_control_s::COLOR_PURPLE;
- } else if (battery_warning == battery_status_s::BATTERY_WARNING_LOW) {
+ } else if (battery_warning == battery_status_s::WARNING_LOW) {
led_color = led_control_s::COLOR_AMBER;
- } else if (battery_warning == battery_status_s::BATTERY_WARNING_CRITICAL) {
+ } else if (battery_warning == battery_status_s::WARNING_CRITICAL) {
led_color = led_control_s::COLOR_RED;
} else {
@@ -2828,16 +2821,6 @@ void Commander::dataLinkCheck()
_vehicle_status.open_drone_id_system_present = true;
_vehicle_status.open_drone_id_system_healthy = healthy;
}
-
- if (telemetry.heartbeat_component_obstacle_avoidance) {
- if (_avoidance_system_lost) {
- _avoidance_system_lost = false;
- _status_changed = true;
- }
-
- _datalink_last_heartbeat_avoidance_system = telemetry.timestamp;
- _vehicle_status.avoidance_system_valid = telemetry.avoidance_system_healthy;
- }
}
}
@@ -2889,17 +2872,6 @@ void Commander::dataLinkCheck()
_open_drone_id_system_lost = true;
_status_changed = true;
}
-
- // AVOIDANCE SYSTEM state check (only if it is enabled)
- if (_vehicle_status.avoidance_system_required && !_onboard_controller_lost) {
- // if heartbeats stop
- if (!_avoidance_system_lost && (_datalink_last_heartbeat_avoidance_system > 0)
- && (hrt_elapsed_time(&_datalink_last_heartbeat_avoidance_system) > 5_s)) {
-
- _avoidance_system_lost = true;
- _vehicle_status.avoidance_system_valid = false;
- }
- }
}
void Commander::battery_status_check()
@@ -2907,7 +2879,7 @@ void Commander::battery_status_check()
// Handle shutdown request from emergency battery action
if (_battery_warning != _failsafe_flags.battery_warning) {
- if (_failsafe_flags.battery_warning == battery_status_s::BATTERY_WARNING_EMERGENCY) {
+ if (_failsafe_flags.battery_warning == battery_status_s::WARNING_EMERGENCY) {
#if defined(BOARD_HAS_POWER_CONTROL)
if (!isArmed() && (px4_shutdown_request(60_s) == 0)) {
diff --git a/src/modules/commander/Commander.hpp b/src/modules/commander/Commander.hpp
index f4d1b5eaae..fbfdce886e 100644
--- a/src/modules/commander/Commander.hpp
+++ b/src/modules/commander/Commander.hpp
@@ -241,7 +241,6 @@ private:
Hysteresis _auto_disarm_killed{false};
hrt_abstime _datalink_last_heartbeat_open_drone_id_system{0};
- hrt_abstime _datalink_last_heartbeat_avoidance_system{0};
hrt_abstime _datalink_last_heartbeat_gcs{0};
hrt_abstime _datalink_last_heartbeat_onboard_controller{0};
hrt_abstime _datalink_last_heartbeat_parachute_system{0};
@@ -263,12 +262,11 @@ private:
hrt_abstime _last_health_and_arming_check{0};
- uint8_t _battery_warning{battery_status_s::BATTERY_WARNING_NONE};
+ uint8_t _battery_warning{battery_status_s::WARNING_NONE};
bool _failsafe_user_override_request{false}; ///< override request due to stick movements
bool _open_drone_id_system_lost{true};
- bool _avoidance_system_lost{false};
bool _onboard_controller_lost{false};
bool _parachute_system_lost{true};
@@ -343,7 +341,6 @@ private:
(ParamBool) _param_com_force_safety,
(ParamFloat) _param_com_kill_disarm,
(ParamBool) _param_com_mot_test_en,
- (ParamBool) _param_com_obs_avoid,
(ParamFloat) _param_com_obc_loss_t,
(ParamInt) _param_com_prearm_mode,
(ParamInt) _param_com_rc_override,
diff --git a/src/modules/commander/HealthAndArmingChecks/CMakeLists.txt b/src/modules/commander/HealthAndArmingChecks/CMakeLists.txt
index 7265e042b4..d62d577ca4 100644
--- a/src/modules/commander/HealthAndArmingChecks/CMakeLists.txt
+++ b/src/modules/commander/HealthAndArmingChecks/CMakeLists.txt
@@ -42,6 +42,7 @@ px4_add_library(health_and_arming_checks
checks/batteryCheck.cpp
checks/cpuResourceCheck.cpp
checks/distanceSensorChecks.cpp
+ checks/opticalFlowCheck.cpp
checks/escCheck.cpp
checks/estimatorCheck.cpp
checks/failureDetectorCheck.cpp
diff --git a/src/modules/commander/HealthAndArmingChecks/HealthAndArmingChecks.hpp b/src/modules/commander/HealthAndArmingChecks/HealthAndArmingChecks.hpp
index d04b8d088e..d4f7136f1d 100644
--- a/src/modules/commander/HealthAndArmingChecks/HealthAndArmingChecks.hpp
+++ b/src/modules/commander/HealthAndArmingChecks/HealthAndArmingChecks.hpp
@@ -46,6 +46,7 @@
#include "checks/baroCheck.hpp"
#include "checks/cpuResourceCheck.hpp"
#include "checks/distanceSensorChecks.hpp"
+#include "checks/opticalFlowCheck.hpp"
#include "checks/escCheck.hpp"
#include "checks/estimatorCheck.hpp"
#include "checks/failureDetectorCheck.hpp"
@@ -130,6 +131,7 @@ private:
BaroChecks _baro_checks;
CpuResourceChecks _cpu_resource_checks;
DistanceSensorChecks _distance_sensor_checks;
+ OpticalFlowCheck _optical_flow_check;
EscChecks _esc_checks;
EstimatorChecks _estimator_checks;
FailureDetectorChecks _failure_detector_checks;
@@ -169,6 +171,7 @@ private:
&_baro_checks,
&_cpu_resource_checks,
&_distance_sensor_checks,
+ &_optical_flow_check,
&_esc_checks,
&_estimator_checks,
&_failure_detector_checks,
diff --git a/src/modules/commander/HealthAndArmingChecks/checks/batteryCheck.cpp b/src/modules/commander/HealthAndArmingChecks/checks/batteryCheck.cpp
index 85a19cf550..c20919ba56 100644
--- a/src/modules/commander/HealthAndArmingChecks/checks/batteryCheck.cpp
+++ b/src/modules/commander/HealthAndArmingChecks/checks/batteryCheck.cpp
@@ -39,7 +39,7 @@
using namespace time_literals;
using battery_fault_reason_t = events::px4::enums::battery_fault_reason_t;
-static_assert(battery_status_s::BATTERY_FAULT_COUNT == (static_cast(battery_fault_reason_t::_max) + 1)
+static_assert(battery_status_s::FAULT_COUNT == (static_cast(battery_fault_reason_t::_max) + 1)
, "Battery fault flags mismatch!");
static constexpr const char *battery_fault_reason_str(battery_fault_reason_t battery_fault_reason)
@@ -78,7 +78,7 @@ void BatteryChecks::checkAndReport(const Context &context, Report &reporter)
// Reset related failsafe flags otherwise failures from before disabling the check cause failsafes without reported reason
reporter.failsafeFlags().battery_unhealthy = false;
reporter.failsafeFlags().battery_low_remaining_time = false;
- reporter.failsafeFlags().battery_warning = battery_status_s::BATTERY_WARNING_NONE;
+ reporter.failsafeFlags().battery_warning = battery_status_s::WARNING_NONE;
return;
}
@@ -86,7 +86,7 @@ void BatteryChecks::checkAndReport(const Context &context, Report &reporter)
// There are possibly multiple batteries, and we can't know which ones serve which purpose. So the safest
// option is to check if ANY of them have a warning, and specifically find which one has the most
// urgent warning.
- uint8_t worst_warning = battery_status_s::BATTERY_WARNING_NONE;
+ uint8_t worst_warning = battery_status_s::WARNING_NONE;
float worst_battery_remaining = 1.f;
// To make sure that all connected batteries are being regularly reported, we check which one has the
// oldest timestamp.
@@ -132,7 +132,7 @@ void BatteryChecks::checkAndReport(const Context &context, Report &reporter)
}
// trigger a battery failsafe action if a battery disconnects in flight
- worst_warning = battery_status_s::BATTERY_WARNING_CRITICAL;
+ worst_warning = battery_status_s::WARNING_CRITICAL;
}
if (battery.connected) {
@@ -195,13 +195,13 @@ void BatteryChecks::checkAndReport(const Context &context, Report &reporter)
reporter.failsafeFlags().battery_warning = worst_warning;
}
- const bool battery_warning = reporter.failsafeFlags().battery_warning > battery_status_s::BATTERY_WARNING_NONE
- && reporter.failsafeFlags().battery_warning < battery_status_s::BATTERY_WARNING_FAILED;
+ const bool battery_warning = reporter.failsafeFlags().battery_warning > battery_status_s::WARNING_NONE
+ && reporter.failsafeFlags().battery_warning < battery_status_s::WARNING_FAILED;
const bool configured_arm_threshold_in_use = !context.isArmed() && (_param_com_arm_bat_min.get() >= -FLT_EPSILON);
const bool below_configured_arm_threshold = (worst_battery_remaining < _param_com_arm_bat_min.get());
if (battery_warning || (configured_arm_threshold_in_use && below_configured_arm_threshold)) {
- const bool critical_or_higher = reporter.failsafeFlags().battery_warning >= battery_status_s::BATTERY_WARNING_CRITICAL;
+ const bool critical_or_higher = reporter.failsafeFlags().battery_warning >= battery_status_s::WARNING_CRITICAL;
NavModes affected_modes = (!configured_arm_threshold_in_use && critical_or_higher)
|| (configured_arm_threshold_in_use && below_configured_arm_threshold) ? NavModes::All : NavModes::None;
events::LogLevel log_level = critical_or_higher || below_configured_arm_threshold
@@ -209,7 +209,7 @@ void BatteryChecks::checkAndReport(const Context &context, Report &reporter)
switch (reporter.failsafeFlags().battery_warning) {
default:
- case battery_status_s::BATTERY_WARNING_LOW:
+ case battery_status_s::WARNING_LOW:
/* EVENT
* @description
* The lowest battery state of charge is below the low threshold.
@@ -227,7 +227,7 @@ void BatteryChecks::checkAndReport(const Context &context, Report &reporter)
break;
- case battery_status_s::BATTERY_WARNING_CRITICAL:
+ case battery_status_s::WARNING_CRITICAL:
/* EVENT
* @description
* The lowest battery state of charge is below the critical threshold.
@@ -245,7 +245,7 @@ void BatteryChecks::checkAndReport(const Context &context, Report &reporter)
break;
- case battery_status_s::BATTERY_WARNING_EMERGENCY:
+ case battery_status_s::WARNING_EMERGENCY:
/* EVENT
* @description
* The lowest battery state of charge is below the emergency threshold.
@@ -275,7 +275,7 @@ void BatteryChecks::checkAndReport(const Context &context, Report &reporter)
|| is_required_battery_missing
// No currently-connected batteries have any fault
|| battery_has_fault
- || reporter.failsafeFlags().battery_warning == battery_status_s::BATTERY_WARNING_FAILED;
+ || reporter.failsafeFlags().battery_warning == battery_status_s::WARNING_FAILED;
if (reporter.failsafeFlags().battery_unhealthy
&& !is_required_battery_missing && !battery_has_fault) { // missing batteries and faults are reported above already
diff --git a/src/modules/commander/HealthAndArmingChecks/checks/externalChecks.hpp b/src/modules/commander/HealthAndArmingChecks/checks/externalChecks.hpp
index bbba418000..2efa6896c3 100644
--- a/src/modules/commander/HealthAndArmingChecks/checks/externalChecks.hpp
+++ b/src/modules/commander/HealthAndArmingChecks/checks/externalChecks.hpp
@@ -40,9 +40,6 @@
#include
#include
-static_assert((1ull << arming_check_reply_s::HEALTH_COMPONENT_INDEX_AVOIDANCE) == (uint64_t)
- health_component_t::avoidance, "enum definition missmatch");
-
class ExternalChecks : public HealthAndArmingCheckBase
{
public:
diff --git a/src/modules/commander/HealthAndArmingChecks/checks/magnetometerCheck.cpp b/src/modules/commander/HealthAndArmingChecks/checks/magnetometerCheck.cpp
index 6716a8e06a..ac35a61803 100644
--- a/src/modules/commander/HealthAndArmingChecks/checks/magnetometerCheck.cpp
+++ b/src/modules/commander/HealthAndArmingChecks/checks/magnetometerCheck.cpp
@@ -47,9 +47,6 @@ void MagnetometerChecks::checkAndReport(const Context &context, Report &reporter
int num_enabled_and_valid_calibration = 0;
for (int instance = 0; instance < _sensor_mag_sub.size(); instance++) {
- bool is_mag_fault = false;
- const bool is_required = instance == 0 || isMagRequired(instance, is_mag_fault);
-
const bool exists = _sensor_mag_sub[instance].advertised();
bool is_valid = false;
bool is_calibration_valid = false;
@@ -80,7 +77,9 @@ void MagnetometerChecks::checkAndReport(const Context &context, Report &reporter
}
// Do not raise errors if a mag is not required
- if (!is_required) {
+ bool is_mag_fault = false;
+
+ if (!isMagRequired(instance, is_mag_fault)) {
continue;
}
diff --git a/src/lib/bezier/BezierN.hpp b/src/modules/commander/HealthAndArmingChecks/checks/opticalFlowCheck.cpp
similarity index 56%
rename from src/lib/bezier/BezierN.hpp
rename to src/modules/commander/HealthAndArmingChecks/checks/opticalFlowCheck.cpp
index 7f635e94b5..c01c8cf565 100644
--- a/src/lib/bezier/BezierN.hpp
+++ b/src/modules/commander/HealthAndArmingChecks/checks/opticalFlowCheck.cpp
@@ -1,8 +1,6 @@
-
-
/****************************************************************************
*
- * Copyright (C) 2020 PX4 Development Team. All rights reserved.
+ * Copyright (c) 2025 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,44 +31,38 @@
*
****************************************************************************/
-/**
- * @file BezierN.hpp
- *
- * @author Julian Kent
- *
- * N-order Bezier library designed for time-aware trajectory tracking
- */
+#include "opticalFlowCheck.hpp"
-#pragma once
-#include
-
-namespace bezier
+void OpticalFlowCheck::checkAndReport(const Context &context, Report &reporter)
{
+ if (!_param_sys_has_num_of.get()) {
+ return;
+ }
-/*
- * Calculates the location and velocity with respect to T on a given bezier curve of any order.
- *
- */
-bool calculateBezierPosVel(const matrix::Vector3f *positions, int N, float t,
- matrix::Vector3f &position, matrix::Vector3f &velocity);
+ const bool exists = _vehicle_optical_flow_sub.advertised();
-/*
- * Calculates the position, velocity and acceleration with respect to T on a given bezier curve of any order.
- *
- */
-bool calculateBezierPosVelAcc(const matrix::Vector3f *positions, int N, float t,
- matrix::Vector3f &position, matrix::Vector3f &velocity, matrix::Vector3f &acceleration);
+ if (exists) {
+ vehicle_optical_flow_s flow_sens;
+ const bool valid = _vehicle_optical_flow_sub.copy(&flow_sens) && (hrt_elapsed_time(&flow_sens.timestamp) < 1_s);
+ reporter.setIsPresent(health_component_t::optical_flow);
-/*
- * Calculates the position and velocity of yaw with respect to t on a bezier curve.
- * All yaw setpoints are wrapped relative to the starting yaw.
- *
- */
-bool calculateBezierYaw(const float *setpoints, int N, float t, float &yaw_setpoint, float &yaw_vel_setpoint);
-
-/*
- * Calculates the fraction between the begin and end time which can be used for fast bezier curve lookups
- */
-bool calculateT(int64_t start_time, int64_t end_time, int64_t now, float &T);
+ if (!valid) {
+ /* EVENT
+ */
+ reporter.healthFailure(NavModes::All, health_component_t::optical_flow,
+ events::ID("check_optical_flow_sensor_invalid"),
+ events::Log::Error, "No valid data from optical flow sensor");
+ }
+ } else {
+ /* EVENT
+ * @description
+ *
+ * This check can be configured via SYS_HAS_NUM_OF parameter.
+ *
+ */
+ reporter.healthFailure(NavModes::All, health_component_t::optical_flow,
+ events::ID("check_optical_sensor_missing"),
+ events::Log::Error, "Optical flow sensor missing");
+ }
}
diff --git a/src/drivers/voxl2_io/voxl2_io_serial.hpp b/src/modules/commander/HealthAndArmingChecks/checks/opticalFlowCheck.hpp
similarity index 71%
rename from src/drivers/voxl2_io/voxl2_io_serial.hpp
rename to src/modules/commander/HealthAndArmingChecks/checks/opticalFlowCheck.hpp
index 638bdef288..4eaa47f1f4 100644
--- a/src/drivers/voxl2_io/voxl2_io_serial.hpp
+++ b/src/modules/commander/HealthAndArmingChecks/checks/opticalFlowCheck.hpp
@@ -1,6 +1,6 @@
/****************************************************************************
*
- * Copyright (c) 2020 PX4 Development Team. All rights reserved.
+ * Copyright (c) 2025 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,37 +33,23 @@
#pragma once
-#include
-#include
-#include
-#include
+#include "../Common.hpp"
-#ifdef __PX4_QURT
-#include
-#define FAR
-#endif
+#include
+#include
-class Voxl2IoSerial
+class OpticalFlowCheck : public HealthAndArmingCheckBase
{
public:
- Voxl2IoSerial();
- virtual ~Voxl2IoSerial();
+ OpticalFlowCheck() = default;
+ ~OpticalFlowCheck() = default;
- int uart_open(const char *dev, speed_t speed);
- int uart_set_baud(speed_t speed);
- int uart_close();
- int uart_write(FAR void *buf, size_t len);
- int uart_read(FAR void *buf, size_t len);
- bool is_open() { return _uart_fd >= 0; };
- int uart_get_baud() {return _speed; }
+ void checkAndReport(const Context &context, Report &reporter) override;
private:
- int _uart_fd = -1;
+ uORB::Subscription _vehicle_optical_flow_sub{ORB_ID::vehicle_optical_flow};
-#if ! defined(__PX4_QURT)
- struct termios _orig_cfg;
- struct termios _cfg;
-#endif
-
- int _speed = -1;
+ DEFINE_PARAMETERS_CUSTOM_PARENT(HealthAndArmingCheckBase,
+ (ParamInt) _param_sys_has_num_of
+ )
};
diff --git a/src/modules/commander/HealthAndArmingChecks/checks/powerCheck.cpp b/src/modules/commander/HealthAndArmingChecks/checks/powerCheck.cpp
index 69afd1c12c..a27d17f1be 100644
--- a/src/modules/commander/HealthAndArmingChecks/checks/powerCheck.cpp
+++ b/src/modules/commander/HealthAndArmingChecks/checks/powerCheck.cpp
@@ -36,6 +36,14 @@
using namespace time_literals;
+PowerChecks::PowerChecks()
+{
+ _voltage_low_hysteresis.set_hysteresis_time_from(false, 0_s);
+ _voltage_low_hysteresis.set_hysteresis_time_from(true, 15_s);
+ _voltage_high_hysteresis.set_hysteresis_time_from(false, 0_s);
+ _voltage_high_hysteresis.set_hysteresis_time_from(true, 15_s);
+}
+
void PowerChecks::checkAndReport(const Context &context, Report &reporter)
{
if (circuit_breaker_enabled_by_val(_param_cbrk_supply_chk.get(), CBRK_SUPPLY_CHK_KEY)) {
@@ -77,7 +85,11 @@ void PowerChecks::checkAndReport(const Context &context, Report &reporter)
const float low_error_threshold = 4.7f;
const float high_error_threshold = 5.4f;
- if (avionics_power_rail_voltage < low_error_threshold) {
+ const auto now = hrt_absolute_time();
+ _voltage_low_hysteresis.set_state_and_update(avionics_power_rail_voltage < low_error_threshold, now);
+ _voltage_high_hysteresis.set_state_and_update(avionics_power_rail_voltage > high_error_threshold, now);
+
+ if (_voltage_low_hysteresis.get_state()) {
/* EVENT
* @description
@@ -96,7 +108,7 @@ void PowerChecks::checkAndReport(const Context &context, Report &reporter)
(double)avionics_power_rail_voltage);
}
- } else if (avionics_power_rail_voltage > high_error_threshold) {
+ } else if (_voltage_high_hysteresis.get_state()) {
/* EVENT
* @description
* Check the voltage supply to the FMU, it must be below {2:.2} Volt.
diff --git a/src/modules/commander/HealthAndArmingChecks/checks/powerCheck.hpp b/src/modules/commander/HealthAndArmingChecks/checks/powerCheck.hpp
index b81fadaee0..76d8b9aae0 100644
--- a/src/modules/commander/HealthAndArmingChecks/checks/powerCheck.hpp
+++ b/src/modules/commander/HealthAndArmingChecks/checks/powerCheck.hpp
@@ -35,13 +35,14 @@
#include "../Common.hpp"
+#include
#include
#include
class PowerChecks : public HealthAndArmingCheckBase
{
public:
- PowerChecks() = default;
+ PowerChecks();
~PowerChecks() = default;
void checkAndReport(const Context &context, Report &reporter) override;
@@ -49,6 +50,8 @@ public:
private:
uORB::Subscription _system_power_sub{ORB_ID(system_power)};
bool _overcurrent_warning_sent{false};
+ systemlib::Hysteresis _voltage_low_hysteresis{false};
+ systemlib::Hysteresis _voltage_high_hysteresis{false};
DEFINE_PARAMETERS_CUSTOM_PARENT(HealthAndArmingCheckBase,
(ParamInt) _param_cbrk_supply_chk,
diff --git a/src/modules/commander/HealthAndArmingChecks/checks/systemCheck.cpp b/src/modules/commander/HealthAndArmingChecks/checks/systemCheck.cpp
index 32beaba9af..1f2592c9ed 100644
--- a/src/modules/commander/HealthAndArmingChecks/checks/systemCheck.cpp
+++ b/src/modules/commander/HealthAndArmingChecks/checks/systemCheck.cpp
@@ -121,27 +121,6 @@ void SystemChecks::checkAndReport(const Context &context, Report &reporter)
}
}
- // avoidance system
- if (context.status().avoidance_system_required) {
- if (context.status().avoidance_system_valid) {
- reporter.setIsPresent(health_component_t::avoidance);
-
- } else {
- /* EVENT
- * @description
- *
- * This check can be configured via COM_OBS_AVOID parameter.
- *
- */
- reporter.armingCheckFailure(NavModes::All, health_component_t::system, events::ID("check_system_avoidance_not_ready"),
- events::Log::Error, "Avoidance system not ready");
-
- if (reporter.mavlink_log_pub()) {
- mavlink_log_critical(reporter.mavlink_log_pub(), "Preflight Fail: Avoidance system not ready");
- }
- }
- }
-
// VTOL in transition
if (context.status().is_vtol && !context.isArmed()) {
if (context.status().in_transition_mode) {
diff --git a/src/modules/commander/UserModeIntention.cpp b/src/modules/commander/UserModeIntention.cpp
index 02b4a7f3f7..3a766640ec 100644
--- a/src/modules/commander/UserModeIntention.cpp
+++ b/src/modules/commander/UserModeIntention.cpp
@@ -45,7 +45,6 @@ bool UserModeIntention::change(uint8_t user_intended_nav_state, ModeChangeSource
bool force)
{
_ever_had_mode_change = true;
- _had_mode_change = true;
if (_handler) {
// If a replacement mode is selected, select the internal one instead. The replacement will be selected after.
diff --git a/src/modules/commander/commander_params.c b/src/modules/commander/commander_params.c
index 37dcbdc9a9..44c2f07987 100644
--- a/src/modules/commander/commander_params.c
+++ b/src/modules/commander/commander_params.c
@@ -640,14 +640,6 @@ PARAM_DEFINE_INT32(COM_RCL_EXCEPT, 0);
*/
PARAM_DEFINE_INT32(COM_ACT_FAIL_ACT, 0);
-/**
- * Flag to enable obstacle avoidance.
- *
- * @boolean
- * @group Commander
- */
-PARAM_DEFINE_INT32(COM_OBS_AVOID, 0);
-
/**
* Expect and require a healthy MAVLink parachute system
*
diff --git a/src/modules/commander/failsafe/failsafe.cpp b/src/modules/commander/failsafe/failsafe.cpp
index 3ba1131d97..6e6aee83b2 100644
--- a/src/modules/commander/failsafe/failsafe.cpp
+++ b/src/modules/commander/failsafe/failsafe.cpp
@@ -192,16 +192,16 @@ FailsafeBase::ActionOptions Failsafe::fromBatteryWarningActParam(int param_value
switch (battery_warning) {
default:
- case battery_status_s::BATTERY_WARNING_NONE:
+ case battery_status_s::WARNING_NONE:
options.action = Action::None;
break;
- case battery_status_s::BATTERY_WARNING_LOW:
+ case battery_status_s::WARNING_LOW:
options.action = Action::Warn;
options.cause = Cause::BatteryLow;
break;
- case battery_status_s::BATTERY_WARNING_CRITICAL:
+ case battery_status_s::WARNING_CRITICAL:
options.action = Action::Warn;
options.cause = Cause::BatteryCritical;
@@ -222,7 +222,7 @@ FailsafeBase::ActionOptions Failsafe::fromBatteryWarningActParam(int param_value
break;
- case battery_status_s::BATTERY_WARNING_EMERGENCY:
+ case battery_status_s::WARNING_EMERGENCY:
options.action = Action::Warn;
options.cause = Cause::BatteryEmergency;
@@ -550,21 +550,21 @@ void Failsafe::checkStateAndMode(const hrt_abstime &time_us, const State &state,
_param_com_low_bat_act.get() : (int32_t)LowBatteryAction::Warning;
switch (status_flags.battery_warning) {
- case battery_status_s::BATTERY_WARNING_LOW:
+ case battery_status_s::WARNING_LOW:
_last_state_battery_warning_low = checkFailsafe(_caller_id_battery_warning_low, _last_state_battery_warning_low,
- true, fromBatteryWarningActParam(low_battery_action, battery_status_s::BATTERY_WARNING_LOW));
+ true, fromBatteryWarningActParam(low_battery_action, battery_status_s::WARNING_LOW));
break;
- case battery_status_s::BATTERY_WARNING_CRITICAL:
+ case battery_status_s::WARNING_CRITICAL:
_last_state_battery_warning_critical = checkFailsafe(_caller_id_battery_warning_critical,
_last_state_battery_warning_critical,
- true, fromBatteryWarningActParam(low_battery_action, battery_status_s::BATTERY_WARNING_CRITICAL));
+ true, fromBatteryWarningActParam(low_battery_action, battery_status_s::WARNING_CRITICAL));
break;
- case battery_status_s::BATTERY_WARNING_EMERGENCY:
+ case battery_status_s::WARNING_EMERGENCY:
_last_state_battery_warning_emergency = checkFailsafe(_caller_id_battery_warning_emergency,
_last_state_battery_warning_emergency,
- true, fromBatteryWarningActParam(low_battery_action, battery_status_s::BATTERY_WARNING_EMERGENCY));
+ true, fromBatteryWarningActParam(low_battery_action, battery_status_s::WARNING_EMERGENCY));
break;
default:
diff --git a/src/modules/commander/mag_calibration.cpp b/src/modules/commander/mag_calibration.cpp
index a72f0fcadb..7aeadeab55 100644
--- a/src/modules/commander/mag_calibration.cpp
+++ b/src/modules/commander/mag_calibration.cpp
@@ -903,6 +903,15 @@ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub, int32_t cal_ma
bool param_save = false;
bool failed = true;
+ bool external_mag_available = false;
+
+ for (unsigned cur_mag = 0; cur_mag < MAX_MAGS; cur_mag++) {
+ if (worker_data.calibration[cur_mag].external() && worker_data.calibration[cur_mag].enabled()) {
+ external_mag_available = true;
+ break;
+ }
+ }
+
for (unsigned cur_mag = 0; cur_mag < MAX_MAGS; cur_mag++) {
calibration::Magnetometer ¤t_cal = worker_data.calibration[cur_mag];
@@ -921,6 +930,11 @@ calibrate_return mag_calibrate_all(orb_advert_t *mavlink_log_pub, int32_t cal_ma
current_cal.set_offdiagonal(offdiag[cur_mag]);
}
+ if (external_mag_available && !current_cal.external()) {
+ // automatically disable the internal mags as they should not be used for navigation
+ current_cal.disable();
+ }
+
current_cal.PrintStatus();
if (current_cal.ParametersSave(cur_mag, true)) {
diff --git a/src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessControlSurfaces.cpp b/src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessControlSurfaces.cpp
index 23dee70563..46fea5f33e 100644
--- a/src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessControlSurfaces.cpp
+++ b/src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessControlSurfaces.cpp
@@ -69,15 +69,11 @@ void ActuatorEffectivenessControlSurfaces::updateParams()
{
ModuleParams::updateParams();
- int32_t count = 0;
-
- if (param_get(_count_handle, &count) != 0) {
+ if (param_get(_count_handle, &_count) != PX4_OK) {
PX4_ERR("param_get failed");
return;
}
- _count = count;
-
for (int i = 0; i < _count; i++) {
param_get(_param_handles[i].type, (int32_t *)&_params[i].type);
diff --git a/src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessControlSurfaces.hpp b/src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessControlSurfaces.hpp
index 7047363cc8..5e64e5a738 100644
--- a/src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessControlSurfaces.hpp
+++ b/src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessControlSurfaces.hpp
@@ -107,7 +107,7 @@ private:
param_t _count_handle;
Params _params[MAX_COUNT] {};
- int _count{0};
+ int32_t _count{0};
SlewRate _flaps_setpoint_with_slewrate;
SlewRate _spoilers_setpoint_with_slewrate;
diff --git a/src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessHelicopter.cpp b/src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessHelicopter.cpp
index 643b218c47..967706a6d8 100644
--- a/src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessHelicopter.cpp
+++ b/src/modules/control_allocator/VehicleActuatorEffectiveness/ActuatorEffectivenessHelicopter.cpp
@@ -65,6 +65,7 @@ ActuatorEffectivenessHelicopter::ActuatorEffectivenessHelicopter(ModuleParams *p
_param_handles.yaw_throttle_scale = param_find("CA_HELI_YAW_TH_S");
_param_handles.yaw_ccw = param_find("CA_HELI_YAW_CCW");
_param_handles.spoolup_time = param_find("COM_SPOOLUP_TIME");
+ _param_handles.max_servo_throw = param_find("CA_MAX_SVO_THROW");
updateParams();
}
@@ -73,14 +74,13 @@ void ActuatorEffectivenessHelicopter::updateParams()
{
ModuleParams::updateParams();
- int32_t count = 0;
-
- if (param_get(_param_handles.num_swash_plate_servos, &count) != 0) {
+ if (param_get(_param_handles.num_swash_plate_servos, &_geometry.num_swash_plate_servos) != PX4_OK) {
PX4_ERR("param_get failed");
return;
}
- _geometry.num_swash_plate_servos = math::constrain((int)count, 3, NUM_SWASH_PLATE_SERVOS_MAX);
+ _geometry.num_swash_plate_servos = math::constrain(_geometry.num_swash_plate_servos,
+ (int32_t)3, (int32_t)NUM_SWASH_PLATE_SERVOS_MAX);
for (int i = 0; i < _geometry.num_swash_plate_servos; ++i) {
float angle_deg{};
@@ -102,6 +102,21 @@ void ActuatorEffectivenessHelicopter::updateParams()
int32_t yaw_ccw = 0;
param_get(_param_handles.yaw_ccw, &yaw_ccw);
_geometry.yaw_sign = (yaw_ccw == 1) ? -1.f : 1.f;
+ float max_servo_throw_deg = 0.f;
+ param_get(_param_handles.max_servo_throw, &max_servo_throw_deg);
+
+ if (max_servo_throw_deg > 0.f) {
+ // linearization feature enabled
+ _geometry.linearize_servos = 1;
+ const float max_servo_throw = math::radians(max_servo_throw_deg);
+ _geometry.max_servo_height = sinf(max_servo_throw);
+ _geometry.inverse_max_servo_throw = 1.f / max_servo_throw;
+
+ } else {
+ // handle any undefined behaviour if disabled
+ _geometry.linearize_servos = 0;
+ _geometry.max_servo_height = _geometry.inverse_max_servo_throw = 0.f;
+ }
}
bool ActuatorEffectivenessHelicopter::getEffectivenessMatrix(Configuration &configuration,
@@ -169,6 +184,11 @@ void ActuatorEffectivenessHelicopter::updateSetpoint(const matrix::Vector", "Storage file", true);
+#endif
PRINT_MODULE_USAGE_PARAM_FLAG('r', "Use RAM backend (NOT persistent)", true);
+#ifdef CONFIG_DATAMAN_PERSISTENT_STORAGE
PRINT_MODULE_USAGE_PARAM_COMMENT("The options -f and -r are mutually exclusive. If nothing is specified, a file 'dataman' is used");
+#endif
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
}
@@ -930,9 +956,14 @@ dataman_main(int argc, char *argv[])
return -1;
}
+#ifdef CONFIG_DATAMAN_PERSISTENT_STORAGE
backend = BACKEND_FILE;
k_data_manager_device_path = strdup(dmoptarg);
PX4_INFO("dataman file set to: %s", k_data_manager_device_path);
+#else
+ backend = BACKEND_RAM;
+ PX4_WARN("dataman does not support persistent storage. Falling back to RAM.");
+#endif
break;
case 'r':
@@ -951,16 +982,22 @@ dataman_main(int argc, char *argv[])
}
if (backend == BACKEND_NONE) {
+#ifdef CONFIG_DATAMAN_PERSISTENT_STORAGE
backend = BACKEND_FILE;
k_data_manager_device_path = strdup(default_device_path);
+#else
+ backend = BACKEND_RAM;
+#endif
}
start();
if (!is_running()) {
PX4_ERR("dataman start failed");
+#ifdef CONFIG_DATAMAN_PERSISTENT_STORAGE
free(k_data_manager_device_path);
k_data_manager_device_path = nullptr;
+#endif
return -1;
}
@@ -976,8 +1013,10 @@ dataman_main(int argc, char *argv[])
if (!strcmp(argv[1], "stop")) {
stop();
+#ifdef CONFIG_DATAMAN_PERSISTENT_STORAGE
free(k_data_manager_device_path);
k_data_manager_device_path = nullptr;
+#endif
} else if (!strcmp(argv[1], "status")) {
status();
diff --git a/src/modules/ekf2/CMakeLists.txt b/src/modules/ekf2/CMakeLists.txt
index 112b920ba2..181978792c 100644
--- a/src/modules/ekf2/CMakeLists.txt
+++ b/src/modules/ekf2/CMakeLists.txt
@@ -38,6 +38,7 @@ execute_process(
COMMAND ${PYTHON_EXECUTABLE} -m symforce.symbolic
RESULT_VARIABLE PYTHON_SYMFORCE_EXIT_CODE
OUTPUT_QUIET
+ ERROR_QUIET
)
# for now only provide symforce target helper if derivation.py generation isn't default
diff --git a/src/modules/ekf2/EKF/aid_sources/aux_global_position/aux_global_position.cpp b/src/modules/ekf2/EKF/aid_sources/aux_global_position/aux_global_position.cpp
index 3307dd56b9..675bffdd3c 100644
--- a/src/modules/ekf2/EKF/aid_sources/aux_global_position/aux_global_position.cpp
+++ b/src/modules/ekf2/EKF/aid_sources/aux_global_position/aux_global_position.cpp
@@ -104,9 +104,20 @@ void AuxGlobalPosition::update(Ekf &ekf, const estimator::imuSample &imu_delayed
_state = State::starting;
if (ekf.global_origin_valid()) {
- ekf.enableControlStatusAuxGpos();
- _reset_counters.lat_lon = sample.lat_lon_reset_counter;
- _state = State::active;
+ const bool fused = ekf.fuseHorizontalPosition(aid_src);
+ bool reset = false;
+
+ if (!fused && !ekf.isOtherSourceOfHorizontalPositionAidingThan(ekf.control_status_flags().aux_gpos)) {
+ ekf.resetGlobalPositionTo(sample.latitude, sample.longitude, sample.altitude_amsl, pos_var, sq(sample.epv));
+ ekf.resetAidSourceStatusZeroInnovation(aid_src);
+ reset = true;
+ }
+
+ if (fused || reset) {
+ ekf.enableControlStatusAuxGpos();
+ _reset_counters.lat_lon = sample.lat_lon_reset_counter;
+ _state = State::active;
+ }
} else {
// Try to initialize using measurement
@@ -128,12 +139,18 @@ void AuxGlobalPosition::update(Ekf &ekf, const estimator::imuSample &imu_delayed
if (isTimedOut(aid_src.time_last_fuse, imu_delayed.time_us, ekf._params.no_aid_timeout_max)
|| (_reset_counters.lat_lon != sample.lat_lon_reset_counter)) {
+ if (ekf.isOnlyActiveSourceOfHorizontalPositionAiding(ekf.control_status_flags().aux_gpos)) {
- ekf.resetHorizontalPositionTo(sample.latitude, sample.longitude, Vector2f(aid_src.observation_variance));
+ ekf.resetHorizontalPositionTo(sample.latitude, sample.longitude, Vector2f(aid_src.observation_variance));
- ekf.resetAidSourceStatusZeroInnovation(aid_src);
+ ekf.resetAidSourceStatusZeroInnovation(aid_src);
- _reset_counters.lat_lon = sample.lat_lon_reset_counter;
+ _reset_counters.lat_lon = sample.lat_lon_reset_counter;
+
+ } else {
+ ekf.disableControlStatusAuxGpos();
+ _state = State::stopped;
+ }
}
} else {
diff --git a/src/modules/ekf2/EKF/estimator_interface.cpp b/src/modules/ekf2/EKF/estimator_interface.cpp
index 84ced94c80..22ccf958f0 100644
--- a/src/modules/ekf2/EKF/estimator_interface.cpp
+++ b/src/modules/ekf2/EKF/estimator_interface.cpp
@@ -600,12 +600,32 @@ bool EstimatorInterface::isOtherSourceOfHorizontalAidingThan(const bool aiding_f
}
int EstimatorInterface::getNumberOfActiveHorizontalAidingSources() const
+{
+ return getNumberOfActiveHorizontalPositionAidingSources() + getNumberOfActiveHorizontalVelocityAidingSources();
+}
+
+bool EstimatorInterface::isOnlyActiveSourceOfHorizontalPositionAiding(const bool aiding_flag) const
+{
+ return aiding_flag && !isOtherSourceOfHorizontalPositionAidingThan(aiding_flag);
+}
+
+bool EstimatorInterface::isOtherSourceOfHorizontalPositionAidingThan(const bool aiding_flag) const
+{
+ const int nb_sources = getNumberOfActiveHorizontalPositionAidingSources();
+ return aiding_flag ? nb_sources > 1 : nb_sources > 0;
+}
+
+int EstimatorInterface::getNumberOfActiveHorizontalPositionAidingSources() const
{
return int(_control_status.flags.gps)
- + int(_control_status.flags.opt_flow)
+ int(_control_status.flags.ev_pos)
+ + int(_control_status.flags.aux_gpos);
+}
+
+int EstimatorInterface::getNumberOfActiveHorizontalVelocityAidingSources() const
+{
+ return int(_control_status.flags.opt_flow)
+ int(_control_status.flags.ev_vel)
- + int(_control_status.flags.aux_gpos)
// Combined airspeed and sideslip fusion allows sustained wind relative dead reckoning
// and so is treated as a single aiding source.
+ int(_control_status.flags.fuse_aspd && _control_status.flags.fuse_beta);
diff --git a/src/modules/ekf2/EKF/estimator_interface.h b/src/modules/ekf2/EKF/estimator_interface.h
index 1212300278..93632bc109 100644
--- a/src/modules/ekf2/EKF/estimator_interface.h
+++ b/src/modules/ekf2/EKF/estimator_interface.h
@@ -207,8 +207,8 @@ public:
// set air density used by the multi-rotor specific drag force fusion
void set_air_density(float air_density) { _air_density = air_density; }
- // the flags considered are opt_flow, gps, ev_vel and ev_pos
bool isOnlyActiveSourceOfHorizontalAiding(bool aiding_flag) const;
+ bool isOnlyActiveSourceOfHorizontalPositionAiding(bool aiding_flag) const;
/*
* Check if there are any other active source of horizontal aiding
@@ -221,6 +221,7 @@ public:
* @return true if an other source than aiding_flag is active
*/
bool isOtherSourceOfHorizontalAidingThan(bool aiding_flag) const;
+ bool isOtherSourceOfHorizontalPositionAidingThan(bool aiding_flag) const;
// Return true if at least one source of horizontal aiding is active
// the flags considered are opt_flow, gps, ev_vel and ev_pos
@@ -228,6 +229,8 @@ public:
bool isVerticalAidingActive() const;
int getNumberOfActiveHorizontalAidingSources() const;
+ int getNumberOfActiveHorizontalPositionAidingSources() const;
+ int getNumberOfActiveHorizontalVelocityAidingSources() const;
bool isOtherSourceOfVerticalPositionAidingThan(bool aiding_flag) const;
bool isVerticalPositionAidingActive() const;
diff --git a/src/modules/esc_battery/EscBattery.cpp b/src/modules/esc_battery/EscBattery.cpp
index 0fb4a3efad..78d1c2c71f 100644
--- a/src/modules/esc_battery/EscBattery.cpp
+++ b/src/modules/esc_battery/EscBattery.cpp
@@ -40,7 +40,7 @@ using namespace time_literals;
EscBattery::EscBattery() :
ModuleParams(nullptr),
WorkItem(MODULE_NAME, px4::wq_configurations::lp_default),
- _battery(1, this, ESC_BATTERY_INTERVAL_US, battery_status_s::BATTERY_SOURCE_ESCS)
+ _battery(1, this, ESC_BATTERY_INTERVAL_US, battery_status_s::SOURCE_ESCS)
{
}
diff --git a/src/modules/events/set_leds.cpp b/src/modules/events/set_leds.cpp
index 20541f6fbb..88c2ed43d0 100644
--- a/src/modules/events/set_leds.cpp
+++ b/src/modules/events/set_leds.cpp
@@ -101,12 +101,12 @@ void StatusDisplay::set_leds()
}
// handle battery warnings, once a state is reached it can not be reset
- if (_battery_status_sub.get().warning == battery_status_s::BATTERY_WARNING_CRITICAL || _critical_battery) {
+ if (_battery_status_sub.get().warning == battery_status_s::WARNING_CRITICAL || _critical_battery) {
_led_control.color = led_control_s::COLOR_RED;
_led_control.mode = led_control_s::MODE_BLINK_FAST;
_critical_battery = true;
- } else if (_battery_status_sub.get().warning == battery_status_s::BATTERY_WARNING_LOW || _low_battery) {
+ } else if (_battery_status_sub.get().warning == battery_status_s::WARNING_LOW || _low_battery) {
_led_control.color = led_control_s::COLOR_RED;
_led_control.mode = led_control_s::MODE_FLASH;
_low_battery = true;
diff --git a/src/modules/flight_mode_manager/tasks/Auto/CMakeLists.txt b/src/modules/flight_mode_manager/tasks/Auto/CMakeLists.txt
index 2fadf2754d..905e08e80b 100644
--- a/src/modules/flight_mode_manager/tasks/Auto/CMakeLists.txt
+++ b/src/modules/flight_mode_manager/tasks/Auto/CMakeLists.txt
@@ -35,5 +35,5 @@ px4_add_library(FlightTaskAuto
FlightTaskAuto.cpp
)
-target_link_libraries(FlightTaskAuto PUBLIC avoidance FlightTask FlightTaskUtility WeatherVane)
+target_link_libraries(FlightTaskAuto PUBLIC FlightTask FlightTaskUtility WeatherVane)
target_include_directories(FlightTaskAuto PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/src/modules/flight_mode_manager/tasks/Auto/FlightTaskAuto.cpp b/src/modules/flight_mode_manager/tasks/Auto/FlightTaskAuto.cpp
index 8e19ffd5a3..5cb75222a0 100644
--- a/src/modules/flight_mode_manager/tasks/Auto/FlightTaskAuto.cpp
+++ b/src/modules/flight_mode_manager/tasks/Auto/FlightTaskAuto.cpp
@@ -156,17 +156,11 @@ bool FlightTaskAuto::update()
break;
}
- if (_param_com_obs_avoid.get()) {
- _obstacle_avoidance.updateAvoidanceDesiredSetpoints(_position_setpoint, _velocity_setpoint, (int)_type);
- _obstacle_avoidance.injectAvoidanceSetpoints(_position_setpoint, _velocity_setpoint, _yaw_setpoint,
- _yawspeed_setpoint);
- }
-
_checkEmergencyBraking();
Vector3f waypoints[] = {_prev_wp, _position_setpoint, _next_wp};
if (isTargetModified()) {
- // In case object avoidance has injected a new setpoint, we take this as the next waypoints
+ // In case the target has been modified, we take this as the next waypoints
waypoints[2] = _position_setpoint;
}
@@ -259,9 +253,15 @@ void FlightTaskAuto::_prepareLandSetpoints()
// Stick full up -1 -> stop, stick full down 1 -> double the speed
vertical_speed *= (1 - _sticks.getThrottleZeroCenteredExpo());
+ Vector2f sticks_xy = _sticks.getPitchRollExpo();
+
+ if (sticks_xy.longerThan(FLT_EPSILON)) {
+ // Ensure no unintended yawing when nudging horizontally during initial heading alignment
+ _land_heading = _yaw_sp_prev;
+ }
+
rcHelpModifyYaw(_land_heading);
- Vector2f sticks_xy = _sticks.getPitchRollExpo();
Vector2f sticks_ne = sticks_xy;
Sticks::rotateIntoHeadingFrameXY(sticks_ne, _yaw, _land_heading);
@@ -477,17 +477,6 @@ bool FlightTaskAuto::_evaluateTriplets()
_updateInternalWaypoints();
}
- if (_param_com_obs_avoid.get()
- && _sub_vehicle_status.get().vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING) {
- _obstacle_avoidance.updateAvoidanceDesiredWaypoints(_triplet_target, _yaw_setpoint, _yawspeed_setpoint,
- _triplet_next_wp,
- _sub_triplet_setpoint.get().next.yaw,
- (float)NAN,
- _weathervane.isActive(), _sub_triplet_setpoint.get().current.type);
- _obstacle_avoidance.checkAvoidanceProgress(
- _position, _triplet_prev_wp, _target_acceptance_radius, Vector2f(_closest_pt));
- }
-
// set heading
_weathervane.update();
diff --git a/src/modules/flight_mode_manager/tasks/Auto/FlightTaskAuto.hpp b/src/modules/flight_mode_manager/tasks/Auto/FlightTaskAuto.hpp
index 90a98cac23..6c49dd8726 100644
--- a/src/modules/flight_mode_manager/tasks/Auto/FlightTaskAuto.hpp
+++ b/src/modules/flight_mode_manager/tasks/Auto/FlightTaskAuto.hpp
@@ -53,13 +53,6 @@
#include "StickAccelerationXY.hpp"
#include "StickYaw.hpp"
-// TODO: make this switchable in the board config, like a module
-#if CONSTRAINED_FLASH
-#include
-#else
-#include
-#endif
-
/**
* This enum has to agree with position_setpoint_s type definition
* The only reason for not using the struct position_setpoint is because
@@ -147,8 +140,6 @@ protected:
AlphaFilter _yawspeed_filter;
bool _yaw_sp_aligned{false};
- ObstacleAvoidance _obstacle_avoidance{this}; /**< class adjusting setpoints according to external avoidance module's input */
-
PositionSmoothing _position_smoothing;
Vector3f _unsmoothed_velocity_setpoint;
Sticks _sticks{this};
@@ -165,7 +156,6 @@ protected:
(ParamFloat)
_param_nav_mc_alt_rad, //vertical acceptance radius at which waypoints are updated
(ParamInt) _param_mpc_yaw_mode, // defines how heading is executed,
- (ParamInt) _param_com_obs_avoid, // obstacle avoidance active
(ParamFloat) _param_mpc_yawrauto_max,
(ParamFloat) _param_mis_yaw_err, // yaw-error threshold
(ParamFloat) _param_mpc_acc_hor, // acceleration in flight
diff --git a/src/modules/flight_mode_manager/tasks/ManualAccelerationSlow/FlightTaskManualAccelerationSlow.cpp b/src/modules/flight_mode_manager/tasks/ManualAccelerationSlow/FlightTaskManualAccelerationSlow.cpp
index 7b1c24f1dd..dd2ca1da59 100644
--- a/src/modules/flight_mode_manager/tasks/ManualAccelerationSlow/FlightTaskManualAccelerationSlow.cpp
+++ b/src/modules/flight_mode_manager/tasks/ManualAccelerationSlow/FlightTaskManualAccelerationSlow.cpp
@@ -39,6 +39,7 @@
#include
using namespace time_literals;
+using namespace matrix;
bool FlightTaskManualAccelerationSlow::update()
{
@@ -128,7 +129,29 @@ bool FlightTaskManualAccelerationSlow::update()
FlightTaskManualAltitude::_velocity_constraint_down = velocity_down;
FlightTaskManualAcceleration::_stick_yaw.setYawspeedConstraint(yaw_rate);
- return FlightTaskManualAcceleration::update();
+ bool ret = FlightTaskManualAcceleration::update();
+
+ // Optimize input-to-video latency gimbal control
+ if (_gimbal.checkForTelemetry(_time_stamp_current) && haveTakenOff()) {
+ _gimbal.acquireGimbalControlIfNeeded();
+
+ // the exact same _yawspeed_setpoint is setpoint for the gimbal and vehicle feed-forward
+ const float pitchrate_setpoint = getInputFromSanitizedAuxParameterIndex(_param_mc_slow_map_pitch.get()) * yaw_rate;
+ _yawspeed_setpoint = _sticks.getYaw() * yaw_rate;
+
+ _gimbal.publishGimbalManagerSetAttitude(Gimbal::FLAGS_ALL_AXES_LOCKED, Quatf(NAN, NAN, NAN, NAN),
+ Vector3f(NAN, pitchrate_setpoint, _yawspeed_setpoint));
+
+ if (_gimbal.allAxesLockedConfirmed()) {
+ // but the vehicle makes sure it stays alligned with the gimbal absolute yaw
+ _yaw_setpoint = _gimbal.getTelemetryYaw();
+ }
+
+ } else {
+ _gimbal.releaseGimbalControlIfNeeded();
+ }
+
+ return ret;
}
float FlightTaskManualAccelerationSlow::getInputFromSanitizedAuxParameterIndex(int parameter_value)
@@ -136,3 +159,11 @@ float FlightTaskManualAccelerationSlow::getInputFromSanitizedAuxParameterIndex(i
const int sanitized_index = math::constrain(parameter_value - 1, 0, 5);
return _sticks.getAux()(sanitized_index);
}
+
+bool FlightTaskManualAccelerationSlow::haveTakenOff()
+{
+ takeoff_status_s takeoff_status{};
+ _takeoff_status_sub.copy(&takeoff_status);
+
+ return takeoff_status.takeoff_state == takeoff_status_s::TAKEOFF_STATE_FLIGHT;
+}
diff --git a/src/modules/flight_mode_manager/tasks/ManualAccelerationSlow/FlightTaskManualAccelerationSlow.hpp b/src/modules/flight_mode_manager/tasks/ManualAccelerationSlow/FlightTaskManualAccelerationSlow.hpp
index b54d9b765d..66b2de4a8f 100644
--- a/src/modules/flight_mode_manager/tasks/ManualAccelerationSlow/FlightTaskManualAccelerationSlow.hpp
+++ b/src/modules/flight_mode_manager/tasks/ManualAccelerationSlow/FlightTaskManualAccelerationSlow.hpp
@@ -42,6 +42,7 @@
#include "FlightTaskManualAcceleration.hpp"
#include "StickAccelerationXY.hpp"
+#include "Gimbal.hpp"
#include
#include
@@ -67,9 +68,15 @@ private:
bool _velocity_limits_received_before{false};
+ // Gimbal control
+ Gimbal _gimbal{this};
+
uORB::Subscription _velocity_limits_sub{ORB_ID(velocity_limits)};
velocity_limits_s _velocity_limits{};
+ uORB::Subscription _takeoff_status_sub{ORB_ID(takeoff_status)};
+ bool haveTakenOff();
+
DEFINE_PARAMETERS_CUSTOM_PARENT(FlightTaskManualAcceleration,
(ParamInt) _param_mc_slow_map_hvel,
(ParamInt) _param_mc_slow_map_vvel,
@@ -83,6 +90,7 @@ private:
(ParamFloat) _param_mpc_vel_manual,
(ParamFloat) _param_mpc_z_vel_max_up,
(ParamFloat) _param_mpc_z_vel_max_dn,
- (ParamFloat) _param_mpc_man_y_max
+ (ParamFloat) _param_mpc_man_y_max,
+ (ParamInt) _param_mc_slow_map_pitch
)
};
diff --git a/src/modules/flight_mode_manager/tasks/ManualAccelerationSlow/flight_task_acceleration_slow_params.c b/src/modules/flight_mode_manager/tasks/ManualAccelerationSlow/flight_task_acceleration_slow_params.c
index 4c643d87d8..32558d98ea 100644
--- a/src/modules/flight_mode_manager/tasks/ManualAccelerationSlow/flight_task_acceleration_slow_params.c
+++ b/src/modules/flight_mode_manager/tasks/ManualAccelerationSlow/flight_task_acceleration_slow_params.c
@@ -156,3 +156,17 @@ PARAM_DEFINE_FLOAT(MC_SLOW_DEF_VVEL, 1.f);
* @group Multicopter Position Slow Mode
*/
PARAM_DEFINE_FLOAT(MC_SLOW_DEF_YAWR, 45.f);
+
+/**
+ * RC_MAP_AUX{N} to allow for gimbal pitch rate control in position slow mode
+ *
+ * @value 0 No pitch rate input
+ * @value 1 AUX1
+ * @value 2 AUX2
+ * @value 3 AUX3
+ * @value 4 AUX4
+ * @value 5 AUX5
+ * @value 6 AUX6
+ * @group Multicopter Position Slow Mode
+ */
+PARAM_DEFINE_INT32(MC_SLOW_MAP_PTCH, 0);
diff --git a/src/modules/flight_mode_manager/tasks/ManualAltitude/FlightTaskManualAltitude.cpp b/src/modules/flight_mode_manager/tasks/ManualAltitude/FlightTaskManualAltitude.cpp
index 7ea9289cb6..ed7676296f 100644
--- a/src/modules/flight_mode_manager/tasks/ManualAltitude/FlightTaskManualAltitude.cpp
+++ b/src/modules/flight_mode_manager/tasks/ManualAltitude/FlightTaskManualAltitude.cpp
@@ -129,6 +129,7 @@ void FlightTaskManualAltitude::_updateAltitudeLock()
} else {
_position_setpoint(2) = _position(2);
+ _dist_to_ground_lock = NAN;
}
}
diff --git a/src/modules/flight_mode_manager/tasks/ManualPosition/FlightTaskManualPosition.hpp b/src/modules/flight_mode_manager/tasks/ManualPosition/FlightTaskManualPosition.hpp
index fb7f5dd4e5..b1f05092d3 100644
--- a/src/modules/flight_mode_manager/tasks/ManualPosition/FlightTaskManualPosition.hpp
+++ b/src/modules/flight_mode_manager/tasks/ManualPosition/FlightTaskManualPosition.hpp
@@ -68,5 +68,5 @@ private:
uint8_t _reset_counter{0}; /**< counter for estimator resets in xy-direction */
WeatherVane _weathervane{this}; /**< weathervane library, used to implement a yaw control law that turns the vehicle nose into the wind */
- CollisionPrevention _collision_prevention{this}; /**< collision avoidance setpoint amendment */
+ CollisionPrevention _collision_prevention{this}; /**< collision prevention setpoint amendment */
};
diff --git a/src/modules/flight_mode_manager/tasks/Utility/CMakeLists.txt b/src/modules/flight_mode_manager/tasks/Utility/CMakeLists.txt
index 911da11d26..44a5e1dba1 100644
--- a/src/modules/flight_mode_manager/tasks/Utility/CMakeLists.txt
+++ b/src/modules/flight_mode_manager/tasks/Utility/CMakeLists.txt
@@ -36,9 +36,10 @@ px4_add_library(FlightTaskUtility
StickAccelerationXY.cpp
StickTiltXY.cpp
StickYaw.cpp
+ Gimbal.cpp
)
-target_link_libraries(FlightTaskUtility PUBLIC FlightTask hysteresis bezier SlewRate motion_planning mathlib)
+target_link_libraries(FlightTaskUtility PUBLIC FlightTask hysteresis SlewRate motion_planning mathlib)
target_include_directories(FlightTaskUtility PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
px4_add_functional_gtest(SRC StickTiltXYTest.cpp LINKLIBS FlightTaskUtility)
diff --git a/src/modules/flight_mode_manager/tasks/Utility/Gimbal.cpp b/src/modules/flight_mode_manager/tasks/Utility/Gimbal.cpp
new file mode 100644
index 0000000000..21e97f5fc3
--- /dev/null
+++ b/src/modules/flight_mode_manager/tasks/Utility/Gimbal.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+ *
+ * Copyright (c) 2025 PX4 Development Team. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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.
+ *
+ ****************************************************************************/
+
+#include "Gimbal.hpp"
+#include
+
+using namespace time_literals;
+using namespace matrix;
+
+Gimbal::Gimbal(ModuleParams *parent) :
+ ModuleParams(parent)
+{}
+
+Gimbal::~Gimbal()
+{
+ releaseGimbalControlIfNeeded();
+}
+
+bool Gimbal::checkForTelemetry(const hrt_abstime now)
+{
+ if (_gimbal_device_attitude_status_sub.updated()) {
+ gimbal_device_attitude_status_s gimbal_device_attitude_status{};
+
+ if (_gimbal_device_attitude_status_sub.copy(&gimbal_device_attitude_status)) {
+ _telemtry_timestamp = gimbal_device_attitude_status.timestamp;
+ _telemetry_flags = gimbal_device_attitude_status.device_flags;
+ _telemetry_yaw = Eulerf(Quatf(gimbal_device_attitude_status.q)).psi();
+ }
+ }
+
+ return now < _telemtry_timestamp + 2_s;
+}
+
+void Gimbal::acquireGimbalControlIfNeeded()
+{
+ if (!_have_gimbal_control) {
+ _have_gimbal_control = true;
+
+ vehicle_command_s vehicle_command{};
+ vehicle_command.command = vehicle_command_s::VEHICLE_CMD_DO_GIMBAL_MANAGER_CONFIGURE;
+ vehicle_command.param1 = _param_mav_sys_id.get();
+ vehicle_command.param2 = _param_mav_comp_id.get();
+ vehicle_command.param3 = -1.0f; // Leave unchanged.
+ vehicle_command.param4 = -1.0f; // Leave unchanged.
+ vehicle_command.timestamp = hrt_absolute_time();
+ vehicle_command.source_system = _param_mav_sys_id.get();
+ vehicle_command.source_component = _param_mav_comp_id.get();
+ vehicle_command.target_system = _param_mav_sys_id.get();
+ vehicle_command.target_component = _param_mav_sys_id.get();
+ vehicle_command.from_external = false;
+ _vehicle_command_pub.publish(vehicle_command);
+ }
+}
+
+void Gimbal::releaseGimbalControlIfNeeded()
+{
+ if (_have_gimbal_control) {
+ _have_gimbal_control = false;
+
+ // Restore default flags, setting rate setpoints to NAN lead to unexpected behavior
+ publishGimbalManagerSetAttitude(FLAGS_ROLL_PITCH_LOCKED,
+ Quatf(NAN, NAN, NAN, NAN),
+ Vector3f(NAN, 0.f, 0.f));
+
+ // Release gimbal
+ vehicle_command_s vehicle_command{};
+ vehicle_command.command = vehicle_command_s::VEHICLE_CMD_DO_GIMBAL_MANAGER_CONFIGURE;
+ vehicle_command.param1 = -3.0f; // Remove control if it had it.
+ vehicle_command.param2 = -3.0f; // Remove control if it had it.
+ vehicle_command.param3 = -1.0f; // Leave unchanged.
+ vehicle_command.param4 = -1.0f; // Leave unchanged.
+ vehicle_command.timestamp = hrt_absolute_time();
+ vehicle_command.from_external = false;
+ vehicle_command.source_system = _param_mav_sys_id.get();
+ vehicle_command.source_component = _param_mav_comp_id.get();
+ vehicle_command.target_system = _param_mav_sys_id.get();
+ vehicle_command.target_component = _param_mav_comp_id.get();
+ _vehicle_command_pub.publish(vehicle_command);
+ }
+}
+
+void Gimbal::publishGimbalManagerSetAttitude(const uint16_t gimbal_flags,
+ const matrix::Quatf &q_gimbal_setpoint,
+ const matrix::Vector3f &gimbal_rates)
+{
+ gimbal_manager_set_attitude_s gimbal_setpoint{};
+ gimbal_setpoint.origin_sysid = _param_mav_sys_id.get();
+ gimbal_setpoint.origin_compid = _param_mav_comp_id.get();
+ gimbal_setpoint.flags = gimbal_flags;
+ q_gimbal_setpoint.copyTo(gimbal_setpoint.q);
+ gimbal_setpoint.angular_velocity_x = gimbal_rates(0);
+ gimbal_setpoint.angular_velocity_y = gimbal_rates(1);
+ gimbal_setpoint.angular_velocity_z = gimbal_rates(2);
+ gimbal_setpoint.timestamp = hrt_absolute_time();
+ _gimbal_manager_set_attitude_pub.publish(gimbal_setpoint);
+}
diff --git a/src/modules/flight_mode_manager/tasks/Utility/Gimbal.hpp b/src/modules/flight_mode_manager/tasks/Utility/Gimbal.hpp
new file mode 100644
index 0000000000..938ef32aa2
--- /dev/null
+++ b/src/modules/flight_mode_manager/tasks/Utility/Gimbal.hpp
@@ -0,0 +1,90 @@
+/****************************************************************************
+ *
+ * Copyright (c) 2025 PX4 Development Team. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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.
+ *
+ ****************************************************************************/
+
+/**
+ * @file Gimbal.hpp
+ * @brief Gimbal interface with flight tasks
+ * @author Pernilla Wikström
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Sticks.hpp"
+
+
+class Gimbal : public ModuleParams
+{
+public:
+ Gimbal(ModuleParams *parent);
+ ~Gimbal();
+
+ bool checkForTelemetry(const hrt_abstime now);
+ void publishGimbalManagerSetAttitude(const uint16_t gimbal_flags,
+ const matrix::Quatf &q_gimbal_setpoint,
+ const matrix::Vector3f &gimbal_rates);
+ void acquireGimbalControlIfNeeded();
+ void releaseGimbalControlIfNeeded();
+ float getTelemetryYaw() { return _telemetry_yaw; }
+ bool allAxesLockedConfirmed() { return _telemetry_flags == FLAGS_ALL_AXES_LOCKED; }
+
+ static constexpr uint16_t FLAGS_ALL_AXES_LOCKED = gimbal_manager_set_attitude_s::GIMBAL_MANAGER_FLAGS_ROLL_LOCK
+ | gimbal_manager_set_attitude_s::GIMBAL_MANAGER_FLAGS_PITCH_LOCK
+ | gimbal_manager_set_attitude_s::GIMBAL_MANAGER_FLAGS_YAW_LOCK;
+ static constexpr uint16_t FLAGS_ROLL_PITCH_LOCKED =
+ gimbal_manager_set_attitude_s::GIMBAL_MANAGER_FLAGS_ROLL_LOCK
+ | gimbal_manager_set_attitude_s::GIMBAL_MANAGER_FLAGS_PITCH_LOCK;
+
+private:
+ bool _have_gimbal_control{false};
+
+ uORB::Subscription _gimbal_device_attitude_status_sub{ORB_ID(gimbal_device_attitude_status)};
+ hrt_abstime _telemtry_timestamp{};
+ uint16_t _telemetry_flags{};
+ float _telemetry_yaw{};
+
+ uORB::Publication _gimbal_manager_set_attitude_pub{ORB_ID(gimbal_manager_set_attitude)};
+ uORB::Publication _vehicle_command_pub{ORB_ID(vehicle_command)};
+
+ DEFINE_PARAMETERS(
+ (ParamInt) _param_mav_sys_id,
+ (ParamInt) _param_mav_comp_id
+ )
+};
diff --git a/src/modules/fw_pos_control/FixedwingPositionControl.cpp b/src/modules/fw_pos_control/FixedwingPositionControl.cpp
index 8baddd55e6..e939a56f54 100644
--- a/src/modules/fw_pos_control/FixedwingPositionControl.cpp
+++ b/src/modules/fw_pos_control/FixedwingPositionControl.cpp
@@ -487,8 +487,6 @@ FixedwingPositionControl::status_publish()
pos_ctrl_status.wp_dist = get_distance_to_next_waypoint(_current_latitude, _current_longitude,
_pos_sp_triplet.current.lat, _pos_sp_triplet.current.lon);
- pos_ctrl_status.yaw_acceptance = NAN;
-
pos_ctrl_status.timestamp = hrt_absolute_time();
pos_ctrl_status.type = _position_sp_type;
@@ -1318,7 +1316,15 @@ FixedwingPositionControl::control_auto_loiter(const float control_interval, cons
} else {
// continue straight until vehicle has sufficient altitude
+ // keep flaps in landing configuration if the airspeed is below the min airspeed (keep deployed if airspeed not valid)
roll_body = 0.0f;
+
+ if (!_airspeed_valid || _airspeed_eas < _performance_model.getMinimumCalibratedAirspeed()) {
+ _flaps_setpoint = _param_fw_flaps_lnd_scl.get();
+
+ } else {
+ _flaps_setpoint = 0.f;
+ }
}
is_low_height = true; // In low-height flight, TECS will control altitude tighter
diff --git a/src/modules/gimbal/input_mavlink.cpp b/src/modules/gimbal/input_mavlink.cpp
index e20bf6c552..aef348ca53 100644
--- a/src/modules/gimbal/input_mavlink.cpp
+++ b/src/modules/gimbal/input_mavlink.cpp
@@ -43,6 +43,8 @@
#include
#include
+using namespace matrix;
+
namespace gimbal
{
@@ -936,21 +938,19 @@ InputMavlinkGimbalV2::UpdateResult InputMavlinkGimbalV2::_process_set_manual_con
if (set_manual_control.origin_sysid == control_data.sysid_primary_control &&
set_manual_control.origin_compid == control_data.compid_primary_control) {
- const matrix::Quatf q =
- (PX4_ISFINITE(set_manual_control.pitch) && PX4_ISFINITE(set_manual_control.yaw))
- ?
- matrix::Quatf(
- matrix::Eulerf(0.0f, set_manual_control.pitch, set_manual_control.yaw))
- :
- matrix::Quatf(NAN, NAN, NAN, NAN);
+ Quatf q(NAN, NAN, NAN, NAN);
- const matrix::Vector3f angular_velocity =
- (PX4_ISFINITE(set_manual_control.pitch_rate) &&
- PX4_ISFINITE(set_manual_control.yaw_rate)) ?
- matrix::Vector3f(0.0f,
- math::radians(_parameters.mnt_rate_pitch) * set_manual_control.pitch_rate,
- math::radians(_parameters.mnt_rate_yaw) * set_manual_control.yaw_rate) :
- matrix::Vector3f(NAN, NAN, NAN);
+ if (PX4_ISFINITE(set_manual_control.pitch) && PX4_ISFINITE(set_manual_control.yaw)) {
+ q = Quatf(matrix::Eulerf(0.0f, set_manual_control.pitch, set_manual_control.yaw));
+ }
+
+ Vector3f angular_velocity(NAN, NAN, NAN);
+
+ if (PX4_ISFINITE(set_manual_control.pitch_rate) && PX4_ISFINITE(set_manual_control.yaw_rate)) {
+ angular_velocity = Vector3f(0.0f,
+ set_manual_control.pitch_rate * math::radians(_parameters.mnt_rate_pitch),
+ set_manual_control.yaw_rate * math::radians(_parameters.mnt_rate_yaw));
+ }
_set_control_data_from_set_attitude(control_data, set_manual_control.flags, q,
angular_velocity, set_manual_control.timestamp);
diff --git a/src/modules/internal_combustion_engine_control/CMakeLists.txt b/src/modules/internal_combustion_engine_control/CMakeLists.txt
new file mode 100644
index 0000000000..15df6ca368
--- /dev/null
+++ b/src/modules/internal_combustion_engine_control/CMakeLists.txt
@@ -0,0 +1,46 @@
+############################################################################
+#
+# Copyright (c) 2025 PX4 Development Team. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# 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.
+#
+############################################################################
+px4_add_module(
+ MODULE modules__internal_combustion_engine_control
+ MAIN internal_combustion_engine_control
+ COMPILE_FLAGS
+ #-DDEBUG_BUILD
+ SRCS
+ InternalCombustionEngineControl.cpp
+ InternalCombustionEngineControl.hpp
+ MODULE_CONFIG
+ module.yaml
+ DEPENDS
+ px4_work_queue
+ SlewRate
+)
diff --git a/src/modules/internal_combustion_engine_control/InternalCombustionEngineControl.cpp b/src/modules/internal_combustion_engine_control/InternalCombustionEngineControl.cpp
new file mode 100644
index 0000000000..1e8a1b1a35
--- /dev/null
+++ b/src/modules/internal_combustion_engine_control/InternalCombustionEngineControl.cpp
@@ -0,0 +1,418 @@
+/****************************************************************************
+ *
+ * Copyright (c) 2025 PX4 Development Team. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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.
+ *
+ ****************************************************************************/
+
+#include "InternalCombustionEngineControl.hpp"
+
+#include
+
+using namespace time_literals;
+
+namespace internal_combustion_engine_control
+{
+
+InternalCombustionEngineControl::InternalCombustionEngineControl() :
+ ModuleParams(nullptr),
+ ScheduledWorkItem(MODULE_NAME, px4::wq_configurations::lp_default)
+{
+ _internal_combustion_engine_control_pub.advertise();
+ _internal_combustion_engine_status_pub.advertise();
+}
+
+InternalCombustionEngineControl::~InternalCombustionEngineControl()
+{
+
+}
+
+int InternalCombustionEngineControl::task_spawn(int argc, char *argv[])
+{
+ InternalCombustionEngineControl *obj = new InternalCombustionEngineControl();
+
+ if (!obj) {
+ PX4_ERR("alloc failed");
+ return -1;
+ }
+
+ _object.store(obj);
+ _task_id = task_id_is_work_queue;
+
+ /* Schedule a cycle to start things. */
+ obj->start();
+
+ return 0;
+}
+
+void InternalCombustionEngineControl::start()
+{
+ ScheduleOnInterval(20_ms); // 50 Hz
+}
+
+void InternalCombustionEngineControl::Run()
+{
+ if (should_exit()) {
+ ScheduleClear();
+ exit_and_cleanup();
+ }
+
+ // check for parameter updates
+ if (_parameter_update_sub.updated()) {
+ // clear update
+ parameter_update_s pupdate;
+ _parameter_update_sub.copy(&pupdate);
+
+ // update parameters from storage
+ updateParams();
+ _throttle_control_slew_rate.setSlewRate(_param_ice_thr_slew.get());
+ }
+
+
+ manual_control_setpoint_s manual_control_setpoint;
+ _manual_control_setpoint_sub.copy(&manual_control_setpoint);
+
+ vehicle_status_s vehicle_status;
+ _vehicle_status_sub.copy(&vehicle_status);
+
+ actuator_motors_s actuator_motors;
+ _actuator_motors.copy(&actuator_motors);
+
+ const float throttle_in = actuator_motors.control[0];
+
+ const hrt_abstime now = hrt_absolute_time();
+
+ UserOnOffRequest user_request = UserOnOffRequest::Off;
+
+ switch (static_cast(_param_ice_on_source.get())) {
+ case ICESource::ArmingState: {
+ if (vehicle_status.arming_state == vehicle_status_s::ARMING_STATE_ARMED) {
+ user_request = UserOnOffRequest::On;
+ }
+ }
+ break;
+
+ case ICESource::Aux1: {
+ if (manual_control_setpoint.aux1 > 0.5f) {
+ user_request = UserOnOffRequest::On;
+ }
+ }
+ break;
+
+ case ICESource::Aux2: {
+ if (manual_control_setpoint.aux2 > 0.5f) {
+ user_request = UserOnOffRequest::On;
+ }
+ }
+ break;
+ }
+
+ switch (_state) {
+ case State::Stopped: {
+ controlEngineStop();
+
+ if (user_request == UserOnOffRequest::On && !maximumAttemptsReached()) {
+
+ _state = State::Starting;
+ _state_start_time = now;
+ PX4_INFO("ICE: Starting");
+ }
+ }
+ break;
+
+ case State::Starting: {
+
+ if (user_request == UserOnOffRequest::Off) {
+ _state = State::Stopped;
+ _starting_retry_cycle = 0;
+ PX4_INFO("ICE: Stopped");
+
+ } else {
+
+ switch (_starting_sub_state) {
+ case SubState::Rest: {
+ if (isStartingPermitted(now)) {
+ _state_start_time = now;
+ _starting_sub_state = SubState::Run;
+ }
+ }
+ break;
+
+ case SubState::Run:
+ default: {
+ controlEngineStartup(now);
+
+ if (isEngineRunning(now)) {
+ _state = State::Running;
+ PX4_INFO("ICE: Starting finished");
+
+ } else {
+
+ if (maximumAttemptsReached()) {
+ _state = State::Fault;
+ PX4_WARN("ICE: Fault");
+
+ } else if (!isStartingPermitted(now)) {
+ controlEngineStop();
+ _starting_sub_state = SubState::Rest;
+ }
+ }
+
+ break;
+ }
+
+ }
+ }
+
+ }
+ break;
+
+ case State::Running: {
+ controlEngineRunning(throttle_in);
+
+ if (user_request == UserOnOffRequest::Off) {
+ _state = State::Stopped;
+ _starting_retry_cycle = 0;
+ PX4_INFO("ICE: Stopped");
+
+ } else if (!isEngineRunning(now) && _param_ice_running_fault_detection.get()) {
+ // without RPM feedback we assume the engine is running after the
+ // starting procedure but only switch state if fault detection is enabled
+ _state = State::Starting;
+ _state_start_time = now;
+ _starting_retry_cycle = 0;
+ PX4_WARN("ICE: Running Fault detected");
+ events::send(events::ID("internal_combustion_engine_control_fault"), events::Log::Critical,
+ "IC engine fault detected");
+ }
+ }
+
+ break;
+
+ case State::Fault: {
+
+ // do nothing
+ if (user_request == UserOnOffRequest::Off) {
+ _state = State::Stopped;
+ _starting_retry_cycle = 0;
+ PX4_INFO("ICE: Stopped");
+
+ } else {
+ controlEngineFault();
+ }
+ }
+
+
+ break;
+ }
+
+ const float control_interval = math::constrain(static_cast((now - _last_time_run) * 1e-6f), 0.01f, 0.1f);
+
+ _last_time_run = now;
+
+ // slew rate limit throttle control if it's finite, otherwise just pass it through (0 throttle = NAN = disarmed)
+ if (PX4_ISFINITE(_throttle_control)) {
+ _throttle_control = _throttle_control_slew_rate.update(_throttle_control, control_interval);
+
+ } else {
+ _throttle_control_slew_rate.setForcedValue(0.f);
+ }
+
+ publishControl(now, user_request);
+}
+
+void InternalCombustionEngineControl::publishControl(const hrt_abstime now, const UserOnOffRequest user_request)
+{
+ internal_combustion_engine_control_s ice_control{};
+ ice_control.timestamp = now;
+ ice_control.choke_control = _choke_control;
+ ice_control.ignition_on = _ignition_on;
+ ice_control.starter_engine_control = _starter_engine_control;
+ ice_control.throttle_control = _throttle_control;
+ ice_control.user_request = static_cast(user_request);
+ _internal_combustion_engine_control_pub.publish(ice_control);
+
+ internal_combustion_engine_status_s ice_status;
+ ice_status.state = static_cast(_state);
+ ice_status.timestamp = now;
+ _internal_combustion_engine_status_pub.publish(ice_status);
+}
+
+bool InternalCombustionEngineControl::isEngineRunning(const hrt_abstime now)
+{
+ rpm_s rpm;
+
+ if (_rpm_sub.copy(&rpm)) {
+ const hrt_abstime rpm_timestamp = rpm.timestamp;
+
+ return (_param_ice_min_run_rpm.get() > FLT_EPSILON && (now < rpm_timestamp + 2_s)
+ && rpm.rpm_estimate > _param_ice_min_run_rpm.get());
+ }
+
+ return false;
+}
+
+void InternalCombustionEngineControl::controlEngineRunning(float throttle_in)
+{
+ _ignition_on = true;
+ _choke_control = 0.f;
+ _starter_engine_control = 0.f;
+ _throttle_control = throttle_in;
+
+}
+
+void InternalCombustionEngineControl::controlEngineStop()
+{
+ _ignition_on = false;
+ _choke_control = _param_ice_stop_choke.get() ? 1.f : 0.f;
+ _starter_engine_control = 0.f;
+ _throttle_control = 0.f;
+}
+
+void InternalCombustionEngineControl::controlEngineFault()
+{
+ _ignition_on = false;
+ _choke_control = _param_ice_stop_choke.get() ? 1.f : 0.f;
+ _starter_engine_control = 0.f;
+ _throttle_control = 0.f;
+}
+
+void InternalCombustionEngineControl::controlEngineStartup(const hrt_abstime now)
+{
+ float ignition_delay = 0.f;
+ float choke_duration = 0.f;
+ const float starter_duration = _param_ice_strt_dur.get();
+
+ if (_starting_retry_cycle == 0) {
+ ignition_delay = math::max(_param_ice_ign_delay.get(), 0.f);
+
+ if (_param_ice_choke_st_dur.get() > FLT_EPSILON) {
+ choke_duration = _param_ice_choke_st_dur.get();
+ }
+ }
+
+ _ignition_on = true;
+ _throttle_control = _param_ice_strt_thr.get();
+ _choke_control = now < _state_start_time + (choke_duration + ignition_delay) * 1_s ? 1.f : 0.f;
+ _starter_engine_control = now > _state_start_time + (ignition_delay * 1_s) ? 1.f : 0.f;
+ const hrt_abstime cycle_timeout_duration = (ignition_delay + choke_duration + starter_duration) * 1_s;
+
+ if (now > _state_start_time + cycle_timeout_duration) {
+ // start resting timer if engine is not running
+ _starting_rest_time = now;
+ _starting_retry_cycle++;
+ PX4_INFO("ICE: starting attempt %i finished", _starting_retry_cycle);
+ }
+}
+
+bool InternalCombustionEngineControl::isStartingPermitted(const hrt_abstime now)
+{
+ return now > _starting_rest_time + DELAY_BEFORE_RESTARTING * 1_s;
+}
+
+bool InternalCombustionEngineControl::maximumAttemptsReached()
+{
+ // First and only attempt
+ if (_param_ice_strt_attempts.get() == 0) {
+ return _starting_retry_cycle > 0;
+ }
+
+ return _starting_retry_cycle >= _param_ice_strt_attempts.get();
+}
+
+int InternalCombustionEngineControl::print_usage(const char *reason)
+{
+ if (reason) {
+ PX4_ERR("%s\n", reason);
+ }
+
+ PRINT_MODULE_DESCRIPTION(
+ R"DESCR_STR(
+### Description
+
+The module controls internal combustion engine (ICE) features including:
+ignition (on/off), throttle and choke level, starter engine delay, and user request.
+
+### Enabling
+
+This feature is not enabled by default needs to be configured in the
+build target for your board together with the rpm capture driver:
+
+```
+CONFIG_MODULES_INTERNAL_COMBUSTION_ENGINE_CONTROL=y
+CONFIG_DRIVERS_RPM_CAPTURE=y
+```
+
+Additionally, to enable the module:
+
+- Set [ICE_EN](../advanced_config/parameter_reference.md#ICE_EN)
+to true and adjust the other `ICE_` module parameters according to your needs.
+- Set [RPM_CAP_ENABLE](../advanced_config/parameter_reference.md#RPM_CAP_ENABLE) to true.
+
+The module outputs control signals for ignition, throttle, and choke,
+and takes inputs from an RPM sensor.
+These must be mapped to AUX outputs/inputs in the [Actuator configuration](../config/actuators.md),
+similar to the setup shown below.
+
+
+
+### Implementation
+
+The ICE is implemented with a (4) state machine:
+
+
+
+The state machine:
+
+- Checks if [Rpm.msg](../msg_docs/Rpm.md) is updated to know if the engine is running
+- Allows for user inputs from:
+ - AUX{N}
+ - Arming state in [VehicleStatus.msg](../msg_docs/VehicleStatus.md)
+
+The module publishes [InternalCombustionEngineControl.msg](../msg_docs/InternalCombustionEngineControl.md).
+
+The architecture is as shown below:
+
+
+
+
+)DESCR_STR");
+
+ PRINT_MODULE_USAGE_NAME("internal_combustion_engine_control", "system");
+ PRINT_MODULE_USAGE_COMMAND("start");
+ PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
+ return 0;
+}
+
+extern "C" __EXPORT int internal_combustion_engine_control_main(int argc, char *argv[])
+{
+ return InternalCombustionEngineControl::main(argc, argv);
+}
+
+} // namespace internal_combustion_engine_control
diff --git a/src/modules/internal_combustion_engine_control/InternalCombustionEngineControl.hpp b/src/modules/internal_combustion_engine_control/InternalCombustionEngineControl.hpp
new file mode 100644
index 0000000000..01884e4967
--- /dev/null
+++ b/src/modules/internal_combustion_engine_control/InternalCombustionEngineControl.hpp
@@ -0,0 +1,159 @@
+/****************************************************************************
+ *
+ * Copyright (c) 2025 PX4 Development Team. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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.
+ *
+ ****************************************************************************/
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+namespace internal_combustion_engine_control
+{
+
+class InternalCombustionEngineControl : public ModuleBase, public ModuleParams,
+ public px4::ScheduledWorkItem
+{
+public:
+ InternalCombustionEngineControl();
+ ~InternalCombustionEngineControl() override;
+
+ static int task_spawn(int argc, char *argv[]);
+
+ /** @see ModuleBase */
+ static int custom_command(int argc, char *argv[])
+ {
+ return print_usage("unknown command");
+ }
+
+ /** @see ModuleBase */
+ static int print_usage(const char *reason = nullptr);
+
+ void start();
+
+private:
+ void Run() override;
+
+ uORB::Subscription _manual_control_setpoint_sub{ORB_ID(manual_control_setpoint)};
+ uORB::Subscription _vehicle_status_sub{ORB_ID(vehicle_status)};
+ uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)};
+ uORB::Subscription _rpm_sub{ORB_ID(rpm)};
+ uORB::Subscription _actuator_motors{ORB_ID(actuator_motors)};
+
+ uORB::Publication _internal_combustion_engine_control_pub{ORB_ID(internal_combustion_engine_control)};
+ uORB::Publication _internal_combustion_engine_status_pub{ORB_ID(internal_combustion_engine_status)};
+
+
+ // has to mirror internal_combustion_engine_status_s::State
+ enum class State {
+ Stopped,
+ Starting,
+ Running,
+ Fault
+ } _state{State::Stopped};
+
+ enum class SubState {
+ Run,
+ Rest
+ };
+
+ enum class UserOnOffRequest {
+ Off,
+ On
+ };
+
+ enum class ICESource {
+ ArmingState,
+ Aux1,
+ Aux2,
+ };
+
+ hrt_abstime _state_start_time{0};
+ hrt_abstime _last_time_run{0};
+
+ bool _ignition_on{false};
+ float _choke_control{1.f};
+ float _starter_engine_control{0.f};
+ float _throttle_control{0.f};
+
+ SlewRate _throttle_control_slew_rate;
+
+ bool isEngineRunning(const hrt_abstime now);
+ void controlEngineRunning(float throttle_in);
+ void controlEngineStop();
+ void controlEngineStartup(const hrt_abstime now);
+ void controlEngineFault();
+ bool maximumAttemptsReached();
+ void publishControl(const hrt_abstime now, const UserOnOffRequest user_request);
+
+ // Starting state specifics
+ static constexpr float DELAY_BEFORE_RESTARTING{1.f};
+ int _starting_retry_cycle{0};
+ hrt_abstime _starting_rest_time{0};
+ SubState _starting_sub_state{SubState::Run};
+
+ /**
+ * @brief Currently the ICE starting state is permitted after resting
+ * DELAY_BEFORE_RESTARTING s to reduce wear on the starter motor.
+ * @param now current time
+ * @return if true, otherwise false
+ */
+ bool isStartingPermitted(const hrt_abstime now);
+
+ DEFINE_PARAMETERS(
+ (ParamInt) _param_ice_on_source,
+ (ParamFloat) _param_ice_choke_st_dur,
+ (ParamFloat) _param_ice_strt_dur,
+ (ParamFloat) _param_ice_min_run_rpm,
+ (ParamInt) _param_ice_strt_attempts,
+ (ParamInt) _param_ice_running_fault_detection,
+ (ParamFloat) _param_ice_strt_thr,
+ (ParamInt) _param_ice_stop_choke,
+ (ParamFloat) _param_ice_thr_slew,
+ (ParamFloat) _param_ice_ign_delay
+ )
+};
+
+} // namespace internal_combustion_engine_control
diff --git a/src/modules/internal_combustion_engine_control/Kconfig b/src/modules/internal_combustion_engine_control/Kconfig
new file mode 100644
index 0000000000..c0d0e9049f
--- /dev/null
+++ b/src/modules/internal_combustion_engine_control/Kconfig
@@ -0,0 +1,5 @@
+menuconfig MODULES_INTERNAL_COMBUSTION_ENGINE_CONTROL
+ bool "internal_combustion_engine_control"
+ default n
+ ---help---
+ Enable support for internal_combustion_engine_control
diff --git a/src/modules/internal_combustion_engine_control/module.yaml b/src/modules/internal_combustion_engine_control/module.yaml
new file mode 100644
index 0000000000..517fc89fee
--- /dev/null
+++ b/src/modules/internal_combustion_engine_control/module.yaml
@@ -0,0 +1,120 @@
+module_name: Internal Combustion Engine Control
+
+parameters:
+ - group: ICE
+ definitions:
+
+ ICE_EN:
+ description:
+ short: Enable internal combustion engine
+ type: boolean
+ default: true
+
+ ICE_ON_SOURCE:
+ description:
+ short: Engine start/stop input source
+ type: enum
+ default: 0
+ values:
+ 0: On arming - disarming
+ 1: Aux1
+ 2: Aux2
+
+ ICE_CHOKE_ST_DUR:
+ description:
+ short: Duration of choking during startup
+ type: float
+ unit: s
+ min: 0
+ max: 10
+ decimal: 1
+ increment: 0.1
+ default: 5
+
+ ICE_STRT_DUR:
+ description:
+ short: Duration of single starting attempt (excl. choking)
+ long: |
+ Maximum expected time for startup before declaring timeout.
+ type: float
+ unit: s
+ min: 0
+ max: 10
+ decimal: 1
+ increment: 0.1
+ default: 5
+
+ ICE_MIN_RUN_RPM:
+ description:
+ short: Minimum RPM for engine to be declared running
+ type: float
+ unit: rpm
+ min: 0
+ max: 10000
+ decimal: 0
+ increment: 1
+ default: 2000
+
+ ICE_STRT_ATTEMPT:
+ description:
+ short: Number attempts for starting the engine
+ long: |
+ Number of accepted attempts for starting the engine before declaring a fault.
+ type: int32
+ min: 0
+ max: 10
+ default: 3
+
+ ICE_RUN_FAULT_D:
+ description:
+ short: Fault detection if it stops in running state
+ long: |
+ Enables restart if a fault is detected during the running state. Otherwise
+ commands continues in running state until given an user request off.
+ type: boolean
+ default: true
+
+ ICE_STRT_THR:
+ description:
+ short: Throttle value for starting engine
+ long: |
+ During the choking and the starting phase, the throttle value is set to this value.
+ type: float
+ unit: norm
+ min: 0
+ max: 1
+ decimal: 0
+ increment: 0.01
+ default: 0.1
+
+ ICE_STOP_CHOKE:
+ description:
+ short: Apply choke when stopping engine
+ type: boolean
+ default: true
+
+ ICE_THR_SLEW:
+ description:
+ short: Throttle slew rate
+ long: |
+ Maximum rate of change of throttle value per second.
+ type: float
+ unit: 1/s
+ min: 0
+ max: 1
+ decimal: 2
+ increment: 0.01
+ default: 0.5
+
+ ICE_IGN_DELAY:
+ description:
+ short: Cold-start delay after ignition before engaging starter
+ long: |
+ In case that the ignition takes a moment to be up and running, this parameter can be set to account for that.
+ type: float
+ unit: s
+ min: 0
+ max: 10
+ decimal: 1
+ increment: 0.1
+ default: 0
diff --git a/src/modules/logger/logged_topics.cpp b/src/modules/logger/logged_topics.cpp
index 57b2a429de..84d8e3eadd 100644
--- a/src/modules/logger/logged_topics.cpp
+++ b/src/modules/logger/logged_topics.cpp
@@ -79,6 +79,7 @@ void LoggedTopics::add_default_topics()
add_topic("home_position");
add_topic("hover_thrust_estimate", 100);
add_topic("input_rc", 500);
+ add_optional_topic("internal_combustion_engine_control", 10);
add_optional_topic("internal_combustion_engine_status", 10);
add_optional_topic("iridiumsbd_status", 1000);
add_optional_topic("irlock_report", 1000);
@@ -104,17 +105,11 @@ void LoggedTopics::add_default_topics()
add_topic("radio_status");
add_optional_topic("rover_attitude_setpoint", 100);
add_optional_topic("rover_attitude_status", 100);
- add_optional_topic("rover_velocity_status", 100);
add_optional_topic("rover_rate_setpoint", 100);
add_optional_topic("rover_rate_status", 100);
add_optional_topic("rover_steering_setpoint", 100);
add_optional_topic("rover_throttle_setpoint", 100);
- add_optional_topic("rover_differential_guidance_status", 100);
- add_optional_topic("rover_differential_setpoint", 100);
- add_optional_topic("rover_differential_status", 100);
- add_optional_topic("rover_mecanum_guidance_status", 100);
- add_optional_topic("rover_mecanum_setpoint", 100);
- add_optional_topic("rover_mecanum_status", 100);
+ add_optional_topic("rover_velocity_status", 100);
add_topic("rtl_time_estimate", 1000);
add_topic("rtl_status", 2000);
add_optional_topic("sensor_airflow", 100);
@@ -335,8 +330,6 @@ void LoggedTopics::add_vision_and_avoidance_topics()
add_topic("obstacle_distance_fused");
add_topic("obstacle_distance");
add_topic("vehicle_mocap_odometry", 30);
- add_topic("vehicle_trajectory_waypoint", 200);
- add_topic("vehicle_trajectory_waypoint_desired", 200);
add_topic("vehicle_visual_odometry", 30);
}
diff --git a/src/modules/logger/params.c b/src/modules/logger/params.c
index 3d7e873854..e1bbd5145f 100644
--- a/src/modules/logger/params.c
+++ b/src/modules/logger/params.c
@@ -123,7 +123,7 @@ PARAM_DEFINE_INT32(SDLOG_MISSION, 0);
* 4 : Full rates for analysis of fast maneuvers (RC, attitude, rates and actuators)
* 5 : Debugging topics (debug_*.msg topics, for custom code)
* 6 : Topics for sensor comparison (low rate raw IMU, Baro and magnetometer data)
- * 7 : Topics for computer vision and collision avoidance
+ * 7 : Topics for computer vision and collision prevention
* 8 : Raw FIFO high-rate IMU (Gyro)
* 9 : Raw FIFO high-rate IMU (Accel)
* 10: Logging of mavlink tunnel message (useful for payload communication debugging)
diff --git a/src/modules/mavlink/mavlink b/src/modules/mavlink/mavlink
index 619947d8bc..8690e10164 160000
--- a/src/modules/mavlink/mavlink
+++ b/src/modules/mavlink/mavlink
@@ -1 +1 @@
-Subproject commit 619947d8bc29e80eecff18b0f4fecc42d9e171dd
+Subproject commit 8690e10164da864d7d36a3daad5547662e7a4103
diff --git a/src/modules/mavlink/mavlink_main.cpp b/src/modules/mavlink/mavlink_main.cpp
index 6e81849600..724391cf86 100644
--- a/src/modules/mavlink/mavlink_main.cpp
+++ b/src/modules/mavlink/mavlink_main.cpp
@@ -1525,7 +1525,6 @@ Mavlink::configure_streams_to_default(const char *configure_single_stream)
configure_stream_local("SYS_STATUS", 5.0f);
configure_stream_local("SYSTEM_TIME", 1.0f);
configure_stream_local("TIME_ESTIMATE_TO_TARGET", 1.0f);
- configure_stream_local("TRAJECTORY_REPRESENTATION_WAYPOINTS", 5.0f);
configure_stream_local("VFR_HUD", 10.0f);
configure_stream_local("VIBRATION", 0.5f);
configure_stream_local("WIND_COV", 10.0f);
@@ -1592,7 +1591,6 @@ Mavlink::configure_streams_to_default(const char *configure_single_stream)
configure_stream_local("RC_CHANNELS", 5.0f);
configure_stream_local("SERVO_OUTPUT_RAW_0", 1.0f);
configure_stream_local("SYS_STATUS", 5.0f);
- configure_stream_local("TRAJECTORY_REPRESENTATION_WAYPOINTS", 5.0f);
configure_stream_local("VFR_HUD", 4.0f);
configure_stream_local("VIBRATION", 0.5f);
configure_stream_local("WIND_COV", 1.0f);
@@ -1784,7 +1782,6 @@ Mavlink::configure_streams_to_default(const char *configure_single_stream)
configure_stream_local("SYS_STATUS", 5.0f);
configure_stream_local("SYSTEM_TIME", 2.0f);
configure_stream_local("TIME_ESTIMATE_TO_TARGET", 1.0f);
- configure_stream_local("TRAJECTORY_REPRESENTATION_WAYPOINTS", 5.0f);
configure_stream_local("VFR_HUD", 4.0f);
configure_stream_local("VIBRATION", 0.5f);
configure_stream_local("WIND_COV", 1.0f);
diff --git a/src/modules/mavlink/mavlink_messages.cpp b/src/modules/mavlink/mavlink_messages.cpp
index 72b5b49123..7d5e23bb6e 100644
--- a/src/modules/mavlink/mavlink_messages.cpp
+++ b/src/modules/mavlink/mavlink_messages.cpp
@@ -116,7 +116,6 @@
#include "streams/SYSTEM_TIME.hpp"
#include "streams/TIME_ESTIMATE_TO_TARGET.hpp"
#include "streams/TIMESYNC.hpp"
-#include "streams/TRAJECTORY_REPRESENTATION_WAYPOINTS.hpp"
#include "streams/VFR_HUD.hpp"
#include "streams/VIBRATION.hpp"
#include "streams/WIND_COV.hpp"
@@ -382,9 +381,6 @@ static const StreamListItem streams_list[] = {
#if defined(MANUAL_CONTROL_HPP)
create_stream_list_item(),
#endif // MANUAL_CONTROL_HPP
-#if defined(TRAJECTORY_REPRESENTATION_WAYPOINTS_HPP)
- create_stream_list_item(),
-#endif // TRAJECTORY_REPRESENTATION_WAYPOINTS_HPP
#if defined(OPTICAL_FLOW_RAD_HPP)
create_stream_list_item(),
#endif // OPTICAL_FLOW_RAD_HPP
diff --git a/src/modules/mavlink/mavlink_receiver.cpp b/src/modules/mavlink/mavlink_receiver.cpp
index aa8b50d01a..39b626b4d2 100644
--- a/src/modules/mavlink/mavlink_receiver.cpp
+++ b/src/modules/mavlink/mavlink_receiver.cpp
@@ -256,14 +256,6 @@ MavlinkReceiver::handle_message(mavlink_message_t *msg)
handle_message_tunnel(msg);
break;
- case MAVLINK_MSG_ID_TRAJECTORY_REPRESENTATION_BEZIER:
- handle_message_trajectory_representation_bezier(msg);
- break;
-
- case MAVLINK_MSG_ID_TRAJECTORY_REPRESENTATION_WAYPOINTS:
- handle_message_trajectory_representation_waypoints(msg);
- break;
-
case MAVLINK_MSG_ID_ONBOARD_COMPUTER_STATUS:
handle_message_onboard_computer_status(msg);
break;
@@ -1822,13 +1814,13 @@ MavlinkReceiver::handle_message_battery_status(mavlink_message_t *msg)
// Set the battery warning based on remaining charge.
// Note: Smallest values must come first in evaluation.
if (battery_status.remaining < _param_bat_emergen_thr.get()) {
- battery_status.warning = battery_status_s::BATTERY_WARNING_EMERGENCY;
+ battery_status.warning = battery_status_s::WARNING_EMERGENCY;
} else if (battery_status.remaining < _param_bat_crit_thr.get()) {
- battery_status.warning = battery_status_s::BATTERY_WARNING_CRITICAL;
+ battery_status.warning = battery_status_s::WARNING_CRITICAL;
} else if (battery_status.remaining < _param_bat_low_thr.get()) {
- battery_status.warning = battery_status_s::BATTERY_WARNING_LOW;
+ battery_status.warning = battery_status_s::WARNING_LOW;
}
_battery_pub.publish(battery_status);
@@ -1984,66 +1976,17 @@ MavlinkReceiver::handle_message_tunnel(mavlink_message_t *msg)
memcpy(tunnel.payload, mavlink_tunnel.payload, sizeof(tunnel.payload));
static_assert(sizeof(tunnel.payload) == sizeof(mavlink_tunnel.payload), "mavlink_tunnel.payload size mismatch");
- _mavlink_tunnel_pub.publish(tunnel);
+ switch (mavlink_tunnel.payload_type) {
+ case MAV_TUNNEL_PAYLOAD_TYPE_MODALAI_ESC_UART_PASSTHRU:
+ _esc_serial_passthru_pub.publish(tunnel);
+ break;
-}
-
-void
-MavlinkReceiver::handle_message_trajectory_representation_bezier(mavlink_message_t *msg)
-{
- mavlink_trajectory_representation_bezier_t trajectory;
- mavlink_msg_trajectory_representation_bezier_decode(msg, &trajectory);
-
- vehicle_trajectory_bezier_s trajectory_bezier{};
-
- trajectory_bezier.timestamp = _mavlink_timesync.sync_stamp(trajectory.time_usec);
-
- for (int i = 0; i < vehicle_trajectory_bezier_s::NUMBER_POINTS; ++i) {
- trajectory_bezier.control_points[i].position[0] = trajectory.pos_x[i];
- trajectory_bezier.control_points[i].position[1] = trajectory.pos_y[i];
- trajectory_bezier.control_points[i].position[2] = trajectory.pos_z[i];
-
- trajectory_bezier.control_points[i].delta = trajectory.delta[i];
- trajectory_bezier.control_points[i].yaw = trajectory.pos_yaw[i];
+ default:
+ _mavlink_tunnel_pub.publish(tunnel);
+ break;
}
- trajectory_bezier.bezier_order = math::min(trajectory.valid_points, vehicle_trajectory_bezier_s::NUMBER_POINTS);
- _trajectory_bezier_pub.publish(trajectory_bezier);
-}
-void
-MavlinkReceiver::handle_message_trajectory_representation_waypoints(mavlink_message_t *msg)
-{
- mavlink_trajectory_representation_waypoints_t trajectory;
- mavlink_msg_trajectory_representation_waypoints_decode(msg, &trajectory);
-
- vehicle_trajectory_waypoint_s trajectory_waypoint{};
-
- const int number_valid_points = math::min(trajectory.valid_points, vehicle_trajectory_waypoint_s::NUMBER_POINTS);
-
- for (int i = 0; i < number_valid_points; ++i) {
- trajectory_waypoint.waypoints[i].position[0] = trajectory.pos_x[i];
- trajectory_waypoint.waypoints[i].position[1] = trajectory.pos_y[i];
- trajectory_waypoint.waypoints[i].position[2] = trajectory.pos_z[i];
-
- trajectory_waypoint.waypoints[i].velocity[0] = trajectory.vel_x[i];
- trajectory_waypoint.waypoints[i].velocity[1] = trajectory.vel_y[i];
- trajectory_waypoint.waypoints[i].velocity[2] = trajectory.vel_z[i];
-
- trajectory_waypoint.waypoints[i].acceleration[0] = trajectory.acc_x[i];
- trajectory_waypoint.waypoints[i].acceleration[1] = trajectory.acc_y[i];
- trajectory_waypoint.waypoints[i].acceleration[2] = trajectory.acc_z[i];
-
- trajectory_waypoint.waypoints[i].yaw = trajectory.pos_yaw[i];
- trajectory_waypoint.waypoints[i].yaw_speed = trajectory.vel_yaw[i];
-
- trajectory_waypoint.waypoints[i].point_valid = true;
-
- trajectory_waypoint.waypoints[i].type = UINT8_MAX;
- }
-
- trajectory_waypoint.timestamp = hrt_absolute_time();
- _trajectory_waypoint_pub.publish(trajectory_waypoint);
}
void
@@ -2259,11 +2202,6 @@ MavlinkReceiver::handle_message_heartbeat(mavlink_message_t *msg)
_heartbeat_component_osd = now;
break;
- case MAV_COMP_ID_OBSTACLE_AVOIDANCE:
- _heartbeat_component_obstacle_avoidance = now;
- _mavlink.telemetry_status().avoidance_system_healthy = (hb.system_status == MAV_STATE_ACTIVE);
- break;
-
case MAV_COMP_ID_VISUAL_INERTIAL_ODOMETRY:
_heartbeat_component_visual_inertial_odometry = now;
break;
@@ -2669,7 +2607,6 @@ MavlinkReceiver::handle_message_hil_state_quaternion(mavlink_message_t *msg)
airspeed.timestamp_sample = timestamp_sample;
airspeed.indicated_airspeed_m_s = hil_state.ind_airspeed * 1e-2f;
airspeed.true_airspeed_m_s = hil_state.true_airspeed * 1e-2f;
- airspeed.air_temperature_celsius = 15.f;
airspeed.timestamp = hrt_absolute_time();
_airspeed_pub.publish(airspeed);
}
@@ -2976,7 +2913,6 @@ void MavlinkReceiver::CheckHeartbeats(const hrt_abstime &t, bool force)
tstatus.heartbeat_component_telemetry_radio = (t <= TIMEOUT + _heartbeat_component_telemetry_radio);
tstatus.heartbeat_component_log = (t <= TIMEOUT + _heartbeat_component_log);
tstatus.heartbeat_component_osd = (t <= TIMEOUT + _heartbeat_component_osd);
- tstatus.heartbeat_component_obstacle_avoidance = (t <= TIMEOUT + _heartbeat_component_obstacle_avoidance);
tstatus.heartbeat_component_vio = (t <= TIMEOUT + _heartbeat_component_visual_inertial_odometry);
tstatus.heartbeat_component_pairing_manager = (t <= TIMEOUT + _heartbeat_component_pairing_manager);
tstatus.heartbeat_component_udp_bridge = (t <= TIMEOUT + _heartbeat_component_udp_bridge);
diff --git a/src/modules/mavlink/mavlink_receiver.h b/src/modules/mavlink/mavlink_receiver.h
index 326d0ee19e..6c7b3065e2 100644
--- a/src/modules/mavlink/mavlink_receiver.h
+++ b/src/modules/mavlink/mavlink_receiver.h
@@ -110,8 +110,6 @@
#include
#include
#include
-#include
-#include
#include
#if !defined(CONSTRAINED_FLASH)
@@ -201,8 +199,6 @@ private:
void handle_message_set_position_target_local_ned(mavlink_message_t *msg);
void handle_message_statustext(mavlink_message_t *msg);
void handle_message_tunnel(mavlink_message_t *msg);
- void handle_message_trajectory_representation_bezier(mavlink_message_t *msg);
- void handle_message_trajectory_representation_waypoints(mavlink_message_t *msg);
void handle_message_utm_global_position(mavlink_message_t *msg);
#if defined(MAVLINK_MSG_ID_SET_VELOCITY_LIMITS) // For now only defined if development.xml is used
void handle_message_set_velocity_limits(mavlink_message_t *msg);
@@ -311,6 +307,7 @@ private:
uORB::Publication _landing_target_pose_pub{ORB_ID(landing_target_pose)};
uORB::Publication