mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-13 11:29:58 +03:00
Merge branch 'upstream' of github.com:multiwii/baseflight into upstream
Conflicts: Makefile src/main.c
This commit is contained in:
commit
cae6bc86f1
25 changed files with 3757 additions and 3500 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*.o
|
||||||
|
*~
|
17
Makefile
17
Makefile
|
@ -23,6 +23,9 @@ OPTIONS ?=
|
||||||
# Debugger optons, must be empty or GDB
|
# Debugger optons, must be empty or GDB
|
||||||
DEBUG ?=
|
DEBUG ?=
|
||||||
|
|
||||||
|
# Serial port/Device for flashing
|
||||||
|
SERIAL_DEVICE ?= /dev/ttyUSB0
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Things that need to be maintained as the source changes
|
# Things that need to be maintained as the source changes
|
||||||
#
|
#
|
||||||
|
@ -192,6 +195,20 @@ $(OBJECT_DIR)/$(TARGET)/%.o): %.S
|
||||||
clean:
|
clean:
|
||||||
rm -f $(TARGET_HEX) $(TARGET_ELF) $(TARGET_OBJS)
|
rm -f $(TARGET_HEX) $(TARGET_ELF) $(TARGET_OBJS)
|
||||||
|
|
||||||
|
flash_$(TARGET): $(TARGET_HEX)
|
||||||
|
stty -F $(SERIAL_DEVICE) raw speed 115200 -crtscts cs8 -parenb -cstopb -ixon
|
||||||
|
echo -n 'R' >$(SERIAL_DEVICE)
|
||||||
|
stm32flash -w $(TARGET_HEX) -v -g 0x0 -b 115200 $(SERIAL_DEVICE)
|
||||||
|
|
||||||
|
flash: flash_$(TARGET)
|
||||||
|
|
||||||
|
|
||||||
|
unbrick_$(TARGET): $(TARGET_HEX)
|
||||||
|
stty -F $(SERIAL_DEVICE) raw speed 115200 -crtscts cs8 -parenb -cstopb -ixon
|
||||||
|
stm32flash -w $(TARGET_HEX) -v -g 0x0 -b 115200 $(SERIAL_DEVICE)
|
||||||
|
|
||||||
|
unbrick: unbrick_$(TARGET)
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Makefile for the baseflight firmware"
|
@echo "Makefile for the baseflight firmware"
|
||||||
|
|
|
@ -165,6 +165,7 @@
|
||||||
<Capability>1</Capability>
|
<Capability>1</Capability>
|
||||||
<DriverSelection>4096</DriverSelection>
|
<DriverSelection>4096</DriverSelection>
|
||||||
</Flash1>
|
</Flash1>
|
||||||
|
<bUseTDR>0</bUseTDR>
|
||||||
<Flash2>BIN\UL2CM3.DLL</Flash2>
|
<Flash2>BIN\UL2CM3.DLL</Flash2>
|
||||||
<Flash3>"" ()</Flash3>
|
<Flash3>"" ()</Flash3>
|
||||||
<Flash4></Flash4>
|
<Flash4></Flash4>
|
||||||
|
@ -196,7 +197,7 @@
|
||||||
<AdsLsun>1</AdsLsun>
|
<AdsLsun>1</AdsLsun>
|
||||||
<AdsLven>1</AdsLven>
|
<AdsLven>1</AdsLven>
|
||||||
<AdsLsxf>1</AdsLsxf>
|
<AdsLsxf>1</AdsLsxf>
|
||||||
<RvctClst>0</RvctClst>
|
<RvctClst>1</RvctClst>
|
||||||
<GenPPlst>0</GenPPlst>
|
<GenPPlst>0</GenPPlst>
|
||||||
<AdsCpuType>"Cortex-M3"</AdsCpuType>
|
<AdsCpuType>"Cortex-M3"</AdsCpuType>
|
||||||
<RvctDeviceName></RvctDeviceName>
|
<RvctDeviceName></RvctDeviceName>
|
||||||
|
@ -970,8 +971,9 @@
|
||||||
<Capability>1</Capability>
|
<Capability>1</Capability>
|
||||||
<DriverSelection>4096</DriverSelection>
|
<DriverSelection>4096</DriverSelection>
|
||||||
</Flash1>
|
</Flash1>
|
||||||
|
<bUseTDR>0</bUseTDR>
|
||||||
<Flash2>BIN\UL2CM3.DLL</Flash2>
|
<Flash2>BIN\UL2CM3.DLL</Flash2>
|
||||||
<Flash3></Flash3>
|
<Flash3>"" ()</Flash3>
|
||||||
<Flash4></Flash4>
|
<Flash4></Flash4>
|
||||||
</Utilities>
|
</Utilities>
|
||||||
<TargetArmAds>
|
<TargetArmAds>
|
||||||
|
@ -988,7 +990,7 @@
|
||||||
<ldmm>1</ldmm>
|
<ldmm>1</ldmm>
|
||||||
<ldXref>1</ldXref>
|
<ldXref>1</ldXref>
|
||||||
<BigEnd>0</BigEnd>
|
<BigEnd>0</BigEnd>
|
||||||
<AdsALst>0</AdsALst>
|
<AdsALst>1</AdsALst>
|
||||||
<AdsACrf>1</AdsACrf>
|
<AdsACrf>1</AdsACrf>
|
||||||
<AdsANop>0</AdsANop>
|
<AdsANop>0</AdsANop>
|
||||||
<AdsANot>0</AdsANot>
|
<AdsANot>0</AdsANot>
|
||||||
|
@ -1001,7 +1003,7 @@
|
||||||
<AdsLsun>1</AdsLsun>
|
<AdsLsun>1</AdsLsun>
|
||||||
<AdsLven>1</AdsLven>
|
<AdsLven>1</AdsLven>
|
||||||
<AdsLsxf>1</AdsLsxf>
|
<AdsLsxf>1</AdsLsxf>
|
||||||
<RvctClst>0</RvctClst>
|
<RvctClst>1</RvctClst>
|
||||||
<GenPPlst>0</GenPPlst>
|
<GenPPlst>0</GenPPlst>
|
||||||
<AdsCpuType>"Cortex-M3"</AdsCpuType>
|
<AdsCpuType>"Cortex-M3"</AdsCpuType>
|
||||||
<RvctDeviceName></RvctDeviceName>
|
<RvctDeviceName></RvctDeviceName>
|
||||||
|
@ -1719,6 +1721,7 @@
|
||||||
<Capability>1</Capability>
|
<Capability>1</Capability>
|
||||||
<DriverSelection>4096</DriverSelection>
|
<DriverSelection>4096</DriverSelection>
|
||||||
</Flash1>
|
</Flash1>
|
||||||
|
<bUseTDR>0</bUseTDR>
|
||||||
<Flash2>BIN\UL2CM3.DLL</Flash2>
|
<Flash2>BIN\UL2CM3.DLL</Flash2>
|
||||||
<Flash3>"" ()</Flash3>
|
<Flash3>"" ()</Flash3>
|
||||||
<Flash4></Flash4>
|
<Flash4></Flash4>
|
||||||
|
|
6401
obj/baseflight.hex
6401
obj/baseflight.hex
File diff suppressed because it is too large
Load diff
|
@ -13,7 +13,12 @@
|
||||||
|
|
||||||
#include "stm32f10x_conf.h"
|
#include "stm32f10x_conf.h"
|
||||||
#include "core_cm3.h"
|
#include "core_cm3.h"
|
||||||
|
|
||||||
|
#ifndef __CC_ARM
|
||||||
|
// only need this garbage on gcc
|
||||||
|
#define USE_LAME_PRINTF
|
||||||
#include "printf.h"
|
#include "printf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef M_PI
|
#ifndef M_PI
|
||||||
#define M_PI 3.14159265358979323846f
|
#define M_PI 3.14159265358979323846f
|
||||||
|
@ -75,6 +80,7 @@ typedef void (* sensorReadFuncPtr)(int16_t *data); // sensor read and a
|
||||||
typedef void (* baroCalculateFuncPtr)(int32_t *pressure, int32_t *temperature); // baro calculation (filled params are pressure and temperature)
|
typedef void (* baroCalculateFuncPtr)(int32_t *pressure, int32_t *temperature); // baro calculation (filled params are pressure and temperature)
|
||||||
typedef void (* uartReceiveCallbackPtr)(uint16_t data); // used by uart2 driver to return frames to app
|
typedef void (* uartReceiveCallbackPtr)(uint16_t data); // used by uart2 driver to return frames to app
|
||||||
typedef uint16_t (* rcReadRawDataPtr)(uint8_t chan); // used by receiver driver to return channel data
|
typedef uint16_t (* rcReadRawDataPtr)(uint8_t chan); // used by receiver driver to return channel data
|
||||||
|
typedef void (* pidControllerFuncPtr)(void); // pid controller function prototype
|
||||||
|
|
||||||
typedef struct sensor_t
|
typedef struct sensor_t
|
||||||
{
|
{
|
||||||
|
@ -195,6 +201,7 @@ typedef struct baro_t
|
||||||
#include "drv_pwm.h"
|
#include "drv_pwm.h"
|
||||||
#include "drv_uart.h"
|
#include "drv_uart.h"
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// AfroFlight32
|
// AfroFlight32
|
||||||
#include "drv_system.h" // timers, delays, etc
|
#include "drv_system.h" // timers, delays, etc
|
||||||
#include "drv_adc.h"
|
#include "drv_adc.h"
|
||||||
|
|
108
src/cli.c
108
src/cli.c
|
@ -44,7 +44,7 @@ const char * const mixerNames[] = {
|
||||||
const char * const featureNames[] = {
|
const char * const featureNames[] = {
|
||||||
"PPM", "VBAT", "INFLIGHT_ACC_CAL", "SPEKTRUM", "MOTOR_STOP",
|
"PPM", "VBAT", "INFLIGHT_ACC_CAL", "SPEKTRUM", "MOTOR_STOP",
|
||||||
"SERVO_TILT", "GYRO_SMOOTHING", "LED_RING", "GPS",
|
"SERVO_TILT", "GYRO_SMOOTHING", "LED_RING", "GPS",
|
||||||
"FAILSAFE", "SONAR", "TELEMETRY", "VARIO",
|
"FAILSAFE", "SONAR", "TELEMETRY", "POWERMETER", "VARIO",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -131,8 +131,9 @@ const clivalue_t valueTable[] = {
|
||||||
{ "moron_threshold", VAR_UINT8, &mcfg.moron_threshold, 0, 128 },
|
{ "moron_threshold", VAR_UINT8, &mcfg.moron_threshold, 0, 128 },
|
||||||
{ "gyro_lpf", VAR_UINT16, &mcfg.gyro_lpf, 0, 256 },
|
{ "gyro_lpf", VAR_UINT16, &mcfg.gyro_lpf, 0, 256 },
|
||||||
{ "gyro_cmpf_factor", VAR_UINT16, &mcfg.gyro_cmpf_factor, 100, 1000 },
|
{ "gyro_cmpf_factor", VAR_UINT16, &mcfg.gyro_cmpf_factor, 100, 1000 },
|
||||||
|
{ "gyro_cmpfm_factor", VAR_UINT16, &mcfg.gyro_cmpfm_factor, 100, 1000 },
|
||||||
{ "gps_type", VAR_UINT8, &mcfg.gps_type, 0, 3 },
|
{ "gps_type", VAR_UINT8, &mcfg.gps_type, 0, 3 },
|
||||||
|
{ "pid_controller", VAR_UINT8, &cfg.pidController, 0, 1 },
|
||||||
{ "deadband", VAR_UINT8, &cfg.deadband, 0, 32 },
|
{ "deadband", VAR_UINT8, &cfg.deadband, 0, 32 },
|
||||||
{ "yawdeadband", VAR_UINT8, &cfg.yawdeadband, 0, 100 },
|
{ "yawdeadband", VAR_UINT8, &cfg.yawdeadband, 0, 100 },
|
||||||
{ "alt_hold_throttle_neutral", VAR_UINT8, &cfg.alt_hold_throttle_neutral, 1, 250 },
|
{ "alt_hold_throttle_neutral", VAR_UINT8, &cfg.alt_hold_throttle_neutral, 1, 250 },
|
||||||
|
@ -145,6 +146,7 @@ const clivalue_t valueTable[] = {
|
||||||
{ "failsafe_delay", VAR_UINT8, &cfg.failsafe_delay, 0, 200 },
|
{ "failsafe_delay", VAR_UINT8, &cfg.failsafe_delay, 0, 200 },
|
||||||
{ "failsafe_off_delay", VAR_UINT8, &cfg.failsafe_off_delay, 0, 200 },
|
{ "failsafe_off_delay", VAR_UINT8, &cfg.failsafe_off_delay, 0, 200 },
|
||||||
{ "failsafe_throttle", VAR_UINT16, &cfg.failsafe_throttle, 1000, 2000 },
|
{ "failsafe_throttle", VAR_UINT16, &cfg.failsafe_throttle, 1000, 2000 },
|
||||||
|
{ "failsafe_detect_threshold", VAR_UINT16, &cfg.failsafe_detect_threshold, 100, 2000 },
|
||||||
{ "yaw_direction", VAR_INT8, &cfg.yaw_direction, -1, 1 },
|
{ "yaw_direction", VAR_INT8, &cfg.yaw_direction, -1, 1 },
|
||||||
{ "tri_yaw_middle", VAR_UINT16, &cfg.tri_yaw_middle, 0, 2000 },
|
{ "tri_yaw_middle", VAR_UINT16, &cfg.tri_yaw_middle, 0, 2000 },
|
||||||
{ "tri_yaw_min", VAR_UINT16, &cfg.tri_yaw_min, 0, 2000 },
|
{ "tri_yaw_min", VAR_UINT16, &cfg.tri_yaw_min, 0, 2000 },
|
||||||
|
@ -169,7 +171,6 @@ const clivalue_t valueTable[] = {
|
||||||
{ "gimbal_roll_max", VAR_UINT16, &cfg.gimbal_roll_max, 100, 3000 },
|
{ "gimbal_roll_max", VAR_UINT16, &cfg.gimbal_roll_max, 100, 3000 },
|
||||||
{ "gimbal_roll_mid", VAR_UINT16, &cfg.gimbal_roll_mid, 100, 3000 },
|
{ "gimbal_roll_mid", VAR_UINT16, &cfg.gimbal_roll_mid, 100, 3000 },
|
||||||
{ "acc_lpf_factor", VAR_UINT8, &cfg.acc_lpf_factor, 0, 250 },
|
{ "acc_lpf_factor", VAR_UINT8, &cfg.acc_lpf_factor, 0, 250 },
|
||||||
{ "acc_lpf_for_velocity", VAR_UINT8, &cfg.acc_lpf_for_velocity, 1, 250 },
|
|
||||||
{ "acc_trim_pitch", VAR_INT16, &cfg.angleTrim[PITCH], -300, 300 },
|
{ "acc_trim_pitch", VAR_INT16, &cfg.angleTrim[PITCH], -300, 300 },
|
||||||
{ "acc_trim_roll", VAR_INT16, &cfg.angleTrim[ROLL], -300, 300 },
|
{ "acc_trim_roll", VAR_INT16, &cfg.angleTrim[ROLL], -300, 300 },
|
||||||
{ "baro_tab_size", VAR_UINT8, &cfg.baro_tab_size, 0, BARO_TAB_SIZE_MAX },
|
{ "baro_tab_size", VAR_UINT8, &cfg.baro_tab_size, 0, BARO_TAB_SIZE_MAX },
|
||||||
|
@ -598,7 +599,7 @@ static void cliDump(char *cmdline)
|
||||||
static void cliExit(char *cmdline)
|
static void cliExit(char *cmdline)
|
||||||
{
|
{
|
||||||
uartPrint("\r\nLeaving CLI mode...\r\n");
|
uartPrint("\r\nLeaving CLI mode...\r\n");
|
||||||
memset(cliBuffer, 0, sizeof(cliBuffer));
|
*cliBuffer = '\0';
|
||||||
bufferIndex = 0;
|
bufferIndex = 0;
|
||||||
cliMode = 0;
|
cliMode = 0;
|
||||||
// save and reboot... I think this makes the most sense
|
// save and reboot... I think this makes the most sense
|
||||||
|
@ -860,6 +861,16 @@ static void cliSet(char *cmdline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uartPrint("ERR: Unknown variable name\r\n");
|
uartPrint("ERR: Unknown variable name\r\n");
|
||||||
|
} else {
|
||||||
|
// no equals, check for matching variables.
|
||||||
|
for (i = 0; i < VALUE_COUNT; i++) {
|
||||||
|
if (strstr(valueTable[i].name, cmdline)) {
|
||||||
|
val = &valueTable[i];
|
||||||
|
printf("%s = ", valueTable[i].name);
|
||||||
|
cliPrintVar(val, 0);
|
||||||
|
printf("\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -904,6 +915,35 @@ void cliProcess(void)
|
||||||
|
|
||||||
while (uartAvailable()) {
|
while (uartAvailable()) {
|
||||||
uint8_t c = uartRead();
|
uint8_t c = uartRead();
|
||||||
|
|
||||||
|
/* first step: translate "ESC[" -> "CSI" */
|
||||||
|
if (c == '\033') {
|
||||||
|
c = uartReadPoll();
|
||||||
|
if (c == '[')
|
||||||
|
c = 0x9b;
|
||||||
|
else
|
||||||
|
/* ignore unknown sequences */
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* second step: translate known CSI sequence into singlebyte control sequences */
|
||||||
|
if (c == 0x9b) {
|
||||||
|
c = uartReadPoll();
|
||||||
|
if (c == 'A') //up
|
||||||
|
c = 0x0b;
|
||||||
|
else if (c == 'B') //down
|
||||||
|
c = 0x0a;
|
||||||
|
else if (c == 'C') //right
|
||||||
|
c = 0x0c;
|
||||||
|
else if (c == 'D') //left
|
||||||
|
c = 0x08;
|
||||||
|
else if (c == 0x33 && uartReadPoll() == 0x7e) //delete
|
||||||
|
c = 0xff; // nonstandard, borrowing 0xff for the delete key
|
||||||
|
else
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* from here on everything is a single byte */
|
||||||
if (c == '\t' || c == '?') {
|
if (c == '\t' || c == '?') {
|
||||||
// do tab completion
|
// do tab completion
|
||||||
const clicmd_t *cmd, *pstart = NULL, *pend = NULL;
|
const clicmd_t *cmd, *pstart = NULL, *pend = NULL;
|
||||||
|
@ -919,9 +959,10 @@ void cliProcess(void)
|
||||||
for (; ; bufferIndex++) {
|
for (; ; bufferIndex++) {
|
||||||
if (pstart->name[bufferIndex] != pend->name[bufferIndex])
|
if (pstart->name[bufferIndex] != pend->name[bufferIndex])
|
||||||
break;
|
break;
|
||||||
if (!pstart->name[bufferIndex]) {
|
if (!pstart->name[bufferIndex] && bufferIndex < sizeof(cliBuffer) - 2) {
|
||||||
/* Unambiguous -- append a space */
|
/* Unambiguous -- append a space */
|
||||||
cliBuffer[bufferIndex++] = ' ';
|
cliBuffer[bufferIndex++] = ' ';
|
||||||
|
cliBuffer[bufferIndex] = '\0';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cliBuffer[bufferIndex] = pstart->name[bufferIndex];
|
cliBuffer[bufferIndex] = pstart->name[bufferIndex];
|
||||||
|
@ -942,20 +983,41 @@ void cliProcess(void)
|
||||||
} else if (!bufferIndex && c == 4) {
|
} else if (!bufferIndex && c == 4) {
|
||||||
cliExit(cliBuffer);
|
cliExit(cliBuffer);
|
||||||
return;
|
return;
|
||||||
|
} else if (c == 0x15) {
|
||||||
|
// ctrl+u == delete line
|
||||||
|
uartPrint("\033[G\033[K# ");
|
||||||
|
bufferIndex = 0;
|
||||||
|
*cliBuffer = '\0';
|
||||||
|
} else if (c == 0x0b) {
|
||||||
|
//uartPrint("up unimplemented");
|
||||||
|
} else if (c == 0x0a) {
|
||||||
|
//uartPrint("down unimplemend");
|
||||||
|
} else if (c == 0x08) {
|
||||||
|
if (bufferIndex > 0) {
|
||||||
|
bufferIndex--;
|
||||||
|
uartPrint("\033[D");
|
||||||
|
}
|
||||||
} else if (c == 12) {
|
} else if (c == 12) {
|
||||||
// clear screen
|
if (cliBuffer[bufferIndex]) {
|
||||||
uartPrint("\033[2J\033[1;1H");
|
bufferIndex++;
|
||||||
cliPrompt();
|
uartPrint("\033[C");
|
||||||
} else if (bufferIndex && (c == '\n' || c == '\r')) {
|
}
|
||||||
|
} else if (c == 0xff) {
|
||||||
|
// delete key
|
||||||
|
if (cliBuffer[bufferIndex]) {
|
||||||
|
int len = strlen(cliBuffer + bufferIndex);
|
||||||
|
memmove(cliBuffer + bufferIndex, cliBuffer + bufferIndex + 1, len + 1);
|
||||||
|
printf("%s \033[%dD", cliBuffer + bufferIndex, len);
|
||||||
|
}
|
||||||
|
} else if (*cliBuffer && (c == '\n' || c == '\r')) {
|
||||||
// enter pressed
|
// enter pressed
|
||||||
clicmd_t *cmd = NULL;
|
clicmd_t *cmd = NULL;
|
||||||
clicmd_t target;
|
clicmd_t target;
|
||||||
uartPrint("\r\n");
|
uartPrint("\r\n");
|
||||||
cliBuffer[bufferIndex] = 0; // null terminate
|
|
||||||
|
|
||||||
target.name = cliBuffer;
|
target.name = cliBuffer;
|
||||||
target.param = NULL;
|
target.param = NULL;
|
||||||
|
|
||||||
cmd = bsearch(&target, cmdTable, CMD_COUNT, sizeof cmdTable[0], cliCompare);
|
cmd = bsearch(&target, cmdTable, CMD_COUNT, sizeof cmdTable[0], cliCompare);
|
||||||
if (cmd)
|
if (cmd)
|
||||||
cmd->func(cliBuffer + strlen(cmd->name) + 1);
|
cmd->func(cliBuffer + strlen(cmd->name) + 1);
|
||||||
|
@ -971,15 +1033,25 @@ void cliProcess(void)
|
||||||
cliPrompt();
|
cliPrompt();
|
||||||
} else if (c == 127) {
|
} else if (c == 127) {
|
||||||
// backspace
|
// backspace
|
||||||
if (bufferIndex) {
|
if (bufferIndex && *cliBuffer) {
|
||||||
cliBuffer[--bufferIndex] = 0;
|
int len = strlen(cliBuffer + bufferIndex);
|
||||||
uartPrint("\010 \010");
|
|
||||||
|
--bufferIndex;
|
||||||
|
memmove(cliBuffer + bufferIndex, cliBuffer + bufferIndex + 1, len + 1);
|
||||||
|
printf("\033[D%s \033[%dD", cliBuffer + bufferIndex, len + 1);
|
||||||
}
|
}
|
||||||
} else if (bufferIndex < sizeof(cliBuffer) && c >= 32 && c <= 126) {
|
} else if (strlen(cliBuffer) + 1 < sizeof(cliBuffer) && c >= 32 && c <= 126) {
|
||||||
|
int len;
|
||||||
|
|
||||||
if (!bufferIndex && c == 32)
|
if (!bufferIndex && c == 32)
|
||||||
continue;
|
continue;
|
||||||
cliBuffer[bufferIndex++] = c;
|
|
||||||
uartWrite(c);
|
len = strlen(cliBuffer + bufferIndex);
|
||||||
|
|
||||||
|
memmove(cliBuffer + bufferIndex + 1, cliBuffer + bufferIndex, len + 1);
|
||||||
|
cliBuffer[bufferIndex] = c;
|
||||||
|
printf("%s \033[%dD", cliBuffer + bufferIndex, len + 1);
|
||||||
|
++bufferIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
src/config.c
15
src/config.c
|
@ -13,7 +13,7 @@ master_t mcfg; // master config struct with data independent from profiles
|
||||||
config_t cfg; // profile config struct
|
config_t cfg; // profile config struct
|
||||||
const char rcChannelLetters[] = "AERT1234";
|
const char rcChannelLetters[] = "AERT1234";
|
||||||
|
|
||||||
static uint8_t EEPROM_CONF_VERSION = 47;
|
static uint8_t EEPROM_CONF_VERSION = 48;
|
||||||
static uint32_t enabledSensors = 0;
|
static uint32_t enabledSensors = 0;
|
||||||
static void resetConf(void);
|
static void resetConf(void);
|
||||||
|
|
||||||
|
@ -84,6 +84,7 @@ void readEEPROM(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.tri_yaw_middle = constrain(cfg.tri_yaw_middle, cfg.tri_yaw_min, cfg.tri_yaw_max); //REAR
|
cfg.tri_yaw_middle = constrain(cfg.tri_yaw_middle, cfg.tri_yaw_min, cfg.tri_yaw_max); //REAR
|
||||||
|
setPIDController(cfg.pidController);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeEEPROM(uint8_t b, uint8_t updateProfile)
|
void writeEEPROM(uint8_t b, uint8_t updateProfile)
|
||||||
|
@ -170,7 +171,8 @@ static void resetConf(void)
|
||||||
|
|
||||||
// global settings
|
// global settings
|
||||||
mcfg.current_profile = 0; // default profile
|
mcfg.current_profile = 0; // default profile
|
||||||
mcfg.gyro_cmpf_factor = 400; // default MWC
|
mcfg.gyro_cmpf_factor = 600; // default MWC
|
||||||
|
mcfg.gyro_cmpfm_factor = 250; // default MWC
|
||||||
mcfg.gyro_lpf = 42; // supported by all gyro drivers now. In case of ST gyro, will default to 32Hz instead
|
mcfg.gyro_lpf = 42; // supported by all gyro drivers now. In case of ST gyro, will default to 32Hz instead
|
||||||
mcfg.accZero[0] = 0;
|
mcfg.accZero[0] = 0;
|
||||||
mcfg.accZero[1] = 0;
|
mcfg.accZero[1] = 0;
|
||||||
|
@ -201,6 +203,7 @@ static void resetConf(void)
|
||||||
mcfg.serial_baudrate = 115200;
|
mcfg.serial_baudrate = 115200;
|
||||||
mcfg.looptime = 3500;
|
mcfg.looptime = 3500;
|
||||||
|
|
||||||
|
cfg.pidController = 0;
|
||||||
cfg.P8[ROLL] = 40;
|
cfg.P8[ROLL] = 40;
|
||||||
cfg.I8[ROLL] = 30;
|
cfg.I8[ROLL] = 30;
|
||||||
cfg.D8[ROLL] = 23;
|
cfg.D8[ROLL] = 23;
|
||||||
|
@ -242,7 +245,6 @@ static void resetConf(void)
|
||||||
cfg.angleTrim[1] = 0;
|
cfg.angleTrim[1] = 0;
|
||||||
cfg.mag_declination = 0; // For example, -6deg 37min, = -637 Japan, format is [sign]dddmm (degreesminutes) default is zero.
|
cfg.mag_declination = 0; // For example, -6deg 37min, = -637 Japan, format is [sign]dddmm (degreesminutes) default is zero.
|
||||||
cfg.acc_lpf_factor = 4;
|
cfg.acc_lpf_factor = 4;
|
||||||
cfg.acc_lpf_for_velocity = 10;
|
|
||||||
cfg.accz_deadband = 50;
|
cfg.accz_deadband = 50;
|
||||||
cfg.baro_tab_size = 21;
|
cfg.baro_tab_size = 21;
|
||||||
cfg.baro_noise_lpf = 0.6f;
|
cfg.baro_noise_lpf = 0.6f;
|
||||||
|
@ -256,9 +258,10 @@ static void resetConf(void)
|
||||||
cfg.alt_hold_fast_change = 1;
|
cfg.alt_hold_fast_change = 1;
|
||||||
|
|
||||||
// Failsafe Variables
|
// Failsafe Variables
|
||||||
cfg.failsafe_delay = 10; // 1sec
|
cfg.failsafe_delay = 10; // 1sec
|
||||||
cfg.failsafe_off_delay = 200; // 20sec
|
cfg.failsafe_off_delay = 200; // 20sec
|
||||||
cfg.failsafe_throttle = 1200; // decent default which should always be below hover throttle for people.
|
cfg.failsafe_throttle = 1200; // decent default which should always be below hover throttle for people.
|
||||||
|
cfg.failsafe_detect_threshold = 985; // any of first 4 channels below this value will trigger failsafe
|
||||||
|
|
||||||
// servos
|
// servos
|
||||||
cfg.yaw_direction = 1;
|
cfg.yaw_direction = 1;
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
#define HMC_POS_BIAS 1
|
#define HMC_POS_BIAS 1
|
||||||
#define HMC_NEG_BIAS 2
|
#define HMC_NEG_BIAS 2
|
||||||
|
|
||||||
bool hmc5883lDetect(void)
|
static int8_t sensor_align[3];
|
||||||
|
|
||||||
|
bool hmc5883lDetect(int8_t *align)
|
||||||
{
|
{
|
||||||
bool ack = false;
|
bool ack = false;
|
||||||
uint8_t sig = 0;
|
uint8_t sig = 0;
|
||||||
|
@ -26,6 +28,8 @@ bool hmc5883lDetect(void)
|
||||||
if (!ack || sig != 'H')
|
if (!ack || sig != 'H')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
memcpy(sensor_align, align, 3);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,10 +121,19 @@ void hmc5883lInit(float *calibrationGain)
|
||||||
void hmc5883lRead(int16_t *magData)
|
void hmc5883lRead(int16_t *magData)
|
||||||
{
|
{
|
||||||
uint8_t buf[6];
|
uint8_t buf[6];
|
||||||
|
int16_t mag[3];
|
||||||
|
int i;
|
||||||
|
|
||||||
i2cRead(MAG_ADDRESS, MAG_DATA_REGISTER, 6, buf);
|
i2cRead(MAG_ADDRESS, MAG_DATA_REGISTER, 6, buf);
|
||||||
|
mag[0] = buf[0] << 8 | buf[1];
|
||||||
|
mag[1] = buf[2] << 8 | buf[3];
|
||||||
|
mag[2] = buf[4] << 8 | buf[5];
|
||||||
|
|
||||||
magData[0] = buf[0] << 8 | buf[1];
|
for (i = 0; i < 3; i++) {
|
||||||
magData[1] = buf[2] << 8 | buf[3];
|
int8_t axis = sensor_align[i];
|
||||||
magData[2] = buf[4] << 8 | buf[5];
|
if (axis > 0)
|
||||||
|
magData[axis - 1] = mag[i];
|
||||||
|
else
|
||||||
|
magData[-axis - 1] = -mag[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
bool hmc5883lDetect(void);
|
bool hmc5883lDetect(int8_t *align);
|
||||||
void hmc5883lInit(float *calibrationGain);
|
void hmc5883lInit(float *calibrationGain);
|
||||||
void hmc5883lRead(int16_t *magData);
|
void hmc5883lRead(int16_t *magData);
|
||||||
|
|
|
@ -31,7 +31,6 @@ void I2C2_EV_IRQHandler(void)
|
||||||
i2c_ev_handler();
|
i2c_ev_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define I2C_DEFAULT_TIMEOUT 30000
|
#define I2C_DEFAULT_TIMEOUT 30000
|
||||||
static volatile uint16_t i2cErrorCount = 0;
|
static volatile uint16_t i2cErrorCount = 0;
|
||||||
|
|
||||||
|
@ -79,26 +78,18 @@ static void i2c_er_handler(void)
|
||||||
bool i2cWriteBuffer(uint8_t addr_, uint8_t reg_, uint8_t len_, uint8_t *data)
|
bool i2cWriteBuffer(uint8_t addr_, uint8_t reg_, uint8_t len_, uint8_t *data)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
uint8_t my_data[16];
|
|
||||||
uint32_t timeout = I2C_DEFAULT_TIMEOUT;
|
uint32_t timeout = I2C_DEFAULT_TIMEOUT;
|
||||||
|
|
||||||
addr = addr_ << 1;
|
addr = addr_ << 1;
|
||||||
reg = reg_;
|
reg = reg_;
|
||||||
writing = 1;
|
writing = 1;
|
||||||
reading = 0;
|
reading = 0;
|
||||||
write_p = my_data;
|
write_p = data;
|
||||||
read_p = my_data;
|
read_p = data;
|
||||||
bytes = len_;
|
bytes = len_;
|
||||||
busy = 1;
|
busy = 1;
|
||||||
error = false;
|
error = false;
|
||||||
|
|
||||||
// too long
|
|
||||||
if (len_ > 16)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (i = 0; i < len_; i++)
|
|
||||||
my_data[i] = data[i];
|
|
||||||
|
|
||||||
if (!(I2Cx->CR2 & I2C_IT_EVT)) { //if we are restarting the driver
|
if (!(I2Cx->CR2 & I2C_IT_EVT)) { //if we are restarting the driver
|
||||||
if (!(I2Cx->CR1 & 0x0100)) { // ensure sending a start
|
if (!(I2Cx->CR1 & 0x0100)) { // ensure sending a start
|
||||||
while (I2Cx->CR1 & 0x0200) { ; } //wait for any stop to finish sending
|
while (I2Cx->CR1 & 0x0200) { ; } //wait for any stop to finish sending
|
||||||
|
|
|
@ -118,6 +118,7 @@ static pwmPortData_t *servos[MAX_SERVOS];
|
||||||
static uint8_t numMotors = 0;
|
static uint8_t numMotors = 0;
|
||||||
static uint8_t numServos = 0;
|
static uint8_t numServos = 0;
|
||||||
static uint8_t numInputs = 0;
|
static uint8_t numInputs = 0;
|
||||||
|
static uint16_t failsafeThreshold = 985;
|
||||||
// external vars (ugh)
|
// external vars (ugh)
|
||||||
extern int16_t failsafeCnt;
|
extern int16_t failsafeCnt;
|
||||||
|
|
||||||
|
@ -394,6 +395,7 @@ static void ppmCallback(uint8_t port, uint16_t capture)
|
||||||
static uint16_t now;
|
static uint16_t now;
|
||||||
static uint16_t last = 0;
|
static uint16_t last = 0;
|
||||||
static uint8_t chan = 0;
|
static uint8_t chan = 0;
|
||||||
|
static uint8_t GoodPulses;
|
||||||
|
|
||||||
last = now;
|
last = now;
|
||||||
now = capture;
|
now = capture;
|
||||||
|
@ -404,6 +406,15 @@ static void ppmCallback(uint8_t port, uint16_t capture)
|
||||||
} else {
|
} else {
|
||||||
if (diff > 750 && diff < 2250 && chan < 8) { // 750 to 2250 ms is our 'valid' channel range
|
if (diff > 750 && diff < 2250 && chan < 8) { // 750 to 2250 ms is our 'valid' channel range
|
||||||
captures[chan] = diff;
|
captures[chan] = diff;
|
||||||
|
if (chan < 4 && diff > failsafeThreshold)
|
||||||
|
GoodPulses |= (1 << chan); // if signal is valid - mark channel as OK
|
||||||
|
if (GoodPulses == 0x0F) { // If first four chanells have good pulses, clear FailSafe counter
|
||||||
|
GoodPulses = 0;
|
||||||
|
if (failsafeCnt > 20)
|
||||||
|
failsafeCnt -= 20;
|
||||||
|
else
|
||||||
|
failsafeCnt = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
chan++;
|
chan++;
|
||||||
failsafeCnt = 0;
|
failsafeCnt = 0;
|
||||||
|
@ -434,6 +445,9 @@ bool pwmInit(drv_pwm_config_t *init)
|
||||||
int i = 0;
|
int i = 0;
|
||||||
const uint8_t *setup;
|
const uint8_t *setup;
|
||||||
|
|
||||||
|
// to avoid importing cfg/mcfg
|
||||||
|
failsafeThreshold = init->failsafeThreshold;
|
||||||
|
|
||||||
// this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ]
|
// this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ]
|
||||||
if (init->airplane)
|
if (init->airplane)
|
||||||
i = 2; // switch to air hardware config
|
i = 2; // switch to air hardware config
|
||||||
|
|
|
@ -14,6 +14,7 @@ typedef struct drv_pwm_config_t {
|
||||||
uint8_t adcChannel; // steal one RC input for current sensor
|
uint8_t adcChannel; // steal one RC input for current sensor
|
||||||
uint16_t motorPwmRate;
|
uint16_t motorPwmRate;
|
||||||
uint16_t servoPwmRate;
|
uint16_t servoPwmRate;
|
||||||
|
uint16_t failsafeThreshold;
|
||||||
} drv_pwm_config_t;
|
} drv_pwm_config_t;
|
||||||
|
|
||||||
// This indexes into the read-only hardware definition structure in drv_pwm.c, as well as into pwmPorts[] structure with dynamic data.
|
// This indexes into the read-only hardware definition structure in drv_pwm.c, as well as into pwmPorts[] structure with dynamic data.
|
||||||
|
|
|
@ -66,6 +66,7 @@ static void ppmIRQHandler(TIM_TypeDef *tim)
|
||||||
static uint16_t now;
|
static uint16_t now;
|
||||||
static uint16_t last = 0;
|
static uint16_t last = 0;
|
||||||
static uint8_t chan = 0;
|
static uint8_t chan = 0;
|
||||||
|
static uint8_t GoodPulses;
|
||||||
|
|
||||||
if (TIM_GetITStatus(tim, TIM_IT_CC1) == SET) {
|
if (TIM_GetITStatus(tim, TIM_IT_CC1) == SET) {
|
||||||
last = now;
|
last = now;
|
||||||
|
@ -86,6 +87,15 @@ static void ppmIRQHandler(TIM_TypeDef *tim)
|
||||||
} else {
|
} else {
|
||||||
if (diff > 750 && diff < 2250 && chan < 8) { // 750 to 2250 ms is our 'valid' channel range
|
if (diff > 750 && diff < 2250 && chan < 8) { // 750 to 2250 ms is our 'valid' channel range
|
||||||
Inputs[chan].capture = diff;
|
Inputs[chan].capture = diff;
|
||||||
|
if (chan < 4 && diff > FAILSAFE_DETECT_TRESHOLD)
|
||||||
|
GoodPulses |= (1 << chan); // if signal is valid - mark channel as OK
|
||||||
|
if (GoodPulses == 0x0F) { // If first four chanells have good pulses, clear FailSafe counter
|
||||||
|
GoodPulses = 0;
|
||||||
|
if (failsafeCnt > 20)
|
||||||
|
failsafeCnt -= 20;
|
||||||
|
else
|
||||||
|
failsafeCnt = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
chan++;
|
chan++;
|
||||||
failsafeCnt = 0;
|
failsafeCnt = 0;
|
||||||
|
|
|
@ -33,7 +33,7 @@ uint32_t micros(void)
|
||||||
ms = sysTickUptime;
|
ms = sysTickUptime;
|
||||||
cycle_cnt = SysTick->VAL;
|
cycle_cnt = SysTick->VAL;
|
||||||
} while (ms != sysTickUptime);
|
} while (ms != sysTickUptime);
|
||||||
return (ms * 1000) + (72000 - cycle_cnt) / 72;
|
return (ms * 1000) + (usTicks * 1000 - cycle_cnt) / usTicks;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return system uptime in milliseconds (rollover in 49 days)
|
// Return system uptime in milliseconds (rollover in 49 days)
|
||||||
|
|
|
@ -8,10 +8,11 @@
|
||||||
|
|
||||||
// Receive buffer, circular DMA
|
// Receive buffer, circular DMA
|
||||||
volatile uint8_t rxBuffer[UART_BUFFER_SIZE];
|
volatile uint8_t rxBuffer[UART_BUFFER_SIZE];
|
||||||
uint32_t rxDMAPos = 0;
|
volatile uint32_t rxDMAPos = 0;
|
||||||
volatile uint8_t txBuffer[UART_BUFFER_SIZE];
|
volatile uint8_t txBuffer[UART_BUFFER_SIZE];
|
||||||
uint32_t txBufferTail = 0;
|
volatile uint32_t txBufferTail = 0;
|
||||||
uint32_t txBufferHead = 0;
|
volatile uint32_t txBufferHead = 0;
|
||||||
|
volatile bool txDMAEmpty = false;
|
||||||
|
|
||||||
static void uartTxDMA(void)
|
static void uartTxDMA(void)
|
||||||
{
|
{
|
||||||
|
@ -23,7 +24,7 @@ static void uartTxDMA(void)
|
||||||
DMA1_Channel4->CNDTR = UART_BUFFER_SIZE - txBufferTail;
|
DMA1_Channel4->CNDTR = UART_BUFFER_SIZE - txBufferTail;
|
||||||
txBufferTail = 0;
|
txBufferTail = 0;
|
||||||
}
|
}
|
||||||
|
txDMAEmpty = false;
|
||||||
DMA_Cmd(DMA1_Channel4, ENABLE);
|
DMA_Cmd(DMA1_Channel4, ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +35,8 @@ void DMA1_Channel4_IRQHandler(void)
|
||||||
|
|
||||||
if (txBufferHead != txBufferTail)
|
if (txBufferHead != txBufferTail)
|
||||||
uartTxDMA();
|
uartTxDMA();
|
||||||
|
else
|
||||||
|
txDMAEmpty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void uartInit(uint32_t speed)
|
void uartInit(uint32_t speed)
|
||||||
|
@ -109,6 +112,11 @@ uint16_t uartAvailable(void)
|
||||||
return (DMA_GetCurrDataCounter(DMA1_Channel5) != rxDMAPos) ? true : false;
|
return (DMA_GetCurrDataCounter(DMA1_Channel5) != rxDMAPos) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool uartTransmitDMAEmpty(void)
|
||||||
|
{
|
||||||
|
return txDMAEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
bool uartTransmitEmpty(void)
|
bool uartTransmitEmpty(void)
|
||||||
{
|
{
|
||||||
return (txBufferTail == txBufferHead);
|
return (txBufferTail == txBufferHead);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
void uartInit(uint32_t speed);
|
void uartInit(uint32_t speed);
|
||||||
uint16_t uartAvailable(void);
|
uint16_t uartAvailable(void);
|
||||||
bool uartTransmitEmpty(void);
|
bool uartTransmitEmpty(void);
|
||||||
|
bool uartTransmitDMAEmpty(void);
|
||||||
uint8_t uartRead(void);
|
uint8_t uartRead(void);
|
||||||
uint8_t uartReadPoll(void);
|
uint8_t uartReadPoll(void);
|
||||||
void uartWrite(uint8_t ch);
|
void uartWrite(uint8_t ch);
|
||||||
|
|
85
src/gps.c
85
src/gps.c
|
@ -928,24 +928,46 @@ typedef struct {
|
||||||
uint32_t speed_2d;
|
uint32_t speed_2d;
|
||||||
int32_t heading_2d;
|
int32_t heading_2d;
|
||||||
uint32_t speed_accuracy;
|
uint32_t speed_accuracy;
|
||||||
uint32_t heading_accuracy;
|
uint32_t heading_accuracy;
|
||||||
} ubx_nav_velned;
|
} ubx_nav_velned;
|
||||||
|
|
||||||
enum {
|
typedef struct
|
||||||
PREAMBLE1 = 0xb5,
|
{
|
||||||
PREAMBLE2 = 0x62,
|
uint8_t chn; // Channel number, 255 for SVx not assigned to channel
|
||||||
|
uint8_t svid; // Satellite ID
|
||||||
|
uint8_t flags; // Bitmask
|
||||||
|
uint8_t quality; // Bitfield
|
||||||
|
uint8_t cno; // Carrier to Noise Ratio (Signal Strength)
|
||||||
|
uint8_t elev; // Elevation in integer degrees
|
||||||
|
int16_t azim; // Azimuth in integer degrees
|
||||||
|
int32_t prRes; // Pseudo range residual in centimetres
|
||||||
|
} ubx_nav_svinfo_channel;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t time; // GPS Millisecond time of week
|
||||||
|
uint8_t numCh; // Number of channels
|
||||||
|
uint8_t globalFlags; // Bitmask, Chip hardware generation 0:Antaris, 1:u-blox 5, 2:u-blox 6
|
||||||
|
uint16_t reserved2; // Reserved
|
||||||
|
ubx_nav_svinfo_channel channel[16]; // 16 satellites * 12 byte
|
||||||
|
} ubx_nav_svinfo;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PREAMBLE1 = 0xb5,
|
||||||
|
PREAMBLE2 = 0x62,
|
||||||
CLASS_NAV = 0x01,
|
CLASS_NAV = 0x01,
|
||||||
CLASS_ACK = 0x05,
|
CLASS_ACK = 0x05,
|
||||||
CLASS_CFG = 0x06,
|
CLASS_CFG = 0x06,
|
||||||
MSG_ACK_NACK = 0x00,
|
MSG_ACK_NACK = 0x00,
|
||||||
MSG_ACK_ACK = 0x01,
|
MSG_ACK_ACK = 0x01,
|
||||||
MSG_POSLLH = 0x2,
|
MSG_POSLLH = 0x2,
|
||||||
MSG_STATUS = 0x3,
|
MSG_STATUS = 0x3,
|
||||||
MSG_SOL = 0x6,
|
MSG_SOL = 0x6,
|
||||||
MSG_VELNED = 0x12,
|
MSG_VELNED = 0x12,
|
||||||
MSG_CFG_PRT = 0x00,
|
MSG_SVINFO = 0x30,
|
||||||
MSG_CFG_RATE = 0x08,
|
MSG_CFG_PRT = 0x00,
|
||||||
MSG_CFG_SET_RATE = 0x01,
|
MSG_CFG_RATE = 0x08,
|
||||||
|
MSG_CFG_SET_RATE = 0x01,
|
||||||
MSG_CFG_NAV_SETTINGS = 0x24
|
MSG_CFG_NAV_SETTINGS = 0x24
|
||||||
} ubs_protocol_bytes;
|
} ubs_protocol_bytes;
|
||||||
|
|
||||||
|
@ -986,13 +1008,14 @@ static uint8_t _disable_counter;
|
||||||
// Receive buffer
|
// Receive buffer
|
||||||
static union {
|
static union {
|
||||||
ubx_nav_posllh posllh;
|
ubx_nav_posllh posllh;
|
||||||
ubx_nav_status status;
|
ubx_nav_status status;
|
||||||
ubx_nav_solution solution;
|
ubx_nav_solution solution;
|
||||||
ubx_nav_velned velned;
|
ubx_nav_velned velned;
|
||||||
uint8_t bytes[64];
|
ubx_nav_svinfo svinfo;
|
||||||
} _buffer;
|
uint8_t bytes[200];
|
||||||
|
} _buffer;
|
||||||
void _update_checksum(uint8_t *data, uint8_t len, uint8_t *ck_a, uint8_t *ck_b)
|
|
||||||
|
void _update_checksum(uint8_t *data, uint8_t len, uint8_t *ck_a, uint8_t *ck_b)
|
||||||
{
|
{
|
||||||
while (len--) {
|
while (len--) {
|
||||||
*ck_a += *data;
|
*ck_a += *data;
|
||||||
|
@ -1068,6 +1091,7 @@ static bool GPS_UBLOX_newFrame(uint8_t data)
|
||||||
|
|
||||||
static bool UBLOX_parse_gps(void)
|
static bool UBLOX_parse_gps(void)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
switch (_msg_id) {
|
switch (_msg_id) {
|
||||||
case MSG_POSLLH:
|
case MSG_POSLLH:
|
||||||
//i2c_dataset.time = _buffer.posllh.time;
|
//i2c_dataset.time = _buffer.posllh.time;
|
||||||
|
@ -1093,12 +1117,23 @@ static bool UBLOX_parse_gps(void)
|
||||||
case MSG_VELNED:
|
case MSG_VELNED:
|
||||||
// speed_3d = _buffer.velned.speed_3d; // cm/s
|
// speed_3d = _buffer.velned.speed_3d; // cm/s
|
||||||
GPS_speed = _buffer.velned.speed_2d; // cm/s
|
GPS_speed = _buffer.velned.speed_2d; // cm/s
|
||||||
GPS_ground_course = (uint16_t) (_buffer.velned.heading_2d / 10000); // Heading 2D deg * 100000 rescaled to deg * 10
|
GPS_ground_course = (uint16_t) (_buffer.velned.heading_2d / 10000); // Heading 2D deg * 100000 rescaled to deg * 10
|
||||||
_new_speed = true;
|
_new_speed = true;
|
||||||
break;
|
break;
|
||||||
default:
|
case MSG_SVINFO:
|
||||||
return false;
|
GPS_numCh = _buffer.svinfo.numCh;
|
||||||
}
|
if (GPS_numCh > 16)
|
||||||
|
GPS_numCh = 16;
|
||||||
|
for (i = 0; i < GPS_numCh; i++){
|
||||||
|
GPS_svinfo_chn[i]= _buffer.svinfo.channel[i].chn;
|
||||||
|
GPS_svinfo_svid[i]= _buffer.svinfo.channel[i].svid;
|
||||||
|
GPS_svinfo_quality[i]=_buffer.svinfo.channel[i].quality;
|
||||||
|
GPS_svinfo_cno[i]= _buffer.svinfo.channel[i].cno;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// we only return true when we get new position and speed data
|
// we only return true when we get new position and speed data
|
||||||
// this ensures we don't use stale data
|
// this ensures we don't use stale data
|
||||||
|
|
147
src/imu.c
147
src/imu.c
|
@ -2,7 +2,6 @@
|
||||||
#include "mw.h"
|
#include "mw.h"
|
||||||
|
|
||||||
int16_t gyroADC[3], accADC[3], accSmooth[3], magADC[3];
|
int16_t gyroADC[3], accADC[3], accSmooth[3], magADC[3];
|
||||||
float accLPFVel[3];
|
|
||||||
int16_t acc_25deg = 0;
|
int16_t acc_25deg = 0;
|
||||||
int32_t baroPressure = 0;
|
int32_t baroPressure = 0;
|
||||||
int32_t baroTemperature = 0;
|
int32_t baroTemperature = 0;
|
||||||
|
@ -48,8 +47,6 @@ void computeIMU(void)
|
||||||
static uint32_t timeInterleave = 0;
|
static uint32_t timeInterleave = 0;
|
||||||
static int16_t gyroYawSmooth = 0;
|
static int16_t gyroYawSmooth = 0;
|
||||||
|
|
||||||
#define GYRO_INTERLEAVE
|
|
||||||
|
|
||||||
if (sensors(SENSOR_ACC)) {
|
if (sensors(SENSOR_ACC)) {
|
||||||
ACC_getADC();
|
ACC_getADC();
|
||||||
getEstimatedAttitude();
|
getEstimatedAttitude();
|
||||||
|
@ -57,18 +54,11 @@ void computeIMU(void)
|
||||||
|
|
||||||
Gyro_getADC();
|
Gyro_getADC();
|
||||||
|
|
||||||
for (axis = 0; axis < 3; axis++) {
|
for (axis = 0; axis < 3; axis++)
|
||||||
#ifdef GYRO_INTERLEAVE
|
|
||||||
gyroADCp[axis] = gyroADC[axis];
|
gyroADCp[axis] = gyroADC[axis];
|
||||||
#else
|
|
||||||
gyroData[axis] = gyroADC[axis];
|
|
||||||
#endif
|
|
||||||
if (!sensors(SENSOR_ACC))
|
|
||||||
accADC[axis] = 0;
|
|
||||||
}
|
|
||||||
timeInterleave = micros();
|
timeInterleave = micros();
|
||||||
annexCode();
|
annexCode();
|
||||||
#ifdef GYRO_INTERLEAVE
|
|
||||||
if ((micros() - timeInterleave) > 650) {
|
if ((micros() - timeInterleave) > 650) {
|
||||||
annex650_overrun_count++;
|
annex650_overrun_count++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -84,7 +74,6 @@ void computeIMU(void)
|
||||||
if (!sensors(SENSOR_ACC))
|
if (!sensors(SENSOR_ACC))
|
||||||
accADC[axis] = 0;
|
accADC[axis] = 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (feature(FEATURE_GYRO_SMOOTHING)) {
|
if (feature(FEATURE_GYRO_SMOOTHING)) {
|
||||||
static uint8_t Smoothing[3] = { 0, 0, 0 };
|
static uint8_t Smoothing[3] = { 0, 0, 0 };
|
||||||
|
@ -128,12 +117,6 @@ void computeIMU(void)
|
||||||
|
|
||||||
//****** advanced users settings *******************
|
//****** advanced users settings *******************
|
||||||
|
|
||||||
/* Set the Low Pass Filter factor for Magnetometer */
|
|
||||||
/* Increasing this value would reduce Magnetometer noise (not visible in GUI), but would increase Magnetometer lag time*/
|
|
||||||
/* Comment this if you do not want filter at all.*/
|
|
||||||
/* Default WMC value: n/a*/
|
|
||||||
//#define MG_LPF_FACTOR 4
|
|
||||||
|
|
||||||
/* Set the Gyro Weight for Gyro/Magnetometer complementary filter */
|
/* Set the Gyro Weight for Gyro/Magnetometer complementary filter */
|
||||||
/* Increasing this value would reduce and delay Magnetometer influence on the output of the filter*/
|
/* Increasing this value would reduce and delay Magnetometer influence on the output of the filter*/
|
||||||
/* Default WMC value: n/a*/
|
/* Default WMC value: n/a*/
|
||||||
|
@ -142,7 +125,7 @@ void computeIMU(void)
|
||||||
//****** end of advanced users settings *************
|
//****** end of advanced users settings *************
|
||||||
|
|
||||||
#define INV_GYR_CMPF_FACTOR (1.0f / ((float)mcfg.gyro_cmpf_factor + 1.0f))
|
#define INV_GYR_CMPF_FACTOR (1.0f / ((float)mcfg.gyro_cmpf_factor + 1.0f))
|
||||||
#define INV_GYR_CMPFM_FACTOR (1.0f / (GYR_CMPFM_FACTOR + 1.0f))
|
#define INV_GYR_CMPFM_FACTOR (1.0f / ((float)mcfg.gyro_cmpfm_factor + 1.0f))
|
||||||
|
|
||||||
// #define GYRO_SCALE ((1998 * M_PI)/((32767.0f / 4.0f ) * 180.0f * 1000000.0f)) // 32767 / 16.4lsb/dps for MPU3000
|
// #define GYRO_SCALE ((1998 * M_PI)/((32767.0f / 4.0f ) * 180.0f * 1000000.0f)) // 32767 / 16.4lsb/dps for MPU3000
|
||||||
|
|
||||||
|
@ -164,11 +147,6 @@ void rotateV(struct fp_vector *v, float *delta)
|
||||||
{
|
{
|
||||||
struct fp_vector v_tmp = *v;
|
struct fp_vector v_tmp = *v;
|
||||||
|
|
||||||
#if INACCURATE
|
|
||||||
v->Z -= delta[ROLL] * v_tmp.X + delta[PITCH] * v_tmp.Y;
|
|
||||||
v->X += delta[ROLL] * v_tmp.Z - delta[YAW] * v_tmp.Y;
|
|
||||||
v->Y += delta[PITCH] * v_tmp.Z + delta[YAW] * v_tmp.X;
|
|
||||||
#else
|
|
||||||
// This does a "proper" matrix rotation using gyro deltas without small-angle approximation
|
// This does a "proper" matrix rotation using gyro deltas without small-angle approximation
|
||||||
float mat[3][3];
|
float mat[3][3];
|
||||||
float cosx, sinx, cosy, siny, cosz, sinz;
|
float cosx, sinx, cosy, siny, cosz, sinz;
|
||||||
|
@ -200,7 +178,6 @@ void rotateV(struct fp_vector *v, float *delta)
|
||||||
v->X = v_tmp.X * mat[0][0] + v_tmp.Y * mat[1][0] + v_tmp.Z * mat[2][0];
|
v->X = v_tmp.X * mat[0][0] + v_tmp.Y * mat[1][0] + v_tmp.Z * mat[2][0];
|
||||||
v->Y = v_tmp.X * mat[0][1] + v_tmp.Y * mat[1][1] + v_tmp.Z * mat[2][1];
|
v->Y = v_tmp.X * mat[0][1] + v_tmp.Y * mat[1][1] + v_tmp.Z * mat[2][1];
|
||||||
v->Z = v_tmp.X * mat[0][2] + v_tmp.Y * mat[1][2] + v_tmp.Z * mat[2][2];
|
v->Z = v_tmp.X * mat[0][2] + v_tmp.Y * mat[1][2] + v_tmp.Z * mat[2][2];
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int16_t _atan2f(float y, float x)
|
static int16_t _atan2f(float y, float x)
|
||||||
|
@ -209,18 +186,26 @@ static int16_t _atan2f(float y, float x)
|
||||||
return (int16_t)(atan2f(y, x) * (180.0f / M_PI * 10.0f));
|
return (int16_t)(atan2f(y, x) * (180.0f / M_PI * 10.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use original baseflight angle calculation
|
||||||
|
// #define BASEFLIGHT_CALC
|
||||||
|
static float invG;
|
||||||
|
|
||||||
static void getEstimatedAttitude(void)
|
static void getEstimatedAttitude(void)
|
||||||
{
|
{
|
||||||
uint32_t axis;
|
uint32_t axis;
|
||||||
int32_t accMag = 0;
|
int32_t accMag = 0;
|
||||||
static t_fp_vector EstM;
|
static t_fp_vector EstM;
|
||||||
#if defined(MG_LPF_FACTOR)
|
|
||||||
static int16_t mgSmooth[3];
|
|
||||||
#endif
|
|
||||||
static float accLPF[3];
|
static float accLPF[3];
|
||||||
static uint32_t previousT;
|
static uint32_t previousT;
|
||||||
uint32_t currentT = micros();
|
uint32_t currentT = micros();
|
||||||
float scale, deltaGyroAngle[3];
|
float scale, deltaGyroAngle[3];
|
||||||
|
#ifndef BASEFLIGHT_CALC
|
||||||
|
float sqGZ;
|
||||||
|
float sqGX;
|
||||||
|
float sqGY;
|
||||||
|
float sqGX_sqGZ;
|
||||||
|
float invmagXZ;
|
||||||
|
#endif
|
||||||
|
|
||||||
scale = (currentT - previousT) * gyro.scale;
|
scale = (currentT - previousT) * gyro.scale;
|
||||||
previousT = currentT;
|
previousT = currentT;
|
||||||
|
@ -234,17 +219,7 @@ static void getEstimatedAttitude(void)
|
||||||
} else {
|
} else {
|
||||||
accSmooth[axis] = accADC[axis];
|
accSmooth[axis] = accADC[axis];
|
||||||
}
|
}
|
||||||
accLPFVel[axis] = accLPFVel[axis] * (1.0f - (1.0f / cfg.acc_lpf_for_velocity)) + accADC[axis] * (1.0f / cfg.acc_lpf_for_velocity);
|
|
||||||
accMag += (int32_t)accSmooth[axis] * accSmooth[axis];
|
accMag += (int32_t)accSmooth[axis] * accSmooth[axis];
|
||||||
|
|
||||||
if (sensors(SENSOR_MAG)) {
|
|
||||||
#if defined(MG_LPF_FACTOR)
|
|
||||||
mgSmooth[axis] = (mgSmooth[axis] * (MG_LPF_FACTOR - 1) + magADC[axis]) / MG_LPF_FACTOR; // LPF for Magnetometer values
|
|
||||||
#define MAG_VALUE mgSmooth[axis]
|
|
||||||
#else
|
|
||||||
#define MAG_VALUE magADC[axis]
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
accMag = accMag * 100 / ((int32_t)acc_1G * acc_1G);
|
accMag = accMag * 100 / ((int32_t)acc_1G * acc_1G);
|
||||||
|
|
||||||
|
@ -258,35 +233,39 @@ static void getEstimatedAttitude(void)
|
||||||
f.SMALL_ANGLES_25 = 0;
|
f.SMALL_ANGLES_25 = 0;
|
||||||
|
|
||||||
// Apply complimentary filter (Gyro drift correction)
|
// Apply complimentary filter (Gyro drift correction)
|
||||||
// If accel magnitude >1.4G or <0.6G and ACC vector outside of the limit range => we neutralize the effect of accelerometers in the angle estimation.
|
// If accel magnitude >1.15G or <0.85G and ACC vector outside of the limit range => we neutralize the effect of accelerometers in the angle estimation.
|
||||||
// To do that, we just skip filter, as EstV already rotated by Gyro
|
// To do that, we just skip filter, as EstV already rotated by Gyro
|
||||||
if ((36 < accMag && accMag < 196) || f.SMALL_ANGLES_25) {
|
if (72 < accMag && accMag < 133) {
|
||||||
for (axis = 0; axis < 3; axis++)
|
for (axis = 0; axis < 3; axis++)
|
||||||
EstG.A[axis] = (EstG.A[axis] * (float)mcfg.gyro_cmpf_factor + accSmooth[axis]) * INV_GYR_CMPF_FACTOR;
|
EstG.A[axis] = (EstG.A[axis] * (float)mcfg.gyro_cmpf_factor + accSmooth[axis]) * INV_GYR_CMPF_FACTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sensors(SENSOR_MAG)) {
|
if (sensors(SENSOR_MAG)) {
|
||||||
for (axis = 0; axis < 3; axis++)
|
for (axis = 0; axis < 3; axis++)
|
||||||
EstM.A[axis] = (EstM.A[axis] * GYR_CMPFM_FACTOR + MAG_VALUE) * INV_GYR_CMPFM_FACTOR;
|
EstM.A[axis] = (EstM.A[axis] * (float)mcfg.gyro_cmpfm_factor + magADC[axis]) * INV_GYR_CMPFM_FACTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attitude of the estimated vector
|
// Attitude of the estimated vector
|
||||||
#if INACCURATE
|
#ifdef BASEFLIGHT_CALC
|
||||||
angle[ROLL] = _atan2f(EstG.V.X, EstG.V.Z);
|
|
||||||
angle[PITCH] = _atan2f(EstG.V.Y, EstG.V.Z);
|
|
||||||
#else
|
|
||||||
// This hack removes gimbal lock (sorta) on pitch, so rolling around doesn't make pitch jump when roll reaches 90deg
|
// This hack removes gimbal lock (sorta) on pitch, so rolling around doesn't make pitch jump when roll reaches 90deg
|
||||||
angle[ROLL] = _atan2f(EstG.V.X, EstG.V.Z);
|
angle[ROLL] = _atan2f(EstG.V.X, EstG.V.Z);
|
||||||
angle[PITCH] = -asinf(EstG.V.Y / -sqrtf(EstG.V.X * EstG.V.X + EstG.V.Y * EstG.V.Y + EstG.V.Z * EstG.V.Z)) * (180.0f / M_PI * 10.0f);
|
angle[PITCH] = -asinf(EstG.V.Y / -sqrtf(EstG.V.X * EstG.V.X + EstG.V.Y * EstG.V.Y + EstG.V.Z * EstG.V.Z)) * (180.0f / M_PI * 10.0f);
|
||||||
|
#else
|
||||||
|
// MW2.2 version
|
||||||
|
sqGZ = EstG.V.Z * EstG.V.Z;
|
||||||
|
sqGX = EstG.V.X * EstG.V.X;
|
||||||
|
sqGY = EstG.V.Y * EstG.V.Y;
|
||||||
|
sqGX_sqGZ = sqGX + sqGZ;
|
||||||
|
invmagXZ = 1.0f / sqrtf(sqGX_sqGZ);
|
||||||
|
invG = 1.0f / sqrtf(sqGX_sqGZ + sqGY);
|
||||||
|
angle[ROLL] = _atan2f(EstG.V.X, EstG.V.Z);
|
||||||
|
angle[PITCH] = _atan2f(EstG.V.Y, invmagXZ * sqGX_sqGZ);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MAG
|
#ifdef MAG
|
||||||
if (sensors(SENSOR_MAG)) {
|
if (sensors(SENSOR_MAG)) {
|
||||||
#if INACCURATE
|
#ifdef BASEFLIGHT_CALC
|
||||||
heading = _atan2f(EstG.V.X * EstM.V.Z - EstG.V.Z * EstM.V.X, EstG.V.Z * EstM.V.Y - EstG.V.Y * EstM.V.Z);
|
// baseflight calculation
|
||||||
heading = heading + magneticDeclination;
|
|
||||||
heading = heading / 10;
|
|
||||||
#else
|
|
||||||
float rollRAD = (float)angle[ROLL] * RADX10;
|
float rollRAD = (float)angle[ROLL] * RADX10;
|
||||||
float pitchRAD = -(float)angle[PITCH] * RADX10;
|
float pitchRAD = -(float)angle[PITCH] * RADX10;
|
||||||
float magX = EstM.A[1]; // Swap X/Y
|
float magX = EstM.A[1]; // Swap X/Y
|
||||||
|
@ -300,6 +279,11 @@ static void getEstimatedAttitude(void)
|
||||||
float Yh = magY * cr - magZ * sr;
|
float Yh = magY * cr - magZ * sr;
|
||||||
float hd = (atan2f(-Yh, Xh) * 1800.0f / M_PI + magneticDeclination) / 10.0f;
|
float hd = (atan2f(-Yh, Xh) * 1800.0f / M_PI + magneticDeclination) / 10.0f;
|
||||||
heading = hd;
|
heading = hd;
|
||||||
|
#else
|
||||||
|
// MW 2.2 calculation
|
||||||
|
heading = _atan2f(EstM.V.Z * EstG.V.X - EstM.V.X * EstG.V.Z, EstM.V.Y * invG * sqGX_sqGZ - (EstM.V.X * EstG.V.X + EstM.V.Z * EstG.V.Z) * invG * EstG.V.Y);
|
||||||
|
heading = heading + magneticDeclination;
|
||||||
|
heading = heading / 10;
|
||||||
#endif
|
#endif
|
||||||
if (heading > 180)
|
if (heading > 180)
|
||||||
heading = heading - 360;
|
heading = heading - 360;
|
||||||
|
@ -313,7 +297,7 @@ static void getEstimatedAttitude(void)
|
||||||
#define UPDATE_INTERVAL 25000 // 40hz update rate (20hz LPF on acc)
|
#define UPDATE_INTERVAL 25000 // 40hz update rate (20hz LPF on acc)
|
||||||
#define INIT_DELAY 4000000 // 4 sec initialization delay
|
#define INIT_DELAY 4000000 // 4 sec initialization delay
|
||||||
|
|
||||||
int16_t applyDeadband16(int16_t value, int16_t deadband)
|
int16_t applyDeadband(int16_t value, int16_t deadband)
|
||||||
{
|
{
|
||||||
if (abs(value) < deadband) {
|
if (abs(value) < deadband) {
|
||||||
value = 0;
|
value = 0;
|
||||||
|
@ -325,54 +309,16 @@ int16_t applyDeadband16(int16_t value, int16_t deadband)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
float applyDeadbandFloat(float value, int16_t deadband)
|
|
||||||
{
|
|
||||||
if (abs(value) < deadband) {
|
|
||||||
value = 0;
|
|
||||||
} else if (value > 0) {
|
|
||||||
value -= deadband;
|
|
||||||
} else if (value < 0) {
|
|
||||||
value += deadband;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
float InvSqrt(float x)
|
|
||||||
{
|
|
||||||
union {
|
|
||||||
int32_t i;
|
|
||||||
float f;
|
|
||||||
} conv;
|
|
||||||
conv.f = x;
|
|
||||||
conv.i = 0x5f3759df - (conv.i >> 1);
|
|
||||||
return 0.5f * conv.f * (3.0f - x * conv.f * conv.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t isq(int32_t x)
|
|
||||||
{
|
|
||||||
return x * x;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define applyDeadband(value, deadband) \
|
|
||||||
if(abs(value) < deadband) { \
|
|
||||||
value = 0; \
|
|
||||||
} else if(value > 0){ \
|
|
||||||
value -= deadband; \
|
|
||||||
} else if(value < 0){ \
|
|
||||||
value += deadband; \
|
|
||||||
}
|
|
||||||
|
|
||||||
int getEstimatedAltitude(void)
|
int getEstimatedAltitude(void)
|
||||||
{
|
{
|
||||||
static int32_t baroGroundPressure;
|
static int32_t baroGroundPressure;
|
||||||
static uint16_t previousT;
|
static uint32_t previousT;
|
||||||
uint16_t currentT = micros();
|
uint32_t currentT = micros();
|
||||||
uint16_t dTime;
|
uint32_t dTime;
|
||||||
float invG;
|
|
||||||
int16_t error16;
|
int16_t error16;
|
||||||
int16_t baroVel;
|
int16_t baroVel;
|
||||||
int16_t accZ;
|
int16_t accZ;
|
||||||
static int16_t accZoffset = 0; // = acc_1G*6; //58 bytes saved and convergence is fast enough to omit init
|
static int16_t accZoffset = 0;
|
||||||
static float vel = 0.0f;
|
static float vel = 0.0f;
|
||||||
static int32_t lastBaroAlt;
|
static int32_t lastBaroAlt;
|
||||||
int16_t vel_tmp;
|
int16_t vel_tmp;
|
||||||
|
@ -390,12 +336,12 @@ int getEstimatedAltitude(void)
|
||||||
// pressure relative to ground pressure with temperature compensation (fast!)
|
// pressure relative to ground pressure with temperature compensation (fast!)
|
||||||
// baroGroundPressure is not supposed to be 0 here
|
// baroGroundPressure is not supposed to be 0 here
|
||||||
// see: https://code.google.com/p/ardupilot-mega/source/browse/libraries/AP_Baro/AP_Baro.cpp
|
// see: https://code.google.com/p/ardupilot-mega/source/browse/libraries/AP_Baro/AP_Baro.cpp
|
||||||
BaroAlt = log(baroGroundPressure * (cfg.baro_tab_size - 1) / (float)baroPressureSum) * (baroTemperature + 27315) * 29.271267f; // in cemtimeter
|
BaroAlt = logf(baroGroundPressure * (cfg.baro_tab_size - 1) / (float)baroPressureSum) * (baroTemperature + 27315) * 29.271267f; // in cemtimeter
|
||||||
EstAlt = (EstAlt * 6 + BaroAlt * 2) >> 3; // additional LPF to reduce baro noise
|
EstAlt = (EstAlt * 6 + BaroAlt * 2) >> 3; // additional LPF to reduce baro noise
|
||||||
|
|
||||||
//P
|
//P
|
||||||
error16 = constrain(AltHold - EstAlt, -300, 300);
|
error16 = constrain(AltHold - EstAlt, -300, 300);
|
||||||
applyDeadband(error16, 10); // remove small P parametr to reduce noise near zero position
|
error16 = applyDeadband(error16, 10); // remove small P parametr to reduce noise near zero position
|
||||||
BaroPID = constrain((cfg.P8[PIDALT] * error16 >> 7), -150, +150);
|
BaroPID = constrain((cfg.P8[PIDALT] * error16 >> 7), -150, +150);
|
||||||
|
|
||||||
//I
|
//I
|
||||||
|
@ -404,8 +350,7 @@ int getEstimatedAltitude(void)
|
||||||
BaroPID += errorAltitudeI >> 9; // I in range +/-60
|
BaroPID += errorAltitudeI >> 9; // I in range +/-60
|
||||||
|
|
||||||
// projection of ACC vector to global Z, with 1G subtructed
|
// projection of ACC vector to global Z, with 1G subtructed
|
||||||
// Math: accZ = A * G / |G| - 1G
|
// Math: accZ = A * G / |G| - 1G (invG is calculated in getEstimatedAttitude)
|
||||||
invG = InvSqrt(isq(EstG.V.X) + isq(EstG.V.Y) + isq(EstG.V.Z));
|
|
||||||
accZ = (accSmooth[ROLL] * EstG.V.X + accSmooth[PITCH] * EstG.V.Y + accSmooth[YAW] * EstG.V.Z) * invG;
|
accZ = (accSmooth[ROLL] * EstG.V.X + accSmooth[PITCH] * EstG.V.Y + accSmooth[YAW] * EstG.V.Z) * invG;
|
||||||
|
|
||||||
if (!f.ARMED) {
|
if (!f.ARMED) {
|
||||||
|
@ -413,7 +358,7 @@ int getEstimatedAltitude(void)
|
||||||
accZoffset += accZ;
|
accZoffset += accZ;
|
||||||
}
|
}
|
||||||
accZ -= accZoffset >> 3;
|
accZ -= accZoffset >> 3;
|
||||||
applyDeadband(accZ, cfg.accz_deadband);
|
accZ = applyDeadband(accZ, cfg.accz_deadband);
|
||||||
|
|
||||||
// Integrator - velocity, cm/sec
|
// Integrator - velocity, cm/sec
|
||||||
vel += accZ * accVelScale * dTime;
|
vel += accZ * accVelScale * dTime;
|
||||||
|
@ -422,7 +367,7 @@ int getEstimatedAltitude(void)
|
||||||
lastBaroAlt = EstAlt;
|
lastBaroAlt = EstAlt;
|
||||||
|
|
||||||
baroVel = constrain(baroVel, -300, 300); // constrain baro velocity +/- 300cm/s
|
baroVel = constrain(baroVel, -300, 300); // constrain baro velocity +/- 300cm/s
|
||||||
applyDeadband(baroVel, 10); // to reduce noise near zero
|
baroVel = applyDeadband(baroVel, 10); // to reduce noise near zero
|
||||||
|
|
||||||
// apply Complimentary Filter to keep the calculated velocity based on baro velocity (i.e. near real velocity).
|
// apply Complimentary Filter to keep the calculated velocity based on baro velocity (i.e. near real velocity).
|
||||||
// By using CF it's possible to correct the drift of integrated accZ (velocity) without loosing the phase, i.e without delay
|
// By using CF it's possible to correct the drift of integrated accZ (velocity) without loosing the phase, i.e without delay
|
||||||
|
@ -430,7 +375,7 @@ int getEstimatedAltitude(void)
|
||||||
|
|
||||||
// D
|
// D
|
||||||
vel_tmp = vel;
|
vel_tmp = vel;
|
||||||
applyDeadband(vel_tmp, 5);
|
vel_tmp = applyDeadband(vel_tmp, 5);
|
||||||
vario = vel_tmp;
|
vario = vel_tmp;
|
||||||
BaroPID -= constrain(cfg.D8[PIDALT] * vel_tmp >> 4, -150, 150);
|
BaroPID -= constrain(cfg.D8[PIDALT] * vel_tmp >> 4, -150, 150);
|
||||||
|
|
||||||
|
|
26
src/main.c
26
src/main.c
|
@ -7,12 +7,23 @@ extern rcReadRawDataPtr rcReadRawFunc;
|
||||||
// two receiver read functions
|
// two receiver read functions
|
||||||
extern uint16_t pwmReadRawRC(uint8_t chan);
|
extern uint16_t pwmReadRawRC(uint8_t chan);
|
||||||
extern uint16_t spektrumReadRawRC(uint8_t chan);
|
extern uint16_t spektrumReadRawRC(uint8_t chan);
|
||||||
|
|
||||||
|
#ifdef USE_LAME_PRINTF
|
||||||
|
// gcc/GNU version
|
||||||
static void _putc(void *p, char c)
|
static void _putc(void *p, char c)
|
||||||
{
|
{
|
||||||
uartWrite(c);
|
uartWrite(c);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
// keil/armcc version
|
||||||
|
int fputc(int c, FILE *f)
|
||||||
|
{
|
||||||
|
// let DMA catch up a bit when using set or dump, we're too fast.
|
||||||
|
while (!uartTransmitDMAEmpty());
|
||||||
|
uartWrite(c);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
@ -41,8 +52,10 @@ int main(void)
|
||||||
GPIOB->CRL = 0x44433444; // PIN 4 & 3 Output 50MHz
|
GPIOB->CRL = 0x44433444; // PIN 4 & 3 Output 50MHz
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
systemInit();
|
systemInit();
|
||||||
init_printf(NULL, _putc);
|
#ifdef USE_LAME_PRINTF
|
||||||
|
init_printf(NULL, _putc);
|
||||||
|
#endif
|
||||||
|
|
||||||
checkFirstTime(false);
|
checkFirstTime(false);
|
||||||
readEEPROM();
|
readEEPROM();
|
||||||
|
@ -72,7 +85,8 @@ int main(void)
|
||||||
pwm_params.useServos = useServo;
|
pwm_params.useServos = useServo;
|
||||||
pwm_params.extraServos = cfg.gimbal_flags & GIMBAL_FORWARDAUX;
|
pwm_params.extraServos = cfg.gimbal_flags & GIMBAL_FORWARDAUX;
|
||||||
pwm_params.motorPwmRate = mcfg.motor_pwm_rate;
|
pwm_params.motorPwmRate = mcfg.motor_pwm_rate;
|
||||||
pwm_params.servoPwmRate = mcfg.servo_pwm_rate;
|
pwm_params.servoPwmRate = mcfg.servo_pwm_rate;
|
||||||
|
pwm_params.failsafeThreshold = cfg.failsafe_detect_threshold;
|
||||||
switch (mcfg.power_adc_channel) {
|
switch (mcfg.power_adc_channel) {
|
||||||
case 1:
|
case 1:
|
||||||
pwm_params.adcChannel = PWM2;
|
pwm_params.adcChannel = PWM2;
|
||||||
|
|
229
src/mw.c
229
src/mw.c
|
@ -1,7 +1,7 @@
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "mw.h"
|
#include "mw.h"
|
||||||
|
|
||||||
// October 2012 V2.1-dev
|
// June 2013 V2.2-dev
|
||||||
|
|
||||||
flags_t f;
|
flags_t f;
|
||||||
int16_t debug[4];
|
int16_t debug[4];
|
||||||
|
@ -24,6 +24,10 @@ int16_t lookupThrottleRC[11]; // lookup table for expo & mid THROTTLE
|
||||||
uint16_t rssi; // range: [0;1023]
|
uint16_t rssi; // range: [0;1023]
|
||||||
rcReadRawDataPtr rcReadRawFunc = NULL; // receive data from default (pwm/ppm) or additional (spek/sbus/?? receiver drivers)
|
rcReadRawDataPtr rcReadRawFunc = NULL; // receive data from default (pwm/ppm) or additional (spek/sbus/?? receiver drivers)
|
||||||
|
|
||||||
|
static void pidMultiWii(void);
|
||||||
|
static void pidRewrite(void);
|
||||||
|
pidControllerFuncPtr pid_controller = pidMultiWii; // which pid controller are we using, defaultMultiWii
|
||||||
|
|
||||||
uint8_t dynP8[3], dynI8[3], dynD8[3];
|
uint8_t dynP8[3], dynI8[3], dynD8[3];
|
||||||
uint8_t rcOptions[CHECKBOXITEMS];
|
uint8_t rcOptions[CHECKBOXITEMS];
|
||||||
|
|
||||||
|
@ -44,12 +48,17 @@ int16_t GPS_angle[2] = { 0, 0 }; // it's the angles that must be applied for
|
||||||
uint16_t GPS_ground_course = 0; // degrees * 10
|
uint16_t GPS_ground_course = 0; // degrees * 10
|
||||||
uint8_t GPS_Present = 0; // Checksum from Gps serial
|
uint8_t GPS_Present = 0; // Checksum from Gps serial
|
||||||
uint8_t GPS_Enable = 0;
|
uint8_t GPS_Enable = 0;
|
||||||
int16_t nav[2];
|
int16_t nav[2];
|
||||||
int16_t nav_rated[2]; // Adding a rate controller to the navigation to make it smoother
|
int16_t nav_rated[2]; // Adding a rate controller to the navigation to make it smoother
|
||||||
int8_t nav_mode = NAV_MODE_NONE; // Navigation mode
|
int8_t nav_mode = NAV_MODE_NONE; // Navigation mode
|
||||||
|
uint8_t GPS_numCh; // Number of channels
|
||||||
// Automatic ACC Offset Calibration
|
uint8_t GPS_svinfo_chn[16]; // Channel number
|
||||||
uint16_t InflightcalibratingA = 0;
|
uint8_t GPS_svinfo_svid[16]; // Satellite ID
|
||||||
|
uint8_t GPS_svinfo_quality[16]; // Bitfield Qualtity
|
||||||
|
uint8_t GPS_svinfo_cno[16]; // Carrier to Noise Ratio (Signal Strength)
|
||||||
|
|
||||||
|
// Automatic ACC Offset Calibration
|
||||||
|
uint16_t InflightcalibratingA = 0;
|
||||||
int16_t AccInflightCalibrationArmed;
|
int16_t AccInflightCalibrationArmed;
|
||||||
uint16_t AccInflightCalibrationMeasurementDone = 0;
|
uint16_t AccInflightCalibrationMeasurementDone = 0;
|
||||||
uint16_t AccInflightCalibrationSavetoEEProm = 0;
|
uint16_t AccInflightCalibrationSavetoEEProm = 0;
|
||||||
|
@ -127,6 +136,7 @@ void annexCode(void)
|
||||||
prop1 = 100 - (uint16_t) cfg.yawRate * tmp / 500;
|
prop1 = 100 - (uint16_t) cfg.yawRate * tmp / 500;
|
||||||
}
|
}
|
||||||
dynP8[axis] = (uint16_t) cfg.P8[axis] * prop1 / 100;
|
dynP8[axis] = (uint16_t) cfg.P8[axis] * prop1 / 100;
|
||||||
|
dynI8[axis] = (uint16_t) cfg.I8[axis] * prop1 / 100;
|
||||||
dynD8[axis] = (uint16_t) cfg.D8[axis] * prop1 / 100;
|
dynD8[axis] = (uint16_t) cfg.D8[axis] * prop1 / 100;
|
||||||
if (rcData[axis] < mcfg.midrc)
|
if (rcData[axis] < mcfg.midrc)
|
||||||
rcCommand[axis] = -rcCommand[axis];
|
rcCommand[axis] = -rcCommand[axis];
|
||||||
|
@ -268,24 +278,160 @@ static void mwVario(void)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t errorGyroI[3] = { 0, 0, 0 };
|
||||||
|
static int32_t errorAngleI[2] = { 0, 0 };
|
||||||
|
|
||||||
|
static void pidMultiWii(void)
|
||||||
|
{
|
||||||
|
int axis, prop;
|
||||||
|
int32_t error, errorAngle;
|
||||||
|
int32_t PTerm, ITerm, PTermACC, ITermACC = 0, PTermGYRO = 0, ITermGYRO = 0, DTerm;
|
||||||
|
static int16_t lastGyro[3] = { 0, 0, 0 };
|
||||||
|
static int32_t delta1[3], delta2[3];
|
||||||
|
int32_t deltaSum;
|
||||||
|
int32_t delta;
|
||||||
|
|
||||||
|
// **** PITCH & ROLL & YAW PID ****
|
||||||
|
prop = max(abs(rcCommand[PITCH]), abs(rcCommand[ROLL])); // range [0;500]
|
||||||
|
for (axis = 0; axis < 3; axis++) {
|
||||||
|
if ((f.ANGLE_MODE || f.HORIZON_MODE) && axis < 2) { // MODE relying on ACC
|
||||||
|
// 50 degrees max inclination
|
||||||
|
errorAngle = constrain(2 * rcCommand[axis] + GPS_angle[axis], -500, +500) - angle[axis] + cfg.angleTrim[axis];
|
||||||
|
PTermACC = errorAngle * cfg.P8[PIDLEVEL] / 100; // 32 bits is needed for calculation: errorAngle*P8[PIDLEVEL] could exceed 32768 16 bits is ok for result
|
||||||
|
PTermACC = constrain(PTermACC, -cfg.D8[PIDLEVEL] * 5, +cfg.D8[PIDLEVEL] * 5);
|
||||||
|
|
||||||
|
errorAngleI[axis] = constrain(errorAngleI[axis] + errorAngle, -10000, +10000); // WindUp
|
||||||
|
ITermACC = (errorAngleI[axis] * cfg.I8[PIDLEVEL]) >> 12;
|
||||||
|
}
|
||||||
|
if (!f.ANGLE_MODE || f.HORIZON_MODE || axis == 2) { // MODE relying on GYRO or YAW axis
|
||||||
|
error = (int32_t)rcCommand[axis] * 10 * 8 / cfg.P8[axis];
|
||||||
|
error -= gyroData[axis];
|
||||||
|
|
||||||
|
PTermGYRO = rcCommand[axis];
|
||||||
|
|
||||||
|
errorGyroI[axis] = constrain(errorGyroI[axis] + error, -16000, +16000); // WindUp
|
||||||
|
if (abs(gyroData[axis]) > 640)
|
||||||
|
errorGyroI[axis] = 0;
|
||||||
|
ITermGYRO = (errorGyroI[axis] / 125 * cfg.I8[axis]) >> 6;
|
||||||
|
}
|
||||||
|
if (f.HORIZON_MODE && axis < 2) {
|
||||||
|
PTerm = (PTermACC * (500 - prop) + PTermGYRO * prop) / 500;
|
||||||
|
ITerm = (ITermACC * (500 - prop) + ITermGYRO * prop) / 500;
|
||||||
|
} else {
|
||||||
|
if (f.ANGLE_MODE && axis < 2) {
|
||||||
|
PTerm = PTermACC;
|
||||||
|
ITerm = ITermACC;
|
||||||
|
} else {
|
||||||
|
PTerm = PTermGYRO;
|
||||||
|
ITerm = ITermGYRO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PTerm -= (int32_t)gyroData[axis] * dynP8[axis] / 10 / 8; // 32 bits is needed for calculation
|
||||||
|
delta = gyroData[axis] - lastGyro[axis];
|
||||||
|
lastGyro[axis] = gyroData[axis];
|
||||||
|
deltaSum = delta1[axis] + delta2[axis] + delta;
|
||||||
|
delta2[axis] = delta1[axis];
|
||||||
|
delta1[axis] = delta;
|
||||||
|
DTerm = (deltaSum * dynD8[axis]) / 32;
|
||||||
|
axisPID[axis] = PTerm + ITerm - DTerm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GYRO_I_MAX 256
|
||||||
|
|
||||||
|
static void pidRewrite(void)
|
||||||
|
{
|
||||||
|
int32_t errorAngle;
|
||||||
|
int axis;
|
||||||
|
int32_t delta, deltaSum;
|
||||||
|
static int32_t delta1[3], delta2[3];
|
||||||
|
int32_t PTerm, ITerm, DTerm;
|
||||||
|
static int32_t lastError[3] = { 0, 0, 0 };
|
||||||
|
int32_t AngleRateTmp, RateError;
|
||||||
|
|
||||||
|
// ----------PID controller----------
|
||||||
|
for (axis = 0; axis < 3; axis++) {
|
||||||
|
// -----Get the desired angle rate depending on flight mode
|
||||||
|
if ((f.ANGLE_MODE || f.HORIZON_MODE) && axis < 2 ) { // MODE relying on ACC
|
||||||
|
// calculate error and limit the angle to 50 degrees max inclination
|
||||||
|
errorAngle = constrain((rcCommand[axis] << 1) + GPS_angle[axis], -500, +500) - angle[axis] + cfg.angleTrim[axis]; // 16 bits is ok here
|
||||||
|
}
|
||||||
|
if (axis == 2) { // YAW is always gyro-controlled (MAG correction is applied to rcCommand)
|
||||||
|
AngleRateTmp = (((int32_t)(cfg.yawRate + 27) * rcCommand[2]) >> 5);
|
||||||
|
} else {
|
||||||
|
if (!f.ANGLE_MODE) { //control is GYRO based (ACRO and HORIZON - direct sticks control is applied to rate PID
|
||||||
|
AngleRateTmp = ((int32_t) (cfg.rollPitchRate + 27) * rcCommand[axis]) >> 4;
|
||||||
|
if (f.HORIZON_MODE) {
|
||||||
|
// mix up angle error to desired AngleRateTmp to add a little auto-level feel
|
||||||
|
AngleRateTmp += (errorAngle * cfg.I8[PIDLEVEL]) >> 8;
|
||||||
|
}
|
||||||
|
} else { // it's the ANGLE mode - control is angle based, so control loop is needed
|
||||||
|
AngleRateTmp = (errorAngle * cfg.P8[PIDLEVEL]) >> 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------low-level gyro-based PID. ----------
|
||||||
|
// Used in stand-alone mode for ACRO, controlled by higher level regulators in other modes
|
||||||
|
// -----calculate scaled error.AngleRates
|
||||||
|
// multiplication of rcCommand corresponds to changing the sticks scaling here
|
||||||
|
RateError = AngleRateTmp - gyroData[axis];
|
||||||
|
|
||||||
|
// -----calculate P component
|
||||||
|
PTerm = (RateError * cfg.P8[axis]) >> 7;
|
||||||
|
// -----calculate I component
|
||||||
|
// there should be no division before accumulating the error to integrator, because the precision would be reduced.
|
||||||
|
// Precision is critical, as I prevents from long-time drift. Thus, 32 bits integrator is used.
|
||||||
|
// Time correction (to avoid different I scaling for different builds based on average cycle time)
|
||||||
|
// is normalized to cycle time = 2048.
|
||||||
|
errorGyroI[axis] = errorGyroI[axis] + ((RateError * cycleTime) >> 11) * cfg.I8[axis];
|
||||||
|
|
||||||
|
// limit maximum integrator value to prevent WindUp - accumulating extreme values when system is saturated.
|
||||||
|
// I coefficient (I8) moved before integration to make limiting independent from PID settings
|
||||||
|
errorGyroI[axis] = constrain(errorGyroI[axis], (int32_t)-GYRO_I_MAX << 13, (int32_t)+GYRO_I_MAX << 13);
|
||||||
|
ITerm = errorGyroI[axis] >> 13;
|
||||||
|
|
||||||
|
//-----calculate D-term
|
||||||
|
delta = RateError - lastError[axis]; // 16 bits is ok here, the dif between 2 consecutive gyro reads is limited to 800
|
||||||
|
lastError[axis] = RateError;
|
||||||
|
|
||||||
|
// Correct difference by cycle time. Cycle time is jittery (can be different 2 times), so calculated difference
|
||||||
|
// would be scaled by different dt each time. Division by dT fixes that.
|
||||||
|
delta = (delta * ((uint16_t)0xFFFF / (cycleTime >> 4))) >> 6;
|
||||||
|
// add moving average here to reduce noise
|
||||||
|
deltaSum = delta1[axis] + delta2[axis] + delta;
|
||||||
|
delta2[axis] = delta1[axis];
|
||||||
|
delta1[axis] = delta;
|
||||||
|
DTerm = (deltaSum * cfg.D8[axis]) >> 8;
|
||||||
|
|
||||||
|
// -----calculate total PID output
|
||||||
|
axisPID[axis] = PTerm + ITerm + DTerm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPIDController(int type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
pid_controller = pidMultiWii;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
pid_controller = pidRewrite;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void loop(void)
|
void loop(void)
|
||||||
{
|
{
|
||||||
static uint8_t rcDelayCommand; // this indicates the number of time (multiple of RC measurement at 50Hz) the sticks must be maintained to run or switch off motors
|
static uint8_t rcDelayCommand; // this indicates the number of time (multiple of RC measurement at 50Hz) the sticks must be maintained to run or switch off motors
|
||||||
static uint8_t rcSticks; // this hold sticks position for command combos
|
static uint8_t rcSticks; // this hold sticks position for command combos
|
||||||
uint8_t stTmp = 0;
|
uint8_t stTmp = 0;
|
||||||
uint8_t axis, i;
|
int i;
|
||||||
int16_t error, errorAngle;
|
|
||||||
int16_t delta, deltaSum;
|
|
||||||
int16_t PTerm, ITerm, PTermACC, ITermACC = 0, PTermGYRO = 0, ITermGYRO = 0, DTerm;
|
|
||||||
static int16_t lastGyro[3] = { 0, 0, 0 };
|
|
||||||
static int16_t delta1[3], delta2[3];
|
|
||||||
static int16_t errorGyroI[3] = { 0, 0, 0 };
|
|
||||||
static int16_t errorAngleI[2] = { 0, 0 };
|
|
||||||
static uint32_t rcTime = 0;
|
static uint32_t rcTime = 0;
|
||||||
static int16_t initialThrottleHold;
|
static int16_t initialThrottleHold;
|
||||||
static uint32_t loopTime;
|
static uint32_t loopTime;
|
||||||
uint16_t auxState = 0;
|
uint16_t auxState = 0;
|
||||||
int16_t prop;
|
|
||||||
static uint8_t GPSNavReset = 1;
|
static uint8_t GPSNavReset = 1;
|
||||||
|
|
||||||
// this will return false if spektrum is disabled. shrug.
|
// this will return false if spektrum is disabled. shrug.
|
||||||
|
@ -423,7 +569,7 @@ void loop(void)
|
||||||
i = 1;
|
i = 1;
|
||||||
}
|
}
|
||||||
if (i) {
|
if (i) {
|
||||||
writeEEPROM(1, false);
|
writeEEPROM(1, true);
|
||||||
rcDelayCommand = 0; // allow autorepetition
|
rcDelayCommand = 0; // allow autorepetition
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -697,53 +843,8 @@ void loop(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// **** PITCH & ROLL & YAW PID ****
|
// PID - note this is function pointer set by setPIDController()
|
||||||
prop = max(abs(rcCommand[PITCH]), abs(rcCommand[ROLL])); // range [0;500]
|
pid_controller();
|
||||||
for (axis = 0; axis < 3; axis++) {
|
|
||||||
if ((f.ANGLE_MODE || f.HORIZON_MODE) && axis < 2) { // MODE relying on ACC
|
|
||||||
// 50 degrees max inclination
|
|
||||||
errorAngle = constrain(2 * rcCommand[axis] + GPS_angle[axis], -500, +500) - angle[axis] + cfg.angleTrim[axis];
|
|
||||||
PTermACC = (int32_t)errorAngle * cfg.P8[PIDLEVEL] / 100; // 32 bits is needed for calculation: errorAngle*P8[PIDLEVEL] could exceed 32768 16 bits is ok for result
|
|
||||||
PTermACC = constrain(PTermACC, -cfg.D8[PIDLEVEL] * 5, +cfg.D8[PIDLEVEL] * 5);
|
|
||||||
|
|
||||||
errorAngleI[axis] = constrain(errorAngleI[axis] + errorAngle, -10000, +10000); // WindUp
|
|
||||||
ITermACC = ((int32_t)errorAngleI[axis] * cfg.I8[PIDLEVEL]) >> 12;
|
|
||||||
}
|
|
||||||
if (!f.ANGLE_MODE || f.HORIZON_MODE || axis == 2) { // MODE relying on GYRO or YAW axis
|
|
||||||
error = (int32_t)rcCommand[axis] * 10 * 8 / cfg.P8[axis];
|
|
||||||
error -= gyroData[axis];
|
|
||||||
|
|
||||||
PTermGYRO = rcCommand[axis];
|
|
||||||
|
|
||||||
errorGyroI[axis] = constrain(errorGyroI[axis] + error, -16000, +16000); // WindUp
|
|
||||||
if (abs(gyroData[axis]) > 640)
|
|
||||||
errorGyroI[axis] = 0;
|
|
||||||
ITermGYRO = (errorGyroI[axis] / 125 * cfg.I8[axis]) >> 6;
|
|
||||||
}
|
|
||||||
if (f.HORIZON_MODE && axis < 2) {
|
|
||||||
PTerm = ((int32_t)PTermACC * (500 - prop) + (int32_t)PTermGYRO * prop) / 500;
|
|
||||||
ITerm = ((int32_t)ITermACC * (500 - prop) + (int32_t)ITermGYRO * prop) / 500;
|
|
||||||
} else {
|
|
||||||
if (f.ANGLE_MODE && axis < 2) {
|
|
||||||
PTerm = PTermACC;
|
|
||||||
ITerm = ITermACC;
|
|
||||||
} else {
|
|
||||||
PTerm = PTermGYRO;
|
|
||||||
ITerm = ITermGYRO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PTerm -= (int32_t)gyroData[axis] * dynP8[axis] / 10 / 8; // 32 bits is needed for calculation
|
|
||||||
|
|
||||||
delta = gyroData[axis] - lastGyro[axis]; // 16 bits is ok here, the dif between 2 consecutive gyro reads is limited to 800
|
|
||||||
lastGyro[axis] = gyroData[axis];
|
|
||||||
deltaSum = delta1[axis] + delta2[axis] + delta;
|
|
||||||
delta2[axis] = delta1[axis];
|
|
||||||
delta1[axis] = delta;
|
|
||||||
|
|
||||||
DTerm = ((int32_t)deltaSum * dynD8[axis]) >> 5; // 32 bits is needed for calculation
|
|
||||||
axisPID[axis] = PTerm + ITerm - DTerm;
|
|
||||||
}
|
|
||||||
|
|
||||||
mixTable();
|
mixTable();
|
||||||
writeServos();
|
writeServos();
|
||||||
|
|
22
src/mw.h
22
src/mw.h
|
@ -145,6 +145,7 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct config_t {
|
typedef struct config_t {
|
||||||
|
uint8_t pidController; // 0 = multiwii original, 1 = rewrite from http://www.multiwii.com/forum/viewtopic.php?f=8&t=3671
|
||||||
uint8_t P8[PIDITEMS];
|
uint8_t P8[PIDITEMS];
|
||||||
uint8_t I8[PIDITEMS];
|
uint8_t I8[PIDITEMS];
|
||||||
uint8_t D8[PIDITEMS];
|
uint8_t D8[PIDITEMS];
|
||||||
|
@ -163,7 +164,6 @@ typedef struct config_t {
|
||||||
|
|
||||||
// sensor-related stuff
|
// sensor-related stuff
|
||||||
uint8_t acc_lpf_factor; // Set the Low Pass Filter factor for ACC. Increasing this value would reduce ACC noise (visible in GUI), but would increase ACC lag time. Zero = no filter
|
uint8_t acc_lpf_factor; // Set the Low Pass Filter factor for ACC. Increasing this value would reduce ACC noise (visible in GUI), but would increase ACC lag time. Zero = no filter
|
||||||
uint8_t acc_lpf_for_velocity; // ACC lowpass for AccZ height hold
|
|
||||||
uint8_t accz_deadband; // ??
|
uint8_t accz_deadband; // ??
|
||||||
uint8_t baro_tab_size; // size of baro filter array
|
uint8_t baro_tab_size; // size of baro filter array
|
||||||
float baro_noise_lpf; // additional LPF to reduce baro noise
|
float baro_noise_lpf; // additional LPF to reduce baro noise
|
||||||
|
@ -181,6 +181,7 @@ typedef struct config_t {
|
||||||
uint8_t failsafe_delay; // Guard time for failsafe activation after signal lost. 1 step = 0.1sec - 1sec in example (10)
|
uint8_t failsafe_delay; // Guard time for failsafe activation after signal lost. 1 step = 0.1sec - 1sec in example (10)
|
||||||
uint8_t failsafe_off_delay; // Time for Landing before motors stop in 0.1sec. 1 step = 0.1sec - 20sec in example (200)
|
uint8_t failsafe_off_delay; // Time for Landing before motors stop in 0.1sec. 1 step = 0.1sec - 20sec in example (200)
|
||||||
uint16_t failsafe_throttle; // Throttle level used for landing - specify value between 1000..2000 (pwm pulse width for slightly below hover). center throttle = 1500.
|
uint16_t failsafe_throttle; // Throttle level used for landing - specify value between 1000..2000 (pwm pulse width for slightly below hover). center throttle = 1500.
|
||||||
|
uint16_t failsafe_detect_threshold; // Update controls channel only if pulse is above failsafe_detect_threshold. below this trigger failsafe.
|
||||||
|
|
||||||
// mixer-related configuration
|
// mixer-related configuration
|
||||||
int8_t yaw_direction;
|
int8_t yaw_direction;
|
||||||
|
@ -245,6 +246,7 @@ typedef struct master_t {
|
||||||
uint8_t acc_hardware; // Which acc hardware to use on boards with more than one device
|
uint8_t acc_hardware; // Which acc hardware to use on boards with more than one device
|
||||||
uint16_t gyro_lpf; // gyro LPF setting - values are driver specific, in case of invalid number, a reasonable default ~30-40HZ is chosen.
|
uint16_t gyro_lpf; // gyro LPF setting - values are driver specific, in case of invalid number, a reasonable default ~30-40HZ is chosen.
|
||||||
uint16_t gyro_cmpf_factor; // Set the Gyro Weight for Gyro/Acc complementary filter. Increasing this value would reduce and delay Acc influence on the output of the filter.
|
uint16_t gyro_cmpf_factor; // Set the Gyro Weight for Gyro/Acc complementary filter. Increasing this value would reduce and delay Acc influence on the output of the filter.
|
||||||
|
uint16_t gyro_cmpfm_factor; // Set the Gyro Weight for Gyro/Magnetometer complementary filter. Increasing this value would reduce and delay Magnetometer influence on the output of the filter
|
||||||
uint32_t gyro_smoothing_factor; // How much to smoothen with per axis (32bit value with Roll, Pitch, Yaw in bits 24, 16, 8 respectively
|
uint32_t gyro_smoothing_factor; // How much to smoothen with per axis (32bit value with Roll, Pitch, Yaw in bits 24, 16, 8 respectively
|
||||||
uint8_t moron_threshold; // people keep forgetting that moving model while init results in wrong gyro offsets. and then they never reset gyro. so this is now on by default.
|
uint8_t moron_threshold; // people keep forgetting that moving model while init results in wrong gyro offsets. and then they never reset gyro. so this is now on by default.
|
||||||
uint8_t mpu6050_scale; // es/non-es variance between MPU6050 sensors, half my boards are mpu6000ES, need this to be dynamic. automatically set by mpu6050 driver.
|
uint8_t mpu6050_scale; // es/non-es variance between MPU6050 sensors, half my boards are mpu6000ES, need this to be dynamic. automatically set by mpu6050 driver.
|
||||||
|
@ -353,18 +355,24 @@ extern int16_t GPS_angle[2]; // it's the angles
|
||||||
extern uint16_t GPS_ground_course; // degrees*10
|
extern uint16_t GPS_ground_course; // degrees*10
|
||||||
extern uint8_t GPS_Present; // Checksum from Gps serial
|
extern uint8_t GPS_Present; // Checksum from Gps serial
|
||||||
extern uint8_t GPS_Enable;
|
extern uint8_t GPS_Enable;
|
||||||
extern int16_t nav[2];
|
extern int16_t nav[2];
|
||||||
extern int8_t nav_mode; // Navigation mode
|
extern int8_t nav_mode; // Navigation mode
|
||||||
extern int16_t nav_rated[2]; // Adding a rate controller to the navigation to make it smoother
|
extern int16_t nav_rated[2]; // Adding a rate controller to the navigation to make it smoother
|
||||||
|
extern uint8_t GPS_numCh; // Number of channels
|
||||||
extern master_t mcfg;
|
extern uint8_t GPS_svinfo_chn[16]; // Channel number
|
||||||
extern config_t cfg;
|
extern uint8_t GPS_svinfo_svid[16]; // Satellite ID
|
||||||
|
extern uint8_t GPS_svinfo_quality[16]; // Bitfield Qualtity
|
||||||
|
extern uint8_t GPS_svinfo_cno[16]; // Carrier to Noise Ratio (Signal Strength)
|
||||||
|
|
||||||
|
extern master_t mcfg;
|
||||||
|
extern config_t cfg;
|
||||||
extern flags_t f;
|
extern flags_t f;
|
||||||
extern sensor_t acc;
|
extern sensor_t acc;
|
||||||
extern sensor_t gyro;
|
extern sensor_t gyro;
|
||||||
extern baro_t baro;
|
extern baro_t baro;
|
||||||
|
|
||||||
// main
|
// main
|
||||||
|
void setPIDController(int type);
|
||||||
void loop(void);
|
void loop(void);
|
||||||
|
|
||||||
// IMU
|
// IMU
|
||||||
|
|
|
@ -30,8 +30,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "printf.h"
|
#ifdef USE_LAME_PRINTF
|
||||||
|
|
||||||
#define PRINTF_LONG_SUPPORT
|
#define PRINTF_LONG_SUPPORT
|
||||||
|
|
||||||
typedef void (*putcf) (void *, char);
|
typedef void (*putcf) (void *, char);
|
||||||
|
@ -246,3 +245,4 @@ void tfp_sprintf(char *s, char *fmt, ...)
|
||||||
putcp(&s, 0);
|
putcp(&s, 0);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
|
#endif /* USE_LAME_PRINTF */
|
||||||
|
|
|
@ -107,7 +107,7 @@ retry:
|
||||||
gyro.init();
|
gyro.init();
|
||||||
|
|
||||||
#ifdef MAG
|
#ifdef MAG
|
||||||
if (!hmc5883lDetect())
|
if (!hmc5883lDetect(mcfg.align[ALIGN_MAG]))
|
||||||
sensorsClear(SENSOR_MAG);
|
sensorsClear(SENSOR_MAG);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -402,19 +402,13 @@ void Gyro_getADC(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MAG
|
#ifdef MAG
|
||||||
static float magCal[3] = { 1.0, 1.0, 1.0 }; // gain for each axis, populated at sensor init
|
static float magCal[3] = { 1.0f, 1.0f, 1.0f }; // gain for each axis, populated at sensor init
|
||||||
static uint8_t magInit = 0;
|
static uint8_t magInit = 0;
|
||||||
|
|
||||||
static void Mag_getRawADC(void)
|
static void Mag_getRawADC(void)
|
||||||
{
|
{
|
||||||
|
// MAG driver will align itself, so no need to alignSensors()
|
||||||
hmc5883lRead(magADC);
|
hmc5883lRead(magADC);
|
||||||
|
|
||||||
// Default mag orientation is -2, -3, 1 or
|
|
||||||
// no way? is THIS finally the proper orientation?? (by GrootWitBaas)
|
|
||||||
// magADC[ROLL] = rawADC[2]; // X
|
|
||||||
// magADC[PITCH] = -rawADC[0]; // Y
|
|
||||||
// magADC[YAW] = -rawADC[1]; // Z
|
|
||||||
alignSensors(ALIGN_MAG, magADC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mag_init(void)
|
void Mag_init(void)
|
||||||
|
|
87
src/serial.c
87
src/serial.c
|
@ -25,6 +25,7 @@
|
||||||
#define MSP_PIDNAMES 117 //out message the PID names
|
#define MSP_PIDNAMES 117 //out message the PID names
|
||||||
#define MSP_WP 118 //out message get a WP, WP# is in the payload, returns (WP#, lat, lon, alt, flags) WP#0-home, WP#16-poshold
|
#define MSP_WP 118 //out message get a WP, WP# is in the payload, returns (WP#, lat, lon, alt, flags) WP#0-home, WP#16-poshold
|
||||||
#define MSP_BOXIDS 119 //out message get the permanent IDs associated to BOXes
|
#define MSP_BOXIDS 119 //out message get the permanent IDs associated to BOXes
|
||||||
|
#define MSP_SERVO_CONF 120 //out message Servo settings
|
||||||
|
|
||||||
#define MSP_SET_RAW_RC 200 //in message 8 rc chan
|
#define MSP_SET_RAW_RC 200 //in message 8 rc chan
|
||||||
#define MSP_SET_RAW_GPS 201 //in message fix, numsat, lat, lon, alt, speed
|
#define MSP_SET_RAW_GPS 201 //in message fix, numsat, lat, lon, alt, speed
|
||||||
|
@ -38,6 +39,8 @@
|
||||||
#define MSP_SET_WP 209 //in message sets a given WP (WP#,lat, lon, alt, flags)
|
#define MSP_SET_WP 209 //in message sets a given WP (WP#,lat, lon, alt, flags)
|
||||||
#define MSP_SELECT_SETTING 210 //in message Select Setting Number (0-2)
|
#define MSP_SELECT_SETTING 210 //in message Select Setting Number (0-2)
|
||||||
#define MSP_SET_HEAD 211 //in message define a new heading hold direction
|
#define MSP_SET_HEAD 211 //in message define a new heading hold direction
|
||||||
|
#define MSP_SET_SERVO_CONF 212 //in message Servo settings
|
||||||
|
#define MSP_SET_MOTOR 214 //in message PropBalance function
|
||||||
|
|
||||||
// #define MSP_BIND 240 //in message no param
|
// #define MSP_BIND 240 //in message no param
|
||||||
|
|
||||||
|
@ -47,12 +50,13 @@
|
||||||
#define MSP_DEBUG 254 //out message debug1,debug2,debug3,debug4
|
#define MSP_DEBUG 254 //out message debug1,debug2,debug3,debug4
|
||||||
|
|
||||||
// Additional commands that are not compatible with MultiWii
|
// Additional commands that are not compatible with MultiWii
|
||||||
#define MSP_UID 160 //out message Unique device ID
|
#define MSP_UID 160 //out message Unique device ID
|
||||||
#define MSP_ACC_TRIM 240 //out message get acc angle trim values
|
#define MSP_ACC_TRIM 240 //out message get acc angle trim values
|
||||||
#define MSP_SET_ACC_TRIM 239 //in message set acc angle trim values
|
#define MSP_SET_ACC_TRIM 239 //in message set acc angle trim values
|
||||||
|
#define MSP_GPSSVINFO 164 //out message get Signal Strength (only U-Blox)
|
||||||
#define INBUF_SIZE 64
|
|
||||||
|
#define INBUF_SIZE 64
|
||||||
|
|
||||||
struct box_t {
|
struct box_t {
|
||||||
const uint8_t boxIndex; // this is from boxnames enum
|
const uint8_t boxIndex; // this is from boxnames enum
|
||||||
const char *boxName; // GUI-readable box name
|
const char *boxName; // GUI-readable box name
|
||||||
|
@ -293,7 +297,7 @@ void serialInit(uint32_t baudrate)
|
||||||
|
|
||||||
static void evaluateCommand(void)
|
static void evaluateCommand(void)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i, tmp;
|
||||||
uint8_t wp_no;
|
uint8_t wp_no;
|
||||||
int32_t lat = 0, lon = 0, alt = 0;
|
int32_t lat = 0, lon = 0, alt = 0;
|
||||||
|
|
||||||
|
@ -370,6 +374,9 @@ static void evaluateCommand(void)
|
||||||
serialize16(cycleTime);
|
serialize16(cycleTime);
|
||||||
serialize16(i2cGetErrorCounter());
|
serialize16(i2cGetErrorCounter());
|
||||||
serialize16(sensors(SENSOR_ACC) | sensors(SENSOR_BARO) << 1 | sensors(SENSOR_MAG) << 2 | sensors(SENSOR_GPS) << 3 | sensors(SENSOR_SONAR) << 4);
|
serialize16(sensors(SENSOR_ACC) | sensors(SENSOR_BARO) << 1 | sensors(SENSOR_MAG) << 2 | sensors(SENSOR_GPS) << 3 | sensors(SENSOR_SONAR) << 4);
|
||||||
|
#if FUCK_MULTIWII
|
||||||
|
// OK, so you waste all the fucking time to have BOXNAMES and BOXINDEXES etc, and then you go ahead and serialize enabled shit simply by stuffing all
|
||||||
|
// the bits in order, instead of setting the enabled bits based on BOXINDEX. WHERE IS THE FUCKING LOGIC IN THIS, FUCKWADS.
|
||||||
serialize32(f.ANGLE_MODE << BOXANGLE | f.HORIZON_MODE << BOXHORIZON |
|
serialize32(f.ANGLE_MODE << BOXANGLE | f.HORIZON_MODE << BOXHORIZON |
|
||||||
f.BARO_MODE << BOXBARO | f.MAG_MODE << BOXMAG | f.HEADFREE_MODE << BOXHEADFREE | rcOptions[BOXHEADADJ] << BOXHEADADJ |
|
f.BARO_MODE << BOXBARO | f.MAG_MODE << BOXMAG | f.HEADFREE_MODE << BOXHEADFREE | rcOptions[BOXHEADADJ] << BOXHEADADJ |
|
||||||
rcOptions[BOXCAMSTAB] << BOXCAMSTAB | rcOptions[BOXCAMTRIG] << BOXCAMTRIG |
|
rcOptions[BOXCAMSTAB] << BOXCAMSTAB | rcOptions[BOXCAMTRIG] << BOXCAMTRIG |
|
||||||
|
@ -383,6 +390,49 @@ static void evaluateCommand(void)
|
||||||
rcOptions[BOXGOV] << BOXGOV |
|
rcOptions[BOXGOV] << BOXGOV |
|
||||||
rcOptions[BOXOSD] << BOXOSD |
|
rcOptions[BOXOSD] << BOXOSD |
|
||||||
f.ARMED << BOXARM);
|
f.ARMED << BOXARM);
|
||||||
|
#else
|
||||||
|
// Serialize the boxes in the order we delivered them
|
||||||
|
tmp = 0;
|
||||||
|
for (i = 0; i < numberBoxItems; i++) {
|
||||||
|
uint8_t val, box = availableBoxes[i];
|
||||||
|
switch (box) {
|
||||||
|
// Handle the special cases
|
||||||
|
case BOXANGLE:
|
||||||
|
val = f.ANGLE_MODE;
|
||||||
|
break;
|
||||||
|
case BOXHORIZON:
|
||||||
|
val = f.HORIZON_MODE;
|
||||||
|
break;
|
||||||
|
case BOXMAG:
|
||||||
|
val = f.MAG_MODE;
|
||||||
|
break;
|
||||||
|
case BOXBARO:
|
||||||
|
val = f.BARO_MODE;
|
||||||
|
break;
|
||||||
|
case BOXHEADFREE:
|
||||||
|
val = f.HEADFREE_MODE;
|
||||||
|
break;
|
||||||
|
case BOXGPSHOME:
|
||||||
|
val = f.GPS_HOME_MODE;
|
||||||
|
break;
|
||||||
|
case BOXGPSHOLD:
|
||||||
|
val = f.GPS_HOLD_MODE;
|
||||||
|
break;
|
||||||
|
case BOXPASSTHRU:
|
||||||
|
val = f.PASSTHRU_MODE;
|
||||||
|
break;
|
||||||
|
case BOXARM:
|
||||||
|
val = f.ARMED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// These just directly rely on their RC inputs
|
||||||
|
val = rcOptions[ box ];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tmp |= (val << i);
|
||||||
|
}
|
||||||
|
serialize32(tmp);
|
||||||
|
#endif
|
||||||
serialize8(mcfg.current_profile);
|
serialize8(mcfg.current_profile);
|
||||||
break;
|
break;
|
||||||
case MSP_RAW_IMU:
|
case MSP_RAW_IMU:
|
||||||
|
@ -565,13 +615,22 @@ static void evaluateCommand(void)
|
||||||
case MSP_UID:
|
case MSP_UID:
|
||||||
headSerialReply(12);
|
headSerialReply(12);
|
||||||
serialize32(U_ID_0);
|
serialize32(U_ID_0);
|
||||||
serialize32(U_ID_1);
|
serialize32(U_ID_1);
|
||||||
serialize32(U_ID_2);
|
serialize32(U_ID_2);
|
||||||
break;
|
break;
|
||||||
|
case MSP_GPSSVINFO:
|
||||||
default: // we do not know how to handle the (valid) message, indicate error MSP $M!
|
headSerialReply(1 + (GPS_numCh * 4));
|
||||||
headSerialError(0);
|
serialize8(GPS_numCh);
|
||||||
break;
|
for (i = 0; i < GPS_numCh; i++){
|
||||||
|
serialize8(GPS_svinfo_chn[i]);
|
||||||
|
serialize8(GPS_svinfo_svid[i]);
|
||||||
|
serialize8(GPS_svinfo_quality[i]);
|
||||||
|
serialize8(GPS_svinfo_cno[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: // we do not know how to handle the (valid) message, indicate error MSP $M!
|
||||||
|
headSerialError(0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
tailSerialReply();
|
tailSerialReply();
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,9 +95,9 @@ static void sendAccel(void)
|
||||||
static void sendBaro(void)
|
static void sendBaro(void)
|
||||||
{
|
{
|
||||||
sendDataHead(ID_ALTITUDE_BP);
|
sendDataHead(ID_ALTITUDE_BP);
|
||||||
serialize16(EstAlt / 100);
|
serialize16(BaroAlt / 100);
|
||||||
sendDataHead(ID_ALTITUDE_AP);
|
sendDataHead(ID_ALTITUDE_AP);
|
||||||
serialize16(EstAlt % 100);
|
serialize16(BaroAlt % 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sendTemperature1(void)
|
static void sendTemperature1(void)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue