2023年8月11日金曜日

Edisonが故障した一件

 最近またEdisonで遊んでいます。


教育用のデバイスとしてよく出来ているなと思っているEdisonですが、現在3台を所有しています。
最近このうちの1台が調子が悪くなってしましました。具体的にはBeep用のデバイスが壊れたようです。購入時にチェックをしたつもりですが今回久々に音関係のプログラムを作っていたところ音が出なくなっていました。
通常は電源を入れるとBeep音が鳴るのですがこれが出ないのでおかしいなと思って、とりあえずプログラムを作って動かした所やはり音が出ませんでした。

あれ、Blogerのプレビューが動かない!


これはMacBook Airで書いて居るのですが、今までプレビューも問題なく使えていましたが今日は「読み込んでいます」でループして居るようです。
とりあえずiMacに移って続きを書き始めましたが、こちらでは問題無くプレビューできるようです。
私のMacBook AirもEarly 2015と既に8年前の物、最近ではシステムアップデートもできていませんし、バッテリーもお亡くなり寸前の状態です。そろそろ買い替えたいなと考えていますが、今のところ動いているので延び延びになっています。
来年あたりは変えかられるかなぁ〜

閑話休題


早速、サポートに連絡を入れましたがレスポンスも翌日にはあり、その後も丁寧に対応してくれました。非常に好感が持てましたので嬉しくなってアップした次第です。5、6回のやりとりをしましたが、概ね翌日の午前中にはレスポンスがあリました。アーストラリアとは2時間の時差なので、向こうで朝一メールをチェックして対応しているのかなと言う感じでした。

やはり、ブザーデバイスの故障ということになり、保証期間内なので代替品を送ってもらえることになりました。

保証期間は1年間あるのですが、これもしっかりとした物作りができていると言う自信なのでしょうか? Edisonそのものは非常にコンパクトでしっかりとした作りになっています。小さいお子さんも使う前提で小さな部品もほぼ無く(電池カバーのみ)鋭角な部分も少なく安全にも配慮された作りになっていると思います。 LEGOと組み合わせることができるので、レゴを使った場合には小さなお子さんがLEGOブロックを飲み込む危険があるので注意が必要にはなります。
製造は中国で行っているようですが、今まで問題になったのは電池ボックスの蓋のバネが弱くて電池がうまく接触しなかったケースぐらいです。これもバネを少し伸ばしてあげることで問題なく使えるようになりました。

マイナス点としては、電源スイッチが非常に小さいので小さなお子さんでは電源を入れられないかもしれないと言う点。
あとは、電池ボックスの蓋がちょっと癖があるので開け閉めにコツがいることでしょうか。これはホームページのFAQにも対策が書いてありました。

Edisonドキュメントの日本語化を進めています


EdisonはEdBlock(Scratch Jr)、EdScratch(Scratch)、EdPy(Python)と理解に応じた言語が用意されているので年長さんあたりから中学生あたりまで広くプログラミングの学習に使えるなと考えています。
ただ、問題は日本語ドキュメントが無いのがネックになっていると思います。上記3つの言語ツールも全て英語版だけなのでそこが利用する上でのネックになっているのかと思います。
本体は6千円程度で入手できるのでLEGOと比べると購入しやすいと思います。

と言うことで、現在プログラミング学習用ドキュメントの日本語化を進めています。
本家が非常に良質なプログラミング学習用ドキュメントを用意してくれていて、翻訳したいと連絡したら翻訳用キットを送ってもらえました。
現在、鋭意翻訳中ですので終了しましたら公開していきたいと考えています。
1人でやっているので時間がかかりますが、まずは生徒用ドキュメントから翻訳を始めています。

今しばらくお待ちくださいね。

2023年4月7日金曜日

ESP32をW5500で有線LAN接続してmDNSしてみた -2-

前回投稿より1年近くが経ってしまいました。途中、投稿しとこうかと思った事も幾つかあったのですが、ついついコードを書く事が優先して気がつくと何を書こうとしたのかも忘れてしまう有様でした。
そろそろボケが入って来たのかな?

W5500搭載 ATOM PoEキット


現在IoT 関連のプログラムを趣味のように書いていますが、その中でこんな物を見つけたのでWi-Fiが使えない&電源を取るのが難しいという状況でセンサーが使えそうだなということで早速購入して遊んでみました。

W5500については以前ブログにアップしていたので簡単に動くかと思ったのですが・・・

当時のplatformio.iniは

