Compare commits

...

17 Commits

Author SHA1 Message Date
Hamish Willee 556bec3374 [Docs] ModalAI starling superseded 2025-07-17 12:12:01 +10:00
Hamish Willee 06d25b9400 [Doc] FW Takeoff update for waypoint and position loss + relnote (#25226)
* [Doc] FW Takeoff update for waypoint and position loss + relnote

* Update docs/en/flight_modes_fw/takeoff.md

Co-authored-by: Silvan Fuhrer <silvan@auterion.com>

* Update for clarity

* Update docs/en/flight_modes_fw/takeoff.md

---------

Co-authored-by: Silvan Fuhrer <silvan@auterion.com>
2025-07-17 11:19:51 +10:00
bresch bfbc76189e ekf-agp: use same timeout value as other aid sources 2025-07-16 10:07:15 +02:00
Beat Küng 80febaf0f0 mc_pos_control: immediately switch out of goto setpoint when receiving trajectory_setpoint
Previously, when switching from a goto setpoint into a mode that publishes
trajectory_setpoint, the previous goto setpoint was still used for 500ms,
which then caused a setpoint jump.
This change makes sure that when a trajectory_setpoint is received, any
existing goto setpoint is marked as invalid immediately.
2025-07-16 09:02:47 +02:00
Beat Küng f0ecd9e757 fix commander: set failsafe action state immediately after failsafe update
There was a race condition: for example when an external mode disabled
failsafe deferring, that then triggered a failsafe, while the mode executor
immediately sends a command (to e.g. switch modes).
In that case the failsafe got triggered but the mode switch was still
allowed.
This was because of the processing ordering:
- mode updates (and propagating the failsafe_action_active state)
- failsafe updates
- command handling

This patch makes sure failsafe_action_active is set immediately after
updating the failsafes.
2025-07-15 17:18:54 +02:00
Beat Küng 168d99cd18 commander: do not trigger obsolete failsafe when deactivating failsafe deferring
Previously, when deferring was active and e.g. RC loss was triggered, and
RC regained, the action was not cleared, as the RC loss action only clears
on mode switch/disarm (when set to RTL for example).
When deferring was then disabled, the RC loss failsafe would still trigger.

This changes the behavior to immediately remove those actions when
deferring is active.

It also ensures to reset the Hold delay when deferring is disabled and no
failsafe is being deferred.
2025-07-15 17:18:54 +02:00
chfriedrich98 b8dacf5ae4 rover: fix speed setpoint in position controller 2025-07-15 13:55:28 +02:00
bresch 54f2652329 ekf2: always decorrelate pos and vel in vel reset 2025-07-15 13:44:55 +02:00
Matthias Grob f9b811b0c5 Commander: add option to ignore manual control loss in external modes 2025-07-15 13:08:18 +02:00
Marco Hauswirth a755dfa07f enable baro-gnss autocalibration by default (#25196) 2025-07-15 10:53:04 +02:00
chfriedrich98 b4bfbbb5e0 ackermann: add SIH (#25194) 2025-07-15 09:58:41 +02:00
Silvan Fuhrer 35a3f519f2 Revert "commander: publish full home attitude, not only yaw (#19717)"
This reverts commit 6855aa57c4.
2025-07-15 09:24:55 +02:00
Hamish Willee a3f1fb2e01 [Docs] Airframe param reset on update (#24964)
* Airframe param reset on update

* Update docs/en/dev_airframes/adding_a_new_frame.md

* Apply suggestions from code review

Co-authored-by: Matthias Grob <maetugr@gmail.com>

* Update adding_a_new_frame.md

* Update adding_a_new_frame.md

---------

Co-authored-by: Matthias Grob <maetugr@gmail.com>
2025-07-15 13:32:44 +10:00
Hamish Willee f224d27e4d Docs: Prettier on takeoff and fix some links (#25218)
* Prettier on takeoff and fix some links

* Fix flaw link
2025-07-15 12:30:55 +10:00
Matthias Grob 7d33df4650 Doc Orbit: update and clarify configurability and behavior around limits (#25208)
* Doc Orbit: update and clarify configurability and behavior around limits

* run prettier

* Fix up link to table

---------

Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
2025-07-15 12:29:29 +10:00
Stefano Colli 3c0a0ed129 mavlink_main: add profile handling (#25214) 2025-07-14 10:19:30 -08:00
Alexander Lerach 7f5119f402 sensors: autostart bmm350 and add it to common mags 2025-07-14 17:52:18 +02:00
43 changed files with 440 additions and 162 deletions
@@ -0,0 +1,72 @@
#!/bin/sh
# @name Rover Ackermann
# @type Rover
# @class Rover
. ${R}etc/init.d/rc.rover_ackermann_defaults
set VEHICLE_TYPE rover_ackermann
param set-default CA_AIRFRAME 5 # Rover (Ackermann)
param set-default CA_R_REV 1 # Motor is assumed to be reversible
param set-default EKF2_MAG_TYPE 1 # Make sure magnetometer is fused even when not driving
param set-default NAV_ACC_RAD 0.5 # Waypoint acceptance radius
param set-default EKF2_GBIAS_INIT 0.01
param set-default EKF2_ANGERR_INIT 0.01
PX4_SIMULATOR=${PX4_SIMULATOR:=sihsim}
PX4_SIM_MODEL=${PX4_SIM_MODEL:=rover_ackermann}
param set-default SIH_VEHICLE_TYPE 5 # sih as rover ackermann
param set-default PWM_MAIN_FUNC1 201 # Steering
param set-default PWM_MAIN_FUNC2 101 # Throttle
param set-default SIH_MASS 20
param set-default SIH_IXX 0.4333
param set-default SIH_IYY 1.6833
param set-default SIH_IZZ 2.0833
param set-default SIH_IXZ 0
param set-default SIH_KDV 50
param set-default SIH_KDW 10
param set-default SENS_EN_GPSSIM 1
param set-default SENS_EN_BAROSIM 1
param set-default SENS_EN_MAGSIM 1
# Ackermann Parameters
param set-default RA_WHEEL_BASE 0.321
param set-default RA_ACC_RAD_GAIN 2
param set-default RA_ACC_RAD_MAX 3
param set-default RA_MAX_STR_ANG 0.5236
param set-default RA_STR_RATE_LIM 360
# 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 400
param set-default RO_YAW_DECEL_LIM 800
param set-default RO_YAW_RATE_CORR 1
# Attitude Control Parameters
param set-default RO_YAW_P 5
# Velocity Control Parameters
param set-default RO_ACCEL_LIM 3
param set-default RO_DECEL_LIM 3
param set-default RO_JERK_LIM 10
param set-default RO_MAX_THR_SPEED 3.2
param set-default RO_SPEED_LIM 3
param set-default RO_SPEED_I 0.001
param set-default RO_SPEED_P 0.001
param set-default RO_SPEED_RED 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
# Pure Pursuit parameters
param set-default PP_LOOKAHD_GAIN 1
param set-default PP_LOOKAHD_MAX 10
param set-default PP_LOOKAHD_MIN 1
@@ -108,6 +108,7 @@ px4_add_romfs_files(
10042_sihsim_xvert
10043_sihsim_standard_vtol
10044_sihsim_hex
10045_sihsim_rover_ackermann
17001_flightgear_tf-g1
17002_flightgear_tf-g2
+1
View File
@@ -236,6 +236,7 @@ then
qmc5883l -X -q start
qmc5883p -X -q start
rm3100 -X -q start
bmm350 -X -q start
# start last (wait for possible icm20948 passthrough mode)
ak09916 -X -q start
-1
View File
@@ -18,7 +18,6 @@ CONFIG_COMMON_INS=y
CONFIG_COMMON_LIGHT=y
CONFIG_COMMON_MAGNETOMETER=y
CONFIG_DATAMAN_PERSISTENT_STORAGE=n
CONFIG_DRIVERS_MAGNETOMETER_BOSCH_BMM350=y
CONFIG_DRIVERS_PWM_OUT=y
CONFIG_DRIVERS_RC_INPUT=y
CONFIG_DRIVERS_ROBOCLAW=y
@@ -25,7 +25,6 @@ CONFIG_COMMON_INS=y
CONFIG_COMMON_LIGHT=y
CONFIG_DRIVERS_LIGHTS_RGBLED_PWM=y
CONFIG_COMMON_MAGNETOMETER=y
CONFIG_DRIVERS_MAGNETOMETER_BOSCH_BMM350=y
CONFIG_COMMON_OPTICAL_FLOW=y
CONFIG_COMMON_OSD=y
CONFIG_DRIVERS_POWER_MONITOR_INA226=y
+1 -1
View File
@@ -34,7 +34,6 @@
- [Static Pressure Buildup](advanced_config/static_pressure_buildup.md)
- [Flying (Basics)](flying/basic_flying_mc.md)
- [Complete Vehicles](complete_vehicles_mc/index.md)
- [ModalAI Starling](complete_vehicles_mc/modalai_starling.md)
- [PX4 Vision Kit](complete_vehicles_mc/px4_vision_kit.md)
- [MindRacer BNF & RTF](complete_vehicles_mc/mindracer_BNF_RTF.md)
- [MindRacer 210](complete_vehicles_mc/mindracer210.md)
@@ -42,6 +41,7 @@
- [Bitcraze Crazyflie 2.1](complete_vehicles_mc/crazyflie21.md)
- [Holybro Kopis 2](complete_vehicles_mc/holybro_kopis2.md)
- [Amov F410 Drone](complete_vehicles_mc/amov_F410_drone.md)
- [ModalAI Starling (Superseded)](complete_vehicles_mc/modalai_starling.md)
- [Kits](frames_multicopter/kits.md)
- [X500 v2 (Pixhawk 6C)](frames_multicopter/holybro_x500v2_pixhawk6c.md)
- [X500 v2 (Pixhawk 5X)](frames_multicopter/holybro_x500V2_pixhawk5x.md)
@@ -1,6 +1,11 @@
# VOXL 2 Starling PX4 Development Drone
# VOXL 2 Starling PX4 Development Drone (Discontinued/Superseded)
The [Starling](https://modalai.com/starling) is a SLAM development drone supercharged by [VOXL 2](../flight_controller/modalai_voxl_2.md) and PX4 with SWAP-optimized sensors and payloads optimized for indoor and outdoor autonomous navigation.
::: info
The Starling as been superseded by new frames (see [Starlings](https://www.modalai.com/pages/starlings) for more information).
It is not clear whether these can be used in the same way.
:::
The [Starling](https://www.modalai.com/pages/starlings) is a SLAM development drone supercharged by [VOXL 2](../flight_controller/modalai_voxl_2.md) and PX4 with SWAP-optimized sensors and payloads optimized for indoor and outdoor autonomous navigation.
Powered by Blue UAS Framework autopilot, VOXL 2, the Starling weighs only 275g and boasts an impressive 30 minutes of autonomous indoor flight time.
![Overview](../../assets/hardware/complete_vehicles/modalai_starling/starling_front_hero.jpg)
@@ -21,7 +26,7 @@ If you are new to VOXL, be sure to familiarize yourself with the core features o
## Where to Buy
[modalai.com/starling](https://modalai.com/starling)
[modalai.com/starling](https://www.modalai.com/pages/starlings)
## Hardware Overview
+3 -3
View File
@@ -104,9 +104,9 @@ The debug port definition includes the following solder pads (on board next to c
| 2 | GPIO1 | +3.3V |
| 3 | GPIO2 | +3.3V |
The socket is a _6-pin JST SH_ - Digikey number: [BM06B-SRSS-TBT(LF)(SN)](https://www.digikey.com/products/en?keywords=455-2875-1-ND) (vertical mount), [SM06B-SRSS-TBT(LF)(SN)](https://www.digikey.com/products/en?keywords=455-1806-1-ND)(side mount).
The socket is a _6-pin JST SH_ - Digikey number: [BM06B-SRSS-TBT(LF)(SN)](https://www.digikey.com/en/products/detail/jst-sales-america-inc/BM06B-SRSS-TBT/1785724) (vertical mount), [SM06B-SRSS-TBT(LF)(SN)](https://www.digikey.com/en/products/detail/jst-sales-america-inc/SM06B-SRSS-TB/926712) (side mount).
You can connect to the debug port using a [cable like this one](https://www.digikey.com/products/en?keywords=A06SR06SR30K152A).
You can connect to the debug port using a [cable like this one](https://www.digikey.com/en/products/detail/jst-sales-america-inc/A06SR06SR30K152A/6009379).
![6-pin JST SH Cable](../../assets/debug/cable_6pin_jst_sh.jpg)
@@ -134,7 +134,7 @@ The pinout is as shown below (pins required for debugging are bold):
The GPIO1/2 pins are free pins that can be used to generate signals in software for timing analysis with a logic analyzer.
The socket is a _10-pin JST SH_ - Digikey number: [BM10B-SRSS-TB(LF)(SN)](https://www.digikey.com/products/en?keywords=455-1796-2-ND) (vertical mount) or [SM10B-SRSS-TB(LF)(SN)](https://www.digikey.com/products/en?keywords=455-1810-2-ND) (side mount).
The socket is a _10-pin JST SH_ - Digikey number: [BM10B-SRSS-TB(LF)(SN)](https://www.digikey.com/en/products/detail/jst-sales-america-inc/BM10B-SRSS-TB/926702) (vertical mount) or [SM10B-SRSS-TB(LF)(SN)](https://www.digikey.com/en/products/detail/jst-sales-america-inc/BM10B-SRSS-TB/926702) (side mount).
You can connect to the debug port using a [cable like this one](https://www.digikey.com/products/en?keywords=A10SR10SR30K203A).
+14 -2
View File
@@ -26,7 +26,7 @@ The recommended process for developing a new frame configuration is:
1. Configure the [geometry and actuator outputs](../config/actuators.md).
1. Perform other [basic configuration](../config/index.md).
1. Tune the vehicle.
1. Run the [`param show-for-airframe`](../modules/modules_command.md#param) console command to list the parameter difference compared to the original generic airfame.
1. Run the [`param show-for-airframe`](../modules/modules_command.md#param) console command to list the parameter difference compared to the original generic airframe.
Once you have the parameters you can create a new frame configuration file by copying the configuration file for the generic configuration, and appending the new parameters.
@@ -39,7 +39,7 @@ To add a frame configuration to firmware:
1. Create a new config file in the [init.d/airframes](https://github.com/PX4/PX4-Autopilot/tree/main/ROMFS/px4fmu_common/init.d/airframes) folder.
- Give it a short descriptive filename and prepend the filename with an unused autostart ID (for example, `1033092_superfast_vtol`).
- Update the file with configuration parameters and apps (see section above).
1. Add the name of the new frame config file to the [CMakeLists.txt](https://github.com/PX4/PX4-Autopilot/blob/main/ROMFS/px4fmu_common/init.d/airframes/CMakeLists.txt) in the relevant section for the type of vehicle
1. Add the name of the new frame config file to the [CMakeLists.txt](https://github.com/PX4/PX4-Autopilot/blob/main/ROMFS/px4fmu_common/init.d/airframes/CMakeLists.txt) in the relevant section for the type of vehicle.
1. [Build and upload](../dev_setup/building_px4.md) the software.
## How to add a Configuration to an SD Card
@@ -65,6 +65,18 @@ These aspects are mostly independent, which means that many configurations share
New frame configuration files are only automatically added to the build system after a clean build (run `make clean`).
:::
## Force Reset of Airframe Parameters on Update
To force a reset to the airframe defaults for all users of a specific airframe during update, increase the `PARAM_DEFAULTS_VER` variable in the airframe configuration.
It starts at `1` in [rcS](https://github.com/PX4/PX4-Autopilot/blob/main/ROMFS/px4fmu_common/init.d/rcS#L40).
Add `set PARAM_DEFAULTS_VER 2` in your airframe file, increasing the value with each future reset needed.
This value is compared to [SYS_PARAM_VER](https://github.com/PX4/PX4-Autopilot/pull/advanced_config/parameter_reference.md#SYS_PARAM_VER) during PX4 updates.
If different, user-customized parameters are reset to defaults.
Note that system parameters primarily include those related to the vehicle airframe configuration.
Parameters such as accumulating flight hours, RC and sensor calibrations, are preserved.
### Example - Generic Quadcopter Frame Config
The configuration file for a generic Quad X copter is shown below ([original file here](https://github.com/PX4/PX4-Autopilot/blob/main/ROMFS/px4fmu_common/init.d/airframes/4001_quad_x)).
@@ -26,7 +26,6 @@ Omissions:
- Simulation: Gazebo and ROS are not supported.
- Only NuttX and JMAVSim/SITL builds are supported.
- [Known problems](https://github.com/orgs/PX4/projects/6) (Also use to report issues).
### Shell Script Installation
@@ -86,7 +85,7 @@ The toolchain gets maintained and hence these instructions might not cover every
That's what [cygwin64/install-cygwin-px4.bat](https://github.com/PX4/PX4-windows-toolchain/blob/master/toolchain/cygwin64/install-cygwin-px4.bat) does.
:::
1. Write up or copy the **batch scripts** [`run-console.bat`](https://github.com/MaEtUgR/PX4Toolchain/blob/master/run-console.bat) and [`setup-environment.bat`](https://github.com/PX4/PX4-windows-toolchain/blob/master/toolchain/scripts/setup-environment.bat).
1. Write up or copy the **batch scripts** [`run-console.bat`](https://github.com/PX4/PX4-windows-toolchain/blob/master/run-console.bat) and [`setup-environment.bat`](https://github.com/PX4/PX4-windows-toolchain/blob/master/toolchain/scripts/setup-environment.bat).
The reason to start all the development tools through the prepared batch script is they preconfigure the starting program to use the local, portable Cygwin environment inside the toolchain's folder.
This is done by always first calling the script [**setup-environment.bat**](https://github.com/PX4/PX4-windows-toolchain/blob/master/toolchain/scripts/setup-environment.bat) and the desired application like the console after that.
@@ -102,17 +101,17 @@ The toolchain gets maintained and hence these instructions might not cover every
```
::: info
That's what [cygwin64/install-cygwin-python-packages.bat](https://github.com/MaEtUgR/PX4Toolchain/blob/master/toolchain/cygwin64/install-cygwin-python-packages.bat) does.
That's what [cygwin64/install-cygwin-python-packages.bat](https://github.com/PX4/PX4-windows-toolchain/blob/master/toolchain/cygwin64/install-cygwin-python-packages.bat) does.
:::
1. Download the [**ARM GCC compiler**](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads) as zip archive of the binaries for Windows and unpack the content to the folder `C:\PX4\toolchain\gcc-arm`.
1. Download the [**ARM GCC compiler**](https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain) as zip archive of the binaries for Windows and unpack the content to the folder `C:\PX4\toolchain\gcc-arm`.
::: info
This is what the toolchain does in: [gcc-arm/install-gcc-arm.bat](https://github.com/PX4/PX4-windows-toolchain/blob/master/toolchain/gcc-arm/install-gcc-arm.bat).
:::
1. Install the JDK:
- Download Java 14 from [Oracle](https://www.oracle.com/java/technologies/downloads/) or [AdoptOpenJDK](https://adoptopenjdk.net/).
- Download Java 14 from [Oracle](https://www.oracle.com/java/technologies/downloads/)
- Because sadly there is no portable archive containing the binaries directly you have to install it.
- Find the binaries and move/copy them to **C:\PX4\toolchain\jdk**.
- You can uninstall the Kit from your Windows system again, we only needed the binaries for the toolchain.
+50 -31
View File
@@ -26,40 +26,61 @@ Vehicles are [hand or catapult launched](#catapult-hand-launch) by default, but
Takeoff mode (and [fixed wing mission takeoff](../flight_modes_fw/mission.md#mission-takeoff)) has two modalities: [catapult/hand-launch](#catapult-hand-launch) or [runway takeoff](#runway-takeoff) (hardware-dependent).
The mode defaults to catapult/hand launch, but can be set to runway takeoff by setting [RWTO_TKOFF](#RWTO_TKOFF) to 1.
To use _Takeoff mode_ you first switch to the mode, and then arm the vehicle.
To use _Takeoff mode_ you first switch to the mode, and then arm the vehicle (or send the [MAV_CMD_NAV_TAKEOFF](https://mavlink.io/en/messages/common.html#MAV_CMD_NAV_TAKEOFF) command which does both).
The acceleration of hand/catapult launch triggers the motors to start.
For runway launch, motors ramp up automatically once the vehicle has been armed.
Irrespective of the modality, a flight path (starting point and takeoff course) and clearance altitude are defined:
- The starting point is the vehicle position when the takeoff mode is first entered.
- The course is set to the vehicle heading on arming
- The clearance altitude is set to [MIS_TAKEOFF_ALT](#MIS_TAKEOFF_ALT).
- The course is set to the vehicle heading on arming by default.
If a valid waypoint latitude/longitude is set the vehicle will instead track towards the waypoint.
- The clearance altitude is set to [MIS_TAKEOFF_ALT](#MIS_TAKEOFF_ALT) by default.
If a valid waypoint altitude is set is set the vehicle will instead use it as the clearance altitude.
On takeoff, the aircraft will follow line defined by the starting point and course, climbing at the maximum climb rate ([FW_T_CLMB_MAX](../advanced_config/parameter_reference.md#FW_T_CLMB_MAX)) until reaching the clearance altitude.
By default, on takeoff the aircraft will follow the line defined by the starting point and course, climbing at the maximum climb rate ([FW_T_CLMB_MAX](../advanced_config/parameter_reference.md#FW_T_CLMB_MAX)) until reaching the clearance altitude.
Reaching the clearance altitude causes the vehicle to enter [Hold mode](../flight_modes_fw/takeoff.md).
Special case for invalid local position: In case the local position is invalid or becomes invalid while executing the takeoff, the controller is not able to track a course setpoint and will instead proceed climbing while keeping the wings level until the clearance altitude is reached.
If a valid waypoint target is set, using `MAV_CMD_NAV_TAKEOFF` or the [VehicleCommand](../msg_docs/VehicleCommand.md) uORB topic, the vehicle will instead track towards the waypoint, and enter [Hold mode](../flight_modes_fw/takeoff.md) after reaching the waypoint altitude (within the acceptance radius).
::: tip
If the local position is invalid or becomes invalid while executing the takeoff, the controller is not able to track a course setpoint and will instead proceed climbing while keeping the wings level until the clearance altitude is reached.
:::
::: info
- Takeoff towards a target position was added in <Badge type="tip" text="main (planned for: PX4 v1.17)" />.
- Holding wings level and ascending to clearance attitude when local position is invalid during takeoff was added in <Badge type="tip" text="main (planned for: PX4 v1.17)" />.
- QGroundControl does not support `MAV_CMD_NAV_TAKEOFF` (at time of writing).
:::
### Parameters
Parameters that affect both catapult/hand-launch and runway takeoffs:
| Parameter | Description |
| ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| <a id="MIS_TAKEOFF_ALT"></a>[MIS_TAKEOFF_ALT](../advanced_config/parameter_reference.md#MIS_TAKEOFF_ALT) | Minimum altitude setpoint above Home that the vehicle will climb to during takeoff. |
| <a id="FW_TKO_AIRSPD"></a>[FW_TKO_AIRSPD](../advanced_config/parameter_reference.md#FW_TKO_AIRSPD) | Takeoff airspeed (is set to [FW_AIRSPD_MIN](../advanced_config/parameter_reference.md#FW_AIRSPD_MIN) if not defined by operator) |
| <a id="FW_TKO_PITCH_MIN"></a>[FW_TKO_PITCH_MIN](../advanced_config/parameter_reference.md#FW_TKO_PITCH_MIN) | This is the minimum pitch angle setpoint during the climbout phase |
| <a id="FW_T_CLMB_MAX"></a>[FW_T_CLMB_MAX](../advanced_config/parameter_reference.md#FW_T_CLMB_MAX) | Climb rate setpoint during climbout to takeoff altitude. |
| <a id="FW_FLAPS_TO_SCL"></a>[FW_FLAPS_TO_SCL](../advanced_config/parameter_reference.md#FW_FLAPS_TO_SCL) | Flaps setpoint during takeoff |
| <a id="FW_AIRSPD_FLP_SC"></a>[FW_AIRSPD_FLP_SC](../advanced_config/parameter_reference.md#FW_AIRSPD_FLP_SC) | Factor applied to the minimum airspeed when flaps are fully deployed. Necessary if FW_TKO_AIRSPD is below FW_AIRSPD_MIN. |
| Parameter | Description |
| ----------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <a id="MIS_TAKEOFF_ALT"></a>[MIS_TAKEOFF_ALT][MIS_TAKEOFF_ALT] | This is the relative altitude (above launch altitude) the system will take off to if not otherwise specified. takeoff. |
| <a id="FW_TKO_AIRSPD"></a>[FW_TKO_AIRSPD][FW_TKO_AIRSPD] | Takeoff airspeed (is set to [FW_AIRSPD_MIN][FW_AIRSPD_MIN] if not defined by operator) |
| <a id="FW_TKO_PITCH_MIN"></a>[FW_TKO_PITCH_MIN][FW_TKO_PITCH_MIN] | This is the minimum pitch angle setpoint during the climbout phase |
| <a id="FW_T_CLMB_MAX"></a>[FW_T_CLMB_MAX][FW_T_CLMB_MAX] | Climb rate setpoint during climbout to takeoff altitude. |
| <a id="FW_FLAPS_TO_SCL"></a>[FW_FLAPS_TO_SCL][FW_FLAPS_TO_SCL] | Flaps setpoint during takeoff |
| <a id="FW_AIRSPD_FLP_SC"></a>[FW_AIRSPD_FLP_SC][FW_AIRSPD_FLP_SC] | Factor applied to the minimum airspeed when flaps are fully deployed. Needed if [FW_TKO_AIRSPD](#FW_TKO_AIRSPD) is below [FW_AIRSPD_MIN][FW_AIRSPD_MIN]. |
[FW_AIRSPD_MIN]: ../advanced_config/parameter_reference.md#FW_AIRSPD_MIN
[FW_FLAPS_TO_SCL]: ../advanced_config/parameter_reference.md#FW_FLAPS_TO_SCL
[FW_AIRSPD_FLP_SC]: ../advanced_config/parameter_reference.md#FW_AIRSPD_FLP_SC
[FW_TKO_AIRSPD]: ../advanced_config/parameter_reference.md#FW_TKO_AIRSPD
[MIS_TAKEOFF_ALT]: ../advanced_config/parameter_reference.md#MIS_TAKEOFF_ALT
[FW_TKO_PITCH_MIN]: ../advanced_config/parameter_reference.md#FW_TKO_PITCH_MIN
[FW_T_CLMB_MAX]: ../advanced_config/parameter_reference.md#FW_T_CLMB_MAX
::: info
The vehicle always respects normal FW max/min throttle settings during takeoff ([FW_THR_MIN](../advanced_config/parameter_reference.md#FW_THR_MIN), [FW_THR_MAX](../advanced_config/parameter_reference.md#FW_THR_MAX)).
:::
<a id="hand_launch"></a>
## Catapult/Hand Launch
## Catapult/Hand Launch {#hand_launch}
In _catapult/hand-launch mode_ the vehicle waits to detect launch (based on acceleration trigger).
On launch it enables the motor(s) and climbs with the maximum climb rate [FW_T_CLMB_MAX](#FW_T_CLMB_MAX) while keeping the pitch setpoint above [FW_TKO_PITCH_MIN](#FW_TKO_PITCH_MIN).
@@ -85,9 +106,7 @@ The _launch detector_ is affected by the following parameters:
| <a id="FW_LAUN_AC_T"></a>[FW_LAUN_AC_T](../advanced_config/parameter_reference.md#FW_LAUN_AC_T) | Trigger time (acceleration must be above threshold for this amount of seconds) |
| <a id="FW_LAUN_MOT_DEL"></a>[FW_LAUN_MOT_DEL](../advanced_config/parameter_reference.md#FW_LAUN_MOT_DEL) | Delay from launch detection to motor spin up |
<a id="runway_launch"></a>
## Runway Takeoff
## Runway Takeoff {#runway_launch}
Runway takeoffs can be used by vehicles with landing gear and and steerable wheel (only).
You will first need to enable the wheel controller using the parameter [FW_W_EN](#FW_W_EN).
@@ -110,18 +129,18 @@ It consists of a rate controller (P-I-FF-controller with the parameters [FW_WR_P
Runway takeoff is affected by the following parameters:
| Parameter | Description |
| ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| <a id="RWTO_TKOFF"></a>[RWTO_TKOFF](../advanced_config/parameter_reference.md#RWTO_TKOFF) | Enable runway takeoff |
| <a id="FW_W_EN"></a>[FW_W_EN](../advanced_config/parameter_reference.md#FW_W_EN) | Enable wheel controller |
| <a id="RWTO_MAX_THR"></a>[RWTO_MAX_THR](../advanced_config/parameter_reference.md#RWTO_MAX_THR) | Max throttle during runway takeoff |
| <a id="RWTO_RAMP_TIME"></a>[RWTO_RAMP_TIME](../advanced_config/parameter_reference.md#RWTO_RAMP_TIME) | Throttle ramp up time |
| <a id="RWTO_ROT_AIRSPD"></a>[RWTO_ROT_AIRSPD](../advanced_config/parameter_reference.md#RWTO_ROT_AIRSPD) | Airspeed threshold to start rotation (pitching up). If not configured by operator is set to 0.9\*FW_TKO_AIRSPD. |
| <a id="RWTO_ROT_TIME"></a>[RWTO_ROT_TIME](../advanced_config/parameter_reference.md#RWTO_ROT_TIME) | This is the time desired to linearly ramp in takeoff pitch constraints during the takeoff rotation. |
| <a id="FW_TKO_AIRSPD"></a>[FW_TKO_AIRSPD](../advanced_config/parameter_reference.md#FW_TKO_AIRSPD) | Airspeed setpoint during the takeoff climbout phase (after rotation). If not configured by operator is set to FW_AIRSPD_MIN. |
| <a id="RWTO_NUDGE"></a>[RWTO_NUDGE](../advanced_config/parameter_reference.md#RWTO_NUDGE) | Enable wheel controller nudging while on the runway |
| <a id="FW_WING_SPAN"></a>[FW_WING_SPAN](../advanced_config/parameter_reference.md#FW_WING_SPAN) | The wingspan of the vehicle. Used to prevent wingstrikes. |
| <a id="FW_WING_HEIGHT"></a>[FW_WING_HEIGHT](../advanced_config/parameter_reference.md#FW_WING_HEIGHT) | The height of the wings above ground (ground clearance). Used to prevent wingstrikes. |
| Parameter | Description |
| -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| <a id="RWTO_TKOFF"></a>[RWTO_TKOFF](../advanced_config/parameter_reference.md#RWTO_TKOFF) | Enable runway takeoff |
| <a id="FW_W_EN"></a>[FW_W_EN](../advanced_config/parameter_reference.md#FW_W_EN) | Enable wheel controller |
| <a id="RWTO_MAX_THR"></a>[RWTO_MAX_THR](../advanced_config/parameter_reference.md#RWTO_MAX_THR) | Max throttle during runway takeoff |
| <a id="RWTO_RAMP_TIME"></a>[RWTO_RAMP_TIME](../advanced_config/parameter_reference.md#RWTO_RAMP_TIME) | Throttle ramp up time |
| <a id="RWTO_ROT_AIRSPD"></a>[RWTO_ROT_AIRSPD](../advanced_config/parameter_reference.md#RWTO_ROT_AIRSPD) | Airspeed threshold to start rotation (pitching up). If not configured by operator is set to 0.9\*FW_TKO_AIRSPD. |
| <a id="RWTO_ROT_TIME"></a>[RWTO_ROT_TIME](../advanced_config/parameter_reference.md#RWTO_ROT_TIME) | This is the time desired to linearly ramp in takeoff pitch constraints during the takeoff rotation. |
| <a id="FW_TKO_AIRSPD"></a>[FW_TKO_AIRSPD](../advanced_config/parameter_reference.md#FW_TKO_AIRSPD) | Airspeed setpoint during the takeoff climbout phase (after rotation). If not configured by operator is set to FW_AIRSPD_MIN. |
| <a id="RWTO_NUDGE"></a>[RWTO_NUDGE](../advanced_config/parameter_reference.md#RWTO_NUDGE) | Enable wheel controller nudging while on the runway |
| <a id="FW_WING_SPAN"></a>[FW_WING_SPAN](../advanced_config/parameter_reference.md#FW_WING_SPAN) | The wingspan of the vehicle. Used to prevent wingstrikes. |
| <a id="FW_WING_HEIGHT"></a>[FW_WING_HEIGHT](../advanced_config/parameter_reference.md#FW_WING_HEIGHT) | The height of the wings above ground (ground clearance). Used to prevent wingstrikes. |
## See Also
+17 -11
View File
@@ -38,13 +38,16 @@ RC control cannot be used to start the mode (if you switch to the mode via RC it
RC control can be used to change the orbit altitude, radius, speed, and orbit direction:
- **Left stick:**
- _up/down:_ controls speed of ascent/descent, as in [Position mode](../flight_modes_mc/position.md). When in center deadzone, altitude is locked.
- _up/down:_ controls speed of ascent/descent, as in [Position mode](../flight_modes_mc/position.md).
When in center deadzone, altitude is locked.
- _left/right:_ no effect.
- **Right stick:**
- _left/right:_ controls acceleration of orbit in clockwise/counter-clockwise directions. When centered the current speed is locked.
- Maximum velocity is 10m/s and further limited to keep the centripetal acceleration below 2m/s^2.
- _left/right:_ controls acceleration of orbit in clockwise/counter-clockwise directions.
When centered the current speed is locked.
- Maximum velocity is [MPC_XY_VEL_MAX](#MPC_XY_VEL_MAX) and further limited to keep the centripetal acceleration below 2m/s^2.
- _up/down:_ controls orbit radius (smaller/bigger). When centered the current radius is locked.
- Minimum radius is 1m. Maximum radius is 100m.
- Minimum radius is 1m.
Maximum radius is [MC_ORBIT_RAD_MAX](#MC_ORBIT_RAD_MAX).
The diagram below shows the mode behaviour visually (for a [mode 2 transmitter](../getting_started/rc_transmitter_receiver.md#transmitter_modes)).
@@ -56,19 +59,22 @@ The mode can be stopped by switching to any other flight mode (using RC or QGC).
The mode is affected by the following parameters:
| Parameter | Description |
| ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| <a id="MC_ORBIT_RAD_MAX"></a>[MC_ORBIT_RAD_MAX](../advanced_config/parameter_reference.md#MC_ORBIT_RAD_MAX) | Maximum radius of orbit. Default: 1000m. |
| <a id="MC_ORBIT_YAW_MOD"></a>[MC_ORBIT_YAW_MOD](../advanced_config/parameter_reference.md#MC_ORBIT_YAW_MOD) | Yaw behaviour during orbit flight. Default: Front to Circle Center. |
| Parameter | Description |
| ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| <a id="MC_ORBIT_RAD_MAX"></a>[MC_ORBIT_RAD_MAX](../advanced_config/parameter_reference.md#MC_ORBIT_RAD_MAX) | Maximum radius of orbit. Default: 1000m. |
| <a id="MC_ORBIT_YAW_MOD"></a>[MC_ORBIT_YAW_MOD](../advanced_config/parameter_reference.md#MC_ORBIT_YAW_MOD) | Yaw behaviour during orbit flight. Default: Front to Circle Center. |
| <a id="MPC_XY_VEL_MAX"></a>[MPC_XY_VEL_MAX](../advanced_config/parameter_reference.md#MPC_XY_VEL_MAX) | Tangential speed limit. Stick input won't accelerate beyond this limit. Higher commands are accepted but capped. |
The following limits are hard coded:
- Initial/default rotation is 1 m/s in a clockwise direction.
- The maximum acceleration is limited to 2 m/s^2, with priority on keeping the commanded circle trajectory rather than commanded ground speed (i.e. the vehicle will slow down in order to achieve the correct circle if the acceleration exceeds 2m/s^2).
- Initial/default rotation is 1m/s in a clockwise direction.
- The maximum acceleration is limited to 2m/s^2, with priority on keeping the commanded circle trajectory rather than commanded ground speed (i.e. the vehicle will slow down in order to achieve the correct circle if the acceleration exceeds 2m/s^2).
## MAVLink Messages (Developers)
Orbit mode uses the following MAVLink commands:
- [MAV_CMD_DO_ORBIT](https://mavlink.io/en/messages/common.html#MAV_CMD_DO_ORBIT) - Start an orbit with specified center point, radius, direction, altitude, speed and [yaw direction](https://mavlink.io/en/messages/common.html#ORBIT_YAW_BEHAVIOUR) (vehicle defaults to faceing centre of orbit).
- [MAV_CMD_DO_ORBIT](https://mavlink.io/en/messages/common.html#MAV_CMD_DO_ORBIT) - Start an orbit with specified center point, radius, direction, altitude, speed and [yaw direction](https://mavlink.io/en/messages/common.html#ORBIT_YAW_BEHAVIOUR).
The same defaults and limits apply.
When exceeding limits the command is accepted but velocity and radius capped.
- [ORBIT_EXECUTION_STATUS](https://mavlink.io/en/messages/common.html#ORBIT_EXECUTION_STATUS) - Orbit status emitted during orbit to update GCS of current orbit parameters (these may be changed by the RC controller).
+2 -1
View File
@@ -80,7 +80,8 @@ Please continue reading for [upgrade instructions](#upgrade-guide).
### Fixed-wing
- TBD
- [Fixed Wing Takeoff mode](../flight_modes_fw/takeoff.md) will now keep climbing with level wings on position loss.
A target takeoff waypoint can be set to control takeoff course and loiter altitude. ([PX4-Autopilot#25083](https://github.com/PX4/PX4-Autopilot/pull/25083)).
### Rover
-2
View File
@@ -12,8 +12,6 @@ float32 x # X coordinate in meters
float32 y # Y coordinate in meters
float32 z # Z coordinate in meters
float32 roll # Pitch angle in radians
float32 pitch # Roll angle in radians
float32 yaw # Yaw angle in radians
bool valid_alt # true when the altitude has been set
+1
View File
@@ -5,6 +5,7 @@ menu "Magnetometer"
select DRIVERS_MAGNETOMETER_AKM_AK8963
select DRIVERS_MAGNETOMETER_AKM_AK09916
select DRIVERS_MAGNETOMETER_BOSCH_BMM150
select DRIVERS_MAGNETOMETER_BOSCH_BMM350
select DRIVERS_MAGNETOMETER_HMC5883
select DRIVERS_MAGNETOMETER_QMC5883L
select DRIVERS_MAGNETOMETER_QMC5883P
+3 -6
View File
@@ -999,10 +999,6 @@ Commander::handle_command(const vehicle_command_s &cmd)
}
} else {
float roll = matrix::wrap_2pi(math::radians(cmd.param2));
roll = PX4_ISFINITE(roll) ? roll : 0.0f;
float pitch = matrix::wrap_2pi(math::radians(cmd.param3));
pitch = PX4_ISFINITE(pitch) ? pitch : 0.0f;
float yaw = matrix::wrap_2pi(math::radians(cmd.param4));
yaw = PX4_ISFINITE(yaw) ? yaw : (float)NAN;
const double lat = cmd.param5;
@@ -1011,7 +1007,7 @@ Commander::handle_command(const vehicle_command_s &cmd)
if (PX4_ISFINITE(lat) && PX4_ISFINITE(lon) && PX4_ISFINITE(alt)) {
if (_home_position.setManually(lat, lon, alt, roll, pitch, yaw)) {
if (_home_position.setManually(lat, lon, alt, yaw)) {
cmd_result = vehicle_command_ack_s::VEHICLE_CMD_RESULT_ACCEPTED;
@@ -2347,6 +2343,7 @@ bool Commander::handleModeIntentionAndFailsafe()
}
// Handle failsafe action
_mode_management.setFailsafeState(_failsafe.selectedAction() > FailsafeBase::Action::Warn);
_vehicle_status.nav_state_user_intention = _mode_management.getNavStateReplacementIfValid(_user_mode_intention.get(),
false);
_vehicle_status.nav_state = _mode_management.getNavStateReplacementIfValid(FailsafeBase::modeFromAction(
@@ -2414,7 +2411,7 @@ void Commander::modeManagementUpdate()
{
ModeManagement::UpdateRequest mode_management_update{};
_mode_management.update(isArmed(), _vehicle_status.nav_state_user_intention,
_failsafe.selectedAction() > FailsafeBase::Action::Warn, mode_management_update);
mode_management_update);
if (!isArmed() && mode_management_update.change_user_intended_nav_state) {
_user_mode_intention.change(mode_management_update.user_intended_nav_state);
+8 -19
View File
@@ -1,6 +1,6 @@
/****************************************************************************
*
* Copyright (c) 2022-2025 PX4 Development Team. All rights reserved.
* Copyright (c) 2022-2023 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
@@ -99,9 +99,7 @@ bool HomePosition::setHomePosition(bool force)
const vehicle_local_position_s &lpos = _local_position_sub.get();
_heading_reset_counter = lpos.heading_reset_counter; // TODO: should not be here
const vehicle_attitude_s &attitude = _attitude_sub.get();
fillLocalHomePos(home, lpos, attitude);
fillLocalHomePos(home, lpos);
updated = true;
}
@@ -137,25 +135,19 @@ bool HomePosition::setHomePosition(bool force)
return updated;
}
void HomePosition::fillLocalHomePos(home_position_s &home, const vehicle_local_position_s &lpos,
const vehicle_attitude_s &attitude)
void HomePosition::fillLocalHomePos(home_position_s &home, const vehicle_local_position_s &lpos)
{
matrix::Quatf q(attitude.q);
matrix::Eulerf euler(q);
fillLocalHomePos(home, lpos.x, lpos.y, lpos.z, euler(0), euler(1), euler(2));
fillLocalHomePos(home, lpos.x, lpos.y, lpos.z, lpos.heading);
}
void HomePosition::fillLocalHomePos(home_position_s &home, float x, float y, float z, float roll, float pitch,
float yaw)
void HomePosition::fillLocalHomePos(home_position_s &home, float x, float y, float z, float heading)
{
home.x = x;
home.y = y;
home.z = z;
home.valid_lpos = true;
home.roll = roll;
home.pitch = pitch;
home.yaw = yaw;
home.yaw = heading;
}
void HomePosition::fillGlobalHomePos(home_position_s &home, const vehicle_global_position_s &gpos)
@@ -237,7 +229,7 @@ void HomePosition::setInAirHomePosition()
ref_pos.project(home.lat, home.lon, home_x, home_y);
const float home_z = -(home.alt - lpos.ref_alt);
fillLocalHomePos(home, home_x, home_y, home_z, NAN, NAN, NAN);
fillLocalHomePos(home, home_x, home_y, home_z, NAN);
home.timestamp = hrt_absolute_time();
home.update_count++;
@@ -253,7 +245,7 @@ void HomePosition::setInAirHomePosition()
}
}
bool HomePosition::setManually(double lat, double lon, float alt, float roll, float pitch, float yaw)
bool HomePosition::setManually(double lat, double lon, float alt, float yaw)
{
const vehicle_local_position_s &vehicle_local_position = _local_position_sub.get();
@@ -276,8 +268,6 @@ bool HomePosition::setManually(double lat, double lon, float alt, float roll, fl
home.z = -(alt - vehicle_local_position.ref_alt);
home.valid_lpos = vehicle_local_position.xy_valid && vehicle_local_position.z_valid;
home.roll = roll;
home.pitch = pitch;
home.yaw = yaw;
home.timestamp = hrt_absolute_time();
@@ -313,7 +303,6 @@ void HomePosition::update(bool set_automatically, bool check_if_changed)
{
_local_position_sub.update();
_global_position_sub.update();
_attitude_sub.update();
if (_vehicle_air_data_sub.updated()) {
vehicle_air_data_s baro_data;
+4 -7
View File
@@ -1,6 +1,6 @@
/****************************************************************************
*
* Copyright (c) 2022-2025 PX4 Development Team. All rights reserved.
* Copyright (c) 2022-2023 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
@@ -39,7 +39,6 @@
#include <uORB/topics/sensor_gps.h>
#include <uORB/topics/vehicle_global_position.h>
#include <uORB/topics/vehicle_local_position.h>
#include <uORB/topics/vehicle_attitude.h>
#include <uORB/topics/failsafe_flags.h>
#include <uORB/topics/vehicle_air_data.h>
#include <lib/mathlib/math/filter/AlphaFilter.hpp>
@@ -65,7 +64,7 @@ public:
bool setHomePosition(bool force = false);
void setInAirHomePosition();
bool setManually(double lat, double lon, float alt, float roll, float pitch, float yaw);
bool setManually(double lat, double lon, float alt, float yaw);
void setTakeoffTime(uint64_t takeoff_time) { _takeoff_time = takeoff_time; }
void update(bool set_automatically, bool check_if_changed);
@@ -77,9 +76,8 @@ private:
void setHomePosValid();
void updateHomePositionYaw(float yaw);
static void fillLocalHomePos(home_position_s &home, const vehicle_local_position_s &lpos,
const vehicle_attitude_s &attitude);
static void fillLocalHomePos(home_position_s &home, float x, float y, float z, float roll, float pitch, float yaw);
static void fillLocalHomePos(home_position_s &home, const vehicle_local_position_s &lpos);
static void fillLocalHomePos(home_position_s &home, float x, float y, float z, float heading);
static void fillGlobalHomePos(home_position_s &home, const vehicle_global_position_s &gpos);
static void fillGlobalHomePos(home_position_s &home, double lat, double lon, double alt);
@@ -87,7 +85,6 @@ private:
uORB::SubscriptionData<vehicle_global_position_s> _global_position_sub{ORB_ID(vehicle_global_position)};
uORB::SubscriptionData<vehicle_local_position_s> _local_position_sub{ORB_ID(vehicle_local_position)};
uORB::SubscriptionData<vehicle_attitude_s> _attitude_sub{ORB_ID(vehicle_attitude)};
uORB::Subscription _vehicle_air_data_sub{ORB_ID(vehicle_air_data)};
uint64_t _last_gps_timestamp{0};
+1 -3
View File
@@ -364,10 +364,8 @@ void ModeManagement::checkUnregistrations(uint8_t user_intended_nav_state, Updat
}
}
void ModeManagement::update(bool armed, uint8_t user_intended_nav_state, bool failsafe_action_active,
UpdateRequest &update_request)
void ModeManagement::update(bool armed, uint8_t user_intended_nav_state, UpdateRequest &update_request)
{
_failsafe_action_active = failsafe_action_active;
_external_checks.update();
bool allow_update_while_armed = _external_checks.allowUpdateWhileArmed();
+7 -2
View File
@@ -138,7 +138,11 @@ public:
bool control_setpoint_update{false};
};
void update(bool armed, uint8_t user_intended_nav_state, bool failsafe_action_active, UpdateRequest &update_request);
void update(bool armed, uint8_t user_intended_nav_state, UpdateRequest &update_request);
void setFailsafeState(bool failsafe_action_active)
{
_failsafe_action_active = failsafe_action_active;
}
/**
* Mode executor ID for who is currently in charge (and can send commands etc).
@@ -198,7 +202,8 @@ public:
bool control_setpoint_update{false};
};
void update(bool armed, uint8_t user_intended_nav_state, bool failsafe_action_active, UpdateRequest &update_request) {}
void update(bool armed, uint8_t user_intended_nav_state, UpdateRequest &update_request) {}
void setFailsafeState(bool failsafe_action_active) {}
int modeExecutorInCharge() const { return ModeExecutors::AUTOPILOT_EXECUTOR_ID; }
+4 -2
View File
@@ -618,13 +618,15 @@ PARAM_DEFINE_INT32(NAV_RCL_ACT, 2);
/**
* RC loss exceptions
*
* Specify modes in which RC loss is ignored and the failsafe action not triggered.
* Specify modes where manual control loss is ignored and no failsafe is triggered.
* External modes requiring stick input will still failsafe.
*
* @min 0
* @max 7
* @max 15
* @bit 0 Mission
* @bit 1 Hold
* @bit 2 Offboard
* @bit 3 External Mode
* @group Commander
*/
PARAM_DEFINE_INT32(COM_RCL_EXCEPT, 0);
+12 -1
View File
@@ -472,8 +472,19 @@ void Failsafe::checkStateAndMode(const hrt_abstime &time_us, const State &state,
state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_AUTO_VTOL_TAKEOFF)
&& (_param_com_rcl_except.get() & (int)ManualControlLossExceptionBits::Hold);
const bool rc_loss_ignored_external_mode =
(state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_EXTERNAL1 ||
state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_EXTERNAL2 ||
state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_EXTERNAL3 ||
state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_EXTERNAL4 ||
state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_EXTERNAL5 ||
state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_EXTERNAL6 ||
state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_EXTERNAL7 ||
state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_EXTERNAL8)
&& (_param_com_rcl_except.get() & (int)ManualControlLossExceptionBits::ExternalMode);
const bool rc_loss_ignored = rc_loss_ignored_mission || rc_loss_ignored_loiter || rc_loss_ignored_offboard ||
rc_loss_ignored_takeoff || ignore_any_link_loss_vtol_takeoff_fixedwing
rc_loss_ignored_takeoff || rc_loss_ignored_external_mode || ignore_any_link_loss_vtol_takeoff_fixedwing
|| _manual_control_lost_at_arming;
if (_param_com_rc_in_mode.get() != int32_t(RcInMode::StickInputDisabled) && !rc_loss_ignored) {
+2 -1
View File
@@ -56,7 +56,8 @@ private:
enum class ManualControlLossExceptionBits : int32_t {
Mission = (1 << 0),
Hold = (1 << 1),
Offboard = (1 << 2)
Offboard = (1 << 2),
ExternalMode = (1 << 3)
};
enum class DatalinkLossExceptionBits : int32_t {
@@ -370,6 +370,46 @@ TEST_F(FailsafeTest, defer)
ASSERT_FALSE(failsafe.failsafeDeferred());
}
TEST_F(FailsafeTest, defer_and_clear)
{
FailsafeTester failsafe(nullptr);
failsafe_flags_s failsafe_flags{};
FailsafeBase::State state{};
state.armed = true;
state.user_intended_mode = vehicle_status_s::NAVIGATION_STATE_POSCTL;
state.vehicle_type = vehicle_status_s::VEHICLE_TYPE_ROTARY_WING;
hrt_abstime time = 3847124342;
uint8_t updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
failsafe.deferFailsafes(true, -1);
ASSERT_TRUE(failsafe.getDeferFailsafes());
ASSERT_FALSE(failsafe.failsafeDeferred());
// Manual control lost -> deferred
time += 10_ms;
failsafe_flags.manual_control_signal_lost = true;
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::None);
ASSERT_TRUE(failsafe.failsafeDeferred());
// Clear flag (the failsafe action only clears on mode switch, but we still expect it to clear as it's being deferred)
failsafe_flags.manual_control_signal_lost = false;
time += 5_s;
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::None);
ASSERT_FALSE(failsafe.failsafeDeferred());
// Wait a bit, don't defer anymore -> no failsafe triggered
time += 1_s;
failsafe.deferFailsafes(false, 0);
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
ASSERT_EQ(updated_user_intented_mode, state.user_intended_mode);
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::None);
ASSERT_FALSE(failsafe.getDeferFailsafes());
ASSERT_FALSE(failsafe.failsafeDeferred());
}
TEST_F(FailsafeTest, skip_failsafe)
{
FailsafeTester failsafe(nullptr);
+15 -2
View File
@@ -396,7 +396,11 @@ bool FailsafeBase::checkFailsafe(int caller_id, bool last_state_failure, bool cu
void FailsafeBase::removeAction(ActionOptions &action) const
{
if (action.clear_condition == ClearCondition::WhenConditionClears) {
// If failsafes are being deferred and the action can be deferred, remove it immediately independent of the
// clear_condition to avoid triggering a failsafe after deferring is disabled.
const bool remove_while_deferring = _defer_failsafes && action.can_be_deferred;
if (action.clear_condition == ClearCondition::WhenConditionClears || remove_while_deferring) {
// Remove action
PX4_DEBUG("Caller %i: state changed to valid, removing action", action.id);
action.setInvalid();
@@ -482,8 +486,13 @@ void FailsafeBase::getSelectedAction(const State &state, const failsafe_flags_s
}
// Check if we should enter delayed Hold
const bool action_can_be_delayed = selected_action != Action::None &&
selected_action != Action::Disarm &&
selected_action != Action::Terminate &&
selected_action != Action::Hold;
if (_current_delay > 0 && !_user_takeover_active && allow_user_takeover <= UserTakeoverAllowed::AlwaysModeSwitchOnly
&& selected_action != Action::Disarm && selected_action != Action::Terminate && selected_action != Action::Hold) {
&& action_can_be_delayed) {
returned_state.delayed_action = selected_action;
selected_action = Action::Hold;
allow_user_takeover = UserTakeoverAllowed::AlwaysModeSwitchOnly;
@@ -711,6 +720,10 @@ bool FailsafeBase::deferFailsafes(bool enabled, int timeout_s)
return false;
}
if (!enabled && _failsafe_defer_started == 0) {
_current_delay = 0;
}
if (timeout_s == 0) {
_defer_timeout = DEFAULT_DEFER_TIMEOUT;
@@ -137,7 +137,7 @@ void AuxGlobalPosition::update(Ekf &ekf, const estimator::imuSample &imu_delayed
if (continuing_conditions) {
ekf.fuseHorizontalPosition(aid_src);
if (isTimedOut(aid_src.time_last_fuse, imu_delayed.time_us, ekf._params.no_aid_timeout_max)
if (isTimedOut(aid_src.time_last_fuse, imu_delayed.time_us, ekf._params.reset_timeout_max)
|| (_reset_counters.lat_lon != sample.lat_lon_reset_counter)) {
if (ekf.isOnlyActiveSourceOfHorizontalPositionAiding(ekf.control_status_flags().aux_gpos)) {
+14 -4
View File
@@ -81,16 +81,26 @@ void Ekf::resetHorizontalVelocityTo(const Vector2f &new_horz_vel, const Vector2f
const Vector2f delta_horz_vel = new_horz_vel - Vector2f(_state.vel);
_state.vel.xy() = new_horz_vel;
Vector2f hor_vel_var;
if (PX4_ISFINITE(new_horz_vel_var(0))) {
P.uncorrelateCovarianceSetVariance<1>(State::vel.idx, math::max(sq(0.01f), new_horz_vel_var(0)));
hor_vel_var(0) = math::max(sq(0.01f), new_horz_vel_var(0));
} else {
hor_vel_var(0) = P(State::vel.idx, State::vel.idx);
}
if (PX4_ISFINITE(new_horz_vel_var(1))) {
P.uncorrelateCovarianceSetVariance<1>(State::vel.idx + 1, math::max(sq(0.01f), new_horz_vel_var(1)));
hor_vel_var(1) = math::max(sq(0.01f), new_horz_vel_var(1));
} else {
hor_vel_var(1) = P(State::vel.idx + 1, State::vel.idx + 1);
}
P.uncorrelateCovarianceSetVariance<1>(State::pos.idx, P(State::pos.idx, State::pos.idx));
P.uncorrelateCovarianceSetVariance<1>(State::pos.idx + 1, P(State::pos.idx + 1, State::pos.idx + 1));
P.uncorrelateCovarianceSetVariance<2>(State::vel.idx, hor_vel_var);
// Position decorrelation is also required to avoid issues when no position aiding is active
P.uncorrelateCovarianceSetVariance<2>(State::pos.idx, getPositionVariance().xy());
_output_predictor.resetHorizontalVelocityTo(delta_horz_vel);
+3
View File
@@ -2099,6 +2099,9 @@ Mavlink::task_main(int argc, char *argv[])
} else if (strcmp(myoptarg, "uavionix") == 0) {
_mode = MAVLINK_MODE_UAVIONIX;
} else if (strcmp(myoptarg, "low_bandwidth") == 0) {
_mode = MAVLINK_MODE_LOW_BANDWIDTH;
} else {
PX4_ERR("invalid mode");
err_flag = true;
@@ -75,7 +75,7 @@ private:
msg.y = home.y;
msg.z = home.z;
matrix::Quatf q(matrix::Eulerf(home.roll, home.pitch, home.yaw));
matrix::Quatf q(matrix::Eulerf(0.f, 0.f, home.yaw));
q.copyTo(msg.q);
msg.approach_x = 0.f;
@@ -45,9 +45,16 @@ using namespace time_literals;
bool GotoControl::checkForSetpoint(const hrt_abstime &now, const bool enabled)
{
_goto_setpoint_sub.update();
const bool timestamp_initialized = _goto_setpoint_sub.get().timestamp != 0;
const bool no_timeout = now < (_goto_setpoint_sub.get().timestamp + 500_ms);
_goto_setpoint_sub.update(&_goto_setpoint);
if (!enabled) {
// Flag the setpoint as invalid if disabled, so if it is enabled in near future,
// we don't use an old setpoint
_goto_setpoint.timestamp = 0;
}
const bool timestamp_initialized = _goto_setpoint.timestamp != 0;
const bool no_timeout = now < (_goto_setpoint.timestamp + 500_ms);
const bool need_to_run = timestamp_initialized && no_timeout && enabled;
if (!need_to_run) {
@@ -65,9 +72,7 @@ void GotoControl::update(const float dt, const matrix::Vector3f &position, const
_is_initialized = true;
}
const goto_setpoint_s &goto_setpoint = _goto_setpoint_sub.get();
const Vector3f position_setpoint(_goto_setpoint_sub.get().position);
const Vector3f position_setpoint(_goto_setpoint.position);
if (!position_setpoint.isAllFinite()) {
// TODO: error messaging
@@ -85,7 +90,7 @@ void GotoControl::update(const float dt, const matrix::Vector3f &position, const
resetPositionSmoother(position);
}
setPositionSmootherLimits(goto_setpoint);
setPositionSmootherLimits(_goto_setpoint);
const Vector3f feedforward_velocity{};
const bool force_zero_velocity_setpoint = false;
@@ -99,13 +104,13 @@ void GotoControl::update(const float dt, const matrix::Vector3f &position, const
out_setpoints.acceleration.copyTo(trajectory_setpoint.acceleration);
out_setpoints.jerk.copyTo(trajectory_setpoint.jerk);
if (goto_setpoint.flag_control_heading && PX4_ISFINITE(goto_setpoint.heading) && PX4_ISFINITE(heading)) {
if (_goto_setpoint.flag_control_heading && PX4_ISFINITE(_goto_setpoint.heading) && PX4_ISFINITE(heading)) {
if (!_controlling_heading || _need_smoother_reset) {
resetHeadingSmoother(heading);
}
setHeadingSmootherLimits(goto_setpoint);
_heading_smoothing.update(goto_setpoint.heading, dt);
setHeadingSmootherLimits(_goto_setpoint);
_heading_smoothing.update(_goto_setpoint.heading, dt);
trajectory_setpoint.yaw = _heading_smoothing.getSmoothedHeading();
trajectory_setpoint.yawspeed = _heading_smoothing.getSmoothedHeadingRate();
@@ -121,11 +126,11 @@ void GotoControl::update(const float dt, const matrix::Vector3f &position, const
_need_smoother_reset = false;
trajectory_setpoint.timestamp = goto_setpoint.timestamp;
trajectory_setpoint.timestamp = hrt_absolute_time();
_trajectory_setpoint_pub.publish(trajectory_setpoint);
vehicle_constraints_s vehicle_constraints{
.timestamp = goto_setpoint.timestamp,
.timestamp = trajectory_setpoint.timestamp,
.speed_up = NAN,
.speed_down = NAN,
.want_takeoff = false
@@ -115,10 +115,11 @@ private:
*/
void setHeadingSmootherLimits(const goto_setpoint_s &goto_setpoint);
uORB::SubscriptionData<goto_setpoint_s> _goto_setpoint_sub{ORB_ID(goto_setpoint)};
uORB::Subscription _goto_setpoint_sub{ORB_ID(goto_setpoint)};
uORB::Publication<trajectory_setpoint_s> _trajectory_setpoint_pub{ORB_ID(trajectory_setpoint)};
uORB::Publication<vehicle_constraints_s> _vehicle_constraints_pub{ORB_ID(vehicle_constraints)};
goto_setpoint_s _goto_setpoint{};
PositionSmoothing _position_smoothing;
HeadingSmoothing _heading_smoothing;
@@ -426,9 +426,12 @@ void MulticopterPositionControl::Run()
PositionControlStates states{set_vehicle_states(vehicle_local_position, dt)};
// if a goto setpoint available this publishes a trajectory setpoint to go there
if (_goto_control.checkForSetpoint(vehicle_local_position.timestamp_sample,
_vehicle_control_mode.flag_multicopter_position_control_enabled)) {
// If a goto setpoint is available this publishes a trajectory setpoint to go there
// If trajectory_setpoint is published elsewhere, do not use the goto setpoint
const bool goto_setpoint_enable = _vehicle_control_mode.flag_multicopter_position_control_enabled
&& !_trajectory_setpoint_sub.updated();
if (_goto_control.checkForSetpoint(vehicle_local_position.timestamp_sample, goto_setpoint_enable)) {
_goto_control.update(dt, states.position, states.yaw);
}
@@ -61,12 +61,14 @@ void AckermannPosControl::updatePosControl()
if (target_waypoint_ned.isAllFinite()) {
float distance_to_target = (target_waypoint_ned - _curr_pos_ned).norm();
if (distance_to_target > _acceptance_radius) {
float arrival_speed = PX4_ISFINITE(_rover_position_setpoint.arrival_speed) ? _rover_position_setpoint.arrival_speed :
0.f;
const float distance = arrival_speed > 0.f + FLT_EPSILON ? distance_to_target - _acceptance_radius : distance_to_target;
if (_arrival_speed > FLT_EPSILON) {
distance_to_target -= _acceptance_radius; // shift target to the edge of the acceptance radius if arrival speed not zero
}
if (distance_to_target > _acceptance_radius || _arrival_speed > FLT_EPSILON) {
float speed_setpoint = math::trajectory::computeMaxSpeedFromDistance(_param_ro_jerk_limit.get(),
_param_ro_decel_limit.get(), distance, fabsf(arrival_speed));
_param_ro_decel_limit.get(), distance_to_target, fabsf(_arrival_speed));
speed_setpoint = math::min(speed_setpoint, _param_ro_speed_limit.get());
if (PX4_ISFINITE(_rover_position_setpoint.cruising_speed)) {
@@ -130,6 +132,7 @@ void AckermannPosControl::updateSubscriptions()
_rover_position_setpoint_sub.copy(&_rover_position_setpoint);
_start_ned = Vector2f(_rover_position_setpoint.start_ned[0], _rover_position_setpoint.start_ned[1]);
_start_ned = _start_ned.isAllFinite() ? _start_ned : _curr_pos_ned;
_arrival_speed = PX4_ISFINITE(_rover_position_setpoint.arrival_speed) ? _rover_position_setpoint.arrival_speed : 0.f;
}
}
@@ -106,6 +106,7 @@ private:
Quatf _vehicle_attitude_quaternion{};
Vector2f _curr_pos_ned{};
Vector2f _start_ned{};
float _arrival_speed{0.f};
float _vehicle_yaw{0.f};
float _max_yaw_rate{0.f};
float _acceptance_radius{0.f}; // Acceptance radius for the waypoint.
@@ -54,24 +54,19 @@ void DifferentialPosControl::updatePosControl()
hrt_abstime timestamp = hrt_absolute_time();
if (_rover_position_setpoint_sub.updated()) {
_rover_position_setpoint_sub.copy(&_rover_position_setpoint);
_start_ned = Vector2f(_rover_position_setpoint.start_ned[0], _rover_position_setpoint.start_ned[1]);
_start_ned = _start_ned.isAllFinite() ? _start_ned : _curr_pos_ned;
}
const Vector2f target_waypoint_ned(_rover_position_setpoint.position_ned[0], _rover_position_setpoint.position_ned[1]);
if (target_waypoint_ned.isAllFinite()) {
float distance_to_target = (target_waypoint_ned - _curr_pos_ned).norm();
if (distance_to_target > _param_nav_acc_rad.get()) {
float arrival_speed = PX4_ISFINITE(_rover_position_setpoint.arrival_speed) ? _rover_position_setpoint.arrival_speed :
0.f;
const float distance = arrival_speed > 0.f + FLT_EPSILON ? distance_to_target - _param_nav_acc_rad.get() :
distance_to_target;
if (_arrival_speed > FLT_EPSILON) {
distance_to_target -=
_param_nav_acc_rad.get(); // shift target to the edge of the acceptance radius if arrival speed not zero
}
if (distance_to_target > _param_nav_acc_rad.get() || _arrival_speed > FLT_EPSILON) {
float speed_setpoint = math::trajectory::computeMaxSpeedFromDistance(_param_ro_jerk_limit.get(),
_param_ro_decel_limit.get(), distance, fabsf(arrival_speed));
_param_ro_decel_limit.get(), distance_to_target, fabsf(_arrival_speed));
speed_setpoint = math::min(speed_setpoint, _param_ro_speed_limit.get());
if (PX4_ISFINITE(_rover_position_setpoint.cruising_speed)) {
@@ -119,6 +114,14 @@ void DifferentialPosControl::updateSubscriptions()
_curr_pos_ned = Vector2f(vehicle_local_position.x, vehicle_local_position.y);
}
if (_rover_position_setpoint_sub.updated()) {
_rover_position_setpoint_sub.copy(&_rover_position_setpoint);
_start_ned = Vector2f(_rover_position_setpoint.start_ned[0], _rover_position_setpoint.start_ned[1]);
_start_ned = _start_ned.isAllFinite() ? _start_ned : _curr_pos_ned;
_arrival_speed = PX4_ISFINITE(_rover_position_setpoint.arrival_speed) ? _rover_position_setpoint.arrival_speed : 0.f;
}
}
bool DifferentialPosControl::runSanityChecks()
@@ -103,6 +103,7 @@ private:
// Variables
Vector2f _curr_pos_ned{};
Vector2f _start_ned{};
float _arrival_speed{0.f};
float _vehicle_yaw{0.f};
DEFINE_PARAMETERS(
@@ -56,26 +56,21 @@ void MecanumPosControl::updatePosControl()
hrt_abstime timestamp = hrt_absolute_time();
if (_rover_position_setpoint_sub.updated()) {
_rover_position_setpoint_sub.copy(&_rover_position_setpoint);
_start_ned = Vector2f(_rover_position_setpoint.start_ned[0], _rover_position_setpoint.start_ned[1]);
_start_ned = _start_ned.isAllFinite() ? _start_ned : _curr_pos_ned;
_yaw_setpoint = PX4_ISFINITE(_rover_position_setpoint.yaw) ? _rover_position_setpoint.yaw : _vehicle_yaw;
}
const Vector2f target_waypoint_ned(_rover_position_setpoint.position_ned[0], _rover_position_setpoint.position_ned[1]);
if (target_waypoint_ned.isAllFinite()) {
float distance_to_target = (target_waypoint_ned - _curr_pos_ned).norm();
if (distance_to_target > _param_nav_acc_rad.get()) {
float arrival_speed = PX4_ISFINITE(_rover_position_setpoint.arrival_speed) ? _rover_position_setpoint.arrival_speed :
0.f;
const float distance = arrival_speed > 0.f + FLT_EPSILON ? distance_to_target - _param_nav_acc_rad.get() :
distance_to_target;
if (_arrival_speed > FLT_EPSILON) {
distance_to_target -=
_param_nav_acc_rad.get(); // shift target to the edge of the acceptance radius if arrival speed not zero
}
if (distance_to_target > _param_nav_acc_rad.get() || _arrival_speed > FLT_EPSILON) {
float speed_setpoint = math::trajectory::computeMaxSpeedFromDistance(_param_ro_jerk_limit.get(),
_param_ro_decel_limit.get(), distance, fabsf(arrival_speed));
_param_ro_decel_limit.get(), distance_to_target, fabsf(_arrival_speed));
speed_setpoint = math::min(speed_setpoint, _param_ro_speed_limit.get());
if (PX4_ISFINITE(_rover_position_setpoint.cruising_speed)) {
@@ -130,6 +125,14 @@ void MecanumPosControl::updateSubscriptions()
_curr_pos_ned = Vector2f(vehicle_local_position.x, vehicle_local_position.y);
}
if (_rover_position_setpoint_sub.updated()) {
_rover_position_setpoint_sub.copy(&_rover_position_setpoint);
_start_ned = Vector2f(_rover_position_setpoint.start_ned[0], _rover_position_setpoint.start_ned[1]);
_start_ned = _start_ned.isAllFinite() ? _start_ned : _curr_pos_ned;
_yaw_setpoint = PX4_ISFINITE(_rover_position_setpoint.yaw) ? _rover_position_setpoint.yaw : _vehicle_yaw;
_arrival_speed = PX4_ISFINITE(_rover_position_setpoint.arrival_speed) ? _rover_position_setpoint.arrival_speed : 0.f;
}
}
bool MecanumPosControl::runSanityChecks()
@@ -105,6 +105,7 @@ private:
Quatf _vehicle_attitude_quaternion{};
Vector2f _curr_pos_ned{};
Vector2f _start_ned{};
float _arrival_speed{0.f};
float _vehicle_yaw{0.f};
float _max_yaw_rate{0.f};
float _yaw_setpoint{NAN};
@@ -64,4 +64,4 @@ PARAM_DEFINE_FLOAT(SENS_BARO_RATE, 20.0f);
* @category system
* @group Sensors
*/
PARAM_DEFINE_INT32(SENS_BAR_AUTOCAL, 0);
PARAM_DEFINE_INT32(SENS_BAR_AUTOCAL, 1);
@@ -55,6 +55,7 @@ if(PX4_PLATFORM MATCHES "posix")
xvert
standard_vtol
hex
rover_ackermann
)
# find corresponding airframes
+78 -3
View File
@@ -211,7 +211,7 @@ void Sih::sensor_step()
read_motors(dt);
generate_force_and_torques();
generate_force_and_torques(dt);
equations_of_motion(dt);
@@ -290,6 +290,7 @@ void Sih::init_variables()
_lpos = Vector3f(0.0f, 0.0f, 0.0f);
_v_N = Vector3f(0.0f, 0.0f, 0.0f);
_v_N_dot = Vector3f(0.0f, 0.0f, 0.0f);
_p_E = Vector3d(Wgs84::equatorial_radius, 0.0, 0.0);
_v_E = Vector3f(0.0f, 0.0f, 0.0f);
_q = Quatf(1.0f, 0.0f, 0.0f, 0.0f);
@@ -318,7 +319,7 @@ void Sih::read_motors(const float dt)
}
}
void Sih::generate_force_and_torques()
void Sih::generate_force_and_torques(const float dt)
{
if (_vehicle == VehicleType::Quadcopter) {
_T_B = Vector3f(0.0f, 0.0f, -_T_MAX * (+_u[0] + _u[1] + _u[2] + _u[3]));
@@ -367,6 +368,9 @@ void Sih::generate_force_and_torques()
// thrust 0 because it is already contained in _T_B. in
// equations_of_motion they are all summed into sum_of_forces_E
generate_fw_aerodynamics(_u[4], _u[5], _u[6], 0);
} else if (_vehicle == VehicleType::RoverAckermann) {
generate_rover_ackermann_dynamics(_u[1], _u[0], dt);
}
}
@@ -422,6 +426,73 @@ void Sih::generate_ts_aerodynamics()
_Ma_B = _R_S2B * Ma_ts - _KDW * _w_B; // aerodynamic moments
}
void Sih::generate_rover_ackermann_dynamics(const float throttle_cmd, const float steering_cmd, const float dt)
{
// --- Constants ---
static constexpr float MAX_THROTTLE_FORCE = 400.0f; // [N]
static constexpr float MAX_STEER_ANGLE = radians(30.f); // [rad]
static constexpr float WHEEL_BASE = 0.321f; // [m] Distance between front and rear axle
static constexpr float C = 500.f; // [N/rad] Cornering stiffness
static constexpr float MU_S = 0.5f; // [-] Static Coefficient of friction
static constexpr float MU_K = 0.4f; // [-] Kinetic Coefficient of friction
static constexpr float MU_R = 0.3f; // [-] Rolling Coefficient of friction
static constexpr float ROLLING_THRESHOLD = 0.05f; // [m/s] Threshold for rolling resistance
static constexpr float STATIC_THRESHOLD = 0.01f; // [m/s] Threshold for static resistance
matrix::Vector3f v_B = _q.rotateVectorInverse(_v_N); // Nav -> Body
// --- Compute inputs ---
const float delta = MAX_STEER_ANGLE * steering_cmd; // [rad] Steering angle
const float F_x = MAX_THROTTLE_FORCE * throttle_cmd; // [N] Throttle force
// --- Compute forces and moments ---
float F_y = 0.f; // [N] Lateral force
float M_z = 0.f; // [Nm] Yaw moment
if (fabsf(v_B(0)) > ROLLING_THRESHOLD) {
// Equations based on the lateral dynamics of the bicycle model from [1]
// [1] Sri Anumakonda, Everything you need to know about Self-Driving Cars in <30 minutes
// Link: https://srianumakonda.medium.com/everything-you-need-to-know-about-self-driving-in-30-minutes-b38d68bd3427
const float a_y = C * delta / _MASS - fabsf(v_B(0)) * _w_B(2)
- 2 * C * v_B(1) / (_MASS * fabsf(v_B(0))); // [m/s^2] Lateral acceleration
const float psi_dot_dot = WHEEL_BASE * C * delta / _sih_izz.get()
- C * WHEEL_BASE * WHEEL_BASE * _w_B(2) / (_sih_izz.get() * fabsf(v_B(0))); // [rad/s^2] Yaw acceleration
F_y = _MASS * a_y; // Lateral force [N]
M_z = _sih_izz.get() * psi_dot_dot; // [Nm] Yaw moment
}
_T_B = Vector3f(F_x, F_y, 0.f);
_Mt_B = Vector3f(0.f, 0.f, M_z);
// --- Compute drag/friction forces and moments ---
Vector3f F_f = Vector3f(0.f, 0.f, 0.f); // [N] Friction force
Vector3f F_a = Vector3f(0.f, 0.f, 0.f); // [N] Aerodynamic force (neglect until rover is rolling)
if (_v_E.norm() < STATIC_THRESHOLD) { // Static friction
Vector3f F_f_B = Vector3f(sign(F_x) * math::min(fabsf(F_x), MU_S * _MASS * 9.81f), sign(F_y) * math::min(fabsf(F_y),
MU_S * _MASS * 9.81f), 0.f);
F_f = _q_E.rotateVector(F_f_B);
} else if (_v_E.norm() < ROLLING_THRESHOLD) { // Kinetic friction
if (_T_B.norm() > FLT_EPSILON) {
F_f = _v_E.unit_or_zero() * MU_K * _MASS * 9.81f;
} else {
F_f = _v_E * _MASS / dt; // Stop the vehicle
}
} else { // Rolling friction
F_f = _v_E.unit_or_zero() * MU_R * _MASS * 9.81f;
Vector3f v_E_squared = Vector3f(sign(_v_E(0)) * _v_E(0) * _v_E(0), sign(_v_E(1)) * _v_E(1) * _v_E(1),
sign(_v_E(2)) * _v_E(2) * _v_E(2));
F_a = _KDV * v_E_squared; // [N] Second order drag
}
_Fa_E = -F_a - F_f; // [N] Second order drag and friction
_Ma_B = -_KDW * _w_B; // [Nm] First order angular damper
}
float Sih::computeGravity(const double lat)
{
// Somigliana formula for gravitational acceleration
@@ -459,7 +530,8 @@ void Sih::equations_of_motion(const float dt)
_grounded = true;
} else if (_vehicle == VehicleType::FixedWing) {
} else if (_vehicle == VehicleType::FixedWing
|| _vehicle == VehicleType::RoverAckermann) {
Vector3f down_u = _R_N2E.col(2);
ground_force_E = -down_u * sum_of_forces_E * down_u;
@@ -749,6 +821,9 @@ int Sih::print_status()
} else if (_vehicle == VehicleType::StandardVTOL) {
PX4_INFO("Standard VTOL");
} else if (_vehicle == VehicleType::RoverAckermann) {
PX4_INFO("Rover Ackermann");
}
PX4_INFO("vehicle landed: %d", _grounded);
+3 -2
View File
@@ -151,7 +151,7 @@ private:
void read_motors(const float dt);
// generate the motors thrust and torque in the body frame
void generate_force_and_torques();
void generate_force_and_torques(const float dt);
// apply the equations of motion of a rigid body and integrate one step
void equations_of_motion(const float dt);
@@ -163,6 +163,7 @@ private:
void publish_ground_truth(const hrt_abstime &time_now_us);
void generate_fw_aerodynamics(const float roll_cmd, const float pitch_cmd, const float yaw_cmd, const float thrust);
void generate_ts_aerodynamics();
void generate_rover_ackermann_dynamics(const float throttle_cmd, const float steering_cmd, const float dt);
void sensor_step();
static float computeGravity(double lat);
@@ -220,7 +221,7 @@ private:
float _u[NUM_ACTUATORS_MAX] {}; // thruster signals
enum class VehicleType {Quadcopter, FixedWing, TailsitterVTOL, StandardVTOL, Hexacopter, First = Quadcopter, Last = Hexacopter}; // numbering dependent on parameter SIH_VEHICLE_TYPE
enum class VehicleType {Quadcopter, FixedWing, TailsitterVTOL, StandardVTOL, Hexacopter, RoverAckermann, First = Quadcopter, Last = RoverAckermann}; // numbering dependent on parameter SIH_VEHICLE_TYPE
VehicleType _vehicle = VehicleType::Quadcopter;
// aerodynamic segments for the fixedwing
@@ -334,6 +334,7 @@ PARAM_DEFINE_FLOAT(SIH_T_TAU, 0.05f);
* @value 2 Tailsitter
* @value 3 Standard VTOL
* @value 4 Hexacopter
* @value 5 Rover Ackermann
* @reboot_required true
* @group Simulation In Hardware
*/