LoginSignup
26
14

More than 1 year has passed since last update.

M5StickV MicroPython Instructions

Last updated at Posted at 2019-09-16

使えないメソッド

MaixPy DOCとかに記載があるが使えないメソッドやら機能やら
cpufreq.get_current_frequencies()
 cpufreqをインポートできない
cpufreq.get_kpu_supported_frequencies()
 cpufreqをインポートできない
lcd.set_backlight(bool)
 実行時もエラーにならないが,バックライトの輝度は変わらない.
 このメソッドの代わりに,レジスタを書き換える方法で動的に輝度変更可能
lcd.get_backlight()
 エラーにならないが,常にNoneが返ってくる.
FFT.run()
 FFTモジュールがインポートできない
ハードウェア的にはFFT機能を持っているみたいだけど,現状デフォルトのファーム(micropython実行環境)ではインポートできない.
from Maix import FFTでインポートできる

cpufreq.set_frequency(cpu = cpu_freq, kpu = kpu_freq)
 cpufreqモジュールがインポートできない
image.crop()
Image.scale()
Image.find_number()
Image.classify_object()

・IMU(MPU6886,SH200Q)周り.micropython(MaixPy)にモジュールが無いので使えない.
・omv周り.omvのインポートができない
・SPI周り.pybのインポートができない
・lvglモジュールのインポートができない
・nes周り.デフォルトのファーム・ウェアではインポートは出来るが,nes.run()ができない.ファームをビルドしなおすと,menuconfigでnesモジュールの選択ができる(多分勝手にオンになっている)ので,ビルド後nes.run()出来るようなるが,画面サイズが合っていないので(memory関係のエラーが出る),ソースコードの修正が必要.下記サイトが参考になる.
https://github.com/sipeed/MaixPy/pull/150(多分画面周りの部分だけ修正で動く)

使えるメソッド

●ガベージコレクタ

gc.isenabled() #標準ではTrueが返ってくる
gc.disable()
gc.enable()
gc.mem_alloc()
gc.mem_free()
 手元の環境で空ヒープを見てみる.デフォルトのファーム・ウェアで起動した状態で次の通り.

>>> gc.mem_free()
388160
>>> gc.collect()
>>> gc.mem_free()
500736

micropython.mem_info()
 ガベージコレクタとは関係ないが,メモリ・インフォを出力
micropython.mem_info(1)
 メモリ・ブロックの内容を出力
gc.collect() #ガベージコレクションを起動
gc.threshold(int)
 ガベージコレクタを起動するメモリ占有量の閾値を設定.

gc.get_stats()
gc.get_count()
gc.garbage

gcヒープサイズを調整

from Maix import utils
utils.gc_heap_size(2000000) 


●cmath関係

micropythonでもなにもimportしなくても,複素数を扱える(complexが使える)

cmath.cos(float) #単位はラジアン
cmath.sin(float)
cmath.exp(float)
cmath.log(float) #オリジナルのcmathのような基数の指定はできない
cmath.log10(float)
cmath.phase(complex(float,float)) #極座標から角度をラジアンで得る.返り値の範囲はπ~-π.
cmath.polar(complex(float,float)) #x,y座標から極座標を得る.角度はラジアン.
cmath.sqrt(float) #返り値はcomplex
cmath.rect(float, float) #cmath.polarの逆変換

cmath.pi #3.141593
cmath.e #2.718282

cmath.tan() #使えませ~ん
cmath.acos()
cmath.asin()
cmath.atan()
cmath.acosh()
cmath.cosh()
cmath.isinf()
cmath.isfinite()

●math関係

math.pow(float, float)
math.sqrt(float) #返り値はfloat
math.trunk(float) #0方向へ丸める(正数は少数部切り捨て,負数は切り上げ)
math.acos(float)
math.atan(float)
math.asin(float)
math.atan2(float,float) #高さ/底辺をそれぞれ引数として与える
math.acosh(float)
math.asinh(float)
math.atanh(float)
math.pi
math.e
 etc