[env:esp32doit-devkit-v1]
platform = espressif32
board = esp32doit-devkit-v1
framework = arduino
lib_deps = adafruit/Ethernet2@^1.0.4 khoih.prog/MDNS_Generic@^1.0.1

こんな感じだったのですが、既にこのバージョンは古くなって使えなくなっていました。
ならばと最新版でコンパイルするとコンパイルエラーが多発してうまくいきません。
GitHubのサンプルResolvingHostNames.inoを見ると

// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
#include <MDNS_Generic.h>

のようなコメントもありましたが、依存関係を見るとWiFiを参照していたりと本来ネットワーク媒体には非依存で作成すべきなところがだいぶ複雑になっていそうです。
そこでもっと軽いライブラリはないかなと探してみたところ、やはりいました。

ArduinoMDNS


PlatformIOにもありましたので早速使うことにしました。
依存関係も無くすっきりとしたライブラリのようです。

今回のplatformio.iniは

[env:m5stack-atom] platform = espressif32 board = m5stack-atom framework = arduino monitor_speed = 115200 lib_deps = m5stack/M5Atom@^0.1.0 arduino-libraries/Ethernet@^2.0.2 arduino-libraries/ArduinoMDNS@^0.0.0

こんな感じです。

早速テストして見ると、パニックを起こしてしまいます。
どうやらアドレスエラーのようです・・・
前回同様またソースを見ることになるとは(( _ _ ))..zzzZZ

_finishedResolvingNameが原因でした


ソースを見るとどうやら_finishedResolvingNameメソッドでアドレス例外を出しているようです。
void MDNS::_finishedResolvingName(char* name, const byte ipAddr[4])
{   
   if (NULL != this->_nameFoundCallback) {
      if (NULL != name) {
         uint8_t* n = this->_findFirstDotFromRight((const uint8_t*)name);
         *(n-1) = '\0';
      }
      this->_nameFoundCallback((const char*)name, IPAddress(ipAddr));
   }

   my_free(this->_resolveNames[0]);
   this->_resolveNames[0] = NULL;
}

このメソッドは名前解決が出来た時に呼び出されてコールバック関数を呼び出すのですが、ソースを検索すると、名前解決できなかった時も呼び出されているます。但しipAddrがNULLで呼び出されていました!(前回調査時と同じ不具合)ということでその部分を以下のように変更して問題は解決しました。
this->_nameFoundCallback((const char*)name, 
                 (ipAddr == NULL ? INADDR_NONE : IPAddress(ipAddr)));

resolveNameサンプル


ヘッダファイル:
    DNSClient dns;
    EthernetUDP udp;
    MDNS mdns = MDNS(udp);
ソースファイル:
/* ****************************************************************************
 *      DNS
 ******************************************************************************/
IPAddress resolved_ip_address;
void nameFound(const char* name, IPAddress ip) {
    resolved_ip_address = ip;
    Serial.println(ip == INADDR_NONE ? " failed !!!" : " successed !");
}

IPAddress NetworkClientW5500Class::resolveName(const char *name) {
    IPAddress ipAddress;
    boolean rc = ipAddress.fromString(name);
    if(!rc) { // IP指定だった場合は名前解決不要
        if(this->useDNS) {
            int ret = this->dns.getHostByName(name, ipAddress);
            if (ret != 1) {
                // mDNS初期化
                if(!this->beginMDNS) {
                    if (!this->mdns.begin(Ethernet.localIP(), this->client_name)) {
                        // mDNS初期化エラー
                        Serial.println("Error setting up MDNS(W5500) responder!!!");
                        while(true) { 
                            delay(1000);
                            Serial.print(".");
                        }
                    }
                    this->beginMDNS = true;
                    this->mdns.setNameResolvedCallback(nameFound);
                    Serial.println("mdns.begin is success !");
                }
                Serial.print("host(");
                Serial.print(name);
                Serial.print(") IP address resolving ");
                int count = 0;
                resolved_ip_address = INADDR_NONE;
                while(true) {
                    if (!this->mdns.isResolvingName()) {
                        this->mdns.resolveName(name, 5000);
                        count++;
                        if(count > DNS_RETRY_COUNT)
                            break;
                        else if(count > 1)
                            Serial.print("retry resolving ");
                    }
                    Serial.print(".");
                    this->mdns.run();
                    if(resolved_ip_address != INADDR_NONE) {
                        ipAddress = resolved_ip_address;
                        count = 0;
                        break;
                    }
                    delay(100);
                }
                if(count > 0) {
                    // 名前解決できず
                    Serial.println(" was ended in failure!!!");
                    while(true) { 
                        delay(1000);
                        Serial.print(".");
                    }
                }
            }
            Serial.print("host(");
            Serial.print(name);
            Serial.print(") IP address : ");
            Serial.println(ipAddress);
        } else {
            Serial.print("host(");
            Serial.print(name);
            Serial.print(") name resolution failed !!!");
            while(true) {     
                delay(1000);
                Serial.print(".");
            }
        }     
    }
    return ipAddress;
}

