#author("2021-11-24T09:05:03+09:00;2018-04-24T16:12:22+09:00","d7","d7")
[[授業時に配布した資料:http://yakushi.shinshu-u.ac.jp/robotics-ev3/]]
([[EV3を動かしてみる:http://yakushi.shinshu-u.ac.jp/robotics-ev3/]] 
http://yakushi.shinshu-u.ac.jp/robotics-ev3/ )
をアップしました。
下記のメモより詳しく書いてあります。

セットアップについては下記を参考に、実際のプログラム例は上記の資料を参考にしてください。

目次
#contents

* 参考サイト [#t34f3fc4]
- http://www.ev3dev.org/ (ev3devの開発元)
- https://media.readthedocs.org/pdf/python-ev3dev/latest/python-ev3dev.pdf (python-ev3のPDF文書)
- http://openrtm.org/openrtm/ja/node/5806 (産総研OpenRTM-aistのページ、日本語)

* 準備 [#q864ac9b]

http://www.ev3dev.org/docs/getting-started/ を参考に。

** OSのイメージをダウンロード [#sb77d4ec]
%% https://github.com/ev3dev/ev3dev/releases/download/ev3dev-jessie-2015-12-30/ev3-ev3dev-jessie-2015-12-30.img.xz %%

%% https://github.com/ev3dev/ev3dev/releases/download/ev3dev-jessie-2016-12-21/ev3dev-jessie-ev3-generic-2016-12-21.zip %%

https://github.com/ev3dev/ev3dev/releases/download/ev3dev-jessie-2017-02-11/ev3dev-jessie-ev3-generic-2017-02-11.zip
%% https://github.com/ev3dev/ev3dev/releases/download/ev3dev-jessie-2017-02-11/ev3dev-jessie-ev3-generic-2017-02-11.zip %%

%% https://github.com/ev3dev/ev3dev/releases/download/ev3dev-jessie-2017-06-09/ev3dev-jessie-ev3-generic-2017-06-09.zip %%

2018年4月現在のDebian本家の安定バージョン(stretch)と同じstretch版を使ってみる

https://oss.jfrog.org/list/oss-snapshot-local/org/ev3dev/brickstrap/2018-04-22/snapshot-ev3dev-stretch-ev3-generic-2018-04-22.img.xz

** microSDまたはmicroSDHCにコピー [#jeaf4320]
microSDXCは使えない。microSDのデバイス名が /dev/sdb とすると、以下のようにddでイメージをメディアに書き込む。
 xzcat ~/Download/ev3dev-jessie-ev3-generic-yyyy-mm-dd.img.xz | sudo dd bs=4M of=/dev/sdb

%% xzcat ~/Download/ev3dev-jessie-ev3-generic-yyyy-mm-dd.img.xz | sudo dd bs=4M of=/dev/sdb %%

 xzcat ~/Download/snapshot-ev3dev-stretch-ev3-generic-2018-04-22.img.xz | sudo dd bs=4M of=/dev/sdb
デバイス名が不明な場合は cat /proc/partitions などのコマンドで調べる。
USB経由で接続した場合は /dev/sdb のようなUSBメモリと同じようなデバイス名に、SDカードスロットに入れた場合は /dev/mmcblk0 のようなデバイス名になっていることが多い。



** 起動 [#c943330c]

microSDを本体のカードスロットにセットして電源ON(真ん中の四角いボタンを押す)。microSDが入っていれば、本体のOSではなくmicroSDのOS(ev3dev)が起動する

** ネットワークの接続 [#z38ad46a]

wifiのドングルを使うのがおそらく最も簡単。
brickmanのメニューが表示されたら、
「Wireless and Networks」→「Wi-Fi」で無線ネットワークを選ぶ。
接続できたら、ディスプレイ上部に表示されている、DHCPで取得したアドレスを確認しておく。
「Powered」をチェックすると「StartScan」で無線ネットワークをスキャンできる。
無線ネットワークを選択して接続できたら、ディスプレイ上部に表示されている、DHCPで取得したアドレスを確認しておく。

** sshでログイン [#ia48be56]

IPアドレスが192.168.2.30の場合、パソコン側から
 ssh robot@192.168.2.30
でログインできる(デフォルトのUIDは「robot」、パスワードは「maker」)。
Windowsの場合はTeraTermなどを使えばよい。

 localhost:~$ ssh robot@192.168.2.30
 robot@192.168.2.30's password: 
              _____     _
    _____   _|___ /  __| | _____   __
   / _ \ \ / / |_ \ / _` |/ _ \ \ / /
  |  __/\ V / ___) | (_| |  __/\ V /
   \___| \_/ |____/ \__,_|\___| \_/
 
 Debian jessie on LEGO MINDSTORMS EV3!
 
 The programs included with the Debian GNU/Linux system are free software;
 the exact distribution terms for each program are described in the
 individual files in /usr/share/doc/*/copyright.
 
 Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
 permitted by applicable law.
 Last login: Mon Dec 26 10:13:57 2016 from 192.168.2.21
 robot@ev3dev:~$ 

* Python でインタラクティブに動かす [#s538f8e8]

** pythonの起動 [#id4e94b7]
** python-ev3devのインストール [#i9d40f09]
(ev3dev-jessie-2017-06-09版ではイメージに含まれているのでインストール不要)

デフォルトではpython 2.7 が起動する。
%% python-ev3devをインストールする。(以前はOSイメージに入っていたはずだが、ev3dev-jessie-2017-02-11版には含まれていない。2017-04-24追記)%%

 robot@ev3dev:~$ python
 Python 2.7.9 (default, Aug 13 2016, 17:33:10) 
 [GCC 4.9.2] on linux2
 Type "help", "copyright", "credits" or "license" for more information.
 >>> 
%% robot@ev3dev:~$ sudo apt-get install python-ev3dev %%

また python3 というコマンドでpython 3.4を起動できる。
最近のOSイメージにはもともと収録されているので、インストール不要。(2018-04-24追記)

** pythonの起動 [#id4e94b7]

python3 というコマンドでpython 3.5を起動できる。

 robot@ev3dev:~$ python3
 Python 3.4.2 (default, Oct  8 2014, 14:47:30) 
 [GCC 4.9.1] on linux
 Python 3.5.3 (default, Jan 19 2017, 14:11:04)
 [GCC 6.3.0 20170118] on linux
 Type "help", "copyright", "credits" or "license" for more information.
 >>> 

pythonコマンドでは、最近のev3devがサポートしていない python 2.7 が起動してしまうので、特に理由がない限り python3 を使う。

// robot@ev3dev:~$ python
// Python 2.7.13 (default, Nov 24 2017, 17:33:09) 
// [GCC 6.3.0 20170516] on linux2
// Type "help", "copyright", "credits" or "license" for more information.
// >>> 

** モジュールのインポート [#gb5bbf8b]

 >>> import ev3dev.ev3 as ev3

** モータのインスタンスを生成 [#u9916a64]

 >>> m = ev3.LargeMotor('outA')

モータの各ポート名は、'outA' 'outB' 'outC' 'outD'。
小さい方のモータは、MediumMotor。

モータ・クラスについては http://www.ev3dev.org/docs/drivers/tacho-motor-class/ を参考に。

** モータのリセット [#g87607de]

 >>> m.reset()

** モータを回転させる [#s3b12bed]

モータのリセット後は、duty_cycle_sp(デューティ・サイクルのセットポイント)とspeed_spが0になっている。
回転させるためには、duty_cycle_spに0以外の-100から100までの値を指定し、speed_spに0から1050までの値を指定する
%%回転させるためには、duty_cycle_spに0以外の-100から100までの値を指定し、%% speed_spに %%0から1050%% -1000から+1000までの値を指定する。
最新のev3devでは、run-direct以外では常にレギュレーションがONになっているので、
duty_cycle_spを指定せずに、speed_spだけを指定する。
参考URL: https://sites.google.com/site/ev3python/learn_ev3_python/using-motors

 >>> m.run_forever(duty_cycle_sp=30,speed_sp=500)
 >>> m.run_forever(speed_sp=500)

あるいは、以下でも同じ動作。

 >>> m.duty_cycle_sp=30
 >>> m.speed_sp=500
 >>> m.run_forever()

** モータを止める [#p1e18470]

 >>> m.stop()

モータの止め方は'coast' 'brake' 'hold'の3種類。デフォルトは'coast'。指定の方法は、

 >>> m.stop(stop_action='brake')

のように値を渡すか、

 >>> m.stop_action='brake'
 >>> m.stop()

のようにする。

%% 新しいカーネル(Linux ev3dev 4.4.9-11-ev3dev-ev3)では、stop_commandがstop_actionに、
stop_commandsがstop_actionsに変更になっている。また、speed_spの値を指定しておかないとモータは回らない(最大値は1050)。%%
stop_commandsがstop_actionsに変更になっている。また、speed_spの値を指定しておかないとモータは回らない(-1000〜1000)。%%

** モータを一定時間回す [#vc2bab9e]

 >>> m.run_timed(time_sp=3000, duty_cycle_sp=50, speed_sp=500, stop_action='brake')
 >>> m.run_timed(time_sp=3000, speed_sp=500, stop_action='brake')

timeで指定する時間の単位は1/1000秒。

** モータを一定時間回す(sleep関数を使う方法) [#h602c8c4]

 >>> import time
 >>> m.run_forever(duty_cycle=50,speed_sp=500)
 >>> m.run_forever(speed_sp=500)
 >>> time.sleep(3)
 >>> m.stop()

sleep関数を使うためにtimeモジュールをインポート。sleepで指定する時間の単位は1秒。

** モータを一定時間回す(タイマ関を使う方法) [#q4697311]

上記のsleepを使った方法だと、sleepしている間は他の命令は実行できません。
他の命令を実行したい場合には次のようにタイマを使えば簡単です。

 >>> import time
 >>> ts = ev3.TouchSensor('in1')
 >>> t0 = time.time()
 >>> m.run_forever(duty_cycle=50,speed_sp=500)
 >>> m.run_forever(speed_sp=500)
 >>> while time.time()-t0 < 3:
 >>>     if ts.value() == 1:
 >>>         m.stop()
 >>> m.stop()

** モータを特定の角度だけ回す [#mfa5974d]

 >>> m.run_to_rel_pos(position_sp=360, duty_cycle_sp=70, speed_sp=500, stop_action='hold')
 >>> m.run_to_rel_pos(position_sp=360, speed_sp=500, stop_action='hold')

これは

 >>> m.reset()
 >>> m.run_to_abs_pos(position_sp=360, duty_cycle_sp=70, speed_sp=500, stop_action='hold')
 >>> m.run_to_abs_pos(position_sp=360, speed_sp=500, stop_action='hold')

と同じ。

** センサーの種類 [#i38f24e1]
-TouchSensor 	タッチセンサ
-ColorSensor 	カラーセンサ
-UltrasonicSensor 	超音波センサ
-GyroSensor 	ジャイロセンサ
-SoundSensor 	NXTのサウンドセンサ
-LightSensor 	NXTのライトセンサ
-InfraredSensor 	EV3の赤外線センサ(距離測定用)

** 超音波センサを使う [#n9745bd7]

 >>> us = ev3.UltrasonicSensor()
 >>> us.value()
 112

デフォルトの単位はcm(US-DIST-CM)のはずだが、なぜかmmで値が表示されている。

** 光センサを使う [#e95a60a1]

モード一覧

 >>> cs=ev3.ColorSensor()
 >>> cs.modes
 [u'COL-REFLECT', u'COL-AMBIENT', u'COL-COLOR', u'REF-RAW', u'RGB-RAW', u'COL-CAL']
 ['COL-REFLECT', 'COL-AMBIENT', 'COL-COLOR', 'REF-RAW', 'RGB-RAW', 'COL-CAL']

デフォルトのモードはCOL-REFLECT。

白い紙の1cmほど上で測ってみると

 >>> cs.value()
 58

黒い紙だと大抵ひと桁の値になる。

** タッチセンサを使う [#f3986658]

 >>> ts = ev3.TouchSensor('in3')
 >>> ts.value()
 0
 >>> ts.value()
 1

タッチセンサが押されていない状態で0、押された状態で1。

** ジャイロセンサを使う [#d647d973]

 >>> gs = ev3.GyroSensor()
 >>> gs.modes
 [u'GYRO-ANG', u'GYRO-RATE', u'GYRO-FAS', u'GYRO-G&A', u'GYRO-CAL']
 >>> gs = ev3.GyroSensor()
 ['GYRO-ANG', 'GYRO-RATE', 'GYRO-FAS', 'GYRO-G&A', 'GYRO-CAL']
 >>> gs.mode
 u'GYRO-ANG'
 >>> gs.value()
 -135
 >>> gs.mode = 'GYRO-RATE'  # モードの変更
 >>> gs.value()
 0

** 応用 [#v7ce3ef9]
 >>> import ev3dev.ev3 as ev3
 >>> import time
 >>> ts = ev3.TouchSensor('in1')
 >>> cs = ev3.ColorSensor('in2')
 >>> while ts.value() == 0:
 ...     if cs.value() > 30:
 ...         m.run_forever(duty_cycle_sp=50)
 ...         m.run_forever(speed_sp=500)
 ...     else:
 ...         m.stop(stop_action='brake')
 ...     time.sleep(0.1)
 ...

** pythonの終了 [#s5162f6e]

control-D

* スクリプトの作成と実行 [#hbba8002]

** スクリプトの編集 [#a0a3146c]
エディタ(nanoまたはvi)で次のようなスクリプトを作る。ファイル名は例えばtest.pyのようにpyという拡張子を付けておくと便利。

 robot@ev3dev:~$ nano test.py

 #!/usr/bin/python
 #!/usr/bin/python3
 # -*- coding: utf-8 -*-
 
 import ev3dev.ev3 as ev3
 import time
 
 motor_left = ev3.LargeMotor('outA')
 motor_left.run_forever(duty_cycle_sp=50)
 motor_left.run_forever(speed_sp=500)
 time.sleep(3)
 motor_left.stop(stop_action='brake')

** スクリプトを実行可能に [#ze46f97b]

 robot@ev3dev:~$ chmod +x test.py

** スクリプトの実行 [#f870f300]

 robot@ev3dev:~$ ./test.py

ここで./は現在のフォルダ(ディレクトリ)を表す(ファイル名だけだとパスがつながっていないのでエラーになる)

* ipython notebookで使う [#k7f451a3]
* ipython notebookで使う (obsolete) [#k7f451a3]

https://ipython.org/ipython-doc/1/interactive/public_server.html を参考に

** ipython-notebookのインストール [#a62079cd]
 robot@ev3dev:~$ sudo apt-get update
 robot@ev3dev:~$ sudo apt-get install ipython-notebook

** ipythonの設定 [#oa2c4567]
nbserverという名のプロフィールを作ってみる

 robot@ev3dev:~$ ipython profile create nbserver

この命令を実行すると ~/.ipython/profile_nbserver というディレクトリが作成される。
その中の ipython_notebook_config.py というファイルを編集して、
とりあえず以下の指定をする。

 c.NotebookApp.ip = '*'
 c.NotebookApp.open_browser = False

** notebook serverの起動とアクセス [#zf20811a]

 robot@ev3dev:~$ ipython notebook --profile=nbserver

でサーバを起動すると、パソコンのブラウザから http://192.168.2.30:8888/ のようなアドレスでnotebookにアクセスできる (ev3のIPアドレスが192.168.2.30の場合)。デフォルトのポートは8888。

* jupyter notebook で使う [#jf42d8d8]

** Jupyter notebook のインストール [#n970fb72]

Debian jessieにはjupyterパッケージがないので jessie-backportsからインストールする。

まず、/etc/apt/sources.list.d/jessie-backports.list というファイルを新規に作成して次の一行を書いておく。

 deb http://ftp.jp.debian.org/debian jessie-backports main contrib non-free

updateした後、jupyter-notebookというパッケージをインストールすれば、とりあえずjupyterでpythonを使う上で必要なものも自動的にインストールしてくれる。

 robot@ev3dev:~$ sudo apt-get update
 robot@ev3dev:~$ sudo apt-get install -t jessie-backports jupyter-notebook

次に設定ファイルを作成して編集しておく。

 robot@ev3dev:~$ jupyter-notebook --generate-config

とすると
/home/robot/.jupyter/jupyter_notebook_config.py  というファイルが生成されるのでこれを編集。
とりあえずリモートから使うために以下の項目を設定しておく(もとのファイルではコメントアウトされている)。

 c.NotebookApp.ip = '*'
 c.NotebookApp.notebook_dir = '/home/robot/jupyter'
 c.NotebookApp.open_browser = False

ここで指定した作業用のディレクトリを作成しておく。

 robot@ev3dev:~$ mkdir ~/jupyter

IPアドレスやパスワードでアクセスを制限したい場合は、
http://jupyter-notebook.readthedocs.io/en/latest/public_server.html
あたりを参考に。

** Jupyter notebookを起動 [#ze58f8a2]

notebook を起動する

 robot@ev3dev:~$ jupyter-notebook 

これでパソコンのブラウザを開いて http://192.168.2.30:8888/ のようなURLでアクセスできる。
デフォルトのポートは8888番(設定ファイルで変更可能)。

* MQTTを使った通信 [#g90e4a99]

MQTTという軽量プロトコルを使った通信が
http://www.ev3dev.org/docs/tutorials/sending-and-receiving-messages-with-mqtt/
で紹介されている。

MQTTではpublisher(出版者)が発するメッセージをbroker(仲介者)がsubscriber(購読者)へ配信する。
MQTTは、EV3間の通信だけでなく他のデバイス間でもいろいろと使える。

** ブローカのインストール [#gbde9fb5]
サーバソフト(ブローカ)としてオープンソースのmosquittoを使う。
ネットワークに接続されている機器ならどれにインストールしてもかまわないが、
以下では、
一方のEV3を他方のEV3のリモコンとして使う簡単な例を挙げ、
EV3の一つをbrokerとしても使う方法を紹介する (他のEV3やパソコンにインストールする必要はない)。

上のev3devのサイトではpublisher側(リモコン側)にブローカをインストールしているが、
パソコンなどからでも直接コントロールできるように、リモコン側のEV3ではなく実際に動く側のEV3にブローカをインストールする(もちろんリモコン側にブローカをインストールした場合でも、そのブローカのEV3を起動しておけば、パソコンともう一方のEV3の間の通信は可能)。

 robot@ev3dev:~$ sudo apt-get update
 robot@ev3dev:~$ sudo apt-get install mosquitto

インストールが完了すればサーバが立ち上がる。チェックするには

 robot@ev3dev:~$ sudo service mosquitto status

デフォルトのポートは1883番。

** クライアントのインストール [#tb7a187f]

ブローカにメッセージを送信したり、ブローカからメッセージを購読したりするデバイスやそのためのソフトをMQTTのクライアントと呼ぶ。ブローカ(サーバ)をインストールしたEV3を同時にクライアントとして動作させることも可能。

pythonからMQTTを使うために、各EV3(とパソコン)に[[paho:https://eclipse.org/paho/]]のpython用ライブラリをインストール。
pythonからMQTTを使うために、各EV3(とパソコン)に[[paho:https://eclipse.org/paho/]]のpython用ライブラリをインストール。(その前にpythonパッケージをインストールするためのツールとしてpipをインストールしておく)

 robot@ev3dev:~$ sudo easy_install paho-mqtt
 robot@ev3dev:~$ sudo apt-get install python3-pip
 robot@ev3dev:~$ sudo pip3 install paho-mqtt
// robot@ev3dev:~$ sudo easy_install paho-mqtt

パソコン上にもpaho-mqttをインストールしておくと便利。

paho-mqtt詳細については、 https://pypi.python.org/pypi/paho-mqtt を参照のこと。

** サンプルプログラム [#oe24c9cc]
一方のEV3に接続したモータをアクセルのように使って他方のEV3のモータのスピードをコントロールするプログラムを作ってみる。ただしブローカは%%コントローラ側(パブリッシャー側)%%受信側のEV3で動作させている。

パブリッシャー(送信側)のプログラム

 #!/usr/bin/env python
 #!/usr/bin/python3
 import paho.mqtt.client as mqtt  # pahoのライブラリをインポート
 import ev3dev.ev3 as ev3
 import time
 
 ts = ev3.TouchSensor('in1')   # プログラム停止用のタッチセンサ
 m = ev3.LargeMotor('outA')    # コントローラとして使うモータ
 m.reset()
 duty_cycle_A = 0     # 相手側モータのduty_cycle_spとして送信する値を格納するための変数
 speed_A = 0     # 相手側モータのspeed_spとして送信する値を格納するための変数
 
 client = mqtt.Client()        # MQTTのクライアントを生成
 client.connect("192.168.2.30",1883, 60) # ブローカ(192.168.2.30)の1883番portに接続
                                      # (60秒以上接続がないと切断)
 
 while (ts.value() == 0):      # タッチセンサが押されていない間だけ繰り返し
   pos = m.position            # 現在のモータのポジションを取得
 
   if (pos > 90):
     duty_cycle_A = 100
     speed_A = 900
   elif (pos < -90):
     duty_cycle_A = -100
     speed_A = -900
   else:
     duty_cycle_A = pos*10/9   # ポジションからduty_cycleの値を計算(90度で最大になるようにした)
     speed_A = pos*10   # ポジションからspeed_spの値を計算(90度で最大900になるようにした)
 
   client.publish("ev3/outA", duty_cycle_A)  # "ev3/outA"というトピックスでduty_cycle_Aの値をブローカに送る
   client.publish("ev3/outA", speed_A)  # "ev3/outA"というトピックスでspeed_Aの値をブローカに送る
   time.sleep(0.01)
 
 client.disconnect() # 切断

サブスクライバ(受信側)のプログラム

 #!/usr/bin/env python
 #!/usr/bin/python3
 
 import paho.mqtt.client as mqtt
 import ev3dev.ev3 as ev3
 import time
 
 ts = ev3.TouchSensor('in1')  # プログラム停止用のタッチセンサ
 m = ev3.LargeMotor('outA')   # 動作確認用のモータ
 m.reset()
 
 def on_connect(client, userdata, flags, rc):  # ブローカに接続した時に実行される関数(コールバック関数)を定義しておく
   print("Connected with result code "+str(rc))
   client.subscribe("ev3/outA")                # "ev3/outA"というトピックスを購読
   m.run_direct()                              # モータの属性変更が即時に反映されるモード
 
 def on_message(client, userdata, msg):        # メッセージを受け取った時に実行される関数(コールバック関数)を定義しておく
   m.duty_cycle_sp = int(msg.payload)            # payloadという変数にメッセージが入る
   m.speed_sp = int(msg.payload)               # payloadという変数にメッセージが入る
                                                 # メッセージ自体はutf-8の文字列なので int に変換しておく
 
 client = mqtt.Client()            # MQTTのクライアントを生成
 client.on_connect = on_connect    # 上で定義したコールバック関数を渡す
 client.on_message = on_message    # 上で定義したコールバック関数を渡す
 
 client.connect("localhost",1883, 60)  # ブローカ(自分自身なのでlocalhost)の1883番ポートに接続 (Keep Alive は60秒)
 client.loop_start()               # メッセージ受信ループの開始
 
 while(ts.value() == 0):  # タッチセンサが押されていない間、繰り返し
   time.sleep(0.01)
 
 client.loop_stop()  # 受信ループを停止
 client.disconnect() # 接続を切断
 m.stop()            # モータ停止

**MQTTでパソコンからEV3を操作する [#m41a65ec]
上のsubscriber側のプログラムはそのまま使える。

publisher側のプログラムをパソコンで作成してもよいが、mosquitto-clients というツールを使えばシェルから(コマンドラインで)直接メッセージをパブリッシュできる。

まずはパソコンに mosquitto-clients をインストール

 $ sudo apt-get install mosquitto-clients

メッセージを送ってみる

 $ mosquitto_pub -h 192.168.2.30 -t 'ev3/outA' -m "30"

別のターミナルを開いて自分自身でトピックをsubscribeすることもできる

 $ mosquitto_sub -h 192.168.2.30 -t 'ev3/outA'

上の mosquitto_pub で値をいろいろ送信してみると、その都度その値がターミナルに表示される。
Control + C で終了。


2016年5月31からのこのページのだいたいの訪問者数:
本日&counter(today);
昨日&counter(yesterday);
合計&counter(all);
合計&counter(total);


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS