2019/03/16

MicroPythonで使えるモジュール一式

MicroPythonで使えるモジュール一式

ざっと見てみると、、http,urllib等は無いけど、websocket,mqttなんてのがある。。

>>> help('modules')
__main__          framebuf          socket            upip
_boot             gc                ssl               upip_utarfile
_onewire          hashlib           struct            upysh
_thread           heapq             sys               urandom
_webrepl          inisetup          time              ure
apa106            io                ubinascii         urequests
array             json              ucollections      uselect
binascii          machine           ucryptolib        usocket
btree             math              uctypes           ussl
builtins          micropython       uerrno            ustruct
cmath             neopixel          uhashlib          utime
collections       network           uhashlib          utimeq
dht               ntptime           uheapq            uwebsocket
ds18x20           onewire           uio               uzlib
errno             os                ujson             webrepl
esp               random            umqtt/robust      webrepl_setup
esp32             re                umqtt/simple      websocket_helper
flashbdev         select            uos               zlib
Plus any modules on the filesystem
>>>

ESP-32でWebREPLを使う


MicroPythonを使ってESPのプログラミングを行う場合、PCとESPをシリアルで接続するのが大半と思いますが、WebREPLを走らせることでPC上のブラウザからWeb経由でESPに接続してプログラミングすることも可能です。

ESP8266のMycroPythonの記述では、(0)のwebrepl_setupを行うだけでWebREPLが使えるらしいのですが、ESP32の場合、素でブートさせるとWiFiのAccessPointモードはDisableなので接続できないようです(調べきっていないので推測)。

手元のESP32はWiFiはStationモードで動作させているので、下記手順でWebREPLの動作を確認しました。
(0)最初に使うときは、improt webrepl_setup  を実行してEnableにする
(1)WiFiをStationモード(STA_IF)で立ち上げ、WiFiルータと接続してIPを取得
(2)WebREPLを起動して ESP-32側でWebREPL待ち受けに設定
--------------------------------------
# wifi でネットワーク接続
import network
AP_NAME = "AP名を設定"
AP_PASS = "接続パスワードを設定"
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.scan()                             # Scan for available access points
sta_if.connect(AP_NAME, AP_PASS)
sta_if.isconnected()                      # Check for successful connection

# WebREPLを起動

import webrepl
webrepl.start()
--------------------------------------

ESPが待ち受けになっている状態で、PC側(ブラウザが動いているPC)で、webrepl.htmlをブラウザに読み込ませると、JS経由でWebSocketが動いてESPと接続されます。


ESP8266用のMicroPythonの解説では起動時、WiFiはAPモードで立ち上がり、WebREPL Enableなら何も設定せずともWebREPLとしてデバッグできるようですが、手元のESP32の場合、起動時にAPモードDisableになっている。だから、、もし起動時にWebREPLの待ち受けをさせたい場合は、ESP32の起動時にWebREPLが走るように仕組んで置く必要あり。そうすればシリアルなしでもWebブラウザからプログラミングができるはず。ただ、、WebREPLの動作はシリアル接続の場合と比べてかなり遅いです。ですので、試してみたけど、WebREPLは使わない予定。

PC側のブラウザ内で動作させるスクリプト(WebREPL Client)は以下に接続することでロードされる。
http://micropython.org/webrepl/

PCのローカルにファイル一式をダウンロードして、ブラウザで起動してWebREPL Clientを動かすのも可能
https://github.com/micropython/webrepl

2019/03/09

MicroPythonでサーボ制御をやってみる

MicroPythonの仕様をざっと読んでみたので、以前からやってみたかったサーボ制御をやってみる。入力は1Kのボリュームで、それをAD変換して、得られたレベルに従って、PWM変換してデューティを変えてサーボの角度を調整する。

まずは、ボリューム値を定期的に取ってくるサンプル。
アッテネーションを11DBに設定して3.3Vでも扱えるようにする。また、取得値の幅は計算がしやすいように0-1023と設定。以下のサンプルではIO32に0V-3.3Vまでの変動する電圧がかかるのを想定している。

from machine import ADC
import time

adc = ADC(Pin(32))          # create ADC object on ADC pin
adc.atten(ADC.ATTN_11DB)    # set 11dB input attentuation (voltage range roughly 0.0v - 3.6v)
adc.width(ADC.WIDTH_10BIT)   # set 9 bit return values (returned range 0-1023)

while True:
  print(adc.read())   
  time.sleep_ms(500)

