1
0
Fork 0
mirror of https://github.com/iNavFlight/inav.git synced 2025-07-19 06:15:14 +03:00

Merge branch 'development' into dzikuvx-nav-yaw-adjustments

This commit is contained in:
Pawel Spychalski (DzikuVx) 2020-02-20 10:25:00 +01:00
commit e3b0327657
92 changed files with 1437 additions and 455 deletions

View file

@ -185,9 +185,11 @@ endif
ifneq ($(SEMIHOSTING),)
SEMIHOSTING_CFLAGS = -DSEMIHOSTING
SEMIHOSTING_LDFLAGS = --specs=rdimon.specs -lc -lrdimon
SYSLIB :=
else
SEMIHOSTING_CFLAGS =
SEMIHOSTING_LDFLAGS =
SYSLIB := -lnosys
endif
DEBUG_FLAGS = -ggdb3 -DDEBUG
@ -224,7 +226,7 @@ LDFLAGS = -lm \
-nostartfiles \
--specs=nano.specs \
-lc \
-lnosys \
$(SYSLIB) \
$(ARCH_FLAGS) \
$(LTO_FLAGS) \
$(DEBUG_FLAGS) \

View file

@ -138,8 +138,8 @@ A shorter form is also supported to enable and disable functions using `serial <
| rssi_max | 100 | The maximum RSSI value sent by the receiver, in %. For example, if your receiver's maximum RSSI value shows as 83% in the configurator/OSD set this parameter to 83. See also rssi_min. |
| rc_filter_frequency | 50 | RC data biquad filter cutoff frequency. Lower cutoff frequencies result in smoother response at expense of command control delay. Practical values are 20-50. Set to zero to disable entirely and use unsmoothed RC stick values |
| input_filtering_mode | OFF | Filter out noise from OpenLRS Telemetry RX |
| min_throttle | 1150 | These are min/max values (in us) that are sent to esc when armed. Defaults of 1150/1850 are OK for everyone, for use with AfroESC, they could be set to 1064/1864. |
| max_throttle | 1850 | These are min/max values (in us) that are sent to esc when armed. Defaults of 1150/1850 are OK for everyone, for use with AfroESC, they could be set to 1064/1864. If you have brushed motors, the value should be set to 2000. |
| throttle_idle | 15 | The percentage of the throttle range (`max_throttle` - `min_command`) above `min_command` used for minimum / idle throttle. |
| max_throttle | 1850 | This is the maximum value (in us) sent to esc when armed. Default of 1850 are OK for everyone (legacy). For modern ESCs, higher values (c. 2000) may be more appropriate. If you have brushed motors, the value should be set to 2000. |
| min_command | 1000 | This is the PWM value sent to ESCs when they are not armed. If ESCs beep slowly when powered up, try decreasing this value. It can also be used for calibrating all ESCs at once. |
| 3d_deadband_low | 1406 | Low value of throttle deadband for 3D mode (when stick is in the 3d_deadband_throttle range, the fixed values of 3d_deadband_low / _high are used instead) |
| 3d_deadband_high | 1514 | High value of throttle deadband for 3D mode (when stick is in the deadband range, the value in 3d_neutral is used instead) |
@ -182,7 +182,7 @@ A shorter form is also supported to enable and disable functions using `serial <
| nav_user_control_mode | ATTI | Defines how Pitch/Roll input from RC receiver affects flight in POSHOLD mode: ATTI - pitch/roll controls attitude like in ANGLE mode; CRUISE - pitch/roll controls velocity in forward and right direction. |
| nav_position_timeout | 5 | If GPS fails wait for this much seconds before switching to emergency landing mode (0 - disable) |
| nav_wp_radius | 100 | Waypoint radius [cm]. Waypoint would be considered reached if machine is within this radius |
| nav_wp_safe_distance | 10000 | First waypoint in the mission should be closer than this value [cm] |
| nav_wp_safe_distance | 10000 | First waypoint in the mission should be closer than this value [cm]. A value of 0 disables this check. |
| nav_auto_speed | 300 | Maximum velocity firmware is allowed in full auto modes (RTH, WP) [cm/s] [Multirotor only] |
| nav_auto_climb_rate | 500 | Maximum climb/descent rate that UAV is allowed to reach during navigation modes. [cm/s] |
| nav_manual_speed | 500 | Maximum velocity firmware is allowed when processing pilot input for POSHOLD/CRUISE control mode [cm/s] [Multirotor only] |
@ -221,9 +221,9 @@ A shorter form is also supported to enable and disable functions using `serial <
| nav_fw_launch_max_angle | 45 | Max tilt angle (pitch/roll combined) to consider launch successful. Set to 180 to disable completely [deg] |
| nav_fw_launch_detect_time | 40 | Time for which thresholds have to breached to consider launch happened [ms] |
| nav_fw_launch_thr | 1700 | Launch throttle - throttle to be set during launch sequence (pwm units) |
| nav_fw_launch_idle_thr | 1000 | Launch idle throttle - throttle to be set before launch sequence is initiated. If set below min_throttle it will force motor stop or at idle throttle (depending if the MOTOR_STOP is enabled). If set above min_throttle it will force throttle to this value (if MOTOR_STOP is enabled it will be handled according to throttle stick position) |
| nav_fw_launch_idle_thr | 1000 | Launch idle throttle - throttle to be set before launch sequence is initiated. If set below minimum throttle it will force motor stop or at idle throttle (depending if the MOTOR_STOP is enabled). If set above minimum throttle it will force throttle to this value (if MOTOR_STOP is enabled it will be handled according to throttle stick position) |
| nav_fw_launch_motor_delay | 500 | Delay between detected launch and launch sequence start and throttling up (ms) |
| nav_fw_launch_spinup_time | 100 | Time to bring power from min_throttle to nav_fw_launch_thr - to avoid big stress on ESC and large torque from propeller |
| nav_fw_launch_spinup_time | 100 | Time to bring power from minimum throttle to nav_fw_launch_thr - to avoid big stress on ESC and large torque from propeller |
| nav_fw_launch_timeout | 5000 | Maximum time for launch sequence to be executed. After this time LAUNCH mode will be turned off and regular flight mode will take over (ms) |
| nav_fw_launch_max_altitude | 0 | Altitude at which LAUNCH mode will be turned off and regular flight mode will take over. [cm] |
| nav_fw_launch_climb_angle | 18 | Climb angle for launch sequence (degrees), is also restrained by global max_angle_inclination_pit |
@ -290,7 +290,6 @@ A shorter form is also supported to enable and disable functions using `serial <
| pos_hold_deadband | 20 | Stick deadband in [r/c points], applied after r/c deadband and expo |
| alt_hold_deadband | 50 | Defines the deadband of throttle during alt_hold [r/c points] |
| yaw_motor_direction | 1 | Use if you need to inverse yaw motor direction. |
| yaw_jump_prevention_limit | 200 | Prevent yaw jumps during yaw stops and rapid YAW input. To disable set to 500. Adjust this if your aircraft 'skids out'. Higher values increases YAW authority but can cause roll/pitch instability in case of underpowered UAVs. Lower values makes yaw adjustments more gentle but can cause UAV unable to keep heading |
| tri_unarmed_servo | ON | On tricopter mix only, if this is set to ON, servo will always be correcting regardless of armed state. to disable this, set it to OFF. |
| servo_lpf_hz | 20 | Selects the servo PWM output cutoff frequency. Value is in [Hz] |
| servo_center_pulse | 1500 | Servo midpoint |
@ -364,8 +363,6 @@ A shorter form is also supported to enable and disable functions using `serial <
| nav_mc_vel_z_i | 50 | I gain of velocity PID controller |
| nav_mc_vel_z_d | 10 | D gain of velocity PID controller |
| nav_mc_pos_xy_p | 65 | Controls how fast the drone will fly towards the target position. This is a multiplier to convert displacement to target velocity |
| nav_mc_pos_xy_i | 120 | Controls deceleration time. Measured in 1/100 sec. Expected hold position is placed at a distance calculated as decelerationTime * currentVelocity |
| nav_mc_pos_xy_d | 10 | |
| nav_mc_vel_xy_p | 40 | P gain of Position-Rate (Velocity to Acceleration) PID controller. Higher P means stronger response when position error occurs. Too much P might cause "nervous" behavior and oscillations |
| nav_mc_vel_xy_i | 15 | I gain of Position-Rate (Velocity to Acceleration) PID controller. Used for drift compensation (caused by wind for example). Higher I means stronger response to drift. Too much I gain might cause target overshot |
| nav_mc_vel_xy_d | 100 | D gain of Position-Rate (Velocity to Acceleration) PID controller. It can damp P and I. Increasing D might help when drone overshoots target. |
@ -420,14 +417,23 @@ A shorter form is also supported to enable and disable functions using `serial <
| acc_lpf_hz | 15 | Software-based filter to remove mechanical vibrations from the accelerometer measurements. Value is cutoff frequency (Hz). For larger frames with bigger props set to lower value. |
| acc_lpf_type | BIQUAD | Specifies the type of the software LPF of the acc signals. BIQUAD gives better filtering and more delay, PT1 less filtering and less delay, so use only on clean builds. |
| dterm_lpf_hz | 40 | Dterm low pass filter cutoff frequency. Default setting is very conservative and small multirotors should use higher value between 80 and 100Hz. 80 seems like a gold spot for 7-inch builds while 100 should work best with 5-inch machines. If motors are getting too hot, lower the value |
| dterm_lpf_type | `BIQUAD` | Defines the type of stage 1 D-term LPF filter. Possible values: `PT1`, `BIQUAD`. `PT1` offers faster filter response while `BIQUAD` better attenuation. |
| dterm_lpf2_hz | 0 | Cutoff frequency for stage 2 D-term low pass filter |
| dterm_lpf2_type | `BIQUAD` | Defines the type of stage 1 D-term LPF filter. Possible values: `PT1`, `BIQUAD`. `PT1` offers faster filter response while `BIQUAD` better attenuation. |
| yaw_lpf_hz | 30 | Yaw low pass filter cutoff frequency. Should be disabled (set to `0`) on small multirotors (7 inches and below) |
| dyn_notch_width_percent | 8 | Distance in % of the attenuated frequency for double dynamic filter notched. When set to `0` single dynamic notch filter is used |
| dyn_notch_range | MEDIUM | Dynamic gyro filter range. Possible values `LOW` `MEDIUM` `HIGH`. `MEDIUM` should work best for 5-6" multirotors. `LOW` should work best with 7" and bigger. `HIGH` should work with everything below 4" |
| dyn_notch_q | 120 | Q factor for dynamic notches |
| dyn_notch_min_hz | 150 | Minimum frequency for dynamic notches. Default value of `150` works best with 5" multirors. Should be lowered with increased size of propellers. Values around `100` work fine on 7" drones. 10" can go down to `60` - `70` |
| gyro_stage2_lowpass_hz | 0 | Software based second stage lowpass filter for gyro. Value is cutoff frequency (Hz). Currently experimental |
| gyro_stage2_lowpass_hz | 0 | Software based second stage lowpass filter for gyro. Value is cutoff frequency (Hz) |
| gyro_stage2_lowpass_type | `BIQUAD` | Defines the type of stage 2 gyro LPF filter. Possible values: `PT1`, `BIQUAD`. `PT1` offers faster filter response while `BIQUAD` better attenuation. |
| rpm_gyro_filter_enabled | `OFF` | Enables gyro RPM filtere. Set to `ON` only when ESC telemetry is working and rotation speed of the motors is correctly reported to INAV |
| rpm_gyro_harmonics | 1 | Number of harmonic frequences to be covered by gyro RPM filter. Default value of `1` usually works just fine |
| rpm_gyro_min_hz | 150 | The lowest frequency for gyro RPM filtere. Default `150` is fine for 5" mini-quads. On 7-inch drones you can lower even down to `60`-`70` |
| rpm_gyro_q | 500 | Q factor for gyro RPM filter. Lower values give softer, wider attenuation. Usually there is no need to change this setting |
| pidsum_limit | 500 | A limitation to overall amount of correction Flight PID can request on each axis (Roll/Pitch). If when doing a hard maneuver on one axis machine looses orientation on other axis - reducing this parameter may help |
| pidsum_limit_yaw | 400 | A limitation to overall amount of correction Flight PID can request on each axis (Yaw). If when doing a hard maneuver on one axis machine looses orientation on other axis - reducing this parameter may help |
| `pid_type` | Allows to set type of PID controller used in control loop. Possible values: `NONE`, `PID`, `PIFF`, `AUTO`. Change only in case of experimental platforms like VTOL, tailsitters, rovers, boats, etc. Airplanes should always use `PIFF` and multirotors `PID` |
| iterm_windup | 50 | Used to prevent Iterm accumulation on during maneuvers. Iterm will be dampened when motors are reaching it's limit (when requested motor correction range is above percentage specified by this parameter) |
| rate_accel_limit_roll_pitch | 0 | Limits acceleration of ROLL/PITCH rotation speed that can be requested by stick input. In degrees-per-second-squared. Small and powerful UAV flies great with high acceleration limit ( > 5000 dps^2 and even > 10000 dps^2). Big and heavy multirotors will benefit from low acceleration limit (~ 360 dps^2). When set correctly, it greatly improves stopping performance. Value of 0 disables limiting. |
| rate_accel_limit_yaw | 10000 | Limits acceleration of YAW rotation speed that can be requested by stick input. In degrees-per-second-squared. Small and powerful UAV flies great with high acceleration limit ( > 10000 dps^2). Big and heavy multirotors will benefit from low acceleration limit (~ 180 dps^2). When set correctly, it greatly improves stopping performance and general stability during yaw turns. Value of 0 disables limiting. |

View file

