1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-18 03:52:11 +01:00

Added matrix based actuator mixing. Note the makefile is set to use the original actuator code.

git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@1698 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
les 2010-09-20 19:27:08 +00:00 committed by les
parent 24840b461d
commit 875437f483
9 changed files with 683 additions and 197 deletions

View File

@ -38,7 +38,7 @@ USE_BOOTLOADER ?= NO
# Set to YES when using Code Sourcery toolchain
CODE_SOURCERY ?= NO
CODE_SOURCERY ?= YES
# Toolchain prefix (i.e arm-elf- -> arm-elf-gcc.exe)
TCHAIN_PREFIX ?= arm-none-eabi-
@ -57,7 +57,13 @@ FLASH_TOOL = OPENOCD
USE_THUMB_MODE = YES
# List of modules to include
MODULES = Telemetry GPS ManualControl Actuator Altitude AHRSComms Stabilization/simple/Stabilization Watchdog
MODULES = Telemetry GPS ManualControl Altitude AHRSComms Stabilization/simple/Stabilization Watchdog
#matrix based actuator mixer
#MODULES += Actuator/matrix/Actuator
#original actuator with separate mixers for fixed wing, heli and VTOL
MODULES += Actuator
#MODULES = Telemetry Example
#MODULES = Telemetry MK/MKSerial
#MODULES = Telemetry
@ -180,6 +186,9 @@ SRC += $(OPUAVOBJ)/homelocation.c
SRC += $(OPUAVOBJ)/attitudesettings.c
SRC += $(OPUAVOBJ)/vtolsettings.c
SRC += $(OPUAVOBJ)/vtolstatus.c
SRC += $(OPUAVOBJ)/mixersettings.c
SRC += $(OPUAVOBJ)/mixerstatus.c
#SRC += $(OPUAVOBJ)/lesstabilizationsettings.c
endif
## PIOS Hardware (STM32F10x)
@ -415,7 +424,9 @@ CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) -I.
CFLAGS += -mapcs-frame
CFLAGS += -fomit-frame-pointer
ifeq ($(CODE_SOURCERY), YES)
CFLAGS += -fpromote-loop-indices
endif
CFLAGS += -Wall
CFLAGS += -Werror
@ -465,7 +476,7 @@ UNAME := $(shell uname)
ifeq ($(UNAME), Darwin)
OOCD_CL+=-f ../Project/OpenOCD/floss-jtag.openpilot.osx.cfg -f ../Project/OpenOCD/stm32.cfg
else
OOCD_CL+=-f ../Project/OpenOCD/floss-jtag.openpilot.cfg -f ../Project/OpenOCD/stm32.cfg
OOCD_CL+=-f ../Project/OpenOCD/floss-jtag-revb.cfg -f ../Project/OpenOCD/stm32.cfg
endif
# initialize
OOCD_CL+=-c init

View File

