ラビット・エンジニアリング

趣味の電子工作を、備忘録もかねて・・・・

【Python備忘録】Pythonプログラムで、sinやcosなどの数式関数を使えるようにしてみた。

目標

Pythonプログラムで、sinやcosなどの数式関数を使えるようにしたい。

 

結論

Pythonの対話モードで、以下のコマンドを入力して、numpyをが使えればOK

>>> import numpy as np

ModuleNotFoundError: No module named 'numpy' とエラーが出たら、この記事の続きを読んでnumpyをインストールして使えるようになります。

 

背景

Pythonプログラムで三角関数を使おうとしたら、初期設定では使えなかったので使えるようにしてみた。

 

MathとNumpy

Pythonで数式関数を使うには、2通りの方法があります。

  • Mathモジュールを使う
  • numpyを使う

numpyは、関数の入力に配列が使えるので、numpyつかうことにした。たとえば関数fに変数x1とx2の2つの入力値に対する計算をしたい場合、

  • Mathの場合: y1=f(x1), y2=f(x2) 別々に計算が必要
  • numpyの場合:[y1,y2]=f([x1,x2]) 配列や行列使って一気に計算可能。

 

 

設定方法

numpyが使えないことの確認。対話モード(コンソールでpython3と入力)にして、下記を入力。

>>> import numpy as np
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'numpy'

 

ModuleNotFoundError: 要するにnumpy入っていないとエラーが出ます。

 

 

pipでインストール

pip install numpyしてみた。 

usagi@usagi-mba ~ % pip install numpy
Traceback (most recent call last):
File "/usr/local/bin/pip", line 6, in <module>
from pip._internal.cli.main import main
ModuleNotFoundError: No module named 'pip._internal.cli.main'

 

pipだとエラーが出て進まないので、pip3で再トライ。

usagi@usagi-mba ~ % pip3 install numpy
Collecting numpy
Downloading numpy-1.21.0-cp39-cp39-macosx_11_0_arm64.whl (12.1 MB)
|████████████████████████████████| 12.1 MB 10.5 MB/s
Installing collected packages: numpy
Successfully installed numpy-1.21.0
WARNING: You are using pip version 21.1.1; however, version 21.1.3 is available.
You should consider upgrading via the '/opt/homebrew/opt/python@3.9/bin/python3.9 -m pip install --upgrade pip' command.

 

numpyのインストール完了。pipのバージョンが最新じゃないと警告されたのでついでにpipのバージョンをアップ。

 

usagi@usagi-mba ~ % sudo pip3 install --upgrade pip
Password:
WARNING: The directory '/Users/usagi/Library/Caches/pip' or its parent directory is not owned or is not writable by the current user. The cache has been disabled. Check the permissions and owner of that directory. If executing pip with sudo, you should use sudo's -H flag.
Requirement already satisfied: pip in /opt/homebrew/lib/python3.9/site-packages (21.1.1)
Collecting pip
Downloading pip-21.1.3-py3-none-any.whl (1.5 MB)
|████████████████████████████████| 1.5 MB 10.6 MB/s
Installing collected packages: pip
Attempting uninstall: pip
Found existing installation: pip 21.1.1
Uninstalling pip-21.1.1:
Successfully uninstalled pip-21.1.1
Successfully installed pip-21.1.3
WARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv

 

さらに何か注意されたが、アプグレードはできたらしい。

 

動作確認

numpyでsin使ってみた。

 

>>> import numpy as np
>>> a=np.sin(3.14)
>>> a
0.0015926529164868282

 

使えるようになった。

 

 

アップルM1チップ搭載のMacBookAirで、GitHubを使ってみた!

背景

前から気になっていたGitHubを使ってみた。何が便利なのかよくわからないので、わかるようになるために触ってみることにした。

結論

ローカルのファイルをリモートリポジトリにpushして、外部からアクセスできるようになった。便利さは未だ不明だが、備忘録を残す。

 

前提

マシンはMacBookAir M1 2020、macOS Big Sur バージョン11.2.2 。gitは、初めからインストールされていた。

git version 2.30.1 (Apple Git-130)

 

 

まずはGitHubのアカウント登録

 無料版と有料版があり、有料版だとファイルを非公開で共有できる。お試しなので無料版でやってみた。

techacademy.jp

僕は、ここを参考に登録しました。アドバイスとしては、ユーザーIDとパスワードは覚えられてかつ入力し易いものがオススメ!後からターミナルで入力することになるので、ブラウザが推奨する自動生成パスワードを使うと後悔します。

 

必須単語のおさらい

どうしても覚えなければ話が通じないのでここで2単語を記憶する。リポジトリディレクトリと読み替えればOK

 

コミット(commit)

  • ファイルの追加や変更の履歴をローカルリポジトリに保存すること

プッシュ(push)

 

結局GitHubで何ができるか

gitとGitHubは別物。まずgitはいわゆるタイムマシンのようなもの。ローカルリポジトリでコミットするたびに、その時点での状態がセーブされて、後から過去に戻ることができる。GitHubは、コミットしたgitのローカルリポジトリのアップロード先のこと。

リモートリポジトリの作成

Githubページで、ヘッダーの+ボタンから Create a new repository ボタンを押してリモートリポジトリ(ネット上の保存先)を作成する。赤枠のリポジトリネームを入力して、緑色のボタン押して終了。今回は、m5camera-webcam を作成。

 

