LoginSignup
3

More than 1 year has passed since last update.

OdriveでBLDCを動かしてみよう!

Last updated at Posted at 2021-09-01

本記事の目的

Odriveを使用してBLDCのモーター制御を実行します

環境

本記事は以下の環境で実験しています.

項目 バージョン
Ubuntu 18.04
Odrive 0.5.2

実験環境

Hall wireの接続

Hall wire J4 signal
Red 5V
Yellow A
Blue B
Green Z
Black GND

IMG_1839.JPG

必要機材
- Odrive
- インホイールモーター
- 安定化電源
- Wire 10AWG
- アルミフレーム 2020
- クランプ

Odrivetoolインストール

以下のコマンドを順に打ってodriveをインストールします。

Odriveインストールコマンド
$ sudo apt update
$ sudo apu upgrade
$ sudo apt install python3 python3-pip 
$ sudo pip3 install --upgrade odrive
$ echo "PATH=$PATH:~/.local/bin/" >> ~/.bashrc 

無事にインストールされた場合、odrivetoolと打てば以下のような表示が出るはずです。

odrivetool動作確認
$ odrivetool

ODrive control utility v0.5.2
Please connect your ODrive.
Type help() for help.
ash
Connected to ODrive 207B346D5748 as odrv0

Connected to ODrive 207B346D5748 as odrv0の部分は、odriveに外部電源から電源供給せずにPCに接続しても表示されないので電源供給してからodrivetoolと打ちましょう。
また207B346D5748はodriveの識別ID、odrv0がodriveのボードを意味します。複数個のodriveを使用する場合、odrv1, odrv2...などと表示されます。

次に以下のコマンドでファームウェアをupdateします。

$ sudo odrivetool dfu

無事成功すると以下のように表示されます。

ODrive control utility v0.5.2.post0
Waiting for ODrive...
Found ODrive 207B346D5748 (v3.6-24V) with firmware [unknown version] in DFU mode
Checking online for newest firmware... found v0.5.2
Downloading firmware v0.5.2...
The configuration cannot be backed up because the device is already in DFU mode. The configuration may be lost after updating. Do you want to continue anyway? [Y/n] Y
Erasing... done            
Flashing... done            
Verifying... done            
Device firmware update successful.

BLDC速度制御(1輪のみ)

odriveではボードの永続メモリにconfigを保存してから、ターミナルで指令値を送る事でモーターを回転させる事ができます。ここでは片輪のモーターの速度制御のためのconfigを記載します。しかし、このconfigやキャリブレーションが一筋縄ではいかなかったのでここではその経緯についても補足します。config内の各種パラメータについてはdocumentを参照してください。

まず以下のconfigをodriveに保存します。

config内容
odrv0.axis0.motor.config.pole_pairs = 15
odrv0.axis0.motor.config.resistance_calib_max_voltage = 4
odrv0.axis0.motor.config.requested_current_range = 25 
odrv0.axis0.motor.config.current_control_bandwidth = 100

odrv0.axis0.motor.config.torque_constant = 8.27 / 16
odrv0.axis0.encoder.config.mode = ENCODER_MODE_HALL
odrv0.axis0.encoder.config.cpr = 90
odrv0.axis0.encoder.config.calib_scan_distance = 150

odrv0.axis0.encoder.config.bandwidth = 100
odrv0.axis0.controller.config.pos_gain = 1
odrv0.axis0.controller.config.vel_gain = 0.02 * odrv0.axis0.motor.config.torque_constant * odrv0.axis0.encoder.config.cpr
odrv0.axis0.controller.config.vel_integrator_gain = 0.1 * odrv0.axis0.motor.config.torque_constant * odrv0.axis0.encoder.config.cpr
odrv0.axis0.controller.config.vel_limit = 10

odrv0.axis0.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL

odrv0.config.enable_brake_resistor = True
odrv0.axis0.motor.config.current_lim = 5
odrv0.axis0.motor.config.calibration_current = 5
odrv0.axis0.encoder.config.hall_polarity_calibrated = True 

odrv0.save_configuration()
odrv0.reboot()

次にモーターのキャリブレーションを行います。モーターのキャリブレーション時には、モーターからビープ音がなり、モーターに一定の電流値が流れます。ここでビープ音が鳴らなければconfig内のキャリブレーション関係のパラメータ設定に問題がある可能性があります。具体的なエラー内容についてはdump_errors(odrv0)で確認しましょう。

モーターキャリブレーション
odrv0.axis0.requested_state = AXIS_STATE_MOTOR_CALIBRATION
odrv0.axis0.motor

次にエンコーダのオフセットキャリブレーションを行います。エンコーダオフセットキャリブレーション時にはゆっくりモーターが正転一回、逆転一回動作します。ここでモーターが回らない場合はconfig設定や配線等に問題がある可能性があります。

エンコーダオフセットキャリブレーション
odrv0.axis0.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION
odrv0.axis0.encoder

しかし私の場合、このエンコーダオフセットキャリブレーションで正転一回、逆転一回したにも関わらず、以下のようなエラーが発生していました。

system: no error
axis0
  axis: no error
  motor: no error
  sensorless_estimator: no error
  encoder: Error(s):
    ENCODER_ERROR_ILLEGAL_HALL_STATE
  controller: no error
axis1
  axis: no error
  motor: no error
  sensorless_estimator: no error
  encoder: no error
  controller: no error

エラー内容はENCODER_ERROR_ILLEGAL_HALL_STATEの部分です。エラーの原因について調べると以下のようなサイトに行きつきました。

結局のところ上記エラーの原因はエンコーダーのノイズによるところらしいです。ノイズが酷い事によりエンコーダーからの信号が全て0の場合に発生するエラーです。このエラーに対処する方法は、各エンコーダー信号ピンとGND間に22nF~47nF程度のコンデンサを入れてノイズ除去することで解決することができます。

ノイズ除去のコンデンサーとしては、セラミックコンデンサーもしくはフィルムコンデンサーを使用してください。私はamazonでフィルムコンデンサーを購入しました。

以下の画像のように22nFのコンデンサーを半田付けを行います。

IMG_1823.JPG

この状態で再度エンコーダオフセットキャリブレーションを行うとエラーが無くなりました!

またエンコーダのデバックについてはodrv0.axis0.encoderhall_stateも見ておきましょう。hall_stateが0か7の場合、何か異常があるサインです。本来は、キャリブレーション中にhall_stateを監視し続けて、0か7になる瞬間があるかどうかで判断するのが良いと思われます。

In [37]: odrv0.axis0.encoder
Out[37]: 
calib_scan_response: 144.0 (float)
config:
  abs_spi_cs_gpio_pin: 1 (uint16)
  bandwidth: 100.0 (float)
  calib_range: 0.019999999552965164 (float)
  calib_scan_distance: 150.0 (float)
  calib_scan_omega: 12.566370964050293 (float)
  cpr: 90 (int32)
  direction: -1 (int32)
  enable_phase_interpolation: True (bool)
  find_idx_on_lockin_only: False (bool)
  hall_polarity: 0 (uint8)
  hall_polarity_calibrated: False (bool)
  ignore_illegal_hall_state: False (bool)
  index_offset: 0.0 (float)
  mode: 1 (uint16)
  phase_offset: -23 (int32)
  phase_offset_float: -0.4535244107246399 (float)
  pre_calibrated: False (bool)
  sincos_gpio_pin_cos: 4 (uint16)
  sincos_gpio_pin_sin: 3 (uint16)
  use_index: False (bool)
  use_index_offset: True (bool)
count_in_cpr: 48 (int32)
delta_pos_cpr_counts: 5.605193857299268e-45 (float)
error: 528 (uint16)
hall_state: 5 (uint8)
index_found: False (bool)
interpolation: 0.5 (float)
is_ready: True (bool)
phase: 0.04866981506347656 (float)
pos_abs: 0 (int32)
pos_circular: 0.534058153629303 (float)
pos_cpr_counts: 48.02492141723633 (float)
pos_estimate: 0.5333594679832458 (float)
pos_estimate_counts: 48.00235366821289 (float)
set_linear_count(obj: object_ref, count: int32)
shadow_count: 48 (int32)
spi_error_rate: 0.0 (float)
vel_estimate: 0.0 (float)
vel_estimate_counts: 0.0 (float)

エラーが無くなったので、キャリブレーション内容を永続メモリに保存します。永続メモリに保存する事で次回以降キャリブレーションをする必要がなくなります。永続メモリに保存するコマンドは以下の通りです。

  • モーターのキャリブレーションの場合
    odrv0.axis0.motor.config.pre_calibrated = True
  • エンコーダオフセットキャリブレーションの場合
    odrv0.axis0.encoder.config.pre_calibrated = True

