Merge remote-tracking branch 'multiwii/master'

Conflicts:
	src/cli.c
	src/config.c
	src/drv_system.c
	src/main.c
This commit is contained in:
Dominic Clifton 2013-12-15 16:13:45 +00:00
commit 874bf96447
32 changed files with 4505 additions and 3941 deletions

5
.gitignore vendored
View File

@ -1,2 +1,7 @@
*.o *.o
*~ *~
*.uvopt
*.dep
*.bak
*.uvgui.*
obj/

View File

@ -60,6 +60,7 @@ COMMON_SRC = startup_stm32f10x_md_gcc.S \
drv_i2c_soft.c \ drv_i2c_soft.c \
drv_system.c \ drv_system.c \
drv_serial.c \ drv_serial.c \
drv_softserial.c \
drv_uart.c \ drv_uart.c \
printf.c \ printf.c \
utils.c \ utils.c \
@ -98,9 +99,12 @@ OLIMEXINO_SRC = drv_spi.c \
drv_l3g4200d.c \ drv_l3g4200d.c \
drv_pwm.c \ drv_pwm.c \
drv_timer.c \ drv_timer.c \
drv_softserial.c \
$(COMMON_SRC) $(COMMON_SRC)
# In some cases, %.s regarded as intermediate file, which is actually not.
# This will prevent accidental deletion of startup code.
.PRECIOUS: %.s
# Search path for baseflight sources # Search path for baseflight sources
VPATH := $(SRC_DIR):$(SRC_DIR)/baseflight_startups VPATH := $(SRC_DIR):$(SRC_DIR)/baseflight_startups
@ -182,7 +186,7 @@ TARGET_MAP = $(OBJECT_DIR)/baseflight_$(TARGET).map
# It would be nice to compute these lists, but that seems to be just beyond make. # It would be nice to compute these lists, but that seems to be just beyond make.
$(TARGET_HEX): $(TARGET_ELF) $(TARGET_HEX): $(TARGET_ELF)
$(OBJCOPY) -O ihex $< $@ $(OBJCOPY) -O ihex --set-start 0x8000000 $< $@
$(TARGET_ELF): $(TARGET_OBJS) $(TARGET_ELF): $(TARGET_OBJS)
$(CC) -o $@ $^ $(LDFLAGS) $(CC) -o $@ $^ $(LDFLAGS)

View File

@ -30,6 +30,7 @@
<SLE66AMisc></SLE66AMisc> <SLE66AMisc></SLE66AMisc>
<SLE66LinkerMisc></SLE66LinkerMisc> <SLE66LinkerMisc></SLE66LinkerMisc>
<SFDFile>SFD\ST\STM32F1xx\STM32F103xx.sfr</SFDFile> <SFDFile>SFD\ST\STM32F1xx\STM32F103xx.sfr</SFDFile>
<bCustSvd>0</bCustSvd>
<UseEnv>0</UseEnv> <UseEnv>0</UseEnv>
<BinPath></BinPath> <BinPath></BinPath>
<IncludePath></IncludePath> <IncludePath></IncludePath>
@ -97,6 +98,7 @@
<StopOnExitCode>3</StopOnExitCode> <StopOnExitCode>3</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<DllOption> <DllOption>
<SimDllName>SARMCM3.DLL</SimDllName> <SimDllName>SARMCM3.DLL</SimDllName>
@ -169,6 +171,10 @@
<Flash2>BIN\UL2CM3.DLL</Flash2> <Flash2>BIN\UL2CM3.DLL</Flash2>
<Flash3>"" ()</Flash3> <Flash3>"" ()</Flash3>
<Flash4></Flash4> <Flash4></Flash4>
<pFcarmOut></pFcarmOut>
<pFcarmGrp></pFcarmGrp>
<pFcArmRoot></pFcArmRoot>
<FcArmLst>0</FcArmLst>
</Utilities> </Utilities>
<TargetArmAds> <TargetArmAds>
<ArmAdsMisc> <ArmAdsMisc>
@ -551,6 +557,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Cads> <Cads>
@ -596,6 +603,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Cads> <Cads>
@ -696,6 +704,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>0</ComprImg>
</CommonProperty> </CommonProperty>
<GroupArmAds> <GroupArmAds>
<Cads> <Cads>
@ -788,11 +797,6 @@
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>.\lib\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c</FilePath> <FilePath>.\lib\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c</FilePath>
</File> </File>
<File>
<FileName>stm32f10x_gpio.c</FileName>
<FileType>1</FileType>
<FilePath>.\lib\STM32F10x_StdPeriph_Driver\src\stm32f10x_gpio.c</FilePath>
</File>
<File> <File>
<FileName>stm32f10x_flash.c</FileName> <FileName>stm32f10x_flash.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
@ -822,6 +826,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Aads> <Aads>
@ -881,6 +886,7 @@
<SLE66AMisc></SLE66AMisc> <SLE66AMisc></SLE66AMisc>
<SLE66LinkerMisc></SLE66LinkerMisc> <SLE66LinkerMisc></SLE66LinkerMisc>
<SFDFile>SFD\ST\STM32F1xx\STM32F103xx.sfr</SFDFile> <SFDFile>SFD\ST\STM32F1xx\STM32F103xx.sfr</SFDFile>
<bCustSvd>0</bCustSvd>
<UseEnv>0</UseEnv> <UseEnv>0</UseEnv>
<BinPath></BinPath> <BinPath></BinPath>
<IncludePath></IncludePath> <IncludePath></IncludePath>
@ -948,6 +954,7 @@
<StopOnExitCode>3</StopOnExitCode> <StopOnExitCode>3</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<DllOption> <DllOption>
<SimDllName>SARMCM3.DLL</SimDllName> <SimDllName>SARMCM3.DLL</SimDllName>
@ -1020,6 +1027,10 @@
<Flash2>BIN\UL2CM3.DLL</Flash2> <Flash2>BIN\UL2CM3.DLL</Flash2>
<Flash3>"" ()</Flash3> <Flash3>"" ()</Flash3>
<Flash4></Flash4> <Flash4></Flash4>
<pFcarmOut></pFcarmOut>
<pFcarmGrp></pFcarmGrp>
<pFcArmRoot></pFcArmRoot>
<FcArmLst>0</FcArmLst>
</Utilities> </Utilities>
<TargetArmAds> <TargetArmAds>
<ArmAdsMisc> <ArmAdsMisc>
@ -1402,6 +1413,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Cads> <Cads>
@ -1447,6 +1459,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Cads> <Cads>
@ -1583,11 +1596,6 @@
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>.\lib\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c</FilePath> <FilePath>.\lib\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c</FilePath>
</File> </File>
<File>
<FileName>stm32f10x_gpio.c</FileName>
<FileType>1</FileType>
<FilePath>.\lib\STM32F10x_StdPeriph_Driver\src\stm32f10x_gpio.c</FilePath>
</File>
<File> <File>
<FileName>stm32f10x_flash.c</FileName> <FileName>stm32f10x_flash.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
@ -1617,6 +1625,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Aads> <Aads>
@ -1676,6 +1685,7 @@
<SLE66AMisc></SLE66AMisc> <SLE66AMisc></SLE66AMisc>
<SLE66LinkerMisc></SLE66LinkerMisc> <SLE66LinkerMisc></SLE66LinkerMisc>
<SFDFile>SFD\ST\STM32F10xx\STM32F10xxB.sfr</SFDFile> <SFDFile>SFD\ST\STM32F10xx\STM32F10xxB.sfr</SFDFile>
<bCustSvd>0</bCustSvd>
<UseEnv>0</UseEnv> <UseEnv>0</UseEnv>
<BinPath></BinPath> <BinPath></BinPath>
<IncludePath></IncludePath> <IncludePath></IncludePath>
@ -1743,6 +1753,7 @@
<StopOnExitCode>3</StopOnExitCode> <StopOnExitCode>3</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<DllOption> <DllOption>
<SimDllName>SARMCM3.DLL</SimDllName> <SimDllName>SARMCM3.DLL</SimDllName>
@ -1815,6 +1826,10 @@
<Flash2>BIN\UL2CM3.DLL</Flash2> <Flash2>BIN\UL2CM3.DLL</Flash2>
<Flash3>"" ()</Flash3> <Flash3>"" ()</Flash3>
<Flash4></Flash4> <Flash4></Flash4>
<pFcarmOut></pFcarmOut>
<pFcarmGrp></pFcarmGrp>
<pFcArmRoot></pFcArmRoot>
<FcArmLst>0</FcArmLst>
</Utilities> </Utilities>
<TargetArmAds> <TargetArmAds>
<ArmAdsMisc> <ArmAdsMisc>
@ -2142,6 +2157,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Cads> <Cads>
@ -2187,6 +2203,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Cads> <Cads>
@ -2232,6 +2249,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Cads> <Cads>
@ -2277,6 +2295,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Cads> <Cads>
@ -2327,6 +2346,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Cads> <Cads>
@ -2372,6 +2392,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Cads> <Cads>
@ -2427,6 +2448,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Cads> <Cads>
@ -2472,6 +2494,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Cads> <Cads>
@ -2582,6 +2605,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>0</ComprImg>
</CommonProperty> </CommonProperty>
<GroupArmAds> <GroupArmAds>
<Cads> <Cads>
@ -2674,11 +2698,6 @@
<FileType>1</FileType> <FileType>1</FileType>
<FilePath>.\lib\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c</FilePath> <FilePath>.\lib\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c</FilePath>
</File> </File>
<File>
<FileName>stm32f10x_gpio.c</FileName>
<FileType>1</FileType>
<FilePath>.\lib\STM32F10x_StdPeriph_Driver\src\stm32f10x_gpio.c</FilePath>
</File>
<File> <File>
<FileName>stm32f10x_flash.c</FileName> <FileName>stm32f10x_flash.c</FileName>
<FileType>1</FileType> <FileType>1</FileType>
@ -2703,6 +2722,7 @@
<StopOnExitCode>11</StopOnExitCode> <StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument> <CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules> <IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty> </CommonProperty>
<FileArmAds> <FileArmAds>
<Aads> <Aads>

File diff suppressed because it is too large Load Diff

View File

