站点信息
文章数目:
65 篇
最近动态:
今天
上线时间:
348天
当前版本:
v1.0.0
odrive固件代码学习1 我的天哪cpp大人
分类:
日期:2025-09-11 11:18:15
为什么学odrive
- 本来美美临摹vesc代码,使用自己熟悉的工具写一个精简功能的foc控制器,结果写到电机参数辨识这部分,vesc的实现方法太晦涩了,涉及hfi。这就意味着我要研究透其参数辨识部分,需要先研究其hfi部分,问题是我已经为了其无感部分来研究参数辨识部分了。这样下去没个头,于是灵机一动,想着来参考一下odrive的代码吧。
- 简单看了一下odrive,固件是用cpp写的,其运行逻辑和结构使我耳目一新。我越发觉得不应该只参考它的参数辨识部分,而是要博观约取,将更多部分融入进我的控制器代码中。
预期学习目标
- 看懂总体上控制器从头到尾的运行逻辑;
- 能够逐句解释一些关键模块(pwm生成,adc采样,主体foc计算,电机参数辨识)的代码,搞懂代码背后的数学物理原理;
谁懂看cpp代码茅塞顿开的救赎感
- clone固件库,在此处用vscode打开,这一看啥玩意,全是是cpp,好在它的main.cpp藏得不深,打开以后立马被一连串结构体、类、域定义整花眼了,叽里咕噜说什么呢。
- 与copilot劳斯深入交流,才知道如下事实:
- 域是区分同名变量和函数的好方法;
- 结构体里也可以定义函数,成员;
- 结构体还可以有父类和子类的继承;
- 结构体里定义的函数分三种,
private,protected和public,分别代表:
- 子类不可继承,外界无法访问的函数
- 子类可以继承,外界无法访问的函数
- 外界可以访问的函数,不过访问的时候要带上域
- 父结构体中定义的函数前面有一个virtual,表示这是虚函数,子类可以重写这个函数
- 函数传入参数列表中如果见到
std::optional<float> 某变量这种表达,则表示这个变量在传入时可以是空值,用的时候只要使用某变量.has_value()来辨析就好。可以传入空值,暗示可以用同一个函数模板兼容不同的功能,老子传给儿子的时候就没那么麻烦
- 我也是时候学学面向对象编程了
粗略观察得到odrive大概结构
- 操作系统使用的是freertos
- main函数进行初始化,先是硬件初始化,然后创建了一个main线程,最后是操作系统初始化
- 刚进入操作系统时只有main线程,其中再次进行初始化:按照分组创建一系列线程,分组的核心是axis,据我所知和vesc里的motor1,motor2差不多,也就是说将一个电机系统视为axis,围绕这个axis开启一系列线程来启动电机控制。所有线程创建好以后,main线程删除自己。
- 每一个axis的底层线程一直在运行,大概是电流控制和采样的部分。顶层要运行什么功能,就给axis”绑定“(arm)某一个结构体。例如如果顶层要执行电机整定,则运行相关函数进入中间层,函数会给axis绑定电机整定相关结构体,结构体中定义了要进行电机整定,底层所需的变量和要执行的函数。在绑定期间,底层自动执行操作,中间层获取数据进行计算,计算结束后结构体解绑(disarm),中间层返回上层需要的数据。
- 整个过程中底层自动运行,中间层不干涉底层,顶层不干涉中间层,流程很干净。相比vesc,虽然代码量更大,分布零散,但是确实结构清晰,能够方便区分各层,以及使用f12溯源。即使目前我的工程不用cpp,最后顶层和中间层的关系也应该尽量向这种模式靠拢。