跳转至

摩擦轮模块使用说明

1 前言

摩擦轮组件的代码架构和拨弹盘组件基本一致,不再赘述。

若对功能模块组件的代码架构存在疑问,建议结合源码阅读拨弹盘使用说明

当前摩擦轮组件为基本版,仅有同级两个电机。

对于多级摩擦轮发射机构,每一级只有两个电机的情况,可以分别将每一级注册为独立的摩擦轮模块。

2 配置说明

摩擦轮所需配置参数如下

C++
struct FricConfig2Motor {
  float default_spd_ref;                     // 摩擦轮期望速度预设值, >0, 无默认值, rad/s
  float default_spd_ref_backward = -100.0f;  // 摩擦轮反转目标速度, <0, 默认值 -100 rad/s, 反转模式是为了将卡在摩擦轮中间的弹丸回退出来,转速不易过快
  float stuck_curr_thre = 14.0f;             // 用于判断摩擦轮堵转的电流阈值, >0, 默认值 14 A
  float spd_delta_thre = 10.0f;              // 用于判断摩擦轮速度保持恒定的阈值, >0, 默认值 10 rad/s
  float spd_err_thre = 5.0f;                 // 用于判断摩擦轮速度跟上期望转速的阈值, >0, 默认值 5 rad/s
  float spd_stop_thre = 100.0f;              // 摩擦轮Stop模式,转速小于该阈值后,停止控制电机, >0, 默认值 100 rad/s
  /* 优化项,建议开启 */
  bool opt_spd_same_pid_enabled = false;  // 是否使用双摩擦轮同速PID(期望为0,反馈输入为两轮差速,输出分别正负作用到两个电机上)
  BulletSpdClosedLoop opt_blt_spd_cl;     // 弹速闭环优化
};

/* 优化项:弹速闭环 */
struct BulletSpdClosedLoop {
  bool is_enabled = false;       // 是否开启弹速闭环
  float min_reasonable_blt_spd;  // 最小合理弹丸速度, >0, 无默认值, m/s, 小于该值认为裁判系统反馈数据错误
  float max_reasonable_blt_spd;  // 最大合理弹丸速度, >0, 无默认值, m/s, 大于该值认为裁判系统反馈数据错误
  float min_target_blt_spd;      // 弹丸速度期望值区间下限, >0, 无默认值, m/s
  float max_target_blt_spd;      // 弹丸速度期望值区间上限, >0, 无默认值, m/s
  float spd_gradient = 5.0f;     // 摩擦轮转速调整梯度, >=0, 默认值 5 rad/s
};

配置参数结构体:

成员名称 默认值 说明 备注
default_spd_ref 摩擦轮预设期望转速(rad/s) 开启弹速闭环优化后,摩擦轮实际期望转速可能与default_spd_ref不一致。
default_spd_ref_backward -100.0f 摩擦轮反转时的期望转速(rad/s) 摩擦轮反转模式是为了把卡在摩擦轮中的弹丸回退出来,转速不宜过快。
stuck_curr_thre 14.0f 用于判断摩擦轮是否堵转的电流阈值(A) 默认值适用于3508电机。
spd_delta_thre 10.0f 用于判断摩擦轮转速波动的阈值(rad/s) 若摩擦轮当前反馈转速与上一帧的反馈转速差的绝对值小于阈值,则认为摩擦轮转速稳定
spd_err_thre 5.0f 用于判断摩擦轮转速与期望值差距的阈值(rad/s) 若摩擦轮当前反馈转速与期望转速差的绝对值小于阈值,则认为摩擦轮转速达到期望。在复活模式下,若两摩擦轮转速稳定且达到期望,持续200ms后,进入正常工作模式。
spd_stop_thre 100.0f 摩擦轮停止模式下停止控制摩擦轮的临界转速(rad/s) 摩擦轮由正常工作模式切换为停止模式后,若直接停止控制电机,受惯性影响,摩擦轮需要耗费极长时间才能完全停转;若始终控制电机转速为0,不便于机械队员用手转动摩擦轮做相关检查。
综合以上两种控制策略,当摩擦轮反馈转速大于等于spd_stop_thre时,控制电机转速为0;当摩擦轮反馈转速小于spd_stop_thre时,停止控制电机。
opt_spd_same_pid_enabled false 是否使用双摩擦轮同速PID优化 两摩擦轮转速保持一致,比两摩擦轮的转速与期望值保持一致更重要。同速PID的参考值为0,输入为两摩擦轮的差速,输出分别加/减到两个摩擦轮转速PID的输出上。
若要开启同速PID优化,必须注册同速PID。同速PID参数不宜过大。
opt_blt_spd_cl 弹速闭环优化

