以下の内容はhttps://supernove.hatenadiary.jp/entry/2025/01/22/100000より取得しました。


Pythonでルンバをハックしてみた

新年あけましておめでとうございます(年明けて3週間経つけどw)

今年はもう少し更新頻度を上げていきたいところです。

さて、その昔ハードオフ徘徊をしていたことがありました。

ちょうどこのブログを書いてたときのことです。

supernove.hatenadiary.jp

この時はGPUを探しに行ってたのですが、ジャンク品が入った青いかごを見てた時にたまたまiRobotのロゴが書かれたUSBケーブルを見つけました。

もしかしたらこれを使えばルンバを簡単にハックできそうだと思った僕はとりあえず買っておいたわけです。

買ったはいいものの実家ではルンバを自由に動かせるほど広いスペースが無くずっとルンバを寝かせていたので、買ったケーブルは全く出番がなかったです。

で、去年引っ越した時にルンバを実家から持ち込んで動かしてみたらリビングがまぁまぁ広いので大活躍するようになりました。これはずっと寝かせてたケーブルでハックできるチャンスだ!

というわけで、今回は長年使われていなかったiRobotのUSBケーブルを使ってルンバをハックできるか試してみました。

用意するもの

ハードウェア

OS・ソフトウェア

  • Raspberry Pi OS 12(bookworm)
  • Python 3.11.2(デフォルトでセットアップされているもの)

僕はたまたまiRobotのUSBケーブルを見つけましたが、無いときはRaspberry PiのGPIOを使ってコネクタにジャンパーワイヤーで直接つなげる方法もあります。

ジャンパーワイヤーを使う手順は以下のからあげさんのブログが参考になります。

karaage.hatenadiary.jp

接続

今回使用したモデルは持ち手を上げるとルンバオープンインターフェースのコネクタが隠れているので、そこにUSBケーブルのインターフェース端子を差し込みます。

差し込むとケーブルのLEDが光りました(この時点でケーブルの断線がなさそうだったので一安心)

そしてRaspberry PiにUSB端子を接続すればハードウェアのセットアップは完了です。

Raspberry Piから lsusb を叩いたときに以下のデバイスが表示されたらUSB接続は正常にできています。

Bus 001 Device 002: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC

セットアップ

続いてRaspberry Piのセットアップを行います。

久しくRaspberry Piを触ってなくて、そのままpipインストールをすると以下のエラーが出ます。

error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.

    If you wish to install a non-Debian-packaged Python package,
    create a virtual environment using python3 -m venv path/to/venv.
    Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
    sure you have python3-full installed.

    For more information visit http://rptl.io/venv

note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.

どうやら仮想環境をセットアップするか、エラーを無視するオプションを付ける必要があるようです。

せっかくなので今回はルンバハック用の仮想環境を用意していきます。

仮想環境は以下のコマンドで作成します(久々にPythonの仮想環境用意した…)

python3 -m venv roombahack

仮想環境を有効にするときは以下のコマンドを実行します。

source roombahack/bin/activate

実行し、以下の通りターミナルプロンプトに作成した仮想環境名が表示されたら仮想環境は正常にセットアップされています。

(roombahack) pi@raspberrypi:~ $

ルンバのシリアルインターフェースはオープンに公開されているので、PySerialを使えば通信できますが今回はPipで公開されているルンバをPythonで操作できるようにした以下のライブラリがあったのでこれをインストールしてみます。

github.com

インストールは以下のコマンドを実行するだけです。

pip install pyroombaadapter

ハックする

とりあえず動かしてみる

まずはライブラリのレポジトリにあった動き回るサンプルを動かしてみます。

以下のソースコードをファイル名 move_around.py として保存します。

"""
    Go and back example with roomba
"""
from time import sleep
import math
from pyroombaadapter import PyRoombaAdapter

PORT = "/dev/ttyUSB0"
adapter = PyRoombaAdapter(PORT)
adapter.move(0.2, math.radians(0.0))  # go straight
sleep(1.0)
adapter.move(0, math.radians(-20))  # turn right
sleep(6.0)
adapter.move(0.2, math.radians(0.0))  # go straight
sleep(1.0)
adapter.move(0, math.radians(20))  # turn left
sleep(6.0)

#Print the total distance traveled
print(f"distance: {adapter.request_distance()} mm, angle: {adapter.request_angle()} rad")

