前回の記事でビルドする手順を説明したが手抜きすぎたので、簡単なバッチファイルを作ってみた。賞味期限は非常に短いと思われるけど、cygwin のオプションをいろいろ調べたりしたので、その成果も兼ねて。
(2022.8.10追記)
もとの記事だと「FreeTypeライブラリがない」と怒られてしまったので、cygwin のパッケージにlibfreetype-devel を追加した。これに伴って link.txt の変更が不要になった。
前回の記事でビルドする手順を説明したが手抜きすぎたので、簡単なバッチファイルを作ってみた。賞味期限は非常に短いと思われるけど、cygwin のオプションをいろいろ調べたりしたので、その成果も兼ねて。
(2022.8.10追記)
もとの記事だと「FreeTypeライブラリがない」と怒られてしまったので、cygwin のパッケージにlibfreetype-devel を追加した。これに伴って link.txt の変更が不要になった。
レポジトリには簡単にできそうに書いてあったけど、ビルドできるようにするまで大変だったので備忘としてメモ。
ポイントはcmakeのバージョンをできるだけ下げること。執筆時点でCygwinにインストールされるのは 3.23.2-1 だったけど、これでは不可解なエラーが発生して cmake が失敗する。
先のレポジトリでは最低でも3.7.2と書いてあったので、選択できる一番古いバージョン(3.17.3-2)に戻したら cmake が成功するようになった。
あと、Windowsの項目では「cmake .」するように書かれているけど、Linux/Mac OSと同じように親ディレクトリから「cmake -S pharo-vm -B build」した方が、いろいろ試しやすくてよかった。
レポジトリにある便利スクリプト(scripts\installCygwin.ps1)は必要なパッケージを自動的にインストールしてくれる。実際にはそれだけでは足りずエラーになった。ビルドには更に以下のパッケージが必要だった。(どうせsetupしなおすんだったら、スクリプトに書いてあるパッケージも含めて手動で入れた方が楽かも)
libssl-devel libgit2-devel libz4-devel
パッケージを追加するたびにCygwinのsetupが cmake を最新版にしようとするので、かならず Keep を選んでおくこと。
さて、buildディレクトリでmakeすると途中でエラーになる。freetype ライブラリをリンクする際に-lz が見つからないようだ。cmake のスクリプトを書き換えれば良いのだろうが場所が特定できなかった。(後でやる)
とりあえず build/freetype-build/CMakeFiles/freetype.dir/link.txt を直接編集して、-lz の前に -L/usr/lib を追記したら最後までビルドできた。
cmake は難しい。
エッジAIデバイスである M5StickV や M5UnitV を使って(自前で)画像分類を行う場合、kmodel 形式のモデルを用意する必要がある。このモデルの作成例は(エミュレータ上で動作させるものも含め) Ubuntu を使う場合が多いが、あえて Windows 10 環境で作成することを試みる。
この記事ではモデル作成に必要なツールのインストール手順について説明する。
続きを読む →前回の記事でPharo のプロジェクトを github.com で公開する方法について説明した。
今回は、 Travis CI を使ってテストを自動実行させる方法について説明する。
先に進む前に、Monticello などでパッケージが保存されていることを確認する。テストも含め、いつでもパッケージ内容を元に戻せる状態にしておく方が安全・安心。
Travis CI でテストを実行させるために、リポジトリに2つのテキストファイルを作成する。
1つめは、 .smalltalk.ston である。内容は以下のようなもの。
SmalltalkCISpec {
#loading : [
SCIMetacelloLoadSpec {
#baseline : 'MyProject',
#directory : 'src',
#platforms : [ #pharo ]
}
]
}
MyProject の箇所は適宜修正する必要がある。
2つめは、 .travis.yml である。
language: smalltalk
sudo: false
notifications:
email:
on_success: never
on_failure: always
os:
- linux
smalltalk:
- Pharo32-8.0
- Pharo64-8.0
変更する必要のある箇所は、osのところと、smalltalkのところ。osは、他に osx が指定できる。(きっとwindowsも。詳しくは Travis CI のドキュメントを参照のこと)
smalltalk にはテストしたいイメージのバージョンを書く。このあたりの情報は以下のサイトで確認できる。
https://github.com/hpi-swa/smalltalkCI
上記を適当なテキストエディタで作成して、ローカルレポジトリのフォルダに保存しておく。
ローカルレポジトリ内で行った修正作業は、Iceberg では Commit できないので、Shell でコミットとプッシュを行う必要がある。作成したファイルをadd したあと、適当なコメントで commit して push する。
% git add .smalltalk.ston .travis.yml % git commit -a -m 'add travis ci settings' % git push
プッシュが完了したら Travis CI が自動的にテストを始めるはず。
Pharo の環境にもどり、Iceberg でレポジトリのエントリを右クリックして Fetch を選ぶと、Up to date だったステータスが赤色の Detached Working Copy になる。

