ハードウェアの改良

Ver 1.0としてはこれで

ogochan
ロボットネズミ

この前のエントリで試運転までできました。

動くようになってみると、いろいろ問題に気がついてしまいます。

そこで今回は「ちゃんと動く」ことを目標にハードウェアを修正しました。

動かして見つけた問題点

前回動かしてみて、動くことは動いたのですが、いろいろ問題がありました。

  • モータドライバが不安定で認識しないことがある
  • 電源スイッチがないので電池を入れたり抜いたりが面倒臭い
  • センサーがない

それぞれについて説明して行きます。

モータドライバが不安定

前回も書いたのですが、モータドライバがうまく認識されないことがありました。

前回はパスコンを入れることで随分と改善してたのですが、それでもたまにおかしくなることがありました。起きてしまうと、状態によっては電源断しても回復しなかったりしてました。

一応パスコンは入れたので、電源を入れた時のショックでおかしくなることは随分減ったと思うのですが、完全ではなかったようです。次に書くように「電源スイッチ」を実装してなかったので、スイッチ代わりに電池を入れたり抜いたりしていたせいもあって、そういったことも問題にあるようです。

一応、モータドライバはモータがOFFの時にはほぼ無視できる程度の電流しか流れないこともあって電源スイッチはなしでも良さそうなのでスイッチをつけていなかったのですが、モータドライバ自体がハングアップしてしまったら、それから回復する方法がありません。

電源スイッチがない

つけてないです。なのでないのは当たり前。

電源スイッチをちゃんとつけようと思うと、外からスイッチをアクセスする方法を提供しなければなりません。ところが、元々あった電源スイッチはMaixBitを置くために外してしまったので、そこにはつけられません。筐体の加工はなるべく避けたいと思っていたので、「スイッチを操作するための穴」をあけるという加工はしたくありません。

そんなこともあって、3Vのモータ電源も3.7VのLiPO電池も、スイッチがありません。そうなると、電源の操作をする時には、電池そのものをつけたり外したりすることになります。結構不便なだけではなくて、前述のような不安定さの元でもありました。

センサーがない

センサーがないというのは嘘で、カメラとマイクがついてますね。でも、これらを動かすには、結構な手当が必要になります。この連載ではstep by stepでやって行くつもりなので、いきなり高度な手当が必要なことはしたくありません。簡単なところからやって行きたいですね。

そうなると、カメラ以外の方法で障害物を検出する術が欲しいところです。

これらは「ちゃんとしたハードウェア」を作った時に整備するつもりでいましたが、実験する時にも結構障害となったので、早めに対応しようと思って手を入れました。

改良したハードウェア

以下が改良したハードウェアの回路図です。

前回の回路図と比較すると、回路図の下の方にいくつか追加されているのがわかります。

モータ回路のスイッチ

まず目につくのは、トランジスタ(FET)ですね。これはモータ回路の電源スイッチです。GPIO15を1にすると、トランジスタがON。DRV8830にスイッチが入ります。N-MOS FETによるローサイドスイッチになっています。

スイッチはローサイトでもハイサイドでも結局は同じはずなのですが、

  • ハイサイドにするとP-MOS FETが必要になる上にスイッチが面倒
  • GNDが通電していると、I2Cの線に3.3Vがかかったまま

ということで、ローサイドスイッチの方が安心だなということで、ローサイドスイッチにしました。

ここには最大2A程度流れるので、ちょっと大き目のトランジスタにしてあります。と言ってもサイズはTO-23、つまり普通のちっちゃいチップトランジスタ(IRML6344)です。これでも5Aくらい流せるので、容量的には問題ないでしょう。

衝突センサー

もう一つはBUMPとゆーラベルのついた入力です。この先には、1回路2接点のマイクロスイッチがつながります。普段はGNDで、スイッチを入れると3.3Vになります。

このスイッチは元々壁検出のためについていたマイクロスイッチ回路です。

タミヤの「壁づたいメカ工作セット(ねずみ)」

このエントリの回路図に出て来るスイッチです。

このスイッチは元々は左側の壁を検出するようにセンサー棒がついていましたが、これをちょっと余分に曲げて、前方の障害物に当たった時にも反応するようにしてあります。

こうしてあると、前にも反応します。

コンデンサや抵抗はチャタリング防止回路です。値は適当です。

電源スイッチ

回路図の範囲にないですが、電源スイッチをつけました。

これは元々あった電源スイッチを使ったものです。

