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 timer
    void 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 state
    T timeout_ = static_cast<T>(0);   // Time to count
    T increment_ = static_cast<T>(0);  // Amount to increment each time update() is called
    bool 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 setters
        Endstop* 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_;
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙HarmonyOS 网络请求获取数据Http

注意的是;要为接口返回值指定类型 &#xff0c;以及定义接口数据类型 index.ets import { http } from kit.NetworkKit;interface createAtType {date: number,}interface dataListType {createAt: createAtType;imgUrl: }Component export default struct TabBar {State dat…

Windows VSCode .NET CORE WebAPI Debug配置

1.安装C#插件 全名C# for Visual Studio Code&#xff0c;选择微软的 2. 安装C# Dev Kit插件 全名C# Dev Kit for Visual Studio Code&#xff0c;同样是选择微软的 3.安装Debugger for Unity 4.配置launch.json 文件 {"version": "0.2.0","config…

Odoo:免费开源的流程制造行业ERP管理系统

概述 聚焦流程制造连续性生产的特性&#xff0c;提供集成PLMERPMESBI的一体化解决方案&#xff0c;涵盖计划、生产、质量、配方、供销、库存、成本、设备、资金管理等业务领域的整体性解决方案 行业的最新洞察&行业典型痛点 一、生产过程需要精细化控制 需要在各种制约…

ERP管理系统(源码+文档+部署+讲解)

本文将深入解析“ERP管理系统”的项目&#xff0c;探究其架构、功能以及技术栈&#xff0c;并分享获取完整源码的途径。 系统概述 ERP管理系统是一款全面的资源规划软件&#xff0c;旨在通过集成各种业务流程和功能模块来提高管理效率和决策质量。该系统覆盖了从基础设置、供…

mysql每日一题(上升的温度,date数据的计算)

