🦔

eカート モーター制御について

2023/03/04に公開

Maker Fair Kyotoに出展が決まりました。

eカートのモーター制御について

eカートの最も重要なパーツであり、心臓部であるモーターコントローラーについて解説する。

eカートのモーターを制御しているモーターコントローラーはAmazonhttps://amzn.asia/d/2spl9cvで手に入る中国製の製品で、似たようなコントローラーは数多くある。この製品はLCD付きで24V/36Vに対応する350wのタイプである。左右のモーター用に2つのコントローラーを購入した。LCDは1つあればよいが、配線が同じものであることと、予備である(実はLCDを1つ短絡して壊してしまった)。
おそらくどの製品も簡素な説明資料があるだけで、使い方はネット(動画含む)で情報を集めて試行錯誤を重ねる必要がある。
幸いにもこのコントローラーのLCDディスプレイの機能説明資料がネットhttps://m.ja.aliexpress.com/item/4000319520169.html?gatewayAdapt=gloPc2jpnMsite(中ほどのView Allの中にLCDの詳細情報がある)で入手できたので、ほとんどの機能が理解できた。
一般的な用途は普通の自転車を電動化するものであるが、値段の割にかなり多機能なものとなっており、十分リーズナブルな製品である。
モーターコントローラー自体の配線によって機能を有効化・無効化したり、LCDにより詳細な設定を保存できたりする。
ここでは、使っている機能について解説し、raspberry pi picoを使用して制御をカスタマイズする方法について述べる。

モータードライバーの機能

配線方法

配線により有効化できる機能は以下の通り

  • イグニッション
    常にオンの状態にしている。
  • スロットル
    ハンドルバーに接続し、ハンドルバーを握ることにより、小から大となる信号をスロットルへ送る。
  • (リバース)
    説明書と実機とのバージョンが違うのか、本体にリバースの配線はなかった。但し、モーター位相認識の配線で反転設定することはできる。
  • 低電位ブレーキ信号
    今のところ使っていない。積極的なブレーキではなくスロットルを無効化する機能と理解。
  • ブレーキ信号
    スロットルと逆向きの信号を送る。ハンドルバーを離した状態で信号がMaxになるよう設定している。
  • モーター位相認識
    オス-メスのコネクターを繋いで電源を入れると定速度でモーターが回る。回転方向を変えたい場合は電源を入れた状態で接続を解除する。更に電源を入れ直すと反転する。
  • 外部電源
    バッテリーの電源そのものの外部出力端子。充電もこの端子で行う。2つのモーターコントローラーがあるので、1つはUSB出力に、もう一つは充電ポートに接続している。

LCDディスプレイ

モータードライバー単体では制御できる機能は限られているが、LCDディスプレイを使うことで、様々な機能が使える。
全ての機能を問題なく使えるわけではないが、LCDディスプレイで制御できる機能は以下の通り。

  • 速度表示、電源インジケーター、障害表示、総走行距離(ODO)、単一走行距離

  • 電源・モードボタン
    長押しで電源on/off。短押しでモード切り替え。設定時はパラメタ(P01〜P22)切り替え。
  • ギア・設定アップ、ダウンボタン
    通常はギアのアップダウン。アップ、ダウン両方のボタンを長押しすることで、設定モードに切り替わる。設定モードでは、設定値のアップダウンを行う。
  • パスワードを設定する。
    電源ボタンとアップボタンを同時に押すことでパスワード設定モードになる。パスワードは4文字の数字。
    以下、パラメタ設定。
  • P01 バックライトの明るさを設定する。
    バックライトの明るさを設定する。1は最も暗く、3は最も明るい。
バックライト明るさ
3 最も明るい設定とする。
  • P02 マイルまたはメートルを設定する。
    0はkm/h、1はマイルを意味する。
速度単位
0 km/hとする。
  • P03 バッテリー電圧を設定する。
    24/36/48/60v。