2022年5月24日火曜日

bullseyeで初期設定後画面が真っ黒になって困った

あれ、画面が真っ黒に 

Raspberry Pi OSとして最近はbullseyeを主に使っています。
今まではIoT用途が多かったのでヘッドレスでのセットアップがばかりでしたが久々にディスプレイ+キーボード+マウスの構成でインストールをしたところ初期設定後の再起動で画面が真っ黒になって困ってしまいました。

どうやら言語設定を日本語にすると画面が真っ黒になってしまうようです。

最新のImagerでは色々と初期設定が可能ですが何もしないで今まで通りのインストールを行うと英語の初期設定画面は問題なく表示されるのですが、ロケールなどを日本語環境用に設定した後のリブート後に画面が真っ黒になってしまいます。

OSは問題なく起動されているのでsshでログインすることは可能です。

インストール環境

Raspberry Pi 4B 8MB
MicroSDカード:GIGASTONE 32MB
Raspberry OS:2022-04-04-raspios-bullseye-arm64.img
ディスプレイ:I-O DATA EX-LD2071TB
キーボード、マウス:自宅にあったもの

boot.txtの修正で問題解決

他のディスプレイに接続すると問題なく画面が表示されるディスプレイもあります。
どうやらディスプレイとの相性のようです。

昔もディスプレイとの相性があってconfig.txtをいじったことを思い出しました。

と言うことで今回はSDカードを取り出してWindowsで/boot/config.txtの以下の部分を修正して問題なく画面が表示されるようになりました。
値についてはそれぞれの環境によって違いますが参考としてはこちらと各自のディスプレイの取説を見て下さい。

ちなみにI-O DATA EX-LD2071TBは1920×1080のプログレッシブモードでHDMI接続なので1080pの60Hzの設定(hdmi_mode=5)を使用しました。

framebuffer_width=1920
framebuffer_height=1080

hdmi_group=1
hdmi_mode=5


2022年5月3日火曜日

bullseyeでGrove Base Hat for Raspberry Piが動かない!

 Raspberry Pi OS bullseyeがリリース

2021年10月30日にbullseyeがリリースされましたが、その後Busterも引き続きサポートされていく事がアナウンスされました。本家のNewは2021年12月2日に出されましたが、2021年12月10日にはZD Net Japanが日本語の記事をアップしています。

これに伴ってGrove Base Hat for Raspberry Piの一部センサー等についてbullseyeでは提供されるライブラリで動かなくなったものが出てきた様です。

いずれライブラリもアップデートされるでしょうが今回仕事でGrove Base Hat for Raspberry Pi(以下Hat)を使う必要があったのであえてLegacyを使わずにbullseyeにチャレンジしてみました。

Online one-click installationは使えません

まずはseeed studioのHatのページを見てみるとbullseye以上の場合は「Online one-click installation」が使えないと記載されています。これはbullseyeからPython2が標準インストールされてなくなったのが原因です。但し「Step by step installation」の手順でPython3でインストールすればbullseyeでもHatの利用は可能です。

ほとんどのセンサー類は問題なく動く様です。

では何が問題なのかと言う事ですが、色々と調べてみるとHatライブラリでupmmraaを使っていると問題になるようです。
bullseyeにはupmとmraaはインストールされていないので手動でインストールしようとしてもパッケージが見つからないのでインストール出来ませんでした。
seeed studioのGithubでもupmとmraaについては既にメンテナンスされていない様なのでGroveモジュールでupmとmraaを使用している物は使えないとなっています。

Node-REDで動かしてみる

取り敢えずはbullseyeの環境でインストールしてNode-REDでこちらの温度センサーを使ってみると以下の様なエラ〜メッセージが表示されます。