f:id:Pin-Pon-Usagi:20210703091902p:plain

リモートリポジトリ(ネット上の保存先)を作成しておく

 

ローカルリポジトリの作成

ローカルに、リモートリポジトリとリンクするための作業ディレクトリを作成。ターミナルでの操作。

usagi@usagi-mba git % ls
m5camera m5camera-webcam

 

まずはinitコマンドで初期化するらしい。init実行すると、現在のディレクトリに「. git」なるリポジトリを構成するディレクトリが作成され、 .gitフォルダを含めてinit実行したディレクトリがgitの管理対象として登録されるとのこと

usagi@usagi-mba m5camera-webcam % git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git repository in /Users/usagi/git/m5camera-webcam/.git/

ずらずらと出てきたがエラーがなさそうなので無視していたが、結構重要なこと書いてある。initial branchの名前としてmasterが使われるらしい。ブランチは履歴管理用の枝分かれのこと。最初のコミットでmasterブランチが自動的に作られ、コミットはブランチを切り替えるまではmasterブランチに追加される。

 

git remote add origin の後にリモートリポジトリのアドレスhttps://github.com/momosagek/m5camera-webcam.gitを貼り付けてリターン

これによって、ローカルリポジトリに、push先のリモートリポジトリが登録されます。originというのは弁当屋のことではなく、リモートリポジトリを表す変数のことで、gitが勝手につけたもの。

usagi@usagi-mba m5camera-webcam % git remote add origin https://github.com/momosagek/m5camera-webcam.git
usagi@usagi-mba m5camera-webcam %

 

 

コミットしてプッシュする

リポジトリに格納したいコードをローカルリポジトリにコピー。本当は、開発しているディレクトリをリモートリポジトリに設定するんだろうな・・・ 

usagi@usagi-mba m5camera-webcam % ls
boot.py main.py webCamera.html

 

 addする

リモートリポジトリにプッシュするファイルは、一旦addしてまとめます。

usagi@usagi-mba m5camera-webcam % git add boot.py

usagi@usagi-mba m5camera-webcam % git add main.py

usagi@usagi-mba m5camera-webcam % git add webCam.html

 

コミットする

ローカルリポジトリにコミットします。引数には、コミット内容がわかるようなコメントをつけます。この作業でmasterブランチにコミットが追加される。

usagi@usagi-mba m5camera-webcam % git commit -m "Create files"

 

pushする

ローカルリポジトリの内容を、リモートリポジトリにコピーします。これで、外部からリモートリポジトリにアクセスして、状態を共有できるようになります。

originの名で登録したリモートリポジトリに、masterブランチ(に追加したコミット)をpushしている。

usagi@usagi-mba m5camera-webcam % git push origin master

 

 

確認してみる

無事にpush完了。

f:id:Pin-Pon-Usagi:20210703112827p:plain

push完了の画面

 

とりあえず使ってみた。

M5CAMERAでラジコン戦車作ってみた〜【Part6: picoweb使ってモーターをリモート駆動する】

はじめに

PicoWebサーバーを利用して、PCやスマホのブラウザからM5CAMERAにGroveケーブルで接続したモータを動かしてみます。これが完成すれば、いわゆるラジコンが作れたことになります。

 

全体構成

WiFi経由でモータを動かすイメージを図で説明します。

  1. スマホとM5CAMERAをそれぞれWiFiに接続
  2. PicoWebサーバー上で操作画面となるHPを稼働
  3. スマホのブラウザから操作画面のHPにアクセスしスマホで表示
  4. ブラウザ上でボタンを押すと、PicoWebサーバーを介してPythonプログラムが駆動
  5. PythonプログラムにI2C経由でモータドライバに指令

f:id:Pin-Pon-Usagi:20210604202534p:plain

図1:picowebサーバーを用いて、スマホからモータを動かす信号伝達イメージ

 

 

ブラウザの画面に、ON/OFFボタンを作成し押すとモータが動いて戦車のキャタピラが回るようにします。 

M5CameraのPythonプログラム

 電源投入後、boot.pyが自動的に実行されWiFiに接続します。boot.pyに続いてmain.pyが実行されるので、main.pyの中でPicoWebサーバを稼働させて、スマホからのアクセス待ち状態にしておきます。main.pyのプログラムは以下のようにしました。

 

main.py

import picoweb

import machine

 

app = picoweb.WebApp('app')

i2c = machine.I2C(scl=machine.Pin(13), sda=machine.Pin(4))

 

@app.route("/")

def index(req, resp):

    yield from picoweb.start_response(resp, content_type = 'text/html')

    htmlFile = open('btnCtrl.html', 'r')

    for line in htmlFile:

        yield from resp.awrite(line)

 

 

@app.route("/ButtonPressed")

def index(req, resp):

    queryString = req.qs

    equalSplit = queryString.split("=")

    yield from picoweb.start_response(resp)

    yield from resp.awrite(equalSplit[1])

 

    val = int(equalSplit[1])

 

    if val==0:  #Go

        i2c.writeto_mem(101, 0,b'\x45')

        i2c.writeto_mem(96,  0,b'\x45')

 

    if val==1:  #Stop

        i2c.writeto_mem(101, 0,b'\x7c')

        i2c.writeto_mem(96,  0,b'\x7c')

 

app.run(debug=True, host = '192.168.0.148')

 