再度、右クリックして、 Repair Repository を選ぶ。そこで、Discard image changes and load repository version を選ぶ。ここで、Monticello などに保存していないパッケージの変更があると全て失われてしまうので、必ず保存しておく。問題なければ OK を押す。

続く画面で Checkout を押してレポジトリの状態が Up to date に戻れば完了。これ以降は、Iceberg でもコミット&プッシュ後に Travis CI が自動的に動き出すようになる。
SqueakMap とか、SmalltalkHub とか、Smalltalk のプロジェクトを残す方法はいろいろあったけど、いまは github.com に残すのがナウい。
今年、立て続けに何個かプロジェクトを登録したけど、毎回忘れてしまうので備忘のために残しておく。
参考にしたサイトはこちら。
何かのトラブルでせっかくのコードが失われないように、Monticello Browser でパッケージ(Testsパッケージも)を保存しておく。(方法は省略)
github.com にログインして、新しいレポジトリを作る。

出来上がったばかりのレポジトリが開かれたら、そのgithubアドレスをコピーする。

Code をクリックして、 Clone with SSH の下の欄の git@github.com: のテキストを全てコピーするか、その隣のアイコンをクリックする。
Pharo を起動して Tools – Iceberg を選んで Iceberg を起動する。

右上のAddをクリックする。

このままOKを押すと、いま使っているイメージのあるフォルダの下にローカルレポジトリが作られる。PharoLauncher を使っていて、イメージごと削除するのがイヤな場合は、必要に応じて Local directory の場所を変えておく。
問題なければ OK を押す。
ソース群を格納するためのsrc フォルダを作る。
Iceberg で作成したばかりのレポジトリのエントリを右クリックし、Extra を選んで Inspect … をクリックする。

Inspector が現れたら Raw タブを押して、コードエリアに以下を入力して do it する。
(self location / 'src') ensureCreateDirectory

特に問題が生じなければ、 Inspector を閉じて構わない。
次にプロジェクトのメタデータを生成するために、再度レポジトリのエントリを右クリックして Repair repository を選ぶ。現れたダイアログで、Create project meta-data を選んで、OKを押すと、Edit Project のダイアログが現れる。