弹速闭环优化结构体:

成员名称 默认值 说明 备注
is_enabled false 是否开启弹速闭环优化
min_reasonable_blt_spd 最小合理弹丸速度(m/s) 若反馈弹速低于该值,则认为反馈弹速不合理,不予以采用。
max_reasonable_blt_spd 最大合理弹丸速度(m/s) 若反馈弹速高于该值,则认为反馈弹速不合理,不予以采用。
min_target_blt_spd 最小期望弹丸速度(m/s) 若反馈弹速低于该值,则将摩擦轮实际期望转速加spd_gradient
max_target_blt_spd 最大期望弹丸速度(m/s) 若反馈弹速高于该值,则将摩擦轮实际期望转速减spd_gradient
spd_gradient 5.0f 摩擦轮调整梯度(rad/s)

3 使用方法

3.1 摩擦轮的实例化与初始化

【建议】 自己写一对 ins_fric.hpp 和 ins_fric.cpp 文件,依照全局单例的设计思想,定义拨弹盘的全局单例,并给出接口函数抛出拨弹盘实例指针。

  • ins_fric.hpp

在其中包含fric_2motor.hpp文件,并给出接口函数。

C++
#include "fric_2motor.hpp"
hello_world::module::Fric* CreateFric();
  • ins_fric.cpp

在其中包含ins_fric.hpp,定义拨弹盘全局实例,注册PID和电机指针,实现接口函数。

C++
#include "ins_fric.hpp"

/* 以下配置参数适用于25赛季初英雄机器人 */
hello_world::module::Fric::Config kFricConfig = {
    .default_spd_ref = 640.0f,           ///< 摩擦轮期望速度预设值 rad/s
    .default_spd_ref_backward = -100.0f, ///< 摩擦轮反转目标速度
    .stuck_curr_thre = 14.0f,            ///< 用于判断摩擦轮堵转的电流阈值
    .spd_delta_thre = 10.0f,             ///< 用于判断摩擦轮速度保持恒定的阈值 rad/s
    .spd_err_thre = 5.0f,                ///< 用于判断摩擦轮速度跟上期望转速的阈值 rad/s
    .opt_spd_same_pid_enabled = true,
    .opt_blt_spd_cl = {
                       .is_enabled = true,
                       .min_reasonable_blt_spd = 14.0f,
                       .max_reasonable_blt_spd = 16.5f,
                       .min_target_blt_spd = 15.9f,
                       .max_target_blt_spd = 15.3f,
                       .spd_gradient = 5.0f,
                       }
};

hello_world::module::Fric unique_fric = hello_world::module::Fric(kFricConfig);
hello_world::module::Fric* CreateFric()
{
  static bool is_fric_created = false;

  if (!is_fric_created) {
    unique_fric.registerMotor(CreateMotorFricLeft(), hello_world::module::Fric::MotorIdx::kFirst);    // 注册第一个摩擦轮电机
    unique_fric.registerMotor(CreateMotorFricRight(), hello_world::module::Fric::MotorIdx::kSecond);  // 注册第二个摩擦轮电机
    unique_fric.registerPid(CreatePidMotorFricLeft(), hello_world::module::Fric::PidIdx::kFirst);     // 注册第一个摩擦轮电机PID
    unique_fric.registerPid(CreatePidMotorFricRight(), hello_world::module::Fric::PidIdx::kSecond);   // 注册第二个摩擦轮电机PID
    /* 如果未开启同速PID优化,则无需注册同速PID */
    unique_fric.registerPid(CreatePidFricSameSpd(), hello_world::module::Fric::PidIdx::kSameSpd);  // 注册同速PID
    is_fric_created = true;
  }

  return &unique_fric;
}

