2021/06/06

【Arduino自動化番外編】Leonardo→Poke-Controller変換移植プログラム(不完全、各自で調整が必要)

※本記事は、ポケモン等の自動操作を画像認識ありで行うためにPoke-Controllerを導入した執筆者が、自分のArduino Leonardo用プログラムを移植する労力を軽減するために作成した、プログラムテキストの変換プログラムについて紹介した記事です。

デバッグや改良を人任せにしたいのでぶん投げてみます

普段の記事ではできるだけ簡単に使えることを心がけておりますが、今回は自己満足で作った、不完全なプログラムとなります。細かい要素までは変換できないため、自分でプログラムを書ける人向けです。(Poke-Controllerを最低限使えることを前提に書きます)

Python歴3日程度なので、質問等のサポート要求は基本的に受け付けられませんあなたが分からないことは、たぶん私もわかりません

サポート面や安定性の面から、Leonardo用のプログラムをそのまま使いたい方はおとなしく1000円くらいでマイコンを買って使用することをおすすめします。過去の00回目の記事01回目の記事、あるいは各種自動化関連の記事をご覧ください。


2021.06.12追記:Ver1.01に差し替えました。変換後のholdEndについて、変数waitが不要であるため削除しました。

 

 

きっかけ、動機

先日、AliexpressからUSBシリアル変換アダプターが届いたので、自動操作に画像認識を使うことのできるPoke-Controllerを導入しました。Pythonがほぼ初めてなので、練習がてら過去のプログラムを手入力で移植しましたが、結構手間でした。プログラムの90%以上はライブラリの文法そのままの単純な命令文の繰り返しであるため、単純な部分の変換作業を自動化することで、今後いくつかのプログラムを移植するための労力を軽減しようと考えました。

これで何ができるの?

本プログラムをDLし、指定のフォルダに本プログラムと変換したいArduino Leonaro用のプログラムのテキストファイルを入れた後、Poke-Controller実行時のウィンドウから実行することでArduino Leonardo用プログラム(本ブログで紹介しているプログラム)を、Poke-Controller用プログラムへと移植できる形に変換します。変換前や後に適切に調整をすることで、移植するために1から書きなおすのに比べて体感95%くらいの労力を削減することができます。


あくまでも私個人が使うために作っておりますので、私以外の方が作ったファイルについてそのままではうまく変換できない可能性が高いです。正しく変換するにはプログラムの実行前や後にテキストの改変(あるいはプログラムの改変による機能追加、修正)が必要となります。あくまでも補助的な役割として使用してください。

原理、おおまかな流れ

変換プログラム使用前の準備

本プログラムは、

Poke-Controllerフォルダの下層、「SerialController」フォルダ内に変換したいテキストファイル(初期設定は 'ぽけこん.ino')を置き、この変換プログラム(LeoPyConverter.py)を

SerialController>Commands>PythonCommands

あたりに置くことで、Poke-Controller実行時のウィンドウから「leoからpyへ変換」 プログラムを実行できます。

実行すると、元のテキストファイルと同じところに変換後のファイルが生成されます(初期設定は 'ぽけこん.py')。
正しく変換するにはプログラムの実行前や後に、以下に示すようなテキストの改変が必要となります。移植についてはあくまでも補助的な役割として使用してください。

変換手順

本プログラムならびに前後の作業についての流れは、以下のようになります。

変換実行前

変換の誤動作を防ぐため、主に以下の改変が必要となります。

・コメント(// xxxxxx)とその他の文が同じ行にならないように、改行をしてください。//や/*が含まれる行はすべてコメントとして処理されます。

・変数について、int, float, strなどの関数について、Pythonで定義が不要であれば削除することをおすすめします。あるいは、変換後に改めて調整してください。

・変換前のプログラムについて、使用する関数のうち、void setupとvoid loopは最下層に移動させてください。void loopによりインデントがずれるので、void loopの下に記述したプログラムのインデントがずれ、正確な動作ができなくなります。(気になるようであれば、変換後に位置を調整してください)

・1種類の関数以上に()が複数入り組んでいる場合、誤変換の可能性があります(一部の処理では()を区切りや文末などとして認識します)。不要であれば()を必要としない形に改変、あるいは()を別の文字に置換しておき、変換後に改めて置換しなおしてください。

・ボタンを押すなどの関数において、座標や時間を指定する数字については計算を伴います(座標表記やミリ秒/秒の変換など)。スティックのxy軸やwaitなどに相当するところに変数を使用することができないので、数字に改変するか、後から手作業で修正するかしてください。

・その他、執筆者の今までのArduinoLeonardoでの自動化プログラムを元に本プログラムを作成しております。文体をあわせるか、本プログラムを改変するかしてください。


変換プログラムにより変換される内容

以下の順番で変換が行われます。

1) 変換後ファイルに書き込むデータ(fw)の文頭に、Poke-Controller用プログラムのテンプレートに相当する文
def __init__(self):
        super().__init__()   までを記述