@ -46,6 +46,7 @@ typedef enum {
SENSOR_MAG = 1 << 3, SENSOR_MAG = 1 << 3,
SENSOR_SONAR = 1 << 4, SENSOR_SONAR = 1 << 4,
SENSOR_GPS = 1 << 5, SENSOR_GPS = 1 << 5,
SENSOR_GPSMAG = 1 << 6,
} AvailableSensors; } AvailableSensors;
// Type of accelerometer used/detected // Type of accelerometer used/detected
@ -86,9 +87,16 @@ typedef enum {
typedef enum { typedef enum {
GPS_NMEA = 0, GPS_NMEA = 0,
GPS_UBLOX, GPS_UBLOX,
GPS_MTK, GPS_MTK_NMEA,
GPS_MTK_BINARY,
GPS_MAG_BINARY,
} GPSHardware; } GPSHardware;
typedef enum {
TELEMETRY_UART = 0,
TELEMETRY_SOFTSERIAL,
} TelemetrySerial;
typedef enum { typedef enum {
X = 0, X = 0,
Y, Y,

155
src/cli.c
View File

@ -9,9 +9,11 @@ static void cliDefaults(char *cmdline);
static void cliDump(char *cmdLine); static void cliDump(char *cmdLine);
static void cliExit(char *cmdline); static void cliExit(char *cmdline);
static void cliFeature(char *cmdline); static void cliFeature(char *cmdline);
static void cliGpsPassthrough(char *cmdline);
static void cliHelp(char *cmdline); static void cliHelp(char *cmdline);
static void cliMap(char *cmdline); static void cliMap(char *cmdline);
static void cliMixer(char *cmdline); static void cliMixer(char *cmdline);
static void cliMotor(char *cmdline);
static void cliProfile(char *cmdline); static void cliProfile(char *cmdline);
static void cliSave(char *cmdline); static void cliSave(char *cmdline);
static void cliSet(char *cmdline); static void cliSet(char *cmdline);
@ -25,6 +27,9 @@ extern uint8_t accHardware;
// from config.c RC Channel mapping // from config.c RC Channel mapping
extern const char rcChannelLetters[]; extern const char rcChannelLetters[];
// from mixer.c
extern int16_t motor_disarmed[MAX_MOTORS];
// buffer // buffer
static char cliBuffer[48]; static char cliBuffer[48];
static uint32_t bufferIndex = 0; static uint32_t bufferIndex = 0;
@ -37,7 +42,9 @@ static const char * const mixerNames[] = {
"TRI", "QUADP", "QUADX", "BI", "TRI", "QUADP", "QUADX", "BI",
"GIMBAL", "Y6", "HEX6", "GIMBAL", "Y6", "HEX6",
"FLYING_WING", "Y4", "HEX6X", "OCTOX8", "OCTOFLATP", "OCTOFLATX", "FLYING_WING", "Y4", "HEX6X", "OCTOX8", "OCTOFLATP", "OCTOFLATX",
"AIRPLANE", "HELI_120_CCPM", "HELI_90_DEG", "VTAIL4", "CUSTOM", NULL "AIRPLANE", "HELI_120_CCPM", "HELI_90_DEG", "VTAIL4",
"HEX6H", "PPM_TO_SERVO", "DUALCOPTER", "SINGLECOPTER",
"CUSTOM", NULL
}; };
// sync this with AvailableFeatures enum from board.h // sync this with AvailableFeatures enum from board.h
@ -50,7 +57,7 @@ static const char * const featureNames[] = {
// sync this with AvailableSensors enum from board.h // sync this with AvailableSensors enum from board.h
static const char * const sensorNames[] = { static const char * const sensorNames[] = {
"ACC", "BARO", "MAG", "SONAR", "GPS", NULL "GYRO", "ACC", "BARO", "MAG", "SONAR", "GPS", "GPS+MAG", NULL
}; };
static const char * const accNames[] = { static const char * const accNames[] = {
@ -71,9 +78,11 @@ const clicmd_t cmdTable[] = {
{ "dump", "print configurable settings in a pastable form", cliDump }, { "dump", "print configurable settings in a pastable form", cliDump },
{ "exit", "", cliExit }, { "exit", "", cliExit },
{ "feature", "list or -val or val", cliFeature }, { "feature", "list or -val or val", cliFeature },
{ "gpspassthrough", "passthrough gps to serial", cliGpsPassthrough },
{ "help", "", cliHelp }, { "help", "", cliHelp },
{ "map", "mapping of rc channel order", cliMap }, { "map", "mapping of rc channel order", cliMap },
{ "mixer", "mixer name or list", cliMixer }, { "mixer", "mixer name or list", cliMixer },
{ "motor", "get/set motor output value", cliMotor },
{ "profile", "index (0 to 2)", cliProfile }, { "profile", "index (0 to 2)", cliProfile },
{ "save", "save and reboot", cliSave }, { "save", "save and reboot", cliSave },
{ "set", "name=value or blank or * for list", cliSet }, { "set", "name=value or blank or * for list", cliSet },
@ -114,11 +123,14 @@ const clivalue_t valueTable[] = {
{ "motor_pwm_rate", VAR_UINT16, &mcfg.motor_pwm_rate, 50, 498 }, { "motor_pwm_rate", VAR_UINT16, &mcfg.motor_pwm_rate, 50, 498 },
{ "servo_pwm_rate", VAR_UINT16, &mcfg.servo_pwm_rate, 50, 498 }, { "servo_pwm_rate", VAR_UINT16, &mcfg.servo_pwm_rate, 50, 498 },
{ "retarded_arm", VAR_UINT8, &mcfg.retarded_arm, 0, 1 }, { "retarded_arm", VAR_UINT8, &mcfg.retarded_arm, 0, 1 },
{ "flaps_speed", VAR_UINT8, &mcfg.flaps_speed, 0, 100 },
{ "serial_baudrate", VAR_UINT32, &mcfg.serial_baudrate, 1200, 115200 }, { "serial_baudrate", VAR_UINT32, &mcfg.serial_baudrate, 1200, 115200 },
{ "softserial_baudrate", VAR_UINT32, &mcfg.softserial_baudrate, 9600, 19200 }, { "softserial_baudrate", VAR_UINT32, &mcfg.softserial_baudrate, 9600, 19200 },
{ "softserial_inverted", VAR_UINT8, &mcfg.softserial_inverted, 0, 1 }, { "softserial_inverted", VAR_UINT8, &mcfg.softserial_inverted, 0, 1 },
{ "gps_baudrate", VAR_UINT32, &mcfg.gps_baudrate, 1200, 115200 }, { "gps_type", VAR_UINT8, &mcfg.gps_type, 0, 3 },
{ "gps_baudrate", VAR_INT8, &mcfg.gps_baudrate, -1, 4 },
{ "serialrx_type", VAR_UINT8, &mcfg.serialrx_type, 0, 2 }, { "serialrx_type", VAR_UINT8, &mcfg.serialrx_type, 0, 2 },
{ "telemetry_softserial", VAR_UINT8, &mcfg.telemetry_softserial, 0, 1 },
{ "vbatscale", VAR_UINT8, &mcfg.vbatscale, 10, 200 }, { "vbatscale", VAR_UINT8, &mcfg.vbatscale, 10, 200 },
{ "vbatmaxcellvoltage", VAR_UINT8, &mcfg.vbatmaxcellvoltage, 10, 50 }, { "vbatmaxcellvoltage", VAR_UINT8, &mcfg.vbatmaxcellvoltage, 10, 50 },
{ "vbatmincellvoltage", VAR_UINT8, &mcfg.vbatmincellvoltage, 10, 50 }, { "vbatmincellvoltage", VAR_UINT8, &mcfg.vbatmincellvoltage, 10, 50 },
@ -126,13 +138,15 @@ const clivalue_t valueTable[] = {
{ "align_gyro", VAR_UINT8, &mcfg.gyro_align, 0, 8 }, { "align_gyro", VAR_UINT8, &mcfg.gyro_align, 0, 8 },
{ "align_acc", VAR_UINT8, &mcfg.acc_align, 0, 8 }, { "align_acc", VAR_UINT8, &mcfg.acc_align, 0, 8 },
{ "align_mag", VAR_UINT8, &mcfg.mag_align, 0, 8 }, { "align_mag", VAR_UINT8, &mcfg.mag_align, 0, 8 },
{ "align_board_roll", VAR_INT16, &mcfg.board_align_roll, -180, 360 },
{ "align_board_pitch", VAR_INT16, &mcfg.board_align_pitch, -180, 360 },
{ "align_board_yaw", VAR_INT16, &mcfg.board_align_yaw, -180, 360 },
{ "yaw_control_direction", VAR_INT8, &mcfg.yaw_control_direction, -1, 1 }, { "yaw_control_direction", VAR_INT8, &mcfg.yaw_control_direction, -1, 1 },
{ "acc_hardware", VAR_UINT8, &mcfg.acc_hardware, 0, 5 }, { "acc_hardware", VAR_UINT8, &mcfg.acc_hardware, 0, 5 },
{ "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 }, { "gyro_cmpfm_factor", VAR_UINT16, &mcfg.gyro_cmpfm_factor, 100, 1000 },
{ "gps_type", VAR_UINT8, &mcfg.gps_type, 0, 3 },
{ "pid_controller", VAR_UINT8, &cfg.pidController, 0, 1 }, { "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 },
@ -142,7 +156,7 @@ const clivalue_t valueTable[] = {
{ "rc_rate", VAR_UINT8, &cfg.rcRate8, 0, 250 }, { "rc_rate", VAR_UINT8, &cfg.rcRate8, 0, 250 },
{ "rc_expo", VAR_UINT8, &cfg.rcExpo8, 0, 100 }, { "rc_expo", VAR_UINT8, &cfg.rcExpo8, 0, 100 },
{ "thr_mid", VAR_UINT8, &cfg.thrMid8, 0, 100 }, { "thr_mid", VAR_UINT8, &cfg.thrMid8, 0, 100 },
{ "thr_expo", VAR_UINT8, &cfg.thrExpo8, 0, 250 }, { "thr_expo", VAR_UINT8, &cfg.thrExpo8, 0, 100 },
{ "roll_pitch_rate", VAR_UINT8, &cfg.rollPitchRate, 0, 100 }, { "roll_pitch_rate", VAR_UINT8, &cfg.rollPitchRate, 0, 100 },
{ "yawrate", VAR_UINT8, &cfg.yawRate, 0, 100 }, { "yawrate", VAR_UINT8, &cfg.yawRate, 0, 100 },
{ "failsafe_delay", VAR_UINT8, &cfg.failsafe_delay, 0, 200 }, { "failsafe_delay", VAR_UINT8, &cfg.failsafe_delay, 0, 200 },
@ -152,28 +166,7 @@ const clivalue_t valueTable[] = {
{ "rssi_aux_channel", VAR_INT8, &mcfg.rssi_aux_channel, 0, 4 }, { "rssi_aux_channel", VAR_INT8, &mcfg.rssi_aux_channel, 0, 4 },
{ "yaw_direction", VAR_INT8, &cfg.yaw_direction, -1, 1 }, { "yaw_direction", VAR_INT8, &cfg.yaw_direction, -1, 1 },
{ "tri_unarmed_servo", VAR_INT8, &cfg.tri_unarmed_servo, 0, 1 }, { "tri_unarmed_servo", VAR_INT8, &cfg.tri_unarmed_servo, 0, 1 },
{ "tri_yaw_middle", VAR_UINT16, &cfg.tri_yaw_middle, 0, 2000 },
{ "tri_yaw_min", VAR_UINT16, &cfg.tri_yaw_min, 0, 2000 },
{ "tri_yaw_max", VAR_UINT16, &cfg.tri_yaw_max, 0, 2000 },
{ "wing_left_min", VAR_UINT16, &cfg.wing_left_min, 0, 2000 },
{ "wing_left_mid", VAR_UINT16, &cfg.wing_left_mid, 0, 2000 },
{ "wing_left_max", VAR_UINT16, &cfg.wing_left_max, 0, 2000 },
{ "wing_right_min", VAR_UINT16, &cfg.wing_right_min, 0, 2000 },
{ "wing_right_mid", VAR_UINT16, &cfg.wing_right_mid, 0, 2000 },
{ "wing_right_max", VAR_UINT16, &cfg.wing_right_max, 0, 2000 },
{ "pitch_direction_l", VAR_INT8, &cfg.pitch_direction_l, -1, 1 },
{ "pitch_direction_r", VAR_INT8, &cfg.pitch_direction_r, -1, 1 },
{ "roll_direction_l", VAR_INT8, &cfg.roll_direction_l, -1, 1 },
{ "roll_direction_r", VAR_INT8, &cfg.roll_direction_r, -1, 1 },
{ "gimbal_flags", VAR_UINT8, &cfg.gimbal_flags, 0, 255}, { "gimbal_flags", VAR_UINT8, &cfg.gimbal_flags, 0, 255},
{ "gimbal_pitch_gain", VAR_INT8, &cfg.gimbal_pitch_gain, -100, 100 },
{ "gimbal_roll_gain", VAR_INT8, &cfg.gimbal_roll_gain, -100, 100 },
{ "gimbal_pitch_min", VAR_UINT16, &cfg.gimbal_pitch_min, 100, 3000 },
{ "gimbal_pitch_max", VAR_UINT16, &cfg.gimbal_pitch_max, 100, 3000 },
{ "gimbal_pitch_mid", VAR_UINT16, &cfg.gimbal_pitch_mid, 100, 3000 },
{ "gimbal_roll_min", VAR_UINT16, &cfg.gimbal_roll_min, 100, 3000 },
{ "gimbal_roll_max", VAR_UINT16, &cfg.gimbal_roll_max, 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 },
{ "accxy_deadband", VAR_UINT8, &cfg.accxy_deadband, 0, 100 }, { "accxy_deadband", VAR_UINT8, &cfg.accxy_deadband, 0, 100 },
{ "accz_deadband", VAR_UINT8, &cfg.accz_deadband, 0, 100 }, { "accz_deadband", VAR_UINT8, &cfg.accz_deadband, 0, 100 },
@ -218,7 +211,13 @@ const clivalue_t valueTable[] = {
#define VALUE_COUNT (sizeof(valueTable) / sizeof(clivalue_t)) #define VALUE_COUNT (sizeof(valueTable) / sizeof(clivalue_t))
static void cliSetVar(const clivalue_t *var, const int32_t value);
typedef union {
int32_t int_value;
float float_value;
} int_float_value_t;
static void cliSetVar(const clivalue_t *var, const int_float_value_t value);
static void cliPrintVar(const clivalue_t *var, uint32_t full); static void cliPrintVar(const clivalue_t *var, uint32_t full);
static void cliPrint(const char *str); static void cliPrint(const char *str);
static void cliWrite(uint8_t ch); static void cliWrite(uint8_t ch);
@ -279,7 +278,7 @@ char *itoa(int i, char *a, int r)
static float _atof(const char *p) static float _atof(const char *p)
{ {
int frac = 0; int frac = 0;
double sign, value, scale; float sign, value, scale;
// Skip leading white space, if any. // Skip leading white space, if any.
while (white_space(*p) ) { while (white_space(*p) ) {
@ -287,9 +286,9 @@ static float _atof(const char *p)
} }
// Get sign, if any. // Get sign, if any.
sign = 1.0; sign = 1.0f;
if (*p == '-') { if (*p == '-') {
sign = -1.0; sign = -1.0f;
p += 1; p += 1;
} else if (*p == '+') { } else if (*p == '+') {
@ -297,26 +296,26 @@ static float _atof(const char *p)
} }
// Get digits before decimal point or exponent, if any. // Get digits before decimal point or exponent, if any.
value = 0.0; value = 0.0f;
while (valid_digit(*p)) { while (valid_digit(*p)) {
value = value * 10.0 + (*p - '0'); value = value * 10.0f + (*p - '0');
p += 1; p += 1;
} }
// Get digits after decimal point, if any. // Get digits after decimal point, if any.
if (*p == '.') { if (*p == '.') {
double pow10 = 10.0; float pow10 = 10.0f;
p += 1; p += 1;
while (valid_digit(*p)) { while (valid_digit(*p)) {
value += (*p - '0') / pow10; value += (*p - '0') / pow10;
pow10 *= 10.0; pow10 *= 10.0f;
p += 1; p += 1;
} }
} }
// Handle exponent, if any. // Handle exponent, if any.
scale = 1.0; scale = 1.0f;
if ((*p == 'e') || (*p == 'E')) { if ((*p == 'e') || (*p == 'E')) {
unsigned int expon; unsigned int expon;
p += 1; p += 1;
@ -337,12 +336,13 @@ static float _atof(const char *p)
expon = expon * 10 + (*p - '0'); expon = expon * 10 + (*p - '0');
p += 1; p += 1;
} }
if (expon > 308) expon = 308; if (expon > 308)
expon = 308;
// Calculate scaling factor. // Calculate scaling factor.
while (expon >= 50) { scale *= 1E50; expon -= 50; } // while (expon >= 50) { scale *= 1E50f; expon -= 50; }
while (expon >= 8) { scale *= 1E8; expon -= 8; } while (expon >= 8) { scale *= 1E8f; expon -= 8; }
while (expon > 0) { scale *= 10.0; expon -= 1; } while (expon > 0) { scale *= 10.0f; expon -= 1; }
} }
// Return signed and scaled floating point result. // Return signed and scaled floating point result.
@ -466,7 +466,7 @@ static void cliCMix(char *cmdline)
} }
cliPrint("Sanity check:\t"); cliPrint("Sanity check:\t");
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
cliPrint(fabs(mixsum[i]) > 0.01f ? "NG\t" : "OK\t"); cliPrint(fabsf(mixsum[i]) > 0.01f ? "NG\t" : "OK\t");
cliPrint("\r\n"); cliPrint("\r\n");
return; return;
} else if (strncasecmp(cmdline, "reset", 5) == 0) { } else if (strncasecmp(cmdline, "reset", 5) == 0) {
@ -611,6 +611,8 @@ static void cliExit(char *cmdline)
*cliBuffer = '\0'; *cliBuffer = '\0';
bufferIndex = 0; bufferIndex = 0;
cliMode = 0; cliMode = 0;
// incase some idiot leaves a motor running during motortest, clear it here
mixerResetMotors();
// save and reboot... I think this makes the most sense // save and reboot... I think this makes the most sense
cliSave(cmdline); cliSave(cmdline);
} }
@ -671,6 +673,14 @@ static void cliFeature(char *cmdline)
} }
} }
static void cliGpsPassthrough(char *cmdline)
{
if (gpsSetPassthrough() == -1)
cliPrint("Error: Enable and plug in GPS first\r\n");
else
cliPrint("Enabling GPS passthrough...\r\n");
}
static void cliHelp(char *cmdline) static void cliHelp(char *cmdline)
{ {
uint32_t i = 0; uint32_t i = 0;
@ -741,6 +751,52 @@ static void cliMixer(char *cmdline)
} }
} }
static void cliMotor(char *cmdline)
{
int motor_index = 0;
int motor_value = 0;
int len, index = 0;
char *pch = NULL;
len = strlen(cmdline);
if (len == 0) {
printf("Usage:\r\nmotor index [value] - show [or set] motor value\r\n");
return;
}
pch = strtok(cmdline, " ");
while (pch != NULL) {
switch (index) {
case 0:
motor_index = atoi(pch);
break;
case 1:
motor_value = atoi(pch);
break;
}
index++;
pch = strtok(NULL, " ");
}
if (motor_index < 0 || motor_index >= MAX_MOTORS) {
printf("No such motor, use a number [0, %d]\r\n", MAX_MOTORS);
return;
}
if (index < 2) {
printf("Motor %d is set at %d\r\n", motor_index, motor_disarmed[motor_index]);
return;
}
if (motor_value < 1000 || motor_value > 2000) {
printf("Invalid motor value, 1000..2000\r\n");
return;
}
printf("Setting motor %d to %d\r\n", motor_index, motor_value);
motor_disarmed[motor_index] = motor_value;
}
static void cliProfile(char *cmdline) static void cliProfile(char *cmdline)
{ {
uint8_t len; uint8_t len;
@ -819,25 +875,25 @@ static void cliPrintVar(const clivalue_t *var, uint32_t full)
printf(" %d %d", var->min, var->max); printf(" %d %d", var->min, var->max);
} }
static void cliSetVar(const clivalue_t *var, const int32_t value) static void cliSetVar(const clivalue_t *var, const int_float_value_t value)
{ {
switch (var->type) { switch (var->type) {
case VAR_UINT8: case VAR_UINT8:
case VAR_INT8: case VAR_INT8:
*(char *)var->ptr = (char)value; *(char *)var->ptr = (char)value.int_value;
break; break;
case VAR_UINT16: case VAR_UINT16:
case VAR_INT16: case VAR_INT16:
*(short *)var->ptr = (short)value; *(short *)var->ptr = (short)value.int_value;
break; break;
case VAR_UINT32: case VAR_UINT32:
*(int *)var->ptr = (int)value; *(int *)var->ptr = (int)value.int_value;
break; break;
case VAR_FLOAT: case VAR_FLOAT:
*(float *)var->ptr = *(float *)&value; *(float *)var->ptr = (float)value.float_value;
break; break;
} }
} }
@ -871,7 +927,12 @@ static void cliSet(char *cmdline)
val = &valueTable[i]; val = &valueTable[i];
if (strncasecmp(cmdline, valueTable[i].name, strlen(valueTable[i].name)) == 0) { if (strncasecmp(cmdline, valueTable[i].name, strlen(valueTable[i].name)) == 0) {
if (valuef >= valueTable[i].min && valuef <= valueTable[i].max) { // here we compare the float value since... it should work, RIGHT? if (valuef >= valueTable[i].min && valuef <= valueTable[i].max) { // here we compare the float value since... it should work, RIGHT?
cliSetVar(val, valueTable[i].type == VAR_FLOAT ? *(uint32_t *)&valuef : value); // this is a silly dirty hack. please fix me later. int_float_value_t tmp;
if (valueTable[i].type == VAR_FLOAT)
tmp.float_value = valuef;
else
tmp.int_value = value;
cliSetVar(val, tmp);
printf("%s set to ", valueTable[i].name); printf("%s set to ", valueTable[i].name);
cliPrintVar(val, 0); cliPrintVar(val, 0);
} else { } else {
@ -913,7 +974,7 @@ static void cliStatus(char *cmdline)
if (sensors(SENSOR_ACC)) { if (sensors(SENSOR_ACC)) {
printf("ACCHW: %s", accNames[accHardware]); printf("ACCHW: %s", accNames[accHardware]);
if (accHardware == ACC_MPU6050) if (accHardware == ACC_MPU6050)
printf(".%c", mcfg.mpu6050_scale ? 'o' : 'n'); printf(".%c", core.mpu6050_scale ? 'o' : 'n');
} }
cliPrint("\r\n"); cliPrint("\r\n");

View File

@ -7,13 +7,13 @@
#endif #endif
#define FLASH_PAGE_SIZE ((uint16_t)0x400) #define FLASH_PAGE_SIZE ((uint16_t)0x400)
#define FLASH_WRITE_ADDR (0x08000000 + (uint32_t)FLASH_PAGE_SIZE * (FLASH_PAGE_COUNT - 1)) // use the last KB for storage #define FLASH_WRITE_ADDR (0x08000000 + (uint32_t)FLASH_PAGE_SIZE * (FLASH_PAGE_COUNT - 2)) // use the last 2 KB for storage
master_t mcfg; // master config struct with data independent from profiles 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 const uint8_t EEPROM_CONF_VERSION = 52; static const uint8_t EEPROM_CONF_VERSION = 55;
static uint32_t enabledSensors = 0; static uint32_t enabledSensors = 0;
static void resetConf(void); static void resetConf(void);
@ -69,23 +69,22 @@ void readEEPROM(void)
mcfg.current_profile = 0; mcfg.current_profile = 0;
memcpy(&cfg, &mcfg.profile[mcfg.current_profile], sizeof(config_t)); memcpy(&cfg, &mcfg.profile[mcfg.current_profile], sizeof(config_t));
for (i = 0; i < 6; i++) for (i = 0; i < PITCH_LOOKUP_LENGTH; i++)
lookupPitchRollRC[i] = (2500 + cfg.rcExpo8 * (i * i - 25)) * i * (int32_t) cfg.rcRate8 / 2500; lookupPitchRollRC[i] = (2500 + cfg.rcExpo8 * (i * i - 25)) * i * (int32_t) cfg.rcRate8 / 2500;
for (i = 0; i < 11; i++) { for (i = 0; i < THROTTLE_LOOKUP_LENGTH; i++) {
int16_t tmp = 10 * i - cfg.thrMid8; int16_t tmp = 10 * i - cfg.thrMid8;
uint8_t y = 1; uint8_t y = 1;
if (tmp > 0) if (tmp > 0)
y = 100 - cfg.thrMid8; y = 100 - cfg.thrMid8;
if (tmp < 0) if (tmp < 0)
y = cfg.thrMid8; y = cfg.thrMid8;
lookupThrottleRC[i] = 10 * cfg.thrMid8 + tmp * (100 - cfg.thrExpo8 + (int32_t) cfg.thrExpo8 * (tmp * tmp) / (y * y)) / 10; // [0;1000] lookupThrottleRC[i] = 10 * cfg.thrMid8 + tmp * (100 - cfg.thrExpo8 + (int32_t) cfg.thrExpo8 * (tmp * tmp) / (y * y)) / 10;
lookupThrottleRC[i] = mcfg.minthrottle + (int32_t) (mcfg.maxthrottle - mcfg.minthrottle) * lookupThrottleRC[i] / 1000; // [0;1000] -> [MINTHROTTLE;MAXTHROTTLE] lookupThrottleRC[i] = mcfg.minthrottle + (int32_t) (mcfg.maxthrottle - mcfg.minthrottle) * lookupThrottleRC[i] / 1000; // [MINTHROTTLE;MAXTHROTTLE]
} }
cfg.tri_yaw_middle = constrain(cfg.tri_yaw_middle, cfg.tri_yaw_min, cfg.tri_yaw_max); //REAR
setPIDController(cfg.pidController); setPIDController(cfg.pidController);
GPS_set_pids(); gpsSetPIDs();
} }
void writeEEPROM(uint8_t b, uint8_t updateProfile) void writeEEPROM(uint8_t b, uint8_t updateProfile)
@ -181,6 +180,9 @@ static void resetConf(void)
mcfg.gyro_align = ALIGN_DEFAULT; mcfg.gyro_align = ALIGN_DEFAULT;
mcfg.acc_align = ALIGN_DEFAULT; mcfg.acc_align = ALIGN_DEFAULT;
mcfg.mag_align = ALIGN_DEFAULT; mcfg.mag_align = ALIGN_DEFAULT;
mcfg.board_align_roll = 0;
mcfg.board_align_pitch = 0;
mcfg.board_align_yaw = 0;
mcfg.acc_hardware = ACC_DEFAULT; // default/autodetect mcfg.acc_hardware = ACC_DEFAULT; // default/autodetect
mcfg.yaw_control_direction = 1; mcfg.yaw_control_direction = 1;
mcfg.moron_threshold = 32; mcfg.moron_threshold = 32;
@ -190,6 +192,7 @@ static void resetConf(void)
mcfg.vbatmincellvoltage = 33; mcfg.vbatmincellvoltage = 33;
mcfg.power_adc_channel = 0; mcfg.power_adc_channel = 0;
mcfg.serialrx_type = 0; mcfg.serialrx_type = 0;
mcfg.telemetry_softserial = 0;
mcfg.midrc = 1500; mcfg.midrc = 1500;
mcfg.mincheck = 1100; mcfg.mincheck = 1100;
mcfg.maxcheck = 1900; mcfg.maxcheck = 1900;
@ -206,7 +209,7 @@ static void resetConf(void)
mcfg.servo_pwm_rate = 50; mcfg.servo_pwm_rate = 50;
// gps/nav stuff // gps/nav stuff
mcfg.gps_type = GPS_NMEA; mcfg.gps_type = GPS_NMEA;
mcfg.gps_baudrate = 115200; mcfg.gps_baudrate = 0;
// serial (USART1) baudrate // serial (USART1) baudrate
mcfg.serial_baudrate = 115200; mcfg.serial_baudrate = 115200;
mcfg.softserial_baudrate = 19200; mcfg.softserial_baudrate = 19200;
@ -224,9 +227,9 @@ static void resetConf(void)
cfg.P8[YAW] = 85; cfg.P8[YAW] = 85;
cfg.I8[YAW] = 45; cfg.I8[YAW] = 45;
cfg.D8[YAW] = 0; cfg.D8[YAW] = 0;
cfg.P8[PIDALT] = 50; cfg.P8[PIDALT] = 40;
cfg.I8[PIDALT] = 25; cfg.I8[PIDALT] = 25;
cfg.D8[PIDALT] = 80; cfg.D8[PIDALT] = 60;
cfg.P8[PIDPOS] = 11; // POSHOLD_P * 100; cfg.P8[PIDPOS] = 11; // POSHOLD_P * 100;
cfg.I8[PIDPOS] = 0; // POSHOLD_I * 100; cfg.I8[PIDPOS] = 0; // POSHOLD_I * 100;
cfg.D8[PIDPOS] = 0; cfg.D8[PIDPOS] = 0;
@ -288,32 +291,9 @@ static void resetConf(void)
cfg.yaw_direction = 1; cfg.yaw_direction = 1;
cfg.tri_unarmed_servo = 1; cfg.tri_unarmed_servo = 1;
cfg.tri_yaw_middle = 1500;
cfg.tri_yaw_min = 1020;
cfg.tri_yaw_max = 2000;
// flying wing
cfg.wing_left_min = 1020;
cfg.wing_left_mid = 1500;
cfg.wing_left_max = 2000;
cfg.wing_right_min = 1020;
cfg.wing_right_mid = 1500;
cfg.wing_right_max = 2000;
cfg.pitch_direction_l = 1;
cfg.pitch_direction_r = -1;
cfg.roll_direction_l = 1;
cfg.roll_direction_r = 1;
// gimbal // gimbal
cfg.gimbal_pitch_gain = 10;
cfg.gimbal_roll_gain = 10;
cfg.gimbal_flags = GIMBAL_NORMAL; cfg.gimbal_flags = GIMBAL_NORMAL;
cfg.gimbal_pitch_min = 1020;
cfg.gimbal_pitch_max = 2000;
cfg.gimbal_pitch_mid = 1500;
cfg.gimbal_roll_min = 1020;
cfg.gimbal_roll_max = 2000;
cfg.gimbal_roll_mid = 1500;
// gps/nav stuff // gps/nav stuff
cfg.gps_wp_radius = 200; cfg.gps_wp_radius = 200;

View File

@ -35,7 +35,7 @@ static void adxl345Init(sensor_align_e align);
static void adxl345Read(int16_t *accelData); static void adxl345Read(int16_t *accelData);
static bool useFifo = false; static bool useFifo = false;
static sensor_align_e accAlign = CW0_DEG; static sensor_align_e accAlign = CW270_DEG;
bool adxl345Detect(drv_adxl345_config_t *init, sensor_t *acc) bool adxl345Detect(drv_adxl345_config_t *init, sensor_t *acc)
{ {

View File

@ -115,7 +115,7 @@ bool bmp085Detect(baro_t *baro)
#endif #endif
// EXTI interrupt for barometer EOC // EXTI interrupt for barometer EOC
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource14); gpioExtiLineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource14);
EXTI_InitStructure.EXTI_Line = EXTI_Line14; EXTI_InitStructure.EXTI_Line = EXTI_Line14;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;

View File

@ -31,3 +31,12 @@ void gpioInit(GPIO_TypeDef *gpio, gpio_config_t *config)
} }
} }
} }
void gpioExtiLineConfig(uint8_t portsrc, uint8_t pinsrc)
{
uint32_t tmp = 0x00;
tmp = ((uint32_t)0x0F) << (0x04 * (pinsrc & (uint8_t)0x03));
AFIO->EXTICR[pinsrc >> 0x02] &= ~tmp;
AFIO->EXTICR[pinsrc >> 0x02] |= (((uint32_t)portsrc) << (0x04 * (pinsrc & (uint8_t)0x03)));
}

