Odrive源码分析(三) 数据结构

      Odrive内部存在一些非常好的设计,为了通篇掌握Odrive的设计理念和算法,对项目中采用的设计模式,数据结构和算法必须了解,本文梳理下Odrive中涉及到的一些重要的数据结构。

1. ComponentBase

所有支持update回调的类基类,支持传入一个时间戳用于实时更新对象内部状态。

class ComponentBase {
public:virtual void update(uint32_t timestamp) = 0;
};

子类有:

开环控制器类:OpenLoopController

FOC控制器类:FieldOrientedController

2. InputPort和OutputPort模板类

这两个类非常重要,是Odrive为了解耦各对象之间交互的桥梁,可以简化理解为两个对象之间通讯的中间件(只是类比),有了这个设计,模块可以很方便的连接外部输入源,还能管理输入源的生命周期。

template<typename T>
class OutputPort {
public:OutputPort(T val) : content_(val) {}void operator=(T value) {//关联数据content_ = value;age_ = 0;}void reset() {//强制让数据过期age_++;}std::optional<T> present() {//正值"壮年",数据是刚刚更新有效if (age_ == 0) {return content_;} else {return std::nullopt;}}std::optional<T> previous() {//上一个周期的数据if (age_ == 1) {return content_;} else {return std::nullopt;}}std::optional<T> any() {return content_;}private:uint32_t age_ = 2; T content_;
};template<typename T>
class InputPort {
public://将输入关联到特定的输入源--模板包装void connect_to(OutputPort<T>* input_port) {content_ = input_port;}//将输入关联到特定的输入源-原始指针void connect_to(T* input_ptr) {content_ = input_ptr;}//断开数据源void disconnect() {content_ = (OutputPort<T>*)nullptr;}//更新数据,实际上是获取的输入源数据std::optional<T> present() {if (content_.index() == 2) {OutputPort<T>* ptr = std::get<2>(content_);return ptr ? ptr->present() : std::nullopt;} else if (content_.index() == 1) {T* ptr = std::get<1>(content_);return ptr ? std::make_optional(*ptr) : std::nullopt;} else {return std::get<0>(content_);}}std::optional<T> any() {if (content_.index() == 2) {OutputPort<T>* ptr = std::get<2>(content_);return ptr ? ptr->any() : std::nullopt;} else if (content_.index() == 1) {T* ptr = std::get<1>(content_);return ptr ? std::make_optional(*ptr) : std::nullopt;} else {return std::get<0>(content_);}}private:std::variant<T, T*, OutputPort<T>*> content_;
};

这两个类在很对地方都有用到,比如下面的代码就是把FOC控制的输入源关联到开关控制器的输出中:

axis_->motor_.current_control_.enable_current_control_src_ = (axis_->motor_.config_.motor_type != Motor::MOTOR_TYPE_GIMBAL);
axis_>motor_.current_control_.Idq_setpoint_src_.connect_to(&axis_>open_loop_controller_.Idq_setpoint_);
axis_->motor_.current_control_.Vdq_setpoint_src_.connect_to(&axis_->open_loop_controller_.Vdq_setpoint_);axis_->motor_.current_control_.phase_src_.connect_to(&axis_->open_loop_controller_.phase_);
axis_->acim_estimator_.rotor_phase_src_.connect_to(&axis_->open_loop_controller_.phase_);axis_->motor_.phase_vel_src_.connect_to(&axis_->open_loop_controller_.phase_vel_);
axis_->motor_.current_control_.phase_vel_src_.connect_to(&axis_->open_loop_controller_.phase_vel_);
axis_->acim_estimator_.rotor_phase_vel_src_.connect_to(&axis_->open_loop_controller_.phase_vel_);

再比如下面代码将编码器的输出关联到控制器的相关输入上

controller_.pos_estimate_circular_src_.connect_to(&ax->encoder_.pos_circular_);
controller_.pos_estimate_linear_src_.connect_to(&ax->encoder_.pos_estimate_);
controller_.vel_estimate_src_.connect_to(&ax->encoder_.vel_estimate_);
3. Timer类,用于做相关计时
template <class T>
class Timer {public:void setTimeout(const T timeout) {timeout_ = timeout;}void setIncrement(const T increment) {increment_ = increment;}void start() {running_ = true;}void stop() {running_ = false;}// If the timer is started, increment the timervoid update() {if (running_)timer_ = std::min<T>(timer_ + increment_, timeout_);}void reset() {timer_ = static_cast<T>(0);}bool expired() {return timer_ >= timeout_;}private:T timer_ = static_cast<T>(0);     // Current stateT timeout_ = static_cast<T>(0);   // Time to countT increment_ = static_cast<T>(0);  // Amount to increment each time update() is calledbool running_ = false;            // update() only increments if runing_ is true
};

这个类配合下面的类和宏可以测量任意代码块的执行时间:

struct TaskTimerContext {TaskTimerContext(const TaskTimerContext&) = delete;TaskTimerContext(const TaskTimerContext&&) = delete;void operator=(const TaskTimerContext&) = delete;void operator=(const TaskTimerContext&&) = delete;TaskTimerContext(TaskTimer& timer) : timer_(timer), start_time(timer.start()) {}~TaskTimerContext() { timer_.stop(start_time); }TaskTimer& timer_;uint32_t start_time;bool exit_ = false;
};#define MEASURE_TIME(timer) for (TaskTimerContext __task_timer_ctx{timer}; !__task_timer_ctx.exit_; __task_timer_ctx.exit_ = true)

比如下面的代码就是测量热敏电阻算法更新的耗时:

MEASURE_TIME(axis.task_times_.thermistor_update) {axis.motor_.fet_thermistor_.update();axis.motor_.motor_thermistor_.update();
}
4. Endpoint。用于对输入信号的极性检测进行封装

该类处理GPIO的输入状态进行拦截,同时考虑抖动的处理。

class Endstop {public:struct Config_t {float offset = 0;uint32_t debounce_ms = 50;uint16_t gpio_num = 0;bool enabled = false;bool is_active_high = false;// custom settersEndstop* parent = nullptr;void set_gpio_num(uint16_t value) { gpio_num = value; parent->apply_config(); }void set_enabled(uint32_t value) { enabled = value; parent->apply_config(); }void set_debounce_ms(uint32_t value) { debounce_ms = value; parent->apply_config(); }};Endstop::Config_t config_;Axis* axis_ = nullptr;bool apply_config();void update();constexpr bool get_state(){return endstop_state_;}constexpr bool rose(){return (endstop_state_ != last_state_) && endstop_state_;}constexpr bool fell(){return (endstop_state_ != last_state_) && !endstop_state_;}bool endstop_state_ = false;private:bool last_state_ = false;bool pin_state_ = false;float pos_when_pressed_ = 0.0f;Timer<float> debounceTimer_;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/12160.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录刷题记录(二十七)——55. 右旋字符串

&#xff08;一&#xff09;问题描述 55. 右旋字符串&#xff08;第八期模拟笔试&#xff09;https://kamacoder.com/problempage.php?pid1065字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k&#xff0c;请编写一个函数&…

FreeRTOS 24:事件组EventGroup等待、清零、获取操作

等待事件标志位xEventGroupWaitBits() 既然标记了事件的发生&#xff0c;那么我怎么知道他到底有没有发生&#xff0c;这也是需要一个函数来获 取 事 件 是 否 已 经 发 生 &#xff0c; FreeRTOS 提 供 了 一 个 等 待 指 定 事 件 的 函 数 — — xEventGroupWaitBits()&…

信息安全数学基础(47)域的结构

一、域的定义 设F为一个非空集合&#xff0c;在其上定义两种运算&#xff1a;加法和乘法。如果这两种运算在集合上封闭&#xff0c;且满足以下条件&#xff0c;则称F对于规定的乘法和加法构成一个域&#xff1a; F中所有元素对于加法形成加法交换群&#xff0c;即加法满足交换律…

#渗透测试#SRC漏洞挖掘#CSRF漏洞的防御

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

HarmonyOS 沉浸式状态实现的多种方式

1. HarmonyOS 沉浸式状态实现的多种方式 HarmonyOS 沉浸式状态实现的多种方式 1.1. 方法一 1.1.1. 实现讲解 &#xff08;1&#xff09;首先设置setWindowLayoutFullScreen(true)&#xff08;设置全屏布局&#xff09;。   布局将从屏幕最顶部开始到最底部结束&#xff0c…

在API接口数据获取过程中,如何确保数据的安全性和隐私性?

在API接口数据获取过程中&#xff0c;确保数据的安全性和隐私性至关重要。以下是一些关键措施&#xff0c;可以帮助开发者和管理者保护API接口的数据安全和隐私性&#xff1a; 身份认证和授权 身份认证&#xff1a;确认用户身份的过程&#xff0c;常用的身份认证方式包括用户…

C++常用的特性-->day05

友元的拓展语法 声明一个类为另外一个类的友元时&#xff0c;不再需要使用class关键字&#xff0c;并且还可以使用类的别名&#xff08;使用 typedef 或者 using 定义&#xff09;。 #include <iostream> using namespace std;// 类声明 class Tom; // 定义别名 using …

python-27-Python ORM系列之彻底搞明白ORM概念,对ORM进行封装结合FastAPI实现数据库的增删改查,联表查询等接口

python-27-Python ORM系列之彻底搞明白ORM概念&#xff0c;对ORM进行封装结合FastAPI实现数据库的增删改查&#xff0c;联表查询等接口 一.简介 在Python基础系列ORM部分为大家介绍了如何搭建MySQL数据和MySQL一些访问配置&#xff0c;同时也介绍了pymysql库的封装来实现对数…

从哈佛哲学系到蛋白质设计大师,David Baker:AlphaFold令我深刻认识到深度学习的力量

要说谁是引领蛋白质设计的世界级大师&#xff0c;美国华盛顿大学的 David Baker 教授可谓是当之无愧&#xff0c;作为该领域的顶级专家&#xff0c;Baker 在蛋白质方向发表研究论文 700 余篇&#xff0c;引用量累计超 17.7 万。今年 10 月&#xff0c;因其在蛋白质设计方面的卓…

【测试框架篇】单元测试框架pytest(2):用例编写

一、 前言 前面一章我们介绍了pytest环境安装和配置&#xff0c;并在pycharm里面实现了我们第一个pytest脚本。但是有些童鞋可能在编写脚本的时候遇到了问题&#xff0c;本文会讲一下我们编写pytest用例时需要遵守哪些既定的规则&#xff0c;同时这个规则也是可以修改的。 二…

实现LiDAR和多视角摄像头数据的对齐、可控X-DRIVE:用于驾驶场景的跨模态一致多传感器数据合成

Abstract 近年来&#xff0c;扩散模型在合成驾驶场景中的LiDAR点云或摄像头图像数据方面取得了进展。尽管这些模型在单一模态数据的边际分布建模方面取得成功&#xff0c;但对不同模态之间互相依赖关系的探索仍然不足&#xff0c;而这种依赖关系能够更好地描述复杂的驾驶场景。…

稳恒磁场(1)

物理概念 磁场是物质性的。 地磁场&#xff08;与地磁场正负极相反&#xff09;与磁偏角&#xff08;一般为0到11度&#xff09; 磁感应强度&#xff1a; 单位为特斯拉&#xff08;T&#xff09;&#xff0c;另一个常用单位是高斯&#xff08;G&#xff09;且1T 10^4 G 物…

自动驾驶系列—自动驾驶中的短距离感知:超声波雷达的核心技术与场景应用

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

多语言爬取淘宝价格信息 python 比价api接入指南

以下是爬取淘宝价格信息及接入淘宝比价 API 的一般步骤&#xff1a; 传统爬虫方式获取价格信息&#xff08;不建议大量使用&#xff0c;可能违反淘宝规定&#xff09;&#xff1a; 分析目标页面 URL&#xff1a;在淘宝搜索框输入关键词后&#xff0c;观察页面的 URL 结构。例如…

Java List——针对实习面试

目录 Java ListJava List的三种主要实现是什么&#xff1f;它们各自的特点是什么&#xff1f;Java List和Array&#xff08;数组&#xff09;的区别&#xff1f;Java List和Set有什么区别&#xff1f;ArrayList和Vector有什么区别&#xff1f;什么是LinkedList&#xff1f;它与…

如何在Linux系统中安装微信

官方版微信的安装 好消息是&#xff0c;现在微信已经发布了官方的Linux版本&#xff0c;大家可以直接通过官方网站下载并安装&#xff0c;避免了以前繁琐的第三方工具安装步骤。 1.1 下载官方版微信 微信&#xff0c;是一个生活方式 选择Linux-> X86 1.2 安装微信 提前…

java双向链表解析实现双向链表的创建含代码

双向链表 一.双向链表二.创建MyListCode类实现双向链表创建一.AddFirst创建&#xff08;头插法&#xff09;二.AddLast创建&#xff08;尾叉法&#xff09;三.size四.remove(指定任意节点的首位删除)五.removeAll(包含任意属性值的所有删除)六.AddIndex(给任意位置添加一个节点…

hhdb数据库介绍(2-2)

数据高可用服务 HHDB Server在计算节点、数据节点、配置库等层次提供全面的高可用保障。提供完善的心跳检测、故障切换对存储节点同步追平判断、全局自增序列在故障时自动跳号、客户端连接Hold等机制&#xff0c;保障数据服务的可用性与数据的一致性。 计算节点服务高可用 H…

精挑细选的100道软测高频面试题,面试前你肯定用得上

测试技术面试题 1、什么是兼容性测试&#xff1f;兼容性测试侧重哪些方面&#xff1f; 2、我现在有个程序&#xff0c;发现在 Windows 上运行得很慢&#xff0c;怎么判别是程序存在问题还是软硬件系统存在问题&#xff1f; 3、测试的策略有哪些&#xff1f; 4、正交表测试用…

STM32获取SHT3X温湿度芯片数据

目录 一、概述 二、单次数据采集模式的测量 1、配置说明 2、代码实现方式 三、周期性数据采集模式的测量 1、配置说明 2、代码实现方式 四、完整代码下载链接 一、概述 SHT3X是Sensirion公司推出的一款高精度、完全校准的温湿度传感器&#xff0c;基于CMOSens技术。它提…