LoginSignup
3

More than 5 years have passed since last update.

Kitronik :MOVE mini を MicroPython で制御する

Posted at

この記事はmicrobit Advent Calendar 2017の18日目の投稿です。

MicroPythonとmicrobit、どちらのAdvent Calendarに投稿しようか迷いましたが、こちらに投稿しておきます。

10月に購入済だった Kitronik :MOVE mini を MicroPython で制御してみました。

Kitronik :MOVE mini は、スイッチサイエンスからmicro:bit用 :MOVEミニバギーキットとして購入できます。

IMG_4186.JPG

中身はサーボモータドライバボードのmicro:bit用 Servo:Lite、サーボモータ2個、単4電池4本(要るのは3本なのに4本つけてくるところが大雑把でいいですね)、シャーシー用パーツ、組み立て用ネジ・ナット類、説明書(英語)です。

IMG_4187.JPG

組み立てるとこんなのになります。モータドライバボードとmicro:bit がくっつきすぎで、差し込めるUSBケーブルを探すのが大変です。一日目の投稿にあるように、間にワッシャー入れるのはよいアイデアですね。リセットボタンも普通には押せなくなってしまいますが、爪楊枝なんかをつかうとなんとか押せます。

IMG_4197.JPG

説明書は Microsoft PTX でのプログラミング方法を説明しています。また、説明書にも記述は無いのですが、今ではもっと便利なカスタムブロックも提供されています。

私としてはMicroPythonで動かしたいので、試してみました。

ボードについている5つのLEDはNeoPixel互換です。MicroPythonにもNeoPixelのAPIはあるので簡単だと思ったのですが、説明書の2章STEP15で使っている rotateブロックに相当するAPI が無かったので自作するしかありません。

そんなこんだで作ってみた LEDローテーションのプログラムが以下です(説明書の2章STEP15のものに相当します)。

from microbit import pin0, button_a, button_b, sleep
from neopixel import NeoPixel

COLOR_RED = (0xff, 0, 0)
COLOR_YELLOW = (0xff, 0xff, 0)
COLOR_GREEN = (0, 0xff, 0)
COLOR_BLUE = (0, 0, 0xff)
COLOR_VIOLET = (0x8a, 0xa2, 0xe2)
COLOR_PURPLE = (0xff, 0, 0xff)

np = NeoPixel(pin0, 5)

def light_up_pixels():
    np[0] = COLOR_RED
    np[1] = COLOR_YELLOW
    np[2] = COLOR_GREEN
    np[3] = COLOR_BLUE
    np[4] = COLOR_PURPLE

def turn_off_pixels():
    np.clear()

def rotate_pixels():
    save_pixel = np[0]
    for i in range(len(np)-1):
        np[i] = np[i+1]
    np[-1] = save_pixel

while True:
    if button_a.is_pressed():
        light_up_pixels()
    if button_b.is_pressed():
        turn_off_pixels()
    rotate_pixels()
    np.show()
    sleep(200)

これを転送して、ボタンAを押すと以下のようにLEDがローテーションし、ボタンBを押すとLEDが消えます。

IMG_4250.MOV.gif

さて、サーボモータのほうです。普通のサーボモータは180度くらいの可変範囲を持っていて、PWMで回転角度を制御するのですが、:MOVE mini で使われているのは、連続回転サーボ(Continuous Rotation Servo)というもので、連続して回転することができ、PWMも角度ではなく回転スピードを制御することになります。

MicroPythonでもPWM制御はできるのですが、PTXのようにサーボモータに最適化したAPIは持っていません。ちょと探してみたらこちらにサーボ用のクラスが公開されていたので、少しいじって利用させていただきました。結果として、説明書の8章STEP5に相当するものを実装してみたのが以下です。

from microbit import pin0, pin1, pin2, button_a, button_b, sleep
from neopixel import NeoPixel

class Servo:

    def __init__(self, pin, freq=50, min_us=600, max_us=2400, angle=180):
        self.min_us = min_us
        self.max_us = max_us
        self.us = 0
        self.freq = freq
        self.angle = angle
        self.analog_period = 0
        self.pin = pin
        analog_period = round((1/self.freq) * 1000)  # hertz to miliseconds
        self.pin.set_analog_period(analog_period)

    def write_us(self, us):
        us = min(self.max_us, max(self.min_us, us))
        duty = round(us * 1024 * self.freq // 1000000)
        self.pin.write_analog(duty)

    def write_angle(self, degrees=None):
        degrees = degrees % 360
        total_range = self.max_us - self.min_us
        us = self.min_us + total_range * degrees // self.angle
        self.write_us(us)

COLOR_RED = (0xff, 0, 0)
COLOR_WHITE = (0xff, 0xff, 0xff)
COLOR_OFF = (0, 0, 0)

np = NeoPixel(pin0, 5)
right = Servo(pin1)
left = Servo(pin2)

def forward():
    np[0] = COLOR_WHITE
    np[4] = COLOR_WHITE
    right.write_angle(0)
    left.write_angle(180)

def backward():
    np[0] = COLOR_RED
    np[4] = COLOR_RED
    right.write_angle(180)
    left.write_angle(0)

def stop():
    np[0] = COLOR_OFF
    np[4] = COLOR_OFF
    right.write_angle(90)
    left.write_angle(90)

while True:
    if button_a.is_pressed() and button_b.is_pressed():
        stop()
    elif button_a.is_pressed():
        forward()
    elif button_b.is_pressed():
        backward()
    np.show()
    sleep(200)

これを転送して、ボタンAを押すと白いヘッドライトを点けて前進、Bボタンを押すと赤いヘッドライトを点けて後進、A+Bボタン同時押しで停止します。

以下はこのプログラムを少し変えて遊んでみた例です。

IMG_4253.mov.gif

そのうち、radioも使ってリモコン化しようと思います。

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