@ -0,0 +1,373 @@
/**
******************************************************************************
* @addtogroup OpenPilotModules OpenPilot Modules
* @{
* @addtogroup ActuatorModule Actuator Module
* @brief Compute servo/motor settings based on @ref ActuatorDesired "desired actuator positions" and aircraft type.
* This is where all the mixing of channels is computed.
* @{
*
* @file actuator.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Actuator module. Drives the actuators (servos, motors etc).
*
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "openpilot.h"
#include "actuator.h"
#include "actuatorsettings.h"
//#include "vtolsettings.h"
#include "systemsettings.h"
#include "actuatordesired.h"
#include "actuatorcommand.h"
#include "manualcontrolcommand.h"
#include "mixersettings.h"
#include "mixerstatus.h"
// Private constants
#define MAX_QUEUE_SIZE 2
#define STACK_SIZE configMINIMAL_STACK_SIZE
#define TASK_PRIORITY (tskIDLE_PRIORITY+4)
#define FAILSAFE_TIMEOUT_MS 100
// Private types
// Private variables
static xQueueHandle queue;
static xTaskHandle taskHandle;
// Private functions
static void actuatorTask(void* parameters);
static int32_t RunMixers(ActuatorCommandData * command, ActuatorSettingsData* settings);
static int16_t scaleChannel(float value, int16_t max, int16_t min, int16_t neutral);
static void setFailsafe();
static float MixerCurve(const float throttle, const float* curve);
float ProcessMixer(const int index, const float curve1, const float curve2,
MixerSettingsData* mixerSettings, ActuatorDesiredData* desired,
const float period);
/**
* @brief Module initialization
* @return 0
*/
int32_t ActuatorInitialize()
{
// Create object queue
queue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(UAVObjEvent));
// Listen for ExampleObject1 updates
ActuatorDesiredConnectQueue(queue);
// Start main task
xTaskCreate(actuatorTask, (signed char*)"Actuator", STACK_SIZE, NULL, TASK_PRIORITY, &taskHandle);
return 0;
}
/**
* @brief Main module task
*/
static void actuatorTask(void* parameters)
{
// UAVObjEvent ev;
portTickType lastSysTime;
ActuatorCommandData command;
ActuatorSettingsData settings;
// Set servo update frequency (done only on start-up)
ActuatorSettingsGet(&settings);
PIOS_Servo_SetHz(settings.ChannelUpdateFreq[0], settings.ChannelUpdateFreq[1]);
// Go to the neutral (failsafe) values until an ActuatorDesired update is received
setFailsafe();
// Main task loop
lastSysTime = xTaskGetTickCount();
while (1)
{
ActuatorCommandGet(&command);
ActuatorSettingsGet(&settings);
if ( RunMixers(&command, &settings) == -1 )
{
AlarmsSet(SYSTEMALARMS_ALARM_ACTUATOR, SYSTEMALARMS_ALARM_CRITICAL);
}
else
{
AlarmsClear(SYSTEMALARMS_ALARM_ACTUATOR);
}
// Update output object
ActuatorCommandSet(&command);
// Update in case read only (eg. during servo configuration)
ActuatorCommandGet(&command);
// Update servo outputs
for (int n = 0; n < ACTUATORCOMMAND_CHANNEL_NUMELEM; ++n)
{
PIOS_Servo_Set( n, command.Channel[n] );
}
// Wait until next update
vTaskDelayUntil(&lastSysTime, settings.UpdatePeriod / portTICK_RATE_MS );
}
}
/**
* Universal matrix based mixer for VTOL, helis and fixed wing.
* Converts desired roll,pitch,yaw and throttle to servo/ESC outputs.
*
* Because of how the Throttle ranges from 0 to 1, the motors should too!
*
* Note this code depends on the UAVObjects for the mixers being all being the same
* and in sequence. If you change the object definition, make sure you check the code!
*
* @return -1 if error, 0 if success
*/
//this structure is equivalent to the UAVObjects for one mixer.
typedef struct {
uint8_t type;
float matrix[5];
} __attribute__((packed)) Mixer_t;
#define MAX_MIX_ACTUATORS ACTUATORCOMMAND_CHANNEL_NUMELEM
static int32_t RunMixers(ActuatorCommandData* command, ActuatorSettingsData* settings)
{
SystemSettingsData sysSettings;
MixerSettingsData mixerSettings;
ActuatorDesiredData desired;
MixerStatusData mixerStatus;
SystemSettingsGet(&sysSettings);
MixerStatusGet(&mixerStatus);
MixerSettingsGet (&mixerSettings);
ActuatorDesiredGet(&desired);
float * status = (float *)&mixerStatus; //access status objects as an array of floats
int nMixers = 0;
Mixer_t * mixers = (Mixer_t *)&mixerSettings.Mixer0Type;
for(int ct=0; ct < MAX_MIX_ACTUATORS; ct++)
{
if(mixers[ct].type != MIXERSETTINGS_MIXER0TYPE_DISABLED)
{
nMixers ++;
}
}
if(nMixers < 2) //Nothing can fly with less than two mixers.
{
return(-1);
}
ManualControlCommandData manualControl;
ManualControlCommandGet(&manualControl);
float curve1 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve1);
float curve2 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve2);
for(int ct=0; ct < MAX_MIX_ACTUATORS; ct++)
{
if(mixers[ct].type != MIXERSETTINGS_MIXER0TYPE_DISABLED)
{
status[ct] = scaleChannel(ProcessMixer(ct, curve1, curve2, &mixerSettings, &desired, settings->UpdatePeriod),
settings->ChannelMax[ct],
settings->ChannelMin[ct],
settings->ChannelNeutral[ct]);
if(manualControl.Armed != MANUALCONTROLCOMMAND_ARMED_TRUE &&
mixers[ct].type == MIXERSETTINGS_MIXER0TYPE_MOTOR)
{
command->Channel[ct] = -1; //force zero throttle
}else
{
command->Channel[ct] = status[ct]; //servos always follow command
}
}
}
MixerStatusSet(&mixerStatus);
return(0);
}
/**
*Process mixing for one actuator
*/
float ProcessMixer(const int index, const float curve1, const float curve2,
MixerSettingsData* mixerSettings, ActuatorDesiredData* desired, const float period)
{
static float lastResult[MAX_MIX_ACTUATORS]={0,0,0,0,0,0,0,0};
static float lastFilteredResult[MAX_MIX_ACTUATORS]={0,0,0,0,0,0,0,0};
static float filterAccumulator[MAX_MIX_ACTUATORS]={0,0,0,0,0,0,0,0};
Mixer_t * mixers = (Mixer_t *)&mixerSettings->Mixer0Type; //pointer to array of mixers in UAVObjects
Mixer_t * mixer = &mixers[index];
float result = (mixer->matrix[MIXERSETTINGS_MIXER0MATRIX_THROTTLECURVE1] * curve1) +
(mixer->matrix[MIXERSETTINGS_MIXER0MATRIX_THROTTLECURVE2] * curve2) +
(mixer->matrix[MIXERSETTINGS_MIXER0MATRIX_ROLL] * desired->Roll) +
(mixer->matrix[MIXERSETTINGS_MIXER0MATRIX_PITCH] * desired->Pitch) +
(mixer->matrix[MIXERSETTINGS_MIXER0MATRIX_YAW] * desired->Yaw);
if(mixer->type == MIXERSETTINGS_MIXER0TYPE_MOTOR)
{
if(result < 0) //idle throttle
{
result = 0;
}
//feed forward
float accumulator = filterAccumulator[index];
accumulator += (result - lastResult[index]) * mixerSettings->FeedForward;
lastResult[index] = result;
result += accumulator;
if(accumulator > 0)
{
float filter = mixerSettings->AccelTime / period;
if(filter <1)
{
filter = 1;
}
accumulator -= accumulator / filter;
}else
{
float filter = mixerSettings->DecelTime / period;
if(filter <1)
{
filter = 1;
}
accumulator -= accumulator / filter;
}
filterAccumulator[index] = accumulator;
result += accumulator;
//acceleration limit
float dt = result - lastFilteredResult[index];
float maxDt = mixerSettings->MaxAccel * (period / 1000);
if(dt > maxDt) //we are accelerating too hard
{
result = lastFilteredResult[index] + maxDt;
}
lastFilteredResult[index] = result;
}
return(result);
}
/**
*Interpolate a throttle curve. Throttle input should be in the range 0 to 1.
*Output is in the range 0 to 1.
*/
#define MIXER_CURVE_ENTRIES 5
static float MixerCurve(const float throttle, const float* curve)
{
float scale = throttle * MIXER_CURVE_ENTRIES;
int idx1 = scale;
scale -= (float)idx1; //remainder
if(curve[0] < -1)
{
return(throttle);
}
if (idx1 < 0)
{
idx1 = 0; //clamp to lowest entry in table
scale = 0;
}
int idx2 = idx1 + 1;
if(idx2 >= MIXER_CURVE_ENTRIES)
{
idx2 = MIXER_CURVE_ENTRIES -1; //clamp to highest entry in table
if(idx1 >= MIXER_CURVE_ENTRIES)
{
idx1 = MIXER_CURVE_ENTRIES -1;
}
}
return((curve[idx1] * (1 - scale)) + (curve[idx2] * scale));
}
/**
* Convert channel from -1/+1 to servo pulse duration in microseconds
*/
static int16_t scaleChannel(float value, int16_t max, int16_t min, int16_t neutral)
{
int16_t valueScaled;
// Scale
if ( value >= 0.0)
{
valueScaled = (int16_t)(value*((float)(max-neutral))) + neutral;
}
else
{
valueScaled = (int16_t)(value*((float)(neutral-min))) + neutral;
}
if (max>min)
{
if( valueScaled > max ) valueScaled = max;
if( valueScaled < min ) valueScaled = min;
}
else
{
if( valueScaled < max ) valueScaled = max;
if( valueScaled > min ) valueScaled = min;
}
return valueScaled;
}
/**
* Set actuator output to the neutral values (failsafe)
*/
static void setFailsafe()
{
ActuatorCommandData command;
ActuatorSettingsData settings;
ActuatorCommandGet(&command);
ActuatorSettingsGet(&settings);
// Reset ActuatorCommand to neutral values
for (int n = 0; n < ACTUATORCOMMAND_CHANNEL_NUMELEM; ++n)
{
command.Channel[n] = settings.ChannelNeutral[n];
}
// Set alarm
AlarmsSet(SYSTEMALARMS_ALARM_ACTUATOR, SYSTEMALARMS_ALARM_CRITICAL);
// Update servo outputs
for (int n = 0; n < ACTUATORCOMMAND_CHANNEL_NUMELEM; ++n)
{
PIOS_Servo_Set( n, command.Channel[n] );
}
// Update output object
ActuatorCommandSet(&command);
}
/**
* @}
* @}
*/

