1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-12 19:10:32 +03:00

opticalflow mt sensor added (#14038)

* opticalflow mt sensor added

* set the processedFlow to raw when no rotation

* use sin and cos approximations

Co-authored-by: Petr Ledvina <ledvinap@gmail.com>

* Update src/main/sensors/opticalflow.c

Co-authored-by: Petr Ledvina <ledvinap@gmail.com>

* refactoring

* not needed anymore

* update

* Update src/main/sensors/opticalflow.c

Co-authored-by: Petr Ledvina <ledvinap@gmail.com>

* Update src/main/sensors/opticalflow.c

Co-authored-by: Petr Ledvina <ledvinap@gmail.com>

* Update src/main/drivers/rangefinder/rangefinder_lidarmt.c

Co-authored-by: Petr Ledvina <ledvinap@gmail.com>

* update

* rm prototype

* clean up

* Update src/main/drivers/opticalflow/opticalflow.h

Co-authored-by: Petr Ledvina <ledvinap@gmail.com>

* Update src/main/drivers/opticalflow/opticalflow.h

Co-authored-by: Mark Haslinghuis <mark@numloq.nl>

* update flip_y

* Update src/main/drivers/opticalflow/opticalflow.h

Co-authored-by: Petr Ledvina <ledvinap@gmail.com>

* Update src/main/drivers/rangefinder/rangefinder_lidarmt.c

Co-authored-by: Petr Ledvina <ledvinap@gmail.com>

* Update src/main/drivers/rangefinder/rangefinder_lidarmt.h

Co-authored-by: Petr Ledvina <ledvinap@gmail.com>

* Update src/main/sensors/opticalflow.c

Co-authored-by: Petr Ledvina <ledvinap@gmail.com>

* Update src/main/sensors/opticalflow.c

Co-authored-by: Petr Ledvina <ledvinap@gmail.com>

* Update src/main/sensors/opticalflow.c

Co-authored-by: Mark Haslinghuis <mark@numloq.nl>

* rm casting

* update op rotation

---------

Co-authored-by: Petr Ledvina <ledvinap@gmail.com>
Co-authored-by: Mark Haslinghuis <mark@numloq.nl>
This commit is contained in:
ahmedsalah52 2024-12-20 19:47:36 +01:00 committed by GitHub
parent 2f21754a69
commit d244239f39
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 490 additions and 21 deletions

View file

@ -252,6 +252,7 @@ COMMON_SRC = \
osd/osd_warnings.c \
sensors/barometer.c \
sensors/rangefinder.c \
sensors/opticalflow.c \
telemetry/telemetry.c \
telemetry/crsf.c \
telemetry/ghst.c \

View file

@ -55,6 +55,7 @@ const char * const debugModeNames[DEBUG_COUNT] = {
[DEBUG_FPORT] = "FPORT",
[DEBUG_RANGEFINDER] = "RANGEFINDER",
[DEBUG_RANGEFINDER_QUALITY] = "RANGEFINDER_QUALITY",
[DEBUG_OPTICALFLOW] = "OPTICALFLOW",
[DEBUG_LIDAR_TF] = "LIDAR_TF",
[DEBUG_ADC_INTERNAL] = "ADC_INTERNAL",
[DEBUG_RUNAWAY_TAKEOFF] = "RUNAWAY_TAKEOFF",

View file

@ -57,6 +57,7 @@ typedef enum {
DEBUG_FPORT,
DEBUG_RANGEFINDER,
DEBUG_RANGEFINDER_QUALITY,
DEBUG_OPTICALFLOW,
DEBUG_LIDAR_TF,
DEBUG_ADC_INTERNAL,
DEBUG_RUNAWAY_TAKEOFF,

View file

@ -239,6 +239,7 @@ static const char * const featureNames[] = {
_R(FEATURE_SOFTSERIAL, "SOFTSERIAL"),
_R(FEATURE_GPS, "GPS"),
_R(FEATURE_RANGEFINDER, "RANGEFINDER"),
_R(FEATURE_OPTICALFLOW, "OPTICALFLOW"),
_R(FEATURE_TELEMETRY, "TELEMETRY"),
_R(FEATURE_3D, "3D"),
_R(FEATURE_RX_PARALLEL_PWM, "RX_PARALLEL_PWM"),
@ -272,7 +273,7 @@ static const char *const sensorTypeNames[] = {
#define SENSOR_NAMES_MASK (SENSOR_GYRO | SENSOR_ACC | SENSOR_BARO | SENSOR_MAG | SENSOR_RANGEFINDER)
static const char * const *sensorHardwareNames[] = {
lookupTableGyroHardware, lookupTableAccHardware, lookupTableBaroHardware, lookupTableMagHardware, lookupTableRangefinderHardware
lookupTableGyroHardware, lookupTableAccHardware, lookupTableBaroHardware, lookupTableMagHardware, lookupTableRangefinderHardware, lookupTableOpticalflowHardware
};
#endif // USE_SENSOR_NAMES

View file

@ -129,6 +129,7 @@
#include "sensors/esc_sensor.h"
#include "sensors/gyro.h"
#include "sensors/rangefinder.h"
#include "sensors/opticalflow.h"
#include "scheduler/scheduler.h"
@ -170,6 +171,11 @@ const char * const lookupTableRangefinderHardware[] = {
"NONE", "HCSR04", "TFMINI", "TF02", "MTF01", "MTF02", "MTF01P", "MTF02P"
};
#endif
#if defined(USE_SENSOR_NAMES) || defined(USE_OPTICALFLOW)
const char * const lookupTableOpticalflowHardware[] = {
"NONE", "MT"
};
#endif
const char * const lookupTableOffOn[] = {
"OFF", "ON"
@ -613,6 +619,9 @@ const lookupTableEntry_t lookupTables[] = {
#ifdef USE_RANGEFINDER
LOOKUP_TABLE_ENTRY(lookupTableRangefinderHardware),
#endif
#ifdef USE_OPTICALFLOW
LOOKUP_TABLE_ENTRY(lookupTableOpticalflowHardware),
#endif
#ifdef USE_GYRO_OVERFLOW_CHECK
LOOKUP_TABLE_ENTRY(lookupTableGyroOverflowCheck),
#endif
@ -1710,6 +1719,14 @@ const clivalue_t valueTable[] = {
{ "rangefinder_hardware", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_RANGEFINDER_HARDWARE }, PG_RANGEFINDER_CONFIG, offsetof(rangefinderConfig_t, rangefinder_hardware) },
#endif
// PG_OPTICALFLOW_CONFIG
#ifdef USE_OPTICALFLOW
{ "opticalflow_hardware", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OPTICALFLOW_HARDWARE }, PG_OPTICALFLOW_CONFIG, offsetof(opticalflowConfig_t, opticalflow_hardware) },
{ "opticalflow_rotation", VAR_INT16 | MASTER_VALUE , .config.minmaxUnsigned = {0, 359}, PG_OPTICALFLOW_CONFIG, offsetof(opticalflowConfig_t, rotation) },
{ "opticalflow_lpf", VAR_UINT16 | MASTER_VALUE , .config.minmaxUnsigned = {0, 10000}, PG_OPTICALFLOW_CONFIG, offsetof(opticalflowConfig_t, flow_lpf) },
{ "opticalflow_flip_x", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_OPTICALFLOW_CONFIG, offsetof(opticalflowConfig_t, flip_x) },
#endif
// PG_PINIO_CONFIG
#ifdef USE_PINIO
{ "pinio_config", VAR_UINT8 | HARDWARE_VALUE | MODE_ARRAY, .config.array.length = PINIO_COUNT, PG_PINIO_CONFIG, offsetof(pinioConfig_t, config) },

View file

@ -82,6 +82,9 @@ typedef enum {
#ifdef USE_RANGEFINDER
TABLE_RANGEFINDER_HARDWARE,
#endif
#ifdef USE_OPTICALFLOW
TABLE_OPTICALFLOW_HARDWARE,
#endif
#ifdef USE_GYRO_OVERFLOW_CHECK
TABLE_GYRO_OVERFLOW_CHECK,
#endif
@ -260,6 +263,8 @@ extern const char * const lookupTableMagHardware[];
extern const char * const lookupTableRangefinderHardware[];
extern const char * const lookupTableOpticalflowHardware[];
extern const char * const lookupTableLedstripColors[];
extern const char * const lookupTableRescueAltitudeMode[];

View file

@ -57,6 +57,9 @@ uint32_t featuresSupportedByBuild =
#ifdef USE_RANGEFINDER
| FEATURE_RANGEFINDER
#endif
#ifdef USE_OPTICALFLOW
| FEATURE_OPTICALFLOW
#endif
#ifdef USE_TELEMETRY
| FEATURE_TELEMETRY
#endif

View file

@ -50,6 +50,7 @@ typedef enum {
FEATURE_SERVO_TILT = 1 << 5,
FEATURE_SOFTSERIAL = 1 << 6,
FEATURE_GPS = 1 << 7,
FEATURE_OPTICALFLOW = 1 << 8,
FEATURE_RANGEFINDER = 1 << 9,
FEATURE_TELEMETRY = 1 << 10,
FEATURE_3D = 1 << 12,

View file

@ -0,0 +1,52 @@
/*
* This file is part of Betaflight.
*
* Betaflight is free software. You can redistribute this software
* and/or modify this software 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.
*
* Betaflight 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 software.
*
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include "common/vector.h"
#define OPTICALFLOW_OUT_OF_RANGE -1
#define OPTICALFLOW_HARDWARE_FAILURE -2
#define OPTICALFLOW_NO_NEW_DATA -3
#define OPTICALFLOW_HARDWARE_TIMEOUT_US 100000 // 100ms
typedef struct opticalflowData_s {
uint32_t timeStampUs;
int16_t quality;
vector2_t flowRate;
} opticalflowData_t;
struct opticalflowDev_s;
typedef void opflowOpInitFunc(struct opticalflowDev_s * dev);
typedef void opflowOpUpdateFunc(struct opticalflowDev_s * dev);
typedef void opflowOpReadFunc(struct opticalflowDev_s * dev, opticalflowData_t * result);
typedef struct opticalflowDev_s {
unsigned delayMs;
int16_t minRangeCm;
uint8_t minQualityThreshold;
opflowOpInitFunc *init;
opflowOpUpdateFunc *update;
opflowOpReadFunc *read;
} opticalflowDev_t;

View file

@ -24,7 +24,6 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "platform.h"
@ -34,11 +33,21 @@
#include "common/utils.h"
#include "drivers/time.h"
#include "drivers/rangefinder/rangefinder_lidarmt.h"
#include "sensors/rangefinder.h"
static bool hasNewData = false;
static int32_t sensorData = RANGEFINDER_NO_NEW_DATA;
#include "drivers/opticalflow/opticalflow.h"
#define MT_OPTICALFLOW_MIN_RANGE 80 // mm
#define MT_OPFLOW_MIN_QUALITY_THRESHOLD 30
static opticalflowData_t opticalflowSensorData = {0};
static bool hasRFNewData = false;
static mtRangefinderData_t rfSensorData = {RANGEFINDER_NO_NEW_DATA, 0};
static const MTRangefinderConfig * deviceConf = NULL;
// Initialize the table with values for each rangefinder type
static const MTRangefinderConfig rangefinderConfigs[] = {
@ -63,40 +72,41 @@ static void mtRangefinderUpdate(rangefinderDev_t * dev) {
static int32_t mtRangefinderGetDistance(rangefinderDev_t * dev) {
UNUSED(dev);
if (hasNewData) {
hasNewData = false;
return (sensorData >= 0.0f) ? sensorData : RANGEFINDER_OUT_OF_RANGE;
if (hasRFNewData) {
hasRFNewData = false;
return (rfSensorData.distanceMm >= 0) ? (rfSensorData.distanceMm / 10) : RANGEFINDER_OUT_OF_RANGE;
} else {
return RANGEFINDER_NO_NEW_DATA;
}
}
bool mtRangefinderDetect(rangefinderDev_t * dev, rangefinderType_e mtRangefinderToUse) {
const MTRangefinderConfig* deviceConf = getMTRangefinderDeviceConf(mtRangefinderToUse);
deviceConf = getMTRangefinderDeviceConf(mtRangefinderToUse);
if (!deviceConf) {
return false;
}
dev->delayMs = deviceConf->delayMs;
dev->maxRangeCm = deviceConf->maxRangeCm;
dev->detectionConeDeciDegrees = RANGEFINDER_MT_DETECTION_CONE_DECIDEGREES;
dev->detectionConeExtendedDeciDegrees = RANGEFINDER_MT_DETECTION_CONE_DECIDEGREES;
dev->init = &mtRangefinderInit;
dev->init = &mtRangefinderInit;
dev->update = &mtRangefinderUpdate;
dev->read = &mtRangefinderGetDistance;
dev->read = &mtRangefinderGetDistance;
return true;
}
void mtRangefinderReceiveNewData(const uint8_t * bufferPtr) {
const mspSensorRangefinderLidarMtDataMessage_t * pkt = (const mspSensorRangefinderLidarMtDataMessage_t *)bufferPtr;
sensorData = pkt->distanceMm / 10;
hasNewData = true;
rfSensorData.distanceMm = pkt->distanceMm;
rfSensorData.timestampUs = micros();
hasRFNewData = true;
}
const MTRangefinderConfig* getMTRangefinderDeviceConf(rangefinderType_e mtRangefinderToUse){
const MTRangefinderConfig* getMTRangefinderDeviceConf(rangefinderType_e mtRangefinderToUse) {
for (const MTRangefinderConfig* cfg = rangefinderConfigs; cfg < ARRAYEND(rangefinderConfigs); cfg++) {
if (cfg->deviceType == mtRangefinderToUse) {
return cfg;
@ -105,4 +115,60 @@ const MTRangefinderConfig* getMTRangefinderDeviceConf(rangefinderType_e mtRangef
return NULL;
}
const mtRangefinderData_t * getMTRangefinderData(void) {
return &rfSensorData;
}
typedef struct __attribute__((packed)) {
uint8_t quality; // [0;255]
int32_t motionX;
int32_t motionY;
} mtOpticalflowDataMessage_t;
static void mtOpticalflowInit(opticalflowDev_t * dev) {
UNUSED(dev);
}
static void mtOpticalflowUpdate(opticalflowDev_t * dev) {
UNUSED(dev);
}
static void mtOpticalflowGetData(opticalflowDev_t * dev, opticalflowData_t * result) {
UNUSED(dev);
*result = opticalflowSensorData;
}
bool mtOpticalflowDetect(opticalflowDev_t * dev, rangefinderType_e mtRangefinderToUse) {
deviceConf = getMTRangefinderDeviceConf(mtRangefinderToUse);
if (!deviceConf) {
return false;
}
dev->delayMs = deviceConf->delayMs;
dev->minRangeCm = MT_OPTICALFLOW_MIN_RANGE;
dev->minQualityThreshold = MT_OPFLOW_MIN_QUALITY_THRESHOLD;
dev->init = &mtOpticalflowInit;
dev->update = &mtOpticalflowUpdate;
dev->read = &mtOpticalflowGetData;
return true;
}
void mtOpticalflowReceiveNewData(const uint8_t * bufferPtr) {
const mtRangefinderData_t * latestRangefinderData = getMTRangefinderData();
const mtOpticalflowDataMessage_t * pkt = (const mtOpticalflowDataMessage_t *)bufferPtr;
opticalflowSensorData.timeStampUs = micros();
opticalflowSensorData.flowRate.x = (float)pkt->motionX / 1000.0f;
opticalflowSensorData.flowRate.y = (float)pkt->motionY / 1000.0f;
opticalflowSensorData.quality = pkt->quality * 100 / 255;
if (latestRangefinderData->distanceMm < MT_OPTICALFLOW_MIN_RANGE) {
opticalflowSensorData.quality = OPTICALFLOW_OUT_OF_RANGE;
} else if (cmp32(micros(), latestRangefinderData->timestampUs) > (5000 * deviceConf->delayMs)) { // 5 updates missing
opticalflowSensorData.quality = OPTICALFLOW_HARDWARE_FAILURE;
}
}
#endif // USE_RANGEFINDER_MT

View file

@ -21,6 +21,7 @@
#pragma once
#include "drivers/rangefinder/rangefinder.h"
#include "drivers/opticalflow/opticalflow.h"
#include "sensors/rangefinder.h"
#define RANGEFINDER_MT_DETECTION_CONE_DECIDEGREES 900
@ -31,6 +32,14 @@ typedef struct {
uint16_t maxRangeCm;
} MTRangefinderConfig;
typedef struct {
uint32_t timestampUs;
int32_t distanceMm;
} mtRangefinderData_t;
bool mtRangefinderDetect(rangefinderDev_t * dev, rangefinderType_e mtRangefinderToUse);
void mtRangefinderReceiveNewData(const uint8_t * bufferPtr);
const MTRangefinderConfig* getMTRangefinderDeviceConf(rangefinderType_e mtRangefinderToUse);
bool mtOpticalflowDetect(opticalflowDev_t * dev, rangefinderType_e mtRangefinderToUse);
void mtOpticalflowReceiveNewData(const uint8_t * bufferPtr);

View file

@ -98,6 +98,7 @@
#include "sensors/gyro.h"
#include "sensors/sensors.h"
#include "sensors/rangefinder.h"
#include "sensors/opticalflow.h"
#include "telemetry/telemetry.h"
#include "telemetry/crsf.h"
@ -302,6 +303,20 @@ void taskUpdateRangefinder(timeUs_t currentTimeUs)
}
#endif
#ifdef USE_OPTICALFLOW
void taskUpdateOpticalflow(timeUs_t currentTimeUs)
{
UNUSED(currentTimeUs);
if (!sensors(SENSOR_OPTICALFLOW)) {
return;
}
opticalflowUpdate();
opticalflowProcess();
}
#endif
#ifdef USE_TELEMETRY
static void taskTelemetry(timeUs_t currentTimeUs)
{
@ -449,7 +464,9 @@ task_attribute_t task_attributes[TASK_COUNT] = {
#ifdef USE_RANGEFINDER
[TASK_RANGEFINDER] = DEFINE_TASK("RANGEFINDER", NULL, NULL, taskUpdateRangefinder, TASK_PERIOD_HZ(10), TASK_PRIORITY_LOWEST),
#endif
#ifdef USE_OPTICALFLOW
[TASK_OPTICALFLOW] = DEFINE_TASK("OPTICALFLOW", NULL, NULL, taskUpdateOpticalflow, TASK_PERIOD_HZ(10), TASK_PRIORITY_LOWEST),
#endif
#ifdef USE_CRSF_V3
[TASK_SPEED_NEGOTIATION] = DEFINE_TASK("SPEED_NEGOTIATION", NULL, NULL, speedNegotiationProcess, TASK_PERIOD_HZ(100), TASK_PRIORITY_LOW),
#endif
@ -528,6 +545,12 @@ void tasksInit(void)
}
#endif
#ifdef USE_OPTICALFLOW
if (sensors(SENSOR_OPTICALFLOW)) {
setTaskEnabled(TASK_OPTICALFLOW, featureIsEnabled(FEATURE_OPTICALFLOW));
}
#endif
setTaskEnabled(TASK_RX, true);
setTaskEnabled(TASK_DISPATCH, dispatchIsEnabled());

View file

@ -149,6 +149,7 @@
#include "sensors/gyro.h"
#include "sensors/gyro_init.h"
#include "sensors/rangefinder.h"
#include "sensors/opticalflow.h"
#include "telemetry/msp_shared.h"
#include "telemetry/telemetry.h"
@ -2054,7 +2055,7 @@ case MSP_NAME:
break;
case MSP_SENSOR_CONFIG:
// use sensorIndex_e index: 0:GyroHardware, 1:AccHardware, 2:BaroHardware, 3:MagHardware, 4:RangefinderHardware
// use sensorIndex_e index: 0:GyroHardware, 1:AccHardware, 2:BaroHardware, 3:MagHardware, 4:RangefinderHardware 5:OpticalflowHardware
#if defined(USE_ACC)
sbufWriteU8(dst, accelerometerConfig()->acc_hardware);
#else
@ -2076,6 +2077,12 @@ case MSP_NAME:
#else
sbufWriteU8(dst, RANGEFINDER_NONE);
#endif
#ifdef USE_OPTICALFLOW
sbufWriteU8(dst, opticalflowConfig()->opticalflow_hardware);
#else
sbufWriteU8(dst, OPTICALFLOW_NONE);
#endif
break;
// Added in MSP API 1.46
@ -2107,6 +2114,11 @@ case MSP_NAME:
sbufWriteU8(dst, detectedSensors[SENSOR_INDEX_RANGEFINDER]);
#else
sbufWriteU8(dst, SENSOR_NOT_AVAILABLE);
#endif
#ifdef USE_OPTICAL_FLOW
sbufWriteU8(dst, detectedSensors[SENSOR_INDEX_OPTICALFLOW]);
#else
sbufWriteU8(dst, SENSOR_NOT_AVAILABLE);
#endif
break;
@ -3301,7 +3313,13 @@ static mspResult_e mspProcessInCommand(mspDescriptor_t srcDesc, int16_t cmdMSP,
#ifdef USE_RANGEFINDER
rangefinderConfigMutable()->rangefinder_hardware = sbufReadU8(src);
#else
sbufReadU8(src); // rangefinder hardware
sbufReadU8(src);
#endif
#ifdef USE_OPTICALFLOW
opticalflowConfigMutable()->opticalflow_hardware = sbufReadU8(src);
#else
sbufReadU8(src);
#endif
break;
#ifdef USE_ACC
@ -3658,7 +3676,12 @@ static mspResult_e mspProcessInCommand(mspDescriptor_t srcDesc, int16_t cmdMSP,
case MSP2_SENSOR_RANGEFINDER_LIDARMT:
mtRangefinderReceiveNewData(sbufPtr(src));
break;
case MSP2_SENSOR_OPTICALFLOW_MT:
mtOpticalflowReceiveNewData(sbufPtr(src));
break;
#endif
#ifdef USE_GPS
case MSP2_SENSOR_GPS:
(void)sbufReadU8(src); // instance

View file

@ -29,6 +29,7 @@
#define MSP2_GET_LED_STRIP_CONFIG_VALUES 0x3008
#define MSP2_SET_LED_STRIP_CONFIG_VALUES 0x3009
#define MSP2_SENSOR_CONFIG_ACTIVE 0x300A
#define MSP2_SENSOR_OPTICALFLOW 0x300B
// MSP2_SET_TEXT and MSP2_GET_TEXT variable types
#define MSP2TEXT_PILOT_NAME 1

View file

@ -25,3 +25,4 @@
#define MSP2_SENSOR_GPS 0x1F03
// TODO: implement new, extensible rangefinder protocol
#define MSP2_SENSOR_RANGEFINDER_LIDARMT 0x1F01
#define MSP2_SENSOR_OPTICALFLOW_MT 0x1F02

View file

@ -158,7 +158,9 @@
#define PG_MSP_CONFIG 557
//#define PG_SOFTSERIAL_PIN_CONFIG 558 // removed, merged into SERIAL_PIN_CONFIG
#define PG_GIMBAL_TRACK_CONFIG 559
#define PG_BETAFLIGHT_END 559
#define PG_OPTICALFLOW_CONFIG 560
#define PG_BETAFLIGHT_END 560
// OSD configuration (subject to change)
#define PG_OSD_FONT_CONFIG 2047

View file

@ -134,6 +134,9 @@ typedef enum {
#ifdef USE_RANGEFINDER
TASK_RANGEFINDER,
#endif
#ifdef USE_OPTICALFLOW
TASK_OPTICALFLOW,
#endif
#if defined(USE_BARO) || defined(USE_GPS)
TASK_ALTITUDE,
#endif

View file

@ -45,10 +45,11 @@
#include "sensors/initialisation.h"
#include "sensors/rangefinder.h"
#include "sensors/sensors.h"
#include "sensors/opticalflow.h"
// requestedSensors is not actually used
uint8_t requestedSensors[SENSOR_INDEX_COUNT] = { GYRO_NONE, ACC_NONE, BARO_NONE, MAG_NONE, RANGEFINDER_NONE };
uint8_t detectedSensors[SENSOR_INDEX_COUNT] = { GYRO_NONE, ACC_NONE, BARO_NONE, MAG_NONE, RANGEFINDER_NONE };
uint8_t requestedSensors[SENSOR_INDEX_COUNT] = { GYRO_NONE, ACC_NONE, BARO_NONE, MAG_NONE, RANGEFINDER_NONE, OPTICALFLOW_NONE};
uint8_t detectedSensors[SENSOR_INDEX_COUNT] = { GYRO_NONE, ACC_NONE, BARO_NONE, MAG_NONE, RANGEFINDER_NONE, OPTICALFLOW_NONE};
void sensorsPreInit(void)
{
@ -88,6 +89,10 @@ bool sensorsAutodetect(void)
rangefinderInit();
#endif
#ifdef USE_OPTICALFLOW
opticalflowInit();
#endif
#ifdef USE_ADC_INTERNAL
adcInternalInit();
#endif

View file

@ -0,0 +1,196 @@
/*
* This file is part of Betaflight.
*
* Betaflight is free software. You can redistribute this software
* and/or modify this software 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.
*
* Betaflight 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 software.
*
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <math.h>
#include "platform.h"
#ifdef USE_OPTICALFLOW
#include "build/build_config.h"
#include "build/debug.h"
#include "common/maths.h"
#include "common/time.h"
#include "common/utils.h"
#include "common/filter.h"
#include "config/config.h"
#include "config/feature.h"
#include "fc/runtime_config.h"
#include "scheduler/scheduler.h"
#include "pg/pg.h"
#include "pg/pg_ids.h"
#include "drivers/time.h"
#include "drivers/rangefinder/rangefinder.h"
#include "drivers/rangefinder/rangefinder_lidarmt.h"
#include "io/beeper.h"
#include "sensors/sensors.h"
#include "sensors/gyro.h"
#include "sensors/acceleration.h"
#include "sensors/opticalflow.h"
#define OPTICALFLOW_CALIBRATION_DURATION_MS 30000
#define RATE_SCALE_RESOLUTION (1000.0f)
// static prototypes
static void applySensorRotation(vector2_t * dst, vector2_t * src);
static void applyLPF(vector2_t * flowRates);
PG_REGISTER_WITH_RESET_TEMPLATE(opticalflowConfig_t, opticalflowConfig, PG_OPTICALFLOW_CONFIG, 0);
PG_RESET_TEMPLATE(opticalflowConfig_t, opticalflowConfig,
.opticalflow_hardware = OPTICALFLOW_NONE,
.rotation = 0,
.flow_lpf = 0,
.flip_x = 0
);
static opticalflow_t opticalflow;
float cosRotAngle = 1.0f;
float sinRotAngle = 0.0f;
static pt2Filter_t xFlowLpf, yFlowLpf;
// ======================================================================
// =================== Opticalflow Main Functions =======================
// ======================================================================
static bool opticalflowDetect(opticalflowDev_t * dev, uint8_t opticalflowHardwareToUse) {
UNUSED(dev);
opticalflowType_e opticalflowHardware = OPTICALFLOW_NONE;
requestedSensors[SENSOR_INDEX_OPTICALFLOW] = opticalflowHardwareToUse;
switch (opticalflowHardwareToUse) {
case OPTICALFLOW_MT:
#ifdef USE_RANGEFINDER_MT
if (mtOpticalflowDetect(dev, rangefinderConfig()->rangefinder_hardware)) {
opticalflowHardware = OPTICALFLOW_MT;
rescheduleTask(TASK_OPTICALFLOW, TASK_PERIOD_MS(dev->delayMs));
}
#endif
break;
case OPTICALFLOW_NONE:
opticalflowHardware = OPTICALFLOW_NONE;
break;
}
if (opticalflowHardware == OPTICALFLOW_NONE) {
sensorsClear(SENSOR_OPTICALFLOW);
return false;
}
detectedSensors[SENSOR_INDEX_OPTICALFLOW] = opticalflowHardware;
sensorsSet(SENSOR_OPTICALFLOW);
return true;
}
bool opticalflowInit(void) {
if (!opticalflowDetect(&opticalflow.dev, opticalflowConfig()->opticalflow_hardware)) {
return false;
}
opticalflow.dev.init(&opticalflow.dev);
opticalflow.quality = OPTICALFLOW_NO_NEW_DATA;
opticalflow.rawFlowRates.x = 0;
opticalflow.rawFlowRates.y = 0;
opticalflow.processedFlowRates.x = 0;
opticalflow.processedFlowRates.y = 0;
opticalflow.timeStampUs = micros();
cosRotAngle = cosf(DEGREES_TO_RADIANS(opticalflowConfig()->rotation));
sinRotAngle = sinf(DEGREES_TO_RADIANS(opticalflowConfig()->rotation));
//low pass filter
if (opticalflowConfig()->flow_lpf != 0) {
const float flowCutoffHz = (float)opticalflowConfig()->flow_lpf / 100.0f;
const float flowGain = pt2FilterGain(flowCutoffHz, opticalflow.dev.delayMs / 1000.0f);
pt2FilterInit(&xFlowLpf, flowGain);
pt2FilterInit(&yFlowLpf, flowGain);
}
return true;
}
void opticalflowUpdate(void) {
if (opticalflow.dev.update) {
opticalflow.dev.update(&opticalflow.dev);
}
}
void opticalflowProcess(void) {
opticalflowData_t data = {0};
uint32_t deltaTimeUs = 0;
opticalflow.dev.read(&opticalflow.dev, &data);
opticalflow.quality = data.quality;
deltaTimeUs = cmp32(data.timeStampUs, opticalflow.timeStampUs);
if (deltaTimeUs != 0) { // New data
vector2_t raw = data.flowRate;
vector2_t processed;
applySensorRotation(&processed, &raw);
applyLPF(&processed);
opticalflow.rawFlowRates = raw;
opticalflow.processedFlowRates = processed;
opticalflow.timeStampUs = data.timeStampUs;
// DEBUG SECTION
DEBUG_SET(DEBUG_OPTICALFLOW, 0, opticalflow.quality);
DEBUG_SET(DEBUG_OPTICALFLOW, 1, lrintf(opticalflow.rawFlowRates.x * 1000));
DEBUG_SET(DEBUG_OPTICALFLOW, 2, lrintf(opticalflow.rawFlowRates.y * 1000));
DEBUG_SET(DEBUG_OPTICALFLOW, 3, lrintf(opticalflow.processedFlowRates.x * 1000));
DEBUG_SET(DEBUG_OPTICALFLOW, 4, lrintf(opticalflow.processedFlowRates.y * 1000));
DEBUG_SET(DEBUG_OPTICALFLOW, 5, deltaTimeUs);
}
}
static void applySensorRotation(vector2_t * dst, vector2_t * src) {
dst->x = (opticalflowConfig()->flip_x ? -1.0f : 1.0f) * (src->x * cosRotAngle - src->y * sinRotAngle);
dst->y = src->x * sinRotAngle + src->y * cosRotAngle;
}
static void applyLPF(vector2_t * flowRates) {
if (opticalflowConfig()->flow_lpf == 0) {
return;
}
flowRates->x = pt2FilterApply(&xFlowLpf, flowRates->x);
flowRates->y = pt2FilterApply(&yFlowLpf, flowRates->y);
}
const opticalflow_t * getLatestFlowOpticalflowData(void) {
return &opticalflow;
}
bool isOpticalflowHealthy(void) {
return cmp32(micros(), opticalflow.timeStampUs) < OPTICALFLOW_HARDWARE_TIMEOUT_US;
}
#endif // USE_OPTICALFLOW

View file

@ -0,0 +1,56 @@
/*
* This file is part of Betaflight.
*
* Betaflight is free software. You can redistribute this software
* and/or modify this software 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.
*
* Betaflight 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 software.
*
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "drivers/opticalflow/opticalflow.h"
#include "pg/pg.h"
typedef enum {
OPTICALFLOW_NONE = 0,
OPTICALFLOW_MT = 1,
} opticalflowType_e;
typedef struct opticalflowConfig_s {
uint8_t opticalflow_hardware;
uint16_t rotation;
uint8_t flip_x;
uint16_t flow_lpf;
} opticalflowConfig_t;
PG_DECLARE(opticalflowConfig_t, opticalflowConfig);
typedef struct opticalflow_s {
opticalflowDev_t dev;
int16_t quality;
vector2_t rawFlowRates;
vector2_t processedFlowRates;
uint32_t timeStampUs;
} opticalflow_t;
bool opticalflowInit(void);
void opticalflowUpdate(void);
bool isOpticalflowHealthy(void);
void opticalflowProcess(void);

View file

@ -26,6 +26,7 @@ typedef enum {
SENSOR_INDEX_BARO,
SENSOR_INDEX_MAG,
SENSOR_INDEX_RANGEFINDER,
SENSOR_INDEX_OPTICALFLOW,
SENSOR_INDEX_COUNT
} sensorIndex_e;
@ -52,5 +53,6 @@ typedef enum {
SENSOR_SONAR = 1 << 4,
SENSOR_RANGEFINDER = 1 << 4,
SENSOR_GPS = 1 << 5,
SENSOR_GPSMAG = 1 << 6
SENSOR_GPSMAG = 1 << 6,
SENSOR_OPTICALFLOW = 1 << 7
} sensors_e;