4×4電子チェスボードプロトタイプ:RFIDとArduinoの統合
コンポーネントと用品
![]() |
ホール効果センサー | ×16 |
![]() |
はんだ不要ブレッドボード フルサイズ | ×1 |
![]() |
LED(汎用) | ×16 |
| RFIDリーダー(汎用) 125 kHz RFIDリーダーとアンテナ |
×1 | |
![]() |
Arduino Mega 2560 | ×1 |
| RFIDタグ 3M | ×2 |
必要な工具と機械
| プレキシガラス | |
| 光沢紙 | |
| 木材板 | |
| アクリル絵具(ダークグリーンとクリーム)×2 | |
| 10mm丸型マグネット | |
| ポーンとクイーンのチェス駒 | |
| はんだごてと材料 |
アプリとオンラインサービス
![]() |
Arduino IDE |
このプロジェクトについて
こんにちは、メイカーの皆さん。
私はタヒル・ミリエフ、2018年にトルコ・アンカラの中東工科大学を卒業しました。専攻は応用数学でしたが、電子工作、設計、プログラミングを伴うものづくりが大好きでした。工業デザイン学部で提供されていたプロトタイピングのユニークなコースのおかげで、本当に面白いものを作る機会を得ました。このプロジェクトは学期課題として、1学期(4ヶ月)かけて取り組みました。学生には、既存の製品/デモに創造的なアプローチで取り組み、Arduinoマイクロコントローラーとセンサーを使ってアイデアを実現する課題が出されました。私はチェスについて考え、過去の成功プロジェクトを調査した結果、以前のプロジェクトではメイカーたちは基本的に完成されたチェスエンジン(全駒の手がコアにプログラム済み)をRaspberry Pi、MUX、LED、リードスイッチと共に使用していることに気づきました。私のプロジェクトでは、チェスエンジンのような外部ソフトウェアを排除し、RFIDリーダー、ホール効果センサー、Arduino Megaを使って「駒認識問題」の創造的な解決策を見つけることにしました。

簡単に言うと、「頭脳」=マイクロコントローラーを持つチェスボードがあり、どの駒を手に持っていて、どこに置いたかをボードに理解させる必要があります。これが駒認識問題です。チェスエンジンがあり、ゲーム開始時に全駒が初期配置にある場合、この問題の解決は自明です。なぜか説明する前に、いくつか補足します。
仕組みに興味のある方のために、なぜリードスイッチ(私の場合はホール効果センサー)が必要かを説明します:各駒の下に磁石を置き、ボード上のマスから駒を持ち上げると(各マスの下にリードスイッチがあると仮定)、センサー上の磁場の有無によって、マイクロコントローラーは駒がマスにあるかないかを理解できます。しかし、これだけでは「どの駒」がそのマスにあるかはわかりません。駒が「ある/ない」だけです。ここで駒認識問題に直面します。これは、ゲーム開始時に全駒が初期位置に配置されたチェスエンジンを使えば解決できます。こうすればマイクロコントローラーは最初から全駒の位置を「知っており」、全アドレスがメモリに固定されます。しかし、これは大きな制約をもたらします:例えば任意の数の駒を選んでボードの任意の場所に配置し、そこからゲーム分析を始めることはできません。常に最初から始め、全駒が最初からボードにある必要があります。これが私が気づいた問題で、解決に取り組みました。
私の解決策は非常にシンプルですが、創造的でした。ボードの前面にRFIDリーダーを配置しました。一方、駒の下には磁石だけでなく、各駒にユニークなIDを持つRFIDタグも取り付けました。したがって、駒を任意のマスに置く前に、まず駒をRFIDリーダーの近くにかざしてIDを読み取らせ、駒を特定し、メモリに保存してから、好きな場所に置くことができます。また、リードスイッチの代わりにホール効果センサーを使用し、回路設計を簡略化しました。これらは同様に動作し、マイクロコントローラーに0または1のデジタルデータを送るだけで、それぞれ「駒がある」「駒がない」を意味します。さらにLEDも追加しました(残念ながら同色ではありませんでしたが)、駒を持ち上げると、その駒を置ける全てのマスが点灯します。チェス学習者への教育的練習として考えてください :)
最後に、いくつかの技術を使用しましたが、プロジェクトはシンプルで理解しやすく、深く掘り下げたり過度に複雑にしたりしていません。8×8チェスボードに進む時間がなかった(トルコでは64個のホール効果センサーが高価で、プロジェクト関連費用は全て自己負担だったため)、ポーンとクイーンの2駒のみテストした4×4デモ版に留めました。チェスエンジンの代わりに、全てを生成するArduino用ソースコードを書きました。
ステップバイステップの説明に入る前に、説明動画を見て直感的に理解することをお勧めします。
注1:赤色LEDの1つ(左から最初)が切れていますが、気にしないでください。
注2:広く使われていますが、私の経験ではRFID技術はDIYアプリケーションには最適ではないと言えます(代替手段がある場合)。全てが動作するまで、チェス駒をリーダーに近づけて正しくIDが読み取れるまで多くの試行を繰り返しました。シリアルポートを設定する必要があります。RFIDリーダーがIDを読み取る仕組みは頭痛の種です。自分で試せばその問題が理解できるでしょう。