バッテリー電圧
24 24vに設定する。※現状のバッテリーの公称電圧は25.2vとなっているが、満充電時にはLCD上で28v以上になるので、充電ゲージがなかなか減らない状態となっている(逆に36vにすると常にエンプティとなる)。このため、バッテリーの減りは電圧で確認している。
  • P04 自動スリープ時間を設定する。
    0はスリープしない。1-60 スリープ時間 デフォルト設定 10分
スリープ時間
30 30分に設定する。
  • P05 ギアを設定する。
    0は0-3ギア、1は0-5ギア、2は0-9ギア、3は0-4ギア、4は0-6ギア
ギア
1 0-5とする。5段階の場合、通常は3で、少しパワーが必要なときに4とする。4と5にほとんど差はないため、5はほとんど使わない。
  • P06 リムサイズを設定する。
    インチで指定する。精度0.1インチ。スコープ5-50。既定値は26インチ。
リムサイズ
6.5 自転車であればリムの規格で決まっているが、使用しているタイヤはリムがないため、メーカー外寸表記の6.5インチとする。
  • P07 モーター磁極数比。
    磁性鋼の数と減速比をかけた数となる。数字が大きくなるほど低速になる。
モーター磁極数
5 実際の速度(iPhoneメーターアプリ)に合わせて比率を決めている。


要はリムサイズと合わせて速度の基準となる。P18の速度表示比で更に調整する。

  • P08 制限速度値を設定する。
    速度が設定値まで上がると出力を停止し、設定値より下がると出力を再開する。
制限速度
100 説明書きでは最高速度の設定と読み取れるが、出力のパーセンテージのような動作となる。低いギアで最高速度に達しないときでも速度が低くなる。制限はしない。
  • P09 スタートモードを設定する。
    0はゼロスタート、1はノンゼロスタート。スロットルは、時速6kmまで押すことで働く。
スタートモード
0 ゼロスタートとする。
  • P10 ランニングモードを設定する。
    0はペダルのみ、スロットルなし。1はスロットルのみ、ペダルなし。2はミックス。ペダルとスロットルの両方が機能する。
ランニングモード
1 スロットルのみとする。
  • P11 ペダルスタート感度を設定する。スコープ1-24。
    1は最も敏感。24 は最も鈍感。
ペダルスタート感度
1 ペダルモードは使用しないため、既定値のまま。
  • P12 ペダルスタート強度を設定する。スコープ1-24。

1は最も弱い。5は最も強い。

ペダルスタート強度
5 ペダルモードは使用しないため、既定値のまま。
  • P13 パスセンサータイプを設定する。
    5/6/8/10/12
パスセンサータイプ
6 PASセンサーは使用しないため、既定値のまま。
  • P14 コントローラ電流制限。
    この値<バッテリー最大放電電流である。デフォルト設定は12A。
バッテリー電流制限
12 29V(多めに見積)×12A=348Wで計算。
  • P15 コントローラ低電圧保護を設定する。スコープは設定値+/-6vで、これよりも低いと出力が止まる。
バッテリー最低電圧調整
19 最低電圧
※20Vまで電圧が落ちると充電することにしている。
  • P16 ODOをゼロクリアをする。
    このインターフェイスに切り替えて、アップボタンを6秒間長押しでゼロクリアする。

  • P17 オートクルーズを設定する。
    0はオートクルーズしない。1はオートクルーズする。クルーズに移行するには、数秒間速度を維持する。

オートクルーズ設定
0 オートクルーズは設定解除が直感的にできないし、手を離したときに制御が効かないため使用しない。
  • P18 速度表示比を設定する。
    スコープ50%-150%。P06のリムサイズとP07のモーター磁極数比の組み合わせによる速度表示をより正確に調整する。
速度表示比
100 速度表示比
  • P19 ギア、または異なるプログラム用を設定する。 |
    0はギア。1はギアではない。
速度表示比
0 ギアモード
  • P20 通信プロトコル タイプを設定する。
    0はnumber 2通信プロトコル
    1は5sプロトコル
    2/3 はスタンバイ。デフォルト設定は0
    プログラムを知っている人以外は変更しない。
通信プロトコル
0 デフォルト
  • P21 スロットルギアを設定する。
    0は計器制御スロットルギア。1はフルスロットル、ギア差別なし。