●LCD初期化

 ここでの色指定が何に影響を与えるかは不明(電源を入れた後,この色になります.一度lcd.clear()すると黒になるので,もう影響はなくなるのかも)

lcd.init(freq=15000000)
lcd.init(freq=15000000, color=(255,0,0))

●LCDに文字と画像描画

import lcd, image

lcd.init(freq=15000000)
lcd.draw_string(50,50,"Hello world", lcd.RED, lcd.WHITE)    #LCDに文字描画
img = image.Image()    #新しい画像生成
img2 = img.copy(15, 15, 60, 60)    #元画像左上から60, 60の位置からサイズ15×15で新しいイメージ切り出し.元画像に変更なし.
time.sleep(2)
img.draw_string(10,50,"Hello M5StickV", scale=2)    #画像imgにサイズ2で文字を描画
img.draw_image(img2, 30, 30)    #画像imgにx30, y30の位置でimg2を描画
lcd.display(img)


●LCDに画像表示

 lcd.display(img, roi)ではroiに元画像の表示したい部分を矩形で指定する.画面サイズより小さい領域となる場合は,常にセンタリングされ,空いた部分は黒となる.
 roiはx1, y1, w, hで指定するが, x1もしくはy1が元画像領域をはみ出している場合,実行時エラーとなる. 元画像に対して,領域のオーバーラップが無い場合には,実行時エラーとなる.幅や高さが元画像に入りきらない場合は,はみ出し部分は黒塗りとなる.

import lcd, time, sensor

img = sensor.snapshot()
lcd.display(img)    #roiを省略した場合,img全体を描画(はみ出す場合はセンタリング)
time.sleep(2)
roi = (10,10,64,64)
lcd.display(img, roi)
time.sleep(2)
lcd.display(img, (100,100,64,64))


●LCDの表示をクリア

 指定した色で画面全体を塗りつぶす.色を省略した場合は黒で塗りつぶす.lcd.initの色指定の影響は受けない.

lcd.clear((255,0,0))    #赤で画面クリア


●LCDを回転

lcd.rotation(2)    #M5StickVの場合,90°を2回するとカメラの向きと液晶の向きが合う


●CPU/KPU動作周波数

 freq.set(400)で周波数の設定可能なようであるが,リブートしてしまう.
 freq.set(200)をやってみたら,動作しなくなりました(笑). ファームウェア書き換えで復帰.
 freq.set(kpu_div(2))でKPUの動作周波数を半分に落とすことには成功.

from Maix import freq

print(freq.get_cpu())    #CPU動作周波数
print(freq.get_kpu())    #KPU動作周波数


●タイマ割込み

 コールバック関数はタイマ・オブジェクトを引数として渡す形で呼び出されるため,引数を少なくとも1つ取る形にしなければならない.

<第1引数>タイマを選択: Timer.TIMER0 or Timer.TIMER1 or Timer.Timer2
<第2引数>タイマ・チャネル:Timer.CHANNEL0~Timer.CHANNEL3
<mode>モード: [Timer.MODE_ONE_SHOT or Timer.MODE_PERIODIC or Timer.MODE_PWM]
 省略した場合はワンショット
<period>タイマ周期: 省略すると1000
<unit>単位[Timer.UNIT_S or Timer.UNIT_MS or Timer.UNIT_US orTimer.UNIT_NS]
 省略した場合はms
<callback>コールバック関数

import time
from machine import Timer

def timer1(timer):
    print("arg: ", timer)

Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_ONE_SHOT, period=3000, callback=timer1)

time.sleep(5)    #5秒スリープ(このスリープではtimerも止まる)

Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PERIODIC, callback=timer1)


●時間を取得

timeでもutimeでも違いは無いみたい.
起動してからの経過時間を取得できる.

import utime

currentTime = utime.ticks_ms()    #milli second
currentTime1 = utime.ticks_us()    #micro second