View File

@ -53,3 +53,4 @@ typedef struct
#define digitalIn(p, i) (p->IDR & i) #define digitalIn(p, i) (p->IDR & i)
void gpioInit(GPIO_TypeDef *gpio, gpio_config_t *config); void gpioInit(GPIO_TypeDef *gpio, gpio_config_t *config);
void gpioExtiLineConfig(uint8_t portsrc, uint8_t pinsrc);

View File

@ -90,7 +90,7 @@ void hcsr04_init(sonar_config_t config)
gpioInit(GPIOB, &gpio); gpioInit(GPIOB, &gpio);
// setup external interrupt on echo pin // setup external interrupt on echo pin
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, exti_pin_source); gpioExtiLineConfig(GPIO_PortSourceGPIOB, exti_pin_source);
EXTI_ClearITPendingBit(exti_line); EXTI_ClearITPendingBit(exti_line);

View File

@ -157,9 +157,9 @@ void hmc5883lInit(void)
LED1_TOGGLE; LED1_TOGGLE;
} }
magGain[X] = fabs(660.0f * HMC58X3_X_SELF_TEST_GAUSS * 2.0f * 10.0f / xyz_total[X]); magGain[X] = fabsf(660.0f * HMC58X3_X_SELF_TEST_GAUSS * 2.0f * 10.0f / xyz_total[X]);
magGain[Y] = fabs(660.0f * HMC58X3_Y_SELF_TEST_GAUSS * 2.0f * 10.0f / xyz_total[Y]); magGain[Y] = fabsf(660.0f * HMC58X3_Y_SELF_TEST_GAUSS * 2.0f * 10.0f / xyz_total[Y]);
magGain[Z] = fabs(660.0f * HMC58X3_Z_SELF_TEST_GAUSS * 2.0f * 10.0f / xyz_total[Z]); magGain[Z] = fabsf(660.0f * HMC58X3_Z_SELF_TEST_GAUSS * 2.0f * 10.0f / xyz_total[Z]);
// leave test mode // leave test mode
i2cWrite(MAG_ADDRESS, HMC58X3_R_CONFA, 0x70); // Configuration Register A -- 0 11 100 00 num samples: 8 ; output rate: 15Hz ; normal measurement mode i2cWrite(MAG_ADDRESS, HMC58X3_R_CONFA, 0x70); // Configuration Register A -- 0 11 100 00 num samples: 8 ; output rate: 15Hz ; normal measurement mode

View File

@ -131,7 +131,7 @@ static uint8_t I2C_ReceiveByte(void)
void i2cInit(I2C_TypeDef * I2C) void i2cInit(I2C_TypeDef * I2C)
{ {
GPIO_Config gpio; gpio_config_t gpio;
gpio.pin = Pin_10 | Pin_11; gpio.pin = Pin_10 | Pin_11;
gpio.speed = Speed_2MHz; gpio.speed = Speed_2MHz;

View File

@ -254,7 +254,7 @@ static void ppmCallback(uint8_t port, uint16_t capture)
if (diff > 2700) { // Per http://www.rcgroups.com/forums/showpost.php?p=21996147&postcount=3960 "So, if you use 2.5ms or higher as being the reset for the PPM stream start, you will be fine. I use 2.7ms just to be safe." if (diff > 2700) { // Per http://www.rcgroups.com/forums/showpost.php?p=21996147&postcount=3960 "So, if you use 2.5ms or higher as being the reset for the PPM stream start, you will be fine. I use 2.7ms just to be safe."
chan = 0; chan = 0;
} else { } else {
if (diff > 750 && diff < 2250 && chan < 8) { // 750 to 2250 ms is our 'valid' channel range if (diff > 750 && diff < 2250 && chan < MAX_INPUTS) { // 750 to 2250 ms is our 'valid' channel range
captures[chan] = diff; captures[chan] = diff;
if (chan < 4 && diff > failsafeThreshold) if (chan < 4 && diff > failsafeThreshold)
GoodPulses |= (1 << chan); // if signal is valid - mark channel as OK GoodPulses |= (1 << chan); // if signal is valid - mark channel as OK
@ -354,7 +354,7 @@ bool pwmInit(drv_pwm_config_t *init)
pwmInConfig(port, pwmCallback, numInputs); pwmInConfig(port, pwmCallback, numInputs);
numInputs++; numInputs++;
} else if (mask & TYPE_M) { } else if (mask & TYPE_M) {
motors[numMotors++] = pwmOutConfig(port, 1000000 / init->motorPwmRate, PULSE_1MS); motors[numMotors++] = pwmOutConfig(port, 1000000 / init->motorPwmRate, init->idlePulse > 0 ? init->idlePulse : PULSE_1MS);
} else if (mask & TYPE_S) { } else if (mask & TYPE_S) {
servos[numServos++] = pwmOutConfig(port, 1000000 / init->servoPwmRate, PULSE_1MS); servos[numServos++] = pwmOutConfig(port, 1000000 / init->servoPwmRate, PULSE_1MS);
} }

View File

@ -15,6 +15,8 @@ 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 idlePulse; // PWM value to use when initializing the driver;
// default of zero means PULSE_1MS, otherwise set to given value. Used by 3D mode.
uint16_t failsafeThreshold; uint16_t failsafeThreshold;
} drv_pwm_config_t; } drv_pwm_config_t;

View File

@ -103,7 +103,6 @@ void systemInit(void)
systemBeepPtr = beepRev4; systemBeepPtr = beepRev4;
BEEP_OFF; BEEP_OFF;
#endif #endif
LED0_OFF; LED0_OFF;
LED1_OFF; LED1_OFF;
@ -224,50 +223,3 @@ void systemBeep(bool onoff)
#endif #endif
} }
void alignSensors(int16_t *src, int16_t *dest, uint8_t rotation)
{
switch (rotation) {
case CW0_DEG:
dest[X] = src[X];
dest[Y] = src[Y];
dest[Z] = src[Z];
break;
case CW90_DEG:
dest[X] = src[Y];
dest[Y] = -src[X];
dest[Z] = src[Z];
break;
case CW180_DEG:
dest[X] = -src[X];
dest[Y] = -src[Y];
dest[Z] = src[Z];
break;
case CW270_DEG:
dest[X] = -src[Y];
dest[Y] = src[X];
dest[Z] = src[Z];
break;
case CW0_DEG_FLIP:
dest[X] = -src[X];
dest[Y] = src[Y];
dest[Z] = -src[Z];
break;
case CW90_DEG_FLIP:
dest[X] = src[Y];
dest[Y] = src[X];
dest[Z] = -src[Z];
break;
case CW180_DEG_FLIP:
dest[X] = src[X];
dest[Y] = -src[Y];
dest[Z] = -src[Z];
break;
case CW270_DEG_FLIP:
dest[X] = -src[Y];
dest[Y] = -src[X];
dest[Z] = -src[Z];
break;
default:
break;
}
}

View File

@ -15,6 +15,3 @@ void systemReset(bool toBootloader);
// current crystal frequency - 8 or 12MHz // current crystal frequency - 8 or 12MHz
extern uint32_t hse_value; extern uint32_t hse_value;
// sensor orientation
void alignSensors(int16_t *src, int16_t *dest, uint8_t rotation);

333
src/gps.c
View File