3.2 更新裁判系统数据

C++
1
2
3
4
5
6
7
8
9
void updateRfrData(const FricRfrInputData &inp_data);

// 用法:
hello_world::module::Fric* fric_ptr_ = CreateFric();
hello_world::module::Fric::RfrInputData fric_rfr_input_data;

/* 设置 rfr_input_data, fric_ok_flag, 略 */

fric_ptr_->updateRfrData(fric_rfr_input_data);

updateRfrData()用于更新拨弹盘所需的裁判系统反馈数据,不更新时,采用用户上一次的更新值或者默认值。

裁判系统数据结构体如下:

C++
1
2
3
4
5
struct FricRfrInputData {
  bool is_power_on = false;          // 摩擦轮电源是否开启
  float is_new_bullet_shot = false;  // 是否有一颗新弹丸射出
  float bullet_spd;                  // 发射机构检测到的弹丸速度, 无默认值, m/s
};

【注意】

  1. 裁判系统反馈数据完全用于弹速闭环优化。(如is_new_bullet_shotbullet_spdis_power_on不会用到,状态机内部根据是否与电机正常通信来判断是否上电。)因此,如果配置参数未开启弹速闭环优化,可以不更新裁判系统数据。
  2. is_new_bullet_shot的读取方式见拨弹盘使用说明 1.2节【注意】第2点

3.3 设定工作模式

用户需要根据自身需求设定工作模式。

C++
void setWorkingMode(WorkingMode mode) { working_mode_ = mode; }

// 用法:
hello_world::module::Fric* fric_ptr_ = CreateFric();

typedef hello_world::module::Fric::WorkingMode WorkingMode;

WorkingMode working_mode = WorkingMode::kStop;     // 停止模式
WorkingMode working_mode = WorkingMode::kShoot;    // 正常工作模式
WorkingMode working_mode = WorkingMode::kBackward; // 倒转模式(为了退出卡住的弹丸)

fric_ptr_->setWorkingMode(WorkingMode);

3.4 运行摩擦轮状态机

当主状态机处于Dead或者Resurrection状态时,如下运行摩擦轮状态机:

C++
1
2
3
4
hello_world::module::Fric *fric_ptr_ = CreateFric();

fric_ptr_->update();
fric_ptr_->standby();

【说明】

摩擦轮状态机的standby()运行函数实现了快速停转+停转后不控制摩擦轮电机的效果。

考虑到关闭遥控器杀死主状态机后,主状态机在Dead状态和Resurrection状态反复运行,因此需要让主状态机在这两个状态下调用standby(),保证关闭遥控器后摩擦轮快速停转,并且可以上手把玩。

当主状态机处于Working状态时,如下运行摩擦轮状态机:

C++
1
2
3
4
hello_world::module::Fric *fric_ptr_ = CreateFric();

fric_ptr_->update();
fric_ptr_->run();

此外,摩擦轮状态机还提供了一个复位接口,以便于重置整个摩擦轮状态机:

C++
1
2
3
hello_world::module::Fric *fric_ptr_ = CreateFric();

fric_ptr_->reset();

3.5(补充) 读取摩擦轮状态机内部数据

除摩擦轮当前运行状态外,一般无需读取摩擦轮状态机的内部数据。平常调试时,可以通过Ozone直接查看实例的内部数据。

由于拨弹盘状态机需要摩擦轮运行状态,因此提供了相应接口:

C++
1
2
3
hello_world::module::Fric *fric_ptr_ = CreateFric();

bool is_fric_ready = fric_ptr_->getStatus();

此外,为了规范性,摩擦轮状态机还提供了以下接口:

C++
1
2
3
Config &getConfig() { return cfg_; }
const Config &getConfig() const { return cfg_; }
WorkingMode getWorkingMode() const { return working_mode_; }

附录

版本说明

版本号 发布日期 说明 贡献者
2025.02.07 2摩擦轮模块使用说明 娄开杨