●フレーム・レート及び時間差を取得

 下記のプログラムを動かすと,clock.avg()clock.fps()の動きがよくわかる.
 ただし筆者の環境では2段目のfps()は理論値の800msではなく600msくらいを出してきた.1秒未満とかの小さい数字にはあまり,追従しないようである.(time.sleep()の方の問題?)

import time

clock = time.clock()    #コンストラクタ
while(1):
    clock.tick()
    time.sleep(0.5)
    print(clock.avg())    #tick()からの経過時間[ms]<この場合,理論値は500>
    print(clock.fps())    #↑の逆数[frame/sec]<理論値は2>
    time.sleep(0.3)
    print(clock.avg())    #<理論値は800>
    print(clock.fps())    #<理論値は1.25>


●ローカル・タイムを取得

 utime.localtime()の引数にEPOCHタイムを与えると(sec単位のint値)長さ8のタプルが返ってくる.
 ただし,基準は1970年ではなく,2000年.
 引数を省略した場合,よくわからない時間(タプル)が返ってくる.ループで値を定期的に取得し,秒の数字に着目してみると,時間に応じて更新されていくようである(引数なしの場合).

import utime, lcd

lcd.init(freq=15000000)

difference = 946652400    #Difference between 1970 and 2000
now = 1568642215       #16th September 2019
currentTime = utime.localtime(now - difference)
year,month,mday,hour,minute,second,weekday,yearday = currentTime
lcd.draw_string(10,0, 'year: ' + str(year), lcd.RED, lcd.WHITE)
lcd.draw_string(10,16, 'month: ' + str(month), lcd.RED, lcd.WHITE)
lcd.draw_string(10,32, 'mday: ' + str(mday), lcd.RED, lcd.WHITE)
lcd.draw_string(10,48, 'hour: ' + str(hour), lcd.RED, lcd.WHITE)
lcd.draw_string(10,64, 'minute: ' + str(minute), lcd.RED, lcd.WHITE)
lcd.draw_string(10,80, 'second: ' + str(second), lcd.RED, lcd.WHITE)
lcd.draw_string(10,96, 'weekday: ' + str(weekday), lcd.RED, lcd.WHITE)
lcd.draw_string(10,112, 'yearday: ' + str(yearday), lcd.RED, lcd.WHITE)


●スリープ

import utime

utime.sleep(1)    #1秒スリープ
utime.sleep(0.1)    #float も可
utime.sleep_ms(1)    #1msスリープ
utime.sleep_us(1)    #1usスリープ


●GPIOの操作

 ペリフェラルを自由にアサインできる,fpioaと呼ばれるシステムになっているらしい(ESP32のIOマトリックスのようなものか?)
fm.register()の第1引数に指定する物は下記のファイルに記述してあるようである.
https://github.com/sipeed/MaixPy/blob/master/projects/maixpy_m5stickv/builtin_py/board.py
M5StickVの円筒型容器のふたに貼ってある丸いシールに記載の番号でペリフェラルを指定することもできる.つまりboard_info.BUTTON_A は 36と同義.

from Maix import GPIO
from fpioa_manager import fm
from board import board_info

fm.register(board_info.BUTTON_A, fm.fpioa.GPIO1)
button_a = GPIO(GPIO.GPIO1, GPIO.IN, GPIO.PULL_UP)

while(1):
    if button_a.value() == 0:
        print("Button A pushed")


●GPIO操作でLED

 本体内蔵のフルカラーLEDはGPIOで制御します.
 下記のサンプル・プログラムはMaxiPy DOCから転載.

fm.register(board_info.LED_R, fm.fpioa.GPIO0)    #GPIOピンの対応付け(board_info.LED_Rが6番ピンを表す.6とリテラルを書いても良い)
led_r=GPIO(GPIO.GPIO0,GPIO.OUT)    #GPIO0(←ピンの指定ではない)を出力に設定
led_r.value(0) 


●PWMでLEDを制御