モータ回路のスイッチはトランジスタで作ってしまったので、物理で電源スイッチが必要なのは3.7Vの回路だけになりました。

電池をつないでスイッチを入れた時には、絶対にUSBがつなげられませんね。前もそうでしたけど、今回はスイッチ操作だけになったので、逆に危険になってしまいました。

元々あったマイクロスイッチも電源スイッチも使ってしまったので、元々あった部品のうち使ってないのは、電池箱の接点だけとなりました。あとは、ちょっとのビニール被覆線。捨てるものがないのはエコですね。また、部品を新規に買うものも少ないので、地方の人も安心。今のところMaixBit以外に部品は、1000円かかってないはずです。

動作確認

さて、ハードウェアが出来たので、ソフトの方も対応して動作確認をしてみます。

プログラムはこんな感じで。

from machine import I2C, Timer, PWM
from Maix import GPIO
import time, utime, sys
from fpioa_manager import fm


FORWARD = 0x01
BACKWARD = 0x02
STOP = 0x00
BREAK = 0x03
LEFT = 98
RIGHT = 96

SCL = 9
SDA = 10
LED_B = 14
MOTOR_SWITCH = 15
BUMP = 17

p = 0x18

def init():
    global io_bump
    global i2c
    global io_motor

    fm.register(MOTOR_SWITCH, fm.fpioa.GPIO0)
    fm.register(BUMP,         fm.fpioa.GPIO1)
    #fm.register(LED_B, fm.fpioa.GPIO0)
    io_motor = GPIO(GPIO.GPIO0, GPIO.OUT)
    io_bump = GPIO(GPIO.GPIO1, GPIO.IN, GPIO.PULL_DOWN)
    i2c = I2C(I2C.I2C0, mode=I2C.MODE_MASTER, freq=100000, scl=SCL, sda=SDA)
    devices = i2c.scan()
    print(devices)


def motor_start():
    io_motor.value(1)
    utime.sleep_ms(500)
def motor_end():
    utime.sleep_ms(500)
    io_motor.value(0)

def motor(side, direction, power):
    vol = bytearray(1)
    vol[0] = 0x80
    i2c.writeto_mem(side, 0x01, vol[0], mem_size=8)
    time.sleep_ms(2)
    vol[0] = ( power << 2 ) | direction
    i2c.writeto_mem(side, 0x00,  vol[0], mem_size=8)
    time.sleep_ms(2)

def main():
    init()
    motor_start()

    tim = Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PWM)
    ch = PWM(tim, freq=500000, duty=50, pin=LED_B)

    while True:
        ch.duty(100)
        motor(LEFT, FORWARD, p)
        time.sleep_ms(500)
        motor(LEFT, STOP, p)
        ch.duty(0)
        print(io_bump.value())
        if ( io_bump.value() == 1 ):
            motor_end()
            sys.exit()
        motor(RIGHT, FORWARD, p)
        time.sleep_ms(500)
        motor(RIGHT, STOP, p)

main()

試行錯誤した後に綺麗に(?)掃除しました。

init()はポート等の設定です。

GPIOにはGPIOGPIOHSとがありますが、今回はどっちでもいいです。

motor_start()はモータ回路への給電開始、motor_end()はモータ回路への給電停止です。IO_15を操作するだけですから1つの手続きでいいじゃんって話もありますが、将来あれこれあるかも知れないので、別の手続きにしてあります。

main()の中を見れば、何をしているかわかると思います。左右のモータを交互に動かしながら---つまりジグザグに進みながら---障害物に当たったらモータを停止して終わりということになってます。もうちょっとマシにするのであれば、障害物に当たった時にちょっとバックしてちょっと向きを変えて... ってやればいいですね。それだけでルンバ的な感じにはなるでしょう。

おわりに

いろいろありますが、とりあえずハードウェアのVer 1.0としてはこれで終わりということにしたいと思います。この他に何とかしたいと思っているのは、

  • RumiCarのように左右に距離センサーをつける
  • 移動距離のセンサーをつける

というのがあります。これらが出来ると、もうちょっとマシな自己位置推定が出来るので、いろいろ面白いなと思います。

とは言え、いずれも現在の筐体でやるのは難しそうなので、今回はここまでにしておこうと思います。これらについては、Ver 2.0のハードウェアを作る時に考えます。また、何らかの「ラジコン」があると面白いなと思うのですが、これも保留にして次に進めたいと思います。基板起こす時には考えるかも知れません。

次回はカメラを動かして何かをさせるためのソフトウェアをやろうと思います。