Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/OSD.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ Here are the OSD Elements provided by INAV.
| 164 | OSD_H_DIST_TO_FENCE | 8.0.0 | |
| 165 | OSD_V_DIST_TO_FENCE | 8.0.0 | |
| 166 | OSD_NAV_FW_ALT_CONTROL_RESPONSE | 8.0.0 | |
| 167 | OSD_NAV_MIN_GROUND_SPEED | 9.0.0 | |

# Pilot Logos

Expand Down
6 changes: 6 additions & 0 deletions docs/Programming Framework.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ IPF can be edited using INAV Configurator user interface, or via CLI. To use COn
| 53 | Disable GPS Sensor Fix | Disables the GNSS sensor fix. For testing GNSS failure. |
| 54 | Mag calibration | Trigger a magnetometer calibration. |
| 55 | Set Gimbal Sensitivity | Scales `Operand A` from [`-16` : `15`]
| 56 | Override Minimum Ground Speed | When active, sets the minimum ground speed to the value specified in `Operand A` [m/s]. Minimum allowed value is set in `nav_min_ground_speed`. Maximum value is `150` |

### Operands

Expand Down Expand Up @@ -164,6 +165,11 @@ IPF can be edited using INAV Configurator user interface, or via CLI. To use COn
| 41 | FW Land Sate | Integer `1` - `5`, indicates the status of the FW landing, 0 Idle, 1 Downwind, 2 Base Leg, 3 Final Approach, 4 Glide, 5 Flare |
| 42 | Current battery profile | The active battery profile. Integer `[1..MAX_PROFILE_COUNT]` |
| 43 | Flown Loiter Radius [m] | The actual loiter radius flown by a fixed wing during hold modes, in `meters` |
| 44 | Downlink Link Quality | |
| 45 | Uplink RSSI [dBm] | |
| 46 | Minimum Ground Speed [m/s] | The current minimum ground speed allowed in navigation flight modes |
| 47 | Horizontal Wind Speed [cm/s] | Estimated wind speed. If the wind estimator is unavailble or the wind estimation is invalid, -1 is returned |
| 48 | Wind Direction [deg] | Estimated wind direction. If the wind estimator is unavailble or the wind estimation is invalid, -1 is returned |

#### FLIGHT_MODE

Expand Down
64 changes: 33 additions & 31 deletions src/main/common/maths.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,49 +35,51 @@

#define RAD (M_PIf / 180.0f)

#define DEGREES_TO_CENTIDEGREES(angle) ((angle) * 100)
#define CENTIDEGREES_TO_DEGREES(angle) ((angle) * 0.01f)
#define DEGREES_TO_CENTIDEGREES(angle) ((angle) * 100)
#define CENTIDEGREES_TO_DEGREES(angle) ((angle) * 0.01f)

#define CENTIDEGREES_TO_DECIDEGREES(angle) ((angle) / 10.0f)
#define DECIDEGREES_TO_CENTIDEGREES(angle) ((angle) * 10)
#define CENTIDEGREES_TO_DECIDEGREES(angle) ((angle) / 10.0f)
#define DECIDEGREES_TO_CENTIDEGREES(angle) ((angle) * 10)

#define DEGREES_TO_DECIDEGREES(angle) ((angle) * 10)
#define DECIDEGREES_TO_DEGREES(angle) ((angle) / 10.0f)
#define DEGREES_TO_DECIDEGREES(angle) ((angle) * 10)
#define DECIDEGREES_TO_DEGREES(angle) ((angle) / 10.0f)

#define DEGREES_PER_DEKADEGREE 10
#define DEGREES_TO_DEKADEGREES(angle) ((angle) / DEGREES_PER_DEKADEGREE)
#define DEKADEGREES_TO_DEGREES(angle) ((angle) * DEGREES_PER_DEKADEGREE)
#define DEGREES_PER_DEKADEGREE 10
#define DEGREES_TO_DEKADEGREES(angle) ((angle) / DEGREES_PER_DEKADEGREE)
#define DEKADEGREES_TO_DEGREES(angle) ((angle) * DEGREES_PER_DEKADEGREE)