PWMの使用例(コンストラクタ)
Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PWM)

  • Timer.TIMER0 :Timerは0~2の3つを使用可能
  • Timer.Timer.CHANNEL0 :チャネルは0~3の4つを使用可能
  • mode :Timer.MODE_PWMを指定

PWM(tim, freq=500000, duty=50, pin=board_info.LED_G)
- tim :上で作ったタイマ
- freq :PWMの周波数
- duty :PWMのデューティー比
- pin :PWM出力にするピン番号

 下記のサンプル・プログラムはMaixPy DOCから転載.

tim = Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PWM)    #タイマ0,チャネル0でPWMタイマ生成
ch = PWM(tim, freq=500000, duty=50, pin=board_info.LED_G)    #board_info.LED_G(9番ピン)をPWM出力に設定
duty=0    #デューティー比を0で初期化
dir = True
while True:
    if dir:
        duty += 10
    else:
        duty -= 10
    if duty>100:
        duty = 100
        dir = False
    elif duty<0:
        duty = 0
        dir = True
    time.sleep(0.05)    #スリープ
    ch.duty(duty)    #デューティー比を設定


●ファイル・システムの操作

 micropythonの実行環境は疑似的なファイル・システムを持っている.
 Maix DOCによるとモジュールはuosとなっているが,osでもアクセスできる.CPythonの同モジュールのサブセットらしい.

os.listdir()

 :カレント・ディレクトリのファイル一覧取得.下記の様なリストが返ってくる.
['boot.py', 'ding.wav', 'startup.jpg', 'freq.conf']

os.ilistdir()

 :ファイル・リストのiteratorオブジェクトを返す.
 iteratorの各要素は下記の様な,長さ4のタプルである.

  • ファイル名
  • ファイルかディレクトリかを表す数字(ディレクトリ:16384, ファイル:32768)
  • 0(0が返ってくる...? おそらくinodeの欄だが,inodeを持たないシステムの場合0が返る)
  • ファイルサイズ(単位はバイト)
ite = os.ilistdir()    #イテレイターを取得
print(next(ite))    #次の要素をプリント

os.mkdir(name)

 :ディレクトリを作る

os.rmdir(name)

 :ディレクトリを削除

os.stat(name)

 :ファイルの詳細を返す

os.statvfs(name)

  • f_bsize – ファイルシステム・ブロック・サイズ
  • f_frsize – フラグメント・サイズ
  • f_blocks – size of fs in f_frsize units
  • f_bfree – 空きブロック数
  • f_bavail – 非特権ユーザ用空ブロック・サイズ
  • f_files – inodeの数
  • f_ffree – 空きinodeの数
  • f_favail – 非特権ユーザ向け空きinodeの数
  • f_flag – mount flags
  • f_namemax – ファイル名の最大長さ

port specificな実装のシステムでは,inode関連のf_files, f_ffree, f_avail, f_flagsの4つのプロパティは0を返します.

Parameters related to inodes: f_files, f_ffree, f_avail and the f_flags parameter may return 0 as they can be unavailable in a port-specific implementation.

os.getcwd()

 :カレントディレクトリの名前を返す

os.chdir(path)

 :カレントディレクトリを変更する(移動する)

os.rename(old_path, new_path)

 :パスの指定が独特かも?パスを間違うと,エラーが返ってくるが,old_pathで指定したファイルは消えている(笑)

os.remove(path)

 :pathで指定したファイルを削除する
 カレントディレクトリのファイルstartup.jpgを指定する場合は,./startup.jpgとする.

os.uname()

 :システムの情報を返す.筆者の環境では次の情報が返ってくる.
(sysname='MaixPy', nodename='MaixPy', release='0.4.0', version='v0.4.0-46-gf46e4c423-dirty on 2019-08-30', machine='M5StickV with Kendryte K210')

uos.urandom(int)

 :乱数を生成する.引数で乱数のバイト数を与える.Maix DOCによるとハードウェア乱数生成器を使っている.

RAMディスク

 プログラムはMaixPy DOCに掲載されているものを転用.

import uos