M5CAMERAのPythonプログラム解説

  • import部分では、picowebとmachineをインポートして、picowebサーバーとI2Cを使えるようにしています
  • @app.route("/")部分は、ブラウザからM5CAMERAのIPアドレスにアクセス時に実行されるプログラムです。ブラウザに表示されるhtmlを読み込んでブラウザからのリクエストに対し、htmlをレスポンスとして返します。
  • @app.route("/ButtonPressed") この部分は、ブラウザでボタンが押された時のアクションを定義しています。押したボタンごとに異なる値をパラメータとして送るように設定しておき、受け取ったリクエストに含まれるパラメータを確認して、0の場合は前進命令を、1の場合は停止命令をI2Cを用いてモータドライバに送っています。
  • app.run(debug=True, host = '192.168.0.148')の部分で、指定したIPアドレスでwebサーバーを稼働します。このアドレスにブラウザからアクセスすると、コントロール画面がレスポンスとしてブラウザ側に帰されます。

ブラウザ側のhtmlプログラム

htmlで操作画面を作ります。

  • Goボタンを押した時に、Goボタンが押された事をサーバーに送る
  • Stopボタンを押した時に、Stopボタンが押された事をサーバーに送る

HTMLの画面とプログラムはこんな感じ。

 

f:id:Pin-Pon-Usagi:20210627150955p:plain

ブラウザに表示される操作画面。GoとStopボタンのみ。statusにパラメータを表示

btnCtrol.html

<!DOCTYPE html>

<html>

    <head>

        <title>Remote Test</title>

    </head>

    <body>

        <center>

        <br><div id="status"> status </div><br>

        <button type="button" onclick="MyFunction(this)"    id="0"    >Go     </button>

        <button type="button" onclick="MyFunction(this)"    id="1"    >Stop   </button>

        <p> @2021 Developed by Ping-Pong-USAGI</p>

        </center>

    </body>

    

    <script>

        function MyFunction(e){

            var id_value = e.id;

            var xhr = new XMLHttpRequest();

            xhr.onreadystatechange = function() {

                if (this.readyState == 4 && this.status == 200) {

                    var resp = this.responseText;

                    document.getElementById("status").innerHTML = resp;

                }

            }

            xhr.open("GET", "ButtonPressed?param=" + id_value, true);

            xhr.send();

        }

    </script>

</html>

 

ブラウザ側のhtmlプログラムの解説

<body>~</body>部分は画面レイアウトで、画面中央にボタンを2つ設置しています。

 

<script>~<script>の部分で、設置した2つのボタンクリックに対するアクションを定義しています。ボタンがクリックされると、

  • id_value変数に、ボタンのidを格納
  • XMLHttpRequestを生成し、非同期でmain.pyの@app.route("/ButtonPressed")を呼び出します。

@app.route("/ButtonPressed")の内容

ボタンがクリックされると、下記のプログラムが呼び出されます。

 

def index(req, resp):

    queryString = req.qs

    equalSplit = queryString.split("=")

    yield from picoweb.start_response(resp)

    yield from resp.awrite(equalSplit[1])

 

    val = int(equalSplit[1])

 

    if val==0:  #Go

        i2c.writeto_mem(101, 0,b'\x45')

        i2c.writeto_mem(96,  0,b'\x45')

 

    if val==1:  #Stop

        i2c.writeto_mem(101, 0,b'\x7c')

        i2c.writeto_mem(96,  0,b'\x7c')

 

 

ブラウザ側で、GoとStopのどちらのボタンがクリックされたのかを判定するために、html側では以下のようなxmlHttpRequestのopenメソッドでid_valueとしてパラメータを渡します。

 

xhr.open("GET", "ButtonPressed?param=" + id_value, true);

 

Pythonプログラム側では、equalSplit = queryString.split("=")のように、split()関数を用いて、文字列”=” を目標にして、パラメータとして受け取った文字列を分割することで、パラメータ部分を抽出します。処理の完了を通知するために、パラメータはxml側に返されてブラウザに表示しています。パラメータの値が0の場合は戦車を前進、1の場合はストップするようにモータドライバにi2cで命令します。

 

動作確認

boot.py, main.py, btnCtrol.htmlの3ファイルをampyコマンドでM5Cametaに転送して再起動します。wiif接続が確立したら、ウェブブラウザから、M5CameraのIPアドレスにアクセスします。アドレスが、192.168.0.148の場合、ブラウザのアドレス入力部分に

192.168.0.148:8081/ と入力します。@app.route("/")部分が実行されて、btnCtrol.htmlが読み込まれることでブラウザに操作画面が表示されます。あとはボタンをクリックして戦車が動けばOKです。

 

こちらに動作確認風景を録画しました。

 

www.youtube.com

 

 

M5CAMERAでラジコン戦車作ってみた〜【Part5:picowebをインストールする】

はじめに

M5CAMERAに接続したモータをスマホから遠隔操作するために、ここではpicowebを使えるように設定を行います。picowebは小型のマイクロコントローラ上で動く軽量なwebフレームワークで、インストールするとwebサーバーを簡単に実装できるようになります。M5CAMERAをWiFiに接続した状態で、インターネットからpicowebプログラムをpipコマンドでインストールし、動作に必要なファイルulogging.pyをダウンロードします。 

先ずはWiFi接続