オンラインマニュアルよりコードを引用して改変
http://docs.micropython.org/en/latest/esp32/quickref.html#adc-analog-to-digital-conversion


 上記ADCのサンプルとPWMによるサーボ制御を連結させて作ったのが以下のソース
PWMの設定として、50Hz周期で、パルス幅が0.5 - 2.4の間を変動させることでサーボのアームの角度が変わる。ボリュームのレベルの比率で、0.5msec-2.4msecの間を遷移させればボリュームの回した状態に応じてアームが動くと。。
  デバッグ用にprintさせている、また、貧乏省のため、loop内では100msecWAIT(sleep)を入れている。100msecのWAITを入れるとやっぱり応答が遅くなり、微妙な制御の目的には使えない。一方、WAITを取ってしまうと、AD変換でサンプリングの誤差が出て、サーボがプルプル微振動する。だから、、人のフィードバックには忠実に、しかも、サンプリングした値をサーボに与える時点で±1~2の変動は丸めるといった変換が必要と思う。簡単なフィルタ関数かと。。


#-------------------------------------------------------------
# servo_ctrl.py

from machine import Pin, PWM
from machine import ADC
import time

LOOP_WAIT = 100             # wait 100msec

SERVO_MIN = 27
SERVO_MAX = 126
SERVO_CENTER = int((SERVO_MAX - SERVO_MIN)/2) + SERVO_MIN

servo = PWM(Pin(12), freq=50, duty=SERVO_CENTER)  # setup servo  freq=50Hz  set Center=77

vol = ADC(Pin(32))          # create ADC object on ADC pin
vol.atten(ADC.ATTN_11DB)    # set 11dB input attentuation (voltage range roughly 0.0v - 3.6v)
vol.width(ADC.WIDTH_10BIT)   # set 9 bit return values (returned range 0-1023)

while True:
  level = vol.read()
  servo_setting = int((SERVO_MAX - SERVO_MIN) * level / 1023) + SERVO_MIN
  servo.duty(servo_setting)
  print("VR:{:d} Servo:{:d}".format(level,servo_setting))
  time.sleep_ms(LOOP_WAIT)

ESP-WROOM-03にサーボとボリュームを付けて動かしているところ。デバッグにはオシロも欠かせない。













勝手にリンク。。
http://nomolk.hatenablog.com/entry/2017/04/09/222415
滅茶苦茶サーボに詳しい記事 nomolkのブログ 様

ESP32上でMicroPythonを使う

 組込み用にMicroPythonを使うので、ESP起動時に自分の書いたpythonスクリプトが走ってほしい。ファイルシステムがどうなっているのか??
os モジュールが提供されているようで、osモジュール内にlistdir関数があるのでそれを実行してみる。。すると、boot.pyなるファイルが存在する。これが多分起動時に呼ばれると思われる。

>>> import os
>>> dir(os)['__class__', '__name__', 'remove', 'VfsFat', 'chdir', 'dupterm', 'dupterm_notify', 'getcwd', 'ilistdir', 'listdir', 'mkdir', 'mount', 'rename', 'rmdir', 'stat', 'statvfs', 'umount', 'uname', 'urandom']
>>> os.listdir()
['boot.py']

boot.pyを読んでみる。catコマンドとかあるのかもしれないが、、調べるのがまどろっこしいので、、ファイルオープンしてreadしてみる。

>>> with open('boot.py') as b:
...     print(b.read())
...
...
...
# This file is executed on every boot (including wake-boot from deepsleep)
#import esp
#esp.osdebug(None)
#import webrepl
#webrepl.start()

webreplが走っている。これはREPLがwebサーバとして提供されているということと思えるが。。シリアルコンソール以外に、web版のREPLも提供しているということか? と思ったら、、落ち着いてよく考えると、#はpythonのコメントなので、boot.pyは実質何もしていないということか。

microbitの場合、microfsというツールが提供されており、microfsツールを使うことでMicroPythonが管理するファイルシステムにプログラム等を転送できるようである。

https://microbit-micropython.readthedocs.io/ja/latest/tutorials/storage.html

で、、main.pyなるファイルを置いておけば、MicroPython起動時にmain.pyが読み込まれて実行されるらしい。micropython  main.py で逆引きしたら、、以下のようにESP8266でもmain.pyを内蔵ファイルシステムに置いておけば走りますということであった。

https://docs.micropython.org/en/latest/esp8266/tutorial/filesystem.html#start-up-scripts

