2010-09-27 09:28:34 +02:00
|
|
|
/**
|
|
|
|
******************************************************************************
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
|
2010-12-20 17:38:17 +01:00
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
#include "openpilot.h"
|
2011-06-04 22:31:06 +02:00
|
|
|
#include "accessorydesired.h"
|
2010-09-27 09:28:34 +02:00
|
|
|
#include "actuator.h"
|
|
|
|
#include "actuatorsettings.h"
|
|
|
|
#include "systemsettings.h"
|
|
|
|
#include "actuatordesired.h"
|
|
|
|
#include "actuatorcommand.h"
|
2011-05-03 18:04:44 +02:00
|
|
|
#include "flightstatus.h"
|
2010-09-27 09:28:34 +02:00
|
|
|
#include "mixersettings.h"
|
|
|
|
#include "mixerstatus.h"
|
2011-08-10 04:24:27 +02:00
|
|
|
#include "cameradesired.h"
|
2011-09-07 06:16:34 +02:00
|
|
|
#include "manualcontrolcommand.h"
|
2010-09-27 09:28:34 +02:00
|
|
|
|
|
|
|
// Private constants
|
|
|
|
#define MAX_QUEUE_SIZE 2
|
2011-02-01 03:18:35 +01:00
|
|
|
|
|
|
|
#if defined(PIOS_ACTUATOR_STACK_SIZE)
|
|
|
|
#define STACK_SIZE_BYTES PIOS_ACTUATOR_STACK_SIZE
|
|
|
|
#else
|
|
|
|
#define STACK_SIZE_BYTES 1312
|
|
|
|
#endif
|
|
|
|
|
2011-01-24 08:52:20 +01:00
|
|
|
#define TASK_PRIORITY (tskIDLE_PRIORITY+4)
|
2010-09-27 09:28:34 +02:00
|
|
|
#define FAILSAFE_TIMEOUT_MS 100
|
2010-10-01 14:33:33 +02:00
|
|
|
#define MAX_MIX_ACTUATORS ACTUATORCOMMAND_CHANNEL_NUMELEM
|
2010-09-27 09:28:34 +02:00
|
|
|
|
2012-11-25 12:36:34 +01:00
|
|
|
#define CAMERA_BOOT_DELAY_MS 7000
|
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
// Private types
|
|
|
|
|
|
|
|
|
|
|
|
// Private variables
|
2010-10-01 14:33:20 +02:00
|
|
|
static xQueueHandle queue;
|
2010-09-27 09:28:34 +02:00
|
|
|
static xTaskHandle taskHandle;
|
|
|
|
|
2010-10-03 20:37:07 +02:00
|
|
|
static float lastResult[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};
|
2012-06-23 22:55:57 +02:00
|
|
|
// used to inform the actuator thread that actuator update rate is changed
|
2012-08-12 01:46:00 +02:00
|
|
|
static volatile bool actuator_settings_updated;
|
|
|
|
// used to inform the actuator thread that mixer settings are changed
|
|
|
|
static volatile bool mixer_settings_updated;
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
// Private functions
|
|
|
|
static void actuatorTask(void* parameters);
|
|
|
|
static int16_t scaleChannel(float value, int16_t max, int16_t min, int16_t neutral);
|
2012-08-12 01:46:00 +02:00
|
|
|
static void setFailsafe(const ActuatorSettingsData * actuatorSettings, const MixerSettingsData * mixerSettings);
|
2011-09-10 02:40:58 +02:00
|
|
|
static float MixerCurve(const float throttle, const float* curve, uint8_t elements);
|
2012-08-12 01:46:00 +02:00
|
|
|
static bool set_channel(uint8_t mixer_channel, uint16_t value, const ActuatorSettingsData * actuatorSettings);
|
|
|
|
static void actuator_update_rate_if_changed(const ActuatorSettingsData * actuatorSettings, bool force_update);
|
|
|
|
static void MixerSettingsUpdatedCb(UAVObjEvent * ev);
|
|
|
|
static void ActuatorSettingsUpdatedCb(UAVObjEvent * ev);
|
2010-09-27 09:28:34 +02:00
|
|
|
float ProcessMixer(const int index, const float curve1, const float curve2,
|
2012-08-12 01:46:00 +02:00
|
|
|
const MixerSettingsData* mixerSettings, ActuatorDesiredData* desired,
|
2010-09-27 19:30:42 +02:00
|
|
|
const float period);
|
2010-09-27 09:28:34 +02:00
|
|
|
|
2010-10-01 14:33:33 +02:00
|
|
|
//this structure is equivalent to the UAVObjects for one mixer.
|
|
|
|
typedef struct {
|
|
|
|
uint8_t type;
|
2010-10-01 22:28:14 +02:00
|
|
|
int8_t matrix[5];
|
2010-10-01 14:33:33 +02:00
|
|
|
} __attribute__((packed)) Mixer_t;
|
|
|
|
|
2011-06-20 07:35:40 +02:00
|
|
|
/**
|
|
|
|
* @brief Module initialization
|
|
|
|
* @return 0
|
|
|
|
*/
|
|
|
|
int32_t ActuatorStart()
|
|
|
|
{
|
|
|
|
// Start main task
|
|
|
|
xTaskCreate(actuatorTask, (signed char*)"Actuator", STACK_SIZE_BYTES/4, NULL, TASK_PRIORITY, &taskHandle);
|
|
|
|
TaskMonitorAdd(TASKINFO_RUNNING_ACTUATOR, taskHandle);
|
|
|
|
PIOS_WDG_RegisterFlag(PIOS_WDG_ACTUATOR);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2010-10-01 14:33:33 +02:00
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
/**
|
|
|
|
* @brief Module initialization
|
|
|
|
* @return 0
|
|
|
|
*/
|
|
|
|
int32_t ActuatorInitialize()
|
|
|
|
{
|
2012-08-12 01:46:00 +02:00
|
|
|
// Register for notification of changes to ActuatorSettings
|
2011-06-18 18:59:02 +02:00
|
|
|
ActuatorSettingsInitialize();
|
2012-08-12 01:46:00 +02:00
|
|
|
ActuatorSettingsConnectCallback(ActuatorSettingsUpdatedCb);
|
|
|
|
|
|
|
|
// Register for notification of changes to MixerSettings
|
2011-06-18 18:59:02 +02:00
|
|
|
MixerSettingsInitialize();
|
2012-08-12 01:46:00 +02:00
|
|
|
MixerSettingsConnectCallback(MixerSettingsUpdatedCb);
|
|
|
|
|
|
|
|
// Listen for ActuatorDesired updates (Primary input to this module)
|
|
|
|
ActuatorDesiredInitialize();
|
|
|
|
queue = xQueueCreate(MAX_QUEUE_SIZE, sizeof(UAVObjEvent));
|
|
|
|
ActuatorDesiredConnectQueue(queue);
|
|
|
|
|
|
|
|
// Primary output of this module
|
2011-07-30 04:28:21 +02:00
|
|
|
ActuatorCommandInitialize();
|
2012-08-12 01:46:00 +02:00
|
|
|
|
Final step: lot of small fixes, last commit in this commit series
This is the first cleanup pass through makefiles and pios.
Probably it is difficult to track changes due to the nature of them.
I would recommend to look at resulting files and compiled code instead.
NOTE: original branch was rebased and lot of conflicts were fixed on
the way. So do not expect that every commit in this series will be
buildable (unlike original branch). Only final result was tested.
The main goal was to remove as much duplication of code (and copy/paste
errors) as possible, moving common parts out of Makefiles. It still is
not perfect, and mostly no code changes made - Makefiles and #ifdefs only.
But please while testing make sure that all code works as before, and no
modules/options are missed by accident.
Brief list of changes:
- Moved common parts of Makefiles into the set of *.mk files.
- Changed method of passing common vars from top Makefile to lower ones.
- Some pios cleanup, mostly #ifdefs, and all pios_config.h files.
- Many obsolete files removed (for instance, AHRS files, op_config.h).
- Many obsolete or unused macros removed or fixed/renamed (ALL_DIGNOSTICS).
- Unified pios_config.h template. Please don't remove lines for board
configs, only comment/uncomment them. Adding new PIOS options, please
propagate them to all board files keeping the same order.
- Some formatting, spacing, indentation (no line endings change yet).
- Some cosmetic fixes (no more C:\X\Y\filename.c printings on Windows).
- Added some library.mk files to move libs into AR achives later.
- EntireFlash target now uses cross-platform python script to generate bin
files. So it works on all supported platforms: Linux, OSX, Windows.
- Top level packaging is completely rewritten. Now it is a part of top
Makefile. As such, all dependencies are checked and accounted, no
more 'make -j' problems should occur.
- Default GCS_BUILD_CONF is release now, may be changed if necessary
using 'make GCS_BUILD_CONF=debug gcs'.
- GCS build paths are separated into debug and release, so no more obj
file clashes. Packaging system supports only release builds.
- New target is introduced: 'clean_package'. Now 'make package' does not
clean build directory. Use clean_package instead for distributable builds.
- Targets like 'all', 'opfw_resource', etc now will print extra contex
in parallel builds too.
- If any of 'package', 'clean_package', 'opfw_resource' targets are given
on command line, GCS build will depend on the resource, so all fw_*.opfw
targets will be built and embedded into GCS. By default GCS does not
depend on resource, and will be built w/o firmware (unless the resource
files already exist and the Qt resource file is generated).
- fw_simposix (ELF executable) is now packaged for linux. Run'n'play!
- Make help is refined and is now up to date.
Still broken:
- UnitTests, should be fixed
- SimPosix: buildable, but should be reworked.
Next planned passes to do:
- toolchain bootstrapping and packaging (including windows - WIP)
- CMSIS/StdPeriph lib cleanup
- more PIOS cleanup
- move libs into AR archives to save build time
- sim targets refactir and cleanup
- move android-related directories under <top>/android
- unit test targets fix
- source code line ending changes (there are many different, were not changed)
- coding style
Merging this, please use --no-ff git option to make it the real commit point
Conflicts:
A lot of... :-)
2013-03-24 12:02:08 +01:00
|
|
|
#ifdef DIAG_MIXERSTATUS
|
2012-08-12 01:46:00 +02:00
|
|
|
// UAVO only used for inspecting the internal status of the mixer during debug
|
2011-06-18 18:59:02 +02:00
|
|
|
MixerStatusInitialize();
|
|
|
|
#endif
|
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2011-07-13 05:44:32 +02:00
|
|
|
MODULE_INITCALL(ActuatorInitialize, ActuatorStart)
|
2010-09-27 09:28:34 +02:00
|
|
|
|
|
|
|
/**
|
2011-02-01 03:17:55 +01:00
|
|
|
* @brief Main Actuator module task
|
2010-10-01 14:33:33 +02:00
|
|
|
*
|
|
|
|
* 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
|
2010-09-27 09:28:34 +02:00
|
|
|
*/
|
|
|
|
static void actuatorTask(void* parameters)
|
|
|
|
{
|
2010-10-01 14:33:20 +02:00
|
|
|
UAVObjEvent ev;
|
2010-09-27 09:28:34 +02:00
|
|
|
portTickType lastSysTime;
|
2010-10-01 14:33:33 +02:00
|
|
|
portTickType thisSysTime;
|
2013-05-03 11:54:54 +02:00
|
|
|
float dTSeconds;
|
|
|
|
uint32_t dTMilliseconds;
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2011-06-03 06:18:34 +02:00
|
|
|
ActuatorCommandData command;
|
2010-10-01 14:33:33 +02:00
|
|
|
ActuatorDesiredData desired;
|
|
|
|
MixerStatusData mixerStatus;
|
2011-05-03 18:04:44 +02:00
|
|
|
FlightStatusData flightStatus;
|
2011-06-03 06:18:34 +02:00
|
|
|
|
2012-08-12 01:46:00 +02:00
|
|
|
/* Read initial values of ActuatorSettings */
|
|
|
|
ActuatorSettingsData actuatorSettings;
|
|
|
|
actuator_settings_updated = false;
|
|
|
|
ActuatorSettingsGet(&actuatorSettings);
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2012-08-12 01:46:00 +02:00
|
|
|
/* Read initial values of MixerSettings */
|
|
|
|
MixerSettingsData mixerSettings;
|
|
|
|
mixer_settings_updated = false;
|
|
|
|
MixerSettingsGet(&mixerSettings);
|
|
|
|
|
|
|
|
/* Force an initial configuration of the actuator update rates */
|
|
|
|
actuator_update_rate_if_changed(&actuatorSettings, true);
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
// Go to the neutral (failsafe) values until an ActuatorDesired update is received
|
2012-08-12 01:46:00 +02:00
|
|
|
setFailsafe(&actuatorSettings, &mixerSettings);
|
2010-10-01 14:33:33 +02:00
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
// Main task loop
|
|
|
|
lastSysTime = xTaskGetTickCount();
|
|
|
|
while (1)
|
2011-06-23 08:47:55 +02:00
|
|
|
{
|
2011-01-10 01:16:30 +01:00
|
|
|
PIOS_WDG_UpdateFlag(PIOS_WDG_ACTUATOR);
|
2010-11-23 18:13:42 +01:00
|
|
|
|
2012-08-12 01:46:00 +02:00
|
|
|
// Wait until the ActuatorDesired object is updated
|
|
|
|
uint8_t rc = xQueueReceive(queue, &ev, FAILSAFE_TIMEOUT_MS / portTICK_RATE_MS);
|
|
|
|
|
|
|
|
/* Process settings updated events even in timeout case so we always act on the latest settings */
|
|
|
|
if (actuator_settings_updated) {
|
|
|
|
actuator_settings_updated = false;
|
|
|
|
ActuatorSettingsGet (&actuatorSettings);
|
|
|
|
actuator_update_rate_if_changed (&actuatorSettings, false);
|
|
|
|
}
|
|
|
|
if (mixer_settings_updated) {
|
|
|
|
mixer_settings_updated = false;
|
|
|
|
MixerSettingsGet (&mixerSettings);
|
2010-10-03 20:37:07 +02:00
|
|
|
}
|
|
|
|
|
2012-08-12 01:46:00 +02:00
|
|
|
if (rc != pdTRUE) {
|
|
|
|
/* Update of ActuatorDesired timed out. Go to failsafe */
|
|
|
|
setFailsafe(&actuatorSettings, &mixerSettings);
|
|
|
|
continue;
|
2012-06-23 22:55:57 +02:00
|
|
|
}
|
2012-08-12 01:46:00 +02:00
|
|
|
|
2010-10-01 14:33:33 +02:00
|
|
|
// Check how long since last update
|
|
|
|
thisSysTime = xTaskGetTickCount();
|
2013-05-03 11:54:54 +02:00
|
|
|
dTMilliseconds = (thisSysTime == lastSysTime)? 1: (thisSysTime - lastSysTime) * portTICK_RATE_MS;
|
2010-10-01 14:33:33 +02:00
|
|
|
lastSysTime = thisSysTime;
|
2013-05-03 11:54:54 +02:00
|
|
|
dTSeconds = dTMilliseconds * 0.001f;
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2011-05-03 18:04:44 +02:00
|
|
|
FlightStatusGet(&flightStatus);
|
2010-10-01 14:33:33 +02:00
|
|
|
ActuatorDesiredGet(&desired);
|
2010-09-27 09:28:34 +02:00
|
|
|
ActuatorCommandGet(&command);
|
2011-06-03 06:18:34 +02:00
|
|
|
|
Final step: lot of small fixes, last commit in this commit series
This is the first cleanup pass through makefiles and pios.
Probably it is difficult to track changes due to the nature of them.
I would recommend to look at resulting files and compiled code instead.
NOTE: original branch was rebased and lot of conflicts were fixed on
the way. So do not expect that every commit in this series will be
buildable (unlike original branch). Only final result was tested.
The main goal was to remove as much duplication of code (and copy/paste
errors) as possible, moving common parts out of Makefiles. It still is
not perfect, and mostly no code changes made - Makefiles and #ifdefs only.
But please while testing make sure that all code works as before, and no
modules/options are missed by accident.
Brief list of changes:
- Moved common parts of Makefiles into the set of *.mk files.
- Changed method of passing common vars from top Makefile to lower ones.
- Some pios cleanup, mostly #ifdefs, and all pios_config.h files.
- Many obsolete files removed (for instance, AHRS files, op_config.h).
- Many obsolete or unused macros removed or fixed/renamed (ALL_DIGNOSTICS).
- Unified pios_config.h template. Please don't remove lines for board
configs, only comment/uncomment them. Adding new PIOS options, please
propagate them to all board files keeping the same order.
- Some formatting, spacing, indentation (no line endings change yet).
- Some cosmetic fixes (no more C:\X\Y\filename.c printings on Windows).
- Added some library.mk files to move libs into AR achives later.
- EntireFlash target now uses cross-platform python script to generate bin
files. So it works on all supported platforms: Linux, OSX, Windows.
- Top level packaging is completely rewritten. Now it is a part of top
Makefile. As such, all dependencies are checked and accounted, no
more 'make -j' problems should occur.
- Default GCS_BUILD_CONF is release now, may be changed if necessary
using 'make GCS_BUILD_CONF=debug gcs'.
- GCS build paths are separated into debug and release, so no more obj
file clashes. Packaging system supports only release builds.
- New target is introduced: 'clean_package'. Now 'make package' does not
clean build directory. Use clean_package instead for distributable builds.
- Targets like 'all', 'opfw_resource', etc now will print extra contex
in parallel builds too.
- If any of 'package', 'clean_package', 'opfw_resource' targets are given
on command line, GCS build will depend on the resource, so all fw_*.opfw
targets will be built and embedded into GCS. By default GCS does not
depend on resource, and will be built w/o firmware (unless the resource
files already exist and the Qt resource file is generated).
- fw_simposix (ELF executable) is now packaged for linux. Run'n'play!
- Make help is refined and is now up to date.
Still broken:
- UnitTests, should be fixed
- SimPosix: buildable, but should be reworked.
Next planned passes to do:
- toolchain bootstrapping and packaging (including windows - WIP)
- CMSIS/StdPeriph lib cleanup
- more PIOS cleanup
- move libs into AR archives to save build time
- sim targets refactir and cleanup
- move android-related directories under <top>/android
- unit test targets fix
- source code line ending changes (there are many different, were not changed)
- coding style
Merging this, please use --no-ff git option to make it the real commit point
Conflicts:
A lot of... :-)
2013-03-24 12:02:08 +01:00
|
|
|
#ifdef DIAG_MIXERSTATUS
|
2011-06-17 16:50:10 +02:00
|
|
|
MixerStatusGet(&mixerStatus);
|
|
|
|
#endif
|
2010-10-01 14:33:33 +02:00
|
|
|
int nMixers = 0;
|
2010-12-14 00:54:30 +01:00
|
|
|
Mixer_t * mixers = (Mixer_t *)&mixerSettings.Mixer1Type;
|
2010-10-01 14:33:33 +02:00
|
|
|
for(int ct=0; ct < MAX_MIX_ACTUATORS; ct++)
|
|
|
|
{
|
2010-12-14 00:54:30 +01:00
|
|
|
if(mixers[ct].type != MIXERSETTINGS_MIXER1TYPE_DISABLED)
|
2010-10-01 14:33:33 +02:00
|
|
|
{
|
|
|
|
nMixers ++;
|
|
|
|
}
|
|
|
|
}
|
2011-11-30 08:18:23 +01:00
|
|
|
if((nMixers < 2) && !ActuatorCommandReadOnly()) //Nothing can fly with less than two mixers.
|
2010-09-27 19:30:42 +02:00
|
|
|
{
|
2012-08-12 01:46:00 +02:00
|
|
|
setFailsafe(&actuatorSettings, &mixerSettings); // So that channels like PWM buzzer keep working
|
2010-10-03 20:37:07 +02:00
|
|
|
continue;
|
2010-09-27 19:30:42 +02:00
|
|
|
}
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2010-10-01 16:09:14 +02:00
|
|
|
AlarmsClear(SYSTEMALARMS_ALARM_ACTUATOR);
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2011-05-03 18:04:44 +02:00
|
|
|
bool armed = flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMED;
|
2011-11-26 23:12:32 +01:00
|
|
|
bool positiveThrottle = desired.Throttle >= 0.00f;
|
2012-08-12 01:46:00 +02:00
|
|
|
bool spinWhileArmed = actuatorSettings.MotorsSpinWhileArmed == ACTUATORSETTINGS_MOTORSSPINWHILEARMED_TRUE;
|
2011-06-23 08:47:55 +02:00
|
|
|
|
2011-09-10 02:40:58 +02:00
|
|
|
float curve1 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve1,MIXERSETTINGS_THROTTLECURVE1_NUMELEM);
|
|
|
|
|
2011-06-04 22:31:06 +02:00
|
|
|
//The source for the secondary curve is selectable
|
2011-06-05 15:34:12 +02:00
|
|
|
float curve2 = 0;
|
2011-06-04 22:31:06 +02:00
|
|
|
AccessoryDesiredData accessory;
|
|
|
|
switch(mixerSettings.Curve2Source) {
|
|
|
|
case MIXERSETTINGS_CURVE2SOURCE_THROTTLE:
|
2011-09-10 02:40:58 +02:00
|
|
|
curve2 = MixerCurve(desired.Throttle,mixerSettings.ThrottleCurve2,MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
2011-06-04 22:31:06 +02:00
|
|
|
break;
|
|
|
|
case MIXERSETTINGS_CURVE2SOURCE_ROLL:
|
2011-09-10 02:40:58 +02:00
|
|
|
curve2 = MixerCurve(desired.Roll,mixerSettings.ThrottleCurve2,MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
2011-06-04 22:31:06 +02:00
|
|
|
break;
|
|
|
|
case MIXERSETTINGS_CURVE2SOURCE_PITCH:
|
2011-09-10 02:40:58 +02:00
|
|
|
curve2 = MixerCurve(desired.Pitch,mixerSettings.ThrottleCurve2,
|
|
|
|
MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
2011-06-04 22:31:06 +02:00
|
|
|
break;
|
|
|
|
case MIXERSETTINGS_CURVE2SOURCE_YAW:
|
2011-09-10 02:40:58 +02:00
|
|
|
curve2 = MixerCurve(desired.Yaw,mixerSettings.ThrottleCurve2,MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
2011-06-04 22:31:06 +02:00
|
|
|
break;
|
2011-09-07 06:16:34 +02:00
|
|
|
case MIXERSETTINGS_CURVE2SOURCE_COLLECTIVE:
|
|
|
|
ManualControlCommandCollectiveGet(&curve2);
|
2011-09-10 22:54:10 +02:00
|
|
|
curve2 = MixerCurve(curve2,mixerSettings.ThrottleCurve2,
|
|
|
|
MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
2011-09-07 06:16:34 +02:00
|
|
|
break;
|
2011-06-05 22:30:38 +02:00
|
|
|
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0:
|
2011-06-04 22:31:06 +02:00
|
|
|
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY1:
|
|
|
|
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY2:
|
2011-06-06 17:52:02 +02:00
|
|
|
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY3:
|
|
|
|
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY4:
|
|
|
|
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY5:
|
2011-06-05 22:30:38 +02:00
|
|
|
if(AccessoryDesiredInstGet(mixerSettings.Curve2Source - MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0,&accessory) == 0)
|
2011-09-10 02:40:58 +02:00
|
|
|
curve2 = MixerCurve(accessory.AccessoryVal,mixerSettings.ThrottleCurve2,MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
2011-06-23 08:47:55 +02:00
|
|
|
else
|
|
|
|
curve2 = 0;
|
2011-06-04 22:31:06 +02:00
|
|
|
break;
|
|
|
|
}
|
2011-06-23 08:47:55 +02:00
|
|
|
|
2012-08-12 01:46:00 +02:00
|
|
|
float * status = (float *)&mixerStatus; //access status objects as an array of floats
|
|
|
|
|
2010-10-01 14:33:33 +02:00
|
|
|
for(int ct=0; ct < MAX_MIX_ACTUATORS; ct++)
|
2010-09-27 19:30:42 +02:00
|
|
|
{
|
2012-11-25 12:36:34 +01:00
|
|
|
// During boot all camera actuators should be completely disabled (PWM pulse = 0).
|
|
|
|
// command.Channel[i] is reused below as a channel PWM activity flag:
|
|
|
|
// 0 - PWM disabled, >0 - PWM set to real mixer value using scaleChannel() later.
|
|
|
|
// Setting it to 1 by default means "Rescale this channel and enable PWM on its output".
|
|
|
|
command.Channel[ct] = 1;
|
|
|
|
|
2011-05-12 03:09:28 +02:00
|
|
|
if(mixers[ct].type == MIXERSETTINGS_MIXER1TYPE_DISABLED) {
|
|
|
|
// Set to minimum if disabled. This is not the same as saying PWM pulse = 0 us
|
|
|
|
status[ct] = -1;
|
2011-05-05 07:32:15 +02:00
|
|
|
continue;
|
2011-05-12 03:09:28 +02:00
|
|
|
}
|
2011-06-23 08:47:55 +02:00
|
|
|
|
|
|
|
if((mixers[ct].type == MIXERSETTINGS_MIXER1TYPE_MOTOR) || (mixers[ct].type == MIXERSETTINGS_MIXER1TYPE_SERVO))
|
2013-05-03 11:54:54 +02:00
|
|
|
status[ct] = ProcessMixer(ct, curve1, curve2, &mixerSettings, &desired, dTSeconds);
|
2011-06-23 08:47:55 +02:00
|
|
|
else
|
|
|
|
status[ct] = -1;
|
|
|
|
|
2011-05-05 07:32:15 +02:00
|
|
|
// Motors have additional protection for when to be on
|
2011-06-23 08:47:55 +02:00
|
|
|
if(mixers[ct].type == MIXERSETTINGS_MIXER1TYPE_MOTOR) {
|
2011-05-05 07:32:15 +02:00
|
|
|
|
|
|
|
// If not armed or motors aren't meant to spin all the time
|
|
|
|
if( !armed ||
|
|
|
|
(!spinWhileArmed && !positiveThrottle))
|
2010-10-01 14:33:33 +02:00
|
|
|
{
|
2010-10-03 20:37:07 +02:00
|
|
|
filterAccumulator[ct] = 0;
|
2011-06-23 08:47:55 +02:00
|
|
|
lastResult[ct] = 0;
|
2011-05-05 07:32:15 +02:00
|
|
|
status[ct] = -1; //force min throttle
|
2011-06-23 08:47:55 +02:00
|
|
|
}
|
|
|
|
// If armed meant to keep spinning,
|
2011-05-05 07:32:15 +02:00
|
|
|
else if ((spinWhileArmed && !positiveThrottle) ||
|
|
|
|
(status[ct] < 0) )
|
2011-06-23 08:47:55 +02:00
|
|
|
status[ct] = 0;
|
2010-10-01 14:33:33 +02:00
|
|
|
}
|
2011-06-23 08:47:55 +02:00
|
|
|
|
2011-06-06 17:46:07 +02:00
|
|
|
// If an accessory channel is selected for direct bypass mode
|
|
|
|
// In this configuration the accessory channel is scaled and mapped
|
|
|
|
// directly to output. Note: THERE IS NO SAFETY CHECK HERE FOR ARMING
|
2011-06-23 08:47:55 +02:00
|
|
|
// these also will not be updated in failsafe mode. I'm not sure what
|
2011-06-06 17:46:07 +02:00
|
|
|
// the correct behavior is since it seems domain specific. I don't love
|
|
|
|
// this code
|
2011-06-23 08:47:55 +02:00
|
|
|
if( (mixers[ct].type >= MIXERSETTINGS_MIXER1TYPE_ACCESSORY0) &&
|
|
|
|
(mixers[ct].type <= MIXERSETTINGS_MIXER1TYPE_ACCESSORY5))
|
2011-06-05 22:30:38 +02:00
|
|
|
{
|
2011-06-06 17:46:07 +02:00
|
|
|
if(AccessoryDesiredInstGet(mixers[ct].type - MIXERSETTINGS_MIXER1TYPE_ACCESSORY0,&accessory) == 0)
|
2011-06-04 22:31:06 +02:00
|
|
|
status[ct] = accessory.AccessoryVal;
|
2011-06-05 15:34:12 +02:00
|
|
|
else
|
|
|
|
status[ct] = -1;
|
2011-06-04 22:31:06 +02:00
|
|
|
}
|
2012-11-25 12:36:34 +01:00
|
|
|
|
2013-01-31 00:57:32 +01:00
|
|
|
if( (mixers[ct].type >= MIXERSETTINGS_MIXER1TYPE_CAMERAROLLORSERVO1) &&
|
2011-08-10 04:24:27 +02:00
|
|
|
(mixers[ct].type <= MIXERSETTINGS_MIXER1TYPE_CAMERAYAW))
|
|
|
|
{
|
|
|
|
CameraDesiredData cameraDesired;
|
|
|
|
if( CameraDesiredGet(&cameraDesired) == 0 ) {
|
|
|
|
switch(mixers[ct].type) {
|
2013-01-31 00:57:32 +01:00
|
|
|
case MIXERSETTINGS_MIXER1TYPE_CAMERAROLLORSERVO1:
|
|
|
|
status[ct] = cameraDesired.RollOrServo1;
|
2011-08-10 04:24:27 +02:00
|
|
|
break;
|
2013-01-31 00:57:32 +01:00
|
|
|
case MIXERSETTINGS_MIXER1TYPE_CAMERAPITCHORSERVO2:
|
|
|
|
status[ct] = cameraDesired.PitchOrServo2;
|
2011-08-10 04:24:27 +02:00
|
|
|
break;
|
|
|
|
case MIXERSETTINGS_MIXER1TYPE_CAMERAYAW:
|
|
|
|
status[ct] = cameraDesired.Yaw;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
status[ct] = -1;
|
2012-11-25 12:36:34 +01:00
|
|
|
|
|
|
|
// Disable camera actuators for CAMERA_BOOT_DELAY_MS after boot
|
|
|
|
if (thisSysTime < (CAMERA_BOOT_DELAY_MS / portTICK_RATE_MS))
|
|
|
|
command.Channel[ct] = 0;
|
2011-08-10 04:24:27 +02:00
|
|
|
}
|
2010-09-27 19:30:42 +02:00
|
|
|
}
|
2012-11-25 12:36:34 +01:00
|
|
|
|
|
|
|
// Set real actuator output values scaling them from mixers. All channels
|
|
|
|
// will be set except explicitly disabled (which will have PWM pulse = 0).
|
|
|
|
for (int i = 0; i < MAX_MIX_ACTUATORS; i++)
|
|
|
|
if (command.Channel[i])
|
|
|
|
command.Channel[i] = scaleChannel(status[i],
|
2012-08-12 01:46:00 +02:00
|
|
|
actuatorSettings.ChannelMax[i],
|
|
|
|
actuatorSettings.ChannelMin[i],
|
|
|
|
actuatorSettings.ChannelNeutral[i]);
|
2012-11-25 12:36:34 +01:00
|
|
|
|
2011-01-10 02:11:44 +01:00
|
|
|
// Store update time
|
2013-05-03 11:54:54 +02:00
|
|
|
command.UpdateTime = dTMilliseconds;
|
2012-11-25 12:36:34 +01:00
|
|
|
if (command.UpdateTime > command.MaxUpdateTime)
|
|
|
|
command.MaxUpdateTime = command.UpdateTime;
|
2011-11-26 23:12:32 +01:00
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
// Update output object
|
|
|
|
ActuatorCommandSet(&command);
|
|
|
|
// Update in case read only (eg. during servo configuration)
|
|
|
|
ActuatorCommandGet(&command);
|
2010-10-03 20:37:07 +02:00
|
|
|
|
Final step: lot of small fixes, last commit in this commit series
This is the first cleanup pass through makefiles and pios.
Probably it is difficult to track changes due to the nature of them.
I would recommend to look at resulting files and compiled code instead.
NOTE: original branch was rebased and lot of conflicts were fixed on
the way. So do not expect that every commit in this series will be
buildable (unlike original branch). Only final result was tested.
The main goal was to remove as much duplication of code (and copy/paste
errors) as possible, moving common parts out of Makefiles. It still is
not perfect, and mostly no code changes made - Makefiles and #ifdefs only.
But please while testing make sure that all code works as before, and no
modules/options are missed by accident.
Brief list of changes:
- Moved common parts of Makefiles into the set of *.mk files.
- Changed method of passing common vars from top Makefile to lower ones.
- Some pios cleanup, mostly #ifdefs, and all pios_config.h files.
- Many obsolete files removed (for instance, AHRS files, op_config.h).
- Many obsolete or unused macros removed or fixed/renamed (ALL_DIGNOSTICS).
- Unified pios_config.h template. Please don't remove lines for board
configs, only comment/uncomment them. Adding new PIOS options, please
propagate them to all board files keeping the same order.
- Some formatting, spacing, indentation (no line endings change yet).
- Some cosmetic fixes (no more C:\X\Y\filename.c printings on Windows).
- Added some library.mk files to move libs into AR achives later.
- EntireFlash target now uses cross-platform python script to generate bin
files. So it works on all supported platforms: Linux, OSX, Windows.
- Top level packaging is completely rewritten. Now it is a part of top
Makefile. As such, all dependencies are checked and accounted, no
more 'make -j' problems should occur.
- Default GCS_BUILD_CONF is release now, may be changed if necessary
using 'make GCS_BUILD_CONF=debug gcs'.
- GCS build paths are separated into debug and release, so no more obj
file clashes. Packaging system supports only release builds.
- New target is introduced: 'clean_package'. Now 'make package' does not
clean build directory. Use clean_package instead for distributable builds.
- Targets like 'all', 'opfw_resource', etc now will print extra contex
in parallel builds too.
- If any of 'package', 'clean_package', 'opfw_resource' targets are given
on command line, GCS build will depend on the resource, so all fw_*.opfw
targets will be built and embedded into GCS. By default GCS does not
depend on resource, and will be built w/o firmware (unless the resource
files already exist and the Qt resource file is generated).
- fw_simposix (ELF executable) is now packaged for linux. Run'n'play!
- Make help is refined and is now up to date.
Still broken:
- UnitTests, should be fixed
- SimPosix: buildable, but should be reworked.
Next planned passes to do:
- toolchain bootstrapping and packaging (including windows - WIP)
- CMSIS/StdPeriph lib cleanup
- more PIOS cleanup
- move libs into AR archives to save build time
- sim targets refactir and cleanup
- move android-related directories under <top>/android
- unit test targets fix
- source code line ending changes (there are many different, were not changed)
- coding style
Merging this, please use --no-ff git option to make it the real commit point
Conflicts:
A lot of... :-)
2013-03-24 12:02:08 +01:00
|
|
|
#ifdef DIAG_MIXERSTATUS
|
2011-11-26 23:12:32 +01:00
|
|
|
MixerStatusSet(&mixerStatus);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
// Update servo outputs
|
2011-01-10 02:11:44 +01:00
|
|
|
bool success = true;
|
2011-06-23 08:47:55 +02:00
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
for (int n = 0; n < ACTUATORCOMMAND_CHANNEL_NUMELEM; ++n)
|
|
|
|
{
|
2012-08-12 01:46:00 +02:00
|
|
|
success &= set_channel(n, command.Channel[n], &actuatorSettings);
|
2011-01-10 02:11:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!success) {
|
|
|
|
command.NumFailedUpdates++;
|
|
|
|
ActuatorCommandSet(&command);
|
2011-06-23 08:47:55 +02:00
|
|
|
AlarmsSet(SYSTEMALARMS_ALARM_ACTUATOR, SYSTEMALARMS_ALARM_CRITICAL);
|
2010-09-27 09:28:34 +02:00
|
|
|
}
|
2011-01-10 02:11:44 +01:00
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*Process mixing for one actuator
|
2010-09-27 19:30:42 +02:00
|
|
|
*/
|
2010-09-27 09:28:34 +02:00
|
|
|
float ProcessMixer(const int index, const float curve1, const float curve2,
|
2012-08-12 01:46:00 +02:00
|
|
|
const MixerSettingsData* mixerSettings, ActuatorDesiredData* desired, const float period)
|
2010-09-27 09:28:34 +02:00
|
|
|
{
|
2012-08-12 01:46:00 +02:00
|
|
|
static float lastFilteredResult[MAX_MIX_ACTUATORS];
|
|
|
|
const Mixer_t * mixers = (Mixer_t *)&mixerSettings->Mixer1Type; //pointer to array of mixers in UAVObjects
|
|
|
|
const Mixer_t * mixer = &mixers[index];
|
|
|
|
|
2011-11-26 23:12:32 +01:00
|
|
|
float result = (((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_THROTTLECURVE1] / 128.0f) * curve1) +
|
2012-08-12 01:46:00 +02:00
|
|
|
(((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_THROTTLECURVE2] / 128.0f) * curve2) +
|
|
|
|
(((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_ROLL] / 128.0f) * desired->Roll) +
|
|
|
|
(((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_PITCH] / 128.0f) * desired->Pitch) +
|
|
|
|
(((float)mixer->matrix[MIXERSETTINGS_MIXER1VECTOR_YAW] / 128.0f) * desired->Yaw);
|
|
|
|
|
2010-12-14 00:54:30 +01:00
|
|
|
if(mixer->type == MIXERSETTINGS_MIXER1TYPE_MOTOR)
|
2010-09-27 19:30:42 +02:00
|
|
|
{
|
2011-11-26 23:12:32 +01:00
|
|
|
if(result < 0.0f) //idle throttle
|
2010-09-27 19:30:42 +02:00
|
|
|
{
|
2011-11-26 23:12:32 +01:00
|
|
|
result = 0.0f;
|
2010-09-27 19:30:42 +02:00
|
|
|
}
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2010-09-27 19:30:42 +02:00
|
|
|
//feed forward
|
|
|
|
float accumulator = filterAccumulator[index];
|
|
|
|
accumulator += (result - lastResult[index]) * mixerSettings->FeedForward;
|
|
|
|
lastResult[index] = result;
|
|
|
|
result += accumulator;
|
2013-04-30 13:06:42 +02:00
|
|
|
if(period > 0.0f)
|
2010-09-27 19:30:42 +02:00
|
|
|
{
|
2011-11-26 23:12:32 +01:00
|
|
|
if(accumulator > 0.0f)
|
2010-09-27 19:30:42 +02:00
|
|
|
{
|
2010-10-03 20:37:07 +02:00
|
|
|
float filter = mixerSettings->AccelTime / period;
|
|
|
|
if(filter <1)
|
|
|
|
{
|
|
|
|
filter = 1;
|
|
|
|
}
|
|
|
|
accumulator -= accumulator / filter;
|
|
|
|
}else
|
2010-09-27 19:30:42 +02:00
|
|
|
{
|
2010-10-03 20:37:07 +02:00
|
|
|
float filter = mixerSettings->DecelTime / period;
|
|
|
|
if(filter <1)
|
|
|
|
{
|
|
|
|
filter = 1;
|
|
|
|
}
|
|
|
|
accumulator -= accumulator / filter;
|
2010-09-27 19:30:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
filterAccumulator[index] = accumulator;
|
|
|
|
result += accumulator;
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2010-09-27 19:30:42 +02:00
|
|
|
//acceleration limit
|
|
|
|
float dt = result - lastFilteredResult[index];
|
2010-10-01 16:37:03 +02:00
|
|
|
float maxDt = mixerSettings->MaxAccel * period;
|
2010-09-27 19:30:42 +02:00
|
|
|
if(dt > maxDt) //we are accelerating too hard
|
|
|
|
{
|
|
|
|
result = lastFilteredResult[index] + maxDt;
|
|
|
|
}
|
|
|
|
lastFilteredResult[index] = result;
|
|
|
|
}
|
2011-11-26 23:12:32 +01:00
|
|
|
|
2010-09-27 19:30:42 +02:00
|
|
|
return(result);
|
2010-09-27 09:28:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*Interpolate a throttle curve. Throttle input should be in the range 0 to 1.
|
|
|
|
*Output is in the range 0 to 1.
|
2010-09-27 19:30:42 +02:00
|
|
|
*/
|
2011-09-10 02:40:58 +02:00
|
|
|
static float MixerCurve(const float throttle, const float* curve, uint8_t elements)
|
2010-09-27 09:28:34 +02:00
|
|
|
{
|
2011-11-26 23:12:32 +01:00
|
|
|
float scale = throttle * (float) (elements - 1);
|
2010-09-27 19:30:42 +02:00
|
|
|
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;
|
2011-09-10 02:40:58 +02:00
|
|
|
if(idx2 >= elements)
|
2010-09-27 19:30:42 +02:00
|
|
|
{
|
2011-09-10 02:40:58 +02:00
|
|
|
idx2 = elements -1; //clamp to highest entry in table
|
|
|
|
if(idx1 >= elements)
|
2010-09-27 19:30:42 +02:00
|
|
|
{
|
2011-09-10 02:40:58 +02:00
|
|
|
idx1 = elements -1;
|
2010-09-27 19:30:42 +02:00
|
|
|
}
|
|
|
|
}
|
2011-11-26 23:12:32 +01:00
|
|
|
return curve[idx1] * (1.0f - scale) + curve[idx2] * scale;
|
2010-09-27 09:28:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2011-11-26 23:12:32 +01:00
|
|
|
if ( value >= 0.0f)
|
2010-09-27 09:28:34 +02:00
|
|
|
{
|
|
|
|
valueScaled = (int16_t)(value*((float)(max-neutral))) + neutral;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
valueScaled = (int16_t)(value*((float)(neutral-min))) + neutral;
|
|
|
|
}
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
if (max>min)
|
|
|
|
{
|
|
|
|
if( valueScaled > max ) valueScaled = max;
|
|
|
|
if( valueScaled < min ) valueScaled = min;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( valueScaled < max ) valueScaled = max;
|
|
|
|
if( valueScaled > min ) valueScaled = min;
|
|
|
|
}
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
return valueScaled;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set actuator output to the neutral values (failsafe)
|
|
|
|
*/
|
2012-08-12 01:46:00 +02:00
|
|
|
static void setFailsafe(const ActuatorSettingsData * actuatorSettings, const MixerSettingsData * mixerSettings)
|
2010-09-27 09:28:34 +02:00
|
|
|
{
|
2012-08-12 01:46:00 +02:00
|
|
|
/* grab only the parts that we are going to use */
|
2011-06-03 06:18:34 +02:00
|
|
|
int16_t Channel[ACTUATORCOMMAND_CHANNEL_NUMELEM];
|
|
|
|
ActuatorCommandChannelGet(Channel);
|
2010-10-05 16:47:48 +02:00
|
|
|
|
2012-08-12 01:46:00 +02:00
|
|
|
const Mixer_t * mixers = (Mixer_t *)&mixerSettings->Mixer1Type; //pointer to array of mixers in UAVObjects
|
2010-10-05 16:47:48 +02:00
|
|
|
|
|
|
|
// Reset ActuatorCommand to safe values
|
2010-09-27 09:28:34 +02:00
|
|
|
for (int n = 0; n < ACTUATORCOMMAND_CHANNEL_NUMELEM; ++n)
|
|
|
|
{
|
2011-06-23 08:47:55 +02:00
|
|
|
|
2010-12-14 00:54:30 +01:00
|
|
|
if(mixers[n].type == MIXERSETTINGS_MIXER1TYPE_MOTOR)
|
2010-10-05 16:47:48 +02:00
|
|
|
{
|
2012-08-12 01:46:00 +02:00
|
|
|
Channel[n] = actuatorSettings->ChannelMin[n];
|
2010-10-05 16:47:48 +02:00
|
|
|
}
|
2011-05-12 03:09:28 +02:00
|
|
|
else if(mixers[n].type == MIXERSETTINGS_MIXER1TYPE_SERVO)
|
2010-10-05 16:47:48 +02:00
|
|
|
{
|
2012-08-12 01:46:00 +02:00
|
|
|
Channel[n] = actuatorSettings->ChannelNeutral[n];
|
2010-10-05 16:47:48 +02:00
|
|
|
}
|
2011-05-12 03:09:28 +02:00
|
|
|
else
|
|
|
|
{
|
2011-06-03 06:18:34 +02:00
|
|
|
Channel[n] = 0;
|
2011-05-12 03:09:28 +02:00
|
|
|
}
|
2011-11-26 23:12:32 +01:00
|
|
|
|
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
}
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
// Set alarm
|
|
|
|
AlarmsSet(SYSTEMALARMS_ALARM_ACTUATOR, SYSTEMALARMS_ALARM_CRITICAL);
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2010-09-27 09:28:34 +02:00
|
|
|
// Update servo outputs
|
|
|
|
for (int n = 0; n < ACTUATORCOMMAND_CHANNEL_NUMELEM; ++n)
|
|
|
|
{
|
2012-08-12 01:46:00 +02:00
|
|
|
set_channel(n, Channel[n], actuatorSettings);
|
2010-09-27 09:28:34 +02:00
|
|
|
}
|
2010-10-03 20:37:07 +02:00
|
|
|
|
2011-06-03 06:18:34 +02:00
|
|
|
// Update output object's parts that we changed
|
2011-11-26 22:51:24 +01:00
|
|
|
ActuatorCommandChannelSet(Channel);
|
2010-09-27 09:28:34 +02:00
|
|
|
}
|
|
|
|
|
2012-11-05 10:09:43 +01:00
|
|
|
/**
|
|
|
|
* determine buzzer or blink sequence
|
|
|
|
**/
|
|
|
|
|
|
|
|
typedef enum {BUZZ_BUZZER=0,BUZZ_ARMING=1,BUZZ_INFO=2,BUZZ_MAX=3} buzzertype;
|
|
|
|
|
|
|
|
static inline bool buzzerState(buzzertype type)
|
|
|
|
{
|
|
|
|
// This is for buzzers that take a PWM input
|
|
|
|
|
|
|
|
static uint32_t tune[BUZZ_MAX]={0};
|
|
|
|
static uint32_t tunestate[BUZZ_MAX]={0};
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t newTune = 0;
|
|
|
|
if(type==BUZZ_BUZZER)
|
|
|
|
{
|
|
|
|
// Decide what tune to play
|
|
|
|
if (AlarmsGet(SYSTEMALARMS_ALARM_BATTERY) > SYSTEMALARMS_ALARM_WARNING) {
|
|
|
|
newTune = 0b11110110110000; // pause, short, short, short, long
|
|
|
|
} else if (AlarmsGet(SYSTEMALARMS_ALARM_GPS) >= SYSTEMALARMS_ALARM_WARNING) {
|
|
|
|
newTune = 0x80000000; // pause, short
|
|
|
|
} else {
|
|
|
|
newTune = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else { // BUZZ_ARMING || BUZZ_INFO
|
|
|
|
uint8_t arming;
|
|
|
|
FlightStatusArmedGet(&arming);
|
|
|
|
//base idle tune
|
|
|
|
newTune = 0x80000000; // 0b1000...
|
|
|
|
|
|
|
|
// Merge the error pattern for InfoLed
|
|
|
|
if(type==BUZZ_INFO)
|
|
|
|
{
|
|
|
|
if (AlarmsGet(SYSTEMALARMS_ALARM_BATTERY) > SYSTEMALARMS_ALARM_WARNING)
|
|
|
|
{
|
|
|
|
newTune |= 0b00000000001111111011111110000000;
|
|
|
|
}
|
|
|
|
else if(AlarmsGet(SYSTEMALARMS_ALARM_GPS) >= SYSTEMALARMS_ALARM_WARNING)
|
|
|
|
{
|
|
|
|
newTune |= 0b00000000000000110110110000000000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// fast double blink pattern if armed
|
|
|
|
if (arming == FLIGHTSTATUS_ARMED_ARMED)
|
|
|
|
newTune |= 0xA0000000; // 0b101000...
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do we need to change tune?
|
|
|
|
if (newTune != tune[type]) {
|
|
|
|
tune[type] = newTune;
|
|
|
|
// resynchronize all tunes on change, so they stay in sync
|
|
|
|
for (int i=0;i<BUZZ_MAX;i++) {
|
|
|
|
tunestate[i] = tune[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Play tune
|
|
|
|
bool buzzOn = false;
|
|
|
|
static portTickType lastSysTime = 0;
|
|
|
|
portTickType thisSysTime = xTaskGetTickCount();
|
|
|
|
portTickType dT = 0;
|
|
|
|
|
|
|
|
// For now, only look at the battery alarm, because functions like AlarmsHasCritical() can block for some time; to be discussed
|
|
|
|
if (tune[type]) {
|
|
|
|
if(thisSysTime > lastSysTime) {
|
|
|
|
dT = thisSysTime - lastSysTime;
|
|
|
|
} else {
|
|
|
|
lastSysTime = 0; // avoid the case where SysTimeMax-lastSysTime <80
|
|
|
|
}
|
|
|
|
|
|
|
|
buzzOn = (tunestate[type]&1);
|
|
|
|
|
|
|
|
if (dT > 80) {
|
|
|
|
// Go to next bit in alarm_seq_state
|
|
|
|
for (int i=0;i<BUZZ_MAX;i++) {
|
|
|
|
tunestate[i] >>=1;
|
|
|
|
if (tunestate[i]==0) // All done, re-start the tune
|
|
|
|
tunestate[i]=tune[i];
|
|
|
|
}
|
|
|
|
lastSysTime = thisSysTime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return buzzOn;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-12 01:39:18 +01:00
|
|
|
#if defined(ARCH_POSIX) || defined(ARCH_WIN32)
|
2012-08-12 01:46:00 +02:00
|
|
|
static bool set_channel(uint8_t mixer_channel, uint16_t value, const ActuatorSettingsData * actuatorSettings)
|
|
|
|
{
|
2011-01-12 01:39:18 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#else
|
2012-08-12 01:46:00 +02:00
|
|
|
static bool set_channel(uint8_t mixer_channel, uint16_t value, const ActuatorSettingsData * actuatorSettings)
|
|
|
|
{
|
|
|
|
switch(actuatorSettings->ChannelType[mixer_channel]) {
|
2012-09-11 00:23:49 +02:00
|
|
|
case ACTUATORSETTINGS_CHANNELTYPE_PWMALARMBUZZER:
|
2012-08-12 01:46:00 +02:00
|
|
|
PIOS_Servo_Set(actuatorSettings->ChannelAddr[mixer_channel],
|
2012-11-05 10:09:43 +01:00
|
|
|
buzzerState(BUZZ_BUZZER)?actuatorSettings->ChannelMax[mixer_channel]:actuatorSettings->ChannelMin[mixer_channel]);
|
|
|
|
return true;
|
|
|
|
case ACTUATORSETTINGS_CHANNELTYPE_ARMINGLED:
|
|
|
|
PIOS_Servo_Set(actuatorSettings->ChannelAddr[mixer_channel],
|
|
|
|
buzzerState(BUZZ_ARMING)?actuatorSettings->ChannelMax[mixer_channel]:actuatorSettings->ChannelMin[mixer_channel]);
|
|
|
|
return true;
|
|
|
|
case ACTUATORSETTINGS_CHANNELTYPE_INFOLED:
|
|
|
|
PIOS_Servo_Set(actuatorSettings->ChannelAddr[mixer_channel],
|
|
|
|
buzzerState(BUZZ_INFO)?actuatorSettings->ChannelMax[mixer_channel]:actuatorSettings->ChannelMin[mixer_channel]);
|
2011-03-12 10:02:02 +01:00
|
|
|
return true;
|
2011-01-10 02:11:44 +01:00
|
|
|
case ACTUATORSETTINGS_CHANNELTYPE_PWM:
|
2012-08-12 01:46:00 +02:00
|
|
|
PIOS_Servo_Set(actuatorSettings->ChannelAddr[mixer_channel], value);
|
2011-01-10 02:11:44 +01:00
|
|
|
return true;
|
2011-02-20 08:14:02 +01:00
|
|
|
#if defined(PIOS_INCLUDE_I2C_ESC)
|
2011-06-23 08:47:55 +02:00
|
|
|
case ACTUATORSETTINGS_CHANNELTYPE_MK:
|
2012-08-12 01:46:00 +02:00
|
|
|
return PIOS_SetMKSpeed(actuatorSettings->ChannelAddr[mixer_channel],value);
|
2011-01-10 02:11:44 +01:00
|
|
|
case ACTUATORSETTINGS_CHANNELTYPE_ASTEC4:
|
2012-08-12 01:46:00 +02:00
|
|
|
return PIOS_SetAstec4Speed(actuatorSettings->ChannelAddr[mixer_channel],value);
|
2011-02-20 08:14:02 +01:00
|
|
|
#endif
|
2011-01-10 02:11:44 +01:00
|
|
|
default:
|
|
|
|
return false;
|
2011-06-23 08:47:55 +02:00
|
|
|
}
|
|
|
|
|
2011-01-10 02:11:44 +01:00
|
|
|
return false;
|
2011-06-23 08:47:55 +02:00
|
|
|
|
2011-01-10 02:11:44 +01:00
|
|
|
}
|
2011-01-12 01:39:18 +01:00
|
|
|
#endif
|
2011-01-10 02:11:44 +01:00
|
|
|
|
2012-08-12 01:46:00 +02:00
|
|
|
/**
|
|
|
|
* @brief Update the servo update rate
|
|
|
|
*/
|
|
|
|
static void actuator_update_rate_if_changed(const ActuatorSettingsData * actuatorSettings, bool force_update)
|
|
|
|
{
|
|
|
|
static uint16_t prevChannelUpdateFreq[ACTUATORSETTINGS_CHANNELUPDATEFREQ_NUMELEM];
|
|
|
|
|
|
|
|
// check if the any rate setting is changed
|
|
|
|
if (force_update ||
|
|
|
|
memcmp (prevChannelUpdateFreq,
|
|
|
|
actuatorSettings->ChannelUpdateFreq,
|
|
|
|
sizeof(prevChannelUpdateFreq)) != 0) {
|
|
|
|
/* Something has changed, apply the settings to HW */
|
|
|
|
memcpy (prevChannelUpdateFreq,
|
|
|
|
actuatorSettings->ChannelUpdateFreq,
|
|
|
|
sizeof(prevChannelUpdateFreq));
|
|
|
|
PIOS_Servo_SetHz(actuatorSettings->ChannelUpdateFreq, ACTUATORSETTINGS_CHANNELUPDATEFREQ_NUMELEM);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ActuatorSettingsUpdatedCb(UAVObjEvent * ev)
|
|
|
|
{
|
|
|
|
actuator_settings_updated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void MixerSettingsUpdatedCb(UAVObjEvent * ev)
|
|
|
|
{
|
|
|
|
mixer_settings_updated = true;
|
|
|
|
}
|
2010-09-27 09:28:34 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @}
|
2010-09-27 19:30:42 +02:00
|
|
|
* @}
|
|
|
|
*/
|