View File

@ -0,0 +1,42 @@
/**
******************************************************************************
* @addtogroup OpenPilotModules OpenPilot Modules
* @{
* @addtogroup ActuatorModule Actuator Module
* @brief Compute servo/motor settings based on @ref ActuatorDesired "desired actuator positions" and aircraft type.
* This is where all the mixing of channels is computed.
* @{
*
* @file actuator.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Actuator module. Drives the actuators (servos, motors etc).
*
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef ACTUATOR_H
#define ACTUATOR_H
int32_t ActuatorInitialize();
#endif // ACTUATOR_H
/**
* @}
* @}
*/

View File

@ -52,6 +52,8 @@
#include "homelocation.h"
#include "manualcontrolcommand.h"
#include "manualcontrolsettings.h"
#include "mixersettings.h"
#include "mixerstatus.h"
#include "navigationdesired.h"
#include "navigationsettings.h"
#include "objectpersistence.h"
@ -95,6 +97,8 @@ void UAVObjectsInitializeAll()
HomeLocationInitialize();
ManualControlCommandInitialize();
ManualControlSettingsInitialize();
MixerSettingsInitialize();
MixerStatusInitialize();
NavigationDesiredInitialize();
NavigationSettingsInitialize();
ObjectPersistenceInitialize();