2) 全文を通して参照する変数を設定

tab_count = 1:インデントとする1行当たりのタブの数を記録(初期値1)
lastHold = ' ':変換後にスティックをホールドした場合、ホールド解除するまでホールドしているスティック情報を記録。記録していないときはスペースを代入。

3) ここから、変換前のテキストを読み込み、1行目を代入する(line)。

4) ここからwhile文、1行ごとにリセットされる変数を設定
next_tab = 0:次の行におけるタブの数の増減を記録
same_line = 1:処理後のlineを繰り返し実行する回数を記録。数字(int)あるいは文字列(str)を代入

5) インデントを制御するため、行頭にある既存のタブやスペースを削除

6) プログラム動作に関与しないコメント箇所'/*'~'*/', '//'を変換。

7) 定数の置換を宣言する#defineがある場合、
 '#define xxx 100'を'xxx = 100'のように変換。変数扱いのため、変換後に要調整。

8) #define以外に#が付く文(#includeなど)は、行全体を削除(same_line=0とすることで行の書き込みを行わない)

9)  int xxxなどはint(xxx)に書き換えなければならないが、変数ごとに括弧を設定するのが面倒なのでintなどを削除する

10) {がある場合、ブロックの開始点とする。next_tabを1増加させる。

11) }next_tabを1減少

12) 'void setup'がある場合、ここを 'def do(self):'に置換、Poke-Controller用プログラムの開始点とする

13) setupの下に続く'void loop()'を'while True:'に置換する。次の行からはwhile文のブロックとして next_tabを1増加。

14) 12,13以外のvoid関数ならば、'def xxx(self, yy):のように変換

15) delay(500)をwait = 0.5のように変換。以降を含めて、waitなどの時間指定は文字列の数字をミリ秒から秒へ変換(1/1000)するため、数字でない場合(変数)はエラーを吐くので注意。

16)  pushButton(Button::A, 100, 2)をself.press(Button.A, 0.1)のように変換。具体的には、pushButtonの()内のカンマ区切りのデータを
num_listup(self, text)によってリスト型として格納[Button::A, 100, 2]し、各要素を適宜変換したうえでself.press(Button.A, 0.1)の形に変換。same_line=2とすることで書き込みを指定回数繰り返す。

17)  pushHatButtonも16同様に変換。ただし、上下の書き方がUP/DOWNとTOP/BTMとで異なり、斜め方向の書き方も異なるため、方向指定についても変換。

18) pushButtonContinuousなど(長押し)も16同様に変換。ここではdulationを設定しつつ、wait=0.1とする。

19) 'tiltJoystick(lx, ly, rx, ry, dulation)'を変換。18同様に()内をリストで格納し、L、Rスティックごとに変換(stickConvert(self, n_list):)。
変換前はlxなど各座標は-100~0~100の範囲で指定されているものを、
変換後は0~(127)~255の範囲へと変換(角度表記は使用しない)。
ただし、変換前のLorRが[0, 0]であれば無視し、また、[100, 0]のように4方向であれば 座標表記でなく'Direction.RIGHT'のように変換する。

リスト要素[0]の方向指定を変換した後は18同様。ただしwait=0としている。

20) SwitchController().setStickTiltRatio(lx, ly, rx, ry)の場合、self.holdとしてホールドで指定する。方向指定は19と同様。もし、前の行でホールドが行われた場合は、前のホールド指定をself.holdEndで解除してから、その次の行にself.holdを書き込む。書き込んだ後に、lastHoldにホールドしているスティック方向を記録する。ホールド、解除それぞれ、wait=0。

2021.06.12追記:holdEndには、変数waitは不要ですので修正しました(Ver1.01)。

また、指定されている方向が[0, 0, 0, 0]つまりニュートラルの場合、ホールド解除のみと認識し、[0, 0, 0, 0]へのホールドは指定しない。lastHoldにはスペースのみを記録する。

21) 'SwitchController().pressButton'の場合、ボタンのホールドとする。self.hold(Button.A, wait=0)のように置換する。執筆者が使う場面を思い浮かばないので、Hatのホールドは現在非対応(同様に対応させることは簡単)

22) 'SwitchController().releaseButton'の場合、ホールドを解除。21同様。

23) 行頭からfor文が始まっている場合、変換。現在はfor(i=0; i<5; i++)をfor i in range(5)の形への変換のみ対応。while文や、その他のfor文は現在非対応(使っていない)。

