ODrive0.5.5源码分析(7) 启动时尽量让电机少转动

编者:沉尸 ([email protected])
问题
Odrive的固件,用增量式编码器,能否在开机时不要进行电机校准和旋编校准,从而提高开机速度?
答案显然是肯定的,因为ST官方的电机库就没有这样的动作!
解决思路:先进行电机校准和旋编偏移校准,然后将数据存入,重新上电时进行旋编和转子的A相对齐。

准备工作
首先从github中导出Odrive仓库到我的gitee(gitee在国内速度快些)具体导出方式可以百度…

在这里插入图片描述
然后从v0.5.5创建一个分支“cs-v0.5.5”供我自己修改使用
在这里插入图片描述
编译:

通过git版本管理后进行编译,优点是直接能够知道目前版本(比如: v0.5.5)
在这里插入图片描述

否则就会是v0.0.0 (下面图是编译本地的v0.5.1版本截图):
在这里插入图片描述
现在再来查看编译过程中自动升成的文件“version.c”
在这里插入图片描述
源代码中就直接有了版本号了。
这个的控制在哪里呢?请看文件:“tools\odrive\version.py”
在这里插入图片描述
现在开始真正处理代码:
1)增加一个状态机:
在这里插入图片描述
但是修改却不是在这里,这个是自动产生的,修改了也没用,下次编译还是会被复原,真正修改的地方是在文件:
在这里插入图片描述
再编译,就会在“interfaces.hpp”中生成:
AXIS_STATE_ENCODER_ALIGN = 14,
现在直接列出其它修改点:
1)
encoder.hpp和encoder.cpp中增加函数:
“run_encoder_align()”
在这里插入图片描述
在这里插入图片描述
下面将本函数详细贴出,函数的目的就是对齐电机A相和旋编0值。
下面的代码很大部分参考自函数:“run_offset_calibration()”

//--------------------------------------
bool Encoder::run_encoder_align() {
    
    
    const float start_lock_duration = 1.0f;

    // Require index found if enabled
    if (config_.use_index && !index_found_) {
    
    
        set_error(ERROR_INDEX_NOT_FOUND_YET);
        return false;
    }

    // 只有增量式才存在"对齐"的概念
    if (config_.mode != MODE_INCREMENTAL) {
    
    
        return true;
    }

    CRITICAL_SECTION() {
    
    
        // Reset state variables
        axis_->open_loop_controller_.Idq_setpoint_ = {
    
    0.0f, 0.0f};
        axis_->open_loop_controller_.Vdq_setpoint_ = {
    
    0.0f, 0.0f};
        axis_->open_loop_controller_.phase_ = 0.0f;
        axis_->open_loop_controller_.phase_vel_ = 0.0f;

        float max_current_ramp = axis_->motor_.config_.calibration_current / start_lock_duration * 2.0f;
        axis_->open_loop_controller_.max_current_ramp_ = max_current_ramp;
        axis_->open_loop_controller_.max_voltage_ramp_ = max_current_ramp;
        axis_->open_loop_controller_.max_phase_vel_ramp_ = INFINITY;
        axis_->open_loop_controller_.target_current_ = axis_->motor_.config_.motor_type != Motor::MOTOR_TYPE_GIMBAL ? axis_->motor_.config_.calibration_current : 0.0f;
        axis_->open_loop_controller_.target_voltage_ = axis_->motor_.config_.motor_type != Motor::MOTOR_TYPE_GIMBAL ? 0.0f : axis_->motor_.config_.calibration_current;
        axis_->open_loop_controller_.target_vel_ = 0.0f;
        axis_->open_loop_controller_.total_distance_ = 0.0f;
        axis_->open_loop_controller_.phase_ = axis_->open_loop_controller_.initial_phase_ = wrap_pm_pi(0 - config_.calib_scan_distance / 2.0f);

        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_);
    }
    axis_->wait_for_control_iteration();

    axis_->motor_.arm(&axis_->motor_.current_control_);

    // go to start position of forward scan for start_lock_duration to get ready to scan
    for (size_t i = 0; i < (size_t)(start_lock_duration * 1000.0f); ++i) {
    
    
        if (!axis_->motor_.is_armed_) {
    
    
            return false; // TODO: return "disarmed" error code
        }
        if (axis_->requested_state_ != Axis::AXIS_STATE_UNDEFINED) {
    
    
            axis_->motor_.disarm();
            return false; // TODO: return "aborted" error code
        }
        osDelay(1);
    }

    if (!axis_->motor_.is_armed_) {
    
    
        return false;
    }
    axis_->motor_.disarm();

    if (!config_.use_index) {
    
    
        set_circular_count(0, false);
        set_linear_count(0);
        shadow_count_ = count_in_cpr_;
        phase_ = 0.0f;
        phase_vel_ = 0.0f;
    }

    is_ready_ = true;
    return true;
}
//--------------------------------------

