ArduPilot开源代码之AP_OpticalFlow_UPFLOW

1. 源由

AP_OpticalFlow_UPFLOW也是一种光流计,与前面AP_OpticalFlow_CXOF类似。

而且其波特率也是19200 bps,采用同样的pulling方式。唯一的差别就是两者帧格式略有差异。

2. Library设计

设备相关的重要函数:

  • init
  • update
  • detect
class AP_OpticalFlow_UPFLOW : public OpticalFlow_backend
{
public:
    /// 构造函数
    AP_OpticalFlow_UPFLOW(AP_OpticalFlow &_frontend, AP_HAL::UARTDriver *uart);

    // 初始化传感器
    void init() override;

    // 从传感器读取最新的值并填充 x, y 和总量
    void update(void) override;

    // 检测传感器是否可用
    static AP_OpticalFlow_UPFLOW *detect(AP_OpticalFlow &_frontend);

private:
    // 数据结构:光流数据
    struct PACKED UpixelsOpticalFlow {
        int16_t flow_x_integral;        // 单位:10^-4 弧度,乘以 10^-4 得到弧度值
        int16_t flow_y_integral;        // 单位:10^-4 弧度,乘以 10^-4 得到弧度值
        uint16_t integration_timespan;  // 时间间隔,单位:微秒
        uint16_t ground_distance;       // 保留字段,总是为 999
        uint8_t quality;                // 数据质量,0 表示无效,245 表示有效
        uint8_t version;                // 版本号
    };

    AP_HAL::UARTDriver *uart;               // 连接到光流传感器的 UART
    struct UpixelsOpticalFlow updata;       // 接收的数据结构
    uint16_t recv_count;                    // 接收到的字节数
    uint8_t sum;                            // 校验和
    Vector2f gyro_sum;                      // 自上次从光流传感器接收到数据以来陀螺仪传感器值的总和
    uint16_t gyro_sum_count;                // 陀螺仪传感器值的数量
};

3. 重要例程

3.1 AP_OpticalFlow_UPFLOW::init

模块默认波特率19200 bps。

// initialise the sensor
void AP_OpticalFlow_UPFLOW::init()
{
    // sanity check uart
    if (uart == nullptr) {
        return;
    }
    // open serial port with baud rate of 19200
    uart->begin(19200);
}

3.2 AP_OpticalFlow_UPFLOW::update

串口数据采用pull的方式读取,相对来说更占用CPU资源。