Code directory に先ほど作成した src フォルダが選ばれており、Format が Tonel になっていることを確認したら OK を押す。
パッケージの依存関係を明確にするために、BaselineOf クラスのサブクラスを作成する。作成したいパッケージが MyProject なら、以下のようにクラス定義する。
BaselineOf subclass: #BaselineOfMyProject
instanceVariableNames: ''
classVariableNames: ''
package: 'BaselineOfMyProject'
必要なインスタンスメソッドは2つで、1つ目は projectClass メソッドである。
projectClass
^ MetacelloCypressBaselineProject
もう一つは baseline: メソッドである。必要なパッケージに応じて内容を適宜修正する必要がある。他のパッケージを参考に依存関係を示せばよい。
baseline: spec
spec
for: #common
do: [ spec
package: 'MyProject';
package: 'MyProject-Tests'
with: [ spec requires: #('MyProject') ] ]
最後に関係する全てのパッケージを追加する。レポジトリのエントリをダブルクリックして Working copy of のダイアログを表示し、右上の Add Packages ボタンでパッケージ(本体、テスト、BaselineOf)を全てチェックし、Add で追加する。(図のようにパッケージ名を入力して絞り込んで置くとラク)

Iceberg の作業もほぼ終わり。Commit ボタンを押してコミット内容を確認して適当なコメントを書いたら、再度右下の Commit ボタンでコミット完了し、Push ボタンで github にプッシュする。
なお、下図のように Push changes to origin/main をチェックしておけば、コミットと同時にプッシュが行われる。

以上で github.com にパッケージがアップロードされた。
パッケージの内容を変更したときは、同様に Commit + Push すれば、その都度 github.com の内容も更新されていく。
DF-ROBOTのmicro:bit Driver Expansion Board(v2.0)は、安価な割に機能の多いモーター制御ボードである。
https://www.dfrobot.com/product-1738.html
micro:bit 上のGPIOへのアクセスに加えて、8個のサーボモータと4個のDCモータを独立して制御することができる。(全てを使った訳ではないが)
ただ、制御のためのプログラムを作成するには MakeCode なりのブロックプログラミング環境を必要としており、MicroPython で使えるコードを見つけることができなかった。
https://github.com/DFRobot/pxt-motor
このボードは PCA9685 という定番のサーボドライバを使っており、I2C接続で何とかなると思ったら、何とかなったので記事にした。
後述するプログラムリストは、上のMakeCodeブロック対応コードに、SG90へ対応するよう修正を加えた Javascript のプログラムを、micro:bit用の MicroPython に移植しただけの単純なものである。参考にしたのはこちら。
https://github.com/nekoma-seisakusho/pxt-motor
ポイントは、サーボモータもDCモータもPCA9685を使って制御するということである。当初、DCモータドライバもI2Cで別に接続されているかと思って調べていたのだが、PWM入力のDCモータドライバに、PCA9685のPWM出力をつなげたもののようだ。ちなみにDCモータドライバとして、HR8835 が2個使われている。
ということで、MicroPython のコードは以下の通り。
import microbit
import utime
initialized = False
def i2cWrite(addr, reg, value):
buf = [0, 0]
buf[0] = reg
buf[1] = value
microbit.i2c.write(addr, bytes(buf))
def i2cRead(addr, reg):
microbit.i2c.write(addr, bytes([reg]))
ret = microbit.i2c.read(addr, 1)
return ret[0]
def initPCA9685():
global initialized
i2cWrite(64, 0, 0)
oldmode = i2cRead(64, 0)
newmode = (oldmode & 127) | 16
i2cWrite(64, 0, newmode)
i2cWrite(64, 254, 121)
i2cWrite(64, 0, oldmode)
utime.sleep_us(5000)
i2cWrite(64, 0, oldmode | 161)
initialized = True
def setPwm(channel, off):
if channel < 0 or channel > 15:
return
print("setPWM",channel,off)
buf = [0] * 5
buf[0] = 6 + 4 * channel
buf[1] = 0
buf[2] = 0
buf[3] = off & 255
buf[4] = (off >> 8) & 255
microbit.i2c.write(64, bytes(buf))
def Servo(index, degree):
if not initialized:
initPCA9685()
value = (degree * 10 + 600) * 4095 // 20000
setPwm(16 - index, value)
def MotorRun(index, speed):
if index < 1 or index > 4:
return
if not initialized:
initPCA9685()
speed = speed * 16
if speed >= 4096:
speed = 4095
if speed <= -4096:
speed = -4095
dp = speed
dn = 0
if speed < 0:
dp = 0
dn = -speed
ch = (4 - index) * 2
setPwm(ch + 1, dp)
setPwm(ch, dn)
使い方は、Servo(チャネル番号, 角度) で、チャネル番号に1から8を、角度は数値を与えれば対応するサーボモータが動く。また、MotorRun(チャネル番号, 速度) で、チャネル番号に1から4を、速度に -255 から 255 の数値を与えればDCモータが動く。
とあるデモンストレーションのために、 micro:witch を使って Tello を制御する一連の流れをスライドにまとめた。