日期之间的运算 日期类型的加法运算 data_add(now_data,interval 1 month) select date_add(now(), interval 1 day); -- 加1天 select date_add(now(), interval 1 hour); -- 加1小时 select date_add(now(), interval 1 minute); -- 加1分钟 select date_add(now(), inter…

CTF攻防世界小白刷题自学笔记13

1.fileinclude,难度&#xff1a;1,方向&#xff1a;Web 题目来源:宜兴网信办 题目描述:无 给一下题目链接&#xff1a;攻防世界Web方向新手模式第16题。 打开一看给了很多提示&#xff0c;什么language在index.php的第九行&#xff0c;flag在flag.php中&#xff0c;但事情显…

FFmpeg 4.3 音视频-多路H265监控录放C++开发十三.2:avpacket中包含多个 NALU如何解析头部分析

前提&#xff1a; 注意的是&#xff1a;我们这里是从avframe转换成avpacket 后&#xff0c;从avpacket中查看NALU。 在实际开发中&#xff0c;我们有可能是从摄像头中拿到 RGB 或者 PCM&#xff0c;然后将pcm打包成avframe&#xff0c;然后将avframe转换成avpacket&#xff0…

LabVIEW环境监测系统

随着环境问题的日益严重&#xff0c;环境参数的实时监测成为保障公共健康和生态平衡的重要手段。开发了一款基于LabVIEW开发的环境监测系统&#xff0c;能够对大气中的温度、湿度及二氧化硫浓度进行实时监测&#xff0c;并提供数据存储和超阈值报警功能。 系统组成 本系统由下…

【视觉SLAM】2-三维空间刚体运动的数学表示

读书笔记&#xff1a;学习空间变换的三种数学表达形式。 文章目录 1. 旋转矩阵1.1 向量运算1.2 坐标系空间变换1.3 变换矩阵与齐次坐标 2. 旋转向量和欧拉角2.1 旋转向量2.2 欧拉角 3. 四元数 1. 旋转矩阵 1.1 向量运算 对于三维空间中的两个向量 a , b ∈ R 3 a,b \in \R^3 …

SystemVerilog学习笔记(十):进程/细粒度进程控制

进程 进程或线程是作为独立实体执行的任何代码片段。fork-join块创建并行运行的不同线程。在下面的图-1中&#xff0c;可以看到进程的类型和进程控制。 序号进程描述1.fork-join只有所有子线程执行完毕时&#xff0c;父线程才会执行。2.fork-join_any只有任何一个子线程执行完…

【Visual Studio系列教程】如何在 VS 上编程?

上一篇博客中&#xff0c;我们介绍了《什么是 Visual Studio&#xff1f;》。本文&#xff0c;我们来看第2篇《如何在 VS 上编程&#xff1f;》。阅读本文大约10 分钟。我们会向文件中添加代码&#xff0c;了解 Visual Studio 编写、导航和了解代码的简便方法。 本文假定&…

【3D Slicer】的小白入门使用指南八

3D Slicer DMRI(Diffusion MRI)-扩散磁共振认识和使用 0、简介 大脑解剖 ● 白质约占大脑的 45% ● 有髓神经纤维(大约10微米轴突直径) 白质探索 朱尔斯约瑟夫德杰林(Jules Joseph Dejerine,《神经中心解剖学》(巴黎,1890-1901):基于髓磷脂染色标本的神经解剖图谱)…

GraphPad Prism与鹰谷电子实验记录本强强联合,数据兼容互通

在科研探索的征途上&#xff0c;每一次数据的记录与分析都至关重要。鹰谷很高兴地宣布&#xff0c;鹰谷电子实验记录本InELN&#xff0c;与国际知名生物数据统计分析GraphPad Prism软件&#xff0c;实现数据快速兼容互通&#xff01;使用鹰谷电子实验记录本的用户&#xff0c;将…

HarmonyOS的@State装饰器的底层实现

HarmonyOS的State装饰器的底层实现 序言准备工作实现State装饰器 序言 ArkTS是鸿蒙生态的应用开发语言。它在保持TypeScript&#xff08;简称TS&#xff09;基本语法风格的基础上&#xff0c;进一步通过规范强化静态检查和分析&#xff0c;使得在程序运行之前的开发期能检测更…

实战:深入探讨 MySQL 和 SQL Server 全文索引的使用及其弊端

在数据库中处理大量文本数据时,包含搜索(例如查找包含特定单词的文本)往往是必需的。然而,直接使用 LIKE %text% 的方式在大数据量中进行模糊查询会造成性能瓶颈。为了解决这一问题,MySQL 和 SQL Server 提供了全文索引(Full-Text Indexing)功能,可以显著加速文本数据的…

shell 100例

1、每天写一个文件 (题目要求&#xff09; 请按照这样的日期格式(xxxx-xx-xx每日生成一个文件 例如生成的文件为2017-12-20.log&#xff0c;并且把磁盘的使用情况写到到这个文件中不用考虑cron&#xff0c;仅仅写脚本即可 [核心要点] date命令用法 df命令 知识补充&#xff1…

网络管理之---3种网络模式配置

目标&#xff1a; 了解几个概念&#xff1a; 1.什么是IP&#xff1f;什么是IP地址&#xff1f; 2.什么是桥接、NAT、仅主机模式 3.端口&#xff1f; 4.什么是网络接口命名规则 5.网络管理器 IP&#xff1a;指网络之间互联的协议&#xff0c;是TCP/IP 体系中的网络协议 I…

ubuntu 下mosquitto TLS配置

1、/etc/mosquitto/mosquitto.conf文件配置 persistence true persistence_location /var/lib/mosquitto/ log_dest file /var/log/mosquitto/mosquitto.log include_dir /etc/mosquitto/conf.d listener 1883 listener 8883 0.0.0.0 password_file /etc/mosquitto/pwfile cert…

zabbix搭建钉钉告警流程

目录 &#x1f324;️zabbix实验规划 &#x1f324;️zabbix实验步骤 &#x1f4d1;1 使用钉钉添加一个自定义的机器人 ​ &#x1f4d1;2在zabbix-server上编写钉钉信息发送脚本&#xff0c;设置钉钉报警媒介 ☁️ 设置钉钉报警媒介​编辑​编辑 ☁️在添加消息模板​编辑​…

【JavaWeb】JavaWeb入门之XML详解

目录 1.XML介绍 1.1.XML概述 1.1.1.什么是XML 1.1.2.XML的作用 1.1.3.XML与HTML的比较 1.1.4.XML和properties&#xff08;属性文件&#xff09;比较 1.1.5.W3C组织 1.2.XML语法概述 1.2.1.XML文档展示 1.2.2.XML文档的组成部分 1.3.XML文档声明 1.3.1.什么是XML文…