Itamika logo Itamika
ODrive

ODrive

ODriveとは

ODriveBasicWiring

オープンソースのブラシレスモータードライバの一つです

最近は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の制御器

以下のように、位置制御ループ、速度制御ループ、電流制御ループのカスケードで構成されています

Controller-odrive

速度制御の注意点

最高速度の制限は様々な要因が関係するため、注意が必要です

エンコーダーによる制限

AMT102 Amt102-speed-limit.png

AMT212 Amt212-speed-limit.png

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_lim100Aモーターの電流制限
dev0.axis0.motor.config.current_lim_margin10Aモーターの電流制限を超えた場合の許容範囲
dev0.axis0.motor.config.requested_current_range110A電流センサのゲイン且つ上限設定 (current_lim + current_lim_margin以上にする)
dev0.axis0.controller.config.vel_limit50rps(turns/s)モーターの速度制限
dev0.axis0.motor.config.calibration_current10Aモーター初期化時の電流
dev0.axis0.motor.config.resistance_calib_max_voltage4Vモーター初期化時の最大の電圧 (電源電圧の半分未満にする必要がある)
dev0.axis0.motor.config.pole_pairs7永久磁石の極数の半分 (N/Sの組数)
dev0.axis0.motor.config.torque_constant8.27/170Nm/Aトルク定数
8.27KV\frac{8.27}{KV} (8.27は、KV値とトルク定数との関係を示す定数)
dev0.axis0.motor.config.motor_typeMOTOR_TYPE_HIGH_CURRENTMotorTypeMOTOR_TYPE_xxxのように書く (xxxはMotorType)
ブラシレスモーターはHIGH_CURRENT
他には、GIMBAL, ACIMが選択できる

センサレスコントロール設定

コマンド値(例)単位詳細
dev0.axis0.config.sensorless_ramp.vel100ラジアン/sセンサレスの速度制限
dev0.axis0.config.sensorless_ramp.current10Aセンサレスの電流制限
dev0.axis0.motor.config.current_lim2*10A2*sensorless_ramp.current (±の合計のため、2倍している?)
dev0.axis0.controller.config.vel_limit150 / 2*3.14 * 7rps (turns/s)sensorlessramp.velより大きい値2π×polepairs\frac{sensorless_ramp.velより大きい値}{2\pi\times pole_pairs}
単位変換してるだけっぽい
dev0.axis0.sensorless_estimator.config.pm_flux_linkage5.51328895422 / (7 * 170)Wb鎖交磁束(磁束とコイルの巻き数の積)
5.51328895422polepairs×KV\frac{5.51328895422}{pole_pairs\times KV}
dev0.axis0.config.enable_sensorless_modeTrueT/Fセンサレスモードの有効化

エンコーダー設定

コマンド値(例)単位詳細
dev0.axis0.encoder.config.modeENCODER_MODE_INCREMENTALModeENCODER_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.cpr8000cprCounts Per Revolution
インクリメンタルの場合は、PPR*4
アブソリュートの場合は、2**出力ビット
dev0.axis0.encoder.config.calib_range0.05割合初期化時に許容する、1回転あたりの誤差の割合

マイクロスイッチ

VEL_RAMPで速度制御してスイッチまで移動し、その後オフセット位置までTRAP_TRAJで位置制御

コマンド値(例)単位詳細
dev0.axis0.min_endstop.config.gpio_num2GPIO_NUMスイッチを繋いだピンを選択
dev0.axis0.min_endstop.config.enabledTrueT/Fスイッチでの初期化の有効化
dev0.axis0.min_endstop.config.offset0.0turnsスイッチ発見後、どのくらい移動した地点を初期値にするか
dev0.axis0.min_endstop.config.debounce_ms50.0msスイッチのチャタリングを防ぐ
dev0.axis0.min_endstop.config.is_active_highTrueT/FGPIOが浮いている状態?よくわからないので、違ったら変更して
dev0.axis0.controller.config.homing_speed0.5rpsスイッチ初期化時の目標速度

状態設定