先ずはM5CAMERAをWiFiに接続している状態にしてください。WiFiへの接続方法がわからない時は、Part4WiFi接続を参考にしてください。 Part4 で作成したPythonプログラムboot.pyをampyコマンドでM5CAMERAに転送して、リセットスイッチを押すとboot.pyプログラムが起動して、WiFi接続が完了します。ampyを使ったboot.pyの転送は、ターミナルで下記のコマンドを実行します。

 

ampyコマンドで、boot.pyをM5CAMERAの転送(Part4で実施済みの場合は不要)

ampy --port /dev/tty.usbserial-01EF52FF put boot.py

 

boot.pyの転送が終わったら、screenコマンドを実行しパイソンを対話モードにします

screen /dev/tty.usbserial-01EF52FF 115200

 

対話モードの状態でリセットボタンを押すと、画面に文WiFi接続の状態が表示されます 

configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:5180
load:0x40078000,len:14032
load:0x40080400,len:3800
entry 0x4008063c
connecting to network...
network config: ('●.●.●.●', '▲.▲.▲.▲', '■.■.■.■', '×.×.×.×')
MicroPython v1.13-153-g9c0ac7e6a-dirty on 2020-11-07; Camera Module (i2s) with ESP32
Type "help()" for more information.

 

M5CAMERAに割り当てられてIPアドレスが、●.●.●.●の部分に表示されます。通常は192.168.***のような3桁の数値×4セットをコンマで区切った文字列です。

 

picowebをupipでインストールする

WiFiに接続完了したら、picowebをインストールします。Pythonの対話モードでupipコマンドを実行する事で、必要なファイルがインターネットからダウンロードされます。

 

picowebのインストール

import upip
upip.install('picoweb')

 

以下に実行時のターミナルを示します。

>>> import upip
>>> upip.install('picoweb')
Installing to: /lib/
Warning: micropython.org SSL certificate is not validated
Installing picoweb 1.8.2 from https://files.pythonhosted.org/packages/c2/22/a1eb0cf52b72e818fe47acadaf8ade200d7c0c7c6fc5acc7b47f53f2a338/picoweb-1.8.2.tar.gz
Installing pycopy-uasyncio 3.7 from https://files.pythonhosted.org/packages/e5/58/80b8b403c52ea88d44844570dbe487d7a4b3045ae0ecad0c9f4dbac0d104/pycopy-uasyncio-3.7.tar.gz
Installing pycopy-pkg_resources 0.2.1 from https://files.pythonhosted.org/packages/05/4a/5481a3225d43195361695645d78f4439527278088c0822fadaaf2e93378c/pycopy-pkg_resources-0.2.1.tar.gz
Installing pycopy-uasyncio.core 2.3.2 from https://files.pythonhosted.org/packages/ca/b2/c5bba0bde7022b6d927a6144c026d7bf310d3f8a20e031571fbf1a08a433/pycopy-uasyncio.core-2.3.2.tar.gz
>>>

 

このように、エラーなど表示されずに対話モードに戻ればOKです。自分の場合、WiFi電波の弱い場所で実施したら、installingの後に進めなかったことがありました。おそらく電波が弱くてインターネット接続が途切れてしまったのだと思います。その後、場所を変えてやりなおしてうまくいきました。

 

ulogging.pyのダウンロード

少し先回りしてしまいますが、このままpicowebを使うと下の黄色文字のエラーが発生してうまく動きませんでした

>>> app.run(debug=True, host = '●.●.●.●')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/lib/picoweb/__init__.py", line 308, in run
ImportError: no module named 'ulogging'
>>>

 

uloggingモジュールが見当たらないため、importエラーが発生します。従って、ulogging.pyをインターネットからダウンロードして、ampyコマンドでM5CAMERAに転送しておく必要があります。

 

ulogging.pyは、こちらから入手しました。

pypi.org

 

このサイトから、micropython-ulogging-0.3.tar.gz (1.1 kB) をダウンロードして解凍すると、ulogging.pyが入っているので、このファイルをampyでM5CAMERAに転送します。転送先は、M5CAMERA直下ではなく、libフォルダの中にしました。ulogging.pyが置いてあるディレクトリで次のコマンドを実行します

 

ampy --port /dev/tty.usbserial-01EF52FF put ulogging.py /lib/ulogging.py

 

ampyのlsコマンドでlibフォルダ内のファイルが以下のようになっていればOK です。

usagi@usagi-mba work % ampy --port /dev/tty.usbserial-01EF52FF ls /lib
/lib/picoweb
/lib/pkg_resources.py
/lib/uasyncio
/lib/ulogging.py

 

動作確認 

以上でpicowebを使う環境は整いました。動作確認をしてみましょう。対話モードで次のコマンドを入力します。


>>> import picoweb
>>> app = picoweb.WebApp('app')
>>> @app.route("/")
... def index(req, resp):
... yield from picoweb.start_response(resp)
... yield from resp.awrite('test')
...
...
...
>>> app.run(debug=True, host = '●.●.●.●')
* Running on http://●.●.●.●:8081/

 

やっていることは

  • picowebインポートして、appの名前でWebApp生成
  • @app.route("/")で、M5CAMERAに割り当てられたIPアドレスに、ブラウザからアクセスしたときのアクションを定義しています。ここでは文字列testを表示するようにしている。
  • app.run(debug=True, host = '●.●.●.●')の部分で、M5CAMERAに割り当てられてIPアドレスでサーバーを稼働開始し、ブラウザからのアクセス待ち状態に入ります。

