M5Stackとサーマルプリンタで開運おみくじマシーンを作成しよう

# はじめに
こちらの記事は[ユアマイスターアドベントカレンダー2020](https://adventar.org/calendars/5455)、2日目の記事です。

こんにちは！
ユアマイスター広報インターンの村上です。

**気づけば2020年も残すところあと1ヶ月...**
果たしていくつ寝るとお正月なのでしょうか、数えるのも恐ろしいくらい時は早く過ぎ去りますね。

ところで、お正月には初詣に行かれる方は多いはず。
しかし、今年はコロナ禍ということもあり、なかなか外出するのも躊躇われますね...

ということで、そんな状況ではありつつ**おうちでも紙のおみくじを引きたい！！！**とふと思ったので、
今回はサーマルプリンタでおみくじマシーンを作ってみました。

# 完成品
![IMG_7601.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/1e4f7d28-bdf5-2ccb-12b1-cfb7a04bd87a.jpeg)


M5Stackの真ん中のボタンを押せばランダムでおみくじが印刷されるようになっています！
(レシートと同じ紙なのでおみくじがとても丸まってしまう...w)

# 用意するもの
- M5Stack
- microSDカード
- [サーマルプリンタ](https://www.switch-science.com/catalog/5202/)
- 感熱ロール記録紙
- ACアダプタ
- 空き箱

# 下準備
コードを書き込む前の下準備をしていきます！

## サーマルプリンタのセッティング

![qiita_thermal_m5stack.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/0ba81296-6eb4-eb1d-fc4d-228df20a5358.jpeg)

POWERをACアダプタに、TTLをM5Stackに接続します。
TTLのコネクタの4番をGND、5番を16、6番を17番ピンに差し込みます。

また、初期設定としてAdafruit Thermal Printer libraryをインストールします。M5Stackで使用する際はEspSoftwareSerialのライブラリもインストールしておきましょう。

## M5Stackに表示する画像の準備
![omikuji.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/48782d7e-f0c3-3a7b-c7bd-88240361841f.jpeg)
![omikuji_printing.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/62114b2f-599f-d4d5-1ab6-4cb10b6edfb7.jpeg)

今回はデフォルトと印刷中の画像の2つの画像を用意します。
画像のサイズは320×240で、必ず「画像名.jpg」の形式でmicroSDカードに書き込んでください。

## 印刷するおみくじの画像の準備

![スクリーンショット 2020-11-30 3.25.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/b538e763-a7b8-a106-8cd6-93144430e4c1.png)

まず390×639でおみくじ用の画像を用意します。
（縦はどんな長さでも大丈夫ですが、横はこれくらいだとちょうどぴったりくらいで印刷ができると思います。画像のサンプルは[こちら](https://drive.google.com/drive/folders/1aanX7fnOiolfrzR_Lmak5DosiadIGSXH?usp=sharing)）

次にその画像をサーマルプリンタで印刷するために**ビットマップ画像化**します。

ビットマップ画像化するためのProcessingコードは
`ファイル->スケッチ例->Adafruit Thermal Printer library->Processing->bitmapImageConvert` に格納されているので、このファイルをProcessingで開き、実行します。

画像を選択するとProcessingのコンソールに

```
Loading image...
Writing output to /画像パス/sampleImage.h
Done!
```

と表示され、新しくビットマップ化された `画像ファイル名.h` ファイルが生成されます。
中のファイルを見てみると以下のようになっています。

```sampleImage.h
#ifndef _sampleImage_h_
#define _sampleImage_h_

#define sampleImage_width  390
#define sampleImage_height 639

static const uint8_t PROGMEM sampleImage_data[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  .....省略
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

#endif // _sampleImage_h_

```

画像のwidth,heightとビットマップ化されたデータが格納されていますね！

M5Stackに書き込むファイルでこちらのファイルを読み込み、width,height,dataを引数として渡すことで印刷ができるようになります。

```c
// 画像データのファイルを読み込む
#include "sampleImage.h"

// 画像の幅と高さ、ビットマップデータを引数として渡す
printer.printBitmap(sampleImage_width, sampleImage_height, sampleImage_data);
```


今回はおみくじ画像のwidthとheightは同じなので、Processingでできた画像データの配列を4枚分（大吉、中吉、小吉、凶）をコピーして　`omikuji.h` ファイルに追記していきましょう。

## 空き箱の加工
![IMG_7612.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/54df0e65-c0ed-afc9-c1bd-ead33d9af8ba.jpeg)

M5Stackとサーマルプリンタ丸出しの状態だと一体感がなかったので、今回は空き箱の中に収納しました。（作りが雑なのはご了承ください...）

前面にM5Stack、その後ろにサーマルプリンタが配置されるようにし、空き箱の画面部分とサーマルプリンタの印刷部分に穴を空けます。


# コードを書き込む

今回はM5Stackの真ん中のボタンを押すとランダムにおみくじが印刷されるようなコードを書き込みます。

サーマルプリンターのセッティングと各画像の準備をし、microSDカードを差し込んだら以下のコードをM5Stackに書き込みます。

```c

#include "Adafruit_Thermal.h"
#include "omikuji.h"
#include <M5Stack.h>

#include "SoftwareSerial.h"

// YELLOW WIRE labeled RX on printer
#define TX_PIN 16
// GREEN WIRE labeled TX on printer
#define RX_PIN 17

// Declare SoftwareSerial obj first
SoftwareSerial mySerial(RX_PIN, TX_PIN);
// Pass addr to printer constructor
Adafruit_Thermal printer(&mySerial);

void setup() {
  
  M5.begin();
  
  // デフォルト画像を表示する
  M5.Lcd.drawJpgFile(SD, "/omikuji.jpg");

  // Initialize SoftwareSerial
  mySerial.begin(19200);
  // Init printer (same regardless of serial type)
  printer.begin();

}

void loop() {
  
  M5.update();

  // 真ん中のボタンを押した時の操作
  if (M5.BtnB.wasPressed()) {

    // 乱数の作成
    int randomNumber = random(0,4);

    // 印刷中画像の表示
    M5.Lcd.clear();
    M5.Lcd.drawJpgFile(SD, "/omikuji_printing.jpg");

    // 乱数ごとにおみくじを印刷
    if (randomNumber==0) {
      printer.printBitmap(omikuji_width, omikuji_height, daikichi_data);
    } else if (randomNumber==1) {
      printer.printBitmap(omikuji_width, omikuji_height, syokichi_data);
    } else if (randomNumber==2) {
      printer.printBitmap(omikuji_width, omikuji_height, tyukichi_data);
    } else {
      printer.printBitmap(omikuji_width, omikuji_height, kyou_data);
    }

    // 切りやすいように紙を出す
    printer.feed(4);

    // Tell printer to sleep
    printer.sleep();
    // Sleep for 3 seconds
    delay(3000L);
    // MUST wake() before printing again, even if reset
    printer.wake();
    // Restore printer to defaults
    printer.setDefault();

    // デフォルト画像の表示
    M5.Lcd.clear();
    M5.Lcd.drawJpgFile(SD, "/omikuji.jpg");
  }
}
```

**【印刷されたおみくじ】**
![IMG_7607.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/a4586e04-3ceb-47b3-e9c9-d64453cf8d3a.jpeg)


# おわりに
最初は画像ではなく文字で印刷しようとしたのですが、日本語での印刷がなかなかむずかしく、アレンジが効きにくいので画像での印刷にしました。

現状4枚(少ないw)がランダムで出る形なのですが、もう少しバラエティを増やしてオリジナルなおみくじを作ることができれば、さらに面白くなりそうです。

しかし、普通のおみくじと違って気軽に何回も引けてしまうのはよろしくないですねw
~~ちなみに私は大吉が出るまで5回引きました。~~
でも最後に出たのが大吉だったので2021年はいい年になると思います！！！！！！

それでは残り1ヶ月良いお年をお過ごしください！

# 参考にしたもの
- [Bitmap Printing | Mini Thermal Receipt Printer](https://learn.adafruit.com/mini-thermal-receipt-printer/bitmap-printing?view=all)