Error: Command failed: python -u /home/pi/.node-red/node_modules/node-red-contrib-grove-base-hat/grove-temperature-sensor/grove-temperature-sensor.py 2 1651393678682
Traceback (most recent call last):
  File "/home/pi/.node-red/node_modules/node-red-contrib-grove-base-hat/grove-temperature-sensor/grove-temperature-sensor.py", line 26, in <module>
    from grove.factory import Factory
  File "/usr/local/lib/python3.9/dist-packages/grove/factory/__init__.py", line 2, in <module>
    from .factory import *
  File "/usr/local/lib/python3.9/dist-packages/grove/factory/factory.py", line 38, in <module>
    from grove.temperature import *
  File "/usr/local/lib/python3.9/dist-packages/grove/temperature/__init__.py", line 2, in <module>
    from .mcp9808 import TemperMCP9808
  File "/usr/local/lib/python3.9/dist-packages/grove/temperature/mcp9808.py", line 38, in <module>
    from upm.pyupm_mcp9808 import MCP9808
ModuleNotFoundError: No module named 'upm'
    at ChildProcess.exithandler (child_process.js:383:12)
    at ChildProcess.emit (events.js:400:28)
    at maybeClose (internal/child_process.js:1058:16)
    at Socket.<anonymous> (internal/child_process.js:443:11)
    at Socket.emit (events.js:400:28)
    at Pipe.<anonymous> (net.js:686:12) {
  killed: false,
  code: 1,
  signal: null,
  cmd: 'python -u /home/pi/.node-red/node_modules/node-red-contrib-grove-base-hat/grove-temperature-sensor/grove-temperature-sensor.py 2 1651393678682'
}

この温度センサーではNTC Thermistorを使っているのでMCP9808は使っていないのですがエラーになっています。「grove/temperature/__init__.py」が有無を言わさずに「mcp9808.py」をimportしている様です。

そこでupmとmraaを使用しているモジュールを調べてみると

$ sudo grep -rl upm /usr/local/lib/python3.9/dist-packages/grove
/usr/local/lib/python3.9/dist-packages/grove/display/jhd1802.py
/usr/local/lib/python3.9/dist-packages/grove/display/__init__.py
/usr/local/lib/python3.9/dist-packages/grove/display/sh1107g.py
/usr/local/lib/python3.9/dist-packages/grove/display/__pycache__/jhd1802.cpython-39.pyc
/usr/local/lib/python3.9/dist-packages/grove/display/__pycache__/__init__.cpython-39.pyc
/usr/local/lib/python3.9/dist-packages/grove/display/__pycache__/sh1107g.cpython-39.pyc
/usr/local/lib/python3.9/dist-packages/grove/temperature/mcp9808.py
/usr/local/lib/python3.9/dist-packages/grove/temperature/__pycache__/mcp9808.cpython-39.pyc
/usr/local/lib/python3.9/dist-packages/grove/grove_optical_rotary_encoder.py
$
$sudo grep -rl mraa /usr/local/lib/python3.9/dist-packages/grove
/usr/local/lib/python3.9/dist-packages/grove/display/sh1107g.py
/usr/local/lib/python3.9/dist-packages/grove/display/jhd1802.py
/usr/local/lib/python3.9/dist-packages/grove/display/__pycache__/sh1107g.cpython-39.pyc
/usr/local/lib/python3.9/dist-packages/grove/display/__pycache__/jhd1802.cpython-39.pyc
/usr/local/lib/python3.9/dist-packages/grove/gpio/gpio_mraa.py
/usr/local/lib/python3.9/dist-packages/grove/gpio/__init__.py
/usr/local/lib/python3.9/dist-packages/grove/gpio/__pycache__/gpio_mraa.cpython-39.pyc
/usr/local/lib/python3.9/dist-packages/grove/gpio/__pycache__/__init__.cpython-39.pyc
/usr/local/lib/python3.9/dist-packages/grove/grove_optical_rotary_encoder.py

それぞれのソースにあたってみると、

  • displayでは__init__.pyで直接upmからimportしています。
  • temperatureでは__init__.pyで直接upmをimportしていませんが、__init__.pyでmcp9808.pyをimportしているので間接的にimportされます。
  • grove_optical_rotary_encoderについては光ロータリーエンコーダを使用しなければ問題ありません。
  • gpioについてはRPi.GPIOがインストールされていない場合にgpio_mraaを使用するようになっていますがbullseyeではRPi.GPIOがインストールされているのでmraaは使用されません。

以上からdisplayとtemperatureについて対応してあげれば使用できるようになりそうです。

Groveにパッチを当てる

以下の修正をする事でNode-REDで問題なく温度の測定をする事ができるようになりました。