@ -2,12 +2,9 @@
## Arming
When armed, the aircraft is ready to fly and the motors will spin when throttle is applied. The motors will
spin at a slow speed when armed (this feature may be disabled by setting MOTOR_STOP, but for safety reasons,
that is not recommended).
When armed, the aircraft is ready to fly and the motors will spin when throttle is applied. The motors will spin at a slow speed when armed (this feature may be disabled by setting MOTOR_STOP, but for safety reasons, that is not recommended).
By default, arming and disarming is done using stick positions. (NOTE: this feature is disabled when using a
switch to arm.)
By default, arming and disarming is done using stick positions. (NOTE: this feature is disabled when using a switch to arm.)
## Stick Positions
@ -45,14 +42,9 @@ The stick positions are combined to activate different functions:
## Yaw control
While arming/disarming with sticks, your yaw stick will be moving to extreme values. In order to prevent your craft
from trying to yaw during arming/disarming while on the ground, your yaw input will not cause the craft to yaw when the
throttle is LOW (i.e. below the `min_check` setting).
While arming/disarming with sticks, your yaw stick will be moving to extreme values. In order to prevent your craft from trying to yaw during arming/disarming while on the ground, your yaw input will not cause the craft to yaw when the throttle is LOW (i.e. below the `min_check` setting).
For tricopters, you may want to retain the ability to yaw while on the ground, so that you can verify that your tail
servo is working correctly before takeoff. You can do this by setting `tri_unarmed_servo` to `1` on the CLI (this is the
default). If you are having issues with your tail rotor contacting the ground during arm/disarm, you can set this to
`0` instead. Check this table to decide which setting will suit you:
For tricopters, you may want to retain the ability to yaw while on the ground, so that you can verify that your tail servo is working correctly before takeoff. You can do this by setting `tri_unarmed_servo` to `1` on the CLI (this is the default). If you are having issues with your tail rotor contacting the ground during arm/disarm, you can set this to `0` instead. Check this table to decide which setting will suit you:
<table>
<tr>
@ -78,23 +70,24 @@ default). If you are having issues with your tail rotor contacting the ground du
</tr>
</table>
## Throttle settings and their interaction
*Terminology. After iNav 2.3, the setting `min_throttle` was replaced with `throttle_idle` which is more appropriate to modern hardware. In this document `min_throttle` may be taken as either the older `min_throttle` value, or the throttle value calculated from the modern `throttle_idle` setting. The way that `throttle_idle` generates a throttle value is described in `Cli.md`.*
`min_command` -
With motor stop enabled this is the command sent to the esc's when the throttle is below min_check or disarmed. With motor stop disabled, this is the command sent only when the copter is disarmed. This must be set well below motors spinning for safety.
`min_check` -
With switch arming mode is in use, lowering your throttle below min_check will result in motors spinning at min_throttle. When using the default stick arming, lowering your throttle below min_check will result in motors spinning at min_throttle and yaw being disabled so that you may arm/disarm. With motor stop enabled, lowering your throttle below min_check will also result in motors off and the esc's being sent min_command. Min_check must be set to a level that is 100% reliably met by the throttle throw. A setting too low may result in a dangerous condition where the copter cant be disarmed. It is ok to set this below min_throttle because the FC will automaticly scale the output to the esc's
With switch arming mode is in use, lowering your throttle below min_check will result in motors spinning at `throttle_idle` (min_throttle). When using the default stick arming, lowering your throttle below min_check will result in motors spinning at min_throttle and yaw being disabled so that you may arm/disarm. With motor stop enabled, lowering your throttle below min_check will also result in motors off and the esc's being sent min_command. Min_check must be set to a level that is 100% reliably met by the throttle throw. A setting too low may result in a dangerous condition where the copter cant be disarmed. It is ok to set this below `throttle_idle` (min_throttle) because the FC will automaticly scale the output to the ESCs
`min_throttle` -
`throttle_idle` (previously `min_throttle)` -
Typically set to just above reliable spin up of all motors. Sometimes this is set slightly higher for prop stall prevention during advanced maneuvers or sometimes considerably higher to produce a desired result. When armed with motor stop off, your motors will spin at this command so keep that in mind from a safety stand point.
`max_check` -
Throttle positions above this level will send max_command to the esc's.
Throttle positions above this level will send max_command to the ESCs.
`max_throttle` -
This is the max command to the esc's from the flight controller.
This is the max command to the ESCs from the flight controller.
In depth videos explaining these terms are available from Joshua Bardwell here:

View file

@ -0,0 +1,127 @@
# Serial printf style debugging
## Overview
inav offers a function to use serial `printf` style debugging.
This provides a simple and intuitive debugging facility. This facility is only available after the serial sub-system has been initialised, which should be adequate for all but the most hard-core debugging requirements.
In order to use this feature, the source file must include `common/log.h`.
## CLI settings
It is necessary to set a serial port for serial logging using the function mask `FUNCTION_LOG`, 32768. For convenience this may be shared with MSP (mask 1), but no other function.
For example, on a VCP port.
```
serial 20 32769 115200 115200 0 115200
```
If the port is shared, it will be resused with extant settings; if the port is not shared it is opened at 921600 baud.
There are two run time settings that control the verbosity, the most verbose settings being:
```
log_level = DEBUG
Allowed values: ERROR, WARNING, INFO, VERBOSE, DEBUG
log_topics = 0
Allowed range: 0 - 4294967295
```
The use of level and topics is described in the following sections.
## LOG LEVELS
Log levels are defined in `src/main/common/log.h`, at the time of writing these include (in ascending order):
* ERROR
* WARNING
* INFO
* VERBOSE
* DEBUG
These are used at both compile time and run time.
At compile time, a maximum level may be defined. As of inav 2.3, for F3 targets the maximum level is ERROR, for F4/F7 the maximum level is DEBUG.
At run time, the level defines the level that will be displayed, so for a F4 or F7 target that has compile time suport for all log levels, if the CLI sets
```
log_level = INFO
```
then only `ERROR`, `WARNING` and `INFO` levels will be output.
## Log Topic
Log topics are defined in `src/main/common/log.h`, at the time of writing:
* SYSTEM
* GYRO
* BARO
* PITOT
* PWM
* TIMER
* IMU
* TEMPERATURE
* POS_ESTIMATOR
* VTX
* OSD
Topics are stored as masks (SYSTEM=1 ... OSD=1024) and may be used to unconditionally display log messages.
If the CLI `log_topics` is non-zero, then all topics matching the mask will be displayed regardless of `log_level`. Setting `log_topics` to 4294967295 (all bits set) will display all log messages regardless of run time level (but still constrained by compile time settings), so F3 will still only display ERROR level messages.
## Code usage
A set of macros `LOG_S()` (log system) through `LOG_D()` (log debug) may be used, subject to compile time log level constraints. These provide `printf` style logging for a given topic.
```
// LOG_D(topic, fmt, ...)
LOG_D(SYSTEM, "This is %s topic debug message, value %d", "system", 42);
```
It is also possible to dump a hex representation of arbitrary data:
```
// LOG_BUF_D(topic, buf, size)
struct {...} tstruct;
...
LOG_BUF_D(TEMPERATURE, &tstruct, sizeof(tstruct));
```
## Output Support
Log messages are transmitted through the `FUNCTION_LOG` serial port as MSP messages (`MSP_DEBUGMSG`). It is possible to use any serial terminal to display these messages, however it is advisable to use an application that understands `MSP_DEBUGMSG` in order to maintain readability (in a raw serial terminal the MSP message envelope may result in the display of strange characters). `MSP_DEBUGMSG` aware applications include:
* msp-tool https://github.com/fiam/msp-tool
* mwp https://github.com/stronnag/mwptools
* inav Configurator
For example, with the final lines of `src/main/fc/fc_init.c` set to:
```
LOG_E(SYSTEM, "Init is complete");
systemState |= SYSTEM_STATE_READY;
```
and the following CLI settings:
```
serial 20 32769 115200 115200 0 115200
set log_level = DEBUG
set log_topics = 4294967295
```
The output will be formatted as follows:
```
# msp-tool
[DEBUG] [ 3.967] Init is complete
# mwp (stderr log file)
2020-02-02T19:09:02+0000 DEBUG:[ 3.968] Init is complete
```
The numeric value in square brackets is the FC uptime in seconds.

View file

@ -25,7 +25,7 @@ RELEASE_TARGETS += NOX WINGFC
RELEASE_TARGETS += OMNIBUSF4V6
RELEASE_TARGETS += MAMBAF405
RELEASE_TARGETS += MAMBAF405 MAMBAF405US MAMBAF722
RELEASE_TARGETS += IFLIGHTF7_TWING IFLIGHTF4_TWING

View file

@ -101,6 +101,7 @@ COMMON_SRC = \
io/beeper.c \
io/esc_serialshot.c \
io/frsky_osd.c \
io/osd_dji_hd.c \
io/lights.c \
io/piniobox.c \
io/pwmdriver_i2c.c \

View file

@ -7,8 +7,9 @@
#
###############################################################
GCC_REQUIRED_VERSION ?= 8.2.1
ARM_SDK_DIR ?= $(TOOLS_DIR)/gcc-arm-none-eabi-8-2018-q4-major
GCC_REQUIRED_VERSION ?= 9.2.1
ARM_SDK_DIR ?= $(TOOLS_DIR)/gcc-arm-none-eabi-9-2019-q4-major
ARM_SDK_URL_BASE := https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-rm/9-2019q4/gcc-arm-none-eabi-9-2019-q4-major
.PHONY: arm_sdk_version
@ -17,11 +18,9 @@ arm_sdk_version:
.PHONY: arm_sdk_install
ARM_SDK_URL_BASE := https://developer.arm.com/-/media/Files/downloads/gnu-rm/8-2018q4/gcc-arm-none-eabi-8-2018-q4-major
# source: https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads
ifdef LINUX
ARM_SDK_URL := $(ARM_SDK_URL_BASE)-linux.tar.bz2
ARM_SDK_URL := $(ARM_SDK_URL_BASE)-x86_64-linux.tar.bz2
endif
ifdef MACOSX

View file

@ -624,14 +624,14 @@ static bool testBlackboxConditionUncached(FlightLogFieldCondition condition)
case FLIGHT_LOG_FIELD_CONDITION_FIXED_WING_NAV:
#ifdef USE_NAV
return STATE(FIXED_WING);
return STATE(FIXED_WING_LEGACY);
#else
return false;
#endif
case FLIGHT_LOG_FIELD_CONDITION_MC_NAV:
#ifdef USE_NAV
return !STATE(FIXED_WING);
return !STATE(FIXED_WING_LEGACY);
#else
return false;
#endif
@ -755,7 +755,7 @@ static void writeIntraframe(void)
* Write the throttle separately from the rest of the RC data so we can apply a predictor to it.
* Throttle lies in range [minthrottle..maxthrottle]:
*/
blackboxWriteUnsignedVB(blackboxCurrent->rcCommand[THROTTLE] - motorConfig()->minthrottle);
blackboxWriteUnsignedVB(blackboxCurrent->rcCommand[THROTTLE] - getThrottleIdleValue());
if (testBlackboxCondition(FLIGHT_LOG_FIELD_CONDITION_VBAT)) {
/*
@ -809,7 +809,7 @@ static void writeIntraframe(void)
}
//Motors can be below minthrottle when disarmed, but that doesn't happen much
blackboxWriteUnsignedVB(blackboxCurrent->motor[0] - motorConfig()->minthrottle);
blackboxWriteUnsignedVB(blackboxCurrent->motor[0] - getThrottleIdleValue());
//Motors tend to be similar to each other so use the first motor's value as a predictor of the others
const int motorCount = getMotorCount();
@ -1369,7 +1369,7 @@ static void loadMainState(timeUs_t currentTimeUs)
blackboxCurrent->magADC[i] = mag.magADC[i];
#endif
#ifdef USE_NAV
if (!STATE(FIXED_WING)) {
if (!STATE(FIXED_WING_LEGACY)) {
// log requested velocity in cm/s
blackboxCurrent->mcPosAxisP[i] = lrintf(nav_pids->pos[i].output_constrained);
@ -1384,7 +1384,7 @@ static void loadMainState(timeUs_t currentTimeUs)
}
#ifdef USE_NAV
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
// log requested pitch in decidegrees
blackboxCurrent->fwAltPID[0] = lrintf(nav_pids->fw_alt.proportional);
@ -1618,10 +1618,10 @@ static bool blackboxWriteSysinfo(void)
BLACKBOX_PRINT_HEADER_LINE("Log start datetime", "%s", blackboxGetStartDateTime(buf));
BLACKBOX_PRINT_HEADER_LINE("Craft name", "%s", systemConfig()->name);
BLACKBOX_PRINT_HEADER_LINE("P interval", "%u/%u", blackboxConfig()->rate_num, blackboxConfig()->rate_denom);
BLACKBOX_PRINT_HEADER_LINE("minthrottle", "%d", motorConfig()->minthrottle);
BLACKBOX_PRINT_HEADER_LINE("minthrottle", "%d", getThrottleIdleValue());
BLACKBOX_PRINT_HEADER_LINE("maxthrottle", "%d", motorConfig()->maxthrottle);
BLACKBOX_PRINT_HEADER_LINE("gyro_scale", "0x%x", castFloatBytesToInt(1.0f));
BLACKBOX_PRINT_HEADER_LINE("motorOutput", "%d,%d", motorConfig()->minthrottle,motorConfig()->maxthrottle);
BLACKBOX_PRINT_HEADER_LINE("motorOutput", "%d,%d", getThrottleIdleValue(),motorConfig()->maxthrottle);
BLACKBOX_PRINT_HEADER_LINE("acc_1G", "%u", acc.dev.acc_1G);
BLACKBOX_PRINT_HEADER_LINE_CUSTOM(
@ -1682,12 +1682,21 @@ static bool blackboxWriteSysinfo(void)
pidBank()->pid[PID_VEL_Z].D);
BLACKBOX_PRINT_HEADER_LINE("yaw_lpf_hz", "%d", pidProfile()->yaw_lpf_hz);
BLACKBOX_PRINT_HEADER_LINE("dterm_lpf_hz", "%d", pidProfile()->dterm_lpf_hz);
BLACKBOX_PRINT_HEADER_LINE("dterm_lpf_type", "%d", pidProfile()->dterm_lpf_type);
BLACKBOX_PRINT_HEADER_LINE("dterm_lpf2_hz", "%d", pidProfile()->dterm_lpf2_hz);
BLACKBOX_PRINT_HEADER_LINE("dterm_lpf2_type", "%d", pidProfile()->dterm_lpf2_type);
BLACKBOX_PRINT_HEADER_LINE("dterm_notch_hz", "%d", pidProfile()->dterm_soft_notch_hz);
BLACKBOX_PRINT_HEADER_LINE("dterm_notch_cutoff", "%d", pidProfile()->dterm_soft_notch_cutoff);
BLACKBOX_PRINT_HEADER_LINE("deadband", "%d", rcControlsConfig()->deadband);
BLACKBOX_PRINT_HEADER_LINE("yaw_deadband", "%d", rcControlsConfig()->yaw_deadband);
BLACKBOX_PRINT_HEADER_LINE("gyro_lpf", "%d", gyroConfig()->gyro_lpf);
BLACKBOX_PRINT_HEADER_LINE("gyro_lpf_hz", "%d", gyroConfig()->gyro_soft_lpf_hz);
BLACKBOX_PRINT_HEADER_LINE("gyro_lpf_type", "%d", gyroConfig()->gyro_soft_lpf_type);
BLACKBOX_PRINT_HEADER_LINE("gyro_lpf2_hz", "%d", gyroConfig()->gyro_stage2_lowpass_hz);
BLACKBOX_PRINT_HEADER_LINE("dyn_notch_width_percent", "%d", gyroConfig()->dyn_notch_width_percent);
BLACKBOX_PRINT_HEADER_LINE("dyn_notch_range", "%d", gyroConfig()->dyn_notch_range);
BLACKBOX_PRINT_HEADER_LINE("dyn_notch_q", "%d", gyroConfig()->dyn_notch_q);
BLACKBOX_PRINT_HEADER_LINE("dyn_notch_min_hz", "%d", gyroConfig()->dyn_notch_min_hz);
BLACKBOX_PRINT_HEADER_LINE("gyro_notch_hz", "%d,%d", gyroConfig()->gyro_soft_notch_hz_1,
gyroConfig()->gyro_soft_notch_hz_2);
BLACKBOX_PRINT_HEADER_LINE("gyro_notch_cutoff", "%d,%d", gyroConfig()->gyro_soft_notch_cutoff_1,
@ -1717,10 +1726,6 @@ static bool blackboxWriteSysinfo(void)
BLACKBOX_PRINT_HEADER_LINE("rpm_gyro_harmonics", "%d", rpmFilterConfig()->gyro_harmonics);
BLACKBOX_PRINT_HEADER_LINE("rpm_gyro_min_hz", "%d", rpmFilterConfig()->gyro_min_hz);
BLACKBOX_PRINT_HEADER_LINE("rpm_gyro_q", "%d", rpmFilterConfig()->gyro_q);
BLACKBOX_PRINT_HEADER_LINE("rpm_dterm_filter_enabled", "%d", rpmFilterConfig()->dterm_filter_enabled);
BLACKBOX_PRINT_HEADER_LINE("rpm_dterm_harmonics", "%d", rpmFilterConfig()->dterm_harmonics);
BLACKBOX_PRINT_HEADER_LINE("rpm_dterm_min_hz", "%d", rpmFilterConfig()->dterm_min_hz);
BLACKBOX_PRINT_HEADER_LINE("rpm_dterm_q", "%d", rpmFilterConfig()->dterm_q);
#endif
default:
return true;

View file

@ -16,7 +16,7 @@
*/
#define FC_VERSION_MAJOR 2 // increment when a major release is made (big new feature, etc)
#define FC_VERSION_MINOR 4 // increment when a minor release is made (small new feature, change etc)
#define FC_VERSION_MINOR 5 // increment when a minor release is made (small new feature, change etc)
#define FC_VERSION_PATCH_LEVEL 0 // increment when a bug is fixed
#define STR_HELPER(x) #x

View file

@ -63,6 +63,7 @@
#include "fc/settings.h"
#include "flight/mixer.h"
#include "flight/servos.h"
// For VISIBLE*
#include "io/osd.h"
@ -765,6 +766,7 @@ void cmsMenuOpen(void)
{
if (!cmsInMenu) {
// New open
setServoOutputEnabled(false);
pCurrentDisplay = cmsDisplayPortSelectCurrent();
if (!pCurrentDisplay)
return;
@ -860,6 +862,8 @@ long cmsMenuExit(displayPort_t *pDisplay, const void *ptr)
displayRelease(pDisplay);
currentCtx.menu = NULL;
setServoOutputEnabled(true);
if ((exitType == CMS_EXIT_SAVEREBOOT) || (exitType == CMS_POPUP_SAVEREBOOT)) {
displayClearScreen(pDisplay);
displayWrite(pDisplay, 5, 3, "REBOOTING...");

View file

@ -42,7 +42,7 @@ static const OSD_Entry menuMiscEntries[]=
{
OSD_LABEL_ENTRY("-- MISC --"),
OSD_SETTING_ENTRY("MIN THR", SETTING_MIN_THROTTLE),
OSD_SETTING_ENTRY("THR IDLE", SETTING_THROTTLE_IDLE),
#if defined(USE_OSD) && defined(USE_ADC)
OSD_SETTING_ENTRY("OSD VOLT DECIMALS", SETTING_OSD_MAIN_VOLTAGE_DECIMALS),
OSD_SETTING_ENTRY("STATS ENERGY UNIT", SETTING_OSD_STATS_ENERGY_UNIT),

View file

@ -271,6 +271,10 @@ static const OSD_Entry menuOsdElemsEntries[] =
OSD_ELEMENT_ENTRY("SENSOR 7 TEMP", OSD_TEMP_SENSOR_7_TEMPERATURE),
#endif
#ifdef USE_ESC_SENSOR
OSD_ELEMENT_ENTRY("ESC RPM", OSD_ESC_RPM),
#endif
OSD_BACK_AND_END_ENTRY,
};

View file

@ -38,7 +38,7 @@
#include "common/axis.h"
PG_REGISTER_ARRAY(globalFunction_t, MAX_GLOBAL_FUNCTIONS, globalFunctions, PG_GLOBAL_FUNCTIONS, 0);
PG_REGISTER_ARRAY_WITH_RESET_FN(globalFunction_t, MAX_GLOBAL_FUNCTIONS, globalFunctions, PG_GLOBAL_FUNCTIONS, 0);
EXTENDED_FASTRAM uint64_t globalFunctionsFlags = 0;
EXTENDED_FASTRAM globalFunctionState_t globalFunctionsStates[MAX_GLOBAL_FUNCTIONS];

View file

@ -42,25 +42,6 @@
PG_REGISTER_ARRAY(logicCondition_t, MAX_LOGIC_CONDITIONS, logicConditions, PG_LOGIC_CONDITIONS, 0);
void pgResetFn_logicConditions(logicCondition_t *instance)
{
for (int i = 0; i < MAX_LOGIC_CONDITIONS; i++) {
RESET_CONFIG(logicCondition_t, &instance[i],
.enabled = 0,
.operation = LOGIC_CONDITION_TRUE,
.operandA = {
.type = LOGIC_CONDITION_OPERAND_TYPE_VALUE,
.value = 0
},
.operandB = {
.type = LOGIC_CONDITION_OPERAND_TYPE_VALUE,
.value = 0
},
.flags = 0
);
}
}
logicConditionState_t logicConditionStates[MAX_LOGIC_CONDITIONS];
static int logicConditionCompute(

View file

@ -42,7 +42,7 @@
//#define PG_PROFILE_SELECTION 23
#define PG_RX_CONFIG 24
#define PG_RC_CONTROLS_CONFIG 25
#define PG_MOTOR_3D_CONFIG 26
#define PG_REVERSIBLE_MOTORS_CONFIG 26
#define PG_LED_STRIP_CONFIG 27
//#define PG_COLOR_CONFIG 28
//#define PG_AIRPLANE_ALT_HOLD_CONFIG 29

View file

@ -127,6 +127,7 @@ static bool mpu6500DeviceDetect(busDevice_t * dev)
switch (tmp) {
case MPU6500_WHO_AM_I_CONST:
case ICM20608G_WHO_AM_I_CONST:
case ICM20601_WHO_AM_I_CONST:
case ICM20602_WHO_AM_I_CONST:
case ICM20689_WHO_AM_I_CONST:
// Compatible chip detected

View file

@ -97,7 +97,7 @@ static bool mag3110Read(magDev_t * mag)
mag->magADCRaw[X] = (int16_t)(buf[0] << 8 | buf[1]);
mag->magADCRaw[Y] = (int16_t)(buf[2] << 8 | buf[3]);
mag->magADCRaw[Z] = (int16_t)(buf[4] << 8 | buf[5]);
mag->magADCRaw[Z] = -(int16_t)(buf[4] << 8 | buf[5]); // Z is down, not up in this sensor
return true;
}

View file

@ -146,7 +146,7 @@ static bool commandBatchError = false;
static const char * const featureNames[] = {
"THR_VBAT_COMP", "VBAT", "TX_PROF_SEL", "BAT_PROF_AUTOSWITCH", "MOTOR_STOP",
"DYNAMIC_FILTERS", "SOFTSERIAL", "GPS", "RPM_FILTERS",
"", "TELEMETRY", "CURRENT_METER", "3D", "",
"", "TELEMETRY", "CURRENT_METER", "REVERSIBLE_MOTORS", "",
"", "RSSI_ADC", "LED_STRIP", "DASHBOARD", "",
"BLACKBOX", "", "TRANSPONDER", "AIRMODE",
"SUPEREXPO", "VTX", "", "", "PWM_SERVO_DRIVER", "PWM_OUTPUT_ENABLE",

View file

@ -48,7 +48,7 @@ typedef enum {
FEATURE_UNUSED_4 = 1 << 9, // was FEATURE_SONAR
FEATURE_TELEMETRY = 1 << 10,
FEATURE_CURRENT_METER = 1 << 11,
FEATURE_3D = 1 << 12,
FEATURE_REVERSIBLE_MOTORS = 1 << 12,
FEATURE_UNUSED_5 = 1 << 13, // RX_PARALLEL_PWM
FEATURE_UNUSED_6 = 1 << 14, // RX_MSP
FEATURE_RSSI_ADC = 1 << 15,

View file

@ -515,7 +515,7 @@ void processRx(timeUs_t currentTimeUs)
calculateRxChannelsAndUpdateFailsafe(currentTimeUs);
// in 3D mode, we need to be able to disarm by switch at any time
if (feature(FEATURE_3D)) {
if (feature(FEATURE_REVERSIBLE_MOTORS)) {
if (!IS_RC_MODE_ACTIVE(BOXARM))
disarm(DISARM_SWITCH_3D);
}
@ -532,7 +532,7 @@ void processRx(timeUs_t currentTimeUs)
const throttleStatus_e throttleStatus = calculateThrottleStatus();
// When armed and motors aren't spinning, do beeps periodically
if (ARMING_FLAG(ARMED) && feature(FEATURE_MOTOR_STOP) && !STATE(FIXED_WING)) {
if (ARMING_FLAG(ARMED) && feature(FEATURE_MOTOR_STOP) && !STATE(FIXED_WING_LEGACY)) {
static bool armedBeeperOn = false;
if (throttleStatus == THROTTLE_LOW) {
@ -633,7 +633,7 @@ void processRx(timeUs_t currentTimeUs)
#endif
// Handle passthrough mode
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
if ((IS_RC_MODE_ACTIVE(BOXMANUAL) && !navigationRequiresAngleMode() && !failsafeRequiresAngleMode()) || // Normal activation of passthrough
(!ARMING_FLAG(ARMED) && isCalibrating())){ // Backup - if we are not armed - enforce passthrough while calibrating
ENABLE_FLIGHT_MODE(MANUAL_MODE);
@ -649,13 +649,13 @@ void processRx(timeUs_t currentTimeUs)
/* In MANUAL mode we reset integrators prevent I-term wind-up (PID output is not used in MANUAL) */
pidResetErrorAccumulators();
}
else if (STATE(FIXED_WING) || rcControlsConfig()->airmodeHandlingType == STICK_CENTER) {
else if (STATE(FIXED_WING_LEGACY) || rcControlsConfig()->airmodeHandlingType == STICK_CENTER) {
if (throttleStatus == THROTTLE_LOW) {
if (STATE(AIRMODE_ACTIVE) && !failsafeIsActive() && ARMING_FLAG(ARMED)) {
rollPitchStatus_e rollPitchStatus = calculateRollPitchCenterStatus();
// ANTI_WINDUP at centred stick with MOTOR_STOP is needed on MRs and not needed on FWs
if ((rollPitchStatus == CENTERED) || (feature(FEATURE_MOTOR_STOP) && !STATE(FIXED_WING))) {
if ((rollPitchStatus == CENTERED) || (feature(FEATURE_MOTOR_STOP) && !STATE(FIXED_WING_LEGACY))) {
ENABLE_STATE(ANTI_WINDUP);
}
else {
@ -753,7 +753,7 @@ void taskMainPidLoop(timeUs_t currentTimeUs)
cycleTime = getTaskDeltaTime(TASK_SELF);
dT = (float)cycleTime * 0.000001f;
if (ARMING_FLAG(ARMED) && (!STATE(FIXED_WING) || !isNavLaunchEnabled() || (isNavLaunchEnabled() && (isFixedWingLaunchDetected() || isFixedWingLaunchFinishedOrAborted())))) {
if (ARMING_FLAG(ARMED) && (!STATE(FIXED_WING_LEGACY) || !isNavLaunchEnabled() || (isNavLaunchEnabled() && (isFixedWingLaunchDetected() || isFixedWingLaunchFinishedOrAborted())))) {
flightTime += cycleTime;
updateAccExtremes();
}
@ -782,7 +782,7 @@ void taskMainPidLoop(timeUs_t currentTimeUs)
#endif
// Apply throttle tilt compensation
if (!STATE(FIXED_WING)) {
if (!STATE(FIXED_WING_LEGACY)) {
int16_t thrTiltCompStrength = 0;
if (navigationRequiresThrottleTiltCompensation()) {
@ -793,9 +793,9 @@ void taskMainPidLoop(timeUs_t currentTimeUs)
}
if (thrTiltCompStrength) {
rcCommand[THROTTLE] = constrain(motorConfig()->minthrottle
+ (rcCommand[THROTTLE] - motorConfig()->minthrottle) * calculateThrottleTiltCompensationFactor(thrTiltCompStrength),
motorConfig()->minthrottle,
rcCommand[THROTTLE] = constrain(getThrottleIdleValue()
+ (rcCommand[THROTTLE] - getThrottleIdleValue()) * calculateThrottleTiltCompensationFactor(thrTiltCompStrength),
getThrottleIdleValue(),
motorConfig()->maxthrottle);
}
}

View file

@ -108,6 +108,7 @@
#include "io/ledstrip.h"
#include "io/pwmdriver_i2c.h"
#include "io/osd.h"
#include "io/osd_dji_hd.h"
#include "io/rcdevice_cam.h"
#include "io/serial.h"
#include "io/displayport_msp.h"
@ -265,6 +266,11 @@ void init(void)
// to run after the sensors have been detected.
mspSerialInit();
#if defined(USE_DJI_HD_OSD)
// DJI OSD uses a special flavour of MSP (subset of Betaflight 4.1.1 MSP) - process as part of serial task
djiOsdSerialInit();
#endif
#if defined(USE_LOG)
// LOG might use serial output, so we only can init it after serial port is ready
// From this point on we can use LOG_*() to produce real-time debugging information
@ -279,7 +285,7 @@ void init(void)
// Some sanity checking
if (motorConfig()->motorPwmProtocol == PWM_TYPE_BRUSHED) {
featureClear(FEATURE_3D);
featureClear(FEATURE_REVERSIBLE_MOTORS);
}
// Initialize motor and servo outpus

View file

@ -153,26 +153,74 @@ typedef enum {
MSP_FLASHFS_BIT_SUPPORTED = 2
} mspFlashfsFlags_e;
#ifdef USE_SERIAL_4WAY_BLHELI_INTERFACE
#define ESC_4WAY 0xff
typedef enum {
MSP_PASSTHROUGH_SERIAL_ID = 0xFD,
MSP_PASSTHROUGH_SERIAL_FUNCTION_ID = 0xFE,
static uint8_t escMode;
static uint8_t escPortIndex;
MSP_PASSTHROUGH_ESC_4WAY = 0xFF,
} mspPassthroughType_e;
static void mspFc4waySerialCommand(sbuf_t *dst, sbuf_t *src, mspPostProcessFnPtr *mspPostProcessFn)
static uint8_t mspPassthroughMode;
static uint8_t mspPassthroughArgument;
static serialPort_t *mspFindPassthroughSerialPort(void)
{
serialPortUsage_t *portUsage = NULL;
switch (mspPassthroughMode) {
case MSP_PASSTHROUGH_SERIAL_ID:
{
portUsage = findSerialPortUsageByIdentifier(mspPassthroughArgument);
break;
}
case MSP_PASSTHROUGH_SERIAL_FUNCTION_ID:
{
const serialPortConfig_t *portConfig = findSerialPortConfig(1 << mspPassthroughArgument);
if (portConfig) {
portUsage = findSerialPortUsageByIdentifier(portConfig->identifier);
}
break;
}
}
return portUsage ? portUsage->serialPort : NULL;
}
static void mspSerialPassthroughFn(serialPort_t *serialPort)
{
serialPort_t *passthroughPort = mspFindPassthroughSerialPort();
if (passthroughPort && serialPort) {
serialPassthrough(passthroughPort, serialPort, NULL, NULL);
}
}
static void mspFcSetPassthroughCommand(sbuf_t *dst, sbuf_t *src, mspPostProcessFnPtr *mspPostProcessFn)
{
const unsigned int dataSize = sbufBytesRemaining(src);
if (dataSize == 0) {
// Legacy format
escMode = ESC_4WAY;
mspPassthroughMode = MSP_PASSTHROUGH_ESC_4WAY;
} else {
escMode = sbufReadU8(src);
escPortIndex = sbufReadU8(src);
mspPassthroughMode = sbufReadU8(src);
if (!sbufReadU8Safe(&mspPassthroughArgument, src)) {
mspPassthroughArgument = 0;
}
}
switch (escMode) {
case ESC_4WAY:
switch (mspPassthroughMode) {
case MSP_PASSTHROUGH_SERIAL_ID:
case MSP_PASSTHROUGH_SERIAL_FUNCTION_ID:
if (mspFindPassthroughSerialPort()) {
if (mspPostProcessFn) {
*mspPostProcessFn = mspSerialPassthroughFn;
}
sbufWriteU8(dst, 1);
} else {
sbufWriteU8(dst, 0);
}
break;
#ifdef USE_SERIAL_4WAY_BLHELI_INTERFACE
case MSP_PASSTHROUGH_ESC_4WAY:
// get channel number
// switch all motor lines HI
// reply with the count of ESC found
@ -182,14 +230,12 @@ static void mspFc4waySerialCommand(sbuf_t *dst, sbuf_t *src, mspPostProcessFnPtr
*mspPostProcessFn = esc4wayProcess;
}
break;
#endif
default:
sbufWriteU8(dst, 0);
}
}
#endif
static void mspRebootFn(serialPort_t *serialPort)
{
UNUSED(serialPort);
@ -702,7 +748,7 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF
case MSP_MISC:
sbufWriteU16(dst, PWM_RANGE_MIDDLE);
sbufWriteU16(dst, motorConfig()->minthrottle);
sbufWriteU16(dst, 0); // Was min_throttle
sbufWriteU16(dst, motorConfig()->maxthrottle);
sbufWriteU16(dst, motorConfig()->mincommand);
@ -732,7 +778,7 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF
case MSP2_INAV_MISC:
sbufWriteU16(dst, PWM_RANGE_MIDDLE);
sbufWriteU16(dst, motorConfig()->minthrottle);
sbufWriteU16(dst, 0); //Was min_throttle
sbufWriteU16(dst, motorConfig()->maxthrottle);
sbufWriteU16(dst, motorConfig()->mincommand);
@ -1064,16 +1110,16 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF
break;
case MSP_3D:
sbufWriteU16(dst, flight3DConfig()->deadband3d_low);
sbufWriteU16(dst, flight3DConfig()->deadband3d_high);
sbufWriteU16(dst, flight3DConfig()->neutral3d);
sbufWriteU16(dst, reversibleMotorsConfig()->deadband_low);
sbufWriteU16(dst, reversibleMotorsConfig()->deadband_high);
sbufWriteU16(dst, reversibleMotorsConfig()->neutral);
break;
case MSP_RC_DEADBAND:
sbufWriteU8(dst, rcControlsConfig()->deadband);
sbufWriteU8(dst, rcControlsConfig()->yaw_deadband);
sbufWriteU8(dst, rcControlsConfig()->alt_hold_deadband);
sbufWriteU16(dst, rcControlsConfig()->deadband3d_throttle);
sbufWriteU16(dst, rcControlsConfig()->mid_throttle_deadband);
break;
case MSP_SENSOR_ALIGNMENT:
@ -1712,7 +1758,7 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)
if (dataSize >= 22) {
sbufReadU16(src); // midrc
motorConfigMutable()->minthrottle = constrain(sbufReadU16(src), PWM_RANGE_MIN, PWM_RANGE_MAX);
sbufReadU16(src); //Was min_throttle
motorConfigMutable()->maxthrottle = constrain(sbufReadU16(src), PWM_RANGE_MIN, PWM_RANGE_MAX);
motorConfigMutable()->mincommand = constrain(sbufReadU16(src), 0, PWM_RANGE_MAX);
@ -1753,7 +1799,7 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)
if (dataSize == 41) {
sbufReadU16(src); // midrc
motorConfigMutable()->minthrottle = constrain(sbufReadU16(src), PWM_RANGE_MIN, PWM_RANGE_MAX);
sbufReadU16(src); // was min_throttle
motorConfigMutable()->maxthrottle = constrain(sbufReadU16(src), PWM_RANGE_MIN, PWM_RANGE_MAX);
motorConfigMutable()->mincommand = constrain(sbufReadU16(src), 0, PWM_RANGE_MAX);
@ -1936,9 +1982,9 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)
case MSP_SET_3D:
if (dataSize >= 6) {
flight3DConfigMutable()->deadband3d_low = sbufReadU16(src);
flight3DConfigMutable()->deadband3d_high = sbufReadU16(src);
flight3DConfigMutable()->neutral3d = sbufReadU16(src);
reversibleMotorsConfigMutable()->deadband_low = sbufReadU16(src);
reversibleMotorsConfigMutable()->deadband_high = sbufReadU16(src);
reversibleMotorsConfigMutable()->neutral = sbufReadU16(src);
} else
return MSP_RESULT_ERROR;
break;
@ -1948,7 +1994,7 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)
rcControlsConfigMutable()->deadband = sbufReadU8(src);
rcControlsConfigMutable()->yaw_deadband = sbufReadU8(src);
rcControlsConfigMutable()->alt_hold_deadband = sbufReadU8(src);
rcControlsConfigMutable()->deadband3d_throttle = sbufReadU16(src);
rcControlsConfigMutable()->mid_throttle_deadband = sbufReadU16(src);
} else
return MSP_RESULT_ERROR;
break;
@ -1991,7 +2037,7 @@ static mspResult_e mspFcProcessInCommand(uint16_t cmdMSP, sbuf_t *src)
case MSP_SET_FILTER_CONFIG :
if (dataSize >= 5) {
gyroConfigMutable()->gyro_soft_lpf_hz = sbufReadU8(src);
pidProfileMutable()->dterm_lpf_hz = constrain(sbufReadU16(src), 0, 255);
pidProfileMutable()->dterm_lpf_hz = constrain(sbufReadU16(src), 0, 500);
pidProfileMutable()->yaw_lpf_hz = constrain(sbufReadU16(src), 0, 255);
if (dataSize >= 9) {
gyroConfigMutable()->gyro_soft_notch_hz_1 = constrain(sbufReadU16(src), 0, 500);
@ -3177,11 +3223,9 @@ mspResult_e mspFcProcessCommand(mspPacket_t *cmd, mspPacket_t *reply, mspPostPro
ret = mspProcessSensorCommand(cmdMSP, src);
} else if (mspFcProcessOutCommand(cmdMSP, dst, mspPostProcessFn)) {
ret = MSP_RESULT_ACK;
#ifdef USE_SERIAL_4WAY_BLHELI_INTERFACE
} else if (cmdMSP == MSP_SET_4WAY_IF) {
mspFc4waySerialCommand(dst, src, mspPostProcessFn);
} else if (cmdMSP == MSP_SET_PASSTHROUGH) {
mspFcSetPassthroughCommand(dst, src, mspPostProcessFn);
ret = MSP_RESULT_ACK;
#endif
} else {
if (!mspFCProcessInOutCommand(cmdMSP, dst, src, &ret)) {
ret = mspFcProcessInCommand(cmdMSP, src);

View file

@ -187,17 +187,17 @@ void initActiveBoxIds(void)
activeBoxIds[activeBoxIdCount++] = BOXCAMSTAB;
#ifdef USE_GPS
if (sensors(SENSOR_BARO) || (STATE(FIXED_WING) && feature(FEATURE_GPS))) {
if (sensors(SENSOR_BARO) || (STATE(FIXED_WING_LEGACY) && feature(FEATURE_GPS))) {
activeBoxIds[activeBoxIdCount++] = BOXNAVALTHOLD;
activeBoxIds[activeBoxIdCount++] = BOXSURFACE;
}
const bool navReadyQuads = !STATE(FIXED_WING) && (getHwCompassStatus() != HW_SENSOR_NONE) && sensors(SENSOR_ACC) && feature(FEATURE_GPS);
const bool navReadyPlanes = STATE(FIXED_WING) && sensors(SENSOR_ACC) && feature(FEATURE_GPS);
const bool navReadyQuads = !STATE(FIXED_WING_LEGACY) && (getHwCompassStatus() != HW_SENSOR_NONE) && sensors(SENSOR_ACC) && feature(FEATURE_GPS);
const bool navReadyPlanes = STATE(FIXED_WING_LEGACY) && sensors(SENSOR_ACC) && feature(FEATURE_GPS);
const bool navFlowDeadReckoning = sensors(SENSOR_OPFLOW) && sensors(SENSOR_ACC) && positionEstimationConfig()->allow_dead_reckoning;
if (navFlowDeadReckoning || navReadyQuads || navReadyPlanes) {
activeBoxIds[activeBoxIdCount++] = BOXNAVPOSHOLD;
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
activeBoxIds[activeBoxIdCount++] = BOXLOITERDIRCHN;
}
}
@ -209,7 +209,7 @@ void initActiveBoxIds(void)
if (feature(FEATURE_GPS)) {
activeBoxIds[activeBoxIdCount++] = BOXGCSNAV;
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
activeBoxIds[activeBoxIdCount++] = BOXNAVCRUISE;
}
}
@ -223,7 +223,7 @@ void initActiveBoxIds(void)
#endif
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
activeBoxIds[activeBoxIdCount++] = BOXMANUAL;
if (!feature(FEATURE_FW_LAUNCH)) {
activeBoxIds[activeBoxIdCount++] = BOXNAVLAUNCH;

View file

@ -61,6 +61,7 @@
#include "io/serial.h"
#include "io/rcdevice_cam.h"
#include "io/vtx.h"
#include "io/osd_dji_hd.h"
#include "msp/msp_serial.h"
@ -97,6 +98,11 @@ void taskHandleSerial(timeUs_t currentTimeUs)
// Allow MSP processing even if in CLI mode
mspSerialProcess(ARMING_FLAG(ARMED) ? MSP_SKIP_NON_MSP_DATA : MSP_EVALUATE_NON_MSP_DATA, mspFcProcessCommand);
#if defined(USE_DJI_HD_OSD)
// DJI OSD uses a special flavour of MSP (subset of Betaflight 4.1.1 MSP) - process as part of serial task
djiOsdSerialProcess();
#endif
}
void taskUpdateBattery(timeUs_t currentTimeUs)

View file

@ -76,7 +76,7 @@ PG_RESET_TEMPLATE(rcControlsConfig_t, rcControlsConfig,
.yaw_deadband = 5,
.pos_hold_deadband = 20,
.alt_hold_deadband = 50,
.deadband3d_throttle = 50,
.mid_throttle_deadband = 50,
.airmodeHandlingType = STICK_CENTER,
.airmodeThrottleThreshold = AIRMODE_THROTTLE_THRESHOLD,
);
@ -101,10 +101,10 @@ bool areSticksDeflectedMoreThanPosHoldDeadband(void)
throttleStatus_e calculateThrottleStatus(void)
{
const uint16_t deadband3d_throttle = rcControlsConfig()->deadband3d_throttle;
if (feature(FEATURE_3D) && (rxGetChannelValue(THROTTLE) > (PWM_RANGE_MIDDLE - deadband3d_throttle) && rxGetChannelValue(THROTTLE) < (PWM_RANGE_MIDDLE + deadband3d_throttle)))
const uint16_t mid_throttle_deadband = rcControlsConfig()->mid_throttle_deadband;
if (feature(FEATURE_REVERSIBLE_MOTORS) && (rxGetChannelValue(THROTTLE) > (PWM_RANGE_MIDDLE - mid_throttle_deadband) && rxGetChannelValue(THROTTLE) < (PWM_RANGE_MIDDLE + mid_throttle_deadband)))
return THROTTLE_LOW;
else if (!feature(FEATURE_3D) && (rxGetChannelValue(THROTTLE) < rxConfig()->mincheck))
else if (!feature(FEATURE_REVERSIBLE_MOTORS) && (rxGetChannelValue(THROTTLE) < rxConfig()->mincheck))
return THROTTLE_LOW;
return THROTTLE_HIGH;
@ -183,7 +183,7 @@ void processRcStickPositions(throttleStatus_e throttleStatus)
bool armingSwitchIsActive = IS_RC_MODE_ACTIVE(BOXARM);
emergencyArmingUpdate(armingSwitchIsActive);
if (STATE(FIXED_WING) && feature(FEATURE_MOTOR_STOP) && armingConfig()->fixed_wing_auto_arm) {
if (STATE(FIXED_WING_LEGACY) && feature(FEATURE_MOTOR_STOP) && armingConfig()->fixed_wing_auto_arm) {
// Auto arm on throttle when using fixedwing and motorstop
if (throttleStatus != THROTTLE_LOW) {
tryArm();

View file

@ -80,7 +80,7 @@ typedef struct rcControlsConfig_s {
uint8_t yaw_deadband; // introduce a deadband around the stick center for yaw axis. Must be greater than zero.
uint8_t pos_hold_deadband; // Adds ability to adjust the Hold-position when moving the sticks (assisted mode)
uint8_t alt_hold_deadband; // Defines the neutral zone of throttle stick during altitude hold
uint16_t deadband3d_throttle; // default throttle deadband from MIDRC
uint16_t mid_throttle_deadband; // default throttle deadband from MIDRC
uint8_t airmodeHandlingType; // Defaults to ANTI_WINDUP triggered at sticks centered
uint16_t airmodeThrottleThreshold; // Throttle threshold for airmode initial activation
} rcControlsConfig_t;

View file

@ -36,12 +36,13 @@
#define YAW_LOOKUP_LENGTH 7
#define THROTTLE_LOOKUP_LENGTH 11
static int16_t lookupThrottleRC[THROTTLE_LOOKUP_LENGTH]; // lookup table for expo & mid THROTTLE
static EXTENDED_FASTRAM int16_t lookupThrottleRC[THROTTLE_LOOKUP_LENGTH]; // lookup table for expo & mid THROTTLE
int16_t lookupThrottleRCMid; // THROTTLE curve mid point
void generateThrottleCurve(const controlRateConfig_t *controlRateConfig)
{
lookupThrottleRCMid = motorConfig()->minthrottle + (int32_t)(motorConfig()->maxthrottle - motorConfig()->minthrottle) * controlRateConfig->throttle.rcMid8 / 100; // [MINTHROTTLE;MAXTHROTTLE]
const int minThrottle = getThrottleIdleValue();
lookupThrottleRCMid = minThrottle + (int32_t)(motorConfig()->maxthrottle - minThrottle) * controlRateConfig->throttle.rcMid8 / 100; // [MINTHROTTLE;MAXTHROTTLE]
for (int i = 0; i < THROTTLE_LOOKUP_LENGTH; i++) {
const int16_t tmp = 10 * i - controlRateConfig->throttle.rcMid8;
@ -51,7 +52,7 @@ void generateThrottleCurve(const controlRateConfig_t *controlRateConfig)
if (tmp < 0)
y = controlRateConfig->throttle.rcMid8;
lookupThrottleRC[i] = 10 * controlRateConfig->throttle.rcMid8 + tmp * (100 - controlRateConfig->throttle.rcExpo8 + (int32_t) controlRateConfig->throttle.rcExpo8 * (tmp * tmp) / (y * y)) / 10;
lookupThrottleRC[i] = motorConfig()->minthrottle + (int32_t) (motorConfig()->maxthrottle - motorConfig()->minthrottle) * lookupThrottleRC[i] / 1000; // [MINTHROTTLE;MAXTHROTTLE]
lookupThrottleRC[i] = minThrottle + (int32_t) (motorConfig()->maxthrottle - minThrottle) * lookupThrottleRC[i] / 1000; // [MINTHROTTLE;MAXTHROTTLE]
}
}

View file

@ -104,7 +104,7 @@ static void processAirmodeMultirotor(void) {
void processAirmode(void) {
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
processAirmodeAirplane();
} else {
processAirmodeMultirotor();

View file

@ -102,18 +102,21 @@ uint32_t sensorsMask(void)
flightModeForTelemetry_e getFlightModeForTelemetry(void)
{
if (FLIGHT_MODE(MANUAL_MODE))
return FLM_MANUAL;
if (FLIGHT_MODE(FAILSAFE_MODE))
return FLM_FAILSAFE;
if (FLIGHT_MODE(MANUAL_MODE))
return FLM_MANUAL;
if (FLIGHT_MODE(NAV_RTH_MODE))
return FLM_RTH;
if (FLIGHT_MODE(NAV_POSHOLD_MODE))
return FLM_POSITION_HOLD;
if (FLIGHT_MODE(NAV_CRUISE_MODE))
return FLM_CRUISE;
if (FLIGHT_MODE(NAV_WP_MODE))
return FLM_MISSION;
@ -129,5 +132,5 @@ flightModeForTelemetry_e getFlightModeForTelemetry(void)
if (FLIGHT_MODE(NAV_LAUNCH_MODE))
return FLM_LAUNCH;
return FLM_ACRO;
return STATE(AIRMODE_ACTIVE) ? FLM_ACRO_AIR : FLM_ACRO;
}

View file

@ -110,7 +110,7 @@ typedef enum {
GPS_FIX = (1 << 1),
CALIBRATE_MAG = (1 << 2),
SMALL_ANGLE = (1 << 3),
FIXED_WING = (1 << 4), // set when in flying_wing or airplane mode. currently used by althold selection code
FIXED_WING_LEGACY = (1 << 4), // No new code should use this state. Use AIRPLANE, MULTIROTOR, ROVER, BOAT, ALTITUDE_CONTROL and MOVE_FORWARD_ONLY states
ANTI_WINDUP = (1 << 5),
FLAPERON_AVAILABLE = (1 << 6),
NAV_MOTOR_STOP_OR_IDLE = (1 << 7), // navigation requests MOTOR_STOP or motor idle regardless of throttle stick, will only activate if MOTOR_STOP feature is available
@ -123,7 +123,13 @@ typedef enum {
NAV_EXTRA_ARMING_SAFETY_BYPASSED = (1 << 14), // nav_extra_arming_safey was bypassed. Keep it until power cycle.
AIRMODE_ACTIVE = (1 << 15),
ESC_SENSOR_ENABLED = (1 << 16),
FW_HEADING_USE_YAW = (1 << 17),
AIRPLANE = (1 << 17),
MULTIROTOR = (1 << 18),
ROVER = (1 << 19),
BOAT = (1 << 20),
ALTITUDE_CONTROL = (1 << 21),
MOVE_FORWARD_ONLY = (1 << 22),
FW_HEADING_USE_YAW = (1 << 23),
} stateFlags_t;
#define DISABLE_STATE(mask) (stateFlags &= ~(mask))
@ -135,12 +141,14 @@ extern uint32_t stateFlags;
typedef enum {
FLM_MANUAL,
FLM_ACRO,
FLM_ACRO_AIR,
FLM_ANGLE,
FLM_HORIZON,
FLM_ALTITUDE_HOLD,
FLM_POSITION_HOLD,
FLM_RTH,
FLM_MISSION,
FLM_CRUISE,
FLM_LAUNCH,
FLM_FAILSAFE,
FLM_COUNT

View file

@ -25,7 +25,7 @@ tables:
values: ["NONE", "PWM", "PPM", "SERIAL", "MSP", "SPI", "UIB"]
enum: rxReceiverType_e
- name: serial_rx
values: ["SPEK1024", "SPEK2048", "SBUS", "SUMD", "SUMH", "XB-B", "XB-B-RJ01", "IBUS", "JETIEXBUS", "CRSF", "FPORT"]
values: ["SPEK1024", "SPEK2048", "SBUS", "SUMD", "SUMH", "XB-B", "XB-B-RJ01", "IBUS", "JETIEXBUS", "CRSF", "FPORT", "SBUS_FAST"]
- name: rx_spi_protocol
values: ["V202_250K", "V202_1M", "SYMA_X", "SYMA_X5C", "CX10", "CX10A", "H8_3D", "INAV", "ELERES"]
enum: rx_spi_protocol_e
@ -478,10 +478,6 @@ groups:
type: motorConfig_t
headers: ["flight/mixer.h"]
members:
- name: min_throttle
field: minthrottle
min: PWM_RANGE_MIN
max: PWM_RANGE_MAX
- name: max_throttle
field: maxthrottle
min: PWM_RANGE_MIN
@ -509,6 +505,10 @@ groups:
field: throttleScale
min: 0
max: 1
- name: throttle_idle
field: throttleIdle
min: 4
max: 30
- name: motor_poles
field: motorPoleCount
min: 4
@ -704,19 +704,19 @@ groups:
min: 0
max: 450
- name: PG_MOTOR_3D_CONFIG
type: flight3DConfig_t
- name: PG_REVERSIBLE_MOTORS_CONFIG
type: reversibleMotorsConfig_t
members:
- name: 3d_deadband_low
field: deadband3d_low
field: deadband_low
min: PWM_RANGE_MIN
max: PWM_RANGE_MAX
- name: 3d_deadband_high
field: deadband3d_high
field: deadband_high
min: PWM_RANGE_MIN
max: PWM_RANGE_MAX
- name: 3d_neutral
field: neutral3d
field: neutral
min: PWM_RANGE_MIN
max: PWM_RANGE_MAX
@ -878,9 +878,6 @@ groups:
- name: rpm_gyro_filter_enabled
field: gyro_filter_enabled
type: bool
- name: rpm_dterm_filter_enabled
field: dterm_filter_enabled
type: bool
- name: rpm_gyro_harmonics
field: gyro_harmonics
type: uint8_t
@ -896,21 +893,6 @@ groups:
type: uint16_t
min: 1
max: 3000
- name: dterm_gyro_harmonics
field: dterm_harmonics
type: uint8_t
min: 1
max: 3
- name: rpm_dterm_min_hz
field: dterm_min_hz
type: uint8_t
min: 50
max: 200
- name: rpm_dterm_q
field: dterm_q
type: uint16_t
min: 1
max: 3000
- name: PG_GPS_CONFIG
type: gpsConfig_t
condition: USE_GPS
@ -958,7 +940,7 @@ groups:
min: 10
max: 250
- name: 3d_deadband_throttle
field: deadband3d_throttle
field: mid_throttle_deadband
min: 0
max: 200
- name: mc_airmode_type
@ -1080,7 +1062,16 @@ groups:
max: 900
- name: dterm_lpf_hz
min: 0
max: 200
max: 500
- name: dterm_lpf_type
field: dterm_lpf_type
table: filter_type
- name: dterm_lpf2_hz
min: 0
max: 500
- name: dterm_lpf2_type
field: dterm_lpf2_type
table: filter_type
- name: use_dterm_fir_filter
field: use_dterm_fir_filter
type: bool

View file

@ -216,7 +216,7 @@ bool failsafeRequiresMotorStop(void)
{
return failsafeState.active &&
failsafeState.activeProcedure == FAILSAFE_PROCEDURE_AUTO_LANDING &&
failsafeConfig()->failsafe_throttle < motorConfig()->minthrottle;
failsafeConfig()->failsafe_throttle < getThrottleIdleValue();
}
void failsafeStartMonitoring(void)
@ -258,7 +258,7 @@ void failsafeApplyControlInput(void)
{
// Prepare FAILSAFE_CHANNEL_AUTO values for rcCommand
int16_t autoRcCommand[4];
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
autoRcCommand[ROLL] = pidAngleToRcCommand(failsafeConfig()->failsafe_fw_roll_angle, pidProfile()->max_angle_inclination[FD_ROLL]);
autoRcCommand[PITCH] = pidAngleToRcCommand(failsafeConfig()->failsafe_fw_pitch_angle, pidProfile()->max_angle_inclination[FD_PITCH]);
autoRcCommand[YAW] = -pidRateToRcCommand(failsafeConfig()->failsafe_fw_yaw_rate, currentControlRateProfile->stabilized.rates[FD_YAW]);
@ -287,7 +287,7 @@ void failsafeApplyControlInput(void)
break;
case THROTTLE:
rcCommand[idx] = feature(FEATURE_3D) ? PWM_RANGE_MIDDLE : motorConfig()->minthrottle;
rcCommand[idx] = feature(FEATURE_REVERSIBLE_MOTORS) ? PWM_RANGE_MIDDLE : getThrottleIdleValue();
break;
}
break;

View file

@ -57,7 +57,7 @@ void hilUpdateControlState(void)
{
// FIXME: There must be a cleaner way to to this
// If HIL active, store PID outout into hilState and disable motor control
if (FLIGHT_MODE(MANUAL_MODE) || !STATE(FIXED_WING)) {
if (FLIGHT_MODE(MANUAL_MODE) || !STATE(FIXED_WING_LEGACY)) {
hilToSIM.pidCommand[ROLL] = rcCommand[ROLL];
hilToSIM.pidCommand[PITCH] = rcCommand[PITCH];
hilToSIM.pidCommand[YAW] = rcCommand[YAW];

View file

@ -481,7 +481,7 @@ static float imuCalculateAccelerometerWeight(const float dT)
const float nearness = ABS(100 - (accMagnitudeSq * 100));
const float accWeight_Nearness = (nearness > MAX_ACC_SQ_NEARNESS) ? 0.0f : 1.0f;
// Experiment: if rotation rate on a FIXED_WING is higher than a threshold - centrifugal force messes up too much and we
// Experiment: if rotation rate on a FIXED_WING_LEGACY is higher than a threshold - centrifugal force messes up too much and we
// should not use measured accel for AHRS comp
// Centrifugal acceleration AccelC = Omega^2 * R = Speed^2 / R
// Omega = Speed / R
@ -499,7 +499,7 @@ static float imuCalculateAccelerometerWeight(const float dT)
// Default - don't apply rate/ignore scaling
float accWeight_RateIgnore = 1.0f;
if (ARMING_FLAG(ARMED) && STATE(FIXED_WING) && imuConfig()->acc_ignore_rate) {
if (ARMING_FLAG(ARMED) && STATE(FIXED_WING_LEGACY) && imuConfig()->acc_ignore_rate) {
const float rotRateMagnitude = sqrtf(vectorNormSquared(&imuMeasuredRotationBF));
const float rotRateMagnitudeFiltered = pt1FilterApply4(&rotRateFilter, rotRateMagnitude, IMU_CENTRIFUGAL_LPF, dT);
@ -532,7 +532,7 @@ static void imuCalculateEstimatedAttitude(float dT)
bool useCOG = false;
#if defined(USE_GPS)
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
bool canUseCOG = isGPSHeadingValid();
// Prefer compass (if available)
@ -670,7 +670,7 @@ bool isImuReady(void)
bool isImuHeadingValid(void)
{
return (sensors(SENSOR_MAG) && STATE(COMPASS_CALIBRATED)) || (STATE(FIXED_WING) && gpsHeadingInitialized);
return (sensors(SENSOR_MAG) && STATE(COMPASS_CALIBRATED)) || (STATE(FIXED_WING_LEGACY) && gpsHeadingInitialized);
}
float calculateCosTiltAngle(void)

View file

@ -61,13 +61,14 @@ static float mixerScale = 1.0f;
static EXTENDED_FASTRAM motorMixer_t currentMixer[MAX_SUPPORTED_MOTORS];
static EXTENDED_FASTRAM uint8_t motorCount = 0;
EXTENDED_FASTRAM int mixerThrottleCommand;
static EXTENDED_FASTRAM int throttleIdleValue = 0;
PG_REGISTER_WITH_RESET_TEMPLATE(flight3DConfig_t, flight3DConfig, PG_MOTOR_3D_CONFIG, 0);
PG_REGISTER_WITH_RESET_TEMPLATE(reversibleMotorsConfig_t, reversibleMotorsConfig, PG_REVERSIBLE_MOTORS_CONFIG, 0);
PG_RESET_TEMPLATE(flight3DConfig_t, flight3DConfig,
.deadband3d_low = 1406,
.deadband3d_high = 1514,
.neutral3d = 1460
PG_RESET_TEMPLATE(reversibleMotorsConfig_t, reversibleMotorsConfig,
.deadband_low = 1406,
.deadband_high = 1514,
.neutral = 1460
);
PG_REGISTER_WITH_RESET_TEMPLATE(mixerConfig_t, mixerConfig, PG_MIXER_CONFIG, 2);
@ -83,26 +84,23 @@ PG_RESET_TEMPLATE(mixerConfig_t, mixerConfig,
#ifdef BRUSHED_MOTORS
#define DEFAULT_PWM_PROTOCOL PWM_TYPE_BRUSHED
#define DEFAULT_PWM_RATE 16000
#define DEFAULT_MIN_THROTTLE 1000
#else
#define DEFAULT_PWM_PROTOCOL PWM_TYPE_STANDARD
#define DEFAULT_PWM_RATE 400
#define DEFAULT_MIN_THROTTLE 1150
#endif
#define DEFAULT_MAX_THROTTLE 1850
PG_REGISTER_WITH_RESET_TEMPLATE(motorConfig_t, motorConfig, PG_MOTOR_CONFIG, 4);
PG_REGISTER_WITH_RESET_TEMPLATE(motorConfig_t, motorConfig, PG_MOTOR_CONFIG, 5);
PG_RESET_TEMPLATE(motorConfig_t, motorConfig,
.minthrottle = DEFAULT_MIN_THROTTLE,
.motorPwmProtocol = DEFAULT_PWM_PROTOCOL,
.motorPwmRate = DEFAULT_PWM_RATE,
.maxthrottle = DEFAULT_MAX_THROTTLE,
.mincommand = 1000,
.motorAccelTimeMs = 0,
.motorDecelTimeMs = 0,
.digitalIdleOffsetValue = 450, // Same scale as in Betaflight
.throttleIdle = 15.0f,
.throttleScale = 1.0f,
.motorPoleCount = 14 // Most brushless motors that we use are 14 poles
);
@ -112,6 +110,15 @@ PG_REGISTER_ARRAY(motorMixer_t, MAX_SUPPORTED_MOTORS, primaryMotorMixer, PG_MOTO
typedef void (*motorRateLimitingApplyFnPtr)(const float dT);
static EXTENDED_FASTRAM motorRateLimitingApplyFnPtr motorRateLimitingApplyFn;
int getThrottleIdleValue(void)
{
if (!throttleIdleValue) {
throttleIdleValue = motorConfig()->mincommand + (((motorConfig()->maxthrottle - motorConfig()->mincommand) / 100.0f) * motorConfig()->throttleIdle);
}
return throttleIdleValue;
}
static void computeMotorCount(void)
{
motorCount = 0;
@ -140,16 +147,35 @@ bool mixerIsOutputSaturated(void)
void mixerUpdateStateFlags(void)
{
// set flag that we're on something with wings or a land/water vehicle
if (
mixerConfig()->platformType == PLATFORM_AIRPLANE ||
mixerConfig()->platformType == PLATFORM_ROVER ||
mixerConfig()->platformType == PLATFORM_BOAT ||
mixerConfig()->platformType == PLATFORM_OTHER
) {
ENABLE_STATE(FIXED_WING); //This is not entirely true, but much closer to reality than not using FIXED_WING mode
} else {
DISABLE_STATE(FIXED_WING);
DISABLE_STATE(FIXED_WING_LEGACY);
DISABLE_STATE(MULTIROTOR);
DISABLE_STATE(ROVER);
DISABLE_STATE(BOAT);
DISABLE_STATE(AIRPLANE);
DISABLE_STATE(MOVE_FORWARD_ONLY);
if (mixerConfig()->platformType == PLATFORM_AIRPLANE) {
ENABLE_STATE(FIXED_WING_LEGACY);
ENABLE_STATE(AIRPLANE);
ENABLE_STATE(ALTITUDE_CONTROL);
ENABLE_STATE(MOVE_FORWARD_ONLY);
} if (mixerConfig()->platformType == PLATFORM_ROVER) {
ENABLE_STATE(ROVER);
ENABLE_STATE(FIXED_WING_LEGACY);
ENABLE_STATE(MOVE_FORWARD_ONLY);
} if (mixerConfig()->platformType == PLATFORM_BOAT) {
ENABLE_STATE(BOAT);
ENABLE_STATE(FIXED_WING_LEGACY);
ENABLE_STATE(MOVE_FORWARD_ONLY);
} else if (mixerConfig()->platformType == PLATFORM_MULTIROTOR) {
ENABLE_STATE(MULTIROTOR);
ENABLE_STATE(ALTITUDE_CONTROL);
} else if (mixerConfig()->platformType == PLATFORM_TRICOPTER) {
ENABLE_STATE(MULTIROTOR);
ENABLE_STATE(ALTITUDE_CONTROL);
} else if (mixerConfig()->platformType == PLATFORM_HELICOPTER) {
ENABLE_STATE(MULTIROTOR);
ENABLE_STATE(ALTITUDE_CONTROL);
}
if (mixerConfig()->hasFlaps) {
@ -168,7 +194,7 @@ void applyMotorRateLimiting(const float dT)
{
static float motorPrevious[MAX_SUPPORTED_MOTORS] = { 0 };
if (feature(FEATURE_3D)) {
if (feature(FEATURE_REVERSIBLE_MOTORS)) {
// FIXME: Don't apply rate limiting in 3D mode
for (int i = 0; i < motorCount; i++) {
motorPrevious[i] = motor[i];
@ -176,7 +202,7 @@ void applyMotorRateLimiting(const float dT)
}
else {
// Calculate max motor step
const uint16_t motorRange = motorConfig()->maxthrottle - motorConfig()->minthrottle;
const uint16_t motorRange = motorConfig()->maxthrottle - throttleIdleValue;
const float motorMaxInc = (motorConfig()->motorAccelTimeMs == 0) ? 2000 : motorRange * dT / (motorConfig()->motorAccelTimeMs * 1e-3f);
const float motorMaxDec = (motorConfig()->motorDecelTimeMs == 0) ? 2000 : motorRange * dT / (motorConfig()->motorDecelTimeMs * 1e-3f);
@ -185,12 +211,12 @@ void applyMotorRateLimiting(const float dT)
motorPrevious[i] = constrainf(motor[i], motorPrevious[i] - motorMaxDec, motorPrevious[i] + motorMaxInc);
// Handle throttle below min_throttle (motor start/stop)
if (motorPrevious[i] < motorConfig()->minthrottle) {
if (motor[i] < motorConfig()->minthrottle) {
if (motorPrevious[i] < throttleIdleValue) {
if (motor[i] < throttleIdleValue) {
motorPrevious[i] = motor[i];
}
else {
motorPrevious[i] = motorConfig()->minthrottle;
motorPrevious[i] = throttleIdleValue;
}
}
}
@ -207,7 +233,7 @@ void mixerInit(void)
computeMotorCount();
loadPrimaryMotorMixer();
// in 3D mode, mixer gain has to be halved
if (feature(FEATURE_3D)) {
if (feature(FEATURE_REVERSIBLE_MOTORS)) {
mixerScale = 0.5f;
}
@ -224,7 +250,7 @@ void mixerResetDisarmedMotors(void)
{
// set disarmed motor values
for (int i = 0; i < MAX_SUPPORTED_MOTORS; i++) {
motor_disarmed[i] = feature(FEATURE_3D) ? flight3DConfig()->neutral3d : motorConfig()->mincommand;
motor_disarmed[i] = feature(FEATURE_REVERSIBLE_MOTORS) ? reversibleMotorsConfig()->neutral : motorConfig()->mincommand;
}
}
@ -236,15 +262,14 @@ void FAST_CODE NOINLINE writeMotors(void)
#ifdef USE_DSHOT
// If we use DSHOT we need to convert motorValue to DSHOT ranges
if (isMotorProtocolDigital()) {
const float dshotMinThrottleOffset = (DSHOT_MAX_THROTTLE - DSHOT_MIN_THROTTLE) / 10000.0f * motorConfig()->digitalIdleOffsetValue;
if (feature(FEATURE_3D)) {
if (motor[i] >= motorConfig()->minthrottle && motor[i] <= flight3DConfig()->deadband3d_low) {
motorValue = scaleRangef(motor[i], motorConfig()->minthrottle, flight3DConfig()->deadband3d_low, DSHOT_3D_DEADBAND_LOW, dshotMinThrottleOffset + DSHOT_MIN_THROTTLE);
if (feature(FEATURE_REVERSIBLE_MOTORS)) {
if (motor[i] >= throttleIdleValue && motor[i] <= reversibleMotorsConfig()->deadband_low) {
motorValue = scaleRangef(motor[i], motorConfig()->mincommand, reversibleMotorsConfig()->deadband_low, DSHOT_3D_DEADBAND_LOW, DSHOT_MIN_THROTTLE);
motorValue = constrain(motorValue, DSHOT_MIN_THROTTLE, DSHOT_3D_DEADBAND_LOW);
}
else if (motor[i] >= flight3DConfig()->deadband3d_high && motor[i] <= motorConfig()->maxthrottle) {
motorValue = scaleRangef(motor[i], flight3DConfig()->deadband3d_high, motorConfig()->maxthrottle, dshotMinThrottleOffset + DSHOT_3D_DEADBAND_HIGH, DSHOT_MAX_THROTTLE);
else if (motor[i] >= reversibleMotorsConfig()->deadband_high && motor[i] <= motorConfig()->maxthrottle) {
motorValue = scaleRangef(motor[i], reversibleMotorsConfig()->deadband_high, motorConfig()->maxthrottle, DSHOT_3D_DEADBAND_HIGH, DSHOT_MAX_THROTTLE);
motorValue = constrain(motorValue, DSHOT_3D_DEADBAND_HIGH, DSHOT_MAX_THROTTLE);
}
else {
@ -252,12 +277,12 @@ void FAST_CODE NOINLINE writeMotors(void)
}
}
else {
if (motor[i] < motorConfig()->minthrottle) { // motor disarmed
if (motor[i] < throttleIdleValue) { // motor disarmed
motorValue = DSHOT_DISARM_COMMAND;
}
else {
motorValue = scaleRangef(motor[i], motorConfig()->minthrottle, motorConfig()->maxthrottle, (dshotMinThrottleOffset + DSHOT_MIN_THROTTLE), DSHOT_MAX_THROTTLE);
motorValue = constrain(motorValue, (dshotMinThrottleOffset + DSHOT_MIN_THROTTLE), DSHOT_MAX_THROTTLE);
motorValue = scaleRangef(motor[i], motorConfig()->mincommand, motorConfig()->maxthrottle, DSHOT_MIN_THROTTLE, DSHOT_MAX_THROTTLE);
motorValue = constrain(motorValue, DSHOT_MIN_THROTTLE, DSHOT_MAX_THROTTLE);
}
}
}
@ -284,7 +309,7 @@ void writeAllMotors(int16_t mc)
void stopMotors(void)
{
writeAllMotors(feature(FEATURE_3D) ? flight3DConfig()->neutral3d : motorConfig()->mincommand);
writeAllMotors(feature(FEATURE_REVERSIBLE_MOTORS) ? reversibleMotorsConfig()->neutral : motorConfig()->mincommand);
delay(50); // give the timers and ESCs a chance to react.
}
@ -298,7 +323,7 @@ void FAST_CODE NOINLINE mixTable(const float dT)
{
int16_t input[3]; // RPY, range [-500:+500]
// Allow direct stick input to motors in passthrough mode on airplanes
if (STATE(FIXED_WING) && FLIGHT_MODE(MANUAL_MODE)) {
if (STATE(FIXED_WING_LEGACY) && FLIGHT_MODE(MANUAL_MODE)) {
// Direct passthru from RX
input[ROLL] = rcCommand[ROLL];
input[PITCH] = rcCommand[PITCH];
@ -334,32 +359,32 @@ void FAST_CODE NOINLINE mixTable(const float dT)
// Find min and max throttle based on condition.
#ifdef USE_GLOBAL_FUNCTIONS
if (GLOBAL_FUNCTION_FLAG(GLOBAL_FUNCTION_FLAG_OVERRIDE_THROTTLE)) {
throttleMin = motorConfig()->minthrottle;
throttleMin = throttleIdleValue;
throttleMax = motorConfig()->maxthrottle;
mixerThrottleCommand = constrain(globalFunctionValues[GLOBAL_FUNCTION_ACTION_OVERRIDE_THROTTLE], throttleMin, throttleMax);
} else
#endif
if (feature(FEATURE_3D)) {
if (feature(FEATURE_REVERSIBLE_MOTORS)) {
if (!ARMING_FLAG(ARMED)) throttlePrevious = PWM_RANGE_MIDDLE; // When disarmed set to mid_rc. It always results in positive direction after arming.
if ((rcCommand[THROTTLE] <= (PWM_RANGE_MIDDLE - rcControlsConfig()->deadband3d_throttle))) { // Out of band handling
throttleMax = flight3DConfig()->deadband3d_low;
throttleMin = motorConfig()->minthrottle;
if ((rcCommand[THROTTLE] <= (PWM_RANGE_MIDDLE - rcControlsConfig()->mid_throttle_deadband))) { // Out of band handling
throttleMax = reversibleMotorsConfig()->deadband_low;
throttleMin = throttleIdleValue;
throttlePrevious = mixerThrottleCommand = rcCommand[THROTTLE];
} else if (rcCommand[THROTTLE] >= (PWM_RANGE_MIDDLE + rcControlsConfig()->deadband3d_throttle)) { // Positive handling
} else if (rcCommand[THROTTLE] >= (PWM_RANGE_MIDDLE + rcControlsConfig()->mid_throttle_deadband)) { // Positive handling
throttleMax = motorConfig()->maxthrottle;
throttleMin = flight3DConfig()->deadband3d_high;
throttleMin = reversibleMotorsConfig()->deadband_high;
throttlePrevious = mixerThrottleCommand = rcCommand[THROTTLE];
} else if ((throttlePrevious <= (PWM_RANGE_MIDDLE - rcControlsConfig()->deadband3d_throttle))) { // Deadband handling from negative to positive
mixerThrottleCommand = throttleMax = flight3DConfig()->deadband3d_low;
throttleMin = motorConfig()->minthrottle;
} else if ((throttlePrevious <= (PWM_RANGE_MIDDLE - rcControlsConfig()->mid_throttle_deadband))) { // Deadband handling from negative to positive
mixerThrottleCommand = throttleMax = reversibleMotorsConfig()->deadband_low;
throttleMin = throttleIdleValue;
} else { // Deadband handling from positive to negative
throttleMax = motorConfig()->maxthrottle;
mixerThrottleCommand = throttleMin = flight3DConfig()->deadband3d_high;
mixerThrottleCommand = throttleMin = reversibleMotorsConfig()->deadband_high;
}
} else {
mixerThrottleCommand = rcCommand[THROTTLE];
throttleMin = motorConfig()->minthrottle;
throttleMin = throttleIdleValue;
throttleMax = motorConfig()->maxthrottle;
// Throttle scaling to limit max throttle when battery is full
@ -399,22 +424,22 @@ void FAST_CODE NOINLINE mixTable(const float dT)
if (failsafeIsActive()) {
motor[i] = constrain(motor[i], motorConfig()->mincommand, motorConfig()->maxthrottle);
} else if (feature(FEATURE_3D)) {
if (throttlePrevious <= (PWM_RANGE_MIDDLE - rcControlsConfig()->deadband3d_throttle)) {
motor[i] = constrain(motor[i], motorConfig()->minthrottle, flight3DConfig()->deadband3d_low);
} else if (feature(FEATURE_REVERSIBLE_MOTORS)) {
if (throttlePrevious <= (PWM_RANGE_MIDDLE - rcControlsConfig()->mid_throttle_deadband)) {
motor[i] = constrain(motor[i], throttleIdleValue, reversibleMotorsConfig()->deadband_low);
} else {
motor[i] = constrain(motor[i], flight3DConfig()->deadband3d_high, motorConfig()->maxthrottle);
motor[i] = constrain(motor[i], reversibleMotorsConfig()->deadband_high, motorConfig()->maxthrottle);
}
} else {
motor[i] = constrain(motor[i], motorConfig()->minthrottle, motorConfig()->maxthrottle);
motor[i] = constrain(motor[i], throttleIdleValue, motorConfig()->maxthrottle);
}
// Motor stop handling
if (ARMING_FLAG(ARMED) && (getMotorStatus() != MOTOR_RUNNING)) {
if (feature(FEATURE_MOTOR_STOP)) {
motor[i] = (feature(FEATURE_3D) ? PWM_RANGE_MIDDLE : motorConfig()->mincommand);
motor[i] = (feature(FEATURE_REVERSIBLE_MOTORS) ? PWM_RANGE_MIDDLE : motorConfig()->mincommand);
} else {
motor[i] = motorConfig()->minthrottle;
motor[i] = throttleIdleValue;
}
}
}
@ -435,7 +460,7 @@ motorStatus_e getMotorStatus(void)
}
if (rxGetChannelValue(THROTTLE) < rxConfig()->mincheck) {
if ((STATE(FIXED_WING) || !STATE(AIRMODE_ACTIVE)) && (!(navigationIsFlyingAutonomousMode() && navConfig()->general.flags.auto_overrides_motor_stop)) && (!failsafeIsActive())) {
if ((STATE(FIXED_WING_LEGACY) || !STATE(AIRMODE_ACTIVE)) && (!(navigationIsFlyingAutonomousMode() && navConfig()->general.flags.auto_overrides_motor_stop)) && (!failsafeIsActive())) {
return MOTOR_STOPPED_USER;
}
}

View file

@ -72,17 +72,16 @@ typedef struct mixerConfig_s {
PG_DECLARE(mixerConfig_t, mixerConfig);
typedef struct flight3DConfig_s {
uint16_t deadband3d_low; // min 3d value
uint16_t deadband3d_high; // max 3d value
uint16_t neutral3d; // center 3d value
} flight3DConfig_t;
typedef struct reversibleMotorsConfig_s {
uint16_t deadband_low; // min 3d value
uint16_t deadband_high; // max 3d value
uint16_t neutral; // center 3d value
} reversibleMotorsConfig_t;
PG_DECLARE(flight3DConfig_t, flight3DConfig);
PG_DECLARE(reversibleMotorsConfig_t, reversibleMotorsConfig);
typedef struct motorConfig_s {
// PWM values, in milliseconds, common range is 1000-2000 (1ms to 2ms)
uint16_t minthrottle; // Set the minimum throttle command sent to the ESC (Electronic Speed Controller). This is the minimum value that allow motors to run at a idle speed.
uint16_t maxthrottle; // This is the maximum value for the ESCs at full power this value can be increased up to 2000
uint16_t mincommand; // This is the value for the ESCs when they are not armed. In some cases, this value must be lowered down to 900 for some specific ESCs
uint16_t motorPwmRate; // The update rate of motor outputs (50-498Hz)
@ -90,6 +89,7 @@ typedef struct motorConfig_s {
uint16_t motorAccelTimeMs; // Time limit for motor to accelerate from 0 to 100% throttle [ms]
uint16_t motorDecelTimeMs; // Time limit for motor to decelerate from 0 to 100% throttle [ms]
uint16_t digitalIdleOffsetValue;
float throttleIdle; // Throttle IDLE value based on min_command, max_throttle, in percent
float throttleScale; // Scaling factor for throttle.
uint8_t motorPoleCount; // Magnetic poles in the motors for calculating actual RPM from eRPM provided by ESC telemetry
} motorConfig_t;
@ -106,6 +106,7 @@ extern int16_t motor[MAX_SUPPORTED_MOTORS];
extern int16_t motor_disarmed[MAX_SUPPORTED_MOTORS];
extern int mixerThrottleCommand;
int getThrottleIdleValue(void);
uint8_t getMotorCount(void);
float getMotorMixRange(void);
bool mixerIsOutputSaturated(void);

View file

@ -81,7 +81,8 @@ typedef struct {
// Rate filtering
rateLimitFilter_t axisAccelFilter;
pt1Filter_t ptermLpfState;
biquadFilter_t deltaLpfState;
filter_t dtermLpfState;
filter_t dtermLpf2State;
// Dterm notch filtering
biquadFilter_t deltaNotchFilter;
float stickPosition;
@ -145,6 +146,7 @@ static EXTENDED_FASTRAM uint8_t usedPidControllerType;
typedef void (*pidControllerFnPtr)(pidState_t *pidState, flight_dynamics_index_t axis, float dT);
static EXTENDED_FASTRAM pidControllerFnPtr pidControllerApplyFn;
static EXTENDED_FASTRAM filterApplyFnPtr dTermLpfFilterApplyFn;
static EXTENDED_FASTRAM filterApplyFnPtr dTermLpf2FilterApplyFn;
PG_REGISTER_PROFILE_WITH_RESET_TEMPLATE(pidProfile_t, pidProfile, PG_PID_PROFILE, 12);
@ -229,7 +231,10 @@ PG_RESET_TEMPLATE(pidProfile_t, pidProfile,
.dterm_soft_notch_hz = 0,
.dterm_soft_notch_cutoff = 1,
.dterm_lpf_type = 1, //Default to BIQUAD
.dterm_lpf_hz = 40,
.dterm_lpf2_type = 1, //Default to BIQUAD
.dterm_lpf2_hz = 0, // Off by default
.yaw_lpf_hz = 0,
.dterm_setpoint_weight = 1.0f,
.use_dterm_fir_filter = 1,
@ -307,8 +312,25 @@ bool pidInitFilters(void)
}
// Init other filters
if (pidProfile()->dterm_lpf_hz) {
for (int axis = 0; axis < 3; ++ axis) {
biquadFilterInitLPF(&pidState[axis].deltaLpfState, pidProfile()->dterm_lpf_hz, refreshRate);
if (pidProfile()->dterm_lpf_type == FILTER_PT1) {
pt1FilterInit(&pidState[axis].dtermLpfState.pt1, pidProfile()->dterm_lpf_hz, refreshRate * 1e-6f);
} else {
biquadFilterInitLPF(&pidState[axis].dtermLpfState.biquad, pidProfile()->dterm_lpf_hz, refreshRate);
}
}
}
// Init other filters
if (pidProfile()->dterm_lpf2_hz) {
for (int axis = 0; axis < 3; ++ axis) {
if (pidProfile()->dterm_lpf2_type == FILTER_PT1) {
pt1FilterInit(&pidState[axis].dtermLpf2State.pt1, pidProfile()->dterm_lpf2_hz, refreshRate * 1e-6f);
} else {
biquadFilterInitLPF(&pidState[axis].dtermLpf2State.biquad, pidProfile()->dterm_lpf2_hz, refreshRate);
}
}
}
for (int i = 0; i < XYZ_AXIS_COUNT; i++) {
@ -334,7 +356,7 @@ void pidResetTPAFilter(void)
{
if (usedPidControllerType == PID_TYPE_PIFF && currentControlRateProfile->throttle.fixedWingTauMs > 0) {
pt1FilterInitRC(&fixedWingTpaFilter, currentControlRateProfile->throttle.fixedWingTauMs * 1e-3f, getLooptime() * 1e-6f);
pt1FilterReset(&fixedWingTpaFilter, motorConfig()->minthrottle);
pt1FilterReset(&fixedWingTpaFilter, getThrottleIdleValue());
}
}
@ -382,10 +404,10 @@ static float calculateFixedWingTPAFactor(uint16_t throttle)
// tpa_rate is amount of curve TPA applied to PIDs
// tpa_breakpoint for fixed wing is cruise throttle value (value at which PIDs were tuned)
if (currentControlRateProfile->throttle.dynPID != 0 && currentControlRateProfile->throttle.pa_breakpoint > motorConfig()->minthrottle) {
if (throttle > motorConfig()->minthrottle) {
if (currentControlRateProfile->throttle.dynPID != 0 && currentControlRateProfile->throttle.pa_breakpoint > getThrottleIdleValue()) {
if (throttle > getThrottleIdleValue()) {
// Calculate TPA according to throttle
tpaFactor = 0.5f + ((float)(currentControlRateProfile->throttle.pa_breakpoint - motorConfig()->minthrottle) / (throttle - motorConfig()->minthrottle) / 2.0f);
tpaFactor = 0.5f + ((float)(currentControlRateProfile->throttle.pa_breakpoint - getThrottleIdleValue()) / (throttle - getThrottleIdleValue()) / 2.0f);
// Limit to [0.5; 2] range
tpaFactor = constrainf(tpaFactor, 0.5f, 2.0f);
@ -521,7 +543,7 @@ static void pidLevel(pidState_t *pidState, flight_dynamics_index_t axis, float h
float angleTarget = pidRcCommandToAngle(rcCommand[axis], pidProfile()->max_angle_inclination[axis]);
// Automatically pitch down if the throttle is manually controlled and reduced bellow cruise throttle
if ((axis == FD_PITCH) && STATE(FIXED_WING) && FLIGHT_MODE(ANGLE_MODE) && !navigationIsControllingThrottle())
if ((axis == FD_PITCH) && STATE(FIXED_WING_LEGACY) && FLIGHT_MODE(ANGLE_MODE) && !navigationIsControllingThrottle())
angleTarget += scaleRange(MAX(0, navConfig()->fw.cruise_throttle - rcCommand[THROTTLE]), 0, navConfig()->fw.cruise_throttle - PWM_RANGE_MIN, 0, mixerConfig()->fwMinThrottleDownPitchAngle);
const float angleErrorDeg = DECIDEGREES_TO_DEGREES(angleTarget - attitude.raw[axis]);
@ -698,12 +720,9 @@ static void FAST_CODE NOINLINE pidApplyMulticopterRateController(pidState_t *pid
// Apply D-term notch
deltaFiltered = notchFilterApplyFn(&pidState->deltaNotchFilter, deltaFiltered);
#ifdef USE_RPM_FILTER
deltaFiltered = rpmFilterDtermApply((uint8_t)axis, deltaFiltered);
#endif
// Apply additional lowpass
deltaFiltered = dTermLpfFilterApplyFn(&pidState->deltaLpfState, deltaFiltered);
deltaFiltered = dTermLpfFilterApplyFn((filter_t *) &pidState->dtermLpfState, deltaFiltered);
deltaFiltered = dTermLpf2FilterApplyFn((filter_t *) &pidState->dtermLpf2State, deltaFiltered);
firFilterUpdate(&pidState->gyroRateFilter, deltaFiltered);
newDTerm = firFilterApply(&pidState->gyroRateFilter);
@ -851,7 +870,7 @@ static void NOINLINE pidTurnAssistant(pidState_t *pidState)
targetRates.x = 0.0f;
targetRates.y = 0.0f;
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
if (calculateCosTiltAngle() >= 0.173648f) {
// Ideal banked turn follow the equations:
// forward_vel^2 / radius = Gravity * tan(roll_angle)
@ -895,7 +914,7 @@ static void NOINLINE pidTurnAssistant(pidState_t *pidState)
pidState[PITCH].rateTarget = constrainf(pidState[PITCH].rateTarget + targetRates.y, -currentControlRateProfile->stabilized.rates[PITCH] * 10.0f, currentControlRateProfile->stabilized.rates[PITCH] * 10.0f);
// Replace YAW on quads - add it in on airplanes
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
pidState[YAW].rateTarget = constrainf(pidState[YAW].rateTarget + targetRates.z * pidProfile()->fixedWingCoordinatedYawGain, -currentControlRateProfile->stabilized.rates[YAW] * 10.0f, currentControlRateProfile->stabilized.rates[YAW] * 10.0f);
}
else {
@ -1008,7 +1027,7 @@ pidType_e pidIndexGetType(pidIndex_e pidIndex)
if (pidIndex == PID_ROLL || pidIndex == PID_PITCH || pidIndex == PID_YAW) {
return usedPidControllerType;
}
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
if (pidIndex == PID_VEL_XY || pidIndex == PID_VEL_Z) {
return PID_TYPE_NONE;
}
@ -1062,21 +1081,35 @@ void pidInit(void)
}
if (pidProfile()->pidControllerType == PID_TYPE_AUTO) {
if (mixerConfig()->platformType == PLATFORM_MULTIROTOR ||
mixerConfig()->platformType == PLATFORM_TRICOPTER ||
mixerConfig()->platformType == PLATFORM_HELICOPTER) {
usedPidControllerType = PID_TYPE_PID;
} else {
if (
mixerConfig()->platformType == PLATFORM_AIRPLANE ||
mixerConfig()->platformType == PLATFORM_BOAT ||
mixerConfig()->platformType == PLATFORM_ROVER
) {
usedPidControllerType = PID_TYPE_PIFF;
} else {
usedPidControllerType = PID_TYPE_PID;
}
} else {
usedPidControllerType = pidProfile()->pidControllerType;
}
if (pidProfile()->dterm_lpf_hz) {
dTermLpfFilterApplyFn = (filterApplyFnPtr) biquadFilterApply;
} else {
dTermLpfFilterApplyFn = nullFilterApply;
if (pidProfile()->dterm_lpf_hz) {
if (pidProfile()->dterm_lpf_type == FILTER_PT1) {
dTermLpfFilterApplyFn = (filterApplyFnPtr) pt1FilterApply;
} else {
dTermLpfFilterApplyFn = (filterApplyFnPtr) biquadFilterApply;
}
}
dTermLpf2FilterApplyFn = nullFilterApply;
if (pidProfile()->dterm_lpf2_hz) {
if (pidProfile()->dterm_lpf2_type == FILTER_PT1) {
dTermLpf2FilterApplyFn = (filterApplyFnPtr) pt1FilterApply;
} else {
dTermLpf2FilterApplyFn = (filterApplyFnPtr) biquadFilterApply;
}
}
if (usedPidControllerType == PID_TYPE_PIFF) {

View file

@ -106,7 +106,13 @@ typedef struct pidProfile_s {
uint16_t dterm_soft_notch_hz; // Dterm Notch frequency
uint16_t dterm_soft_notch_cutoff; // Dterm Notch Cutoff frequency
uint8_t dterm_lpf_hz; // (default 17Hz, Range 1-50Hz) Used for PT1 element in PID1, PID2 and PID5
uint8_t dterm_lpf_type; // Dterm LPF type: PT1, BIQUAD
uint16_t dterm_lpf_hz;
uint8_t dterm_lpf2_type; // Dterm LPF type: PT1, BIQUAD
uint16_t dterm_lpf2_hz;
uint8_t use_dterm_fir_filter; // Use classical INAV FIR differentiator. Very noise robust, can be quite slowish
uint8_t yaw_lpf_hz;

View file

@ -43,17 +43,13 @@
#define RPM_FILTER_RPM_LPF_HZ 150
#define RPM_FILTER_HARMONICS 3
PG_REGISTER_WITH_RESET_TEMPLATE(rpmFilterConfig_t, rpmFilterConfig, PG_RPM_FILTER_CONFIG, 0);
PG_REGISTER_WITH_RESET_TEMPLATE(rpmFilterConfig_t, rpmFilterConfig, PG_RPM_FILTER_CONFIG, 1);
PG_RESET_TEMPLATE(rpmFilterConfig_t, rpmFilterConfig,
.gyro_filter_enabled = 0,
.dterm_filter_enabled = 0,
.gyro_harmonics = 1,
.gyro_min_hz = 100,
.gyro_q = 500,
.dterm_harmonics = 1,
.dterm_min_hz = 100,
.dterm_q = 500, );
.gyro_q = 500, );
typedef struct
{
@ -70,11 +66,8 @@ typedef void (*rpmFilterUpdateFnPtr)(rpmFilterBank_t *filterBank, uint8_t motor,
static EXTENDED_FASTRAM pt1Filter_t motorFrequencyFilter[MAX_SUPPORTED_MOTORS];
static EXTENDED_FASTRAM float erpmToHz;
static EXTENDED_FASTRAM rpmFilterBank_t gyroRpmFilters;
static EXTENDED_FASTRAM rpmFilterBank_t dtermRpmFilters;
static EXTENDED_FASTRAM rpmFilterApplyFnPtr rpmGyroApplyFn;
static EXTENDED_FASTRAM rpmFilterApplyFnPtr rpmDtermApplyFn;
static EXTENDED_FASTRAM rpmFilterUpdateFnPtr rpmGyroUpdateFn;
static EXTENDED_FASTRAM rpmFilterUpdateFnPtr rpmDtermUpdateFn;
float nullRpmFilterApply(rpmFilterBank_t *filter, uint8_t axis, float input)
{
@ -141,7 +134,6 @@ static void rpmFilterInit(rpmFilterBank_t *filter, uint16_t q, uint8_t minHz, ui
void disableRpmFilters(void) {
rpmGyroApplyFn = (rpmFilterApplyFnPtr)nullRpmFilterApply;
rpmDtermApplyFn = (rpmFilterApplyFnPtr)nullRpmFilterApply;
}
void FAST_CODE NOINLINE rpmFilterUpdate(rpmFilterBank_t *filterBank, uint8_t motor, float baseFrequency)
@ -172,7 +164,6 @@ void rpmFiltersInit(void)
erpmToHz = ERPM_PER_LSB / (motorConfig()->motorPoleCount / 2) / RPM_TO_HZ;
rpmGyroUpdateFn = (rpmFilterUpdateFnPtr)nullRpmFilterUpdate;
rpmDtermUpdateFn = (rpmFilterUpdateFnPtr)nullRpmFilterUpdate;
if (rpmFilterConfig()->gyro_filter_enabled)
{
@ -184,17 +175,6 @@ void rpmFiltersInit(void)
rpmGyroApplyFn = (rpmFilterApplyFnPtr)rpmFilterApply;
rpmGyroUpdateFn = (rpmFilterUpdateFnPtr)rpmFilterUpdate;
}
if (rpmFilterConfig()->dterm_filter_enabled)
{
rpmFilterInit(
&dtermRpmFilters,
rpmFilterConfig()->dterm_q,
rpmFilterConfig()->dterm_min_hz,
rpmFilterConfig()->dterm_harmonics);
rpmDtermApplyFn = (rpmFilterApplyFnPtr)rpmFilterApply;
rpmDtermUpdateFn = (rpmFilterUpdateFnPtr)rpmFilterUpdate;
}
}
void FAST_CODE NOINLINE rpmFilterUpdateTask(timeUs_t currentTimeUs)
@ -215,7 +195,6 @@ void FAST_CODE NOINLINE rpmFilterUpdateTask(timeUs_t currentTimeUs)
}
rpmGyroUpdateFn(&gyroRpmFilters, i, baseFrequency);
rpmDtermUpdateFn(&dtermRpmFilters, i, baseFrequency);
}
}
@ -224,9 +203,4 @@ float FAST_CODE rpmFilterGyroApply(uint8_t axis, float input)
return rpmGyroApplyFn(&gyroRpmFilters, axis, input);
}
float FAST_CODE rpmFilterDtermApply(uint8_t axis, float input)
{
return rpmDtermApplyFn(&dtermRpmFilters, axis, input);
}
#endif

View file

@ -50,4 +50,3 @@ void disableRpmFilters(void);
void rpmFiltersInit(void);
void rpmFilterUpdateTask(timeUs_t currentTimeUs);
float rpmFilterGyroApply(uint8_t axis, float input);
float rpmFilterDtermApply(uint8_t axis, float input);

View file

@ -79,7 +79,7 @@ static int8_t RTHInitialAltitudeChangePitchAngle(float altitudeChange) {
static float estimatePitchPower(float pitch) {
int16_t altitudeChangeThrottle = fixedWingPitchToThrottleCorrection(DEGREES_TO_DECIDEGREES(pitch));
altitudeChangeThrottle = constrain(altitudeChangeThrottle, navConfig()->fw.min_throttle, navConfig()->fw.max_throttle);
const float altitudeChangeThrToCruiseThrRatio = (float)(altitudeChangeThrottle - motorConfig()->minthrottle) / (navConfig()->fw.cruise_throttle - motorConfig()->minthrottle);
const float altitudeChangeThrToCruiseThrRatio = (float)(altitudeChangeThrottle - getThrottleIdleValue()) / (navConfig()->fw.cruise_throttle - getThrottleIdleValue());
return (float)heatLossesCompensatedPower(batteryMetersConfig()->idle_power + batteryMetersConfig()->cruise_power * altitudeChangeThrToCruiseThrRatio) / 100;
}
@ -146,10 +146,10 @@ static float estimateRTHEnergyAfterInitialClimb(float distanceToHome, float spee
// returns Wh
static float calculateRemainingEnergyBeforeRTH(bool takeWindIntoAccount) {
// Fixed wing only for now
if (!STATE(FIXED_WING))
if (!STATE(FIXED_WING_LEGACY))
return -1;
if (!(feature(FEATURE_VBAT) && feature(FEATURE_CURRENT_METER) && navigationPositionEstimateIsHealthy() && (batteryMetersConfig()->cruise_power > 0) && (ARMING_FLAG(ARMED)) && ((!STATE(FIXED_WING)) || (isNavLaunchEnabled() && isFixedWingLaunchDetected())) && (navConfig()->fw.cruise_speed > 0) && (currentBatteryProfile->capacity.unit == BAT_CAPACITY_UNIT_MWH) && (currentBatteryProfile->capacity.value > 0) && batteryWasFullWhenPluggedIn() && isImuHeadingValid()
if (!(feature(FEATURE_VBAT) && feature(FEATURE_CURRENT_METER) && navigationPositionEstimateIsHealthy() && (batteryMetersConfig()->cruise_power > 0) && (ARMING_FLAG(ARMED)) && ((!STATE(FIXED_WING_LEGACY)) || (isNavLaunchEnabled() && isFixedWingLaunchDetected())) && (navConfig()->fw.cruise_speed > 0) && (currentBatteryProfile->capacity.unit == BAT_CAPACITY_UNIT_MWH) && (currentBatteryProfile->capacity.value > 0) && batteryWasFullWhenPluggedIn() && isImuHeadingValid()
#ifdef USE_WIND_ESTIMATOR
&& isEstimatedWindSpeedValid()
#endif

View file

@ -247,7 +247,7 @@ void servoMixer(float dT)
input[INPUT_STABILIZED_YAW] = axisPID[YAW];
// Reverse yaw servo when inverted in 3D mode only for multirotor and tricopter
if (feature(FEATURE_3D) && (rxGetChannelValue(THROTTLE) < PWM_RANGE_MIDDLE) &&
if (feature(FEATURE_REVERSIBLE_MOTORS) && (rxGetChannelValue(THROTTLE) < PWM_RANGE_MIDDLE) &&
(mixerConfig()->platformType == PLATFORM_MULTIROTOR || mixerConfig()->platformType == PLATFORM_TRICOPTER)) {
input[INPUT_STABILIZED_YAW] *= -1;
}
@ -449,6 +449,11 @@ bool FAST_CODE NOINLINE isServoOutputEnabled(void)
return servoOutputEnabled;
}
void NOINLINE setServoOutputEnabled(bool flag)
{
servoOutputEnabled = flag;
}
bool FAST_CODE NOINLINE isMixerUsingServos(void)
{
return mixerUsesServos;

View file

@ -142,6 +142,7 @@ typedef struct servoMetadata_s {
extern int16_t servo[MAX_SUPPORTED_SERVOS];
bool isServoOutputEnabled(void);
void setServoOutputEnabled(bool flag);
bool isMixerUsingServos(void);
void writeServos(void);
void loadCustomServoMixer(void);

View file

@ -79,7 +79,7 @@ void updateWindEstimator(timeUs_t currentTimeUs)
{
static timeUs_t lastUpdateUs = 0;
if (!STATE(FIXED_WING) ||
if (!STATE(FIXED_WING_LEGACY) ||
!isGPSHeadingValid() ||
!gpsSol.flags.validVelNE ||
!gpsSol.flags.validVelD) {

View file

@ -811,7 +811,7 @@ static const char * navigationStateMessage(void)
case MW_NAV_STATE_LAND_IN_PROGRESS:
return OSD_MESSAGE_STR("LANDING");
case MW_NAV_STATE_HOVER_ABOVE_HOME:
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
return OSD_MESSAGE_STR("LOITERING AROUND HOME");
}
return OSD_MESSAGE_STR("HOVERING");
@ -2113,7 +2113,7 @@ static bool osdDrawSingleElement(uint8_t item)
if (navStateMessage) {
messages[messageCount++] = navStateMessage;
}
} else if (STATE(FIXED_WING) && (navGetCurrentStateFlags() & NAV_CTL_LAUNCH)) {
} else if (STATE(FIXED_WING_LEGACY) && (navGetCurrentStateFlags() & NAV_CTL_LAUNCH)) {
messages[messageCount++] = "AUTOLAUNCH";
} else {
if (FLIGHT_MODE(NAV_ALTHOLD_MODE) && !navigationRequiresAngleMode()) {

View file

@ -116,7 +116,7 @@ void osdCanvasDrawDirArrow(displayPort_t *display, displayCanvas_t *canvas, cons
displayCanvasSetFillColor(canvas, DISPLAY_CANVAS_COLOR_WHITE);
displayCanvasSetStrokeColor(canvas, DISPLAY_CANVAS_COLOR_BLACK);
displayCanvasCtmRotate(canvas, -DEGREES_TO_RADIANS(degrees));
displayCanvasCtmRotate(canvas, -DEGREES_TO_RADIANS(180 + degrees));
displayCanvasCtmTranslate(canvas, px + canvas->gridElementWidth / 2, py + canvas->gridElementHeight / 2);
displayCanvasFillStrokeTriangle(canvas, 0, 6, 5, -6, -5, -6);
displayCanvasSetFillColor(canvas, DISPLAY_CANVAS_COLOR_TRANSPARENT);

653
src/main/io/osd_dji_hd.c Normal file
View file

@ -0,0 +1,653 @@
/*
* This file is part of INAV.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License Version 3, as described below:
*
* This file is free software: you may copy, redistribute and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
* @author Konstantin Sharlaimov (ksharlaimov@inavflight.com)
*/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "platform.h"
#include "build/debug.h"
#include "build/version.h"
#include "common/streambuf.h"
#include "common/utils.h"
#include "common/maths.h"
#include "common/time.h"
#include "common/crc.h"
#include "fc/fc_core.h"
#include "fc/config.h"
#include "fc/controlrate_profile.h"
#include "fc/fc_msp.h"
#include "fc/fc_msp_box.h"
#include "fc/runtime_config.h"
#include "flight/imu.h"
#include "flight/pid.h"
#include "flight/mixer.h"
#include "io/serial.h"
#include "io/gps.h"
#include "io/osd.h"
#include "io/osd_dji_hd.h"
#include "rx/rx.h"
#include "sensors/sensors.h"
#include "sensors/gyro.h"
#include "sensors/battery.h"
#include "sensors/rangefinder.h"
#include "sensors/acceleration.h"
#include "sensors/esc_sensor.h"
#include "msp/msp.h"
#include "msp/msp_protocol.h"
#include "msp/msp_serial.h"
#include "navigation/navigation.h"
#include "scheduler/scheduler.h"
#if defined(USE_DJI_HD_OSD)
#define DJI_MSP_BAUDRATE 115200
#define DJI_ARMING_DISABLE_FLAGS_COUNT 25
#define DJI_OSD_WARNING_COUNT 16
#define DJI_OSD_TIMER_COUNT 2
#define DJI_OSD_FLAGS_OSD_FEATURE (1 << 0)
/*
* DJI HD goggles use MSPv1 compatible with Betaflight 4.1.0
* DJI uses a subset of messages and assume fixed bit positions for flight modes
*
* To avoid compatibility issues we maintain a separate MSP command processor
* but reuse the packet decoder to minimize code duplication
*/
// External dependency on looptime
extern timeDelta_t cycleTime;
// MSP packet decoder state structure
static mspPort_t djiMspPort;
// Mapping table between DJI PID and INAV PID (order is different)
const uint8_t djiPidIndexMap[] = {
PID_ROLL, // DJI: PID_ROLL
PID_PITCH, // DJI: PID_PITCH
PID_YAW, // DJI: PID_YAW
PID_LEVEL, // DJI: PID_LEVEL
PID_HEADING // DJI: PID_MAG
};
const int djiOSDItemIndexMap[] = {
OSD_RSSI_VALUE, // DJI: OSD_RSSI_VALUE
OSD_MAIN_BATT_VOLTAGE, // DJI: OSD_MAIN_BATT_VOLTAGE
OSD_CROSSHAIRS, // DJI: OSD_CROSSHAIRS
OSD_ARTIFICIAL_HORIZON, // DJI: OSD_ARTIFICIAL_HORIZON
OSD_HORIZON_SIDEBARS, // DJI: OSD_HORIZON_SIDEBARS
OSD_ONTIME, // DJI: OSD_ITEM_TIMER_1
OSD_FLYTIME, // DJI: OSD_ITEM_TIMER_2
OSD_FLYMODE, // DJI: OSD_FLYMODE
OSD_CRAFT_NAME, // DJI: OSD_CRAFT_NAME
OSD_THROTTLE_POS, // DJI: OSD_THROTTLE_POS
OSD_VTX_CHANNEL, // DJI: OSD_VTX_CHANNEL
OSD_CURRENT_DRAW, // DJI: OSD_CURRENT_DRAW
OSD_MAH_DRAWN, // DJI: OSD_MAH_DRAWN
OSD_GPS_SPEED, // DJI: OSD_GPS_SPEED
OSD_GPS_SATS, // DJI: OSD_GPS_SATS
OSD_ALTITUDE, // DJI: OSD_ALTITUDE
OSD_ROLL_PIDS, // DJI: OSD_ROLL_PIDS
OSD_PITCH_PIDS, // DJI: OSD_PITCH_PIDS
OSD_YAW_PIDS, // DJI: OSD_YAW_PIDS
OSD_POWER, // DJI: OSD_POWER
-1, // DJI: OSD_PIDRATE_PROFILE
-1, // DJI: OSD_WARNINGS
OSD_MAIN_BATT_CELL_VOLTAGE, // DJI: OSD_AVG_CELL_VOLTAGE
OSD_GPS_LON, // DJI: OSD_GPS_LON
OSD_GPS_LAT, // DJI: OSD_GPS_LAT
OSD_DEBUG, // DJI: OSD_DEBUG
OSD_ATTITUDE_PITCH, // DJI: OSD_PITCH_ANGLE
OSD_ATTITUDE_ROLL, // DJI: OSD_ROLL_ANGLE
-1, // DJI: OSD_MAIN_BATT_USAGE
-1, // DJI: OSD_DISARMED
OSD_HOME_DIR, // DJI: OSD_HOME_DIR
OSD_HOME_DIST, // DJI: OSD_HOME_DIST
OSD_HEADING, // DJI: OSD_NUMERICAL_HEADING
OSD_VARIO_NUM, // DJI: OSD_NUMERICAL_VARIO
-1, // DJI: OSD_COMPASS_BAR
-1, // DJI: OSD_ESC_TMP
OSD_ESC_RPM, // DJI: OSD_ESC_RPM
OSD_REMAINING_FLIGHT_TIME_BEFORE_RTH, // DJI: OSD_REMAINING_TIME_ESTIMATE
OSD_RTC_TIME, // DJI: OSD_RTC_DATETIME
-1, // DJI: OSD_ADJUSTMENT_RANGE
-1, // DJI: OSD_CORE_TEMPERATURE
-1, // DJI: OSD_ANTI_GRAVITY
-1, // DJI: OSD_G_FORCE
-1, // DJI: OSD_MOTOR_DIAG
-1, // DJI: OSD_LOG_STATUS
-1, // DJI: OSD_FLIP_ARROW
-1, // DJI: OSD_LINK_QUALITY
OSD_TRIP_DIST, // DJI: OSD_FLIGHT_DIST
-1, // DJI: OSD_STICK_OVERLAY_LEFT
-1, // DJI: OSD_STICK_OVERLAY_RIGHT
-1, // DJI: OSD_DISPLAY_NAME
-1, // DJI: OSD_ESC_RPM_FREQ
-1, // DJI: OSD_RATE_PROFILE_NAME
-1, // DJI: OSD_PID_PROFILE_NAME
-1, // DJI: OSD_PROFILE_NAME
-1, // DJI: OSD_RSSI_DBM_VALUE
-1, // DJI: OSD_RC_CHANNELS
};
const int djiOSDStatisticsMap[] = {
-1, // DJI: OSD_STAT_RTC_DATE_TIME
-1, // DJI: OSD_STAT_TIMER_1
-1, // DJI: OSD_STAT_TIMER_2
-1, // DJI: OSD_STAT_MAX_SPEED
-1, // DJI: OSD_STAT_MAX_DISTANCE
-1, // DJI: OSD_STAT_MIN_BATTERY
-1, // DJI: OSD_STAT_END_BATTERY
-1, // DJI: OSD_STAT_BATTERY
-1, // DJI: OSD_STAT_MIN_RSSI
-1, // DJI: OSD_STAT_MAX_CURRENT
-1, // DJI: OSD_STAT_USED_MAH
-1, // DJI: OSD_STAT_MAX_ALTITUDE
-1, // DJI: OSD_STAT_BLACKBOX
-1, // DJI: OSD_STAT_BLACKBOX_NUMBER
-1, // DJI: OSD_STAT_MAX_G_FORCE
-1, // DJI: OSD_STAT_MAX_ESC_TEMP
-1, // DJI: OSD_STAT_MAX_ESC_RPM
-1, // DJI: OSD_STAT_MIN_LINK_QUALITY
-1, // DJI: OSD_STAT_FLIGHT_DISTANCE
-1, // DJI: OSD_STAT_MAX_FFT
-1, // DJI: OSD_STAT_TOTAL_FLIGHTS
-1, // DJI: OSD_STAT_TOTAL_TIME
-1, // DJI: OSD_STAT_TOTAL_DIST
-1, // DJI: OSD_STAT_MIN_RSSI_DBM
};
void djiOsdSerialInit(void)
{
memset(&djiMspPort, 0, sizeof(mspPort_t));
serialPortConfig_t *portConfig = findSerialPortConfig(FUNCTION_DJI_HD_OSD);
if (!portConfig) {
return;
}
serialPort_t *serialPort = openSerialPort(portConfig->identifier, FUNCTION_DJI_HD_OSD, NULL, NULL, DJI_MSP_BAUDRATE, MODE_RXTX, SERIAL_NOT_INVERTED);
if (serialPort) {
resetMspPort(&djiMspPort, serialPort);
}
}
static void djiPackBoxModeBitmask(boxBitmask_t * flightModeBitmask)
{
memset(flightModeBitmask, 0, sizeof(boxBitmask_t));
// Map flight modes to DJI-supported bits
switch(getFlightModeForTelemetry()) {
case FLM_MANUAL:
case FLM_ACRO:
case FLM_ACRO_AIR:
// DJI: No bits set = ACRO
break;
case FLM_ANGLE:
bitArraySet(flightModeBitmask->bits, 1); // DJI: 1 << 1 : ANGLE
break;
case FLM_HORIZON:
bitArraySet(flightModeBitmask->bits, 2); // DJI: 1 << 2
break;
case FLM_RTH:
bitArraySet(flightModeBitmask->bits, 5); // DJI: 1 << 5 : GPS_RESQUE
break;
case FLM_CRUISE:
bitArraySet(flightModeBitmask->bits, 3); // DJI: 1 << 3 : technically HEADFREE
break;
case FLM_FAILSAFE:
bitArraySet(flightModeBitmask->bits, 4); // DJI: 1 << 4
break;
case FLM_LAUNCH:
case FLM_ALTITUDE_HOLD:
case FLM_POSITION_HOLD:
case FLM_MISSION:
default:
// Unsupported ATM, keep at ANGLE
bitArraySet(flightModeBitmask->bits, 1); // DJI: 1 << 1 : ANGLE
}
// Set ARMED mode
if (ARMING_FLAG(ARMED)) {
bitArraySet(flightModeBitmask->bits, 0); // DJI: 1 << 0 : ARMED
}
}
static uint32_t djiPackArmingDisabledFlags(void)
{
// TODO: Map INAV arming disabled flags to DJI/BF ones
// https://github.com/betaflight/betaflight/blob/c6e5882dd91fa20d246b8f8af10cf6c92876bc3d/src/main/fc/runtime_config.h#L42
// For now hide everything in ARMING_DISABLED_ARM_SWITCH (bit 24)
return isArmingDisabled() ? (1 << 24) : 0;
}
static uint32_t djiEncodeOSDEnabledWarnings(void)
{
// TODO:
return 0;
}
static void djiSerializeOSDConfigReply(sbuf_t *dst)
{
// Only send supported flag - always
sbufWriteU8(dst, DJI_OSD_FLAGS_OSD_FEATURE);
// 7456 video system (AUTO/PAL/NTSC)
sbufWriteU8(dst, osdConfig()->video_system);
// Configuration
sbufWriteU8(dst, osdConfig()->units);
// Alarms
sbufWriteU8(dst, osdConfig()->rssi_alarm);
sbufWriteU16(dst, currentBatteryProfile->capacity.warning);
// OSD_ITEM_COUNT (previously was timer alarm)
sbufWriteU8(dst, 0);
sbufWriteU8(dst, ARRAYLEN(djiOSDItemIndexMap));
// Altitude alarm
sbufWriteU16(dst, osdConfig()->alt_alarm);
// OSD element position and visibility
for (unsigned i = 0; i < ARRAYLEN(djiOSDItemIndexMap); i++) {
int inavOSDIdx = djiOSDItemIndexMap[i];
if (inavOSDIdx >= 0) {
// Position & visibility encoded in 16 bits. Position encoding is the same between BF/DJI and INAV
// However visibility is different. INAV has 3 layouts, while BF only has visibility profiles
// Here we use only one OSD layout mapped to first OSD BF profile
uint16_t itemPos = osdConfig()->item_pos[0][inavOSDIdx];
// Workarounds for certain OSD element positions
// INAV calculates these dynamically, while DJI expects the config to have defined coordinates
switch(inavOSDIdx) {
case OSD_CROSSHAIRS:
itemPos = (itemPos & (~OSD_POS_MAX)) | OSD_POS(13, 6);
break;
case OSD_ARTIFICIAL_HORIZON:
itemPos = (itemPos & (~OSD_POS_MAX)) | OSD_POS(14, 2);
break;
case OSD_HORIZON_SIDEBARS:
itemPos = (itemPos & (~OSD_POS_MAX)) | OSD_POS(14, 5);
break;
}
// Enforce visibility in 3 BF OSD profiles
if (OSD_VISIBLE(itemPos)) {
itemPos |= 0x3000;
}
sbufWriteU16(dst, itemPos);
}
else {
// Hide OSD elements unsupported by INAV
sbufWriteU16(dst, 0);
}
}
// Post flight statistics
sbufWriteU8(dst, ARRAYLEN(djiOSDStatisticsMap));
for (unsigned i = 0; i < ARRAYLEN(djiOSDStatisticsMap); i++ ) {
if (djiOSDStatisticsMap[i] >= 0) {
// FIXME: Map post-flight statistics from INAV to BF/DJI
sbufWriteU8(dst, 0);
}
else {
sbufWriteU8(dst, 0);
}
}
// Timers
sbufWriteU8(dst, DJI_OSD_TIMER_COUNT);
for (int i = 0; i < DJI_OSD_TIMER_COUNT; i++) {
// STUB: We don't support BF's OSD timers
sbufWriteU16(dst, 0);
}
// Enabled warnings
// API < 1.41 stub, kept for compatibility
sbufWriteU16(dst, djiEncodeOSDEnabledWarnings() & 0xFFFF);
// API >= 1.41
// Send the warnings count and 32bit enabled warnings flags.
sbufWriteU8(dst, DJI_OSD_WARNING_COUNT);
sbufWriteU32(dst, djiEncodeOSDEnabledWarnings());
// DJI OSD expects 1 OSD profile
sbufWriteU8(dst, 1);
sbufWriteU8(dst, 1);
// No OSD stick overlay
sbufWriteU8(dst, 0);
// API >= 1.43
// Camera frame element width/height - magic numbers taken from Betaflight source
//sbufWriteU8(dst, DJI_OSD_SCREEN_WIDTH); // osdConfig()->camera_frame_width
//sbufWriteU8(dst, DJI_OSD_SCREEN_HEIGHT); // osdConfig()->camera_frame_height
}
static mspResult_e djiProcessMspCommand(mspPacket_t *cmd, mspPacket_t *reply, mspPostProcessFnPtr *mspPostProcessFn)
{
UNUSED(mspPostProcessFn);
sbuf_t *dst = &reply->buf;
sbuf_t *src = &cmd->buf;
// Start initializing the reply message
reply->cmd = cmd->cmd;
reply->result = MSP_RESULT_ACK;
switch (cmd->cmd) {
case DJI_MSP_API_VERSION:
sbufWriteU8(dst, MSP_PROTOCOL_VERSION);
sbufWriteU8(dst, DJI_API_VERSION_MAJOR);
sbufWriteU8(dst, DJI_API_VERSION_MINOR);
break;
case DJI_MSP_FC_VARIANT:
{
const char * const flightControllerIdentifier = INAV_IDENTIFIER;
sbufWriteData(dst, flightControllerIdentifier, FLIGHT_CONTROLLER_IDENTIFIER_LENGTH);
}
break;
case DJI_MSP_FC_VERSION:
sbufWriteU8(dst, 4);
sbufWriteU8(dst, 1);
sbufWriteU8(dst, 0);
break;
case DJI_MSP_NAME:
{
const char * name = systemConfig()->name;
int len = strlen(name);
if (len > 12) len = 12;
sbufWriteData(dst, name, len);
}
break;
case DJI_MSP_STATUS:
case DJI_MSP_STATUS_EX:
{
// DJI OSD relies on a statically defined bit order and doesn't use MSP_BOXIDS
// to get actual BOX order. We need a special packBoxModeFlags()
boxBitmask_t flightModeBitmask;
djiPackBoxModeBitmask(&flightModeBitmask);
sbufWriteU16(dst, (uint16_t)cycleTime);
sbufWriteU16(dst, 0);
sbufWriteU16(dst, packSensorStatus());
sbufWriteData(dst, &flightModeBitmask, 4); // unconditional part of flags, first 32 bits
sbufWriteU8(dst, getConfigProfile());
sbufWriteU16(dst, constrain(averageSystemLoadPercent, 0, 100));
if (cmd->cmd == MSP_STATUS_EX) {
sbufWriteU8(dst, 3); // PID_PROFILE_COUNT
sbufWriteU8(dst, 1); // getCurrentControlRateProfileIndex()
} else {
sbufWriteU16(dst, cycleTime); // gyro cycle time
}
// Cap BoxModeFlags to 32 bits
// write flightModeFlags header. Lowest 4 bits contain number of bytes that follow
sbufWriteU8(dst, 0);
// sbufWriteData(dst, ((uint8_t*)&flightModeBitmask) + 4, byteCount);
// Write arming disable flags
sbufWriteU8(dst, DJI_ARMING_DISABLE_FLAGS_COUNT);
sbufWriteU32(dst, djiPackArmingDisabledFlags());
// Extra flags
sbufWriteU8(dst, 0);
}
break;
case DJI_MSP_RC:
// Only send sticks (first 4 channels)
for (int i = 0; i < STICK_CHANNEL_COUNT; i++) {
sbufWriteU16(dst, rxGetRawChannelValue(i));
}
break;
case DJI_MSP_RAW_GPS:
sbufWriteU8(dst, gpsSol.fixType);
sbufWriteU8(dst, gpsSol.numSat);
sbufWriteU32(dst, gpsSol.llh.lat);
sbufWriteU32(dst, gpsSol.llh.lon);
sbufWriteU16(dst, gpsSol.llh.alt / 100);
sbufWriteU16(dst, gpsSol.groundSpeed);
sbufWriteU16(dst, gpsSol.groundCourse);
break;
case DJI_MSP_COMP_GPS:
sbufWriteU16(dst, GPS_distanceToHome);
sbufWriteU16(dst, GPS_directionToHome);
sbufWriteU8(dst, gpsSol.flags.gpsHeartbeat ? 1 : 0);
break;
case DJI_MSP_ATTITUDE:
sbufWriteU16(dst, attitude.values.roll);
sbufWriteU16(dst, attitude.values.pitch);
sbufWriteU16(dst, DECIDEGREES_TO_DEGREES(attitude.values.yaw));
break;
case DJI_MSP_ALTITUDE:
sbufWriteU32(dst, lrintf(getEstimatedActualPosition(Z)));
sbufWriteU16(dst, lrintf(getEstimatedActualVelocity(Z)));
break;
case DJI_MSP_ANALOG:
sbufWriteU8(dst, constrain(getBatteryVoltage() / 10, 0, 255));
sbufWriteU16(dst, constrain(getMAhDrawn(), 0, 0xFFFF)); // milliamp hours drawn from battery
sbufWriteU16(dst, getRSSI());
sbufWriteU16(dst, constrain(getAmperage(), -0x8000, 0x7FFF)); // send amperage in 0.01 A steps, range is -320A to 320A
sbufWriteU16(dst, getBatteryVoltage());
break;
case DJI_MSP_PID:
for (unsigned i = 0; i < ARRAYLEN(djiPidIndexMap); i++) {
sbufWriteU8(dst, pidBank()->pid[djiPidIndexMap[i]].P);
sbufWriteU8(dst, pidBank()->pid[djiPidIndexMap[i]].I);
sbufWriteU8(dst, pidBank()->pid[djiPidIndexMap[i]].D);
}
break;
case DJI_MSP_BATTERY_STATE:
// Battery characteristics
sbufWriteU8(dst, constrain(getBatteryCellCount(), 0, 255));
sbufWriteU16(dst, currentBatteryProfile->capacity.value);
// Battery state
sbufWriteU8(dst, constrain(getBatteryVoltage() / 10, 0, 255)); // in 0.1V steps
sbufWriteU16(dst, constrain(getMAhDrawn(), 0, 0xFFFF));
sbufWriteU16(dst, constrain(getAmperage(), -0x8000, 0x7FFF));
// Battery alerts - used values match Betaflight's/DJI's
sbufWriteU8(dst, getBatteryState());
// Additional battery voltage field (in 0.01V steps)
sbufWriteU16(dst, getBatteryVoltage());
break;
case DJI_MSP_RTC:
{
dateTime_t datetime;
// We don't care about validity here - dt will be always set to a sane value
// rtcGetDateTime() will call rtcGetDefaultDateTime() internally
rtcGetDateTime(&datetime);
sbufWriteU16(dst, datetime.year);
sbufWriteU8(dst, datetime.month);
sbufWriteU8(dst, datetime.day);
sbufWriteU8(dst, datetime.hours);
sbufWriteU8(dst, datetime.minutes);
sbufWriteU8(dst, datetime.seconds);
sbufWriteU16(dst, datetime.millis);
}
break;
#if defined(USE_ESC_SENSOR)
case DJI_MSP_ESC_SENSOR_DATA:
if (STATE(ESC_SENSOR_ENABLED)) {
sbufWriteU8(dst, getMotorCount());
for (int i = 0; i < getMotorCount(); i++) {
const escSensorData_t * escSensor = getEscTelemetry(i);
sbufWriteU8(dst, escSensor->temperature);
sbufWriteU16(dst, escSensor->rpm);
}
}
else {
reply->result = MSP_RESULT_ERROR;
}
break;
#endif
case DJI_MSP_OSD_CONFIG:
#if defined(USE_OSD)
// This involved some serious magic, better contain in a separate function for readability
djiSerializeOSDConfigReply(dst);
#else
sbufWriteU8(dst, 0);
#endif
break;
case DJI_MSP_FILTER_CONFIG:
sbufWriteU8(dst, gyroConfig()->gyro_soft_lpf_hz); // BF: gyroConfig()->gyro_lowpass_hz
sbufWriteU16(dst, pidProfile()->dterm_lpf_hz); // BF: currentPidProfile->dterm_lowpass_hz
sbufWriteU16(dst, pidProfile()->yaw_lpf_hz); // BF: currentPidProfile->yaw_lowpass_hz
sbufWriteU16(dst, gyroConfig()->gyro_soft_notch_hz_1); // BF: gyroConfig()->gyro_soft_notch_hz_1
sbufWriteU16(dst, gyroConfig()->gyro_soft_notch_cutoff_1); // BF: gyroConfig()->gyro_soft_notch_cutoff_1
sbufWriteU16(dst, pidProfile()->dterm_soft_notch_hz); // BF: currentPidProfile->dterm_notch_hz
sbufWriteU16(dst, pidProfile()->dterm_soft_notch_cutoff); // BF: currentPidProfile->dterm_notch_cutoff
sbufWriteU16(dst, gyroConfig()->gyro_soft_notch_hz_2); // BF: gyroConfig()->gyro_soft_notch_hz_2
sbufWriteU16(dst, gyroConfig()->gyro_soft_notch_cutoff_2); // BF: gyroConfig()->gyro_soft_notch_cutoff_2
sbufWriteU8(dst, 0); // BF: currentPidProfile->dterm_filter_type
sbufWriteU8(dst, gyroConfig()->gyro_lpf); // BF: gyroConfig()->gyro_hardware_lpf);
sbufWriteU8(dst, 0); // BF: DEPRECATED: gyro_32khz_hardware_lpf
sbufWriteU16(dst, gyroConfig()->gyro_soft_lpf_hz); // BF: gyroConfig()->gyro_lowpass_hz);
sbufWriteU16(dst, gyroConfig()->gyro_stage2_lowpass_hz); // BF: gyroConfig()->gyro_lowpass2_hz);
sbufWriteU8(dst, 0); // BF: gyroConfig()->gyro_lowpass_type);
sbufWriteU8(dst, 0); // BF: gyroConfig()->gyro_lowpass2_type);
sbufWriteU16(dst, 0); // BF: currentPidProfile->dterm_lowpass2_hz);
sbufWriteU8(dst, 0); // BF: currentPidProfile->dterm_filter2_type);
break;
case DJI_MSP_RC_TUNING:
sbufWriteU8(dst, 100); // INAV doesn't use rcRate
sbufWriteU8(dst, currentControlRateProfile->stabilized.rcExpo8);
for (int i = 0 ; i < 3; i++) {
// R,P,Y rates see flight_dynamics_index_t
sbufWriteU8(dst, currentControlRateProfile->stabilized.rates[i]);
}
sbufWriteU8(dst, currentControlRateProfile->throttle.dynPID);
sbufWriteU8(dst, currentControlRateProfile->throttle.rcMid8);
sbufWriteU8(dst, currentControlRateProfile->throttle.rcExpo8);
sbufWriteU16(dst, currentControlRateProfile->throttle.pa_breakpoint);
sbufWriteU8(dst, currentControlRateProfile->stabilized.rcYawExpo8);
sbufWriteU8(dst, 100); // INAV doesn't use rcRate
sbufWriteU8(dst, 100); // INAV doesn't use rcRate
sbufWriteU8(dst, currentControlRateProfile->stabilized.rcExpo8);
// added in 1.41
sbufWriteU8(dst, 0);
sbufWriteU8(dst, currentControlRateProfile->throttle.dynPID);
break;
case DJI_MSP_SET_PID:
// Check if we have enough data for all PID coefficients
if ((unsigned)sbufBytesRemaining(src) >= ARRAYLEN(djiPidIndexMap) * 3) {
for (unsigned i = 0; i < ARRAYLEN(djiPidIndexMap); i++) {
pidBankMutable()->pid[djiPidIndexMap[i]].P = sbufReadU8(src);
pidBankMutable()->pid[djiPidIndexMap[i]].I = sbufReadU8(src);
pidBankMutable()->pid[djiPidIndexMap[i]].D = sbufReadU8(src);
}
schedulePidGainsUpdate();
#if defined(USE_NAV)
// This is currently unnecessary, DJI HD doesn't set any NAV PIDs
//navigationUsePIDs();
#endif
}
else {
reply->result = MSP_RESULT_ERROR;
}
break;
case DJI_MSP_PID_ADVANCED:
// TODO
reply->result = MSP_RESULT_ERROR;
break;
case DJI_MSP_SET_FILTER_CONFIG:
case DJI_MSP_SET_PID_ADVANCED:
case DJI_MSP_SET_RC_TUNING:
// TODO
reply->result = MSP_RESULT_ERROR;
break;
default:
// debug[1]++;
// debug[2] = cmd->cmd;
reply->result = MSP_RESULT_ERROR;
break;
}
// Process DONT_REPLY flag
if (cmd->flags & MSP_FLAG_DONT_REPLY) {
reply->result = MSP_RESULT_NO_REPLY;
}
return reply->result;
}
void djiOsdSerialProcess(void)
{
// Check if DJI OSD is configured
if (!djiMspPort.port) {
return;
}
// Piggyback on existing MSP protocol stack, but pass our special command processing function
mspSerialProcessOnePort(&djiMspPort, MSP_SKIP_NON_MSP_DATA, djiProcessMspCommand);
}
#endif

66
src/main/io/osd_dji_hd.h Normal file
View file

@ -0,0 +1,66 @@
/*
* This file is part of INAV.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License Version 3, as described below:
*
* This file is free software: you may copy, redistribute and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
* @author Konstantin Sharlaimov (ksharlaimov@inavflight.com)
*/
#pragma once
#include "msp/msp.h"
#include "msp/msp_serial.h"
#if defined(USE_DJI_HD_OSD)
#define DJI_API_VERSION_MAJOR 1
#define DJI_API_VERSION_MINOR 42
#define DJI_MSP_API_VERSION 1 // INAV: Implemented | DSI: ??? |
#define DJI_MSP_FC_VARIANT 2 // INAV: Implemented | DSI: ??? |
#define DJI_MSP_FC_VERSION 3 // INAV: Implemented | DSI: ??? |
#define DJI_MSP_NAME 10 // INAV: Implemented | DSI: Implemented | For OSD 'Craft Name'
#define DJI_MSP_OSD_CONFIG 84 // INAV: Implemented | DSI: Implemented | OSD item count + positions
#define DJI_MSP_FILTER_CONFIG 92 // INAV: Not implemented | DSI: Implemented |
#define DJI_MSP_PID_ADVANCED 94 // INAV: Not implemented | DSI: Implemented |
#define DJI_MSP_STATUS 101 // INAV: Implemented | DSI: Implemented | For OSD armingTime, Flight controller arming status
#define DJI_MSP_RC 105 // INAV: Implemented | DSI: Implemented |
#define DJI_MSP_RAW_GPS 106 // INAV: Implemented | DSI: Implemented | For OSD GPS Sats + coordinates
#define DJI_MSP_COMP_GPS 107 // INAV: Implemented | DSI: Not implemented | GPS direction to home & distance to home
#define DJI_MSP_ATTITUDE 108 // INAV: Implemented | DSI: Implemented | For OSD Angle: roll & pitch
#define DJI_MSP_ALTITUDE 109 // INAV: Implemented | DSI: Implemented | For OSD Numerical Vario
#define DJI_MSP_ANALOG 110 // INAV: Implemented | DSI: Implemented | For OSD RSSI Value, For OSD Battery voltage etc
#define DJI_MSP_RC_TUNING 111 // INAV: Not implemented | DSI: Implemented |
#define DJI_MSP_PID 112 // INAV: Implemented | DSI: Implemented | For OSD PID roll, yaw, pitch'
#define DJI_MSP_BATTERY_STATE 130 // INAV: Implemented | DSI: Implemented | For OSD Battery current mAh drawn etc
#define DJI_MSP_ESC_SENSOR_DATA 134 // INAV: Implemented | DSI: Implemented | For OSD ESC temperature
#define DJI_MSP_STATUS_EX 150 // INAV: Implemented | DSI: Implemented | For OSD Fly mode', For OSD Disarmed
#define DJI_MSP_RTC 247 // INAV: Implemented | DSI: Implemented | For OSD RTC date time
#define DJI_MSP_SET_FILTER_CONFIG 93
#define DJI_MSP_SET_PID_ADVANCED 95
#define DJI_MSP_SET_PID 202
#define DJI_MSP_SET_RC_TUNING 204
void djiOsdSerialInit(void);
void djiOsdSerialProcess(void);
#endif

View file

@ -52,6 +52,7 @@ typedef enum {
FUNCTION_ESCSERIAL = (1 << 18), // 262144: this is used for both SERIALSHOT and ESC_SENSOR telemetry
FUNCTION_TELEMETRY_SIM = (1 << 19), // 524288
FUNCTION_FRSKY_OSD = (1 << 20), // 1048576
FUNCTION_DJI_HD_OSD = (1 << 21), // 2097152
} serialPortFunction_e;
typedef enum {

View file

@ -321,7 +321,7 @@
#define MSP_SET_ACC_TRIM 239 //in message set acc angle trim values
#define MSP_SERVO_MIX_RULES 241 //out message Returns servo mixer configuration
#define MSP_SET_SERVO_MIX_RULE 242 //in message Sets servo mixer configuration
#define MSP_SET_4WAY_IF 245 //in message Sets 4way interface
#define MSP_SET_PASSTHROUGH 245 //in message Sets up passthrough to different peripherals (4way interface, uart, etc...)
#define MSP_RTC 246 //out message Gets the RTC clock (returns: secs(i32) millis(u16) - (0,0) if time is not known)
#define MSP_SET_RTC 247 //in message Sets the RTC clock (args: secs(i32) millis(u16))

View file

@ -40,7 +40,7 @@
static mspPort_t mspPorts[MAX_MSP_PORT_COUNT];
static void resetMspPort(mspPort_t *mspPortToReset, serialPort_t *serialPort)
void resetMspPort(mspPort_t *mspPortToReset, serialPort_t *serialPort)
{
memset(mspPortToReset, 0, sizeof(mspPort_t));
@ -452,19 +452,8 @@ static void mspProcessPendingRequest(mspPort_t * mspPort)
}
}
/*
* Process MSP commands from serial ports configured as MSP ports.
*
* Called periodically by the scheduler.
*/
void mspSerialProcess(mspEvaluateNonMspData_e evaluateNonMspData, mspProcessCommandFnPtr mspProcessCommandFn)
void mspSerialProcessOnePort(mspPort_t * const mspPort, mspEvaluateNonMspData_e evaluateNonMspData, mspProcessCommandFnPtr mspProcessCommandFn)
{
for (uint8_t portIndex = 0; portIndex < MAX_MSP_PORT_COUNT; portIndex++) {
mspPort_t * const mspPort = &mspPorts[portIndex];
if (!mspPort->port) {
continue;
}
mspPostProcessFnPtr mspPostProcessFn = NULL;
if (serialRxBytesWaiting(mspPort->port)) {
@ -496,6 +485,20 @@ void mspSerialProcess(mspEvaluateNonMspData_e evaluateNonMspData, mspProcessComm
mspProcessPendingRequest(mspPort);
}
}
/*
* Process MSP commands from serial ports configured as MSP ports.
*
* Called periodically by the scheduler.
*/
void mspSerialProcess(mspEvaluateNonMspData_e evaluateNonMspData, mspProcessCommandFnPtr mspProcessCommandFn)
{
for (uint8_t portIndex = 0; portIndex < MAX_MSP_PORT_COUNT; portIndex++) {
mspPort_t * const mspPort = &mspPorts[portIndex];
if (mspPort->port) {
mspSerialProcessOnePort(mspPort, evaluateNonMspData, mspProcessCommandFn);
}
}
}
void mspSerialInit(void)

View file

@ -18,6 +18,7 @@
#pragma once
#include "drivers/time.h"
#include "io/serial.h"
#include "msp/msp.h"
// Each MSP port requires state and a receive buffer, revisit this default if someone needs more than 3 MSP ports.
@ -99,7 +100,9 @@ typedef struct mspPort_s {
void mspSerialInit(void);
void resetMspPort(mspPort_t *mspPortToReset, serialPort_t *serialPort);
void mspSerialProcess(mspEvaluateNonMspData_e evaluateNonMspData, mspProcessCommandFnPtr mspProcessCommandFn);
void mspSerialProcessOnePort(mspPort_t * const mspPort, mspEvaluateNonMspData_e evaluateNonMspData, mspProcessCommandFnPtr mspProcessCommandFn);
void mspSerialAllocatePorts(void);
void mspSerialReleasePortIfAllocated(struct serialPort_s *serialPort);
int mspSerialPushPort(uint16_t cmd, const uint8_t *data, int datalen, mspPort_t *mspPort, mspVersion_e version);

View file

@ -843,7 +843,7 @@ navigationFSMStateFlags_t navGetCurrentStateFlags(void)
static bool navTerrainFollowingRequested(void)
{
// Terrain following not supported on FIXED WING aircraft yet
return !STATE(FIXED_WING) && IS_RC_MODE_ACTIVE(BOXSURFACE);
return !STATE(FIXED_WING_LEGACY) && IS_RC_MODE_ACTIVE(BOXSURFACE);
}
/*************************************************************************************************/
@ -941,7 +941,7 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_CRUISE_2D_INITIALIZE(na
{
const navigationFSMStateFlags_t prevFlags = navGetStateFlags(previousState);
if (!STATE(FIXED_WING)) { return NAV_FSM_EVENT_ERROR; } // Only on FW for now
if (!STATE(FIXED_WING_LEGACY)) { return NAV_FSM_EVENT_ERROR; } // Only on FW for now
DEBUG_SET(DEBUG_CRUISE, 0, 1);
if (checkForPositionSensorTimeout()) { return NAV_FSM_EVENT_SWITCH_TO_IDLE; } // Switch to IDLE if we do not have an healty position. Try the next iteration.
@ -1020,7 +1020,7 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_CRUISE_2D_ADJUSTING(nav
static navigationFSMEvent_t navOnEnteringState_NAV_STATE_CRUISE_3D_INITIALIZE(navigationFSMState_t previousState)
{
if (!STATE(FIXED_WING)) { return NAV_FSM_EVENT_ERROR; } // only on FW for now
if (!STATE(FIXED_WING_LEGACY)) { return NAV_FSM_EVENT_ERROR; } // only on FW for now
navOnEnteringState_NAV_STATE_ALTHOLD_INITIALIZE(previousState);
@ -1051,7 +1051,7 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_RTH_INITIALIZE(navigati
return NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING;
}
if (STATE(FIXED_WING) && (posControl.homeDistance < navConfig()->general.min_rth_distance) && !posControl.flags.forcedRTHActivated) {
if (STATE(FIXED_WING_LEGACY) && (posControl.homeDistance < navConfig()->general.min_rth_distance) && !posControl.flags.forcedRTHActivated) {
// Prevent RTH from activating on airplanes if too close to home unless it's a failsafe RTH
return NAV_FSM_EVENT_SWITCH_TO_IDLE;
}
@ -1080,7 +1080,7 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_RTH_INITIALIZE(navigati
else {
fpVector3_t targetHoldPos;
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
// Airplane - climbout before turning around
calculateFarAwayTarget(&targetHoldPos, posControl.actualState.yaw, 100000.0f); // 1km away
} else {
@ -1117,14 +1117,14 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_RTH_CLIMB_TO_SAFE_ALT(n
// If we have valid pos sensor OR we are configured to ignore GPS loss
if ((posControl.flags.estPosStatus >= EST_USABLE) || !checkForPositionSensorTimeout() || navConfig()->general.flags.rth_climb_ignore_emerg) {
const uint8_t rthClimbMarginPercent = STATE(FIXED_WING) ? FW_RTH_CLIMB_MARGIN_PERCENT : MR_RTH_CLIMB_MARGIN_PERCENT;
const uint8_t rthClimbMarginPercent = STATE(FIXED_WING_LEGACY) ? FW_RTH_CLIMB_MARGIN_PERCENT : MR_RTH_CLIMB_MARGIN_PERCENT;
const float rthAltitudeMargin = MAX(FW_RTH_CLIMB_MARGIN_MIN_CM, (rthClimbMarginPercent/100.0) * fabsf(posControl.rthState.rthInitialAltitude - posControl.rthState.homePosition.pos.z));
// If we reached desired initial RTH altitude or we don't want to climb first
if (((navGetCurrentActualPositionAndVelocity()->pos.z - posControl.rthState.rthInitialAltitude) > -rthAltitudeMargin) || (!navConfig()->general.flags.rth_climb_first)) {
// Delayed initialization for RTH sanity check on airplanes - allow to finish climb first as it can take some distance
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
initializeRTHSanityChecker(&navGetCurrentActualPositionAndVelocity()->pos);
}
@ -1132,7 +1132,7 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_RTH_CLIMB_TO_SAFE_ALT(n
posControl.rthState.rthInitialDistance = posControl.homeDistance;
fpVector3_t * tmpHomePos = rthGetHomeTargetPosition(RTH_HOME_ENROUTE_INITIAL);
if (navConfig()->general.flags.rth_tail_first && !STATE(FIXED_WING)) {
if (navConfig()->general.flags.rth_tail_first && !STATE(FIXED_WING_LEGACY)) {
setDesiredPosition(tmpHomePos, 0, NAV_POS_UPDATE_XY | NAV_POS_UPDATE_Z | NAV_POS_UPDATE_BEARING_TAIL_FIRST);
}
else {
@ -1146,12 +1146,12 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_RTH_CLIMB_TO_SAFE_ALT(n
fpVector3_t * tmpHomePos = rthGetHomeTargetPosition(RTH_HOME_ENROUTE_INITIAL);
/* For multi-rotors execute sanity check during initial ascent as well */
if (!STATE(FIXED_WING) && !validateRTHSanityChecker()) {
if (!STATE(FIXED_WING_LEGACY) && !validateRTHSanityChecker()) {
return NAV_FSM_EVENT_SWITCH_TO_EMERGENCY_LANDING;
}
// Climb to safe altitude and turn to correct direction
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
tmpHomePos->z += FW_RTH_CLIMB_OVERSHOOT_CM;
setDesiredPosition(tmpHomePos, 0, NAV_POS_UPDATE_Z);
} else {
@ -1224,7 +1224,7 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_RTH_HOVER_PRIOR_TO_LAND
if ((posControl.flags.estPosStatus >= EST_USABLE) || !checkForPositionSensorTimeout()) {
// Wait until target heading is reached (with 15 deg margin for error)
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
resetLandingDetector();
updateClimbRateToAltitudeController(0, ROC_TO_ALT_RESET);
return navigationRTHAllowsLanding() ? NAV_FSM_EVENT_SUCCESS : NAV_FSM_EVENT_SWITCH_TO_RTH_HOVER_ABOVE_HOME;
@ -1401,8 +1401,8 @@ static navigationFSMEvent_t navOnEnteringState_NAV_STATE_WAYPOINT_IN_PROGRESS(na
fpVector3_t tmpWaypoint;
tmpWaypoint.x = posControl.activeWaypoint.pos.x;
tmpWaypoint.y = posControl.activeWaypoint.pos.y;
tmpWaypoint.z = scaleRange(constrainf(posControl.wpDistance, posControl.wpInitialDistance / 10, posControl.wpInitialDistance),
posControl.wpInitialDistance, posControl.wpInitialDistance / 10,
tmpWaypoint.z = scaleRangef(constrainf(posControl.wpDistance, posControl.wpInitialDistance / 10.0f, posControl.wpInitialDistance),
posControl.wpInitialDistance, posControl.wpInitialDistance / 10.0f,
posControl.wpInitialAltitude, posControl.activeWaypoint.pos.z);
setDesiredPosition(&tmpWaypoint, 0, NAV_POS_UPDATE_XY | NAV_POS_UPDATE_Z | NAV_POS_UPDATE_BEARING);
return NAV_FSM_EVENT_NONE; // will re-process state in >10ms
@ -1675,7 +1675,7 @@ static fpVector3_t * rthGetHomeTargetPosition(rthTargetMode_e mode)
case RTH_HOME_ENROUTE_PROPORTIONAL:
{
float rthTotalDistanceToTravel = posControl.rthState.rthInitialDistance - (STATE(FIXED_WING) ? navConfig()->fw.loiter_radius : 0);
float rthTotalDistanceToTravel = posControl.rthState.rthInitialDistance - (STATE(FIXED_WING_LEGACY) ? navConfig()->fw.loiter_radius : 0);
if (rthTotalDistanceToTravel >= 100) {
float ratioNotTravelled = constrainf(posControl.homeDistance / rthTotalDistanceToTravel, 0.0f, 1.0f);
posControl.rthState.homeTmpWaypoint.z = (posControl.rthState.rthInitialAltitude * ratioNotTravelled) + (posControl.rthState.rthFinalAltitude * (1.0f - ratioNotTravelled));
@ -2059,7 +2059,7 @@ static bool isWaypointPositionReached(const fpVector3_t * pos, const bool isWayp
// We consider waypoint reached if within specified radius
posControl.wpDistance = calculateDistanceToDestination(pos);
if (STATE(FIXED_WING) && isWaypointHome) {
if (STATE(FIXED_WING_LEGACY) && isWaypointHome) {
// Airplane will do a circular loiter over home and might never approach it closer than waypoint_radius - need extra check
return (posControl.wpDistance <= navConfig()->general.waypoint_radius)
|| (posControl.wpDistance <= (navConfig()->fw.loiter_radius * 1.10f)); // 10% margin of desired circular loiter radius
@ -2318,7 +2318,7 @@ uint32_t getTotalTravelDistance(void)
*-----------------------------------------------------------*/
void calculateInitialHoldPosition(fpVector3_t * pos)
{
if (STATE(FIXED_WING)) { // FIXED_WING
if (STATE(FIXED_WING_LEGACY)) { // FIXED_WING_LEGACY
calculateFixedWingInitialHoldPosition(pos);
}
else {
@ -2375,7 +2375,7 @@ void calculateNewCruiseTarget(fpVector3_t * origin, int32_t yaw, int32_t distanc
*-----------------------------------------------------------*/
void resetLandingDetector(void)
{
if (STATE(FIXED_WING)) { // FIXED_WING
if (STATE(FIXED_WING_LEGACY)) { // FIXED_WING_LEGACY
resetFixedWingLandingDetector();
}
else {
@ -2387,7 +2387,7 @@ bool isLandingDetected(void)
{
bool landingDetected;
if (STATE(FIXED_WING)) { // FIXED_WING
if (STATE(FIXED_WING_LEGACY)) { // FIXED_WING_LEGACY
landingDetected = isFixedWingLandingDetected();
}
else {
@ -2413,7 +2413,7 @@ void updateClimbRateToAltitudeController(float desiredClimbRate, climbRateToAlti
posControl.desiredState.pos.z = altitudeToUse;
}
else {
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
// Fixed wing climb rate controller is open-loop. We simply move the known altitude target
float timeDelta = US2S(currentTimeUs - lastUpdateTimeUs);
@ -2436,7 +2436,7 @@ static void resetAltitudeController(bool useTerrainFollowing)
// Set terrain following flag
posControl.flags.isTerrainFollowEnabled = useTerrainFollowing;
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
resetFixedWingAltitudeController();
}
else {
@ -2446,7 +2446,7 @@ static void resetAltitudeController(bool useTerrainFollowing)
static void setupAltitudeController(void)
{
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
setupFixedWingAltitudeController();
}
else {
@ -2456,7 +2456,7 @@ static void setupAltitudeController(void)
static bool adjustAltitudeFromRCInput(void)
{
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
return adjustFixedWingAltitudeFromRCInput();
}
else {
@ -2469,7 +2469,7 @@ static bool adjustAltitudeFromRCInput(void)
*-----------------------------------------------------------*/
static void resetHeadingController(void)
{
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
resetFixedWingHeadingController();
}
else {
@ -2479,7 +2479,7 @@ static void resetHeadingController(void)
static bool adjustHeadingFromRCInput(void)
{
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
return adjustFixedWingHeadingFromRCInput();
}
else {
@ -2492,7 +2492,7 @@ static bool adjustHeadingFromRCInput(void)
*-----------------------------------------------------------*/
static void resetPositionController(void)
{
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
resetFixedWingPositionController();
}
else {
@ -2505,7 +2505,7 @@ static bool adjustPositionFromRCInput(void)
{
bool retValue;
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
retValue = adjustFixedWingPositionFromRCInput();
}
else {
@ -2773,7 +2773,7 @@ static void processNavigationRCAdjustments(void)
posControl.flags.isAdjustingPosition = adjustPositionFromRCInput();
}
else {
if (!STATE(FIXED_WING)) {
if (!STATE(FIXED_WING_LEGACY)) {
resetMulticopterBrakingMode();
}
}
@ -2825,7 +2825,7 @@ void applyWaypointNavigationAndAltitudeHold(void)
/* Process controllers */
navigationFSMStateFlags_t navStateFlags = navGetStateFlags(posControl.navState);
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
applyFixedWingNavigationController(navStateFlags, currentTimeUs);
}
else {
@ -2898,7 +2898,7 @@ static navigationFSMEvent_t selectNavEventFromBoxModeInput(void)
bool canActivateNavigation = canActivateNavigationModes();
// LAUNCH mode has priority over any other NAV mode
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
if (isNavLaunchEnabled()) { // FIXME: Only available for fixed wing aircrafts now
if (canActivateLaunchMode) {
canActivateLaunchMode = false;
@ -2981,7 +2981,7 @@ static navigationFSMEvent_t selectNavEventFromBoxModeInput(void)
*-----------------------------------------------------------*/
bool navigationRequiresThrottleTiltCompensation(void)
{
return !STATE(FIXED_WING) && (navGetStateFlags(posControl.navState) & NAV_REQUIRE_THRTILT);
return !STATE(FIXED_WING_LEGACY) && (navGetStateFlags(posControl.navState) & NAV_REQUIRE_THRTILT);
}
/*-----------------------------------------------------------
@ -2990,7 +2990,7 @@ bool navigationRequiresThrottleTiltCompensation(void)
bool navigationRequiresAngleMode(void)
{
const navigationFSMStateFlags_t currentState = navGetStateFlags(posControl.navState);
return (currentState & NAV_REQUIRE_ANGLE) || ((currentState & NAV_REQUIRE_ANGLE_FW) && STATE(FIXED_WING));
return (currentState & NAV_REQUIRE_ANGLE) || ((currentState & NAV_REQUIRE_ANGLE_FW) && STATE(FIXED_WING_LEGACY));
}
/*-----------------------------------------------------------
@ -2999,7 +2999,7 @@ bool navigationRequiresAngleMode(void)
bool navigationRequiresTurnAssistance(void)
{
const navigationFSMStateFlags_t currentState = navGetStateFlags(posControl.navState);
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
// For airplanes turn assistant is always required when controlling position
return (currentState & (NAV_CTL_POS | NAV_CTL_ALT));
}
@ -3014,7 +3014,7 @@ bool navigationRequiresTurnAssistance(void)
int8_t navigationGetHeadingControlState(void)
{
// For airplanes report as manual heading control
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
return NAV_HEADING_CONTROL_MANUAL;
}
@ -3039,7 +3039,7 @@ bool navigationTerrainFollowingEnabled(void)
navArmingBlocker_e navigationIsBlockingArming(bool *usedBypass)
{
const bool navBoxModesEnabled = IS_RC_MODE_ACTIVE(BOXNAVRTH) || IS_RC_MODE_ACTIVE(BOXNAVWP) || IS_RC_MODE_ACTIVE(BOXNAVPOSHOLD) || (STATE(FIXED_WING) && IS_RC_MODE_ACTIVE(BOXNAVALTHOLD)) || (STATE(FIXED_WING) && IS_RC_MODE_ACTIVE(BOXNAVCRUISE));
const bool navBoxModesEnabled = IS_RC_MODE_ACTIVE(BOXNAVRTH) || IS_RC_MODE_ACTIVE(BOXNAVWP) || IS_RC_MODE_ACTIVE(BOXNAVPOSHOLD) || (STATE(FIXED_WING_LEGACY) && IS_RC_MODE_ACTIVE(BOXNAVALTHOLD)) || (STATE(FIXED_WING_LEGACY) && IS_RC_MODE_ACTIVE(BOXNAVCRUISE));
const bool navLaunchComboModesEnabled = isNavLaunchEnabled() && (IS_RC_MODE_ACTIVE(BOXNAVRTH) || IS_RC_MODE_ACTIVE(BOXNAVWP) || IS_RC_MODE_ACTIVE(BOXNAVALTHOLD) || IS_RC_MODE_ACTIVE(BOXNAVCRUISE));
if (usedBypass) {

View file

@ -533,7 +533,7 @@ void applyFixedWingPitchRollThrottleController(navigationFSMStateFlags_t navStat
isAutoThrottleManuallyIncreased = false;
}
rcCommand[THROTTLE] = constrain(correctedThrottleValue, motorConfig()->minthrottle, motorConfig()->maxthrottle);
rcCommand[THROTTLE] = constrain(correctedThrottleValue, getThrottleIdleValue(), motorConfig()->maxthrottle);
}
#ifdef NAV_FIXED_WING_LANDING
@ -546,7 +546,7 @@ void applyFixedWingPitchRollThrottleController(navigationFSMStateFlags_t navStat
((posControl.flags.estAglStatus == EST_TRUSTED) && (posControl.actualState.agl.pos.z <= navConfig()->general.land_slowdown_minalt)) ) {
// Set motor to min. throttle and stop it when MOTOR_STOP feature is enabled
rcCommand[THROTTLE] = motorConfig()->minthrottle;
rcCommand[THROTTLE] = getThrottleIdleValue();
ENABLE_STATE(NAV_MOTOR_STOP_OR_IDLE);
// Stabilize ROLL axis on 0 degrees banking regardless of loiter radius and position

View file

@ -138,10 +138,10 @@ static void applyFixedWingLaunchIdleLogic(void)
pidResetTPAFilter();
// Throttle control logic
if (navConfig()->fw.launch_idle_throttle <= motorConfig()->minthrottle)
if (navConfig()->fw.launch_idle_throttle <= getThrottleIdleValue())
{
ENABLE_STATE(NAV_MOTOR_STOP_OR_IDLE); // If MOTOR_STOP is enabled mixer will keep motor stopped
rcCommand[THROTTLE] = motorConfig()->minthrottle; // If MOTOR_STOP is disabled, motors will spin at minthrottle
rcCommand[THROTTLE] = getThrottleIdleValue(); // If MOTOR_STOP is disabled, motors will spin at minthrottle
}
else
{
@ -155,7 +155,7 @@ static void applyFixedWingLaunchIdleLogic(void)
const float timeSinceMotorStartMs = MIN(millis() - timeThrottleRaisedMs, LAUNCH_MOTOR_IDLE_SPINUP_TIME);
rcCommand[THROTTLE] = scaleRangef(timeSinceMotorStartMs,
0.0f, LAUNCH_MOTOR_IDLE_SPINUP_TIME,
motorConfig()->minthrottle, navConfig()->fw.launch_idle_throttle);
getThrottleIdleValue(), navConfig()->fw.launch_idle_throttle);
}
}
}
@ -200,7 +200,7 @@ void applyFixedWingLaunchController(timeUs_t currentTimeUs)
// Increase throttle gradually over `launch_motor_spinup_time` milliseconds
if (navConfig()->fw.launch_motor_spinup_time > 0) {
const float timeSinceMotorStartMs = constrainf(timeElapsedSinceLaunchMs - navConfig()->fw.launch_motor_timer, 0.0f, navConfig()->fw.launch_motor_spinup_time);
const uint16_t minIdleThrottle = MAX(motorConfig()->minthrottle, navConfig()->fw.launch_idle_throttle);
const uint16_t minIdleThrottle = MAX(getThrottleIdleValue(), navConfig()->fw.launch_idle_throttle);
rcCommand[THROTTLE] = scaleRangef(timeSinceMotorStartMs,
0.0f, navConfig()->fw.launch_motor_spinup_time,
minIdleThrottle, navConfig()->fw.launch_throttle);

View file

@ -104,7 +104,7 @@ static void updateAltitudeVelocityController_MC(timeDelta_t deltaMicros)
static void updateAltitudeThrottleController_MC(timeDelta_t deltaMicros)
{
// Calculate min and max throttle boundaries (to compensate for integral windup)
const int16_t thrAdjustmentMin = (int16_t)motorConfig()->minthrottle - (int16_t)navConfig()->mc.hover_throttle;
const int16_t thrAdjustmentMin = (int16_t)getThrottleIdleValue() - (int16_t)navConfig()->mc.hover_throttle;
const int16_t thrAdjustmentMax = (int16_t)motorConfig()->maxthrottle - (int16_t)navConfig()->mc.hover_throttle;
posControl.rcAdjustment[THROTTLE] = navPidApply2(&posControl.pids.vel[Z], posControl.desiredState.vel.z, navGetCurrentActualPositionAndVelocity()->vel.z, US2S(deltaMicros), thrAdjustmentMin, thrAdjustmentMax, 0);
@ -116,7 +116,7 @@ static void updateAltitudeThrottleController_MC(timeDelta_t deltaMicros)
bool adjustMulticopterAltitudeFromRCInput(void)
{
if (posControl.flags.isTerrainFollowEnabled) {
const float altTarget = scaleRangef(rcCommand[THROTTLE], motorConfig()->minthrottle, motorConfig()->maxthrottle, 0, navConfig()->general.max_terrain_follow_altitude);
const float altTarget = scaleRangef(rcCommand[THROTTLE], getThrottleIdleValue(), motorConfig()->maxthrottle, 0, navConfig()->general.max_terrain_follow_altitude);
// In terrain follow mode we apply different logic for terrain control
if (posControl.flags.estAglStatus == EST_TRUSTED && altTarget > 10.0f) {
@ -144,7 +144,7 @@ bool adjustMulticopterAltitudeFromRCInput(void)
}
else {
// Scaling from minthrottle to altHoldThrottleRCZero
rcClimbRate = rcThrottleAdjustment * navConfig()->general.max_manual_climb_rate / (float)(altHoldThrottleRCZero - motorConfig()->minthrottle - rcControlsConfig()->alt_hold_deadband);
rcClimbRate = rcThrottleAdjustment * navConfig()->general.max_manual_climb_rate / (float)(altHoldThrottleRCZero - getThrottleIdleValue() - rcControlsConfig()->alt_hold_deadband);
}
updateClimbRateToAltitudeController(rcClimbRate, ROC_TO_ALT_NORMAL);
@ -181,7 +181,7 @@ void setupMulticopterAltitudeController(void)
// Make sure we are able to satisfy the deadband
altHoldThrottleRCZero = constrain(altHoldThrottleRCZero,
motorConfig()->minthrottle + rcControlsConfig()->alt_hold_deadband + 10,
getThrottleIdleValue() + rcControlsConfig()->alt_hold_deadband + 10,
motorConfig()->maxthrottle - rcControlsConfig()->alt_hold_deadband - 10);
// Force AH controller to initialize althold integral for pending takeoff on reset
@ -249,7 +249,7 @@ static void applyMulticopterAltitudeController(timeUs_t currentTimeUs)
}
// Update throttle controller
rcCommand[THROTTLE] = constrain((int16_t)navConfig()->mc.hover_throttle + posControl.rcAdjustment[THROTTLE], motorConfig()->minthrottle, motorConfig()->maxthrottle);
rcCommand[THROTTLE] = constrain((int16_t)navConfig()->mc.hover_throttle + posControl.rcAdjustment[THROTTLE], getThrottleIdleValue(), motorConfig()->maxthrottle);
// Save processed throttle for future use
rcCommandAdjustedThrottle = rcCommand[THROTTLE];
@ -721,12 +721,12 @@ static void applyMulticopterEmergencyLandingController(timeUs_t currentTimeUs)
}
// Update throttle controller
rcCommand[THROTTLE] = constrain((int16_t)navConfig()->mc.hover_throttle + posControl.rcAdjustment[THROTTLE], motorConfig()->minthrottle, motorConfig()->maxthrottle);
rcCommand[THROTTLE] = constrain((int16_t)navConfig()->mc.hover_throttle + posControl.rcAdjustment[THROTTLE], getThrottleIdleValue(), motorConfig()->maxthrottle);
}
else {
/* Sensors has gone haywire, attempt to land regardless */
if (failsafeConfig()->failsafe_procedure == FAILSAFE_PROCEDURE_DROP_IT) {
rcCommand[THROTTLE] = motorConfig()->minthrottle;
rcCommand[THROTTLE] = getThrottleIdleValue();
}
else {
rcCommand[THROTTLE] = failsafeConfig()->failsafe_throttle;

View file

@ -581,7 +581,7 @@ static bool estimationCalculateCorrection_Z(estimationContext_t * ctx)
return true;
}
else if (STATE(FIXED_WING) && (ctx->newFlags & EST_GPS_Z_VALID)) {
else if (STATE(FIXED_WING_LEGACY) && (ctx->newFlags & EST_GPS_Z_VALID)) {
// If baro is not available - use GPS Z for correction on a plane
// Reset current estimate to GPS altitude if estimate not valid
if (!(ctx->newFlags & EST_Z_VALID)) {

View file

@ -75,7 +75,7 @@ void mspOverrideInit(void)
mspRcChannels[i].expiresAt = nowMs + MAX_INVALID_RX_PULSE_TIME;
}
mspRcChannels[THROTTLE].raw = (feature(FEATURE_3D)) ? PWM_RANGE_MIDDLE : rxConfig()->rx_min_usec;
mspRcChannels[THROTTLE].raw = (feature(FEATURE_REVERSIBLE_MOTORS)) ? PWM_RANGE_MIDDLE : rxConfig()->rx_min_usec;
mspRcChannels[THROTTLE].data = mspRcChannels[THROTTLE].raw;
// Initialize ARM switch to OFF position when arming via switch is defined

View file

@ -195,6 +195,9 @@ bool serialRxInit(const rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig
case SERIALRX_SBUS:
enabled = sbusInit(rxConfig, rxRuntimeConfig);
break;
case SERIALRX_SBUS_FAST:
enabled = sbusInitFast(rxConfig, rxRuntimeConfig);
break;
#endif
#ifdef USE_SERIALRX_SUMD
case SERIALRX_SUMD:
@ -259,7 +262,7 @@ void rxInit(void)
rcChannels[i].expiresAt = nowMs + MAX_INVALID_RX_PULSE_TIME;
}
rcChannels[THROTTLE].raw = (feature(FEATURE_3D)) ? PWM_RANGE_MIDDLE : rxConfig()->rx_min_usec;
rcChannels[THROTTLE].raw = (feature(FEATURE_REVERSIBLE_MOTORS)) ? PWM_RANGE_MIDDLE : rxConfig()->rx_min_usec;
rcChannels[THROTTLE].data = rcChannels[THROTTLE].raw;
// Initialize ARM switch to OFF position when arming via switch is defined

View file

@ -79,6 +79,7 @@ typedef enum {
SERIALRX_JETIEXBUS = 8,
SERIALRX_CRSF = 9,
SERIALRX_FPORT = 10,
SERIALRX_SBUS_FAST = 11,
} rxSerialReceiverType_e;
#define MAX_SUPPORTED_RC_PPM_CHANNEL_COUNT 16

View file

@ -57,6 +57,7 @@
#define SBUS_FRAME_BEGIN_BYTE 0x0F
#define SBUS_BAUDRATE 100000
#define SBUS_BAUDRATE_FAST 200000
#if !defined(SBUS_PORT_OPTIONS)
#define SBUS_PORT_OPTIONS (SERIAL_STOPBITS_2 | SERIAL_PARITY_EVEN)
@ -191,7 +192,7 @@ static uint8_t sbusFrameStatus(rxRuntimeConfig_t *rxRuntimeConfig)
return retValue;
}
bool sbusInit(const rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig)
static bool sbusInitEx(const rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig, uint32_t sbusBaudRate)
{
static uint16_t sbusChannelData[SBUS_MAX_CHANNEL];
static sbusFrameData_t sbusFrameData;
@ -221,7 +222,7 @@ bool sbusInit(const rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig)
FUNCTION_RX_SERIAL,
sbusDataReceive,
&sbusFrameData,
SBUS_BAUDRATE,
sbusBaudRate,
portShared ? MODE_RXTX : MODE_RX,
SBUS_PORT_OPTIONS | (rxConfig->serialrx_inverted ? 0 : SERIAL_INVERTED) | (rxConfig->halfDuplex ? SERIAL_BIDIR : 0)
);
@ -234,4 +235,14 @@ bool sbusInit(const rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig)
return sBusPort != NULL;
}
bool sbusInit(const rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig)
{
return sbusInitEx(rxConfig, rxRuntimeConfig, SBUS_BAUDRATE);
}
bool sbusInitFast(const rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig)
{
return sbusInitEx(rxConfig, rxRuntimeConfig, SBUS_BAUDRATE_FAST);
}
#endif

View file

@ -20,3 +20,4 @@
#define SBUS_DEFAULT_INTERFRAME_DELAY_US 3000 // According to FrSky interframe is 6.67ms, we go smaller just in case
bool sbusInit(const rxConfig_t *initialRxConfig, rxRuntimeConfig_t *rxRuntimeConfig);
bool sbusInitFast(const rxConfig_t *initialRxConfig, rxRuntimeConfig_t *rxRuntimeConfig);

View file

@ -78,11 +78,11 @@ STATIC_FASTRAM filter_t accFilter[XYZ_AXIS_COUNT];
STATIC_FASTRAM filterApplyFnPtr accSoftLpfFilterApplyFn;
STATIC_FASTRAM void *accSoftLpfFilter[XYZ_AXIS_COUNT];
STATIC_FASTRAM pt1Filter_t accVibeFloorFilter[XYZ_AXIS_COUNT];
STATIC_FASTRAM pt1Filter_t accVibeFilter[XYZ_AXIS_COUNT];
static EXTENDED_FASTRAM pt1Filter_t accVibeFloorFilter[XYZ_AXIS_COUNT];
static EXTENDED_FASTRAM pt1Filter_t accVibeFilter[XYZ_AXIS_COUNT];
STATIC_FASTRAM filterApplyFnPtr accNotchFilterApplyFn;
STATIC_FASTRAM void *accNotchFilter[XYZ_AXIS_COUNT];
static EXTENDED_FASTRAM filterApplyFnPtr accNotchFilterApplyFn;
static EXTENDED_FASTRAM void *accNotchFilter[XYZ_AXIS_COUNT];
PG_REGISTER_WITH_RESET_FN(accelerometerConfig_t, accelerometerConfig, PG_ACCELEROMETER_CONFIG, 3);

View file

@ -112,7 +112,7 @@ static bool escSensorDecodeFrame(void)
escSensorData[escSensorMotor].temperature = telemetryBuffer[0];
escSensorData[escSensorMotor].voltage = ((uint16_t)telemetryBuffer[1]) << 8 | telemetryBuffer[2];
escSensorData[escSensorMotor].current = ((uint16_t)telemetryBuffer[3]) << 8 | telemetryBuffer[4];
escSensorData[escSensorMotor].rpm = ((uint16_t)telemetryBuffer[7]) << 8 | telemetryBuffer[8];
escSensorData[escSensorMotor].rpm = computeRpm(((uint16_t)telemetryBuffer[7]) << 8 | telemetryBuffer[8]);
escSensorDataNeedsUpdate = true;
if (escSensorMotor < 4) {
@ -169,7 +169,7 @@ escSensorData_t * escSensorGetData(void)
if (usedEscSensorCount) {
escSensorDataCombined.current = (uint32_t)escSensorDataCombined.current * getMotorCount() / usedEscSensorCount + escSensorConfig()->currentOffset;
escSensorDataCombined.voltage = (uint32_t)escSensorDataCombined.voltage / usedEscSensorCount;
escSensorDataCombined.rpm = computeRpm((float)escSensorDataCombined.rpm / usedEscSensorCount);
escSensorDataCombined.rpm = (float)escSensorDataCombined.rpm / usedEscSensorCount;
}
else {
escSensorDataCombined.dataAge = ESC_DATA_INVALID;

View file

@ -29,7 +29,7 @@ typedef struct {
int8_t temperature;
int16_t voltage;
int32_t current;
int16_t rpm;
uint32_t rpm;
} escSensorData_t;
typedef struct escSensorConfig_s {

View file

@ -57,7 +57,6 @@ void targetConfiguration(void)
if (hardwareMotorType == MOTOR_BRUSHED) {
motorConfigMutable()->motorPwmProtocol = PWM_TYPE_BRUSHED;
motorConfigMutable()->motorPwmRate = BRUSHED_MOTORS_PWM_RATE;
motorConfigMutable()->minthrottle = 1000;
}
pidProfileMutable()->bank_mc.pid[ROLL].P = 36;

View file

@ -63,7 +63,6 @@ void targetConfiguration(void)
if (hardwareMotorType == MOTOR_BRUSHED) {
motorConfigMutable()->motorPwmProtocol = PWM_TYPE_BRUSHED;
motorConfigMutable()->motorPwmRate = BRUSHED_MOTORS_PWM_RATE;
motorConfigMutable()->minthrottle = 1000;
}
if (hardwareRevision == AFF4_REV_1) {
rxConfigMutable()->serialrx_provider = SERIALRX_SPEKTRUM2048;

View file

@ -64,7 +64,6 @@ void targetConfiguration(void)
if (hardwareMotorType == MOTOR_BRUSHED) {
motorConfigMutable()->motorPwmRate = BRUSHED_MOTORS_PWM_RATE;
motorConfigMutable()->minthrottle = 1000;
}
if (hardwareRevision == AFF7_REV_1) {

View file

@ -37,6 +37,5 @@ void targetConfiguration(void)
serialConfigMutable()->portConfigs[findSerialPortIndexByIdentifier(TELEMETRY_UART)].functionMask = FUNCTION_TELEMETRY_SMARTPORT;
motorConfigMutable()->motorPwmProtocol = PWM_TYPE_MULTISHOT;
motorConfigMutable()->motorPwmRate = 4000;
motorConfigMutable()->minthrottle = 1075;
motorConfigMutable()->maxthrottle = 1950;
}

View file

@ -37,6 +37,5 @@ void targetConfiguration(void)
serialConfigMutable()->portConfigs[findSerialPortIndexByIdentifier(TELEMETRY_UART)].functionMask = FUNCTION_TELEMETRY_SMARTPORT;
motorConfigMutable()->motorPwmProtocol = PWM_TYPE_MULTISHOT;
motorConfigMutable()->motorPwmRate = 4000;
motorConfigMutable()->minthrottle = 1075;
motorConfigMutable()->maxthrottle = 1950;
}

View file

@ -35,6 +35,9 @@
#define MPU6000_CS_PIN PA4
#define MPU6000_SPI_BUS BUS_SPI1
#define ICM20689_CS_PIN PA4
#define ICM20689_SPI_BUS BUS_SPI1
#define USE_ACC
#define USE_ACC_MPU6000
@ -44,6 +47,12 @@
#define USE_GYRO_MPU6000
#define GYRO_MPU6000_ALIGN CW90_DEG
#define USE_ACC_ICM20689
#define ACC_ICM20689_ALIGN CW90_DEG
#define USE_GYRO_ICM20689
#define GYRO_ICM20689_ALIGN CW90_DEG
#define USE_MAG
#define MAG_I2C_BUS BUS_I2C2
#define MAG_HMC5883_ALIGN CW90_DEG

View file

@ -3,6 +3,7 @@ FEATURES += SDCARD VCP MSC
TARGET_SRC = \
drivers/accgyro/accgyro_mpu6000.c \
drivers/accgyro/accgyro_icm20689.c \
drivers/barometer/barometer_ms56xx.c \
drivers/compass/compass_hmc5883l.c \
drivers/compass/compass_qmc5883l.c \

View file

@ -82,7 +82,6 @@ void targetConfiguration(void)
blackboxConfigMutable()->rate_num = 1;
blackboxConfigMutable()->rate_denom = 4;
motorConfigMutable()->minthrottle = 1015;
motorConfigMutable()->maxthrottle = 2000;
motorConfigMutable()->mincommand = 980;
motorConfigMutable()->motorPwmRate = 2000;

View file

@ -24,10 +24,10 @@
const timerHardware_t timerHardware[] = {
DEF_TIM(TIM8, CH4, PC9, TIM_USE_PPM, 0, 0 ), // PPM IN
DEF_TIM(TIM2, CH4, PA3, TIM_USE_MC_MOTOR | TIM_USE_FW_MOTOR, 0, 1 ), // S1_OUT - DMA1_ST6_CH3
DEF_TIM(TIM3, CH3, PB0, TIM_USE_MC_MOTOR | TIM_USE_FW_SERVO, 0, 0 ), // S2_OUT - DMA1_ST7_CH5
DEF_TIM(TIM1, CH3N, PB1, TIM_USE_MC_MOTOR | TIM_USE_FW_SERVO, 0, 0 ), // S3_OUT - DMA2_ST6_CH0
DEF_TIM(TIM2, CH3, PA2, TIM_USE_MC_MOTOR | TIM_USE_FW_MOTOR, 0, 0 ), // S4_OUT - DMA1_ST1_CH3
DEF_TIM(TIM2, CH4, PA3, TIM_USE_MC_MOTOR | TIM_USE_FW_MOTOR, 0, 1 ), // S1_OUT - D(1, 6, 3)
DEF_TIM(TIM3, CH3, PB0, TIM_USE_MC_MOTOR | TIM_USE_FW_SERVO, 0, 0 ), // S2_OUT - D(1, 7, 5)
DEF_TIM(TIM3, CH4, PB1, TIM_USE_MC_MOTOR | TIM_USE_FW_SERVO, 0, 0 ), // S3_OUT - D(1, 2, 5)
DEF_TIM(TIM2, CH3, PA2, TIM_USE_MC_MOTOR | TIM_USE_FW_MOTOR, 0, 0 ), // S4_OUT - D(1, 1, 3)
DEF_TIM(TIM2, CH3, PB10, TIM_USE_ANY, 0, 0),
DEF_TIM(TIM2, CH4, PB11, TIM_USE_ANY, 0, 0),
DEF_TIM(TIM5, CH1, PA0, TIM_USE_LED, 0, 0 ), // LED_STRIP - DMA1_ST2_CH6

View file

@ -38,7 +38,7 @@ const timerHardware_t timerHardware[] = {
DEF_TIM(TIM8, CH4, PC9, TIM_USE_MC_MOTOR | TIM_USE_FW_SERVO | TIM_USE_MC_SERVO, 0, 0), // M5 , DMA2_ST7
DEF_TIM(TIM5, CH4, PA3, TIM_USE_MC_MOTOR | TIM_USE_FW_SERVO | TIM_USE_MC_SERVO, 0, 0), // M6 , DMA1_ST1
DEF_TIM(TIM4, CH1, PD12, TIM_USE_LED, 0, 0), // LED_TRIP, DMA1_ST0
DEF_TIM(TIM4, CH1, PD12, TIM_USE_LED, 0, 0), // LED_STRIP, DMA1_ST0
};
const int timerHardwareCount = sizeof(timerHardware) / sizeof(timerHardware[0]);

View file

@ -172,6 +172,9 @@
#define SERIALRX_UART SERIAL_PORT_USART6
#define SERIALRX_PROVIDER SERIALRX_SBUS
#define USE_LED_STRIP
#define WS2811_PIN PD12 //TIM4_CH1
#define USE_SERIAL_4WAY_BLHELI_INTERFACE
#define TARGET_IO_PORTA 0xffff

View file

@ -27,7 +27,7 @@
const timerHardware_t timerHardware[] = {
DEF_TIM(TIM11, CH1, PB9, TIM_USE_PPM, 0, 0 ), // PPM IN
DEF_TIM(TIM1, CH2, PA9, TIM_USE_MC_MOTOR, 0, 0 ), // S4_OUT D(2, 6, 0)
DEF_TIM(TIM1, CH2, PA9, TIM_USE_MC_MOTOR, 0, 1 ), // S4_OUT D(2, 2, 6)
DEF_TIM(TIM1, CH1, PA8, TIM_USE_MC_MOTOR, 0, 1 ), // S3_OUT D(2, 1, 6)
DEF_TIM(TIM8, CH4, PC9, TIM_USE_MC_MOTOR, 0, 0 ), // S2_OUT D(2, 7, 7)
DEF_TIM(TIM8, CH3, PC8, TIM_USE_MC_MOTOR, 0, 0 ), // S1_OUT D(2, 4, 7)

View file

@ -30,7 +30,7 @@ const timerHardware_t timerHardware[] = {
DEF_TIM(TIM8, CH3, PC8, TIM_USE_MC_MOTOR, 0, 0 ), // S1_OUT D(2, 4, 7)
DEF_TIM(TIM8, CH4, PC9, TIM_USE_MC_MOTOR, 0, 0 ), // S2_OUT D(2, 7, 7)
DEF_TIM(TIM1, CH1, PA8, TIM_USE_MC_MOTOR, 0, 1 ), // S3_OUT D(2, 1, 6)
DEF_TIM(TIM1, CH2, PA9, TIM_USE_MC_MOTOR, 0, 0 ), // S4_OUT D(2, 6, 0)
DEF_TIM(TIM1, CH2, PA9, TIM_USE_MC_MOTOR, 0, 1 ), // S4_OUT D(2, 2, 6)
DEF_TIM(TIM2, CH2, PB3, TIM_USE_LED, 0, 0 ), // LED_STRIP D(1, 6, 3)
};

View file

@ -46,7 +46,7 @@
#define USE_ACC
#define USE_ACC_MPU6000
#define ACC_MPU6500_ALIGN CW180_DEG
#define ACC_MPU6000_ALIGN CW180_DEG
// *************** Baro **************************
#define USE_I2C

View file

@ -24,7 +24,7 @@
#include "drivers/bus.h"
const timerHardware_t timerHardware[] = {
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4PRO_LEDSTRIPM5) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)
DEF_TIM(TIM10, CH1, PB8, TIM_USE_PPM, 0, 0), // PPM
DEF_TIM(TIM4, CH4, PB9, TIM_USE_ANY, 0, 0), // S2_IN
#else
@ -42,7 +42,7 @@ const timerHardware_t timerHardware[] = {
DEF_TIM(TIM2, CH3, PA2, TIM_USE_MC_MOTOR | TIM_USE_FW_SERVO, 0, 0), // S4_OUT D1_ST1
// { TIM9, IO_TAG(PA3), TIM_Channel_2, 1, IOCFG_AF_PP_PD, GPIO_AF_TIM9, TIM_USE_MC_MOTOR | TIM_USE_FW_SERVO }, // MOTOR_3
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)
#if (defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)) && !(defined(OMNIBUSF4PRO_LEDSTRIPM5) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS))
DEF_TIM(TIM5, CH2, PA1, TIM_USE_MC_MOTOR | TIM_USE_MC_SERVO | TIM_USE_FW_SERVO, 0, 0), // S5_OUT
DEF_TIM(TIM1, CH1, PA8, TIM_USE_MC_MOTOR | TIM_USE_MC_SERVO | TIM_USE_FW_SERVO, 0, 0), // S6_OUT
#elif defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
@ -59,7 +59,7 @@ const timerHardware_t timerHardware[] = {
DEF_TIM(TIM1, CH1, PA8, TIM_USE_MC_MOTOR | TIM_USE_MC_SERVO | TIM_USE_FW_SERVO, 0, 0), // S6_OUT
#endif
#if (defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS))
#if (defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)) && !defined(OMNIBUSF4PRO_LEDSTRIPM5)
DEF_TIM(TIM4, CH1, PB6, TIM_USE_LED, 0, 0), // LED strip for F4 V2 / F4-Pro-0X and later (RCD_CS for F4)
#endif
};

View file

@ -17,12 +17,18 @@
#pragma once
//Same target as OMNIBUSF4PRO with LED strip in M5
#ifdef OMNIBUSF4PRO_LEDSTRIPM5
#define OMNIBUSF4PRO
#endif
//Same target as OMNIBUSF4V3 with softserial in M5 and M6
#if defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
#define OMNIBUSF4V3
#endif
#ifdef OMNIBUSF4PRO
#define TARGET_BOARD_IDENTIFIER "OBSD"
#elif defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
#elif defined(OMNIBUSF4V3)
#define TARGET_BOARD_IDENTIFIER "OB43"
#elif defined(DYSF4PRO)
#define TARGET_BOARD_IDENTIFIER "DYS4"
@ -32,7 +38,7 @@
#define TARGET_BOARD_IDENTIFIER "OBF4"
#endif
#if defined(DYSF4PRO)
#if defined(DYSF4PRO) || defined(DYSF4PROV2)
#define USBD_PRODUCT_STRING "DysF4Pro"
#else
#define USBD_PRODUCT_STRING "Omnibus F4"
@ -69,8 +75,7 @@
#define MPU6000_CS_PIN PA4
#define MPU6000_SPI_BUS BUS_SPI1
// Long sentence, OMNIBUSF4 always defined
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4PRO_LEDSTRIPM5) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)
#define USE_GYRO_MPU6000
#define GYRO_MPU6000_ALIGN CW270_DEG
@ -85,7 +90,7 @@
#endif
// Support for OMNIBUS F4 PRO CORNER - it has ICM20608 instead of MPU6000
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4PRO_LEDSTRIPM5) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)
#define MPU6500_CS_PIN MPU6000_CS_PIN
#define MPU6500_SPI_BUS MPU6000_SPI_BUS
@ -111,7 +116,7 @@
#define USE_BARO
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4PRO_LEDSTRIPM5) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)
#define USE_BARO_BMP280
#define BMP280_SPI_BUS BUS_SPI3
#define BMP280_CS_PIN PB3 // v1
@ -141,7 +146,7 @@
#define UART1_RX_PIN PA10
#define UART1_TX_PIN PA9
#define UART1_AHB1_PERIPHERALS RCC_AHB1Periph_DMA2
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4PRO_LEDSTRIPM5)
#if defined(OMNIBUSF4PRO)
#define INVERTER_PIN_UART1_RX PC0 // PC0 has never been used as inverter control on genuine OMNIBUS F4 variants, but leave it as is since some clones actually implement it.
#endif
@ -152,12 +157,12 @@
#define USE_UART6
#define UART6_RX_PIN PC7
#define UART6_TX_PIN PC6
#if defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
#if defined(OMNIBUSF4V3)
#define INVERTER_PIN_UART6_RX PC8
#define INVERTER_PIN_UART6_TX PC9
#endif
#if defined(OMNIBUSF4V3)
#if defined(OMNIBUSF4V3) && !(defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS))
#define USE_SOFTSERIAL1
#define SOFTSERIAL_1_RX_PIN PC6 // shared with UART6 TX
#define SOFTSERIAL_1_TX_PIN PC6 // shared with UART6 TX
@ -201,7 +206,7 @@
#define USE_SPI_DEVICE_1
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4PRO_LEDSTRIPM5) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)
#define USE_SPI_DEVICE_2
#define SPI2_NSS_PIN PB12
#define SPI2_SCK_PIN PB13
@ -210,7 +215,7 @@
#endif
#define USE_SPI_DEVICE_3
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4PRO_LEDSTRIPM5) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)
#define SPI3_NSS_PIN PA15
#else
#define SPI3_NSS_PIN PB3
@ -224,7 +229,7 @@
#define MAX7456_SPI_BUS BUS_SPI3
#define MAX7456_CS_PIN PA15
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4PRO_LEDSTRIPM5) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)
#define ENABLE_BLACKBOX_LOGGING_ON_SDCARD_BY_DEFAULT
#define USE_SDCARD
#define USE_SDCARD_SPI
@ -259,7 +264,7 @@
#define SENSORS_SET (SENSOR_ACC|SENSOR_MAG|SENSOR_BARO)
#define USE_LED_STRIP
#if (defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS))
#if (defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)) && !defined(OMNIBUSF4PRO_LEDSTRIPM5)
#define WS2811_PIN PB6
#else
#define WS2811_PIN PA1

View file

@ -28,12 +28,13 @@ const timerHardware_t timerHardware[] = {
DEF_TIM(TIM8, CH1, PC6, TIM_USE_MC_MOTOR | TIM_USE_FW_MOTOR, 0, 0), // S1 UP(1,2)
DEF_TIM(TIM8, CH2, PC7, TIM_USE_MC_MOTOR | TIM_USE_FW_MOTOR, 0, 1), // S2 UP(2,1)
DEF_TIM(TIM8, CH3, PC8, TIM_USE_MC_MOTOR | TIM_USE_FW_SERVO, 0, 1), // S3 UP(2,1)
DEF_TIM(TIM8, CH4, PC9, TIM_USE_MC_MOTOR | TIM_USE_FW_SERVO, 0, 0), // S4 UP(2,1)
DEF_TIM(TIM3, CH3, PC8, TIM_USE_MC_MOTOR | TIM_USE_FW_SERVO, 0, 0), // S3 UP(2,1)
DEF_TIM(TIM3, CH4, PC9, TIM_USE_MC_MOTOR | TIM_USE_FW_SERVO, 0, 0), // S4 UP(2,1)
DEF_TIM(TIM2, CH1, PA15, TIM_USE_MC_MOTOR | TIM_USE_MC_SERVO | TIM_USE_FW_SERVO, 0, 0), // S5 UP(1,7)
DEF_TIM(TIM1, CH1, PA8, TIM_USE_MC_MOTOR | TIM_USE_MC_SERVO | TIM_USE_FW_SERVO, 0, 0), // S6 UP(2,5)
DEF_TIM(TIM4, CH3, PB8, TIM_USE_MC_MOTOR | TIM_USE_MC_SERVO | TIM_USE_FW_SERVO, 0, 0), // S7 D(1,7)!S5 UP(2,6)
DEF_TIM(TIM4, CH1, PB6, TIM_USE_LED, 0, 0), // LED D(1,0) UP(2,6)
};

View file

@ -150,8 +150,8 @@
#define USE_SERIAL_4WAY_BLHELI_INTERFACE
// Number of available PWM outputs
#define MAX_PWM_OUTPUT_PORTS 6
#define TARGET_MOTOR_COUNT 6
#define MAX_PWM_OUTPUT_PORTS 7
#define TARGET_MOTOR_COUNT 7
#define TARGET_IO_PORTA 0xffff
#define TARGET_IO_PORTB 0xffff

View file

@ -107,6 +107,7 @@
#define USE_TELEMETRY_SIM
#define USE_FRSKYOSD
#define USE_DJI_HD_OSD
#define NAV_NON_VOLATILE_WAYPOINT_CLI

View file

@ -185,7 +185,7 @@
#if !defined(MAG3110_I2C_BUS)
#define MAG3110_I2C_BUS MAG_I2C_BUS
#endif
BUSDEV_REGISTER_I2C(busdev_mag3110, DEVHW_MAG3110, MAG3110_I2C_BUS, 0x0C, NONE, DEVFLAGS_NONE);
BUSDEV_REGISTER_I2C(busdev_mag3110, DEVHW_MAG3110, MAG3110_I2C_BUS, 0x0E, NONE, DEVFLAGS_NONE);
#endif
#if defined(USE_MAG_LIS3MDL)

View file

@ -490,7 +490,7 @@ void initCrsfTelemetry(void)
}
#endif
#if defined(USE_BARO) || defined(USE_GPS)
if (sensors(SENSOR_BARO) || (STATE(FIXED_WING) && feature(FEATURE_GPS))) {
if (sensors(SENSOR_BARO) || (STATE(FIXED_WING_LEGACY) && feature(FEATURE_GPS))) {
crsfSchedule[index++] = BV(CRSF_FRAME_VARIO_SENSOR_INDEX);
}
#endif

View file

@ -128,9 +128,9 @@ static ibusAddress_t getAddress(uint8_t ibusPacket[static IBUS_MIN_LEN]) {
return (ibusPacket[1] & 0x0F);
}
// MANUAL, ACRO, ANGLE, HRZN, ALTHOLD, POSHOLD, RTH, WP, LAUNCH, FAILSAFE
static uint8_t flightModeToIBusTelemetryMode1[FLM_COUNT] = { 0, 1, 3, 2, 5, 6, 7, 4, 8, 9 };
static uint8_t flightModeToIBusTelemetryMode2[FLM_COUNT] = { 5, 1, 0, 7, 2, 8, 6, 3, 4, 9 };
// MANUAL, ACRO, AIR, ANGLE, HRZN, ALTHOLD, POSHOLD, RTH, WP, CRUISE, LAUNCH, FAILSAFE
static uint8_t flightModeToIBusTelemetryMode1[FLM_COUNT] = { 0, 1, 1, 3, 2, 5, 6, 7, 4, 4, 8, 9 };
static uint8_t flightModeToIBusTelemetryMode2[FLM_COUNT] = { 5, 1, 1, 0, 7, 2, 8, 6, 3, 3, 4, 9 };
static uint8_t dispatchMeasurementRequest(ibusAddress_t address) {
#if defined(USE_GPS)
uint8_t fix = 0;

View file

@ -467,7 +467,7 @@ void mavlinkSendHUDAndHeartbeat(void)
flightModeForTelemetry_e flm = getFlightModeForTelemetry();
uint8_t mavCustomMode;
if (STATE(FIXED_WING)) {
if (STATE(FIXED_WING_LEGACY)) {
mavCustomMode = inavToArduPlaneMap[flm];
}
else {

View file

@ -132,7 +132,7 @@ static uint8_t simModuleState = SIM_MODULE_NOT_DETECTED;
static int simRssi;
static uint8_t accEvent = ACC_EVENT_NONE;
static char* accEventDescriptions[] = { "", "HIT! ", "DROP ", "HIT " };
static char* modeDescriptions[] = { "MAN", "ACR", "ANG", "HOR", "ALH", "POS", "RTH", "WP", "LAU", "FS" };
static char* modeDescriptions[] = { "MAN", "ACR", "AIR", "ANG", "HOR", "ALH", "POS", "RTH", "WP", "CRS", "LAU", "FS" };
static const char gpsFixIndicators[] = { '!', '*', ' ' };

View file

@ -214,7 +214,7 @@ void telemetryProcess(timeUs_t currentTimeUs)
handleJetiExBusTelemetry();
#endif
#if defined(USE_TELEMETRY_IBUS)
#if defined(USE_SERIALRX_IBUS) && defined(USE_TELEMETRY_IBUS)
handleIbusTelemetry();
#endif

View file

@ -281,10 +281,10 @@ bool feature(uint32_t mask)
return false;
}
throttleStatus_e calculateThrottleStatus(rxConfig_t *rxConfig, uint16_t deadband3d_throttle)
throttleStatus_e calculateThrottleStatus(rxConfig_t *rxConfig, uint16_t mid_throttle_deadband)
{
UNUSED(*rxConfig);
UNUSED(deadband3d_throttle);
UNUSED(mid_throttle_deadband);
return THROTTLE_HIGH;
}

View file

@ -420,10 +420,10 @@ uint32_t millis(void)
return sysTickUptime;
}
throttleStatus_e calculateThrottleStatus(rxConfig_t *rxConfig, uint16_t deadband3d_throttle)
throttleStatus_e calculateThrottleStatus(rxConfig_t *rxConfig, uint16_t mid_throttle_deadband)
{
UNUSED(rxConfig);
UNUSED(deadband3d_throttle);
UNUSED(mid_throttle_deadband);
return throttleStatus;
}