View File

@ -45,7 +45,9 @@ HEADERS += uavobjects_global.h \
homelocation.h \
vtolsettings.h \
vtolstatus.h \
attitudesettings.h
attitudesettings.h \
mixersettings.h \
mixerstatus.h
SOURCES += uavobject.cpp \
uavmetaobject.cpp \
uavobjectmanager.cpp \
@ -87,5 +89,7 @@ SOURCES += uavobject.cpp \
homelocation.cpp \
vtolsettings.cpp \
vtolstatus.cpp \
attitudesettings.cpp
attitudesettings.cpp \
mixersettings.cpp \
mixerstatus.cpp
OTHER_FILES += UAVObjects.pluginspec

View File

@ -54,6 +54,8 @@
#include "homelocation.h"
#include "manualcontrolcommand.h"
#include "manualcontrolsettings.h"
#include "mixersettings.h"
#include "mixerstatus.h"
#include "navigationdesired.h"
#include "navigationsettings.h"
#include "objectpersistence.h"
@ -97,6 +99,8 @@ void UAVObjectsInitialize(UAVObjectManager* objMngr)
objMngr->registerObject( new HomeLocation() );
objMngr->registerObject( new ManualControlCommand() );
objMngr->registerObject( new ManualControlSettings() );
objMngr->registerObject( new MixerSettings() );
objMngr->registerObject( new MixerStatus() );
objMngr->registerObject( new NavigationDesired() );
objMngr->registerObject( new NavigationSettings() );
objMngr->registerObject( new ObjectPersistence() );

View File

@ -0,0 +1,31 @@
<xml>
<object name="MixerSettings" singleinstance="true" settings="true">
<description>Settings for the @ref ActuatorModule that controls the channel assignments for the mixer based on AircraftType</description>
<field name="MaxAccel" units="units/sec" type="float" elements="1" defaultvalue="1000"/>
<field name="FeedForward" units="" type="float" elements="1" defaultvalue="0"/>
<field name="AccelTime" units="ms" type="float" elements="1" defaultvalue="0"/>
<field name="DecelTime" units="ms" type="float" elements="1" defaultvalue="0"/>
<field name="ThrottleCurve1" units="percent" type="float" elements="5" elementnames="0,25,50,75,100" defaultvalue="-10"/>
<field name="ThrottleCurve2" units="percent" type="float" elements="5" elementnames="0,25,50,75,100" defaultvalue="-10"/>
<field name="Mixer0Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer0Matrix" units="" type="float" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer1Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer1Matrix" units="" type="float" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer2Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer2Matrix" units="" type="float" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer3Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer3Matrix" units="" type="float" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer4Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer4Matrix" units="" type="float" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer5Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer5Matrix" units="" type="float" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer6Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer6Matrix" units="" type="float" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<field name="Mixer7Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo" defaultvalue="Disabled"/>
<field name="Mixer7Matrix" units="" type="float" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="true" updatemode="onchange" period="0"/>
<telemetryflight acked="true" updatemode="onchange" period="0"/>
<logging updatemode="never" period="0"/>
</object>
</xml>

View File

@ -0,0 +1,17 @@
<xml>
<object name="MixerStatus" singleinstance="true" settings="false">
<description>Status for the matrix mixer showing the output of each mixer after all scaling</description>
<field name="Mixer0" units="us" type="float" elements="1"/>
<field name="Mixer1" units="us" type="float" elements="1"/>
<field name="Mixer2" units="us" type="float" elements="1"/>
<field name="Mixer3" units="us" type="float" elements="1"/>
<field name="Mixer4" units="us" type="float" elements="1"/>
<field name="Mixer5" units="us" type="float" elements="1"/>
<field name="Mixer6" units="us" type="float" elements="1"/>
<field name="Mixer7" units="us" type="float" elements="1"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="false" updatemode="manual" period="0"/>
<telemetryflight acked="false" updatemode="periodic" period="1000"/>
<logging updatemode="periodic" period="1000"/>
</object>
</xml>