24) 行頭からifやelse if、elseが始まっている場合、それぞれ変換。ifと条件分以外に何か書いてあるとうまく変換できないので、if(条件文)の前後は改行必須。Pythonは括弧はずすのが普通らしいので外してみた。

25)  イングリメント、デグリメントにi++, count--のような表記が使えないので、変換。 i +=1のようにする。

26) 以上の6~25のいずれも適用されず、()を含む行については、自身で指定した関数と仮定する。kansu(x);を、self.kansu(x)のように変換する。(要調整)

27) 以上、6-26で変換した行(line)について、変換後ファイルに書き込むデータ(fw)へと1行ずつ追加する。same_lineに記録されている繰り返し回数について、整数であるならばその回数分だけ行を繰り返し書き込む整数以外(変数)であるならば、lineに記録されている行をfor文に入れ、for文で回数を指定する形にして書き込む。

28) 4~27をもって1行分の変換処理が終了。 変換前のテキストから次の行を読み込み代入する(line)。さらに、1行分の処理でnext_tabによるタブ数の増減をtab_countに反映し、次の1行でのタブの数を決定する。

29)  4-28の変換処理を、変換前のテキストすべてを処理するまで繰り返し。

30) すべての変換処理を終えたら、変換後のファイルを変換前と同じフォルダ内に新規作成(すでに同名ファイルがあるならば上書きするので注意)。データ(fw)をテキストファイルに書き込むことができればプログラムが終了。

 

変換実行後

・定義している変数を確認してください。 特に、複数の関数にまたがって使用される関数については、インスタンス関数として設定しなおしてください。

def __init__(self):
        super().__init__()
        self.count = 0
        self.GOAL = 10

... if (self.count < self.GOAL): ...

・Arduino Leonardoに比べて、Poke-Controllerの方が体感で動作遅延が感じられました(PCスペック等の問題かも)。各自の環境に合わせて、ゲーム内での歩行時間などをPoke-Controllerに合うように調整してください。

・L/Rスティックの方向指定について、今回はすべて座標による指定をしておりますが、角度表記の方が分かりやすいかと思います。気になるようであれば、適宜角度表記へと改変してください。

・def __init__(self):や、def do(self):の位置が最下層にあるため、気になるようであればdef間の位置を動かしてください。

・時間の指定にはfloat型(浮動小数点数)を使用しております。たまに、12.000...001のような小数が生成されるため、気になるようであれば適切な値に設定しなおしてください。

・変換前に置換していた文字等があれば、それを調整してください。

・その他変換ミスがないか、必ずプログラム全体を確認してください。(誤動作で何があっても保証しかねます)

必要なもの

・Poke-Controller動作環境

・変換するArduino Leonardo用プログラム(プログラム名を改変) 

↓一応、執筆者のPoke-Controller環境はこちら


作成したプログラム

作成したプログラム(LeoPyConverter.py)Ver1.01こちら

プログラムの行数が長いのと、インデントがずれる可能性があることから、本ページに一文一句の貼り付けはしません。

 

最後に

本プログラムを使用することで、今まで公開してきたようなArduino Leonardo用プログラムをPoke-Controller用に移植できそうな形に変換することができます。あくまで自身のプログラムの書き方を元に作成したので、特定の条件以外の変換には対応しておりません。

本プログラムを改変して好きなプログラムを変換できるようにするなり、私が公開しているプログラムを移植してPoke-Controllerに応用するなり、ご自由にお使いください。

Python歴3日程度のクソ雑魚スキルしかないので、分からないところを聞かれてもたぶん答えられません。ググってください。大したデバッグもしていないので、何があっても保証できません(デバッグを人任せにしたいのでぶん投げました)。

 

プログラムの不備、改善点などありましたらコメントやお問い合わせからお願いいたします。

Arduino Arduino Leonardo (ピンソケット・ピンヘッダ実装済) 【A000057】
by カエレバ

上がArduino Leonardo(変換前に使用)、下がArduino UNO R3互換機(変換後、Poke-Controllerに使用)

Arduino UNO R3 互換基板 マイコン ATmega328P ATmega16U2 USBケーブル付属
by カエレバ


0 件のコメント:

コメントを投稿

【ポケモンSV×arduino06】道具プリンター乱数自動化(藍の円盤)

 ※本記事は、ポケモンSVの藍の円盤(DLC)にて、 道具プリンター を決まった日時に起動することで 特定のアイテム、ボールを狙って量産する操作を自動化 するプログラムについて解説した記事です。ポケモンSVの操作をArduino Leonardoで自動化しております。 本記事の内...