使用した全ツールのリスト:
電子部品:
- ブレッドボード (×1)
- 全方向性 A1126LUA-T (IC-1126 SW OMNI 3-SIP ALLEGRO) ホール効果センサー (×16)
- 基本 5mm LED (×16)
- ジャンパーワイヤー
- 125 kHz RFIDリーダーとアンテナ (×1)
- Arduino Mega (×1)
- RFID 3Mタグ (×2)
その他の材料:
- プレキシガラス
- 光沢紙
- 短い木材板
- アクリル絵具(ダークグリーンとクリーム)×2
- 薄い段ボール
- 10mm丸型マグネット (×2)
- ポーンとクイーンの駒
- はんだごてと材料

制作手順の説明。以下のステップバイステップ説明に従ってください:
- 21×21cmの段ボールと、ボード上部の壁を作るための余分な段ボールを用意し、A B C D 1 2 3 4と番号付けされた16マスを作ります。段ボールが薄いため、各マスにホール効果センサー(3本足)とLED(2本足)を16個ずつ差し込めます。
- 部品を配置したら、ホール効果センサーとLEDの足をジャンパーワイヤーにはんだ付けします。この段階で、LEDの+と-、ホール効果センサーのVCC、GND、PIN足が混同されないよう、色分けされたワイヤーを賢く選ぶことをお勧めします。もちろん、センサーとWS2812タイプのLEDを既にはんだ付けしたPCBを作ることもできますが、私はプロジェクトをシンプルに保ち、より多くの「手作業」を行うことにしました。この時点でコードとセンサーを準備し、後の段階でFritzing回路図に従って各ワイヤーの端をどこに接続するか確認できます。簡単に言うと、一部はArduino Megaのピンに直接接続(Arduinoには十分なピンがあります)、他はブレッドボードへ、全てのGNDは1本のコードにはんだ付けして共通グランドとし、後でArduinoボードのGNDに接続します。重要な注意点:ホール効果センサーは全方向性(OMNIDIRECTIONAL)で、磁石のどちらの極をセンサーに近づけても、磁場がある間は0データを送り、磁石が離れる(約5cm以上)と1を送ります。
- 同様の21×21cm段ボールを用意し、Arduino Megaとロングブレッドボードを固定します。段ボールから好きな高さの4面を切り出し、2枚の21×21cmボードに垂直に接着します。その後、Fritzing回路図に従ってセットアップします。LEDとホール効果センサーが完了したらRFIDリーダーもセットアップできます。
- 基本的なコードで信号を送り、全LEDとセンサーが動作するかテストします。このステップを省略せず、全てが正常に動作するか確認してからボードのさらなる構築に進んでください。
- ポーンとクイーンを用意し、下部に10cm半径のマグネット2個と丸型RFIDタグを取り付けます。後でArduino IDEのシリアル画面でそれらのタグIDを読み取ります。
- 全てがうまく動けば、メインコードを開始して試せます!
- (任意) 木工で芸術的な仕上げをすれば、デモにより自然な見た目になります。これはあなたの意志と想像力次第です。
様々な段階の動画と写真