この状態で、WiFiに接続しているスマホやPCのブラウザから、M5CAMERAのIPアドレスにアクセスします。アクセスの方法は、ブラウザのアドレスバーにM5CMREAのアドレスを入力します。アドレスはポート番号とルートも含めた●.●.●.●:8081/と入力します。

f:id:Pin-Pon-Usagi:20210612101226j:plain

ブラウザ(サファリ)から、M5CAMERAのIPアドレスにアクセス

 こんな感じで、testと表示されればpicowebがブラウザからのリクエストを検知して、レスポンスを正常に返していることが確認できます。同時に、ターミナルのpython対話モード画面には、ブラウザからのアクセスを受け取ったことを示す情報が表示されます。

 

>>> app.run(debug=True, host = '●.●.●.●')
* Running on http://●.●.●.●:8081/
INFO:picoweb:224.000 <HTTPRequest object at 3f94d5d0> <Stream object at 3f94dc90> "GET /"
INFO:picoweb:224.000 <HTTPRequest object at 3f9503e0> <Stream object at 3f94d810> "GET /favicon.ico"

 

 以上で、picowebを使用できる状態になりました。

 

M5CAMERAでラジコン戦車作ってみた〜【Part4: M5CAMERAとPCをWiFi接続してみる】

はじめに

前回は、USB接続による有線でモータを動かしました。今回は、M5CAMERAとPCをWiFi接続してみます。

f:id:Pin-Pon-Usagi:20210612093925j:plain 

 

 

ステーションモードとアクセスポイントモード

M5CAMERAとPCをWiFi接続する方法は2つのモードがあります。

 

  • 自宅のWiFiに、PCもM5CAMERAも参加させる、ステーションモード
  • M5CAMERAが発するWiFiに、PCを接続する、アクセスポイントモード

f:id:Pin-Pon-Usagi:20210531125914p:plain

WiFi接続は2種類。

ステーション・モードとアクセスポイント・モードのメリットとデメリットを以下に示します。

  メリット デメリット
ステーション・モード WiFiの範囲内であれば、PCとM5の距離が遠くても通信可能 特になし
アクセスポイント・モード 自宅にWiFiがなくてもPCとM5間の無線通信が可能

PCとM5の距離が遠いと通信できなくなる

 

ここでは、ステーション・モードで進めたいと思います。

 

WiFi接続のプログラム

M5CAMERAの電源を投入すると、M5CAMERAに格納したパイソンプログラムファイル、boot.py が自動的に実行されます。電源投入と同時にWiFi接続するように、ファイル名:boot.py として、PC上に次のプログラムを作成します。

 

# boot.pyの参考プログラム例

import network

import utime

import ntptime

from machine import Pin

from time import sleep

 

#station mode

def do_connect():

    sta_if = network.WLAN(network.STA_IF)

    time_out = False

    start_time = utime.time()

 

    if not sta_if.isconnected():

        print('connecting to network...')

        sta_if.active(True)

        sta_if.connect('WiFi-Name', 'SSID')

        while not sta_if.isconnected() and not time_out:

            if utime.time() - start_time >= 10:

                timed_out = True

            else:

                pass

 

    if sta_if.isconnected():

        for n in range(0,10):

            Pin(14, Pin.OUT).value(0)

            sleep(0.2)

            Pin(14, Pin.OUT).value(1)

            sleep(0.2)

        Pin(14, Pin.OUT).value(0)

        print('network config:', sta_if.ifconfig())

    else:

        for n in range(0,20):

            Pin(14, Pin.OUT).value(0)

            sleep(0.2)

            Pin(14, Pin.OUT).value(1)

            sleep(0.2)

        Pin(14, Pin.OUT).value(1)

        print('disable to connect WiFi')

 

 

do_connect()

 

boot.pyがPythonスクリプトで実行されると、M5カメラをWiFiに接続します。sta_if.connect('WiFi-Name', 'SSID')で指定したWiFiに、SSIDを使って接続を行います。WiFi-NameSSIDは、自分のWiFiに合わせて書き換えが必要です。

 

接続成功した時は、M5カメラの横にある内蔵LEDを10回点滅した後、接続中の目印としてLEDを光らせています。

20秒間接続を試みても接続できない時は、LEDを20回点滅した後、接続失敗の目標としてLEDを消灯します。

 

接続プログラムをM5CAMERAにampyで転送する

PC上に作成したboot.pyファイルをM5CAMERAにコピーします。ファイルの転送には、ampyを使います。ampyは、micropythonと通信するPC用のpythonプログラムで、PC側のファイルをM5CAMERAに転送する、転送したボード上のファイルを実行するなどの操作が可能です。

ローカルのboot.pyをM5CAMERAに転送するには、次のコマンドを実行します

  

ampy --port /dev/tty.usbserial-01EF52FF put boot.py

 

ボード側のファイルを確認するに次のコマンドを実行します

 

usagi@usagi-mba% ampy --port /dev/tty.usbserial-01EF52FF ls
/boot.py
usagi@usagi-mba%

boot.pyを実行

ボード側に転送したboot.pyを実行するには、M5STACKのリセットスイッチを押すか、ampyのコマンドでboot.pyを実行します。

 

usagi@usagi-mba% ampy --port /dev/tty.usbserial-01EF52FF run boot.py

 

プログラムが上手く走り、WiFiに接続すると、M5CAMERAのLEDが点滅の後に点灯します。

 