最後にconfigをsaveしてrebootします。

キャリブレーションを保存
odrv0.axis0.requested_state = AXIS_STATE_MOTOR_CALIBRATION
odrv0.axis0.motor
odrv0.axis0.motor.config.pre_calibrated = True

odrv0.axis0.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION
odrv0.axis0.encoder
odrv0.axis0.encoder.config.pre_calibrated = True

odrv0.save_configuration()
odrv0.reboot()

次にモータのrequested_stateをAXIS_STATE_CLOSED_LOOP_CONTROLにして、指令値を送る事でモータが回転します。今回、control_modeがCONTROL_MODE_VELOCITY_CONTROLなのでodrv0.axis0.controller.input_velコマンドで指令値を送ります。

指令値を送信
odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis0.controller.input_vel = 2

これでモーターを速度制御する事が出来ました!

one2.gif

上記一連のコマンドを記載いたします。以下の内容を順にconfig及びターミナルで実行すれば、モーターの速度制御が出来ると思います。

全体のconfig及びキャリブレーション内容
odrv0.axis0.motor.config.pole_pairs = 15
odrv0.axis0.motor.config.resistance_calib_max_voltage = 4
odrv0.axis0.motor.config.requested_current_range = 25 
odrv0.axis0.motor.config.current_control_bandwidth = 100

odrv0.axis0.motor.config.torque_constant = 8.27 / 16
odrv0.axis0.encoder.config.mode = ENCODER_MODE_HALL
odrv0.axis0.encoder.config.cpr = 90
odrv0.axis0.encoder.config.calib_scan_distance = 150

odrv0.axis0.encoder.config.bandwidth = 100
odrv0.axis0.controller.config.pos_gain = 1
odrv0.axis0.controller.config.vel_gain = 0.02 * odrv0.axis0.motor.config.torque_constant * odrv0.axis0.encoder.config.cpr
odrv0.axis0.controller.config.vel_integrator_gain = 0.1 * odrv0.axis0.motor.config.torque_constant * odrv0.axis0.encoder.config.cpr
odrv0.axis0.controller.config.vel_limit = 10

odrv0.axis0.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL

odrv0.config.enable_brake_resistor = True
odrv0.axis0.motor.config.current_lim = 5
odrv0.axis0.motor.config.calibration_current = 5
odrv0.axis0.encoder.config.hall_polarity_calibrated = True 

odrv0.save_configuration()
odrv0.reboot()

odrv0.axis0.requested_state = AXIS_STATE_MOTOR_CALIBRATION
odrv0.axis0.motor
odrv0.axis0.motor.config.pre_calibrated = True

odrv0.axis0.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION
odrv0.axis0.encoder
odrv0.axis0.encoder.config.pre_calibrated = True

odrv0.save_configuration()
odrv0.reboot()

odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis0.controller.input_vel = 2

odrv0.axis0.requested_state = AXIS_STATE_IDLE

BLDC速度制御(2輪)

1つのodriveボードで制御できるモータの個数は2個までです。ここでは上記のconfigを参考に2個のBLDCを同時に回転させるためのconfigを示します。1個目のモータの軸はodrv0.axis0、2個目のモータの軸はodrv0.axis1です。1輪のみの速度制御のconfigとの違いは、axis0と同じ内容をaxis1でも同様に設定する事です。

2輪動作のconfig内容
odrv0.axis0.motor.config.pole_pairs = 15
odrv0.axis0.motor.config.resistance_calib_max_voltage = 4
odrv0.axis0.motor.config.requested_current_range = 25 
odrv0.axis0.motor.config.current_control_bandwidth = 100

odrv0.axis1.motor.config.pole_pairs = 15
odrv0.axis1.motor.config.resistance_calib_max_voltage = 4
odrv0.axis1.motor.config.requested_current_range = 25 
odrv0.axis1.motor.config.current_control_bandwidth = 100

odrv0.axis0.motor.config.torque_constant = 8.27 / 16
odrv0.axis0.encoder.config.mode = ENCODER_MODE_HALL
odrv0.axis0.encoder.config.cpr = 90
odrv0.axis0.encoder.config.calib_scan_distance = 150

