1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-24 00:35:39 +03:00

Add support for LED thrust ring. (St7ven)

This commit includes various fixed not included in the original pull request.
This commit is contained in:
St7ven 2015-01-01 16:04:01 +01:00 committed by Dominic Clifton
parent d2536e3792
commit ddc7a39fa2
3 changed files with 179 additions and 35 deletions

View file

@ -111,6 +111,7 @@ Note: It is perfectly possible to configure an LED to have all directions `NESWU
* `I` - `I`ndicator.
* `A` - `A`rmed state.
* `T` - `T`hrust state.
* `R` - `R`ing thrust state.
Example:
@ -171,6 +172,24 @@ This mode fades the LED current LED color to the previous/next color in the HSB
throttle is in the middle position the color is unaffected, thus it can be mixed with orientation colors to indicate orientation and throttle at
the same time.
#### Thrust ring state
This mode is allows you to use a 12, 16 or 24 leds ring (e.g. NeoPixel ring) for an afterburner effect. When armed the leds use the following sequences: 2 On, 4 Off, 2 On, 4 Off, and so on. The light pattern rotates clockwise as throttle increases.
A better effect is acheived when LEDs configured for thrust ring have no other functions.
LED direction and X/Y positions are irrelevant for thrust ring LED state. The order of the LEDs that have the state determines how the LED behaves.
Each LED of the ring can be a different color. The color can be selected between the 15 colors availables.
For example, led 0 is set as a `R`ing thrust state led in color 13 as follow.
```
led 0 2,2::R:13
```
LED strips and rings can be combined.
## Positioning
Cut the strip into sections as per diagrams below. When the strips are cut ensure you reconnect each output to each input with cable where the break is made.

View file

@ -55,6 +55,7 @@ static failsafe_t* failsafe;
static void ledStripDisable(void);
//#define USE_LED_ANIMATION
//#define USE_LED_RING_DEFAULT_CONFIG
// timers
#ifdef USE_LED_ANIMATION
@ -63,6 +64,7 @@ static uint32_t nextAnimationUpdateAt = 0;
static uint32_t nextIndicatorFlashAt = 0;
static uint32_t nextWarningFlashAt = 0;
static uint32_t nextRotationUpdateAt = 0;
#define LED_STRIP_20HZ ((1000 * 1000) / 20)
#define LED_STRIP_10HZ ((1000 * 1000) / 10)
@ -225,23 +227,44 @@ static const modeColorIndexes_t baroModeColors = {
uint8_t ledGridWidth;
uint8_t ledGridHeight;
uint8_t ledCount;
uint8_t ledsInRingCount;
ledConfig_t *ledConfigs;
hsvColor_t *colors;
#ifdef USE_LED_RING_DEFAULT_CONFIG
const ledConfig_t defaultLedStripConfig[] = {
{ CALCULATE_LED_XY( 2, 2), LED_DIRECTION_SOUTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 2, 1), LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 2, 0), LED_DIRECTION_NORTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 0), LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 0), LED_DIRECTION_NORTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 1), LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 0, 2), LED_DIRECTION_SOUTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 2), LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_UP | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_UP | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_DOWN | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), LED_DIRECTION_DOWN | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 2, 2), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 2, 1), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 2, 0), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 1, 0), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 0, 0), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 0, 1), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 0, 2), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 1, 2), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 1, 1), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 1, 1), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 1, 1), 3, LED_FUNCTION_THRUST_RING},
{ CALCULATE_LED_XY( 1, 1), 3, LED_FUNCTION_THRUST_RING},
};
#else
const ledConfig_t defaultLedStripConfig[] = {
{ CALCULATE_LED_XY( 2, 2), 0, LED_DIRECTION_SOUTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 2, 1), 0, LED_DIRECTION_EAST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 2, 0), 0, LED_DIRECTION_NORTH | LED_DIRECTION_EAST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 0), 0, LED_DIRECTION_NORTH | LED_FUNCTION_FLIGHT_MODE },
{ CALCULATE_LED_XY( 0, 0), 0, LED_DIRECTION_NORTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 0, 1), 0, LED_DIRECTION_WEST | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 0, 2), 0, LED_DIRECTION_SOUTH | LED_DIRECTION_WEST | LED_FUNCTION_INDICATOR | LED_FUNCTION_ARM_STATE },
{ CALCULATE_LED_XY( 1, 2), 0, LED_DIRECTION_SOUTH | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), 0, LED_DIRECTION_UP | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), 0, LED_DIRECTION_UP | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), 0, LED_DIRECTION_DOWN | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
{ CALCULATE_LED_XY( 1, 1), 0, LED_DIRECTION_DOWN | LED_FUNCTION_FLIGHT_MODE | LED_FUNCTION_WARNING },
};
#endif
/*
@ -258,12 +281,13 @@ typedef enum {
X_COORDINATE,
Y_COORDINATE,
DIRECTIONS,
FUNCTIONS
FUNCTIONS,
RING_COLORS
} parseState_e;
#define PARSE_STATE_COUNT 4
#define PARSE_STATE_COUNT 5
static const char chunkSeparators[PARSE_STATE_COUNT] = {',', ':', ':', '\0' };
static const char chunkSeparators[PARSE_STATE_COUNT] = {',', ':', ':',':', '\0' };
static const char directionCodes[] = { 'N', 'E', 'S', 'W', 'U', 'D' };
#define DIRECTION_COUNT (sizeof(directionCodes) / sizeof(directionCodes[0]))
@ -276,14 +300,15 @@ static const uint8_t directionMappings[DIRECTION_COUNT] = {
LED_DIRECTION_DOWN
};
static const char functionCodes[] = { 'I', 'W', 'F', 'A', 'T' };
static const char functionCodes[] = { 'I', 'W', 'F', 'A', 'T', 'R' };
#define FUNCTION_COUNT (sizeof(functionCodes) / sizeof(functionCodes[0]))
static const uint16_t functionMappings[FUNCTION_COUNT] = {
LED_FUNCTION_INDICATOR,
LED_FUNCTION_WARNING,
LED_FUNCTION_FLIGHT_MODE,
LED_FUNCTION_ARM_STATE,
LED_FUNCTION_THROTTLE
LED_FUNCTION_THROTTLE,
LED_FUNCTION_THRUST_RING
};
// grid offsets
@ -327,13 +352,24 @@ void determineOrientationLimits(void)
void updateLedCount(void)
{
const ledConfig_t *ledConfig;
uint8_t ledIndex;
ledCount = 0;
ledsInRingCount = 0;
for (ledIndex = 0; ledIndex < MAX_LED_STRIP_LENGTH; ledIndex++) {
if (ledConfigs[ledIndex].flags == 0 && ledConfigs[ledIndex].xy == 0) {
ledConfig = &ledConfigs[ledIndex];
if (ledConfig->flags == 0 && ledConfig->xy == 0) {
break;
}
ledCount++;
if ((ledConfig->flags & LED_FUNCTION_THRUST_RING)) {
ledsInRingCount++;
}
}
}
@ -410,6 +446,15 @@ bool parseLedStripConfig(uint8_t ledIndex, const char *config)
}
}
break;
case RING_COLORS:
if (atoi(chunk) < CONFIGURABLE_COLOR_COUNT) {
ledConfig->color = atoi(chunk);
} else {
ledConfig->color = 0;
}
break;
default :
break;
}
parseState++;
@ -433,11 +478,13 @@ void generateLedConfig(uint8_t ledIndex, char *ledConfigBuffer, size_t bufferSiz
char directions[DIRECTION_COUNT];
uint8_t index;
uint8_t mappingIndex;
ledConfig_t *ledConfig = &ledConfigs[ledIndex];
memset(ledConfigBuffer, 0, bufferSize);
memset(&functions, 0, sizeof(functions));
memset(&directions, 0, sizeof(directions));
//memset(&ringColors, 0 ,sizeof(ringColors));
for (mappingIndex = 0, index = 0; mappingIndex < FUNCTION_COUNT; mappingIndex++) {
if (ledConfig->flags & functionMappings[mappingIndex]) {
@ -451,7 +498,7 @@ void generateLedConfig(uint8_t ledIndex, char *ledConfigBuffer, size_t bufferSiz
}
}
sprintf(ledConfigBuffer, "%u,%u:%s:%s", GET_LED_X(ledConfig), GET_LED_Y(ledConfig), directions, functions);
sprintf(ledConfigBuffer, "%u,%u:%s:%s:%u", GET_LED_X(ledConfig), GET_LED_Y(ledConfig), directions, functions, ledConfig->color);
}
void applyDirectionalModeColor(const uint8_t ledIndex, const ledConfig_t *ledConfig, const modeColorIndexes_t *modeColors)
@ -529,7 +576,9 @@ void applyLedModeLayer(void)
ledConfig = &ledConfigs[ledIndex];
if (!(ledConfig->flags & LED_FUNCTION_THRUST_RING)) {
setLedHsv(ledIndex, &hsv_black);
}
if (!(ledConfig->flags & LED_FUNCTION_FLIGHT_MODE)) {
if (ledConfig->flags & LED_FUNCTION_ARM_STATE) {
@ -695,15 +744,77 @@ void applyLedThrottleLayer()
}
}
int applyLedThrustRingLayer(void)
{
uint8_t oppositeLedIndex = ledsInRingCount >> 1;
uint8_t ledIndex;
int returnedValue = 1;
int throttleScaled = scaleRange(rcData[THROTTLE], PWM_RANGE_MIN, PWM_RANGE_MAX, 1, 10);
static uint8_t rotationPhase = 0;
static bool nextLedOn = false;
hsvColor_t ringColor;
const ledConfig_t *ledConfig;
for (ledIndex = 0; ledIndex < ledCount; ledIndex++) {
ledConfig = &ledConfigs[ledIndex];
ringColor = colors[ledConfig->color];
if ((ledConfig->flags & LED_FUNCTION_THRUST_RING)) {
if (!ARMING_FLAG(ARMED)) {
if (nextLedOn == false) {
nextLedOn = true;
}
else {
nextLedOn = false;
ringColor = hsv_black;
}
returnedValue = 1;
}
else {
if (rotationPhase == ((oppositeLedIndex) - 1)) {
if (!((ledIndex == rotationPhase) || (ledIndex == (rotationPhase + oppositeLedIndex))
|| (ledIndex == (rotationPhase +1)) || (ledIndex == 0))) {
ringColor = hsv_black;
}
}
else if (!((ledIndex == rotationPhase) || (ledIndex == (rotationPhase + oppositeLedIndex))
|| (ledIndex == (rotationPhase +1)) || (ledIndex == (rotationPhase + oppositeLedIndex +1 )))) {
ringColor = hsv_black;
}
else {
// Led stay on
}
returnedValue = throttleScaled;
}
setLedHsv(ledIndex, &ringColor);
}
}
if (rotationPhase >= (oppositeLedIndex - 1)) {
rotationPhase = 0;
}
else {
rotationPhase++;
}
return returnedValue;
}
#ifdef USE_LED_ANIMATION
void updateLedAnimationState(void)
{
static uint8_t frameCounter = 0;
static uint8_t previousRow;
static uint8_t currentRow;
static uint8_t nextRow;
static void updateLedAnimationState(void)
{
uint8_t animationFrames = ledGridHeight;
previousRow = (frameCounter + animationFrames - 1) % animationFrames;
@ -741,6 +852,7 @@ static void applyLedAnimationLayer(void)
void updateLedStrip(void)
{
if (!(ledStripInitialised && isWS2811LedStripReady())) {
return;
}
@ -763,11 +875,13 @@ void updateLedStrip(void)
bool indicatorFlashNow = indicatorFlashNow = (int32_t)(now - nextIndicatorFlashAt) >= 0L;
bool warningFlashNow = warningFlashNow = (int32_t)(now - nextWarningFlashAt) >= 0L;
bool rotationUpdateNow = (int32_t)(now - nextRotationUpdateAt) >= 0L;
#ifdef USE_LED_ANIMATION
bool animationUpdateNow = animationUpdateNow = (int32_t)(now - nextAnimationUpdateAt) >= 0L;
#endif
if (!(
indicatorFlashNow ||
rotationUpdateNow ||
warningFlashNow
#ifdef USE_LED_ANIMATION
|| animationUpdateNow
@ -812,10 +926,16 @@ void updateLedStrip(void)
nextAnimationUpdateAt = now + LED_STRIP_20HZ;
updateLedAnimationState();
}
applyLedAnimationLayer();
#endif
if (rotationUpdateNow) {
int animationSpeedScaled = applyLedThrustRingLayer();
nextRotationUpdateAt = now + LED_STRIP_5HZ/animationSpeedScaled; // TODO will be changed with more specifics animation
}
ws2811UpdateStrip();
}
@ -835,6 +955,7 @@ bool parseColor(uint8_t index, const char *colorConfig)
if (val > HSV_HUE_MAX) {
ok = false;
continue;
}
colors[index].h = val;
break;

View file

@ -18,6 +18,7 @@
#pragma once
#define MAX_LED_STRIP_LENGTH 32
#define CONFIGURABLE_COLOR_COUNT 16
#define LED_X_BIT_OFFSET 4
#define LED_Y_BIT_OFFSET 0
@ -30,6 +31,7 @@
#define CALCULATE_LED_X(x) ((x & LED_XY_MASK) << LED_X_BIT_OFFSET)
#define CALCULATE_LED_Y(y) ((y & LED_XY_MASK) << LED_Y_BIT_OFFSET)
#define CALCULATE_LED_XY(x,y) (CALCULATE_LED_X(x) | CALCULATE_LED_Y(y))
typedef enum {
@ -44,7 +46,8 @@ typedef enum {
LED_FUNCTION_WARNING = (1 << 7),
LED_FUNCTION_FLIGHT_MODE = (1 << 8),
LED_FUNCTION_ARM_STATE = (1 << 9),
LED_FUNCTION_THROTTLE = (1 << 10)
LED_FUNCTION_THROTTLE = (1 << 10),
LED_FUNCTION_THRUST_RING = (1 << 11),
} ledFlag_e;
#define LED_DIRECTION_BIT_OFFSET 0
@ -55,16 +58,17 @@ typedef enum {
typedef struct ledConfig_s {
uint8_t xy; // see LED_X/Y_MASK defines
uint8_t color; // see colors (config_master)
uint16_t flags; // see ledFlag_e
} ledConfig_t;
extern uint8_t ledCount;
#define CONFIGURABLE_COLOR_COUNT 16
bool parseLedStripConfig(uint8_t ledIndex, const char *config);
void updateLedStrip(void);
void updateLedRing(void);
void applyDefaultLedStripConfig(ledConfig_t *ledConfig);
void generateLedConfig(uint8_t ledIndex, char *ledConfigBuffer, size_t bufferSize);