$ sudo vi /usr/local/lib/python3.9/dist-packages/grove/temperature/__init__.py

from .temper import Temper,TemperTypedNTC
### from .mcp9808 import TemperMCP9808

### __all__ = ["Temper", "TemperTypedNTC", "TemperMCP9808"]
__all__ = ["Temper", "TemperTypedNTC"]

$ sudo vi /usr/local/lib/python3.9/dist-packages/grove/display/__init__.py

### from upm.pyupm_lcd import SSD1306, SSD1308, SSD1327
### from .jhd1802 import JHD1802
### from .sh1107g import SH1107G_SSD1327

### __all__ = ["JHD1802", "SH1107G_SSD1327"]
__all__ = []

尚、コメントにしたGroveモジュールについて使用する場合は自分で対応する必要があります。

2022年5月2日月曜日

Raspberry Pi Imager update to v1.7

 知らないうちにRaspberry Pi Imagerが便利になっていた


セミナーでハンズオンを行う機会が多いのですが、その場合ヘッドレスインストールする事がほとんどでした。
この時に今まではssh、Wi-Fiの設定については/bootにファイルを設置することで可能でしたがhostnameを変更することは出来ませんでした。この為、複数のRaspberry Piが「raspberrypi」と言うhostnameでインストールされることになりせっかくZeroconfでssh接続しようと思っても同じhostnameが乱立することになり初期設定手順が煩雑になっていました。

Raspberry Pi Imagerなんてイメージが書き込めればいいと思っていたのでアップデートすることもなくほったらかしになっていたのですがいつの間にか便利機能が追加されていた様です。

今回v1.7になることで日本語対応してくれた様ですが、v1.6の時に便利機能が追加されていた様です。2021年3月19日のNewsにちゃんと紹介されていました(><)

この時はまだCtrl-Shift-Xと裏技的な取り扱いでしたが今回v1.7ではわかり易くなっていましたので日本語化されたその画面を紹介したいと思います。基本的な設定内容はv1.6と変更はありませんので詳細は上記のNewsを見てください。とは言っても画面を見れば判る事ばかりですが。

Raspberry Pi Imager v1.7


起動直後の画面が日本語になっています。
まだこの時点では設定ボタンは表示されていません。


此処でインストールするOSを選択すると


設定ボタンが表示されます。
これをクリックするとこんな画面が表示されてhostnameも設定できる様になっています(@_@)


これなら複数台のRaspberry Piがあって一斉にインストールしてもssh接続で困る事は無くなったのでセミナーがよりスムーズに進みそうです。
また、この設定はインストールのデフォルト設定とする事も可能なので自宅で何回もイメージの書き換えを行う時も楽になりそうです。

※1:bullseyeからユーザpiが自動設定されなくなったのでユーザ名/パスワードの設定を忘れるとbullseyeのヘッドレスインストールではMicroSDへの書き込み後初めての起動で立ち上がらなくなるのでご注意ください。

※2:bullseyeからuserconf.txtを/bootに用意する事で初期ユーザの作成が行われます。

2022年1月3日月曜日

MINDSTORMS Python まとめ

 MINDSTORMS Python 全部入り

今まで実装してきた非同期処理、ステートマシン、独自ライブラリについて全てまとめたソースについてGiHubへ公開しておきました。
非同期処理で距離センサーを使用しながら、ステートマシンで直進します。距離センサーが20cm以内に物体を検知した場合にイベントで通知するので停止するという簡単なプログラムです。
メイン処理、ステートマシンでの処理、非同期処理するプログラムと3つのプロジェクトに分けて作成してあります。
MINDSTORMSのモーターやセンサーオブジェクトはそれぞれでimportしても動くとは思いますが、接続ポートの変更などを考慮してメインで全て定義して引数で渡す様にしています。
独自ライブラリの方ではできるだけ汎用性が出る様にプログラムを作成する様に心がけるなどすると将来的にも役立つと思います。

クラスの継承問題

サンプルプログラムではclassを使ってオブジェクト思考風に設計していますが、ここで1つ問題が出てきます。オブジェクト指向で設計していくと継承を使いたくなりますがプロジェクトを分割した場合、親クラスが自分のプロジェクト内に定義されているか、importする必要があるということです。(クラスだけでなく関数でも同じです。)