odrv0.axis1.motor.config.torque_constant = 8.27 / 16
odrv0.axis1.encoder.config.mode = ENCODER_MODE_HALL
odrv0.axis1.encoder.config.cpr = 90
odrv0.axis1.encoder.config.calib_scan_distance = 150

odrv0.axis0.encoder.config.bandwidth = 100
odrv0.axis0.controller.config.pos_gain = 1
odrv0.axis0.controller.config.vel_gain = 0.02 * odrv0.axis0.motor.config.torque_constant * odrv0.axis0.encoder.config.cpr
odrv0.axis0.controller.config.vel_integrator_gain = 0.1 * odrv0.axis0.motor.config.torque_constant * odrv0.axis0.encoder.config.cpr
odrv0.axis0.controller.config.vel_limit = 10

odrv0.axis1.encoder.config.bandwidth = 100
odrv0.axis1.controller.config.pos_gain = 1
odrv0.axis1.controller.config.vel_gain = 0.02 * odrv0.axis0.motor.config.torque_constant * odrv0.axis1.encoder.config.cpr
odrv0.axis1.controller.config.vel_integrator_gain = 0.1 * odrv0.axis0.motor.config.torque_constant * odrv0.axis1.encoder.config.cpr
odrv0.axis1.controller.config.vel_limit = 10

odrv0.axis0.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL
odrv0.axis1.controller.config.control_mode = CONTROL_MODE_VELOCITY_CONTROL

odrv0.config.enable_brake_resistor = True
odrv0.axis0.motor.config.current_lim = 5
odrv0.axis0.motor.config.calibration_current = 5
odrv0.axis0.encoder.config.hall_polarity_calibrated = True 

odrv0.axis1.motor.config.current_lim = 5
odrv0.axis1.motor.config.calibration_current = 5
odrv0.axis1.encoder.config.hall_polarity_calibrated = True 

odrv0.save_configuration()
odrv0.reboot()

odrv0.axis0.requested_state = AXIS_STATE_MOTOR_CALIBRATION
odrv0.axis0.motor.config.pre_calibrated = True

odrv0.axis0.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION
odrv0.axis0.encoder.config.pre_calibrated = True

odrv0.axis1.requested_state = AXIS_STATE_MOTOR_CALIBRATION
odrv0.axis1.motor.config.pre_calibrated = True

odrv0.axis1.requested_state = AXIS_STATE_ENCODER_OFFSET_CALIBRATION
odrv0.axis1.encoder.config.pre_calibrated = True

odrv0.save_configuration()
odrv0.reboot()

odrv0.axis0.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis1.requested_state = AXIS_STATE_CLOSED_LOOP_CONTROL
odrv0.axis0.controller.input_vel = 2
odrv0.axis1.controller.input_vel = 2

odrv0.axis0.requested_state = AXIS_STATE_IDLE
odrv0.axis1.requested_state = AXIS_STATE_IDLE

上手く行けば以下のように2輪のモータを同時に速度制御する事が出来ます。

two2.gif

その他よく使用するコマンド

  • 指令値コマンド
odrv0.axis0.controller.input_pos = <turn>
odrv0.axis0.controller.input_vel = <turn/s>
odrv0.axis0.controller.input_torque = <torque in Nm>
  • エンコーダーの値の確認
odrv0.axis0.encoder.shadow_count
  • 外部電源電圧の確認
odrv0.vbus_voltage
  • エラー確認
dump_errors(odrv0)
  • 構成をODriveの永続メモリに保存
odrv0.save_configuration()
  • 構成変数を工場出荷時のデフォルトにリセット
odrv0.erase_configuration()
  • odriveの再起動
odrv0.reboot()
  • デバイスを大文字の16進数で一意に識別する番号
odrv0.serial_number

Odrivetoolアンインストール

以下のコマンドを実行することでOdriveをアンインストールすることが出来ます。

$ sudo pip3 uninstall odrive

無事アンインストール出来れば以下の内容が表示されます。

Successfully uninstalled odrive-0.5.2.post0

移行ガイド

v0.5.1からv0.5.2への変更は、以下のポイントです。

ブレーキ動作

ブレーキ抵抗器を使用する前に、次のように明示的に有効にする必要があります。

odrv0.config.enable_brake_resistor = True

次に、構成を保存して再起動し、設定を有効にします。

まとめ

  • odriveを使用してBLDCの単純な速度制御を行いました

参考文献

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3