class RAMBlockDev:
    def __init__(self, block_size, num_blocks):
        self.block_size = block_size
        self.data = bytearray(block_size * num_blocks)

    def readblocks(self, block_num, buf):
        for i in range(len(buf)):
            buf[i] = self.data[block_num * self.block_size + i]

    def writeblocks(self, block_num, buf):
        for i in range(len(buf)):
            self.data[block_num * self.block_size + i] = buf[i]

    def ioctl(self, op, arg):
        if op == 4: # get number of blocks
            return len(self.data) // self.block_size
        if op == 5: # get block size
            return self.block_size

bdev = RAMBlockDev(512, 50)
uos.VfsFat.mkfs(bdev)
vfs = uos.VfsFat(bdev)
uos.mount(vfs, '/ramdisk')

uos.chdir("/")    #ルートディレクトリに移動
print(uos.listdir())    #ファイル一覧を表示
uos.chdir("/ramdisk")    #/ramdiskディレクトリに移動
print(uos.listdir())    #ファイル一覧を表示
uos.mkdir("/ramdisk/newdir")    #新しいディレクトリnewdirを作る
print(uos.listdir())    #ファイル一覧を表示
uos.chdir("newdir")    #newdirに移動
print(uos.listdir())    #ファイル一覧を表示

●##python関係


menu configの中身

board config
(240) LCD default width
(135) LCD default height
(40000000) LCD default driver clock frequency
(24000000) Sensor clock(xclk) frequency

Drivers configuration
Force SPI SD Card high speed mode
Enable ws2812 over i2s component

Kendryte SDK configurations
log level, 5:LOG_VERSOSE, 4:LOG_DEBUG, 3:LOG_INFO, 2:LOG_WARN, 1:LOG_ERROR,

Micropython configurations
Module configurations
[* ] Enable NES emulator
[* ] Enable video module
[ ] Enable touch screen module
[ ] Minimum size OMV function
[* ] Add YUV convert table, close this will reduce code but lower speed
[ ] Enbale LittlvGL
[ ] Enable Ws2812

Debug configuration
    Use UARTHS to debug(pin9, pin10(, UART2 to REPL(pin4, pin5)

SPIFFS Configuration
(0x300000) SPIFFS size
(0xD00000) Start address of SPIFFS
(0x1000) Erease size of SPIFFS, see the datasheet
(0x20000) Logical block size of SPIFFS(default 32*4k)
(0x1000) Logical page size of SPIFFS(default 4k(SPIFFS_LOGICAL_BLOCK_SIZE/32))
(128) Set SPIFFS Maximum Name Length
[* ] Enable SPIFFS Filesystem Magic
[* ] Enable SPIFFS Filesystem Length Magic
(0) Size of per-file metadata field
Debug Configuration --->
[ ] Enable general SPIFFS debug
[ ] Enable SPIFFS API debug
[ ] Enable SPIFFS Garbage Cleaner debug
[ ] Enable SPIFFS Cache debug
[ ] Enable SPIFFS Filesystem Check debug

SPIFFS Cache Configuration
    [* ]     Enable SPIFFS Write Caching
    [ ]     Enable SPIFFS Cache Statistics


●KPUで顔検出

プログラムはMaixPy DOCから転載

task = kpu.load(0x300000)    #フラッシュから顔認識モデルを読み込み
anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658,5.155437, 6.92275, 6.718375, 9.01025)    #アンカーデータ用バウンディングボックス
a = kpu.init_yolo2(task, 0.5, 0.3, 5, anchor)    #yolo2ネットワークに初期化パラメータを渡す

while(True):
    clock.tick()
    img = sensor.snapshot()
    code = kpu.run_yolo2(task, img)    #検出処理
    if code:
        for i in code:
            print(i)
            a = img.draw_rectangle(i.rect())
    a = lcd.display(img)
    print(clock.fps())
a = kpu.deinit(task)



https://maixpy.sipeed.com/en/
https://docs.openmv.io/index.html

uploading-0

26
14
0

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
26
14