ODrive
ODriveとは
オープンソースのブラシレスモータードライバの一つです
最近はODrive Proとかいうものが出てきて、只でさえ足りない情報が埋もれるようになってしまいました…
公式のドキュメントはv0.5.5のやつで、間違って、最新版のドキュメントを見ないように注意してください
環境構築
現在はUbuntu環境でしか動作できません…
次のコマンドで、gccやmakeなどをインストールします
sudo apt install build-essential
次のコマンドで、ODrive独自のコンパイルシステムに必要なパッケージをインストールします
sudo apt install gcc-arm-none-eabi
sudo apt install tup
sudo apt install python3 python3-yaml python3-jinja2 python3-jsonschema
次のコマンドで、デバッガーをインストールします(arm-none-eabi-gdbにgdb-multiarchのシンボリックリンクを作成することで問題を解決している)
sudo apt install gdb-multiarch
ln -s /usr/bin/gdb-multiarch /usr/bin/arm-none-eabi-gdb
openocd v0.11をインストールします
git clone https://github.com/openocd-org/openocd.git
cd openocd
git checkout -b v0.11.0 refs/tags/v0.11.0
./bootstrap
./configure --enable-ftdi
make -j4
sudo make install
ODriveToolsでデバッグするために必要なパッケージをインストールします
pip install ipython PyUSB requests IntelHex matplotlib monotonic setuptools
echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="0d[0-9][0-9]", MODE="0666"' | sudo tee /etc/udev/rules.d/91-odrive.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
pip install ipython==8.0.1
キャリブレーションで計測されるもの
モーターキャリブレーションでは、位相インダクタンスと位相抵抗が計測されます エンコーダーキャリブレーションでは、位相とエンコーダーの関係を示すオフセットとエンコーダーの回転方向を計測した後、CPR(Counts Per Revolution)と極数が正しいのかがチェックされます
ODriveの制御器
以下のように、位置制御ループ、速度制御ループ、電流制御ループのカスケードで構成されています
速度制御の注意点
最高速度の制限は様々な要因が関係するため、注意が必要です
エンコーダーによる制限
AMT102

AMT212

