ODrive学习——添加485编码器支持

系列文章目录



前言

尝试在ODrive中添加485型的编码器的支持


一、端口处理

计划使用PA2及PA3作为485通信的端口。这样首先要把外部温度传感器的I/O口给改掉。
找到外部温度传感器配置初始化的地方改掉,改成GPIO5,也就是PC4。

class OffboardThermistorCurrentLimiter : public ThermistorCurrentLimiter, public ODriveIntf::OffboardThermistorCurrentLimiterIntf {
public:
    static const size_t num_coeffs_ = 4;

    struct Config_t {
        float thermistor_poly_coeffs[num_coeffs_];

        //0716 Change GPIO PIN TO 5  PC4
#if HW_VERSION_MAJOR == 3
        //uint16_t gpio_pin = 4;
        uint16_t gpio_pin = 5;
#elif HW_VERSION_MAJOR == 4
        uint16_t gpio_pin = 2;
#endif

串口2 默认打开配置

            case ODriveIntf::GPIO_MODE_UART_B: {
                GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
                GPIO_InitStruct.Pull = (i == 0) ? GPIO_PULLDOWN : GPIO_PULLUP; // this is probably swapped but imitates old behavior
                GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
                //if (!odrv.config_.enable_uart_b) {
                    odrv.misconfigured_ = true;
               // }

此外还需要进行I/O的配置,485使用串口的配置。如果想保持原风格的话,需要添加对应枚举类型,在原有的初始化硬件体系下进行。也可以自己定义一个I/O及外设初始化的函数,在所有外设初始化完成以后调用。

二、在Encoder中引入新的类型

1.增加485类型

Encoder的类型是工程通过Odrive-interface.yaml生成的。包括其他的一些枚举类型,所以从工程里直接去链接类型定义是找不到的。


  ODrive.Encoder.Mode:
    values:
      INCREMENTAL:
      HALL:
      SINCOS:
      SPI_ABS_CUI:
        value: 0x100
        doc: Compatible with CUI AMT23xx
      SPI_ABS_AMS:
        value: 0x101
        doc: Compatible with AMS AS5047P, AS5048A/AS5048B (no daisy chain support)
      SPI_ABS_AEAT:
        value: 0x102
        doc: Supports AEAT-8800
      SPI_ABS_RLS:
        value: 0x103
        doc: Supports RLS Orbis Encoders
      SPI_ABS_MA732:
        value: 0x104
        doc: MagAlpha MA732 magnetic encoder
      U485_SRMA34:
        value: 0x400
        doc: SRMA34-M16S17Bit-SY-C-5V encoder

这里增加一个U485_SRMA34的类型,注意开头不要数字开头,编译会有错误。

class Encoder : public ODriveIntf::EncoderIntf {
public:
    static constexpr uint32_t MODE_FLAG_ABS = 0x100;
    // 0717
    static constexpr uint32_t MODE_FLAG_SRMA = 1024;


    static constexpr std::array<float, 6> hall_edge_defaults = 
        {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f};

    struct Config_t {
        //0717 
        Mode mode = MODE_U485_SRMA34; 
        //Mode mode = MODE_INCREMENTAL;

在Encoder类型中,把对应的编码器类型给修改一下。

2.增加串口的初始化操作

这部分可以从系统串口初始化那边扒下来,直接启用串口2。
但是0.5.6版本不支持双串口同时使用,所以不能直接在odrive_main.h中启用uart_b。
所以还是再重新定义一个新的变量和新的处理任务。
这样的话永远不要再用原来的使能来启用uart_b了。

UART_HandleTypeDef* uart_a = &huart4;
UART_HandleTypeDef* uart_b = &huart2; // TODO: this could be supported in ODrive v3.6 (or similar) using STM32's USART2
UART_HandleTypeDef* uart_c = nullptr;
UART_HandleTypeDef* uart_485_a = &huart2; // TODO: this could be supported in ODrive v3.6 (or similar) using STM32's USART2


struct BoardConfig_t {
    ODriveIntf::GpioMode gpio_modes[GPIO_COUNT] = {
        DEFAULT_GPIO_MODES
    };

    bool enable_uart_a = true;
    bool enable_uart_b = false;
    bool enable_uart_c = false;

    bool enable_uart_485_a = true;
    uint32_t uart_485_a_baudrate = 115200;

    uint32_t uart_a_baudrate = 115200;
    uint32_t uart_b_baudrate = 115200;
    uint32_t uart_c_baudrate = 115200;

做戏也做全套,新增一个uart_485_a的变量,也指向huart2。这样后面不再引用uart_b的变量了。
在 boardInit里面增加初始化操作

    //0717
    if (odrv.config_.enable_uart_485_a) {
        uart_485_a->Init.BaudRate = odrv.config_.uart_485_a_baudrate;
        MX_USART2_UART_Init();
    }

当然这样只是初始化完成了外设。还需要把数据处理和数据关联加上。

波特率根据自己用的编码器外设来配置哦。

3.数据处理

在对应的头文件中,添加这些接口的说明。

在main函数的inti_communication函数中,调用此函数。

void init_communication(void) {
    //printf("hi!\r\n");

    // Dual UART operation not supported yet
    if (odrv.config_.enable_uart_a && odrv.config_.enable_uart_b) {
        odrv.misconfigured_ = true;
    }

    if (odrv.config_.enable_uart_a && uart_a) {
        start_uart_server(uart_a);
    } else if (odrv.config_.enable_uart_b && uart_b) {
        start_uart_server(uart_b);
    }
    // 0903 start 485 data handle
    if (odrv.config_.enable_uart_485_a && uart_485_a) {
        start_u485_server(uart_485_a);
    }

之后我们再完善 这个处理数据的任务。先进入到编码器定时采集的接口,sample_now,添加上我们的485编码器类别,。
获取数据的方式还是用DMA的方式,在回调中处理数据到相应的变量。
试了几种方法都不太行,不知道是不是HAL库内部配置的太多了。这样倒是也省了一些额外的任务开支。

        case MODE_U485_SRMA34:
        {
            // Send 485 order to Encoder
              // Send 485 order to Encoder 0912
            get_gpio(6).write(true);
            HAL_UART_AbortReceive(&huart2);
            HAL_UART_Receive_DMA(&huart2, u485_rx_buffer, 6);
            ucTemp = 0x02;
            HAL_UART_Transmit(&huart2, &ucTemp, 1, 10);
            get_gpio(6).write(false);
        }
        break;

再来回想一下,SPI类型的编码器的处理,在其回调中得到一个位置的绝对值,并传递给pos_abs_参数。
数据的处理,可以放到Task任务中去,结合串口中断来实现。
所以直接在Update中来继续剩下的部分。

        case MODE_U485_SRMA34:{

            abs_485_pos_updated_ = false;
            delta_enc = pos_abs_latched - count_in_cpr_; //LATCH
            delta_enc = mod(delta_enc, config_.cpr);
            if (delta_enc > config_.cpr/2) {
                delta_enc -= config_.cpr;
            }
        } break;

关于这套计算的逻辑,需要参考SPI 编码器的参数进行参考。

临时先弄这些。目前只是获取到了编码器的数值,这一套到底能不能运行起来待测试。


总结

提示:这里对文章进行总结:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奔跑的Lunzi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值