動画をここに入れる。

 

boot.pyの動きを観察するには、screenコマンドでM5CAMERAに接続した状態で本体のリセットボタンを押します

写真で指示。

 

f:id:Pin-Pon-Usagi:20210602154548j:plain

黄色の丸で囲った部分を押すと、リセットかかる

 

接続過程を確認する

WiFiへの接続が成功したかどうかは、M5CAMERA正面のLEDの点滅状態で確認できますが、より詳細なboot.pyの進捗状況を確認するには、screenコマンドで対話モードの状態にしておいてリセットボタンを押すことで状況確認が可能です。

 

>>> ets Jun 8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x37 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:5180
load:0x40078000,len:14032
load:0x40080400,len:3800
entry 0x4008063c
connecting to network...
network config: ('●.●.●.●', '▲.▲.▲.▲', '■.■.■.■', '×.×.×.×')
MicroPython v1.13-153-g9c0ac7e6a-dirty on 2020-11-07; Camera Module (i2s) with ESP32
Type "help()" for more information.
>>>

上に示すように、boot.pyの中に記述した、print('network config:', sta_if.ifconfig()) の内容がコンソールに表示されます。●.●.●.●の部分がM5CAMERAに割り当てられたIPアドレスで、通常は192.168.***のような3桁の数値×4セットをコンマで区切った文字列です。表示されたアドレスにpingコマンドを実行し、以下のように返事が返って来れば、PCとM5CAMERAの物理的な接続はできています。

usagi@usagi-mba ~ % ping ●.●.●.●
PING ●.●.●.● (●.●.●.●): 56 data bytes
64 bytes from ●.●.●.●: icmp_seq=0 ttl=255 time=299.085 ms
64 bytes from ●.●.●.●: icmp_seq=1 ttl=255 time=62.754 ms
64 bytes from ●.●.●.●: icmp_seq=2 ttl=255 time=83.577 ms
64 bytes from ●.●.●.●: icmp_seq=3 ttl=255 time=98.869 ms
^C
--- ●.●.●.● ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 62.754/136.071/299.085/94.985 ms
usagi@usagi-mba ~ %

 

以上、M5CAMERAをWiFi接続する手順でした。

 

※本ブログは管理者の備忘録であることをご理解いただき、ホビーの範囲でお楽しみください ^^)

M5CAMERAでラジコン戦車作ってみた〜【Part3: 対話モードでモータを動かしてみる】

M5CAMERAでラジコン作りの記事です^^)

 

前回、Part2 ではファームウエアのインストールについて解説しました。

今回、Part3 ではPythonの対話モードで開発の準備として、モータを動かしてみます

 

 

目標

Pythonの対話モードでモータを動かし、左右のキャタピラを前進・後退方向に動かします。

 

ハードの設置

PCとUSBケーブルで接続しておきます。

この状態で、M5CAMERAおよびモータドライバICにもUSB経由で給電されるので、電池ボックスはOFFのままでOK

f:id:Pin-Pon-Usagi:20210530145236j:plain

PCとUSBで接続。動作チェックの時に戦車が動かないように、

M5CAMERAの空箱に乗せてキャタピラを浮かせています。

 

写真ではわかりにくいですが、動作テスト時に戦車が動かないようにM5CAMERAの空箱に乗せてキャタピラをうかせています。

 

接続確認

モータは、モータドライバICに電線でつながっています。

マイコンから命令をモータドライバに送ると、命令を受けたモータドライバが命令にしたがってモータに電流を流します。今回は主に、次の2点について調べていきます。

  • 命令の送り先である、モータドライバICのアドレスの確認方法
  • 命令の内容となる、回転方向と電圧の指示方法

f:id:Pin-Pon-Usagi:20210530100135p:plain

マイコンとモータドライバの接続

ドライバICのアドレス確認

マイコンとモータドライバは、I2Cと呼ばれる通信インターフェースで接続します。

I2Cはデバイス間を、SCL,SDA2本の通信線で接続し、信号を順番に送るいわゆるシリアル通信です。命令を送るには、まず接続したデバイスであるモータドライバICのアドレス確認からはじまます。

 

接続されているI2C部品のアドレス確認は以下の方法で行います。

  • machineモジュールのインポート
  • i2cオブジェクトの生成
  • i2c.scan()の実施

順番に説明します

 

machineモジュールのインポート

今回使うI2Cインターフェースのような、ハードウエアを扱うには、machineモジュールを使います。screenコマンドでM5CAMERAと接続してPythonの対話モードに入ったら、次のコマンドを実行します。対話モードへの移行方法がわからない方は、こちらを参考にしてください。

 

>>>import machine

>>>

 

i2cオブジェクトの生成

i2cオブジェクトの生成は、次のコマンドを実行します。

>>>i2c = machine.I2C(scl=machine.Pin(13), sda=machine.Pin(4))

>>>

 

注意点としては、sclが13ピン、sdaが4ピンを指定してください。

説明書には、sdaが22ピン、sclが23ピンと書いてありますが、スイッチサイエンスさんのHPにも「本製品は時期によって異なるモデルが存在します。モデルによってピンの配置が異なりますので、下記URL先からどちらのモデルかご確認いただき、適切なピンを宣言してください。」と書いてあります。

f:id:Pin-Pon-Usagi:20210530105821p:plain

説明書のPin番号では、i2c.scan()で検出できない!

