2016年08月18日

Arduboyでブロック崩し

arduboy07.jpg
Arduboyのプログラムは基本的にはArduinoと同じです。
Arduboyのハードウェアにあわせたライブラリが提供されていますので、それを使います。
Arduboyに依存した処理はArduboyクラスで定義されています。

ライブラリの解説は正式なものはまだ内容ですが、Arduino用TFTライブラリなどを使ったことがあれば、それほど難しくはありません。
ヘッダファイルを見ればなんとなく使い方は分かります。

グラフィックス関連のヘッダファイルはこちら。

Arduboy/Arduboy.h at master ・ Arduboy/Arduboy

サウンド関連のヘッダファイルはこちらです。

Arduboy/audio.h at master ・ Arduboy/Arduboy

とりあえず何か作ってみようということで、まずは以前作ったブロック崩しを移植してみました。
ゲームの基本的な処理は変わっていませんが、ゲームとして完結するよう、ミス5回でゲームオーバーとし、スコア表示も追加しています。
また、隠しコマンドとしてゲーム開始時(AまたはBボタン)に左ボタンを押しているとデモモード、右ボタンを押していると高速モードになるようにしています。

Arduboyでの基本的なプログラムは以下のようになります。
#include "Arduboy.h"

Arduboy arduboy;

void setup() {
arduboy.begin();
arduboy.setFrameRate(30);
}

void loop() {
if (!(arduboy.nextFrame()))
return;

// いろいろな処理や描画命令など

arduboy.display();
}



Arduboyでは、描画命令は画面に対してではなく仮想スクリーンに対して行い、仮想スクリーンの内容を
 arduboy.display();
で一気にOLEDに転送しているようです。

それは結構重い処理なのではないかと思ったのですが、考えてみると白黒で128×64ピクセルしかないので、1024バイトの転送で済みます。毎秒60回処理しても60KBの転送量ですから、まあなんとかなりそうです。
カラーLCDだと1ピクセルで2バイトのデータですので、ピクセルあたり1/16のデータ量しかありません。

ただ、少ないArduinoのRAMの半分を仮想スクリーンに使ってしまいますので、メモリの使い方には注意が必要かもしれません。


移植するブロック崩しは、内部的には30×40ピクセルのマップ内で処理を行っており、使用するLCDの解像度に合わせて描画時に拡大することを想定しています。
今回は、Arduboyのスクリーンを90度回転し、マップを縦横2倍に拡大することにしました。
また、スクリーンの縦横比が1:2と大きいので、内部のマップを30×50ピクセルに引き伸ばしました。

128×64ドットのスクリーンの内側の100×60ドットをゲーム画面に使い、残りを枠やスコアなどの表示に使います。

Arduboy特有の命令で今回使ったのは、以下のものです。

・入力関係
arduboy.pressed(A_BUTTON) // ボタンが押されていればtrue
arduboy.notPressed(A_BUTTON) // ボタンが押されていなければtrue
// 他のボタンは、B_BUTTON、UP_BUTTON、DOWN_BUTTON、LEFT_BUTTON、RIGHT_BUTTON


・描画関係
arduboy.clear() // 全消去
arduboy.drawRect(x, y, w, h, color) // 矩形を描画
arduboy.fillRect(x, y, w, h, color) // 塗りつぶした矩形を描画
arduboy.fillCircle(x, y, r, color) // 塗りつぶした円を描画


・音関係
arduboy.tunes.tone(frequency, duration) // frequencyはHz、durationはmsec


このほか、テキスト表示を90度回転させるために、Arduboy.cppの中で定義されているdrawChar()を改変して使っています。

最後に、今回作ったスケッチと動作の様子のビデオを載せておきます。
posted by boochow at 13:08| Comment(0) | Arduino | このブログの読者になる | 更新情報をチェックする

2016年08月17日

ゲーム機型Arduino「Arduboy」を動かしてみた

arduboy01.jpg

Maker Fair Tokyo 2016の会場で入手した「Arduboy」を動かしてみました。