@ -5,106 +5,214 @@
#define sq(x) ((x)*(x)) #define sq(x) ((x)*(x))
#endif #endif
const uint32_t init_speed[5] = { 9600, 19200, 38400, 57600, 115200 }; // GPS timeout for wrong baud rate/disconnection/etc in milliseconds (default 2.5second)
#define GPS_TIMEOUT (2500)
// How many entries in gpsInitData array below
#define GPS_INIT_ENTRIES (5)
static void GPS_NewData(uint16_t c); typedef struct gpsInitData_t {
static void gpsPrint(const char *str); uint32_t baudrate;
const char *ubx;
const char *mtk;
} gpsInitData_t;
#define UBX_INIT_STRING_INDEX 0 static const gpsInitData_t gpsInitData[] = {
#define MTK_INIT_STRING_INDEX 4 { 115200, "$PUBX,41,1,0003,0001,115200,0*1E\r\n", "$PMTK251,115200*1F\r\n" },
{ 57600, "$PUBX,41,1,0003,0001,57600,0*2D\r\n", "$PMTK251,57600*2C\r\n" },
static const char * const gpsInitStrings[] = { { 38400, "$PUBX,41,1,0003,0001,38400,0*26\r\n", "$PMTK251,38400*27\r\n" },
"$PUBX,41,1,0003,0001,19200,0*23\r\n", // UBX0..3 { 19200, "$PUBX,41,1,0003,0001,19200,0*23\r\n", "$PMTK251,19200*22\r\n" },
"$PUBX,41,1,0003,0001,38400,0*26\r\n", // 9600 is not enough for 5Hz updates - leave for compatibility to dumb NMEA that only runs at this speed
"$PUBX,41,1,0003,0001,57600,0*2D\r\n", { 9600, "", "" }
"$PUBX,41,1,0003,0001,115200,0*1E\r\n",
"$PMTK251,19200*22\r\n", // MTK4..7
"$PMTK251,38400*27\r\n",
"$PMTK251,57600*2C\r\n",
"$PMTK251,115200*1F\r\n",
}; };
static const uint8_t ubloxInit[] = { static const uint8_t ubloxInit[] = {
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x05, 0x00, 0xFF, 0x19, // disable all default NMEA messages 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x05, 0x00, 0xFF, 0x19, // VGS: Course over ground and Ground speed
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x03, 0x00, 0xFD, 0x15, 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x03, 0x00, 0xFD, 0x15, // GSV: GNSS Satellites in View
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x01, 0x00, 0xFB, 0x11, 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x01, 0x00, 0xFB, 0x11, // GLL: Latitude and longitude, with time of position fix and status
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x00, 0x00, 0xFA, 0x0F, 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x00, 0x00, 0xFA, 0x0F, // GGA: Global positioning system fix data
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x02, 0x00, 0xFC, 0x13, 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x02, 0x00, 0xFC, 0x13, // GSA: GNSS DOP and Active Satellites
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x04, 0x00, 0xFE, 0x17, 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0xF0, 0x04, 0x00, 0xFE, 0x17, // RMC: Recommended Minimum data
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x02, 0x01, 0x0E, 0x47, // set POSLLH MSG rate 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x02, 0x01, 0x0E, 0x47, // set POSLLH MSG rate
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x03, 0x01, 0x0F, 0x49, // set STATUS MSG rate 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x03, 0x01, 0x0F, 0x49, // set STATUS MSG rate
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x06, 0x01, 0x12, 0x4F, // set SOL MSG rate 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x06, 0x01, 0x12, 0x4F, // set SOL MSG rate
0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x12, 0x01, 0x1E, 0x67, // set VELNED MSG rate 0xB5, 0x62, 0x06, 0x01, 0x03, 0x00, 0x01, 0x12, 0x01, 0x1E, 0x67, // set VELNED MSG rate
0xB5, 0x62, 0x06, 0x16, 0x08, 0x00, 0x03, 0x07, 0x03, 0x00, 0x51, 0x08, 0x00, 0x00, 0x8A, 0x41, // set WAAS to EGNOS 0xB5, 0x62, 0x06, 0x16, 0x08, 0x00, 0x03, 0x07, 0x03, 0x00, 0x51, 0x08, 0x00, 0x00, 0x8A, 0x41, // set WAAS to EGNOS
0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xC8, 0x00, 0x01, 0x00, 0x01, 0x00, 0xDE, 0x6A // set rate to 5Hz 0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xC8, 0x00, 0x01, 0x00, 0x01, 0x00, 0xDE, 0x6A, // set rate to 5Hz
}; };
void gpsInit(uint32_t baudrate) static const char *mtkNMEAInit[] = {
"$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n", // only GGA and RMC sentence
"$PMTK220,200*2C\r\n" // 5 Hz update rate
};
static const char *mtkBinaryInit[] = {
"$PMTK319,1*24\r\n", // SBAS Integrity Mode
"$PMTK220,200*2C\r\n", // 5 Hz update rate
"$PMTK397,0*23\r\n", // NAVTHRES_OFF
"$PMTK313,1*2E\r\n", // SBAS_ON
"$PMTK301,2*2E\r\n", // WAAS_ON
"$PGCMD,16,0,0,0,0,0*6A\r\n" // Binary ON
};
enum {
GPS_UNKNOWN,
GPS_INITIALIZING,
GPS_INITDONE,
GPS_RECEIVINGDATA,
GPS_LOSTCOMMS,
};
typedef struct gpsData_t {
uint8_t state; // GPS thread state. Used for detecting cable disconnects and configuring attached devices
uint8_t baudrateIndex; // index into auto-detecting or current baudrate
int errors; // gps error counter - crc error/lost of data/sync etc. reset on each reinit.
uint32_t lastMessage; // last time valid GPS data was received (millis)
uint32_t lastLastMessage; // last-last valid GPS message. Used to calculate delta.
uint32_t state_position; // incremental variable for loops
} gpsData_t;
gpsData_t gpsData;
static void gpsNewData(uint16_t c);
static bool gpsNewFrameNMEA(char c);
static bool gpsNewFrameUBLOX(uint8_t data);
static void gpsSetState(uint8_t state)
{ {
int i; gpsData.state = state;
int offset = 0; gpsData.state_position = 0;
GPS_set_pids();
core.gpsport = uartOpen(USART2, GPS_NewData, baudrate, MODE_RXTX);
if (mcfg.gps_type == GPS_UBLOX)
offset = UBX_INIT_STRING_INDEX;
else if (mcfg.gps_type == GPS_MTK)
offset = MTK_INIT_STRING_INDEX;
if (mcfg.gps_type != GPS_NMEA) {
for (i = 0; i < 5; i++) {
serialSetBaudRate(core.gpsport, init_speed[i]);
// verify the requested change took effect.
baudrate = serialGetBaudRate(core.gpsport);
switch (baudrate) {
case 19200:
gpsPrint(gpsInitStrings[offset]);
break;
case 38400:
gpsPrint(gpsInitStrings[offset + 1]);
break;
case 57600:
gpsPrint(gpsInitStrings[offset + 2]);
break;
case 115200:
gpsPrint(gpsInitStrings[offset + 3]);
break;
}
delay(10);
}
}
serialSetBaudRate(core.gpsport, baudrate);
if (mcfg.gps_type == GPS_UBLOX) {
for (i = 0; i < sizeof(ubloxInit); i++) {
serialWrite(core.gpsport, ubloxInit[i]); // send ubx init binary
delay(4);
}
} else if (mcfg.gps_type == GPS_MTK) {
gpsPrint("$PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28\r\n"); // only GGA and RMC sentence
gpsPrint("$PMTK220,200*2C\r\n"); // 5 Hz update rate
}
// catch some GPS frames. TODO check this
delay(1000);
if (GPS_Present)
sensorsSet(SENSOR_GPS);
} }
static void gpsPrint(const char *str) void gpsInit(uint8_t baudrate)
{ {
while (*str) { portMode_t mode = MODE_RXTX;
serialWrite(core.gpsport, *str);
if (mcfg.gps_type == GPS_UBLOX) // init gpsData structure. if we're not actually enabled, don't bother doing anything else
delay(4); gpsSetState(GPS_UNKNOWN);
str++; if (!feature(FEATURE_GPS))
} return;
// wait to send all
while (!isSerialTransmitBufferEmpty(core.gpsport)); gpsData.baudrateIndex = baudrate;
delay(30); gpsData.lastMessage = millis();
gpsData.errors = 0;
// only RX is needed for NMEA-style GPS
if (mcfg.gps_type == GPS_NMEA)
mode = MODE_RX;
gpsSetPIDs();
core.gpsport = uartOpen(USART2, gpsNewData, gpsInitData[baudrate].baudrate, mode);
// signal GPS "thread" to initialize when it gets to it
gpsSetState(GPS_INITIALIZING);
} }
void gpsInitHardware(void)
{
switch (mcfg.gps_type) {
case GPS_NMEA:
// nothing to do, just set baud rate and try receiving some stuff and see if it parses
serialSetBaudRate(core.gpsport, gpsInitData[gpsData.baudrateIndex].baudrate);
gpsSetState(GPS_RECEIVINGDATA);
return;
case GPS_UBLOX:
// UBX will run at mcfg.baudrate, it shouldn't be "autodetected". So here we force it to that rate
// Wait until GPS transmit buffer is empty
if (!isSerialTransmitBufferEmpty(core.gpsport))
break;
if (gpsData.state == GPS_INITIALIZING) {
if (gpsData.state_position < GPS_INIT_ENTRIES) {
// try different speed to INIT
serialSetBaudRate(core.gpsport, gpsInitData[gpsData.state_position].baudrate);
// but print our FIXED init string for the baudrate we want to be at
serialPrint(core.gpsport, gpsInitData[mcfg.gps_baudrate].ubx);
gpsData.state_position++;
} else {
// we're now (hopefully) at the correct rate, next state will switch to it
gpsData.baudrateIndex = mcfg.gps_baudrate;
gpsSetState(GPS_INITDONE);
}
} else {
// GPS_INITDONE, set our real baud rate and push some ublox config strings
if (gpsData.state_position == 0)
serialSetBaudRate(core.gpsport, gpsInitData[gpsData.baudrateIndex].baudrate);
if (gpsData.state_position < sizeof(ubloxInit)) {
serialWrite(core.gpsport, ubloxInit[gpsData.state_position]); // send ubx init binary
gpsData.state_position++;
} else {
// ublox should be init'd, time to try receiving some junk
gpsSetState(GPS_RECEIVINGDATA);
}
}
break;
case GPS_MTK_NMEA:
case GPS_MTK_BINARY:
// TODO. need to find my old piece of shit MTK GPS.
break;
}
// clear error counter
gpsData.errors = 0;
}
void gpsThread(void)
{
switch (gpsData.state) {
case GPS_UNKNOWN:
break;
case GPS_INITIALIZING:
case GPS_INITDONE:
gpsInitHardware();
break;
case GPS_LOSTCOMMS:
gpsData.errors++;
// try another rate
gpsData.baudrateIndex++;
gpsData.baudrateIndex %= GPS_INIT_ENTRIES;
gpsData.lastMessage = millis();
// TODO - move some / all of these into gpsData
GPS_numSat = 0;
f.GPS_FIX = 0;
gpsSetState(GPS_INITIALIZING);
break;
case GPS_RECEIVINGDATA:
// check for no data/gps timeout/cable disconnection etc
if (millis() - gpsData.lastMessage > GPS_TIMEOUT) {
// remove GPS from capability
sensorsClear(SENSOR_GPS);
gpsSetState(GPS_LOSTCOMMS);
}
break;
}
}
static bool gpsNewFrame(uint8_t c)
{
switch (mcfg.gps_type) {
case GPS_NMEA: // NMEA
case GPS_MTK_NMEA: // MTK in NMEA mode
return gpsNewFrameNMEA(c);
case GPS_UBLOX: // UBX binary
return gpsNewFrameUBLOX(c);
case GPS_MTK_BINARY: // MTK in BINARY mode (TODO)
return false;
}
return false;
}
/*----------------------------------------------------------- /*-----------------------------------------------------------
* *
* Multiwii GPS code - revision: 1097 * Multiwii GPS code - revision: 1097
@ -130,9 +238,6 @@ static void GPS_calc_location_error(int32_t * target_lat, int32_t * target_lng,
static void GPS_calc_poshold(void); static void GPS_calc_poshold(void);
static void GPS_calc_nav_rate(int max_speed); static void GPS_calc_nav_rate(int max_speed);
static void GPS_update_crosstrack(void); static void GPS_update_crosstrack(void);
static bool GPS_newFrame(char c);
static bool GPS_NMEA_newFrame(char c);
static bool GPS_UBLOX_newFrame(uint8_t data);
static bool UBLOX_parse_gps(void); static bool UBLOX_parse_gps(void);
static int16_t GPS_calc_desired_speed(int16_t max_speed, bool _slow); static int16_t GPS_calc_desired_speed(int16_t max_speed, bool _slow);
int32_t wrap_18000(int32_t error); int32_t wrap_18000(int32_t error);
@ -285,7 +390,7 @@ static int32_t nav_bearing;
// saves the bearing at takeof (1deg = 1) used to rotate to takeoff direction when arrives at home // saves the bearing at takeof (1deg = 1) used to rotate to takeoff direction when arrives at home
static int16_t nav_takeoff_bearing; static int16_t nav_takeoff_bearing;
void GPS_NewData(uint16_t c) static void gpsNewData(uint16_t c)
{ {
int axis; int axis;
static uint32_t nav_loopTimer; static uint32_t nav_loopTimer;
@ -293,7 +398,11 @@ void GPS_NewData(uint16_t c)
int32_t dir; int32_t dir;
int16_t speed; int16_t speed;
if (GPS_newFrame(c)) { if (gpsNewFrame(c)) {
// new data received and parsed, we're in business
gpsData.lastLastMessage = gpsData.lastMessage;
gpsData.lastMessage = millis();
sensorsSet(SENSOR_GPS);
if (GPS_update == 1) if (GPS_update == 1)
GPS_update = 0; GPS_update = 0;
else else
@ -411,7 +520,7 @@ void GPS_reset_nav(void)
} }
// Get the relevant P I D values and set the PID controllers // Get the relevant P I D values and set the PID controllers
void GPS_set_pids(void) void gpsSetPIDs(void)
{ {
posholdPID_PARAM.kP = (float)cfg.P8[PIDPOS] / 100.0f; posholdPID_PARAM.kP = (float)cfg.P8[PIDPOS] / 100.0f;
posholdPID_PARAM.kI = (float)cfg.I8[PIDPOS] / 100.0f; posholdPID_PARAM.kI = (float)cfg.I8[PIDPOS] / 100.0f;
@ -428,6 +537,31 @@ void GPS_set_pids(void)
navPID_PARAM.Imax = POSHOLD_RATE_IMAX * 100; navPID_PARAM.Imax = POSHOLD_RATE_IMAX * 100;
} }
int8_t gpsSetPassthrough(void)
{
if (gpsData.state != GPS_RECEIVINGDATA)
return -1;
// get rid of callback
core.gpsport->callback = NULL;
LED0_OFF;
LED1_OFF;
while(1) {
if (serialTotalBytesWaiting(core.gpsport)) {
LED0_ON;
serialWrite(core.mainport, serialRead(core.gpsport));
LED0_OFF;
}
if (serialTotalBytesWaiting(core.mainport)) {
LED1_ON;
serialWrite(core.gpsport, serialRead(core.mainport));
LED1_OFF;
}
}
}
// OK here is the onboard GPS code // OK here is the onboard GPS code
//////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////
@ -777,19 +911,6 @@ static uint8_t hex_c(uint8_t n)
return n; return n;
} }
static bool GPS_newFrame(char c)
{
switch (mcfg.gps_type) {
case GPS_NMEA: // NMEA
case GPS_MTK: // MTK outputs NMEA too
return GPS_NMEA_newFrame(c);
case GPS_UBLOX: // UBX
return GPS_UBLOX_newFrame(c);
}
return false;
}
/* This is a light implementation of a GPS frame decoding /* This is a light implementation of a GPS frame decoding
This should work with most of modern GPS devices configured to output NMEA frames. This should work with most of modern GPS devices configured to output NMEA frames.
It assumes there are some NMEA GGA frames to decode on the serial bus It assumes there are some NMEA GGA frames to decode on the serial bus
@ -805,7 +926,7 @@ static bool GPS_newFrame(char c)
#define FRAME_GGA 1 #define FRAME_GGA 1
#define FRAME_RMC 2 #define FRAME_RMC 2
static bool GPS_NMEA_newFrame(char c) static bool gpsNewFrameNMEA(char c)
{ {
uint8_t frameOK = 0; uint8_t frameOK = 0;
static uint8_t param = 0, offset = 0, parity = 0; static uint8_t param = 0, offset = 0, parity = 0;
@ -868,8 +989,6 @@ static bool GPS_NMEA_newFrame(char c)
if (!checksum_param) if (!checksum_param)
parity ^= c; parity ^= c;
} }
if (frame)
GPS_Present = 1;
return frameOK && (frame == FRAME_GGA); return frameOK && (frame == FRAME_GGA);
} }
@ -1026,7 +1145,7 @@ void _update_checksum(uint8_t *data, uint8_t len, uint8_t *ck_a, uint8_t *ck_b)
} }
} }
static bool GPS_UBLOX_newFrame(uint8_t data) static bool gpsNewFrameUBLOX(uint8_t data)
{ {
bool parsed = false; bool parsed = false;
@ -1083,10 +1202,8 @@ static bool GPS_UBLOX_newFrame(uint8_t data)
_step = 0; _step = 0;
if (_ck_b != data) if (_ck_b != data)
break; // bad checksum break; // bad checksum
GPS_Present = 1; if (UBLOX_parse_gps())
if (UBLOX_parse_gps()) {
parsed = true; parsed = true;
}
} //end switch } //end switch
return parsed; return parsed;
} }

View File

@ -26,7 +26,7 @@ float accVelScale;
int16_t gyroData[3] = { 0, 0, 0 }; int16_t gyroData[3] = { 0, 0, 0 };
int16_t gyroZero[3] = { 0, 0, 0 }; int16_t gyroZero[3] = { 0, 0, 0 };
int16_t angle[2] = { 0, 0 }; // absolute angle inclination in multiple of 0.1 degree 180 deg = 1800 int16_t angle[2] = { 0, 0 }; // absolute angle inclination in multiple of 0.1 degree 180 deg = 1800
float anglerad[2] = { 0, 0 }; // absolute angle inclination in radians float anglerad[2] = { 0.0f, 0.0f }; // absolute angle inclination in radians
static void getEstimatedAttitude(void); static void getEstimatedAttitude(void);
@ -67,12 +67,14 @@ void computeIMU(void)
Smoothing[YAW] = (mcfg.gyro_smoothing_factor) & 0xff; Smoothing[YAW] = (mcfg.gyro_smoothing_factor) & 0xff;
} }
for (axis = 0; axis < 3; axis++) { for (axis = 0; axis < 3; axis++) {
gyroData[axis] = (int16_t)(((int32_t)((int32_t)gyroSmooth[axis] * (Smoothing[axis] - 1)) + gyroData[axis] + 1) / Smoothing[axis]); gyroData[axis] = (int16_t)(((int32_t)((int32_t)gyroSmooth[axis] * (Smoothing[axis] - 1)) + gyroADC[axis] + 1) / Smoothing[axis]);
gyroSmooth[axis] = gyroData[axis]; gyroSmooth[axis] = gyroData[axis];
} }
} else if (mcfg.mixerConfiguration == MULTITYPE_TRI) { } else if (mcfg.mixerConfiguration == MULTITYPE_TRI) {
gyroData[YAW] = (gyroYawSmooth * 2 + gyroData[YAW]) / 3; gyroData[YAW] = (gyroYawSmooth * 2 + gyroADC[YAW]) / 3;
gyroYawSmooth = gyroData[YAW]; gyroYawSmooth = gyroData[YAW];
gyroData[ROLL] = gyroADC[ROLL];
gyroData[PITCH] = gyroADC[PITCH];
} else { } else {
for (axis = 0; axis < 3; axis++) for (axis = 0; axis < 3; axis++)
gyroData[axis] = gyroADC[axis]; gyroData[axis] = gyroADC[axis];
@ -172,17 +174,21 @@ int32_t applyDeadband(int32_t value, int32_t deadband)
return value; return value;
} }
#define F_CUT_ACCZ 20.0f
static const float fc_acc = 0.5f / (M_PI * F_CUT_ACCZ);
// rotate acc into Earth frame and calculate acceleration in it // rotate acc into Earth frame and calculate acceleration in it
void acc_calc(uint32_t deltaT) void acc_calc(uint32_t deltaT)
{ {
static int32_t accZoffset = 0; static int32_t accZoffset = 0;
static float accz_smooth;
float rpy[3]; float rpy[3];
t_fp_vector accel_ned; t_fp_vector accel_ned;
// the accel values have to be rotated into the earth frame // the accel values have to be rotated into the earth frame
rpy[0] = -(float)anglerad[ROLL]; rpy[0] = -(float)anglerad[ROLL];
rpy[1] = -(float)anglerad[PITCH]; rpy[1] = -(float)anglerad[PITCH];
rpy[2] = -(float)heading * RADX10 * 10.0f; rpy[2] = -(float)heading * RAD;
accel_ned.V.X = accSmooth[0]; accel_ned.V.X = accSmooth[0];
accel_ned.V.Y = accSmooth[1]; accel_ned.V.Y = accSmooth[1];
@ -199,18 +205,20 @@ void acc_calc(uint32_t deltaT)
} else } else
accel_ned.V.Z -= acc_1G; accel_ned.V.Z -= acc_1G;
accz_smooth = accz_smooth + (deltaT / (fc_acc + deltaT)) * (accel_ned.V.Z - accz_smooth); // low pass filter
// apply Deadband to reduce integration drift and vibration influence // apply Deadband to reduce integration drift and vibration influence
accel_ned.V.Z = applyDeadband(accel_ned.V.Z, cfg.accz_deadband); accel_ned.V.Z = applyDeadband(lrintf(accz_smooth), cfg.accz_deadband);
accel_ned.V.X = applyDeadband(accel_ned.V.X, cfg.accxy_deadband); accel_ned.V.X = applyDeadband(lrintf(accel_ned.V.X), cfg.accxy_deadband);
accel_ned.V.Y = applyDeadband(accel_ned.V.Y, cfg.accxy_deadband); accel_ned.V.Y = applyDeadband(lrintf(accel_ned.V.Y), cfg.accxy_deadband);
// sum up Values for later integration to get velocity and distance // sum up Values for later integration to get velocity and distance
accTimeSum += deltaT; accTimeSum += deltaT;
accSumCount++; accSumCount++;
accSum[0] += accel_ned.V.X; accSum[X] += lrintf(accel_ned.V.X);
accSum[1] += accel_ned.V.Y; accSum[Y] += lrintf(accel_ned.V.Y);
accSum[2] += accel_ned.V.Z; accSum[Z] += lrintf(accel_ned.V.Z);
} }
void accSum_reset(void) void accSum_reset(void)
@ -288,7 +296,7 @@ static void getEstimatedAttitude(void)
EstM.A[axis] = (EstM.A[axis] * (float)mcfg.gyro_cmpfm_factor + magADC[axis]) * INV_GYR_CMPFM_FACTOR; EstM.A[axis] = (EstM.A[axis] * (float)mcfg.gyro_cmpfm_factor + magADC[axis]) * INV_GYR_CMPFM_FACTOR;
} }
if (abs(EstG.A[Z]) > accZ_25deg) if (EstG.A[Z] > accZ_25deg)
f.SMALL_ANGLES_25 = 1; f.SMALL_ANGLES_25 = 1;
else else
f.SMALL_ANGLES_25 = 0; f.SMALL_ANGLES_25 = 0;
@ -307,7 +315,7 @@ static void getEstimatedAttitude(void)
acc_calc(deltaT); // rotate acc vector into earth frame acc_calc(deltaT); // rotate acc vector into earth frame
if (cfg.throttle_angle_correction) { if (cfg.throttle_angle_correction) {
int cosZ = EstG.V.Z / acc_1G * 100.0f; int cosZ = EstG.V.Z / (acc_1G * 100.0f);
throttleAngleCorrection = cfg.throttle_angle_correction * constrain(100 - cosZ, 0, 100) / 8; throttleAngleCorrection = cfg.throttle_angle_correction * constrain(100 - cosZ, 0, 100) / 8;
} }
} }
@ -317,7 +325,6 @@ static void getEstimatedAttitude(void)
int getEstimatedAltitude(void) int getEstimatedAltitude(void)
{ {
static int32_t baroGroundPressure;
static uint32_t previousT; static uint32_t previousT;
uint32_t currentT = micros(); uint32_t currentT = micros();
uint32_t dTime; uint32_t dTime;
@ -326,11 +333,12 @@ int getEstimatedAltitude(void)
int32_t vel_tmp; int32_t vel_tmp;
int32_t BaroAlt_tmp; int32_t BaroAlt_tmp;
float dt; float dt;
float PressureScaling;
float vel_acc; float vel_acc;
static float vel = 0.0f; static float vel = 0.0f;
static float accAlt = 0.0f; static float accAlt = 0.0f;
static int32_t lastBaroAlt; static int32_t lastBaroAlt;
static int32_t baroGroundAltitude = 0;
static int32_t baroGroundPressure = 0;
dTime = currentT - previousT; dTime = currentT - previousT;
if (dTime < UPDATE_INTERVAL) if (dTime < UPDATE_INTERVAL)
@ -338,19 +346,22 @@ int getEstimatedAltitude(void)
previousT = currentT; previousT = currentT;
if (calibratingB > 0) { if (calibratingB > 0) {
baroGroundPressure = baroPressureSum / (cfg.baro_tab_size - 1); baroGroundPressure -= baroGroundPressure / 8;
calibratingB--; baroGroundPressure += baroPressureSum / (cfg.baro_tab_size - 1);
baroGroundAltitude = (1.0f - powf((baroGroundPressure / 8) / 101325.0f, 0.190295f)) * 4433000.0f;
vel = 0; vel = 0;
accAlt = 0; accAlt = 0;
calibratingB--;
} }
// calculates height from ground via baro readings // calculates height from ground via baro readings
// see: https://github.com/diydrones/ardupilot/blob/master/libraries/AP_Baro/AP_Baro.cpp#L140 // see: https://github.com/diydrones/ardupilot/blob/master/libraries/AP_Baro/AP_Baro.cpp#L140
PressureScaling = (float)baroPressureSum / ((float)baroGroundPressure * (float)(cfg.baro_tab_size - 1)); BaroAlt_tmp = lrintf((1.0f - powf((float)(baroPressureSum / (cfg.baro_tab_size - 1)) / 101325.0f, 0.190295f)) * 4433000.0f); // in cm
BaroAlt_tmp = 153.8462f * (baroTemperature + 27315) * (1.0f - expf(0.190259f * logf(PressureScaling))); // in cm BaroAlt_tmp -= baroGroundAltitude;
BaroAlt = (float)BaroAlt * cfg.baro_noise_lpf + (float)BaroAlt_tmp * (1.0f - cfg.baro_noise_lpf); // additional LPF to reduce baro noise BaroAlt = lrintf((float)BaroAlt * cfg.baro_noise_lpf + (float)BaroAlt_tmp * (1.0f - cfg.baro_noise_lpf)); // additional LPF to reduce baro noise
dt = accTimeSum * 1e-6; // delta acc reading time in seconds dt = accTimeSum * 1e-6f; // delta acc reading time in seconds
// Integrator - velocity, cm/sec // Integrator - velocity, cm/sec
vel_acc = (float)accSum[2] * accVelScale * (float)accTimeSum / (float)accSumCount; vel_acc = (float)accSum[2] * accVelScale * (float)accTimeSum / (float)accSumCount;
@ -391,7 +402,7 @@ int getEstimatedAltitude(void)
vel = constrain(vel, -1000, 1000); // limit max velocity to +/- 10m/s (36km/h) vel = constrain(vel, -1000, 1000); // limit max velocity to +/- 10m/s (36km/h)
// D // D
vel_tmp = vel; vel_tmp = lrintf(vel);
vel_tmp = applyDeadband(vel_tmp, 5); vel_tmp = applyDeadband(vel_tmp, 5);
vario = vel_tmp; vario = vel_tmp;
BaroPID -= constrain(cfg.D8[PIDALT] * vel_tmp / 16, -150, 150); BaroPID -= constrain(cfg.D8[PIDALT] * vel_tmp / 16, -150, 150);

View File

@ -30,7 +30,9 @@ int main(void)
uint8_t i; uint8_t i;
drv_pwm_config_t pwm_params; drv_pwm_config_t pwm_params;
drv_adc_config_t adc_params; drv_adc_config_t adc_params;
#ifdef SOFTSERIAL_LOOPBACK
serialPort_t* loopbackPort = NULL; serialPort_t* loopbackPort = NULL;
#endif
systemInit(); systemInit();
#ifdef USE_LAME_PRINTF #ifdef USE_LAME_PRINTF
@ -49,6 +51,7 @@ int main(void)
} }
adcInit(&adc_params); adcInit(&adc_params);
initBoardAlignment();
// We have these sensors; SENSORS_SET defined in board.h depending on hardware platform // We have these sensors; SENSORS_SET defined in board.h depending on hardware platform
sensorsSet(SENSORS_SET); sensorsSet(SENSORS_SET);
@ -67,6 +70,7 @@ int main(void)
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.idlePulse = feature(FEATURE_3D) ? mcfg.neutral3d : 0;
pwm_params.failsafeThreshold = cfg.failsafe_detect_threshold; pwm_params.failsafeThreshold = cfg.failsafe_detect_threshold;
switch (mcfg.power_adc_channel) { switch (mcfg.power_adc_channel) {
case 1: case 1:
@ -82,8 +86,11 @@ int main(void)
pwmInit(&pwm_params); pwmInit(&pwm_params);
// configure PWM/CPPM read function. spektrum or sbus below will override that // configure PWM/CPPM read function and max number of channels. spektrum or sbus below will override both of these, if enabled
for (i = 0; i < RC_CHANS; i++)
rcData[i] = 1502;
rcReadRawFunc = pwmReadRawRC; rcReadRawFunc = pwmReadRawRC;
core.numRCChannels = MAX_INPUTS;
if (feature(FEATURE_SERIALRX)) { if (feature(FEATURE_SERIALRX)) {
switch (mcfg.serialrx_type) { switch (mcfg.serialrx_type) {
@ -96,10 +103,12 @@ int main(void)
sbusInit(&rcReadRawFunc); sbusInit(&rcReadRawFunc);
break; break;
} }
} else { } else { // spektrum and GPS are mutually exclusive
// spektrum and GPS are mutually exclusive
// Optional GPS - available in both PPM and PWM input mode, in PWM input, reduces number of available channels by 2. // Optional GPS - available in both PPM and PWM input mode, in PWM input, reduces number of available channels by 2.
if (feature(FEATURE_GPS)) // gpsInit will return if FEATURE_GPS is not enabled.
// Sanity check below - protocols other than NMEA do not support baud rate autodetection
if (mcfg.gps_type > 0 && mcfg.gps_baudrate < 0)
mcfg.gps_baudrate = 0;
gpsInit(mcfg.gps_baudrate); gpsInit(mcfg.gps_baudrate);
} }
#ifdef SONAR #ifdef SONAR
@ -141,6 +150,9 @@ int main(void)
#endif #endif
} }
if (feature(FEATURE_TELEMETRY))
initTelemetry();
previousTime = micros(); previousTime = micros();
if (mcfg.mixerConfiguration == MULTITYPE_GIMBAL) if (mcfg.mixerConfiguration == MULTITYPE_GIMBAL)
calibratingA = CALIBRATING_ACC_CYCLES; calibratingA = CALIBRATING_ACC_CYCLES;

View File

@ -3,7 +3,8 @@
static uint8_t numberMotor = 0; static uint8_t numberMotor = 0;
int16_t motor[MAX_MOTORS]; int16_t motor[MAX_MOTORS];
int16_t servo[8] = { 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500 }; int16_t motor_disarmed[MAX_MOTORS];
int16_t servo[MAX_SERVOS] = { 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500 };
static motorMixer_t currentMixer[MAX_MOTORS]; static motorMixer_t currentMixer[MAX_MOTORS];
@ -106,6 +107,20 @@ static const motorMixer_t mixerVtail4[] = {
{ 1.0f, 1.0f, -1.0f, -0.0f }, // FRONT_L { 1.0f, 1.0f, -1.0f, -0.0f }, // FRONT_L
}; };
static const motorMixer_t mixerHex6H[] = {
{ 1.0f, -1.0f, 1.0f, -1.0f }, // REAR_R
{ 1.0f, -1.0f, -1.0f, 1.0f }, // FRONT_R
{ 1.0f, 1.0f, 1.0f, 1.0f }, // REAR_L
{ 1.0f, 1.0f, -1.0f, -1.0f }, // FRONT_L
{ 1.0f, 0.0f, 0.0f, 0.0f }, // RIGHT
{ 1.0f, 0.0f, 0.0f, 0.0f }, // LEFT
};
static const motorMixer_t mixerDualcopter[] = {
{ 1.0f, 0.0f, 0.0f, -1.0f }, // LEFT
{ 1.0f, 0.0f, 0.0f, 1.0f }, // RIGHT
};
// Keep this synced with MultiType struct in mw.h! // Keep this synced with MultiType struct in mw.h!
const mixer_t mixers[] = { const mixer_t mixers[] = {
// Mo Se Mixtable // Mo Se Mixtable
@ -127,9 +142,37 @@ const mixer_t mixers[] = {
{ 0, 1, NULL }, // * MULTITYPE_HELI_120_CCPM { 0, 1, NULL }, // * MULTITYPE_HELI_120_CCPM
{ 0, 1, NULL }, // * MULTITYPE_HELI_90_DEG { 0, 1, NULL }, // * MULTITYPE_HELI_90_DEG
{ 4, 0, mixerVtail4 }, // MULTITYPE_VTAIL4 { 4, 0, mixerVtail4 }, // MULTITYPE_VTAIL4
{ 6, 0, mixerHex6H }, // MULTITYPE_HEX6H
{ 0, 1, NULL }, // * MULTITYPE_PPM_TO_SERVO
{ 2, 1, mixerDualcopter }, // MULTITYPE_DUALCOPTER
{ 1, 1, NULL }, // MULTITYPE_SINGLECOPTER
{ 0, 0, NULL }, // MULTITYPE_CUSTOM { 0, 0, NULL }, // MULTITYPE_CUSTOM
}; };
int16_t servoMiddle(int nr)
{
// Normally, servo.middle is a value between 1000..2000, but for the purposes of stupid, if it's less than
// the number of RC channels, it means the center value is taken FROM that RC channel (by its index)
if (cfg.servoConf[nr].middle < RC_CHANS && nr < MAX_SERVOS)
return rcData[cfg.servoConf[nr].middle];
else
return cfg.servoConf[nr].middle;
}
int servoDirection(int nr, int lr)
{
// servo.rate is overloaded for servos that don't have a rate, but only need direction
// bit set = negative, clear = positive
// rate[2] = ???_direction
// rate[1] = roll_direction
// rate[0] = pitch_direction
// servo.rate is also used as gimbal gain multiplier (yeah)
if (cfg.servoConf[nr].rate & lr)
return -1;
else
return 1;
}
void mixerInit(void) void mixerInit(void)
{ {
int i; int i;
@ -168,6 +211,15 @@ void mixerInit(void)
} }
} }
} }
mixerResetMotors();
}
void mixerResetMotors(void)
{
int i;
// set disarmed motor values
for (i = 0; i < MAX_MOTORS; i++)
motor_disarmed[i] = feature(FEATURE_3D) ? mcfg.neutral3d : mcfg.mincommand;
} }
void mixerLoadMix(int index) void mixerLoadMix(int index)
@ -211,16 +263,29 @@ void writeServos(void)
} }
break; break;
case MULTITYPE_AIRPLANE: case MULTITYPE_FLYING_WING:
pwmWriteServo(0, servo[3]);
pwmWriteServo(1, servo[4]);
break; break;
case MULTITYPE_FLYING_WING:
case MULTITYPE_GIMBAL: case MULTITYPE_GIMBAL:
pwmWriteServo(0, servo[0]); pwmWriteServo(0, servo[0]);
pwmWriteServo(1, servo[1]); pwmWriteServo(1, servo[1]);
break; break;
case MULTITYPE_DUALCOPTER:
pwmWriteServo(0, servo[4]);
pwmWriteServo(1, servo[5]);
break;
case MULTITYPE_AIRPLANE:
case MULTITYPE_SINGLECOPTER:
pwmWriteServo(0, servo[3]);
pwmWriteServo(1, servo[4]);
pwmWriteServo(2, servo[5]);
pwmWriteServo(3, servo[6]);
break;
default: default:
// Two servos for SERVO_TILT, if enabled // Two servos for SERVO_TILT, if enabled
if (feature(FEATURE_SERVO_TILT)) { if (feature(FEATURE_SERVO_TILT)) {
@ -253,52 +318,55 @@ void writeAllMotors(int16_t mc)
static void airplaneMixer(void) static void airplaneMixer(void)
{ {
#if 0 int16_t flapperons[2] = { 0, 0 };
uint16_t servomid[8]; int i;
int16_t flaperons[2] = { 0, 0 };
for (i = 0; i < 8; i++) {
servomid[i] = 1500 + cfg.servotrim[i]; // servo center is 1500?
}
if (!f.ARMED) if (!f.ARMED)
motor[0] = cfg.mincommand; // Kill throttle when disarmed servo[7] = mcfg.mincommand; // Kill throttle when disarmed
else else
motor[0] = rcData[THROTTLE]; servo[7] = constrain(rcCommand[THROTTLE], mcfg.minthrottle, mcfg.maxthrottle);
motor[0] = servo[7];
#if 0
if (cfg.flaperons) { if (cfg.flaperons) {
} }
#endif
if (cfg.flaps) { if (mcfg.flaps_speed) {
int16_t flap = 1500 - constrain(rcData[cfg.flaps], cfg.servoendpoint_low[2], cfg.servoendpoint_high[2]); // configure SERVO3 middle point in GUI to using an AUX channel for FLAPS control
static int16_t slowFlaps = flap; // use servo min, servo max and servo rate for proper endpoints adjust
static int16_t slow_LFlaps;
int16_t lFlap = servoMiddle(2);
if (cfg.flapspeed) { lFlap = constrain(lFlap, cfg.servoConf[2].min, cfg.servoConf[2].max);
if (slowFlaps < flap) { lFlap = mcfg.midrc - lFlap; // shouldn't this be servoConf[2].middle?
slowFlaps += cfg.flapspeed; if (slow_LFlaps < lFlap)
} else if (slowFlaps > flap) { slow_LFlaps += mcfg.flaps_speed;
slowFlaps -= cfg.flapspeed; else if (slow_LFlaps > lFlap)
} slow_LFlaps -= mcfg.flaps_speed;
} else {
slowFlaps = flap; servo[2] = ((int32_t)cfg.servoConf[2].rate * slow_LFlaps) / 100L;
} servo[2] += mcfg.midrc;
servo[2] = servomid[2] + (slowFlaps * cfg.servoreverse[2]);
} }
if (f.PASSTHRU_MODE) { // Direct passthru from RX if (f.PASSTHRU_MODE) { // Direct passthru from RX
servo[3] = servomid[3] + ((rcCommand[ROLL] + flapperons[0]) * cfg.servoreverse[3]); // Wing 1 servo[3] = rcCommand[ROLL] + flapperons[0]; // Wing 1
servo[4] = servomid[4] + ((rcCommand[ROLL] + flapperons[1]) * cfg.servoreverse[4]); // Wing 2 servo[4] = rcCommand[ROLL] + flapperons[1]; // Wing 2
servo[5] = servomid[5] + (rcCommand[YAW] * cfg.servoreverse[5]); // Rudder servo[5] = rcCommand[YAW]; // Rudder
servo[6] = servomid[6] + (rcCommand[PITCH] * cfg.servoreverse[6]); // Elevator servo[6] = rcCommand[PITCH]; // Elevator
} else { // Assisted modes (gyro only or gyro+acc according to AUX configuration in Gui } else {
servo[3] = (servomid[3] + ((axisPID[ROLL] + flapperons[0]) * cfg.servoreverse[3])); // Wing 1 // Assisted modes (gyro only or gyro+acc according to AUX configuration in Gui
servo[4] = (servomid[4] + ((axisPID[ROLL] + flapperons[1]) * cfg.servoreverse[4])); // Wing 2 servo[3] = axisPID[ROLL] + flapperons[0]; // Wing 1
servo[5] = (servomid[5] + (axisPID[YAW] * cfg.servoreverse[5])); // Rudder servo[4] = axisPID[ROLL] + flapperons[1]; // Wing 2
servo[6] = (servomid[6] + (axisPID[PITCH] * cfg.servoreverse[6])); // Elevator servo[5] = axisPID[YAW]; // Rudder
servo[6] = axisPID[PITCH]; // Elevator
}
for (i = 3; i < 7; i++) {
servo[i] = ((int32_t)cfg.servoConf[i].rate * servo[i]) / 100L; // servo rates
servo[i] += servoMiddle(i);
} }
#endif
} }
void mixTable(void) void mixTable(void)
@ -319,17 +387,17 @@ void mixTable(void)
// airplane / servo mixes // airplane / servo mixes
switch (mcfg.mixerConfiguration) { switch (mcfg.mixerConfiguration) {
case MULTITYPE_BI: case MULTITYPE_BI:
servo[4] = constrain(1500 + (-cfg.yaw_direction * axisPID[YAW]) + axisPID[PITCH], 1020, 2000); //LEFT servo[4] = (servoDirection(4, 2) * axisPID[YAW]) + (servoDirection(4, 1) * axisPID[PITCH]) + servoMiddle(4); // LEFT
servo[5] = constrain(1500 + (-cfg.yaw_direction * axisPID[YAW]) - axisPID[PITCH], 1020, 2000); //RIGHT servo[5] = (servoDirection(5, 2) * axisPID[YAW]) + (servoDirection(5, 1) * axisPID[PITCH]) + servoMiddle(5); // RIGHT
break; break;
case MULTITYPE_TRI: case MULTITYPE_TRI:
servo[5] = constrain(cfg.tri_yaw_middle + -cfg.yaw_direction * axisPID[YAW], cfg.tri_yaw_min, cfg.tri_yaw_max); //REAR servo[5] = (servoDirection(5, 1) * axisPID[YAW]) + servoMiddle(5); // REAR
break; break;
case MULTITYPE_GIMBAL: case MULTITYPE_GIMBAL:
servo[0] = constrain(cfg.gimbal_pitch_mid + cfg.gimbal_pitch_gain * angle[PITCH] / 16 + rcCommand[PITCH], cfg.gimbal_pitch_min, cfg.gimbal_pitch_max); servo[0] = (((int32_t)cfg.servoConf[0].rate * angle[PITCH]) / 50) + servoMiddle(0);
servo[1] = constrain(cfg.gimbal_roll_mid + cfg.gimbal_roll_gain * angle[ROLL] / 16 + rcCommand[ROLL], cfg.gimbal_roll_min, cfg.gimbal_roll_max); servo[1] = (((int32_t)cfg.servoConf[1].rate * angle[ROLL]) / 50) + servoMiddle(1);
break; break;
case MULTITYPE_AIRPLANE: case MULTITYPE_AIRPLANE:
@ -337,47 +405,62 @@ void mixTable(void)
break; break;
case MULTITYPE_FLYING_WING: case MULTITYPE_FLYING_WING:
motor[0] = rcCommand[THROTTLE]; if (!f.ARMED)
servo[7] = mcfg.mincommand;
else
servo[7] = constrain(rcCommand[THROTTLE], mcfg.minthrottle, mcfg.maxthrottle);
motor[0] = servo[7];
if (f.PASSTHRU_MODE) { if (f.PASSTHRU_MODE) {
// do not use sensors for correction, simple 2 channel mixing // do not use sensors for correction, simple 2 channel mixing
servo[0] = cfg.pitch_direction_l * (rcData[PITCH] - mcfg.midrc) + cfg.roll_direction_l * (rcData[ROLL] - mcfg.midrc); servo[3] = (servoDirection(3, 1) * rcCommand[PITCH]) + (servoDirection(3, 2) * rcCommand[ROLL]);
servo[1] = cfg.pitch_direction_r * (rcData[PITCH] - mcfg.midrc) + cfg.roll_direction_r * (rcData[ROLL] - mcfg.midrc); servo[4] = (servoDirection(4, 1) * rcCommand[PITCH]) + (servoDirection(4, 2) * rcCommand[ROLL]);
} else { } else {
// use sensors to correct (gyro only or gyro + acc) // use sensors to correct (gyro only or gyro + acc)
servo[0] = cfg.pitch_direction_l * axisPID[PITCH] + cfg.roll_direction_l * axisPID[ROLL]; servo[3] = (servoDirection(3, 1) * axisPID[PITCH]) + (servoDirection(3, 2) * axisPID[ROLL]);
servo[1] = cfg.pitch_direction_r * axisPID[PITCH] + cfg.roll_direction_r * axisPID[ROLL]; servo[4] = (servoDirection(4, 1) * axisPID[PITCH]) + (servoDirection(4, 2) * axisPID[ROLL]);
} }
servo[0] = constrain(servo[0] + cfg.wing_left_mid, cfg.wing_left_min, cfg.wing_left_max); servo[3] += servoMiddle(3);
servo[1] = constrain(servo[1] + cfg.wing_right_mid, cfg.wing_right_min, cfg.wing_right_max); servo[4] += servoMiddle(4);
break;
case MULTITYPE_DUALCOPTER:
for (i = 4; i < 6; i++ ) {
servo[i] = axisPID[5 - i] * servoDirection(i, 1); // mix and setup direction
servo[i] += servoMiddle(i);
}
break;
case MULTITYPE_SINGLECOPTER:
for (i = 3; i < 7; i++) {
servo[i] = (axisPID[YAW] * servoDirection(i, 2)) + (axisPID[(6 - i) >> 1] * servoDirection(i, 1)); // mix and setup direction
servo[i] += servoMiddle(i);
}
motor[0] = rcCommand[THROTTLE];
break; break;
} }
// do camstab // do camstab
if (feature(FEATURE_SERVO_TILT)) { if (feature(FEATURE_SERVO_TILT)) {
uint16_t aux[2] = { 0, 0 }; // center at fixed position, or vary either pitch or roll by RC channel
servo[0] = servoMiddle(0);
if ((cfg.gimbal_flags & GIMBAL_NORMAL) || (cfg.gimbal_flags & GIMBAL_TILTONLY)) servo[1] = servoMiddle(1);
aux[0] = rcData[AUX3] - mcfg.midrc;
if (!(cfg.gimbal_flags & GIMBAL_DISABLEAUX34))
aux[1] = rcData[AUX4] - mcfg.midrc;
servo[0] = cfg.gimbal_pitch_mid + aux[0];
servo[1] = cfg.gimbal_roll_mid + aux[1];
if (rcOptions[BOXCAMSTAB]) { if (rcOptions[BOXCAMSTAB]) {
if (cfg.gimbal_flags & GIMBAL_MIXTILT) { if (cfg.gimbal_flags & GIMBAL_MIXTILT) {
servo[0] -= (-cfg.gimbal_pitch_gain) * angle[PITCH] / 16 - cfg.gimbal_roll_gain * angle[ROLL] / 16; servo[0] -= (-(int32_t)cfg.servoConf[0].rate) * angle[PITCH] / 50 - (int32_t)cfg.servoConf[1].rate * angle[ROLL] / 50;
servo[1] += (-cfg.gimbal_pitch_gain) * angle[PITCH] / 16 + cfg.gimbal_roll_gain * angle[ROLL] / 16; servo[1] += (-(int32_t)cfg.servoConf[0].rate) * angle[PITCH] / 50 + (int32_t)cfg.servoConf[1].rate * angle[ROLL] / 50;
} else { } else {
servo[0] += cfg.gimbal_pitch_gain * angle[PITCH] / 16; servo[0] += (int32_t)cfg.servoConf[0].rate * angle[PITCH] / 50;
servo[1] += cfg.gimbal_roll_gain * angle[ROLL] / 16; servo[1] += (int32_t)cfg.servoConf[0].rate * angle[ROLL] / 50;
}
} }
} }
servo[0] = constrain(servo[0], cfg.gimbal_pitch_min, cfg.gimbal_pitch_max); // constrain servos
servo[1] = constrain(servo[1], cfg.gimbal_roll_min, cfg.gimbal_roll_max); for (i = 0; i < MAX_SERVOS; i++)
} servo[i] = constrain(servo[i], cfg.servoConf[i].min, cfg.servoConf[i].max); // limit the values
// forward AUX1-4 to servo outputs (not constrained)
if (cfg.gimbal_flags & GIMBAL_FORWARDAUX) { if (cfg.gimbal_flags & GIMBAL_FORWARDAUX) {
int offset = 0; int offset = 0;
if (feature(FEATURE_SERVO_TILT)) if (feature(FEATURE_SERVO_TILT))
@ -408,7 +491,8 @@ void mixTable(void)
motor[i] = mcfg.mincommand; motor[i] = mcfg.mincommand;
} }
} }
if (!f.ARMED) if (!f.ARMED) {
motor[i] = feature(FEATURE_3D) ? mcfg.neutral3d : mcfg.mincommand; motor[i] = motor_disarmed[i];
}
} }
} }

View File

@ -16,10 +16,10 @@ int16_t telemTemperature1; // gyro sensor temperature
int16_t failsafeCnt = 0; int16_t failsafeCnt = 0;
int16_t failsafeEvents = 0; int16_t failsafeEvents = 0;
int16_t rcData[8] = { 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502 }; // interval [1000;2000] int16_t rcData[RC_CHANS]; // interval [1000;2000]
int16_t rcCommand[4]; // interval [1000;2000] for THROTTLE and [-500;+500] for ROLL/PITCH/YAW int16_t rcCommand[4]; // interval [1000;2000] for THROTTLE and [-500;+500] for ROLL/PITCH/YAW
int16_t lookupPitchRollRC[6]; // lookup table for expo & RC rate PITCH+ROLL int16_t lookupPitchRollRC[PITCH_LOOKUP_LENGTH]; // lookup table for expo & RC rate PITCH+ROLL
int16_t lookupThrottleRC[11]; // lookup table for expo & mid THROTTLE int16_t lookupThrottleRC[THROTTLE_LOOKUP_LENGTH]; // 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)
@ -45,8 +45,6 @@ uint16_t GPS_altitude, GPS_speed; // altitude in 0.1m and speed in 0.1m/s
uint8_t GPS_update = 0; // it's a binary toogle to distinct a GPS position update uint8_t GPS_update = 0; // it's a binary toogle to distinct a GPS position update
int16_t GPS_angle[2] = { 0, 0 }; // it's the angles that must be applied for GPS correction int16_t GPS_angle[2] = { 0, 0 }; // it's the angles that must be applied for GPS correction
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_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
@ -179,9 +177,9 @@ void annexCode(void)
LED0_OFF; LED0_OFF;
if (f.ARMED) if (f.ARMED)
LED0_ON; LED0_ON;
// This will switch to/from 9600 or 115200 baud depending on state. Of course, it should only do it on changes. // This will switch to/from 9600 or 115200 baud depending on state. Of course, it should only do it on changes. With telemetry_softserial>0 telemetry is always enabled, also see updateTelemetryState()
if (feature(FEATURE_TELEMETRY)) if (feature(FEATURE_TELEMETRY))
initTelemetry(f.ARMED); updateTelemetryState();
} }
#ifdef LEDRING #ifdef LEDRING
@ -758,8 +756,8 @@ void loop(void)
} }
} else { // not in rc loop } else { // not in rc loop
static int taskOrder = 0; // never call all function in the same loop, to avoid high delay spikes static int taskOrder = 0; // never call all function in the same loop, to avoid high delay spikes
if (taskOrder > 3) if (taskOrder > 4)
taskOrder -= 4; taskOrder -= 5;
switch (taskOrder) { switch (taskOrder) {
case 0: case 0:
taskOrder++; taskOrder++;
@ -780,6 +778,15 @@ void loop(void)
break; break;
#endif #endif
case 3: case 3:
// if GPS feature is enabled, gpsThread() will be called at some intervals to check for stuck
// hardware, wrong baud rates, init GPS if needed, etc. Don't use SENSOR_GPS here as gpsThread() can and will
// change this based on available hardware
taskOrder++;
if (feature(FEATURE_GPS)) {
gpsThread();
break;
}
case 4:
taskOrder++; taskOrder++;
#ifdef SONAR #ifdef SONAR
if (sensors(SENSOR_SONAR)) { if (sensors(SENSOR_SONAR)) {
@ -802,9 +809,6 @@ void loop(void)
currentTime = micros(); currentTime = micros();
cycleTime = (int32_t)(currentTime - previousTime); cycleTime = (int32_t)(currentTime - previousTime);
previousTime = currentTime; previousTime = currentTime;
#ifdef MPU6050_DMP
mpu6050DmpLoop();
#endif
#ifdef MAG #ifdef MAG
if (sensors(SENSOR_MAG)) { if (sensors(SENSOR_MAG)) {
@ -814,6 +818,7 @@ void loop(void)
dif += 360; dif += 360;
if (dif >= +180) if (dif >= +180)
dif -= 360; dif -= 360;
dif *= -mcfg.yaw_control_direction;
if (f.SMALL_ANGLES_25) if (f.SMALL_ANGLES_25)
rcCommand[YAW] -= dif * cfg.P8[PIDMAG] / 30; // 18 deg rcCommand[YAW] -= dif * cfg.P8[PIDMAG] / 30; // 18 deg
} else } else

View File

@ -4,11 +4,13 @@
#define VBATFREQ 6 // to read battery voltage - nth number of loop iterations #define VBATFREQ 6 // to read battery voltage - nth number of loop iterations
#define BARO_TAB_SIZE_MAX 48 #define BARO_TAB_SIZE_MAX 48
#define VERSION 220 #define VERSION 230
#define LAT 0 #define LAT 0
#define LON 1 #define LON 1
#define RC_CHANS (18)
// Serial GPS only variables // Serial GPS only variables
// navigation mode // navigation mode
typedef enum NavigationMode typedef enum NavigationMode
@ -38,16 +40,18 @@ typedef enum MultiType
MULTITYPE_HELI_120_CCPM = 15, MULTITYPE_HELI_120_CCPM = 15,
MULTITYPE_HELI_90_DEG = 16, MULTITYPE_HELI_90_DEG = 16,
MULTITYPE_VTAIL4 = 17, MULTITYPE_VTAIL4 = 17,
MULTITYPE_CUSTOM = 18, // no current GUI displays this MULTITYPE_HEX6H = 18,
MULTITYPE_LAST = 19 MULTITYPE_PPM_TO_SERVO = 19, // PPM -> servo relay
MULTITYPE_DUALCOPTER = 20,
MULTITYPE_SINGLECOPTER = 21,
MULTITYPE_CUSTOM = 22, // no current GUI displays this
MULTITYPE_LAST = 23
} MultiType; } MultiType;
typedef enum GimbalFlags { typedef enum GimbalFlags {
GIMBAL_NORMAL = 1 << 0, GIMBAL_NORMAL = 1 << 0,
GIMBAL_TILTONLY = 1 << 1, GIMBAL_MIXTILT = 1 << 1,
GIMBAL_DISABLEAUX34 = 1 << 2, GIMBAL_FORWARDAUX = 1 << 2,
GIMBAL_FORWARDAUX = 1 << 3,
GIMBAL_MIXTILT = 1 << 4,
} GimbalFlags; } GimbalFlags;
/*********** RC alias *****************/ /*********** RC alias *****************/
@ -194,33 +198,9 @@ typedef struct config_t {
// mixer-related configuration // mixer-related configuration
int8_t yaw_direction; int8_t yaw_direction;
uint8_t tri_unarmed_servo; // send tail servo correction pulses even when unarmed uint8_t tri_unarmed_servo; // send tail servo correction pulses even when unarmed
uint16_t tri_yaw_middle; // tail servo center pos. - use this for initial trim
uint16_t tri_yaw_min; // tail servo min
uint16_t tri_yaw_max; // tail servo max
// flying wing related configuration
uint16_t wing_left_min; // min/mid/max servo travel
uint16_t wing_left_mid;
uint16_t wing_left_max;
uint16_t wing_right_min;
uint16_t wing_right_mid;
uint16_t wing_right_max;
int8_t pitch_direction_l; // left servo - pitch orientation
int8_t pitch_direction_r; // right servo - pitch orientation (opposite sign to pitch_direction_l if servos are mounted mirrored)
int8_t roll_direction_l; // left servo - roll orientation
int8_t roll_direction_r; // right servo - roll orientation (same sign as ROLL_DIRECTION_L, if servos are mounted in mirrored orientation)
// gimbal-related configuration // gimbal-related configuration
int8_t gimbal_pitch_gain; // gimbal pitch servo gain (tied to angle) can be negative to invert movement
int8_t gimbal_roll_gain; // gimbal roll servo gain (tied to angle) can be negative to invert movement
uint8_t gimbal_flags; // in servotilt mode, various things that affect stuff uint8_t gimbal_flags; // in servotilt mode, various things that affect stuff
uint16_t gimbal_pitch_min; // gimbal pitch servo min travel
uint16_t gimbal_pitch_max; // gimbal pitch servo max travel
uint16_t gimbal_pitch_mid; // gimbal pitch servo neutral value
uint16_t gimbal_roll_min; // gimbal roll servo min travel
uint16_t gimbal_roll_max; // gimbal roll servo max travel
uint16_t gimbal_roll_mid; // gimbal roll servo neutral value
// gps-related stuff // gps-related stuff
uint16_t gps_wp_radius; // if we are within this distance to a waypoint then we consider it reached (distance is in cm) uint16_t gps_wp_radius; // if we are within this distance to a waypoint then we consider it reached (distance is in cm)
@ -258,6 +238,9 @@ typedef struct master_t {
sensor_align_e gyro_align; // gyro alignment sensor_align_e gyro_align; // gyro alignment
sensor_align_e acc_align; // acc alignment sensor_align_e acc_align; // acc alignment
sensor_align_e mag_align; // mag alignment sensor_align_e mag_align; // mag alignment
int16_t board_align_roll; // board alignment correction in roll (deg)
int16_t board_align_pitch; // board alignment correction in pitch (deg)
int16_t board_align_yaw; // board alignment correction in yaw (deg)
int8_t yaw_control_direction; // change control direction of yaw (inverted, normal) int8_t yaw_control_direction; // change control direction of yaw (inverted, normal)
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.
@ -265,7 +248,6 @@ typedef struct master_t {
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 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.
int16_t accZero[3]; int16_t accZero[3];
int16_t magZero[3]; int16_t magZero[3];
@ -282,18 +264,21 @@ typedef struct master_t {
uint16_t mincheck; // minimum rc end uint16_t mincheck; // minimum rc end
uint16_t maxcheck; // maximum rc end uint16_t maxcheck; // maximum rc end
uint8_t retarded_arm; // allow disarsm/arm on throttle down + roll left/right uint8_t retarded_arm; // allow disarsm/arm on throttle down + roll left/right
uint8_t flaps_speed; // airplane mode flaps, 0 = no flaps, > 0 = flap speed, larger = faster
uint8_t rssi_aux_channel; // Read rssi from channel. 1+ = AUX1+, 0 to disable. uint8_t rssi_aux_channel; // Read rssi from channel. 1+ = AUX1+, 0 to disable.
// gps-related stuff // gps-related stuff
uint8_t gps_type; // Type of GPS hardware. 0: NMEA 1: UBX 2+ ?? uint8_t gps_type; // Type of GPS hardware. 0: NMEA 1: UBX 2: MTK NMEA 3: MTK Binary
uint32_t gps_baudrate; // GPS baudrate int8_t gps_baudrate; // GPS baudrate, -1: autodetect (NMEA only), 0: 115200, 1: 57600, 2: 38400, 3: 19200, 4: 9600
uint32_t serial_baudrate; uint32_t serial_baudrate;
uint32_t softserial_baudrate; uint32_t softserial_baudrate;
uint8_t softserial_inverted; // use inverted softserial input and output signals uint8_t softserial_inverted; // use inverted softserial input and output signals
uint8_t telemetry_softserial; // Serial to use for Telemetry. 0:USART1, 1:SoftSerial1 (Enable FEATURE_SOFTSERIAL first)
config_t profile[3]; // 3 separate profiles config_t profile[3]; // 3 separate profiles
uint8_t current_profile; // currently loaded profile uint8_t current_profile; // currently loaded profile
@ -307,8 +292,9 @@ typedef struct core_t {
serialPort_t *gpsport; serialPort_t *gpsport;
serialPort_t *telemport; serialPort_t *telemport;
serialPort_t *rcvrport; serialPort_t *rcvrport;
bool useServo; 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 numRCChannels; // number of rc channels as reported by current input driver
bool useServo; // feature SERVO_TILT or wing/airplane mixers will enable this
} core_t; } core_t;
typedef struct flags_t { typedef struct flags_t {
@ -365,15 +351,18 @@ extern int16_t throttleAngleCorrection;
extern int16_t headFreeModeHold; extern int16_t headFreeModeHold;
extern int16_t heading, magHold; extern int16_t heading, magHold;
extern int16_t motor[MAX_MOTORS]; extern int16_t motor[MAX_MOTORS];
extern int16_t servo[8]; extern int16_t servo[MAX_SERVOS];
extern int16_t rcData[8]; extern int16_t rcData[RC_CHANS];
extern uint16_t rssi; // range: [0;1023] extern uint16_t rssi; // range: [0;1023]
extern uint8_t vbat; extern uint8_t vbat;
extern int16_t telemTemperature1; // gyro sensor temperature extern int16_t telemTemperature1; // gyro sensor temperature
extern int16_t lookupPitchRollRC[6]; // lookup table for expo & RC rate PITCH+ROLL
extern int16_t lookupThrottleRC[11]; // lookup table for expo & mid THROTTLE
extern uint8_t toggleBeep; extern uint8_t toggleBeep;
#define PITCH_LOOKUP_LENGTH 7
#define THROTTLE_LOOKUP_LENGTH 12
extern int16_t lookupPitchRollRC[PITCH_LOOKUP_LENGTH]; // lookup table for expo & RC rate PITCH+ROLL
extern int16_t lookupThrottleRC[THROTTLE_LOOKUP_LENGTH]; // lookup table for expo & mid THROTTLE
// GPS stuff // GPS stuff
extern int32_t GPS_coord[2]; extern int32_t GPS_coord[2];
extern int32_t GPS_home[2]; extern int32_t GPS_home[2];
@ -385,8 +374,6 @@ extern uint16_t GPS_altitude,GPS_speed; // altitude in 0.1m
extern uint8_t GPS_update; // it's a binary toogle to distinct a GPS position update extern uint8_t GPS_update; // it's a binary toogle to distinct a GPS position update
extern int16_t GPS_angle[2]; // it's the angles that must be applied for GPS correction extern int16_t GPS_angle[2]; // it's the angles that must be applied for GPS correction
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_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
@ -429,6 +416,7 @@ void Sonar_update(void);
// Output // Output
void mixerInit(void); void mixerInit(void);
void mixerResetMotors(void);
void mixerLoadMix(int index); void mixerLoadMix(int index);
void writeServos(void); void writeServos(void);
void writeMotors(void); void writeMotors(void);
@ -470,13 +458,16 @@ void systemBeep(bool onoff);
void cliProcess(void); void cliProcess(void);
// gps // gps
void gpsInit(uint32_t baudrate); void gpsInit(uint8_t baudrate);
void gpsThread(void);
void gpsSetPIDs(void);
int8_t gpsSetPassthrough(void);
void GPS_reset_home_position(void); void GPS_reset_home_position(void);
void GPS_reset_nav(void); void GPS_reset_nav(void);
void GPS_set_pids(void);
void GPS_set_next_wp(int32_t* lat, int32_t* lon); void GPS_set_next_wp(int32_t* lat, int32_t* lon);
int32_t wrap_18000(int32_t error); int32_t wrap_18000(int32_t error);
// telemetry // telemetry
void initTelemetry(bool State); void initTelemetry(void);
void updateTelemetryState(void);
void sendTelemetry(void); void sendTelemetry(void);

View File

@ -26,6 +26,7 @@ void sbusInit(rcReadRawDataPtr *callback)
core.rcvrport = uartOpen(USART2, sbusDataReceive, 100000, MODE_RX); core.rcvrport = uartOpen(USART2, sbusDataReceive, 100000, MODE_RX);
if (callback) if (callback)
*callback = sbusReadRawRC; *callback = sbusReadRawRC;
core.numRCChannels = SBUS_MAX_CHANNEL;
} }
struct sbus_dat struct sbus_dat

View File

@ -36,7 +36,7 @@ void sensorsAutodetect(void)
bool haveMpu6k = false; bool haveMpu6k = false;
// Autodetect gyro hardware. We have MPU3050 or MPU6050. // Autodetect gyro hardware. We have MPU3050 or MPU6050.
if (mpu6050Detect(&acc, &gyro, mcfg.gyro_lpf, &mcfg.mpu6050_scale)) { if (mpu6050Detect(&acc, &gyro, mcfg.gyro_lpf, &core.mpu6050_scale)) {
// this filled up acc.* struct with init values // this filled up acc.* struct with init values
haveMpu6k = true; haveMpu6k = true;
} else if (l3g4200dDetect(&gyro, mcfg.gyro_lpf)) { } else if (l3g4200dDetect(&gyro, mcfg.gyro_lpf)) {
@ -64,7 +64,7 @@ retry:
; // fallthrough ; // fallthrough
case ACC_MPU6050: // MPU6050 case ACC_MPU6050: // MPU6050
if (haveMpu6k) { if (haveMpu6k) {
mpu6050Detect(&acc, &gyro, mcfg.gyro_lpf, &mcfg.mpu6050_scale); // yes, i'm rerunning it again. re-fill acc struct mpu6050Detect(&acc, &gyro, mcfg.gyro_lpf, &core.mpu6050_scale); // yes, i'm rerunning it again. re-fill acc struct
accHardware = ACC_MPU6050; accHardware = ACC_MPU6050;
if (mcfg.acc_hardware == ACC_MPU6050) if (mcfg.acc_hardware == ACC_MPU6050)
break; break;

View File

@ -3,7 +3,9 @@
// Multiwii Serial Protocol 0 // Multiwii Serial Protocol 0
#define MSP_VERSION 0 #define MSP_VERSION 0
#define PLATFORM_32BIT ((uint32_t)1 << 31) #define CAP_PLATFORM_32BIT ((uint32_t)1 << 31)
#define CAP_DYNBALANCE ((uint32_t)1 << 2)
#define CAP_FLAPS ((uint32_t)1 << 3)
#define MSP_IDENT 100 //out message multitype + multiwii version + protocol version + capability variable #define MSP_IDENT 100 //out message multitype + multiwii version + protocol version + capability variable
#define MSP_STATUS 101 //out message cycletime & errors_count & sensor present & box activation & current setting number #define MSP_STATUS 101 //out message cycletime & errors_count & sensor present & box activation & current setting number
@ -89,51 +91,8 @@ struct box_t {
static uint8_t availableBoxes[CHECKBOXITEMS]; static uint8_t availableBoxes[CHECKBOXITEMS];
// this is the number of filled indexes in above array // this is the number of filled indexes in above array
static uint8_t numberBoxItems = 0; static uint8_t numberBoxItems = 0;
// from mixer.c
static const char boxnames[] = extern int16_t motor_disarmed[MAX_MOTORS];
"ARM;"
"ANGLE;"
"HORIZON;"
"BARO;"
"VARIO;"
"MAG;"
"HEADFREE;"
"HEADADJ;"
"CAMSTAB;"
"CAMTRIG;"
"GPS HOME;"
"GPS HOLD;"
"PASSTHRU;"
"BEEPER;"
"LEDMAX;"
"LEDLOW;"
"LLIGHTS;"
"CALIB;"
"GOVERNOR;"
"OSD SW;";
const uint8_t boxids[] = { // permanent IDs associated to boxes. This way, you can rely on an ID number to identify a BOX function.
0, // "ARM;"
1, // "ANGLE;"
2, // "HORIZON;"
3, // "BARO;"
4, // "VARIO;"
5, // "MAG;"
6, // "HEADFREE;"
7, // "HEADADJ;"
8, // "CAMSTAB;"
9, // "CAMTRIG;"
10, // "GPS HOME;"
11, // "GPS HOLD;"
12, // "PASSTHRU;"
13, // "BEEPER;"
14, // "LEDMAX;"
15, // "LEDLOW;"
16, // "LLIGHTS;"
17, // "CALIB;"
18, // "GOVERNOR;"
19, // "OSD_SWITCH;"
};
static const char pidnames[] = static const char pidnames[] =
"ROLL;" "ROLL;"
@ -149,7 +108,6 @@ static const char pidnames[] =
static uint8_t checksum, indRX, inBuf[INBUF_SIZE]; static uint8_t checksum, indRX, inBuf[INBUF_SIZE];
static uint8_t cmdMSP; static uint8_t cmdMSP;
static bool guiConnected = false;
// signal that we're in cli mode // signal that we're in cli mode
uint8_t cliMode = 0; uint8_t cliMode = 0;
@ -247,31 +205,35 @@ void serializeNames(const char *s)
void serializeBoxNamesReply(void) void serializeBoxNamesReply(void)
{ {
char buf[256]; // no fucking idea int i, idx, j, flag = 1, count = 0, len;
char *c;
int i, j;
memset(buf, 0, sizeof(buf)); reset:
for (i = 0; i < CHECKBOXITEMS; i++) { // in first run of the loop, we grab total size of junk to be sent
for (j = 0; j < numberBoxItems; j++) { // then come back and actually send it
if (boxes[i].boxIndex == availableBoxes[j]) for (i = 0; i < numberBoxItems; i++) {
strcat(buf, boxes[i].boxName); idx = availableBoxes[i];
len = strlen(boxes[idx].boxName);
if (flag) {
count += len;
} else {
for (j = 0; j < len; j++)
serialize8(boxes[idx].boxName[j]);
} }
} }
headSerialReply(strlen(buf)); if (flag) {
for (c = buf; *c; c++) headSerialReply(count);
serialize8(*c); flag = 0;
goto reset;
}
} }
void serialInit(uint32_t baudrate) void serialInit(uint32_t baudrate)
{ {
int idx; int idx;
bool hfadded = false;
core.mainport = uartOpen(USART1, NULL, baudrate, MODE_RXTX); core.mainport = uartOpen(USART1, NULL, baudrate, MODE_RXTX);
// TODO fix/hax
core.telemport = core.mainport;
// calculate used boxes based on features and fill availableBoxes[] array // calculate used boxes based on features and fill availableBoxes[] array
memset(availableBoxes, 0xFF, sizeof(availableBoxes)); memset(availableBoxes, 0xFF, sizeof(availableBoxes));
@ -280,27 +242,20 @@ void serialInit(uint32_t baudrate)
if (sensors(SENSOR_ACC)) { if (sensors(SENSOR_ACC)) {
availableBoxes[idx++] = BOXANGLE; availableBoxes[idx++] = BOXANGLE;
availableBoxes[idx++] = BOXHORIZON; availableBoxes[idx++] = BOXHORIZON;
availableBoxes[idx++] = BOXMAG;
availableBoxes[idx++] = BOXHEADFREE;
availableBoxes[idx++] = BOXHEADADJ;
hfadded = true;
} }
if (sensors(SENSOR_BARO)) { if (sensors(SENSOR_BARO)) {
availableBoxes[idx++] = BOXBARO; availableBoxes[idx++] = BOXBARO;
if (feature(FEATURE_VARIO)) if (feature(FEATURE_VARIO))
availableBoxes[idx++] = BOXVARIO; availableBoxes[idx++] = BOXVARIO;
} }
if (sensors(SENSOR_MAG)) { if (sensors(SENSOR_ACC) || sensors(SENSOR_MAG)) {
// this really shouldn't even needed to be tested as it wouldn't be possible without acc anyway
if (!hfadded) {
availableBoxes[idx++] = BOXMAG; availableBoxes[idx++] = BOXMAG;
availableBoxes[idx++] = BOXHEADFREE; availableBoxes[idx++] = BOXHEADFREE;
availableBoxes[idx++] = BOXHEADADJ; availableBoxes[idx++] = BOXHEADADJ;
} }
}
if (feature(FEATURE_SERVO_TILT)) if (feature(FEATURE_SERVO_TILT))
availableBoxes[idx++] = BOXCAMSTAB; availableBoxes[idx++] = BOXCAMSTAB;
if (feature(FEATURE_GPS) && sensors(SENSOR_GPS)) { if (feature(FEATURE_GPS)) {
availableBoxes[idx++] = BOXGPSHOME; availableBoxes[idx++] = BOXGPSHOME;
availableBoxes[idx++] = BOXGPSHOLD; availableBoxes[idx++] = BOXGPSHOLD;
} }
@ -309,12 +264,13 @@ void serialInit(uint32_t baudrate)
availableBoxes[idx++] = BOXBEEPERON; availableBoxes[idx++] = BOXBEEPERON;
if (feature(FEATURE_INFLIGHT_ACC_CAL)) if (feature(FEATURE_INFLIGHT_ACC_CAL))
availableBoxes[idx++] = BOXCALIB; availableBoxes[idx++] = BOXCALIB;
availableBoxes[idx++] = BOXOSD;
numberBoxItems = idx; numberBoxItems = idx;
} }
static void evaluateCommand(void) static void evaluateCommand(void)
{ {
uint32_t i, tmp; uint32_t i, tmp, junk;
uint8_t wp_no; uint8_t wp_no;
int32_t lat = 0, lon = 0, alt = 0; int32_t lat = 0, lon = 0, alt = 0;
@ -363,8 +319,23 @@ static void evaluateCommand(void)
headSerialReply(0); headSerialReply(0);
break; break;
case MSP_SET_MISC: case MSP_SET_MISC:
read16(); // powerfailmeter
mcfg.minthrottle = read16();
read32(); // mcfg.maxthrottle, mcfg.mincommand
cfg.failsafe_throttle = read16();
read16();
read32();
cfg.mag_declination = read16() * 10;
mcfg.vbatscale = read8(); // actual vbatscale as intended
mcfg.vbatmincellvoltage = read8(); // vbatlevel_warn1 in MWC2.3 GUI
mcfg.vbatmaxcellvoltage = read8(); // vbatlevel_warn2 in MWC2.3 GUI
read8(); // vbatlevel_crit (unused)
headSerialReply(0); headSerialReply(0);
break; break;
case MSP_SET_MOTOR:
for (i = 0; i < 8; i++)
motor_disarmed[i] = read16();
break;
case MSP_SELECT_SETTING: case MSP_SELECT_SETTING:
if (!f.ARMED) { if (!f.ARMED) {
mcfg.current_profile = read8(); mcfg.current_profile = read8();
@ -384,17 +355,18 @@ static void evaluateCommand(void)
serialize8(VERSION); // multiwii version serialize8(VERSION); // multiwii version
serialize8(mcfg.mixerConfiguration); // type of multicopter serialize8(mcfg.mixerConfiguration); // type of multicopter
serialize8(MSP_VERSION); // MultiWii Serial Protocol Version serialize8(MSP_VERSION); // MultiWii Serial Protocol Version
serialize32(PLATFORM_32BIT); // "capability" serialize32(CAP_PLATFORM_32BIT | CAP_DYNBALANCE | (mcfg.flaps_speed ? CAP_FLAPS : 0)); // "capability"
break; break;
case MSP_STATUS: case MSP_STATUS:
headSerialReply(11); headSerialReply(11);
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 // 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. // 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 | // Serialize the boxes in the order we delivered them, until multiwii retards fix their shit
junk = 0;
tmp = 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 |
f.GPS_HOME_MODE << BOXGPSHOME | f.GPS_HOLD_MODE << BOXGPSHOLD | f.GPS_HOME_MODE << BOXGPSHOME | f.GPS_HOLD_MODE << BOXGPSHOLD |
@ -406,50 +378,13 @@ static void evaluateCommand(void)
rcOptions[BOXCALIB] << BOXCALIB | rcOptions[BOXCALIB] << BOXCALIB |
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++) { for (i = 0; i < numberBoxItems; i++) {
uint8_t val, box = availableBoxes[i]; int flag = (tmp & (1 << availableBoxes[i]));
switch (box) { if (flag)
// Handle the special cases junk |= 1 << i;
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(junk);
}
serialize32(tmp);
#endif
serialize8(mcfg.current_profile); serialize8(mcfg.current_profile);
break; break;
case MSP_RAW_IMU: case MSP_RAW_IMU:
@ -468,17 +403,28 @@ static void evaluateCommand(void)
serialize16(magADC[i]); serialize16(magADC[i]);
break; break;
case MSP_SERVO: case MSP_SERVO:
headSerialReply(16); s_struct((uint8_t *)&servo, 16);
for (i = 0; i < 8; i++)
serialize16(servo[i]);
break; break;
case MSP_SERVO_CONF: case MSP_SERVO_CONF:
s_struct((uint8_t *)&cfg.servoConf, 56); // struct servoConf is 7 bytes length: min:2 / max:2 / middle:2 / rate:1 ---- 8 servo => 8x7 = 56 headSerialReply(56);
for (i = 0; i < MAX_SERVOS; i++) {
serialize16(cfg.servoConf[i].min);
serialize16(cfg.servoConf[i].max);
serialize16(cfg.servoConf[i].middle);
serialize8(cfg.servoConf[i].rate);
}
break;
case MSP_SET_SERVO_CONF:
headSerialReply(0);
for (i = 0; i < MAX_SERVOS; i++) {
cfg.servoConf[i].min = read16();
cfg.servoConf[i].max = read16();
cfg.servoConf[i].middle = read16();
cfg.servoConf[i].rate = read8();
}
break; break;
case MSP_MOTOR: case MSP_MOTOR:
headSerialReply(16); s_struct((uint8_t *)motor, 16);
for (i = 0; i < 8; i++)
serialize16(motor[i]);
break; break;
case MSP_RC: case MSP_RC:
headSerialReply(16); headSerialReply(16);
@ -556,8 +502,19 @@ static void evaluateCommand(void)
serialize8(availableBoxes[i]); serialize8(availableBoxes[i]);
break; break;
case MSP_MISC: case MSP_MISC:
headSerialReply(2); headSerialReply(2 * 6 + 4 + 2 + 4);
serialize16(0); // intPowerTrigger1 serialize16(0); // intPowerTrigger1 (aka useless trash)
serialize16(mcfg.minthrottle);
serialize16(mcfg.maxthrottle);
serialize16(mcfg.mincommand);
serialize16(cfg.failsafe_throttle);
serialize16(0); // plog useless shit
serialize32(0); // plog useless shit
serialize16(cfg.mag_declination / 10); // TODO check this shit
serialize8(mcfg.vbatscale);
serialize8(mcfg.vbatmincellvoltage);
serialize8(mcfg.vbatmaxcellvoltage);
serialize8(0);
break; break;
case MSP_MOTOR_PINS: case MSP_MOTOR_PINS:
headSerialReply(8); headSerialReply(8);
@ -718,7 +675,6 @@ void serialCom(void)
indRX = 0; indRX = 0;
checksum ^= c; checksum ^= c;
c_state = HEADER_SIZE; // the command is to follow c_state = HEADER_SIZE; // the command is to follow
guiConnected = true;
} else if (c_state == HEADER_SIZE) { } else if (c_state == HEADER_SIZE) {
cmdMSP = c; cmdMSP = c;
checksum ^= c; checksum ^= c;
@ -733,8 +689,7 @@ void serialCom(void)
c_state = IDLE; c_state = IDLE;
} }
} }
if (!cliMode && !serialTotalBytesWaiting(core.telemport) && feature(FEATURE_TELEMETRY) && f.ARMED) { // The first 2 conditions should never evaluate to true but I'm putting it here anyway - silpstream if (!cliMode && feature(FEATURE_TELEMETRY)) { // The first condition should never evaluate to true but I'm putting it here anyway - silpstream
sendTelemetry(); sendTelemetry();
return;
} }
} }

View File

@ -37,6 +37,7 @@ void spektrumInit(rcReadRawDataPtr *callback)
core.rcvrport = uartOpen(USART2, spektrumDataReceive, 115200, MODE_RX); core.rcvrport = uartOpen(USART2, spektrumDataReceive, 115200, MODE_RX);
if (callback) if (callback)
*callback = spektrumReadRawRC; *callback = spektrumReadRawRC;
core.numRCChannels = SPEK_MAX_CHANNEL;
} }
// Receive ISR callback // Receive ISR callback

View File

@ -45,6 +45,8 @@
#define ID_GYRO_Y 0x41 #define ID_GYRO_Y 0x41
#define ID_GYRO_Z 0x42 #define ID_GYRO_Z 0x42
#define ID_VERT_SPEED 0x30 //opentx vario
// from sensors.c // from sensors.c
extern uint8_t batteryCellCount; extern uint8_t batteryCellCount;
@ -96,7 +98,7 @@ static void sendBaro(void)
sendDataHead(ID_ALTITUDE_BP); sendDataHead(ID_ALTITUDE_BP);
serialize16(BaroAlt / 100); serialize16(BaroAlt / 100);
sendDataHead(ID_ALTITUDE_AP); sendDataHead(ID_ALTITUDE_AP);
serialize16(BaroAlt % 100); serialize16(abs(BaroAlt % 100));
} }
static void sendTemperature1(void) static void sendTemperature1(void)
@ -135,6 +137,16 @@ static void sendGPS(void)
serialize16(GPS_coord[LON] < 0 ? 'W' : 'E'); serialize16(GPS_coord[LON] < 0 ? 'W' : 'E');
} }
/*
* Send vertical speed for opentx. ID_VERT_SPEED
* Unit is cm/s
*/
static void sendVario(void)
{
sendDataHead(ID_VERT_SPEED);
serialize16(vario);
}
/* /*
* Send voltage via ID_VOLT * Send voltage via ID_VOLT
* *
@ -202,13 +214,29 @@ static void sendHeading(void)
static bool telemetryEnabled = false; static bool telemetryEnabled = false;
void initTelemetry(bool State) void initTelemetry(void)
{ {
// Sanity check for softserial vs. telemetry port
if (!feature(FEATURE_SOFTSERIAL))
mcfg.telemetry_softserial = TELEMETRY_UART;
if (mcfg.telemetry_softserial == TELEMETRY_SOFTSERIAL)
core.telemport = &(softSerialPorts[0].port);
else
core.telemport = core.mainport;
}
void updateTelemetryState(void)
{
bool State = mcfg.telemetry_softserial != TELEMETRY_UART ? true : f.ARMED;
if (State != telemetryEnabled) { if (State != telemetryEnabled) {
if (mcfg.telemetry_softserial == TELEMETRY_UART) {
if (State) if (State)
serialInit(9600); serialInit(9600);
else else
serialInit(mcfg.serial_baudrate); serialInit(mcfg.serial_baudrate);
}
telemetryEnabled = State; telemetryEnabled = State;
} }
} }
@ -218,12 +246,19 @@ static uint8_t cycleNum = 0;
void sendTelemetry(void) void sendTelemetry(void)
{ {
if (mcfg.telemetry_softserial == TELEMETRY_UART && !f.ARMED)
return;
if (serialTotalBytesWaiting(core.telemport) != 0)
return;
if (millis() - lastCycleTime >= CYCLETIME) { if (millis() - lastCycleTime >= CYCLETIME) {
lastCycleTime = millis(); lastCycleTime = millis();
cycleNum++; cycleNum++;
// Sent every 125ms // Sent every 125ms
sendAccel(); sendAccel();
sendVario();
sendTelemetryTail(); sendTelemetryTail();
if ((cycleNum % 4) == 0) { // Sent every 500ms if ((cycleNum % 4) == 0) { // Sent every 500ms

View File

@ -1,6 +1,9 @@
#include "board.h" #include "board.h"
#include "mw.h" #include "mw.h"
static bool standardBoardAlignment = true; // board orientation correction
static float boardRotation[3][3]; // matrix
int constrain(int amt, int low, int high) int constrain(int amt, int low, int high)
{ {
if (amt < low) if (amt < low)
@ -10,3 +13,109 @@ int constrain(int amt, int low, int high)
else else
return amt; return amt;
} }
void initBoardAlignment(void)
{
float roll, pitch, yaw;
float cosx, sinx, cosy, siny, cosz, sinz;
float coszcosx, coszcosy, sinzcosx, coszsinx, sinzsinx;
// standard alignment, nothing to calculate
if (!mcfg.board_align_roll && !mcfg.board_align_pitch && !mcfg.board_align_yaw)
return;
standardBoardAlignment = false;
// deg2rad
roll = mcfg.board_align_roll * M_PI / 180.0f;
pitch = mcfg.board_align_pitch * M_PI / 180.0f;
yaw = mcfg.board_align_yaw * M_PI / 180.0f;
cosx = cosf(roll);
sinx = sinf(roll);
cosy = cosf(pitch);
siny = sinf(pitch);
cosz = cosf(yaw);
sinz = sinf(yaw);
coszcosx = cosz * cosx;
coszcosy = cosz * cosy;
sinzcosx = sinz * cosx;
coszsinx = sinx * cosz;
sinzsinx = sinx * sinz;
// define rotation matrix
boardRotation[0][0] = coszcosy;
boardRotation[0][1] = -cosy * sinz;
boardRotation[0][2] = siny;
boardRotation[1][0] = sinzcosx + (coszsinx * siny);
boardRotation[1][1] = coszcosx - (sinzsinx * siny);
boardRotation[1][2] = -sinx * cosy;
boardRotation[2][0] = (sinzsinx) - (coszcosx * siny);
boardRotation[2][1] = (coszsinx) + (sinzcosx * siny);
boardRotation[2][2] = cosy * cosx;
}
void alignBoard(int16_t *vec)
{
int16_t x = vec[X];
int16_t y = vec[Y];
int16_t z = vec[Z];
vec[X] = lrintf(boardRotation[0][0] * x + boardRotation[1][0] * y + boardRotation[2][0] * z);
vec[Y] = lrintf(boardRotation[0][1] * x + boardRotation[1][1] * y + boardRotation[2][1] * z);
vec[Z] = lrintf(boardRotation[0][2] * x + boardRotation[1][2] * y + boardRotation[2][2] * z);
}
void alignSensors(int16_t *src, int16_t *dest, uint8_t rotation)
{
switch (rotation) {
case CW0_DEG:
dest[X] = src[X];
dest[Y] = src[Y];
dest[Z] = src[Z];
break;
case CW90_DEG:
dest[X] = src[Y];
dest[Y] = -src[X];
dest[Z] = src[Z];
break;
case CW180_DEG:
dest[X] = -src[X];
dest[Y] = -src[Y];
dest[Z] = src[Z];
break;
case CW270_DEG:
dest[X] = -src[Y];
dest[Y] = src[X];
dest[Z] = src[Z];
break;
case CW0_DEG_FLIP:
dest[X] = -src[X];
dest[Y] = src[Y];
dest[Z] = -src[Z];
break;
case CW90_DEG_FLIP:
dest[X] = src[Y];
dest[Y] = src[X];
dest[Z] = -src[Z];
break;
case CW180_DEG_FLIP:
dest[X] = src[X];
dest[Y] = -src[Y];
dest[Z] = -src[Z];
break;
case CW270_DEG_FLIP:
dest[X] = -src[Y];
dest[Y] = -src[X];
dest[Z] = -src[Z];
break;
default:
break;
}
if (!standardBoardAlignment)
alignBoard(dest);
}

View File

@ -1,3 +1,6 @@
#pragma once #pragma once
int constrain(int amt, int low, int high); int constrain(int amt, int low, int high);
// sensor orientation
void alignSensors(int16_t *src, int16_t *dest, uint8_t rotation);
void initBoardAlignment(void);

View File

@ -322,7 +322,7 @@ void stmLoader(serialStruct_t *s, FILE *fp, unsigned char overrideParity, unsign
printf("Flashing device...\n"); printf("Flashing device...\n");
jumpAddress = stmHexLoader(s, fp); jumpAddress = stmHexLoader(s, fp);
if (jumpAddress) { if (jumpAddress) {
printf("\nFlash complete, cycle power\n"); printf("\nFlash complete, executing.\n");
go: go:
// send GO command // send GO command