[AP_OpticalFlow_MSP](https://blog.csdn.net/lida2003/article/details/140328944)采用Interrupt方式比较节省资源,并且Matek光流计采用了115200 bps的波特率,速度更快,暂用CPU的时间更短。

update()
├── 检查UART是否有效
│   └── if (uart == nullptr)
│       └── return
├── 记录陀螺仪数值
│   └── if (gyro_sum_count >= 1000)
│       ├── gyro_sum.zero()  // 将陀螺仪累积值清零
│       └── gyro_sum_count = 0  // 重置累积计数
│   └── const Vector3f& gyro = AP::ahrs().get_gyro()  // 获取陀螺仪数据
│   └── gyro_sum.x += gyro.x  // 累积陀螺仪x轴数据
│   └── gyro_sum.y += gyro.y  // 累积陀螺仪y轴数据
│   └── gyro_sum_count++  // 累积计数加一
├── 读取串口数据
│   └── uint32_t nbytes = MIN(uart->available(), 1024u)  // 获取可用数据字节数
│   └── while (nbytes-- > 0)  // 循环读取每个字节数据
│       └── int16_t r = uart->read()  // 读取一个字节数据
│       └── if (r < 0)
│           └── break
│       └── uint8_t c = (uint8_t)r  // 转换为无符号字节
│       └── if (recv_count == 0)
│           └── if (c == UPFLOW_HEADER0)
│               └── recv_count++  // 接收计数加一
│               └── sum = 0  // 校验和清零
│       └── else if (recv_count == 1)
│           └── if (c != UPFLOW_HEADER1)
│               └── recv_count = 0  // 重置接收计数
│           └── else
│               └── recv_count++  // 接收计数加一
│       └── else if (recv_count < 12)
│           └── ((uint8_t*)&updata)[recv_count - 2] = c  // 存储接收到的数据
│           └── sum ^= c  // 更新校验和
│           └── recv_count++  // 接收计数加一
│       └── else if (recv_count == 12)
│           └── if (sum != c)
│               └── recv_count = 0  // 校验和错误,重置接收计数
│           └── else
│               └── recv_count++  // 接收计数加一
│       └── else
│           └── if (c == UPFLOW_FOOTER)
│               └── phrased = true  // 标记解析完成
│           └── recv_count = 0  // 重置接收计数
├── 如果没有有效数据,则返回
│   └── if (phrased == false)
│       └── return
├── 处理接收到的数据
│   └── struct AP_OpticalFlow::OpticalFlow_state state {}  // 定义光流状态结构体
│   └── state.surface_quality = updata.quality  // 设置表面质量
│   └── float dt = updata.integration_timespan * 1.0e-6  // 计算时间间隔
│   └── if (is_positive(dt) && (dt < UPFLOW_TIMEOUT_SEC))  // 如果时间间隔有效
│       ├── 计算流速数值
│       ├── const Vector2f flowScaler = _flowScaler()  // 获取流速缩放器
│       ├── Vector2f flowScaleFactor = Vector2f(1.0f, 1.0f) + flowScaler * 0.001f  // 计算流速缩放因子
│       ├── state.flowRate = Vector2f(-updata.flow_x_integral * flowScaleFactor.x, -updata.flow_y_integral * flowScaleFactor.y)  // 计算流速
│       ├── state.flowRate *= UPFLOW_PIXEL_SCALING / dt  // 根据时间间隔调整流速
│       ├── state.bodyRate = Vector2f(gyro_sum.x / gyro_sum_count, gyro_sum.y / gyro_sum_count)  // 计算体速度
│       └── _applyYaw(state.flowRate)  // 应用偏航角修正流速
│   └── else
│       └── state.flowRate.zero()  // 时间间隔无效时流速置零
│       └── state.bodyRate.zero()  // 时间间隔无效时体速度置零
└── 更新前端状态
    └── _update_frontend(state)  // 更新前端状态信息
└── 重置陀螺仪累积值
    └── gyro_sum.zero()  // 陀螺仪累积值清零
    └── gyro_sum_count = 0  // 重置陀螺仪累积计数

3.3 AP_OpticalFlow_UPFLOW::detect

AP_OpticalFlow初始化的内容直接放到了detect函数实现。

// detect the device
AP_OpticalFlow_UPFLOW *AP_OpticalFlow_UPFLOW::detect(AP_OpticalFlow &_frontend)
{
    AP_SerialManager *serial_manager = AP::serialmanager().get_singleton();
    if (serial_manager == nullptr) {
        return nullptr;
    }

    // look for first serial driver with protocol defined as OpticalFlow
    AP_HAL::UARTDriver *uart = serial_manager->find_serial(AP_SerialManager::SerialProtocol_OpticalFlow, 0);
    if (uart == nullptr) {
        return nullptr;
    }

    // we have found a serial port so use it
    AP_OpticalFlow_UPFLOW *sensor = new AP_OpticalFlow_UPFLOW(_frontend, uart);
    return sensor;
}

4. 总结

UPFLOW和CXOF类似,从协议使用的方式来看,效率偏低。

5. 参考资料

【1】ArduPilot开源飞控系统之简单介绍
【2】ArduPilot之开源代码Task介绍
【3】ArduPilot飞控启动&运行过程简介
【4】ArduPilot之开源代码Library&Sketches设计
【5】ArduPilot之开源代码Sensor Drivers设计
【6】ArduPilot开源飞控之AP_OpticalFlow

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值