#define DEGREES_TO_RADIANS(angle) ((angle) * RAD)
#define RADIANS_TO_DEGREES(angle) ((angle) / RAD)
#define DECIDEGREES_TO_RADIANS(angle) (((angle) / 10.0f) * RAD)
#define RADIANS_TO_DECIDEGREES(angle) (((angle) * 10.0f) / RAD)
#define DEGREES_TO_RADIANS(angle) ((angle) * RAD)
#define RADIANS_TO_DEGREES(angle) ((angle) / RAD)
#define DECIDEGREES_TO_RADIANS(angle) (((angle) / 10.0f) * RAD)
#define RADIANS_TO_DECIDEGREES(angle) (((angle) * 10.0f) / RAD)

#define RADIANS_TO_CENTIDEGREES(angle) (((angle) * 100.0f) / RAD)
#define CENTIDEGREES_TO_RADIANS(angle) (((angle) * 0.01f) * RAD)
#define RADIANS_TO_CENTIDEGREES(angle) (((angle) * 100.0f) / RAD)
#define CENTIDEGREES_TO_RADIANS(angle) (((angle) * 0.01f) * RAD)

#define MILLIMETERS_TO_CENTIMETERS(mm) (mm / 10.0f)
#define MILLIMETERS_TO_CENTIMETERS(mm) (mm / 10.0f)

#define CENTIMETERS_TO_CENTIFEET(cm) (cm / 0.3048f)
#define CENTIMETERS_TO_FEET(cm) (cm / 30.48f)
#define CENTIMETERS_TO_METERS(cm) (cm * 0.01f)
#define CENTIMETERS_TO_CENTIFEET(cm) (cm / 0.3048f)
#define CENTIMETERS_TO_FEET(cm) (cm / 30.48f)
#define CENTIMETERS_TO_METERS(cm) (cm * 0.01f)

#define METERS_TO_CENTIMETERS(m) (m * 100)
#define METERS_TO_KILOMETERS(m) (m / 1000.0f)
#define METERS_TO_MILES(m) (m / 1609.344f)
#define METERS_TO_NAUTICALMILES(m) (m / 1852.00f)
#define METERS_TO_CENTIMETERS(m) (m * 100)
#define METERS_TO_KILOMETERS(m) (m / 1000.0f)
#define METERS_TO_MILES(m) (m / 1609.344f)
#define METERS_TO_NAUTICALMILES(m) (m / 1852.00f)

#define MWH_TO_WH(mWh) (mWh / 1000.0f)
#define MWH_TO_WH(mWh) (mWh / 1000.0f)

#define CMSEC_TO_CENTIMPH(cms) (cms * 2.2369363f)
#define CMSEC_TO_CENTIKPH(cms) (cms * 3.6f)
#define CMSEC_TO_CENTIKNOTS(cms) (cms * 1.943845f)
#define CMSEC_TO_CENTIMPH(cms) (cms * 2.2369363f)
#define CMSEC_TO_CENTIKPH(cms) (cms * 3.6f)
#define CMSEC_TO_CENTIKNOTS(cms) (cms * 1.943845f)

#define CMSEC_TO_MPH(cms) (CMSEC_TO_CENTIMPH(cms) / 100.0f)
#define CMSEC_TO_KPH(cms) (CMSEC_TO_CENTIKPH(cms) / 100.0f)
#define CMSEC_TO_KNOTS(cms) (CMSEC_TO_CENTIKNOTS(cms) / 100.0f)
#define CMSEC_TO_MPH(cms) (CMSEC_TO_CENTIMPH(cms) / 100.0f)
#define CMSEC_TO_KPH(cms) (CMSEC_TO_CENTIKPH(cms) / 100.0f)
#define CMSEC_TO_KNOTS(cms) (CMSEC_TO_CENTIKNOTS(cms) / 100.0f)