これはArduino Leonardo相当のCPUと180mAhのバッテリ、SSD1306 OLEDディスプレイ、圧電ブザー、操作ボタンを組み合わせて携帯ゲーム機にしたものです。
会場での販売価格は5,000円ポッキリでした。
パーツを個別に買ってもそれほど安くはなりませんし、筐体の作りが割合良かったので購入してしまいました。

見かけはゲーム機風ですが、立派にArduino互換機です。
USBコネクタが内蔵されていますのでケーブルをつなぐだけでセットアップ完了です。
もちろん普通にArduino IDEでプログラムを書いて動作させることができます。

arduboy0.jpg


開発環境のセットアップなどは下記のページが詳しいです。

【Kickstarter】Arduboyレビュー、インストール手順、面白いゲーム紹介など - t-miyajima blog

ただ、一点注意が必要なのは、「Arduino 1.6.10では動きません」。
コンパイル中に
-fno-fat-lto-objects are supported only with linker plugin.

というエラーが出て止まってしまいます。
(8/19追記:Arduino 1.6.11がリリースされました。1.6.11では問題なく動作します。)

これはArduinoとArduboy用ライブラリの不整合が原因だそうで、Arduino 1.6.9なら問題ありません。

Cannot Compile or Upload an Example Game: cc1.exe: error [SOLVED] - Arduboy / Issues - Community

とりあえず、付属のサンプルなどゲームをいくつか動かしてみました。

■Hello, World!
OLEDに表示させるサンプルです。コードはこちら
arduboy02.jpg


■ブロック崩し
ボタン操作のブロック崩しです。コードはこちら
arduboy03.jpg


GLOVE
よくできていると評判のゲームです。「Gauntlet」みたいなゲーム、といえば伝わるでしょうか。
コンパイル時のメッセージが
最大28,672バイトのフラッシュメモリのうち、スケッチが28,612バイト(99%)を使っています。
最大2,560バイトのRAMのうち、グローバル変数が1,682バイト(65%)を使っていて、ローカル変数で878バイト使うことができます。

ということですので、詰め込めるだけ詰め込んでいるようですね。
arduboy04.jpg


伊for Arduboy
横スクロールシューティングです。結構たくさんのオブジェクトを画面で動かせるものですね。
arduboy05.jpg


コミュニティサイトを見ると、現在27本のゲームがWikiに登録されているようです。
他に、ゲームではないデモもいろいろあり、ドラクエ風のRPGのデモもありました。

Arduventure

[WIP] Arduventure (RPG) - Arduboy / Development - Community

arduboy06.jpg


いろいろな作品の紹介が下記の記事にあります。

11 Arduboy Games worth Playing - Retro Gaming Magazine | Retro Gaming Magazine

ラベル:Arduboy
posted by boochow at 15:50| Comment(0) | Arduino | このブログの読者になる | 更新情報をチェックする

2015年08月12日

Arduino(10) aitendoの激安キャラクタ液晶をArduino Pro Mini(3.3V)に接続

Arduino Pro MiniへSPI TFT LCDが割とあっさり接続できたので、ついでに買い置きしてあったaitendoのキャラクタ液晶「SPLC792-I2C-M」も接続してみました。

この液晶モジュールは8x8ドットのキャラクタを16字×2行で表示できるものです。
インタフェースはI2Cで、バックライトはLEDです。
価格が50% OFFとなっており、375円(税別)と激安です。
3.3V専用なので、Arduino UNOからはちょっと使いにくいですが、3.3V動作のPro Miniなら問題ありません。

というわけでさっそくピンヘッダを取り付けます。
ジャンパピンが2つ(写真の青い部品)ありますが、これで表示の向きを指定できます。
arduino10-01.jpg


接続は以下のようになります。
電源ラインを除けば、Arduinoの信号線で使うのはI2CのためのA4、A5だけです。
なお電源は、Arduinoに接続したUSBシリアルアダプタが供給する想定です。
また、バックライト(BL+端子)は、100Ωの抵抗を入れて3.3Vに接続しました。
明るさ的にはこれで室内なら十分だと思います。

Arduino Pro MiniのA4、A5端子にはピンヘッダを付けてしまいましたので、接続にブレッドボード用のオス-オス型のジャンパケーブルは使えません。
ブレッドボード側にもピンヘッダを挿して、ピンヘッダ間を接続するメス型コネクタ(デュポンコネクタとかQIコネクタといいます)が両端に付いたワイヤを使います。

