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

embedded/2024/9/22 12:26:44/

系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 一、端口处理
  • 二、在Encoder中引入新的类型
    • 1.增加485类型
    • 2.增加串口的初始化操作
    • 3.数据处理
  • 总结


前言

尝试在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 == 4uint16_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 behaviorGPIO_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: 0x100doc: Compatible with CUI AMT23xxSPI_ABS_AMS:value: 0x101doc: Compatible with AMS AS5047P, AS5048A/AS5048B (no daisy chain support)SPI_ABS_AEAT:value: 0x102doc: Supports AEAT-8800SPI_ABS_RLS:value: 0x103doc: Supports RLS Orbis EncodersSPI_ABS_MA732:value: 0x104doc: MagAlpha MA732 magnetic encoderU485_SRMA34:value: 0x400doc: SRMA34-M16S17Bit-SY-C-5V encoder

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

class Encoder : public ODriveIntf::EncoderIntf {
public:static constexpr uint32_t MODE_FLAG_ABS = 0x100;// 0717static 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 USART2struct 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里面增加初始化操作

    //0717if (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 yetif (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 handleif (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 0912get_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_; //LATCHdelta_enc = mod(delta_enc, config_.cpr);if (delta_enc > config_.cpr/2) {delta_enc -= config_.cpr;}} break;

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

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


总结

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


http://www.ppmy.cn/embedded/113489.html

相关文章

JavaSE - 面向对象编程03

01 多态 01_01 认识多态 01_02 多态的好处和缺点 【1】好处&#xff1a;① 可以解耦合&#xff0c;扩展性更强&#xff0c;父类引用指向的子类对象可以随时切换&#xff0c;而后面的逻辑代码并不需要更改。 ② 使用父类引用可以作为方法的形参或返回类型来接收一切子类对象。…

CTFHub技能树-信息泄露-HG泄漏

目录 漏洞产生原因 解题过程 当开发人员使用 Mercurial 进行版本控制&#xff0c;对站点自动部署。如果配置不当,可能会将.hg 文件夹直接部署到线上环境。这就引起了 hg 泄露漏洞。 漏洞产生原因 Mercurial(hg)是一种分布式版本控制系统&#xff0c;它与Git类似也可以用于管…

微信小程序使用 ==== 粘性布局

目录 Chrome杀了个回马枪 position:sticky简介 你可能不知道的position:sticky 深入理解粘性定位的计算规则 粘性定位其他特征 代码实现 微信小程序在scroll-view中使用sticky Chrome杀了个回马枪 position:sticky早有耳闻也有所了解&#xff0c;后来&#xff0c;Chro…

Redis 配置

一、关系型数据库与非关系型数据库 1. 关系型数据库 关系型数据库是一种结构化数据库&#xff0c;基于关系模型&#xff08;二维表格模型&#xff09;&#xff0c;适合记录数据。通过 SQL&#xff08;结构化查询语言&#xff09;进行数据的检索和操作。主流的关系型数据库包括…

力扣每日一题:1372.二叉树中的最长交错路径

题目 给你一棵以 root 为根的二叉树&#xff0c;二叉树中的交错路径定义如下&#xff1a; 选择二叉树中 任意 节点和一个方向&#xff08;左或者右&#xff09;。如果前进方向为右&#xff0c;那么移动到当前节点的的右子节点&#xff0c;否则移动到它的左子节点。改变前进方…

【LLM多模态】CogVideoX文生视频模型结构和训练过程

note 通过两阶段训练3D VAE&#xff0c;对视频进行压缩编码 第一阶段&#xff1a;在较低分辨率和较少帧数的视频上进行训练&#xff0c;学习压缩和重建视频的基本能力第二阶段&#xff1a;在更长的视频上训练&#xff0c;提高模型处理长视频的能力&#xff0c;同时保持帧与帧之…

SAP学习笔记 - 开发06 - CDSView + Fiori Element 之 List Report

上一章讲了Fiori UI5开发环境搭建和实践&#xff1a; - VSCode 安装Fiori Tools插件 - SEGW 创建后台程序&#xff0c;注册服务&#xff0c;Gateway Client确认服务 - 使用SEGW公开的服务来查询数据显示到页面 SAP学习笔记 - 开发05 - Fiori UI5 开发环境搭建2 Fiori Tools…

Vue的路由守卫与Store

路由守卫 全局路由守卫 router.beforeEach((to, from, next) > {console.log("去哪:", to, "那来&#xff1a;", from);// sessionStorage.getItem()//是否运行放行next(); }) //后置路由守卫 router.afterEach((to, from)>{console.log("后置…