#define C_TO_KELVIN(temp) (temp + 273.15f)
#define KMH_TO_MS(kmh) (kmh / 3.6f)

#define C_TO_KELVIN(temp) (temp + 273.15f)

// Standard Sea Level values
// Ref:https://en.wikipedia.org/wiki/Standard_sea_level
Expand Down
154 changes: 115 additions & 39 deletions src/main/io/osd.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,34 +391,109 @@ static int32_t osdConvertVelocityToUnit(int32_t vel)
* @param _3D is a 3D velocity
* @param _max is a maximum velocity
*/
void osdFormatVelocityStr(char* buff, int32_t vel, bool _3D, bool _max)
void osdFormatVelocityStr(char* buff, int32_t vel, osd_SpeedTypes_e speedType, bool _max)
{
switch ((osd_unit_e)osdConfig()->units) {
case OSD_UNIT_UK:
FALLTHROUGH;
case OSD_UNIT_METRIC_MPH:
FALLTHROUGH;
case OSD_UNIT_IMPERIAL:
if (_max) {
tfp_sprintf(buff, "%c%3d%c", SYM_MAX, (int)osdConvertVelocityToUnit(vel), (_3D ? SYM_3D_MPH : SYM_MPH));
} else {
tfp_sprintf(buff, "%3d%c", (int)osdConvertVelocityToUnit(vel), (_3D ? SYM_3D_MPH : SYM_MPH));
}
break;
case OSD_UNIT_METRIC:
if (_max) {
tfp_sprintf(buff, "%c%3d%c", SYM_MAX, (int)osdConvertVelocityToUnit(vel), (_3D ? SYM_3D_KMH : SYM_KMH));
} else {
tfp_sprintf(buff, "%3d%c", (int)osdConvertVelocityToUnit(vel), (_3D ? SYM_3D_KMH : SYM_KMH));
}
break;
case OSD_UNIT_GA:
if (_max) {
tfp_sprintf(buff, "%c%3d%c", SYM_MAX, (int)osdConvertVelocityToUnit(vel), (_3D ? SYM_3D_KT : SYM_KT));
} else {
tfp_sprintf(buff, "%3d%c", (int)osdConvertVelocityToUnit(vel), (_3D ? SYM_3D_KT : SYM_KT));
}
break;
case OSD_UNIT_UK:
FALLTHROUGH;
case OSD_UNIT_METRIC_MPH:
FALLTHROUGH;
case OSD_UNIT_IMPERIAL:
if (_max) {
switch (speedType) {
case OSD_SPEED_TYPE_GROUND:
tfp_sprintf(buff, "%c%3d%c", SYM_MAX, (int)osdConvertVelocityToUnit(vel), SYM_MPH);
break;
case OSD_SPEED_TYPE_AIR:
tfp_sprintf(buff, "%c%c%3d%c", SYM_MAX, SYM_AIR, (int)osdConvertVelocityToUnit(vel), SYM_MPH);
break;
case OSD_SPEED_TYPE_3D:
tfp_sprintf(buff, "%c%3d%c", SYM_MAX, (int)osdConvertVelocityToUnit(vel), SYM_3D_MPH);
break;
case OSD_SPEED_TYPE_MIN_GROUND:
break;
}
} else {
switch (speedType){
case OSD_SPEED_TYPE_GROUND:
tfp_sprintf(buff, "%3d%c", (int)osdConvertVelocityToUnit(vel), SYM_MPH);
break;
case OSD_SPEED_TYPE_AIR:
tfp_sprintf(buff, "%c%3d%c", SYM_AIR, (int)osdConvertVelocityToUnit(vel), SYM_MPH);
break;
case OSD_SPEED_TYPE_3D:
tfp_sprintf(buff, "%3d%c", (int)osdConvertVelocityToUnit(vel), SYM_3D_MPH);
break;
case OSD_SPEED_TYPE_MIN_GROUND:
tfp_sprintf(buff, "%c%3d%c", SYM_GROUND_COURSE, (int)osdConvertVelocityToUnit(vel), SYM_MPH);
break;
}
}
break;
case OSD_UNIT_METRIC:
if (_max) {
switch (speedType) {
case OSD_SPEED_TYPE_GROUND:
tfp_sprintf(buff, "%c%3d%c", SYM_MAX, (int)osdConvertVelocityToUnit(vel), SYM_KMH);
break;
case OSD_SPEED_TYPE_AIR:
tfp_sprintf(buff, "%c%c%3d%c", SYM_MAX, SYM_AIR, (int)osdConvertVelocityToUnit(vel), SYM_KMH);
break;
case OSD_SPEED_TYPE_3D:
tfp_sprintf(buff, "%c%3d%c", SYM_MAX, (int)osdConvertVelocityToUnit(vel), SYM_3D_KMH);
break;
case OSD_SPEED_TYPE_MIN_GROUND:
break;
}
} else {
switch (speedType) {
case OSD_SPEED_TYPE_GROUND:
tfp_sprintf(buff, "%3d%c", (int)osdConvertVelocityToUnit(vel), SYM_KMH);
break;
case OSD_SPEED_TYPE_AIR:
tfp_sprintf(buff, "%c%3d%c", SYM_AIR, (int)osdConvertVelocityToUnit(vel), SYM_KMH);
break;
case OSD_SPEED_TYPE_3D:
tfp_sprintf(buff, "%3d%c", (int)osdConvertVelocityToUnit(vel), SYM_3D_KMH);
break;
case OSD_SPEED_TYPE_MIN_GROUND:
tfp_sprintf(buff, "%c%3d%c", SYM_GROUND_COURSE, (int)osdConvertVelocityToUnit(vel), SYM_KMH);
break;
}
}
break;
case OSD_UNIT_GA:
if (_max) {
switch (speedType) {
case OSD_SPEED_TYPE_GROUND:
tfp_sprintf(buff, "%c%3d%c", SYM_MAX, (int)osdConvertVelocityToUnit(vel), SYM_KT);
break;
case OSD_SPEED_TYPE_AIR:
tfp_sprintf(buff, "%c%c%3d%c", SYM_MAX, SYM_AIR, (int)osdConvertVelocityToUnit(vel), SYM_KT);
break;
case OSD_SPEED_TYPE_3D:
tfp_sprintf(buff, "%c%3d%c", SYM_MAX, (int)osdConvertVelocityToUnit(vel), SYM_3D_KT);
break;
case OSD_SPEED_TYPE_MIN_GROUND:
break;
}
} else {
switch (speedType) {
case OSD_SPEED_TYPE_GROUND:
tfp_sprintf(buff, "%3d%c", (int)osdConvertVelocityToUnit(vel), SYM_KT);
break;
case OSD_SPEED_TYPE_AIR:
tfp_sprintf(buff, "%c%3d%c", SYM_AIR, (int)osdConvertVelocityToUnit(vel), SYM_KT);
break;
case OSD_SPEED_TYPE_3D:
tfp_sprintf(buff, "%3d%c", (int)osdConvertVelocityToUnit(vel), SYM_3D_KT);
break;
case OSD_SPEED_TYPE_MIN_GROUND:
tfp_sprintf(buff, "%c%3d%c", SYM_GROUND_COURSE, (int)osdConvertVelocityToUnit(vel), SYM_KT);
break;
}
}
break;
}
}