だから、、開発スタイルとしては、、REPLでチビチビテストしながら部品を作って、部品は内蔵ファイルシステムにmoduleとして配置する。自作モジュールが揃ってそれらを組み立ててテストしてOKなら、最後の起動関数をmain.pyに書き込めば、電源ONで希望する動きをするはず。

まずはお決まりのLチカをやってみる。上記スクリプトでIO12のポートがH->Lと変化する。LEDを接続すれば光る。

from machine import Pin

p12 = Pin(12, Pin.OUT)

p12.on()

p12.off()

以下のスクリプトはwhileループでLHLH...を繰り返す。これをオシロで測ればループの速度も分かる。(on/offさせるのがIOレジスタを直接操作しておらずメソッドなのでオーバーヘッドは大きいが)
while True:
    p12.on()
    p12.off()
オシロで計測すると、1サイクル76usecで13.6KHz。マイコンコアの速度が240MHzだったのでスクリプトでの実行という点でオーバーヘッドが大きい。。

直接IOのレジスタを叩く手法

Accessing hardware directly

http://docs.micropython.org/en/latest/reference/speed_python.html#accessing-hardware-directly

ESP WROOM-32 ROMを焼く (MicroPython)

ESP WROOM-32の内蔵ROMに書き込むには GOIO0をGNDに落としてResetをかける。ResetはENをH->L->Hにすることでリセットがかかる。この時のメッセージは以下

rst:0x1 (POWERON_RESET),boot:0x3 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2))
waiting for download

以前ESP8266を触っていた時はpythonの書き込みツールを使っていた。が、、VMWare内のUbuntuで開発環境を構築していてかなり忘れたので、、ここはおとなしく、Espressif社が提供してくれている書き込みツールでMicroPythonを焼いてみる。

ESP32用のMicroPythonは以下から入手可能

 MicroPython



http://micropython.org/download#esp32

書き込み上のポイントとして、(1)FLASHを消去する(2)開始番地は0x1000

MicroPythonのサイトでもesptool.pyによる書き込みが案内されているが、、Ubuntuから書き込むのは面倒なので、、Espressifの書き込みツールで書いてみることに。以下がDownload Toolの設定。焼きたいファイルを指定して、開始番地を指定(0x1000)。開始番地はデフォルトでも設定されるかもしれません。そこまで調査しておらず。[START]で書き込む前に、上記助言に従い、[ERASE]を実行しました。



ファーム書き込みのハマリ点としては、、[ERASE]した後、すぐに[START]で書き込みはできず、ESP WROOM 32を再度ダウンロードモードに遷移させてから[START]で書き込む必要あり。これをやらなかったので、[ERASE]->[START]と続けて操作したら通信タイムアウトになった。 

書き込みが終了後、ResetするとMicroPythonが起動される。起動メッセージは以下

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
ets Jun  8 2016 00:22:57

rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (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:5060
load:0x40078000,len:8788
ho 0 tail 12 room 4
load:0x40080400,len:6772
entry 0x40081610
I (251) cpu_start: Pro cpu up.
I (251) cpu_start: Application information:
I (251) cpu_start: Compile time:     00:48:25
I (253) cpu_start: Compile date:     Mar  9 2019
I (259) cpu_start: ESP-IDF:          v3.3-beta1-268-g5c88c5996
I (265) cpu_start: Single core mode
I (270) heap_init: Initializing. RAM available for dynamic allocation:
I (277) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (283) heap_init: At 3FFB92B0 len 00026D50 (155 KiB): DRAM
I (289) heap_init: At 3FFE0440 len 0001FBC0 (126 KiB): D/IRAM
I (295) heap_init: At 40078000 len 00008000 (32 KiB): IRAM
I (302) heap_init: At 40092834 len 0000D7CC (53 KiB): IRAM
I (308) cpu_start: Pro cpu start user code
I (27) cpu_start: Starting scheduler on PRO CPU.
OSError: [Errno 2] ENOENT
MicroPython v1.10-194-g41e7ad647 on 2019-03-09; ESP32 module with ESP32
Type "help()" for more information.
>>>
特に苦労なくmicroPythonが入り、リセットすることでmicroPythonが起動された。
Single core mode となっている。。 ESP32は以下のようにDual Coreだったはず
  Architecture: Xtensa Dual-Core 32-bit LX6
また、OSError [Error 2] ENOENT  のメッセージが気になるが。。

マニュアル類:

Quick reference for the ESP32

micropythonのGithub

ESP WROOM-32 を使ってみる

 諸般の事情により、IoT技術を自習することになった。一番使いやすいデバイス、ESP WROOM-32を使ってみることに。デバイスを理解するためになるべく周辺回路が付いていない素の状態から立ち上げたいので、SwitchScience社の「ESP-WROOM-32ピッチ変換済みモジュール」を買って、モジュールに電源とか最低限のPIN PullUp/Downを設定して走らせてみた。 WROOM-32 起動時のブートメッセージは以下

**************************************
*       hello espressif ESP32!       *
*        2nd boot is running!        *
*            version (V0.1)          *
**************************************
compile time 18:16:58

  SPI Speed      : 40MHz
  SPI Mode       : DIO
  SPI Flash Size : 4MB
Partition Table:
## Label            Usage          Type ST Offset   Length
 0 factory          factory app      00 00 00010000 00100000
 1 rfdata           RF data          01 01 00110000 00040000
 2 wifidata         WiFi data        01 02 00150000 00040000
End of partition table
Loading app partition at offset 00010000
section 0: paddr=0x00000020 vaddr=0x00000000 size=0x0ffe8 ( 65512)
section 1: paddr=0x00010010 vaddr=0x3f400010 size=0x05b64 ( 23396) map
section 2: paddr=0x00015b7c vaddr=0x3ffba720 size=0x01378 (  4984) load
section 3: paddr=0x00016efc vaddr=0x40080000 size=0x00400 (  1024) load
section 4: paddr=0x00017304 vaddr=0x40080400 size=0x126ac ( 75436) load
section 5: paddr=0x000299b8 vaddr=0x00000000 size=0x06658 ( 26200)
section 6: paddr=0x00030018 vaddr=0x400d0018 size=0x325b4 (206260) map
start: 0x400807ac

Initializing heap allocator:
Region 19: 3FFBBA98 len 00024568 tag 0
Region 25: 3FFE8000 len 00018000 tag 1
Pro cpu up.
Pro cpu start user code
nvs_flash_init
frc2_timer_task_hdl:3ffbc564, prio:22, stack:2048
tcpip_task_hdlxxx : 3ffbeca8, prio:20,stack:2048
phy_version: 80, Aug 26 2016, 13:04:06, 0
pp_task_hdl : 3ffc34f0, prio:23, stack:8192

:>enter uart init
uart init wait fifo succeed
exit uart init

IDF version : master(db93bceb)
WIFI LIB version : master(934d079b)
ssc version : master(r283 4d376412)

!!!ready!!!
mode : softAP(26:0a:c4:07:55:e4)
dhcp server start:(ip: 192.168.4.1, mask: 255.255.255.0, gw: 192.168.4.1)
+WIFI:AP_START


 PIN設定上の注意点:3番ピンのEN(Enable)について、、最初チップ内部でプルアップされていると思って、プルアップにせず放置していたらまともに起動しなかった。ENは10K等の抵抗を介して3.3Vに引き上げるべし。。当たり前か。。

内蔵ROMの工場出荷状態では、softAP(AccessPoint)として動作するようで、ATコマンド等で制御可能(のはず)。 RxD,TxDでシリアル接続していて、115200baudで通信中

適当にATコマンドを叩いても:>what?と聞き返されコマンドは受け付けられず。。? を打ち込むと以下のメッセージが。

Please refer to document ssc_commands.xlsx for detail

他人の記事を見て、、例えば以下の様にコマンドを打ち込んで使うらしい。

:>ap -S -s esp3    .....  自分の入力
+SAP:OK                 .....   ESPからの応答(上記入力には正しく応答)

microPythonで制御したいので、初期ファームの確認はこれぐらいで終わりにする。

2019/02/09

定年までサポートアプリのアイコンを作成

 噴飯モノ(?)の定年までサポートアプリであるが、まだ開発中とはいえ、アイコンが無くてレーダーチャートみたいなアイコンで起動するのはもう嫌だ。。というわけで、勘亭流というのか、江戸文字というのか、正しくは分からないが、ぶっといフォントで定年の定だけを使ってアイコンを作ってみた。アイコンの作り方は、本によると、1536x1536 pixcelでまず作って、各サイズにリサイズするらしい。リサイズするサービスがあって、自分は、MakeAppIconというサービスサイトで変換した。変換するとメールで送られてくるので、開発中のプロジェクトの該当フォルダ(AppIcon.appiconset)にCopy&Pasteすればプロジェクトに組み込まれる。ビルドしてiPhoneに転送すると確認できる。左はXCodeでアイコンが組み込まれたところ。右は自分のiPhoneで表示させたところ。笑える。。