コマンド値(例)単位詳細
dev0.axis0.requested_stateAXIS_STATE_FULL_CALIBRATION_SEQUENCEAxisStateAXIS_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_calibratedFalseT/Fモーターが初期化済みの場合は、これを有効にすると、次回から初期化しなくていい
dev0.axis0.encoder.config.pre_calibratedFalseT/Fアブソリュートエンコーダーを使っており、初期化済みの場合は、これを有効にすると、次回から初期化しなくていい
dev0.config.enable_brake_resistorFalseT/Fブレーキ抵抗がついているか
dev0.config.brake_resistance0.05Ωブレーキ抵抗がついている場合、その値を入力
dev0.config.dc_max_positive_current120A電源の最大電流
dev0.config.dc_max_negative_current-120A電源の最大負電流
dev0.config.dc_bus_overvoltage_trip_level53V電源の最大電圧
ブレーキ抵抗がない場合には、これを上げておかないと、逆起エラーで止まる (48Vの場合は48*1.1=52.8程度にしておけば大丈夫)

コントローラー設定

コマンド値(例)単位詳細
dev0.axis0.controller.config.control_modeCONTROL_MODE_VELOCITY_CONTROLControlModeCONTROL_MODE_xxxのように書く (xxxはControlMode)
TORQUE_CONTROL (トルク制御)
VELOCITY_CONTROL (速度制御)
POSITION_CONTROL (位置制御)
dev0.axis0.controller.config.input_modeINPUT_MODE_VEL_RAMPInputModePASSTHROUGH (input_xxx を xxx_setpoint に直接渡すため、フィルタを通さないで制御器に送ることになる)
VEL_RAMP (台形速度で速度制御器にわたす)
POS_FILTER (マス-バネ-ダンパを模倣するような2次の位置追跡フィルタをかけて位置制御器にわたす)
TRAP_TRAJ (台形速度で位置制御器にわたす)
TORQUE_RAMP (台形トルクでトルク制御器にわたす)
TUNING (制御器のチューニング用の正弦波駆動モード)
dev0.axis0.controller.config.vel_ramp_rate0.5rps (turns/s)1秒に速度が増える量 (加速度)
dev0.axis0.controller.config.input_filter_bandwidth2.0Hzマス-バネ-ダンパを模倣するような2次の位置追跡フィルタの周波数
dev0.axis0.trap_traj.config.vel_limit5.0rps台形速度で位置制御するときの最大速度
dev0.axis0.trap_traj.config.accel_limit1.0rps/s台形速度で位置制御するときの最大加速度
dev0.axis0.trap_traj.config.decel_limit1.0rps/s台形速度で位置制御するときの最大減速度
dev0.axis0.controller.config.pos_gain5.0rps / turn位置制御のゲイン
dev0.axis0.controller.config.vel_gain0.64Nm/rps速度制御のゲイン
dev0.axis0.controller.config.vel_integrator_gain1.28Nm/(rps * s)速度制御の積分ゲイン
dev0.axis0.motor.config.current_control_bandwidth100msトルク(電流)制御の時定数
dev0.axis0.controller.input_pos1turns絶対値入力
目標回転数を入力フィルタに投げる
dev0.axis0.controller.input_vel1rps (turns/s)絶対値入力
目標回転速度を入力フィルタに投げる
速度上限は、rps = 75% * bus_voltage * motor_kv / 60 で大方求められる
dev0.axis0.controller.input_torque1Nm絶対値入力
目標トルクを入力フィルタに投げる
dev0.axis0.controller.move_incremental10, Trueturns, T/F相対値入力 (これを実行するたびに、指定の回転数だけ回る)
True→input_posに相対
False→pos_setpointに相対
dev0.axis0.controller.pos_setpoint1turns直接入力 (フィルタを通さない)
目標回転数を位置制御器に直接入力する
dev0.axis0.controller.vel_setpoint1rps (turns/s)直接入力 (フィルタを通さない)
目標回転速度を速度制御器に直接入力する
dev0.axis0.controller.torque_setpoint1Nm直接入力 (フィルタを通さない)
目標トルクをトルク制御器に直接入力する

デバッグ

コマンド値(例)単位詳細
start_liveplotter(lambda:[COMMAND1, COMMAND2, …])dev0.axis0.encoder.pos_estimateCommandsmatplotlibでグラフが出せる
同時に2つとか入力すると、同じグラフに同時にプロットされる
dump_errors(DEVICE)dev0Devicesエラー出力
dev0.clear_errors()エラー消去
dev0.save_configuration()コマンド(コマンド内にconfigとあるやつ)の現在値を保存
dev0.reboot()ODrive再起動