Expand All @@ -427,7 +502,7 @@ void osdFormatVelocityStr(char* buff, int32_t vel, bool _3D, bool _max)
*/
static void osdGenerateAverageVelocityStr(char* buff) {
uint32_t cmPerSec = getTotalTravelDistance() / getFlightTime();
osdFormatVelocityStr(buff, cmPerSec, false, false);
osdFormatVelocityStr(buff, cmPerSec, OSD_SPEED_TYPE_GROUND, false);
}

/**
Expand Down Expand Up @@ -1883,19 +1958,23 @@ static bool osdDrawSingleElement(uint8_t item)
break;

case OSD_GPS_SPEED:
osdFormatVelocityStr(buff, gpsSol.groundSpeed, false, false);
osdFormatVelocityStr(buff, gpsSol.groundSpeed, OSD_SPEED_TYPE_GROUND, false);
break;

case OSD_NAV_MIN_GROUND_SPEED:
osdFormatVelocityStr(buff, getMinGroundSpeed(navConfig()->general.min_ground_speed) * 100, OSD_SPEED_TYPE_MIN_GROUND, false);
break;

case OSD_GPS_MAX_SPEED:
osdFormatVelocityStr(buff, stats.max_speed, false, true);
osdFormatVelocityStr(buff, stats.max_speed, OSD_SPEED_TYPE_GROUND, true);
break;

case OSD_3D_SPEED:
osdFormatVelocityStr(buff, osdGet3DSpeed(), true, false);
osdFormatVelocityStr(buff, osdGet3DSpeed(), OSD_SPEED_TYPE_3D, false);
break;

case OSD_3D_MAX_SPEED:
osdFormatVelocityStr(buff, stats.max_3D_speed, true, true);
osdFormatVelocityStr(buff, stats.max_3D_speed, OSD_SPEED_TYPE_3D, true);
break;

case OSD_GLIDESLOPE:
Expand Down Expand Up @@ -3245,19 +3324,18 @@ static bool osdDrawSingleElement(uint8_t item)
case OSD_AIR_SPEED:
{
#ifdef USE_PITOT
buff[0] = SYM_AIR;

if (pitotIsHealthy())
{
const float airspeed_estimate = getAirspeedEstimate();
osdFormatVelocityStr(buff + 1, airspeed_estimate, false, false);
osdFormatVelocityStr(buff, airspeed_estimate, OSD_SPEED_TYPE_AIR, false);
if ((osdConfig()->airspeed_alarm_min != 0 && airspeed_estimate < osdConfig()->airspeed_alarm_min) ||
(osdConfig()->airspeed_alarm_max != 0 && airspeed_estimate > osdConfig()->airspeed_alarm_max)) {
TEXT_ATTRIBUTES_ADD_BLINK(elemAttr);
}
}
else
{
buff[0] = SYM_AIR;
strcpy(buff + 1, " X!");
TEXT_ATTRIBUTES_ADD_BLINK(elemAttr);
}
Expand All @@ -3270,9 +3348,7 @@ static bool osdDrawSingleElement(uint8_t item)
case OSD_AIR_MAX_SPEED:
{
#ifdef USE_PITOT
buff[0] = SYM_MAX;
buff[1] = SYM_AIR;
osdFormatVelocityStr(buff + 2, stats.max_air_speed, false, false);
osdFormatVelocityStr(buff, stats.max_air_speed, OSD_SPEED_TYPE_AIR, true);
#else
return false;
#endif
Expand Down Expand Up @@ -4837,7 +4913,7 @@ uint8_t drawStat_Speed(uint8_t col, uint8_t row, uint8_t statValX)

displayWrite(osdDisplayPort, col, row, "MAX/AVG SPEED");

osdFormatVelocityStr(buff2, stats.max_3D_speed, true, false);
osdFormatVelocityStr(buff2, stats.max_3D_speed, OSD_SPEED_TYPE_3D, false);
tfp_sprintf(buff, ": %s/", osdFormatTrimWhiteSpace(buff2));
multiValueXOffset = strlen(buff);
displayWrite(osdDisplayPort, statValX, row, buff);
Expand Down Expand Up @@ -6138,7 +6214,7 @@ textAttributes_t osdGetSystemMessage(char *buff, size_t buff_size, bool isCenter
if (FLIGHT_MODE(NAV_COURSE_HOLD_MODE)) {
if (posControl.cruise.multicopterSpeed >= 50.0f) {
char buf[6];
osdFormatVelocityStr(buf, posControl.cruise.multicopterSpeed, false, false);
osdFormatVelocityStr(buf, posControl.cruise.multicopterSpeed, OSD_SPEED_TYPE_GROUND, false);
tfp_sprintf(messageBuf, "(SPD %s)", buf);
} else {
strcpy(messageBuf, "(HOLD)");
Expand Down
10 changes: 9 additions & 1 deletion src/main/io/osd.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ typedef enum {
OSD_H_DIST_TO_FENCE,
OSD_V_DIST_TO_FENCE,
OSD_NAV_FW_ALT_CONTROL_RESPONSE,
OSD_NAV_MIN_GROUND_SPEED,
OSD_ITEM_COUNT // MUST BE LAST
} osd_items_e;

Expand Down Expand Up @@ -366,6 +367,13 @@ typedef enum {
OSD_CRSF_LQ_TYPE3
} osd_crsf_lq_format_e;

typedef enum {
OSD_SPEED_TYPE_GROUND,
OSD_SPEED_TYPE_AIR,
OSD_SPEED_TYPE_3D,
OSD_SPEED_TYPE_MIN_GROUND,
} osd_SpeedTypes_e;

typedef struct osdLayoutsConfig_s {
// Layouts
uint16_t item_pos[OSD_LAYOUT_COUNT][OSD_ITEM_COUNT];
Expand Down Expand Up @@ -537,7 +545,7 @@ void osdShowEEPROMSavedNotification(void);
void osdCrosshairPosition(uint8_t *x, uint8_t *y);
bool osdFormatCentiNumber(char *buff, int32_t centivalue, uint32_t scale, int maxDecimals, int maxScaledDecimals, int length, bool leadingZeros);
void osdFormatAltitudeSymbol(char *buff, int32_t alt);
void osdFormatVelocityStr(char* buff, int32_t vel, bool _3D, bool _max);
void osdFormatVelocityStr(char* buff, int32_t vel, osd_SpeedTypes_e speedType, bool _max);
// Returns a heading angle in degrees normalized to [0, 360).
int osdGetHeadingAngle(int angle);

Expand Down
4 changes: 2 additions & 2 deletions src/main/navigation/navigation_fixedwing.c
Original file line number Diff line number Diff line change
Expand Up @@ -558,10 +558,10 @@ int16_t applyFixedWingMinSpeedController(timeUs_t currentTimeUs)
previousTimePositionUpdate = currentTimeUs;

if (deltaMicrosPositionUpdate < MAX_POSITION_UPDATE_INTERVAL_US) {
float velThrottleBoost = ((navConfig()->general.min_ground_speed * 100.0f) - posControl.actualState.velXY) * NAV_FW_THROTTLE_SPEED_BOOST_GAIN * US2S(deltaMicrosPositionUpdate);
float velThrottleBoost = ((getMinGroundSpeed(navConfig()->general.min_ground_speed) * 100.0f) - posControl.actualState.velXY) * NAV_FW_THROTTLE_SPEED_BOOST_GAIN * US2S(deltaMicrosPositionUpdate);

// If we are in the deadband of 50cm/s - don't update speed boost
if (fabsf(posControl.actualState.velXY - (navConfig()->general.min_ground_speed * 100.0f)) > 50) {
if (fabsf(posControl.actualState.velXY - (getMinGroundSpeed(navConfig()->general.min_ground_speed) * 100.0f)) > 50) {
throttleSpeedAdjustment += velThrottleBoost;
}

Expand Down
Loading
Loading