自分はここでハマったので、みなさんは気をつけてください。

 

i2c.scan()の実施

下記のコマンドでi2c.scan()を実施します。

>>> devices = i2c.scan()

>>>

 

i2c.scan()は、接続されているi2cデバイスのアドレスを返します。

devices変数に結果が入るので、内容を以下のコマンドで確認します

>>> len(devices)
2
>>>

 

lenは、変数内に格納されているオブジェクトの数を確認するコマンドです。

2つのアドレスが格納されたようなので、次のコマンドでアドレスを確認します。

>>> devices[0]
96
>>> devices[1]
101
>>>

 

96と101がモータドライバICのアドレスであることが確認できました。

 

モータを動かしてみる

モータを動かすために、下記のコマンドを実行します。

>>> i2c.writeto_mem(96,0,b'\x99')

 

止めるには、下記のコマンドを実行します。

>>> i2c.writeto_mem(96,0,b'\x90')

 

コマンドの引数は、

I2C.writeto_mem(addr, memaddr, buf, *, addrsize=8)

順に解説します。

第1引数の96:命令対象デバイスのアドレス

これは、上のi2c.scan()で確認した、モータドライバICのアドレスです。

 

第2引数の0:モータドライバのメモリアドレス(レジスタ番号)

今回使っているドライバICは、テキサスインスツルメント社のdrv8830です。データシートを見ると、以下のようなI2Cレジスタ・マップの説明があり、出力電圧の設定はレジスタ0に設定するようになっています。

f:id:Pin-Pon-Usagi:20210530165155p:plain

drv8830のレジスタマップ

 

第3引数のb'\x90':レジスタ0のコントロール

ここでは、レジスタ0に設定する出力電圧値を指定します。

データシートには、以下のように書かれています。

f:id:Pin-Pon-Usagi:20210530160605p:plain

レジスタ0の設定値について

設定する8bitのうち、D7~D2の上位6桁は、VSETとして電圧を決めるための設定値です。

f:id:Pin-Pon-Usagi:20210530171201p:plain

設定電圧と設定値の対応表

例えば、3.05Vを設定したい時には、表の左下の0x26hをVSETとして設定します。

これで、上位の6桁が決まります。

 

設定する8bitのうち、下位の4桁は、状態を決めます。

同じく、データシートには、下記のように定義されています。

 

f:id:Pin-Pon-Usagi:20210530163328p:plain

モータの状態を決める、組み合わせ

例えば、正転駆動したい場合は、IN2=0, IN1=1を設定します。

 

今回、例としている以下のコマンドの電圧と状態を確認します

>>> i2c.writeto_mem(96,0,b'\x99')

 

レジスタ0のコントロール値は、16進数のx99を、2進数に変換して、10011011なので、

[D7 D6 D5 D4 D3 D2 D1 D0] =[1 0 0 1  1 0 01]

となります。

 

電圧は

[D7 D6 D5 D4 D3 D2] =[1 0 0 1 1 0 ] = 0x26hで3.05Vを

 

状態は

[D1 D0] =[IN2 IN1]=[0 1]  従って、正転であることがわかります。

 

なお、私の接続では、アドレス96が左側のキャタピラ、101が右側のキャタピラでした。

 

 動作確認

設定色々変えて、実際に動かしてみました。

 

正回転、1.04V    

VSET=0x0Dh なので、[D7 D6 D5 D4 D3 D2 D1 D0] =[0 0  1 1  0 1 01] ->設定値:0x35 

逆回転、1.04V    

VSET=0x0Dh なので[D7 D6 D5 D4 D3 D2 D1 D0] =[0 0  1 1  0 1 10] ->設定値:0x36 

 

正回転、3.05V    

VSET=0x26h なので、[D7 D6 D5 D4 D3 D2 D1 D0] =[1 0 0 1  1 0 01] ->設定値:0x99

逆回転、3.05V    

VSET=0x26h なので、[D7 D6 D5 D4 D3 D2 D1 D0] =[1 0 0 1  1 0 10] ->設定値:0x9A

 

動作確認風景はこんな感じです。

youtu.be

 

右側のキャタピラ動かす時に、ギアノイズがかなり大きい・・・

組み立て方が雑だったかな?

 

次回はWiFi接続を行う予定です。 

 

M5CAMERAでラジコン戦車作ってみた〜【Part2:microPythonファームウエアのインストール 】

M5CAMERAでラジコン作りの記事です^^)

 

前回、Part1 ではハードの製作について解説しました。

今回、Part2 では開発の準備として、microPythonファームウエアのインストールを説明します

 

 

開発環境の準備

開発用のプログラミング言語Pythonを使います。

Pythonの命令をM5CAMERAが理解できるように、M5CAMERAに搭載されているesp32マイコンに、専用のファームウエアを書き込みます。

ファームウエアは、これを使いました。

github.com

 

注意点ですが、M5CAMERAのカメラモジュールを使うには、カメラ機能がサポートされたファームウエアが必要です。M5STACK用のファームウエアでは、カメラが使えません。

また、M5CAMERAに搭載されているesp32マイコンフラッシュメモリにファームウエアを書き込むには、esptoolを使います。esptoolをあらかじめインストールしておく必要があるので、こちらを参考に実施してください。

teck-rabbit.hatenablog.com

 

パソコンとM5CAMERAをUSBケーブルでつなぐ

