ArduPilot开源代码之AP_OSD_MAX7456

1. 源由

前面讨论了

本章将针对具体的AP_OSD_MAX7456类进行研讨。

2. 结构设计

2.1 成员变量

新增:

    AP_HAL::OwnPtr<AP_HAL::Device> _dev;

    uint8_t  video_signal_reg;
    bool initialized;
    uint8_t last_font;
    int8_t last_v_offset;
    int8_t last_h_offset;

    static const uint8_t video_lines_ntsc = 13;
    static const uint8_t video_lines_pal = 16;
    static const uint8_t video_columns = 30;
    static const uint16_t spi_buffer_size = 512;

    uint8_t frame[video_lines_pal][video_columns];

    //frame already transfered to max
    //used to optimize number of characters updated
    uint8_t shadow_frame[video_lines_pal][video_columns];

    uint8_t buffer[spi_buffer_size];
    int buffer_offset;

    uint32_t last_signal_check;
    uint32_t video_detect_time;

    uint16_t video_lines;

2.2 OSD 符号

无自定义,将会保持与 AP_OSD_Backend 一致。

3. 接口设计

3.1 一次性接口

3.1.1 init

通过SPI对MAX7456进行重置,并更新字体库。

bool AP_OSD_MAX7456::init()
{
    uint8_t status = 0xFF;

    _dev->get_semaphore()->take_blocking();
    _dev->write_register(MAX7456ADD_VM0, MAX7456_RESET);
    hal.scheduler->delay(1);
    _dev->read_registers(MAX7456ADD_VM0|MAX7456ADD_READ, &status, 1);
    _dev->get_semaphore()->give();
    if (status != 0) {
        return false;
    }
    return update_font();
}

3.1.2 osd_thread_run_once

无,使用 AP_OSD_Backend::osd_thread_run_once

3.1.3 init_symbol_set

无,使用 AP_OSD_Backend::init_symbol_set

3.1.4 probe

最初的初始化,直接在AP_OSD::init_backend中进行,详见:ArduPilot开源代码之AP_OSD

AP_OSD_Backend *AP_OSD_MAX7456::probe(AP_OSD &osd, AP_HAL::OwnPtr<AP_HAL::Device> dev)
{
    if (!dev) {
        return nullptr;
    }

    AP_OSD_MAX7456 *backend = NEW_NOTHROW AP_OSD_MAX7456(osd, std::move(dev));
    if (!backend) {
        return nullptr;
    }
    if (!backend->init()) {
        delete backend;
        return nullptr;
    }
    return backend;
}

3.2 基本操作

3.2.1 write

直接写入界面缓存中。

void AP_OSD_MAX7456::write(uint8_t x, uint8_t y, const char* text)
{
    if (y >= video_lines_pal || text == nullptr) {
        return;
    }
    while ((x < VIDEO_COLUMNS) && (*text != 0)) {
        frame[y][x] = *text;
        ++text;
        ++x;
    }
}

3.2.2 flush

通过SPI刷一帧数据到MAX7456

void AP_OSD_MAX7456::flush()
{
    if (last_font != get_font_num()) {
        update_font();
    }

    // check for offset changes
    if (last_v_offset != _osd.v_offset) {
        int8_t vos = constrain_int16(_osd.v_offset, 0, 31);
        _dev->get_semaphore()->take_blocking();
        _dev->write_register(MAX7456ADD_VOS, vos);
        _dev->get_semaphore()->give();
        last_v_offset = _osd.v_offset;
    }
    if (last_h_offset != _osd.h_offset) {
        int8_t hos = constrain_int16(_osd.h_offset, 0, 63);
        _dev->get_semaphore()->take_blocking();
        _dev->write_register(MAX7456ADD_HOS, hos);
        _dev->get_semaphore()->give();
        last_h_offset = _osd.h_offset;
    }

    check_reinit();
    transfer_frame();
}

3.2.3 clear

缓存清零,相当于OSD清空,但是MAX7456并不清空。

void AP_OSD_MAX7456::clear()
{
    AP_OSD_Backend::clear();
    memset(frame, ' ', sizeof(frame));
}

3.3 功能函数