ブレーキ
0 デフォルト
  • P22 E-ABSを設定する。
    0はE-ABSブレーキなし。1はブレーキ電源OFF時にE-ABS回生制動
E-ABS
1 回生ブレーキを使用する。

※この機能の詳細情報はないため実機確認した範囲だが、坂道を下る際にバッテリーの値がわずかながら増えるところを見ると、確かに回生していると思われる。

raspberry pi pico によるカスタマイズ

やっと、ソフトウェアの登場である。

カスタマイズによる動作イメージ

  • 急発進防止
    スロットルバーの握り加減がわからず、急激に握ったりすると強力なモーターにより、(ウィリーのような)思わぬ動作をしてしまい、危険である。
    急激な操作を抑止するため、マイコン(raspberry pi pico)で速度制御する。

  • 緊急停止(未着手)
    危険なときにはとにかく止まるようにしたい。以下は案である。
    ・キルスイッチ的なもの
    ・一定距離離れると止まる
    ・音声認識により声で止める
    ・画像認識による自動ブレーキ

  • 楽々小回り(未着手)
    左右のモーターを別々に制御して楽に旋回できるようにする。

接続方法


  • 説明
    一つのスロットルの入力(アナログ入力:ADC0)に2つのモーター(PWM出力:GPIO0,1)が対応している。2つのモーターに出力差がある場合でも調整が可能となるように、それぞれのモーターに独立した出力を設定した。

ソース

  • 急発進防止
    このプログラムは、スロットルセンサーの値を読み取り、急な操作があった場合に緩やかに加速するように制御する。具体的には、前回の読み取り値との差分が一定以上ある場合には、直前の値に戻して急な操作をキャンセルし、それ以外の場合にはスロットルセンサーの値をそのままPWMのデューティー比に反映する。
    また、スロットルセンサーの値が一定の範囲を超えた場合には、それぞれ上限値と下限値に制限します。上限値は65535、下限値は18000としていますが、必要に応じて変更することができる。
    さらに、急な操作をキャンセルするための閾値(diff_limit)や、緩やかに加速するための時間差(diff_term)も調整可能である。
from machine import Pin, PWM
import machine
import utime

# PWMの設定
pwm_l = PWM(Pin(0))
pwm_r = PWM(Pin(1))
pwm_l.freq(10000)
pwm_r.freq(10000)

# スロットルセンサーの設定
sensor_throttle = machine.ADC(0)

# 前回の読み取り値を初期化
before_read = sensor_throttle.read_u16()

# 急な操作をキャンセルするための差分閾値、緩やかに加速するための時間差、制限値を設定
diff_term = 0.1
diff_limit = 10000
low_limit = 18000
high_limit = 65535

# 制限フラグの初期化
limit_over = False

# 無限ループでスロットルセンサーの値を読み取り、PWMのデューティー比に反映する
while True:
    reading = sensor_throttle.read_u16()

    # スロットルセンサーの値が上限値を超えた場合は上限値に制限する
    if reading > high_limit:
        reading = high_limit

    # 制限フラグがONの場合は前回の値に戻す
    if limit_over:
        if reading < low_limit:
            limit_over = False
            print("limit off")
        reading = before_read
    else:
        # 前回の値との差分が閾値を超えた場合は制限フラグをONにする
        if reading > before_read:
            if reading - before_read > diff_limit:
                limit_over = True
                print("limit over")
            else:
                # スロットルセンサーの値をPWMのデューティー比に反映する
                pwm_l.duty_u16(int(reading))
                pwm_r.duty_u16(int(reading))
        else:
            # スロットルセンサーの値をPWMのデューティー比に反映する
            pwm_l.duty_u16(int(reading))
            pwm_r.duty_u16(int(reading))

    # 値の確認のために、前回の値、現在の値、制限フラグを出力する
    print(str(before_read) + " " + str(reading) + " " + str(limit_over))

    # 前回の値を更新して、一定時間待つ
    before_read = reading
    utime.sleep(diff_term)
シンギュラリティ・ソサエティ

Discussion