Part1で作成した戦車のM5CAMERAとPCをUSBケーブルでつなぎます。

USBからの給電でM5CAMERAが動くので、電池ボックスの電源はOFFのままで大丈夫!

 

f:id:Pin-Pon-Usagi:20210529173052j:plain

M5CAMERAとPCをUSBケーブルで接続。USBから給電されるので、電池BOXはOFFでOK

 

ファームウエア書き込み

ファームウエア書き込みの流れは、

 

  1. 拡張子.binのファームウェアをローカルにコピー
  2. esptoolを使ってM5CAMERAのフラッシュメモリデータを消去
  3. esptoolを使って新しいファームウエアをフラッシュメモリに書き込み
  4. 動作確認

順に説明します。

 

1.拡張子.binのファームウェアをローカルにコピー

上で紹介したリンク先から、ファームウエアをダウンロードします。

今回使ったのは、こちらのファイルです。

micropython_b7883ce_esp32_idf4.x_ble_camera.bin

 

2.esptoolを使ってM5CAMERAのフラッシュメモリデータを消去

フラッシュメモリの消去は以下のコマンドを使います

ダウンロードした.binファイルが置いてあるディレクトリで、次のコマンドを実行します。

 

esptool.py --port /dev/tty.usbserial-01EF52FF erase_flash

 

ここで、/dev/tty.usbserial-01EF52FFは、M5CAMERAのデバイス名です。

この部分は使っているデバイスや環境によって異なるため、自身の環境で確認が必要です。

確認方法は次のように行ってください。

 

まず、M5CAMERAをUSB接続していない状態で、デバイス情報をlsコマンドで確認 

usagi@usagi-mba ~ % ls /dev/tty.*

/dev/tty.Bluetooth-Incoming-Port
/dev/tty.wlan-debug
/dev/tty.debug-console

 

つぎに、M5CAMERAをUSB接続している状態で、デバイス情報をlsコマンドで確認します

usagi@usagi-mba ~ % ls /dev/tty.*

/dev/tty.Bluetooth-Incoming-Port
/dev/tty.wlan-debug
/dev/tty.debug-console 
/dev/tty.usbserial-01EF52FF

 

一つ増えた。/dev/tty.usbserial-01EF52FFがM5CAMERAです

以下は、メモリ消去実施結果です。

 

usagi@usagi-mba work % esptool.py --port /dev/tty.usbserial-01EF52FF erase_flash
esptool.py v3.0
Serial port /dev/tty.usbserial-01EF52FF
Connecting......
Detecting chip type... ESP32
Chip is ESP32-D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: 24:62:ab:d8:3c:ec
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 12.6s
Hard resetting via RTS pin...
usagi@usagi-mba work %

 

Chip erase completed successfullyと表示されればOK!

 

3.esptoolを使って新しいファームウエアをフラッシュメモリに書き込み

ファームウェアの書き込みは、フラッシュメモリ消去の時と同様に、esptoolをつかいます

書き込むファームウエアを選んで下記のコマンドを実行します

 

esptool.py --chip esp32 --port /dev/tty.usbserial-01EF52FF --baud 460800 write_flash -z 0x1000 micropython_b7883ce_esp32_idf4.x_ble_camera.bin

 

書き込みを行うと以下のメッセージが流れます。

usagi@usagi-mba work % esptool.py --chip esp32 --port /dev/tty.usbserial-01EF52FF write_flash -z 0x1000 micropython_cmake_9fef1c0bd_esp32_idf4.x_ble_camera.bin
esptool.py v3.0
Serial port /dev/tty.usbserial-01EF52FF
Connecting.......
Chip is ESP32-D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: 24:62:ab:d8:3c:ec
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Compressed 1575808 bytes to 1010481...
Wrote 1575808 bytes (1010481 compressed) at 0x00001000 in 89.0 seconds (effective 141.7 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
usagi@usagi-mba work %

 

特にエラーが出ていなければ問題ないと思います。

 

4.動作確認

ターミナルからscreenコマンドで、M5CAMERAに接続します。

screen /dev/tty.usbserial-01EF52FF 115200

 

f:id:Pin-Pon-Usagi:20210528174051p:plain

ターミナルからscreenコマンドを実行

真っ白なターミナル画面が表示されたら、1回リターンキーをおします。

f:id:Pin-Pon-Usagi:20210528174142p:plain

真っ白な画面が現れたら、リターンキーを1回押します

 

すると、プロンプト>>>が表示されて、Pythonの対話モードに入ります。

f:id:Pin-Pon-Usagi:20210528174255p:plain

プロンプト>>>が表示され、Pythonの対話モードが開始される

 

f:id:Pin-Pon-Usagi:20210528175422p:plain

動作およびモジュールの確認画面

Pythonの対話モードでは、上に示したように1+1を入力してリターンすると、計算結果が帰ってきます。help('modules')と入力すると、インストールされたPythonモジュールが表示されますが、この中にcameraが入っていればOKです。

 

Python対話モードの終了は、ctrl+a,ctrl+¥を続けて押します。

下記のような質問があるので、続けてy+エンターで抜けられます。

f:id:Pin-Pon-Usagi:20210528174914p:plain

screenを終了する時の画面

f:id:Pin-Pon-Usagi:20210528175036p:plain
無事、ターミナルに戻れました。

 

 

 

今回は、ここらで終わりにしたいと思います。

次回は、対話モードでモータを動かしたいと思います。