3.3.1 is_compatible_with_backend_type

  • 不兼容:OSD_MAX7456/OSD_SITL
  • 兼容:OSD_MSP/OSD_MSP_DISPLAYPORT
    bool is_compatible_with_backend_type(AP_OSD::osd_types type) const override {
        switch(type) {
        case AP_OSD::osd_types::OSD_MAX7456:
        case AP_OSD::osd_types::OSD_SITL:
            return false;
        case AP_OSD::osd_types::OSD_NONE:
        case AP_OSD::osd_types::OSD_TXONLY:
        case AP_OSD::osd_types::OSD_MSP:
        case AP_OSD::osd_types::OSD_MSP_DISPLAYPORT:
            return true;
        }
        return false;
    }

3.3.2 get_backend_type

    AP_OSD::osd_types get_backend_type() const override {
        return AP_OSD::osd_types::OSD_MAX7456;
    }

3.3.3 get_aspect_ratio_correction

根据视频制式调整纵横比校正因子,确保屏幕显示(OSD)的角度和图形正确无误。解决像素宽高比导致的图形失真问题,确保OSD元素(如仪表、指针)按预期比例显示。

  1. NTSC格式
    返回校正因子12.0f/18.46f ≈ 0.65
    NTSC的像素宽高比通常非正方形(如矩形像素),水平方向较宽。通过缩小水平长度或增加垂直长度,抵消像素拉伸,保持显示比例正确。

  2. PAL格式
    返回校正因子12.0f/15.0f = 0.8
    PAL制式的像素宽高比差异较小,但仍需校正。因子0.8调整水平或垂直方向,确保图形比例准确。

  3. 默认情况
    返回1.0,即不进行校正(假设像素为正方形或无需调整)。

// return a correction factor used to display angles correctly
float AP_OSD_MAX7456::get_aspect_ratio_correction() const
{
    switch (_format) {
    case FORMAT_NTSC:
        return 12.0f/18.46f;

    case FORMAT_PAL:
        return 12.0f/15.0f;

    default:
        return 1.0f;
    };
}

4. 总结

AP_OSD_MAX7456类MAX7456芯片的对象(DO),通过SPI总线,将应用层在AP_OSD`处理结果发送给芯片。

5. 参考资料

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

### ArduPilotAP_MotorsUGV 类的功能和用法 #### 功能概述 `AP_MotorsUGV` 是 ArduPilot 开源飞控系统中的一个重要组件,主要用于控制无人地面车辆 (Unmanned Ground Vehicle, UGV) 的电行为。该类实现了多种功能来支持不同类型的驱动器配置以及复杂的运动模式[^1]。 具体来说,`AP_MotorsUGV` 提供了以下核心能力: - **多轮独立控制**:能够分别调整各个车轮的速度和方向。 - **PID 控制回路**:通过 PID 调节实现精确的速度跟踪与稳定运行。 - **限幅保护制**:防止过载或超出硬件安全范围的操作。 这些特性使得 `AP_MotorsUGV` 成为了开发高效、可靠的无人驾驶地面系统的基石之一。 #### 使用方法 以下是关于如何初始化并调用 `AP_MotorsUGV` 的一些基本指导: ```cpp #include <AP_Motors/AP_Motors.h> // 定义实例化对象所需的参数 const uint8_t num_motors = 4; // 假设四驱布局 float throttle_min = 0.0f; float throttle_max = 1.0f; void setup() { // 创建一个 AP_Motors 对象 AP_Motors motors(num_motors); // 初始化模块 if (!motors.init()) { Serial.println("Motor initialization failed!"); while(true); } // 设置最小最大油门值 motors.set_throttle_range(throttle_min, throttle_max); } void loop() { static float target_speed_left = 0.5f; // 左侧目标速度 static float target_speed_right = -0.3f; // 右侧反向目标速度 // 更新左侧两个马达的目标速度 motors.output_motor(0, target_speed_left); motors.output_motor(1, target_speed_left); // 更新右侧两个马达的目标速度 motors.output_motor(2, target_speed_right); motors.output_motor(3, target_speed_right); delay(10); // 防止过高频率更新影响性能 } ``` 上述代码片段展示了创建 `AP_MotorsUGV` 实例的过程及其基础操作方式。值得注意的是,在实际应用过程中还需要考虑更多细节比如传感器数据融合、路径规划算法集成等问题。 #### 注意事项 当使用此库时需要注意几个方面以确保最佳效果: - 正确校准所有连接设备如编码器等外部反馈装置; - 合理设置 PID 参数以便适应特定环境条件下的动态响应需求; - 不要忽视异常处理逻辑从而提高整个系统的鲁棒性和安全性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值