サンプルではステートマシン用のプロジェクト内にStateクラスとGoStraightクラス(Stateクラスを継承)が定義されていますが、プログラムが大きるなくと各ステート毎にプロジェクトを分割したくなると思います。(私だとステート毎にプロジェクトに分割すると思います)
StateクラスとStateMachineクラス(やその他共通で使用するクラスや関数)を共通ライブラリ化して1つのプロジェクトとして各ステートではStateクラスなどをimportして使うというやり方です。
GoStraightクラスを別プロジェクトにした例が以下です。(Project3.pyとします)

import json

class CopyProject:
    def __init__(self):
        f = open('projects/.slots', 'r')
        data = f.read()
        f.close()
        self.slots = json.loads(data.replace('\'', '"'))

    def getID(self, no):
        return self.slots[no]['id']

    def copy(self, no_from, no_to, name):
        from_path = 'projects/{}/__init__.mpy'.format(self.slots[no_from]['id'])
        to_path = 'projects/{}/{}.mpy'.format(self.slots[no_to]['id'], name)
        f = open(from_path, 'rb')
        data = f.read()
        f.close()
        f = open(to_path, 'wb')
        f.write(data)
        f.close()

cp = CopyProject()
cp.copy(1, 3, 'lib1')
from .lib1 import State

# 直進
class GoStraight(State):
    def __init__(self, name: String, wheels):
        super().__init__(name)
        self.__wheels = wheels

    def entry(self):
        self.__wheels.start(0, -20)

    def exit(self):
        self.__wheels.stop()

if __file__.split('/')[3] == '__init__.mpy':
    print(__file__)

Stateのimportを行わないとプロジェクトをアップロードする時にStateが無いというエラーが出てアップロードすることが出来ません。またStateをimportするのはアップロードする時だけて良さそうですが(ライブラリとしてimportされる場合は、事前にStateをimportしておく)、GoStraightをimportする時もStateをimportしていないとエラーとなります。

CopyProjectクラスだけはimportして使うことが出来ないので、今回の例の様にStateクラスの提供する機能が殆どない様なケースではGoStraightクラスではStateクラスを継承せずに必要なメソッドは自力でコーディングしておく方がソースがスッキリする様です。

共通ライブラリ化の場合は参照関係を整理して助長性とのトレードオフを考える必要がありそうです。


2022年1月2日日曜日

MINDSTORMS Pythonで if __name__ == "__main__"

 if __name__ == "__main__"

Pythonのドキュメントによると

モジュールは、自身の __name__ をチェックすることでメインスコープで実行されているかどうかを確認できます。これはモジュールがスクリプトとして、あるいはインポートでなく python -m で起動されたときに実行するコードの条件として使用できる一般的なイディオムです:

とあります。
ライブラリを作成している時にテストコードを書く場合に良く使用されますが、今回のLEGOでのライブラリ化では使用できませんでした。

色々試した結果以下の方法で実現できました。

LEGOでif __name__ == "__main__"

プロジェクトとして実行された場合にHUBのメモリやディスクの使用状況を表示しています。

if __file__.split('/')[3] == '__init__.mpy':
    import os
    import gc
    import micropython
    print('-----------------------------')
    stat = os.statvfs('/')
    total_size = stat[0] * stat[2]
    free_size = stat[0] * stat[4]
    print('each block is {} bytes big'.format(stat[0]))
    print("in bytes, that's {} bytes free out of a total of {}".format(free_size, total_size))
    print('-----------------------------')
    gc.collect()
    micropython.mem_info()
    print('-----------------------------')
    print('Initial free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
    print('-----------------------------')    
実行すると
-----------------------------
each block is 4096 bytes big
in bytes, that's 29052928 bytes free out of a total of 32505856
-----------------------------
mem: total=595907, current=402437, peak=404485
stack: 1052 out of 7168
GC: total: 242368, used: 193024, free: 49344
 No. of 1-blocks: 3072, 2-blocks: 892, max blk sz: 321, max free sz: 869
-----------------------------
Initial free: 49344 allocated: 193024
-----------------------------
ストレージとしては32Mバイトの殆どが空いていることがわかります。
また、MicroPythonの場合、実行中のプログラムがオブジェクトをインスタンス化すると、必要なメモリがヒープから割り当てられますが、その空き容量が49Kバイト程あることもわかります。

Edisonが故障した一件

 最近またEdisonで遊んでいます。 教育用のデバイスとしてよく出来ているなと思っている Edison ですが、現在3台を所有しています。 最近このうちの1台が調子が悪くなってしましました。具体的にはBeep用のデバイスが壊れたようです。購入時にチェックをしたつもりですが今回久...