上面代码中有几行很重要,需要特别注意:

if (!config_.use_index) {
    
    
	set_circular_count(0, false);
	set_linear_count(0);
    shadow_count_ = count_in_cpr_;
}

2)针对原始函数“run_offset_calibration()”中的代码,也要进行细微修改:
在这里插入图片描述
3)最后修改“axis.cpp”中状态机的处理:
在这里插入图片描述
在这里插入图片描述
什么情况下在启动“对齐”起作用?这里要做完美,理论上也应该添加一个可存储的的变量,类似这样的名字:“config.startup_encoder_align”
然后通过app可以进行配置是否开启,如果这样的话,修改就有点大,再说odrivetool也不支持这种配置(虽然我自己写的app可以随便配置,但是不具有普遍性)。于是我这里就偷了一个懒,做了几个判断,在满足这几个条件时就自动调用“旋编对齐”,严格来说,应该是电机旋编同时对齐!

现在程序基本改完,但是还有步骤以及其它注意事项:
1)按照上面的代码修改,暂时不要用旋编的index,否则需要寻找Z相的动作
在这里插入图片描述
对于使用index,我后期也会继续修改,目前我这里实验环境有点问题(Z相的干扰很大,UVW一通电就会触发Z相的中断)
2)对于一个刚出的新板子,先进行电机校正(其实就是测量相电阻和相电感),再进行旋编offset校正,然后修改:
axis.config.startup_motor_calibration = false
axis.config.startup_encoder_offset_calibrate = false
(其它几种startup参数均设为“false”)
大概设置如下:
在这里插入图片描述
保存参数!重启,大功告成!

另外,我丢掉了“Odrivetool”,一方面odrivetool经常出故障,它的GUI版本在我电脑上也跑不起来,懒得折腾,另外也支持不了v0.5.4(v0.5.5却能支持),于是我自己用Qt写了一个参数配置工具(自己动手,一切均在掌握中):
在这里插入图片描述
在这里插入图片描述
连接的端口还是ODrvie板上的usb口,但是在pc机也会自动生成出来一个串口,通信采取ASCII协议!
在这里插入图片描述

其中的参数树,直接从源代码中抽出来进行json解析
在这里插入图片描述
在这里插入图片描述
另外可以批量设置参数:
在这里插入图片描述
针对固件v0.5.4写的也适应于v0.5.5
用串口走ASCII协议,速度肯定是没有usb的快,但是用来做参数设置辅助,毫无问题,每200ms查询一次速度和位置,连续运行,固件响应非常稳定,但是在v0.5.1上,用串口协议会导致ODrvie经常出故障停机,目前在v0.5.4和v0.5.5上测试,没出现过一次问题,看来官方将固件代码升级的较好!在v0.5.1上,为了解决问题,我甚至修改过通信的中断优先级,有一点改善,还是不行,至于新版本修改了哪些地方导致ascii协议走的无比顺溜,目前暂没空研究(好像也没必要研究了)。
另外经过测试:odrivetool 0.5.1 对接固件v0.5.4,没法连接;对接固件v0.5.5,能够连接成功。
在这里插入图片描述
看样子网传ODrive后面会走上“闭源”道路并无道理,并且可以看到它已经准备用stm32f722配套硬件版本v4.x了
这个从v0.5.5项目中“.vscode\launch.json”文件可以看到:

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/danger/article/details/128101089