move_around.pyを実行し、以下の通り前進したり回転したら問題ありません。

ルンバが停止して最終的に以下のように移動距離と、動いた角度が表示されたら動作確認成功です。もし何も表示されない場合は、ルンバを接続し直すなどして再度試してみてください。

distance: -559 mm, angle: 0.7330382858376184 rad

音を鳴らす

更にドキュメントを見ていると send_song_cmd で自由にメロディを鳴らすことができるようです。

atsushisakai.github.io

音階はMIDIのノートナンバーを指定することで鳴らしたいメロディを鳴らすことができます。また1音の長さもリストで指定することで細かくできるので、MIDIを触ったことある方であれば簡単に設定ができるはずです。

僕はMIDIを触ったことが無いので以下のサイトを頼りにノートナンバーを設定しました。

www.asahi-net.or.jp

このノートナンバーを頼りに名古屋でおなじみの名鉄ミュージックホーンをルンバで鳴らしてみるコードを用意しました。

実際に耳コピしてみたら、なんとたったの3音で構成されているのと音の長さも2種類用意すれば充分再現できました。

以下のソースコードplay_sound.py として保存します。

"""
   Play Meitetsu music horn
"""
from time import sleep
from pyroombaadapter import PyRoombaAdapter

PORT = "/dev/ttyUSB0"
adapter = PyRoombaAdapter(PORT)

e4 = 64
db5 = 73
a4 = 69

# note lengths
MEASURE = 160
HALF = int(MEASURE / 2)
Q = int(MEASURE / 4)

adapter.send_song_cmd(0, 10,
            [e4, db5, a4, e4, db5, a4, e4, db5, e4, a4],
            [Q, Q, Q, Q, Q, Q, Q, Q, Q, HALF]) # set song
sleep(1.0)
adapter.send_song_cmd(1, 7,
            [a4, e4, db5, a4, e4, db5, a4],
            [Q, Q, Q, Q, Q, Q, HALF]) # set song
sleep(3.0)

play_sound.py を動かすと以下の通りルンバで再現した名鉄ミュージックホーンが流れます(音色的にパノラマカーに近い)

www.youtube.com

ホームベースに戻す

それでは最後にホームベースにルンバを戻してみます。

ホームベースに戻すときはルンバの「Dock」ボタンを押せば帰すことができますが、実はこれもPythonで制御することができます。

send_buttons_cmd(dock=true) と記述するだけでDockボタンを押したときと同じ挙動を再現できます。

というわけで駅に停車する時の如くミュージックホーンを鳴らしてホームベースに戻すコードを書いてみます。

以下のソースコードnagoya_roomba.py として保存します。

"""
   Return to Dock with Meitetsu music horn
"""
from time import sleep
from pyroombaadapter import PyRoombaAdapter

PORT = "/dev/ttyUSB0"
adapter = PyRoombaAdapter(PORT)

e4 = 64
db5 = 73
a4 = 69

# note lengths
MEASURE = 160
HALF = int(MEASURE / 2)
Q = int(MEASURE / 4)

adapter.send_song_cmd(0, 10,
            [e4, db5, a4, e4, db5, a4, e4, db5, e4, a4],
            [Q, Q, Q, Q, Q, Q, Q, Q, Q, HALF]) # set song
sleep(1.0)
adapter.send_song_cmd(1, 7,
            [a4, e4, db5, a4, e4, db5, a4],
            [Q, Q, Q, Q, Q, Q, HALF]) # set song
sleep(3.0)

# Retrun to dock
adapter.send_button_command(dock=True)

print("Done")

実際に動かしてみると、ミュージックホーンを鳴らしてホームベースに戻るようになります。

www.youtube.com

まとめ

今回はジャンクで見つけたシリアルケーブルを使ってPythonでルンバをハックしてみました。

ルンバハック自体は昔からあるので何番煎じぐらいの内容ですが、ハードウェアやインターフェースが最初からよく定義されているおかげで今でもちゃんと動いたのはよかったです。

何よりずっと使ってなかったケーブルが卒なく使えて、ハードオフの青かごの中で一番掘り出し物を手に入れてた満足感と同時に今までなんでもっと早く触らなかったんだと後悔しましたw。

次はまた久々にROSを入れてあれこれ遊んでみようと思います(忙しくなりそうな気もするのでどうなることやら…)




以上の内容はhttps://supernove.hatenadiary.jp/entry/2025/01/22/100000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14