ODriveの動作周波数による制限
- 70000 / 極数 = (35000 / 極ペア数)
モーターによる制限
- 電圧 × KV
例
- エンコーダーにAMT112(2048ppr)を使う場合、8000RPM
- ブラシレスモーターの極が14である場合、5000RPM
- 24Vかつ170KVの場合、4080RPM
この場合、最高速度は4080RPMとなります
ODriveの設定コマンドまとめ
以下の2つに注意してください
- 初めの文字がdev0になっているが、これはデバイスの名前を表しているため、環境によってはodrv0だったり、dev1だったりする
- また、axis0はモーターの番号を示しており、2つ動かせるODriveの場合は、axis1が存在する
モーター設定
| コマンド | 値(例) | 単位 | 詳細 |
|---|---|---|---|
| dev0.axis0.motor.config.current_lim | 100 | A | モーターの電流制限 |
| dev0.axis0.motor.config.current_lim_margin | 10 | A | モーターの電流制限を超えた場合の許容範囲 |
| dev0.axis0.motor.config.requested_current_range | 110 | A | 電流センサのゲイン且つ上限設定 (current_lim + current_lim_margin以上にする) |
| dev0.axis0.controller.config.vel_limit | 50 | rps(turns/s) | モーターの速度制限 |
| dev0.axis0.motor.config.calibration_current | 10 | A | モーター初期化時の電流 |
| dev0.axis0.motor.config.resistance_calib_max_voltage | 4 | V | モーター初期化時の最大の電圧 (電源電圧の半分未満にする必要がある) |
| dev0.axis0.motor.config.pole_pairs | 7 | 極 | 永久磁石の極数の半分 (N/Sの組数) |
| dev0.axis0.motor.config.torque_constant | 8.27/170 | Nm/A | トルク定数 (8.27は、KV値とトルク定数との関係を示す定数) |
| dev0.axis0.motor.config.motor_type | MOTOR_TYPE_HIGH_CURRENT | MotorType | MOTOR_TYPE_xxxのように書く (xxxはMotorType) ブラシレスモーターはHIGH_CURRENT 他には、GIMBAL, ACIMが選択できる |
センサレスコントロール設定
| コマンド | 値(例) | 単位 | 詳細 |
|---|---|---|---|
| dev0.axis0.config.sensorless_ramp.vel | 100 | ラジアン/s | センサレスの速度制限 |
| dev0.axis0.config.sensorless_ramp.current | 10 | A | センサレスの電流制限 |
| dev0.axis0.motor.config.current_lim | 2*10 | A | 2*sensorless_ramp.current (±の合計のため、2倍している?) |
| dev0.axis0.controller.config.vel_limit | 150 / 2*3.14 * 7 | rps (turns/s) | 単位変換してるだけっぽい |
| dev0.axis0.sensorless_estimator.config.pm_flux_linkage | 5.51328895422 / (7 * 170) | Wb | 鎖交磁束(磁束とコイルの巻き数の積) |
| dev0.axis0.config.enable_sensorless_mode | True | T/F | センサレスモードの有効化 |
エンコーダー設定
| コマンド | 値(例) | 単位 | 詳細 |
|---|---|---|---|
| dev0.axis0.encoder.config.mode | ENCODER_MODE_INCREMENTAL | Mode | ENCODER_MODE_xxxのように書く (xxxはMode) INCREMENTAL, HALL, SINCOS, SPI_ABS_CUI(AMT23), SPI_ABS_AMS(AMS AS504), SPI_ABS_AEAT(AEAT-8800), SPI_ABS_RLS(RLS Orbisシリーズ), SPI_ABS_MA732(MA732)がある |
| dev0.axis0.encoder.config.cpr | 8000 | cpr | Counts Per Revolution インクリメンタルの場合は、PPR*4 アブソリュートの場合は、2**出力ビット |
| dev0.axis0.encoder.config.calib_range | 0.05 | 割合 | 初期化時に許容する、1回転あたりの誤差の割合 |
マイクロスイッチ
VEL_RAMPで速度制御してスイッチまで移動し、その後オフセット位置までTRAP_TRAJで位置制御
| コマンド | 値(例) | 単位 | 詳細 |
|---|---|---|---|
| dev0.axis0.min_endstop.config.gpio_num | 2 | GPIO_NUM | スイッチを繋いだピンを選択 |
| dev0.axis0.min_endstop.config.enabled | True | T/F | スイッチでの初期化の有効化 |
| dev0.axis0.min_endstop.config.offset | 0.0 | turns | スイッチ発見後、どのくらい移動した地点を初期値にするか |
| dev0.axis0.min_endstop.config.debounce_ms | 50.0 | ms | スイッチのチャタリングを防ぐ |
| dev0.axis0.min_endstop.config.is_active_high | True | T/F | GPIOが浮いている状態?よくわからないので、違ったら変更して |
| dev0.axis0.controller.config.homing_speed | 0.5 | rps | スイッチ初期化時の目標速度 |
状態設定
| コマンド | 値(例) | 単位 | 詳細 |
|---|---|---|---|
| dev0.axis0.requested_state | AXIS_STATE_FULL_CALIBRATION_SEQUENCE | AxisState | AXIS_STATE_xxxのように書く (xxxはAxisState) FULL_CALIBRATION_SEQUENCE (モーターとエンコーダーの初期化) MOTOR_CALIBRATION (モーターの初期化) ENCODER_OFFSET_CALIBRATION (エンコーダーの初期化) ENCODER_INDEX_SEARCH (Z相サーチ) CLOSED_LOOP_CONTROL (閉ループ制御実行) IDLE (PWM無効化) HOMING (インタラプタ初期化)など |
| dev0.axis0.motor.config.pre_calibrated | False | T/F | モーターが初期化済みの場合は、これを有効にすると、次回から初期化しなくていい |
| dev0.axis0.encoder.config.pre_calibrated | False | T/F | アブソリュートエンコーダーを使っており、初期化済みの場合は、これを有効にすると、次回から初期化しなくていい |
| dev0.config.enable_brake_resistor | False | T/F | ブレーキ抵抗がついているか |
| dev0.config.brake_resistance | 0.05 | Ω | ブレーキ抵抗がついている場合、その値を入力 |
| dev0.config.dc_max_positive_current | 120 | A | 電源の最大電流 |
| dev0.config.dc_max_negative_current | -120 | A | 電源の最大負電流 |
| dev0.config.dc_bus_overvoltage_trip_level | 53 | V | 電源の最大電圧 ブレーキ抵抗がない場合には、これを上げておかないと、逆起エラーで止まる (48Vの場合は48*1.1=52.8程度にしておけば大丈夫) |
コントローラー設定
| コマンド | 値(例) | 単位 | 詳細 |
|---|---|---|---|
| dev0.axis0.controller.config.control_mode | CONTROL_MODE_VELOCITY_CONTROL | ControlMode | CONTROL_MODE_xxxのように書く (xxxはControlMode) TORQUE_CONTROL (トルク制御) VELOCITY_CONTROL (速度制御) POSITION_CONTROL (位置制御) |
| dev0.axis0.controller.config.input_mode | INPUT_MODE_VEL_RAMP | InputMode | PASSTHROUGH (input_xxx を xxx_setpoint に直接渡すため、フィルタを通さないで制御器に送ることになる) VEL_RAMP (台形速度で速度制御器にわたす) POS_FILTER (マス-バネ-ダンパを模倣するような2次の位置追跡フィルタをかけて位置制御器にわたす) TRAP_TRAJ (台形速度で位置制御器にわたす) TORQUE_RAMP (台形トルクでトルク制御器にわたす) TUNING (制御器のチューニング用の正弦波駆動モード) |
| dev0.axis0.controller.config.vel_ramp_rate | 0.5 | rps (turns/s) | 1秒に速度が増える量 (加速度) |
| dev0.axis0.controller.config.input_filter_bandwidth | 2.0 | Hz | マス-バネ-ダンパを模倣するような2次の位置追跡フィルタの周波数 |
| dev0.axis0.trap_traj.config.vel_limit | 5.0 | rps | 台形速度で位置制御するときの最大速度 |
| dev0.axis0.trap_traj.config.accel_limit | 1.0 | rps/s | 台形速度で位置制御するときの最大加速度 |
| dev0.axis0.trap_traj.config.decel_limit | 1.0 | rps/s | 台形速度で位置制御するときの最大減速度 |
| dev0.axis0.controller.config.pos_gain | 5.0 | rps / turn | 位置制御のゲイン |
| dev0.axis0.controller.config.vel_gain | 0.64 | Nm/rps | 速度制御のゲイン |
| dev0.axis0.controller.config.vel_integrator_gain | 1.28 | Nm/(rps * s) | 速度制御の積分ゲイン |
| dev0.axis0.motor.config.current_control_bandwidth | 100 | ms | トルク(電流)制御の時定数 |
| dev0.axis0.controller.input_pos | 1 | turns | 絶対値入力 目標回転数を入力フィルタに投げる |
| dev0.axis0.controller.input_vel | 1 | rps (turns/s) | 絶対値入力 目標回転速度を入力フィルタに投げる 速度上限は、rps = 75% * bus_voltage * motor_kv / 60 で大方求められる |
| dev0.axis0.controller.input_torque | 1 | Nm | 絶対値入力 目標トルクを入力フィルタに投げる |
| dev0.axis0.controller.move_incremental | 10, True | turns, T/F | 相対値入力 (これを実行するたびに、指定の回転数だけ回る) True→input_posに相対 False→pos_setpointに相対 |
| dev0.axis0.controller.pos_setpoint | 1 | turns | 直接入力 (フィルタを通さない) 目標回転数を位置制御器に直接入力する |
| dev0.axis0.controller.vel_setpoint | 1 | rps (turns/s) | 直接入力 (フィルタを通さない) 目標回転速度を速度制御器に直接入力する |
| dev0.axis0.controller.torque_setpoint | 1 | Nm | 直接入力 (フィルタを通さない) 目標トルクをトルク制御器に直接入力する |
デバッグ
| コマンド | 値(例) | 単位 | 詳細 |
|---|---|---|---|
| start_liveplotter(lambda:[COMMAND1, COMMAND2, …]) | dev0.axis0.encoder.pos_estimate | Commands | matplotlibでグラフが出せる 同時に2つとか入力すると、同じグラフに同時にプロットされる |
| dump_errors(DEVICE) | dev0 | Devices | エラー出力 |
| dev0.clear_errors() | エラー消去 | ||
| dev0.save_configuration() | コマンド(コマンド内にconfigとあるやつ)の現在値を保存 | ||
| dev0.reboot() | ODrive再起動 |