レーザーモジュールでモールス信号通信 – Arduino二台で送受信
必要なパーツと用品
| Arduino UNO | ×2 |
| ブレッドボード | ×2 |
| レーザートランスミッター | ×1 |
| フォトレジスター(CdSセル) | ×1 |
| ジャンパーワイヤー | ×1 |
使用するアプリ
- Arduino IDE
プロジェクト概要
モールス信号とは
英数字を「点(・)」と「線(−)」の組み合わせで表現する通信方式です。各文字に固有のパターンがあり、秘密通信や符号化通信に用いられます。本プロジェクトでは、レーザー光でモールス信号を送信し、受信側で光センサー(CdSセル)を使って復調・文字表示を行います。受信アルゴリズムが非常にシンプルなのが特徴です。

ステップ1: 送信側(トランスミッター)
必要なハードウェア
- Arduino Uno
- レーザートランスミッター
- ブレッドボード
- ジャンパーワイヤー
配線
レーザーの+ピンをArduinoのデジタル13番ピンに、GNDをArduinoのGNDに接続します(コード内で13番ピン指定)。



プログラムのアルゴリズム
- 送信したい文字列を
char配列で保持 - レーザー接続ピン(13番)を定義
- モールス符号の速度(ドット長)を設定
- ドット長 =
dotLen(ms) - ダッシュ長 = ドット長 × 3
- 要素間スペース = ドット長
- 文字間スペース = ドット長 × 3
- 単語間スペース = ドット長 × 7
- ドット長 =
- 各文字を
switch-caseで判定し、対応するドット/ダッシュのパターンでレーザーをON/OFF
ステップ2: 受信側(レシーバー)
送信された光信号をCdSセルで受光し、シリアルモニタに文字を表示します。


必要なハードウェア
- Arduino Uno
- CdSセル(フォトレジスター)
- 抵抗 10kΩ
- ブレッドボード
- ジャンパーワイヤー
配線
CdSセルの一方を5V、もう一方を10kΩ抵抗とアナログ入力A0に接続。抵抗のもう一方をGNDに接続(分圧回路)。CdSセルは黒い厚紙でドームを作って覆い、外光を遮ると安定します。


受信アルゴリズム(観測ベースのシンプルな手法)
- レーザーが当たっていないとき、CdS値は1000未満。当たると1000を超える。外光の影響がある場合は遮光ドームで対策。
- 値が1000を超えたらループに入り、閾値1000で二値化:超えてたら '1'、以下なら '0' とみなす。
- ループ内で '1' の継続カウント(変数
a)と '0' の継続カウント(変数f)を取る。 - 各文字ごとに
aとfの組み合わせがユニークになるため、パターンマッチングで文字を特定。
制限事項
添付コードは特定の文字(a, b, c, e, i, j, g, o, s)のみ対応。組み合わせを拡張すれば全英数字に対応可能です。本コードの主目的はアルゴリズムの理解です。
ソースコード
CODE-1: 送信側(レーザー制御)
int led13 = 13;
int dotLen = 200;
int dashLen = dotLen * 3;
int elemPause = dotLen;
int Spaces = dotLen * 3;
int wordPause = dotLen * 7;
char stringToMorseCode[] = "HELLO WORLD"; // 送信したい文字列
void setup() {
pinMode(led13, OUTPUT);
}
void loop() {
for (int i = 0; i < sizeof(stringToMorseCode) - 1; i++) {
char tmpChar = stringToMorseCode[i];
tmpChar = toLowerCase(tmpChar);
GetChar(tmpChar);
}
LightsOff(8000); // 文字列終了後の長いポーズ
}
void MorseDot() {
digitalWrite(led13, HIGH);
delay(dotLen);
}
void MorseDash() {
digitalWrite(led13, HIGH);
delay(dashLen);
}
void LightsOff(int delayTime) {
digitalWrite(led13, LOW);
delay(delayTime);
}
void GetChar(char tmpChar) {
switch (tmpChar) {
case 'a': MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); break;
case 'b': MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
case 'c': MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
case 'd': MorseDash(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
case 'e': MorseDot(); LightsOff(elemPause); break;
case 'f': MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
case 'g': MorseDash(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
case 'h': MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
case 'i': MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
case 'j': MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); break;
case 'k': MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); break;
case 'l': MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
case 'm': MorseDash(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); break;
case 'n': MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
case 'o': MorseDash(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); break;
case 'p': MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
case 'q': MorseDash(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); break;
case 'r': MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
case 's': MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
case 't': MorseDash(); LightsOff(elemPause); break;
case 'u': MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); break;
case 'v': MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); break;
case 'w': MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); break;
case 'x': MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); break;
case 'y': MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); break;
case 'z': MorseDash(); LightsOff(elemPause); MorseDash(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); MorseDot(); LightsOff(elemPause); break;
default: LightsOff(Spaces); break; // スペース等
}
}
CODE-2: 受信側(CdSセル読み取り・文字判定)
int sensorPin = 0;
int sensorValue = 0;
int a, f;
void setup() {
Serial.begin(9600);
}
void loop() {
sensorValue = analogRead(sensorPin);
if (sensorValue > 1000) {
for (int i = 0; i <= 13; i++) {
sensorValue = analogRead(sensorPin);
if (sensorValue > 1000) {
a++; // '1' (光あり) のカウント
delay(200);
} else {
f++; // '0' (光なし) のカウント
delay(200);
}
}
}
// パターンマッチングで文字判定
if (a == 4 && f == 10) { Serial.print("a"); }
if (a == 6 && f == 8) { Serial.print("b"); }
if (a == 8 && f == 6) { Serial.print("c"); }
if (a == 1 && f == 13) { Serial.print("e"); }
if (a == 2 && f == 12) { Serial.print("i"); }
if (a == 10 && f == 4) { Serial.print("j"); }
if (a == 7 && f == 7) { Serial.print("g"); }
if (a == 9 && f == 5) { Serial.print("o"); }
if (a == 3 && f == 11) { Serial.print("s"); }
f = a = 0;
delay(200);
}
カスタムパーツとエンクロージャ

回路図

製造プロセス
- レーザーマーキング総合ガイド:種類、メリット、用途
- レーザーポインター:設計、製造、安全性の概要
- 半導体レーザー:現代技術を支える精密光生成
- バーコードスキャナ:技術、設計、将来動向
- レーザー誘導ミサイル:開発、製造、戦略的インパクト
- ZigbeeセンサーとGravioエッジプラットフォームでインタラクティブレーザープロジェクターを構築
- Raspberry Pi 4とHiFive1ボード間でUART通信を確立する
- Raspberry Pi でジェスチャー制御ロボットを構築 – 加速度センサーと RF 通信でハンドフリー操作
- ArduinoだけでDTMFデコーダーを構築 – 外付けIC不要
- Python 3からArduino UNOを制御 – シリアル通信でLED点滅デモ
- 産業製造におけるローコードソリューションの4つの主要メリット