ご覧いただきありがとうございます!全てテストして、コメントで気づいた間違い、改善点、提案などを自由に書き込んでください。プロジェクトについての意見を楽しみにしています。プロジェクトで何か支援が必要な場合は、メール(miriyevt@gmail.com)またはSkype(tahir.miriyev9r1)で連絡してください。スケジュールを調整して詳細に話し合いましょう。幸運を祈ります!
コード
- thinK_code.ino
thinK_code.ino Arduino
コード分析が理解しやすいよう、できるだけ多くのコメントを残しました。正直、最初はロジックが少し複雑に見えるかもしれませんが、コードのロジックを深く掘り下げればより理解しやすくなるでしょう。
注:実際のチェスボードと同様に、マスをA1、A2、A3、A4、B1、...、C1、...、D1、...、D4と抽象的に番号付けしました。しかし、コードではこの表記は実用的ではないため、配列を使用し、マスを00、01、02、03、10、11、12、13、...、32、33と表現しました。
#include <SoftwareSerial.h>
SoftwareSerial RFID(11, 12);
//----------------------------------------------------------- START ---------------------------------------------------------------------------------------------
int empty_pos[2];
int figure_pos[2][2]; // 駒位置を2つのベクトル(クイーンとポーン)の行列として考える(x位置、y位置、値1=クイーン、2=ポーン)
int new_id[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int id_type_matrix[4][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
int temp = 0;
int queen_id[14] = {2, 53, 65, 48, 48, 56, 51, 49, 55, 70, 65, 51, 52, 3};
int pawn_id[14] = {2, 53, 65, 48, 48, 56, 51, 56, 67, 49, 56, 52, 68, 3};
int temp_vect[2];
int count = 0;
int ID = 0;
int yeni_id[14];
// ホール効果センサーの初期配列マトリックス
int hes_bool_matrix[4][4];
// ホール効果センサーのArduinoピンリスト
const int hes_00 = 44; const int hes_01 = 45; const int hes_02 = 46; const int hes_03 = 47;
const int hes_10 = 48; const int hes_11 = 49; const int hes_12 = 50; const int hes_13 = 2;
const int hes_20 = 3; const int hes_21 = 4; const int hes_22 = 5; const int hes_23 = 6;
const int hes_30 = 7; const int hes_31 = 8; const int hes_32 = 9; const int hes_33 = 10;
int hes_pin_matrix[4][4] = {
{hes_00, hes_01, hes_02, hes_03},
{hes_10, hes_11, hes_12, hes_13},
{hes_20, hes_21, hes_22, hes_23},
{hes_30, hes_31, hes_32, hes_33}
};
// LEDピン
const int led_00 = 22; const int led_01 = 23; const int led_02 = 24; const int led_03 = 25;
const int led_10 = 26; const int led_11 = 27; const int led_12 = 28; const int led_13 = 29;
const int led_20 = 30; const int led_21 = 31; const int led_22 = 32; const int led_23 = 33;
const int led_30 = 34; const int led_31 = 35; const int led_32 = 36; const int led_33 = 37;
int led_matrix[4][4] = {
{led_00, led_01, led_02, led_03},
{led_10, led_11, led_12, led_13},
{led_20, led_21, led_22, led_23},
{led_30, led_31, led_32, led_33}
};
//----------------------------------------------------- SETUP AREA ---------------------------------------------------------------------------------
void setup() {
RFID.begin(9600);
Serial.begin(9600);
// ホール効果センサーの入力モード設定
pinMode(hes_01, INPUT); pinMode(hes_02, INPUT); pinMode(hes_03, INPUT); pinMode(hes_00, INPUT);
pinMode(hes_10, INPUT); pinMode(hes_11, INPUT); pinMode(hes_12, INPUT); pinMode(hes_13, INPUT);
pinMode(hes_20, INPUT); pinMode(hes_21, INPUT); pinMode(hes_22, INPUT); pinMode(hes_23, INPUT);
pinMode(hes_30, INPUT); pinMode(hes_31, INPUT); pinMode(hes_32, INPUT); pinMode(hes_33, INPUT);
// LEDピンの出力モード設定
pinMode(led_00, OUTPUT); pinMode(led_01, OUTPUT); pinMode(led_02, OUTPUT); pinMode(led_03, OUTPUT);
pinMode(led_10, OUTPUT); pinMode(led_11, OUTPUT); pinMode(led_12, OUTPUT); pinMode(led_13, OUTPUT);
pinMode(led_20, OUTPUT); pinMode(led_21, OUTPUT); pinMode(led_22, OUTPUT); pinMode(led_23, OUTPUT);
pinMode(led_30, OUTPUT); pinMode(led_31, OUTPUT); pinMode(led_32, OUTPUT); pinMode(led_33, OUTPUT);
read_tags(); delay(1000);
first_figure(); delay(1000);
Serial.end(); RFID.end(); delay(5000);
Serial.begin(9600); delay(1000); RFID.begin(9600); delay(1000);
read_tags(); delay(5000);
// RFID.flush(); // 複数読み取り防止
second_figure(); delay(1000);
// id_type_matrix[0][2] = 2; // id_type_matrix[2][1] = 1;
}
//---------------------------------------------------FUNCTIONS AREA------------------------------------------------------------
//----------------------------------------RFID ID追跡と駒認識-----------------------------------------------
boolean compare_ID(int aa[14], int bb[14]) {
boolean ff = false;
int fg = 0;
for (int cc = 0; cc < 14; cc++) {
if (aa[cc] == bb[cc]) { fg++; }
}
if (fg == 14) { ff = true; }
return ff;
}
int read_tags() {
Serial.println("Place the figure near to RFID reader");
delay(5000);
RFID.flush(); // 複数読み取り防止
if (RFID.available() > 0) {
delay(300);
for (int z = 0; z < 14; z++) {
ID = RFID.read();
new_id[z] = ID;
Serial.println(new_id[z], DEC);
delay(500);
}
}
Serial.println("ID reading is done ");
++count;
delay(5000); // 駒をボードに置き、次の駒をRFIDリーダーにかざす時間
return new_id;
}
void first_figure() {
if (compare_ID(new_id, queen_id) == true) {
Serial.println("QUEEN IS DETECTED");
for (int s = 0; s <= 3; s++) {
for (int t = 0; t <= 3; t++) {
if (digitalRead(hes_pin_matrix[s][t]) == 0) {
id_type_matrix[s][t] = 1;
temp_vect[0] = s; temp_vect[1] = t;
Serial.print("Queen is placed onto:"); Serial.print(s); Serial.println(t);
digitalWrite(led_matrix[s][t], HIGH); delay(1000); digitalWrite(led_matrix[s][t], LOW);
}
}
}
} else if (compare_ID(new_id, pawn_id) == true) {
Serial.println("PAWN IS DETECTED");
for (int s = 0; s <= 3; s++) {
for (int t = 0; t <= 3; t++) {
if (digitalRead(hes_pin_matrix[s][t]) == 0) {
id_type_matrix[s][t] = 2;
temp_vect[0] = s; temp_vect[1] = t;
Serial.print("Pawn is placed onto:"); Serial.print(s); Serial.println(t);
digitalWrite(led_matrix[s][t], HIGH); delay(1000); digitalWrite(led_matrix[s][t], LOW);
}
}
}
} else {
Serial.println("Undefined figure ");
}
}
void second_figure() {
if (compare_ID(new_id, queen_id) == true) {
Serial.println("QUEEN IS DETECTED");
for (int s = 0; s <= 3; s++) {
for (int t = 0; t <= 3; t++) {
if (digitalRead(hes_pin_matrix[s][t]) == 0 && (s != temp_vect[0] || t != temp_vect[1])) {
id_type_matrix[s][t] = 1;
Serial.print("Queen is placed onto:"); Serial.print(s); Serial.println(t);
digitalWrite(led_matrix[s][t], HIGH); delay(1000); digitalWrite(led_matrix[s][t], LOW);
}
}
}
} else if (compare_ID(new_id, pawn_id) == true) {
Serial.println("PAWN IS DETECTED");
for (int s = 0; s <= 3; s++) {
for (int t = 0; t <= 3; t++) {
if (digitalRead(hes_pin_matrix[s][t]) == 0 && (s != temp_vect[0] || t != temp_vect[1])) {
id_type_matrix[s][t] = 2;
Serial.print("Pawn is placed onto:"); Serial.print(s); Serial.println(t);
digitalWrite(led_matrix[s][t], HIGH); delay(1000); digitalWrite(led_matrix[s][t], LOW);
}
}
}
}
}
//----------------------------------------------- LED消灯(駒をボードに戻した時のみ)-------------------------------------------------------------------------
void leds_off() {
int i, j;
for (i = 0; i <= 3; i++) {
for (j = 0; j <= 3; j++) {
digitalWrite(led_matrix[i][j], LOW);
}
}
}
//------------------------------------------------- クイーンの移動可能マス表示------------------------------------------------------------------------------------------------
void move_queen() {
int i, j;
for (i = empty_pos[0]; i < 3;) { digitalWrite(led_matrix[++i][empty_pos[1]], HIGH); } // 縦方向
for (i = empty_pos[0]; i > 0;) { digitalWrite(led_matrix[--i][empty_pos[1]], HIGH); }
for (i = empty_pos[1]; i < 3;) { digitalWrite(led_matrix[empty_pos[0]][++i], HIGH); } // 横方向
for (i = empty_pos[1]; i > 0;) { digitalWrite(led_matrix[empty_pos[0]][--i], HIGH); }
i = empty_pos[0]; j = empty_pos[1];
for (i = i - 3, j = j - 3; i <= 3 && j <= 3; i++, j++) { // 斜め方向
if (i >= 0 && j >= 0 && i != empty_pos[0]) { Serial.print(i); Serial.println(j); digitalWrite(led_matrix[i][j], HIGH); }
}
i = empty_pos[0]; j = empty_pos[1];
for (i = i + 3, j = j - 3; i >= 0 && j <= 3; i--, j++) {
if (i >= 0 && i <= 3 && j >= 0 && j <= 3 && i != empty_pos[0]) { Serial.print(i); Serial.println(j); digitalWrite(led_matrix[i][j], HIGH); }
}
}
//------------------------------------- 駒の数と位置を読み取り保存 --------------------------
void figure_reading() {
int i, j, found_figure = 0;
start:
found_figure = 0;
// ボード上の全位置を読み取り、占有(0)と空き(1)を検出
// 0=空きマス、1=占有マスを変数に代入
hes_bool_matrix[0][0] = digitalRead(hes_00); hes_bool_matrix[0][1] = digitalRead(hes_01);
hes_bool_matrix[0][2] = digitalRead(hes_02); hes_bool_matrix[0][3] = digitalRead(hes_03);
hes_bool_matrix[1][0] = digitalRead(hes_10); hes_bool_matrix[1][1] = digitalRead(hes_11);
hes_bool_matrix[1][2] = digitalRead(hes_12); hes_bool_matrix[1][3] = digitalRead(hes_13);
hes_bool_matrix[2][0] = digitalRead(hes_20); hes_bool_matrix[2][1] = digitalRead(hes_21);
hes_bool_matrix[2][2] = digitalRead(hes_22); hes_bool_matrix[2][3] = digitalRead(hes_23);
hes_bool_matrix[3][0] = digitalRead(hes_30); hes_bool_matrix[3][1] = digitalRead(hes_31);
hes_bool_matrix[3][2] = digitalRead(hes_32); hes_bool_matrix[3][3] = digitalRead(hes_33);
for (i = 0; i <= 3; i++) {
for (j = 0; j <= 3; j++) {
if (hes_bool_matrix[i][j] == 0) {
found_figure++;
if (found_figure == 1) {
if (id_type_matrix[i][j] == 0) { id_type_matrix[i][j] = temp; temp = 0; }
if (id_type_matrix[i][j] == 1) { Serial.print("Queen is standing on:"); Serial.print(i); Serial.println(j); figure_pos[0][0] = i; figure_pos[0][1] = j; }
else if (id_type_matrix[i][j] == 2) { Serial.print("Pawn is standing on:"); Serial.print(i); Serial.println(j); figure_pos[0][0] = i; figure_pos[0][1] = j; }
} else if (found_figure == 2) {
if (id_type_matrix[i][j] == 0) { id_type_matrix[i][j] = temp; temp = 0; }
if (id_type_matrix[i][j] == 1) { Serial.print("Queen is standing on:"); Serial.print(i); Serial.println(j); figure_pos[1][0] = i; figure_pos[1][1] = j; }
else if (id_type_matrix[i][j] == 2) { Serial.print("Pawn is standing on:"); Serial.print(i); Serial.println(j); figure_pos[1][0] = i; figure_pos[1][1] = j; }
}
}
}
}
out:
if (found_figure == 0 || found_figure == 1) { goto start; }
else if (found_figure == 2) { leds_off(); }
//---------------------------------------------- どの駒を持ち上げたか判定 -----------------------------------------------------------------
empty_pos[0] = -1;
delay(2000);
if (digitalRead(hes_pin_matrix[figure_pos[0][0]][figure_pos[0][1]]) == 1) {
empty_pos[0] = figure_pos[0][0]; empty_pos[1] = figure_pos[0][1];
temp = id_type_matrix[empty_pos[0]][empty_pos[1]];
id_type_matrix[empty_pos[0]][empty_pos[1]] = 0;
} else if (digitalRead(hes_pin_matrix[figure_pos[1][0]][figure_pos[1][1]]) == 1) {
empty_pos[0] = figure_pos[1][0]; empty_pos[1] = figure_pos[1][1];
temp = id_type_matrix[empty_pos[0]][empty_pos[1]];
id_type_matrix[empty_pos[0]][empty_pos[1]] = 0;
}
//------------------------------------------- ポーンまたはクイーンの移動可能マス表示----------------------------------------------------------------------------------------------------
if (temp == 1) {
if (empty_pos[0] != -1) { move_queen(); goto start; }
} else if (temp == 2) {
if (empty_pos[0] != -1) {
if (empty_pos[0] < 2) {
digitalWrite(led_matrix[empty_pos[0] + 1][empty_pos[1]], HIGH);
digitalWrite(led_matrix[empty_pos[0] + 2][empty_pos[1]], HIGH);
} else if (empty_pos[0] == 2) {
digitalWrite(led_matrix[empty_pos[0] + 1][empty_pos[1]], HIGH);
}
}
delay(100);
}
figure_reading();
}
//--------------------------------------------------------------------- loop starts ------------------------------------------------------------------------------------
void loop() {
figure_reading();
}
回路図
回路図は少し複雑ですが、アイデアは明確のはずです。Fritzingを初めて使いました(強くお勧めします)、おそらく接続はもっと正確に描けたかもしれません。とにかく、回路図内に全てメモしました。
注:Fritzingのコンポーネントデータベースで正確なRFIDリーダーモデルが見つかりませんでした。使用したのは125kHz RFIDモジュール - UARTです。このモジュールをArduinoでセットアップするチュートリアルはYouTubeで見つかります。
4x4demo_q0nvG3T3nS.fzz
製造プロセス
- ラピッドプロトタイピングが製品開発成功に不可欠な理由
- 電子インク:仕組み、歴史、未来応用
- Raspoulette:太陽光発電自律コープドアシステムのプロトタイプ
- プロトタイプ vs 量産射出成形金型:プロジェクトに最適な金型選び
- PCB試作メーカー選びの完全ガイド:失敗しないための5つの評価基準
- PCB試作必須用語集 第2弾:ガラス転移温度(Tg)ほか
- プロトタイピング解説:スタートアップにとっての重要な検証ステップ
- 電動ポンプ徹底解説:種類・用途・原理と選定指針
- 電子点火システムの仕組み:完全ガイド
- 革新的な電子皮膚、人間の痛覚をリアルタイムで模倣
- RFID技術解説:電波で資産追跡を劇的に効率化