arduino10-04.png


(参考→aitendoのI2C低電圧キャラクタ液晶モジュールをArduino Pro Mini(3.3V)で駆動(配線編) - M.C.P.C. (Mamesibori Creation Plus Communication)

ライブラリは先人が作られたものをありがたく使わせていただきました。

I2C液晶のArduinoライブラリ – ST7032 | オレ工房

他のライブラリ同様、ZIPファイルをIDEに取り込めば、スケッチ例も自動的に追加されます。


無事動作確認ができたところで、一応何か作ってみようということで、ありがちですが手元にあったDHT11センサモジュールを使って、温度湿度計を作ってみました。
arduino10-02.jpg

aitendoの商品ページからリンクされているLCDコントローラ(SPLC792A)の仕様書を見ていたら、キャラクタROMにはカタカナも含まれていることが分かったので、カタカナ表示させてみました。
文字コード表を下に引用しておきます。
splc792a.png


使った温度湿度センサモジュールは、よく見かけるDHT11というセンサを使用した、中国Keyes社のKY-015という型番のものです。
arduino10-07.jpg

DHT11をArduinoから使用するためのソフトウェアは、例によってAdafruit製のライブラリがあります。

adafruit/DHT-sensor-library ・ GitHub

配線は以下の通りです。
(KY-015用の配線です。DHT11を直接接続する場合は配線が異なりますのでご注意ください。)

arduino10-05.png

スケッチファイルも一応アップロードしておきます。


#include <Wire.h>
#include <ST7032.h>
#include <DHT.h>

#define DHTTYPE DHT11
#define DHTPIN 2

ST7032 lcd;
DHT dht(DHTPIN, DHTTYPE);
char str1[14] = {' ',' ',' ',' ',' ',0xdf,'C',' ','/',' ',' ',' ','%',0};
char str2[10] = {' ',' ',0xcc,0xb6,0xb2,0xbc,0xbd,0xb3,0x3a,0};

void setup() {
 lcd.begin(16, 2);
 lcd.setContrast(40);
 lcd.setCursor(0, 0);
 lcd.print(str1);
 lcd.setCursor(0, 1);
 lcd.print(str2);
 
 dht.begin();
}

void loop() {
 delay(2000);
 float h = dht.readHumidity();
 float t = dht.readTemperature();
 if (isnan(h) || isnan(t)) {
   Serial.println("Failed to read from DHT sensor!");
   return;
 }
 float discomfort = 0.81 * t + 0.01 * h * (0.99 * t - 14.3) +46.3;

 lcd.setCursor(3, 0);
 lcd.print(t,0);
 lcd.setCursor(10, 0);
 lcd.print(h,0);
 lcd.setCursor(10, 1);
 lcd.print(discomfort,1);
}



余談ですが、今回使用したセンサモジュールは、中国の通販サイトaliexpressから、Keyes社のモジュール全部入りセットで入手しました。
購入価格は$17(送料無料)でしたので、1モジュール当たり50円強ということになります。

Keyes社のモジュールの一覧は以下のサイトなどで見ることができます。

Arduino 37 sensors - TkkrLab
Advanced Sensors Kit for Arduino - LinkSprite Playgound

届いたものはこんな感じで、全てのモジュールがジップロックの袋に無造作に袋詰めされていました。

arduino10-06.jpg


ホール素子モジュールなどは重複気味ですし、ただのLEDとか、磁気に反応するリードスイッチや傾くと接続する水銀スイッチなどの懐かしいデバイスが多く、ジャイロやI2Cデバイスのような最近のものは入っていませんので、お買い得かといえば迷うところではあります。
しかしロータリーエンコーダやリレー、レーザー、ジョイスティックなど、それなりに使えそうなものもあり、自分で情報を調べて使うことができる人には便利かもしれません。
posted by boochow at 19:55| Comment(0) | Arduino | このブログの読者になる | 更新情報をチェックする

2015年08月11日

Arduino(9) Adafruit_ST7735ライブラリの修正(aitendoの1.8型LCD用)

arduino08-03.jpg
Adafruit_ST7735ライブラリ+aitendo M-Z18SPI-2Pでgraphicstest。
画面右端と下端にゴミが出ています。Hの字の左端が切れています。

Adafruit_ST7735ライブラリでaitendo M-Z18SPI-2Pを制御すると、画面右端と下端にゴミが残り、画面左端が欠けてしまいます。
初期化時、initRのパラメータにINITR_GREENTABを指定するとこの現象は無くなりますが、その代わり色の配列がRGBではなくBGRになってしまいます。

ST7735ではMADCTLというコマンドが色表現のRGB/BGR指定を担っており、これをINITR_BLACKTABのときだけ違う値に設定しているのが関数initRの中の最後の部分です。

void Adafruit_ST7735::initR(uint8_t options) {
commonInit(Rcmd1);
if(options == INITR_GREENTAB) {
commandList(Rcmd2green);
colstart = 2;
rowstart = 1;
} else if(options == INITR_144GREENTAB) {
_height = ST7735_TFTHEIGHT_144;
commandList(Rcmd2green144);
colstart = 2;
rowstart = 3;
} else {
// colstart, rowstart left at default '0' values
commandList(Rcmd2red);
}
commandList(Rcmd3);

// if black, change MADCTL color filter
if (options == INITR_BLACKTAB) {
writecommand(ST7735_MADCTL);
writedata(0xC0);
}


tabcolor = options;
}

これをINITR_GREENTABでも実行するように変更すれば、色がRGBの並びになります。

ただし、本家のINITR_GREENTABが違う動作になるのも困るので、新しくINITR_BLUETABを定義しました。

まずAdafruit_ST7735.hに以下の定義を追加します。(赤字部分)

// some flags for initR() :(
#define INITR_GREENTAB 0x0
#define INITR_REDTAB 0x1
#define INITR_BLACKTAB 0x2
#define INITR_BLUETAB 0x3

#define INITR_18GREENTAB INITR_GREENTAB
#define INITR_18REDTAB INITR_REDTAB
#define INITR_18BLACKTAB INITR_BLACKTAB
#define INITR_144GREENTAB 0x1


そして、Adafruit_ST7735.cppのinitR関数を修正し、BLUETABではGREENTABの初期化+BLACKTAB用追加コードを実行するようにします。
void Adafruit_ST7735::initR(uint8_t options) {
commonInit(Rcmd1);
if((options == INITR_GREENTAB) || (options == INITR_BLUETAB)) {
commandList(Rcmd2green);
colstart = 2;
rowstart = 1;
} else if(options == INITR_144GREENTAB) {
_height = ST7735_TFTHEIGHT_144;
commandList(Rcmd2green144);
colstart = 2;
rowstart = 3;
} else {
// colstart, rowstart left at default '0' values
commandList(Rcmd2red);
}
commandList(Rcmd3);

// if black, change MADCTL color filter
if ((options == INITR_BLACKTAB)|| (options == INITR_BLUETAB)) {
writecommand(ST7735_MADCTL);
writedata(0xC0);
}

tabcolor = options;
}


これで、ノイズなし、かつ正しい色での表示ができるようになります。
(もちろん、setup()の中でinitRの引数をINITR_BLUETABにする必要があります。)

なお、以下のページにST7735の仕様の解説があり、参考になります。

表示器 (ST7735B 1.8" TFT SPI)

・修正後のライブラリ+aitendo M-Z18SPI-2Pでgraphicstest
arduino08-04.jpg
ゴミが消え、画面の左端が見えるようになりました。

posted by boochow at 13:07| Comment(0) | Arduino | このブログの読者になる | 更新情報をチェックする

Arduino(8) Arduino Pro Mini+aitendoの1.8型LCDでブロック崩し

aitendoの1.8インチSPI LCDがPro mini(3.3V/8MHz)で動作するようになったので、先日UNOで作成したブロック崩しを動かしてみました。

基本的には、画面解像度の違いへの対応と、LCD初期化の処理を若干変更するだけて対応できました。


解像度の違いへの対応は、拡大率の変更で行います。
以前使っていた液晶の解像度は240×320ピクセルでしたが、この液晶は解像度が128×160ピクセルです。
ブロック崩しは、論理的な解像度を30×40として作成していますので、座標値を4倍にすればこの液晶にフルスクリーンで表示できます。
(横方向は120ピクセルになるので、8ピクセル余ってしまいますが。)


LCD初期化処理は、Adafruit-TFTLibraryと今回使うAdafruit_ST7735でスケッチ例を見比べて、以下のように修正しました。

・includeするライブラリおよび信号線の定義
(当然ですね。)
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>

#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
#define TFT_SCLK 13 // set these to be whatever pins you like!
#define TFT_MOSI 11 // set these to be whatever pins you like!


・初期化シーケンス
void setup(void) {
tft.initR(INITR_GREENTAB); // initialize a ST7735S chip, green tab
tft.fillScreen(BLACK);

gameStatus = GAME_RESTART;
BallInit(ball);
}

1行目のinitRの引数になっている「INITR_GREENTAB」は、液晶モジュールのバージョンによって、異なる値を与えなければならないようです。

Adafruit_ST7735の現状のヘッダファイルでは、この引数に使える値は「INITR_BLACKTAB」「INITR_GREENTAB」「INITR_REDTAB」の3種類が定義されています。
この値によって、液晶コントローラに送られる初期化コマンド列が変わります。

液晶モジュールの種類をどう見分けるかですが、この「BLACK」「GREEN」「RED」は液晶パネルの保護シールの引き剥がし用の耳(tab)の色なのだそうです。
少し昔のバージョンのAdafruit_ST7735を使ったスケッチ例を見ると、コメントでそのように記載されていました。
以下引用です。
  // Our supplier changed the 1.8" display slightly after Jan 10, 2012
// so that the alignment of the TFT had to be shifted by a few pixels
// this just means the init code is slightly different. Check the
// color of the tab to see which init code to try. If the display is
// cut off or has extra 'random' pixels on the top & left, try the
// other option!
// If you are seeing red and green color inversion, use Black Tab

// If your TFT's plastic wrap has a Black Tab, use the following:
tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab
// If your TFT's plastic wrap has a Red Tab, use the following:
//tft.initR(INITR_REDTAB); // initialize a ST7735R chip, red tab
// If your TFT's plastic wrap has a Green Tab, use the following:
//tft.initR(INITR_GREENTAB); // initialize a ST7735R chip, green tab


今回使用した液晶はAdafruitの製品ではありませんが、青緑色のプルタブが付いていました。
arduino08-02.jpg

Adafruit製品のLCDモジュールと今回のaitendoのLCDモジュールが同一サプライヤの製品であるかどうかは定かではありません。
ネットの情報では、緑のタブの製品でもINITR_BLACKTABを指定すると正しく動いた、という例もあるようで、結局3種類を試して一番正常なものを選ぶのが良さそうです。

ちなみに私が試したところ、今回のaitendoの液晶モジュールは

・INITR_BLACKTAB・・・画面の下端と右端にランダムな色のノイズピクセルが出る。
上端と左端が2ピクセルほど切れる。
(aitendoの商品ページでもそうなっています)

・INITR_REDTAB・・・画面の下半分が表示されない。

・INITR_GREENTAB・・・ピクセルは表示されるが、色指定がRGBではなくBGRとなる。

となりました。

ピクセルが正常に表示されるのは、INITR_GREENTABですが、赤と青が入れ替わるので、まったく違う色調になってしまいます。

今回のブロック崩しは、もともとカラーを8色しか使っていないので、この問題へはスケッチファイル側で色の定義を変更することで対応しました。
スケッチファイル側を変更したくない場合は、ライブラリのソースコード(Adafruit_ST7735.cpp)を編集することで対応することもできます。
ライブラリの修正部分は別記事で載せておきます。

配線は、下図のようにしました。
コントローラ用の可変抵抗器はA1、圧電ブザーは3番の信号線を使用しています。
液晶への配線は前回と変わっていません。

arduino08-01.png


以上の変更を反映したスケッチファイルと、動作の様子は以下の通りです。
breakout5.ino



posted by boochow at 02:39| Comment(0) | Arduino | このブログの読者になる | 更新情報をチェックする
人気記事