部品 · 読了まで17分

433MHz RFモジュールとArduinoのガイド:送信機・受信機・アンテナ

433MHz RFモジュールとArduinoのガイドです。FS1000A送信機とXY-MK-5V受信機の配線、17.3 cmのアンテナ、RadioHeadでのメッセージ送信、RCSwitchでのリモコンのコピーを解説します。

433MHz RFモジュールは、Arduinoのプロジェクトに無線通信を加えるいちばん安い方法です。送信機(FS1000A)と受信機(XY-MK-5V)のセットはとても安く、データ線1本で接続でき、17 cmのワイヤーアンテナを付ければ数十メートル先まで信号が届きます。リモコン式のコンセント、ワイヤレスチャイム、シャッターのリモコン、ドアや窓のセンサー、気象ステーションの屋外センサーも、多くが同じ周波数を使っています。そのため、このモジュールを使えば2台のArduino間でデータを送れるだけでなく、家にある既製のリモコンのコードを読み取り、Arduinoから送り直すこともできます。

このガイドでは、モジュールがASK(OOK)変調でどのように動くのか、アンテナを17.3 cmにする理由、Arduino Uno、ESP32、Raspberry Pi Picoへの配線を学びます。続いて、RadioHeadライブラリで2台のArduino間にテキストとセンサーデータを送り、RCSwitchライブラリでコンセントのリモコンのコードを読み取ってコピーし、通信距離を延ばす方法を確認し、nRF24L01と比較します。

433MHz RFモジュールとは?どのように動くのか

セットは2枚の別々のボードでできています。小さな正方形のFS1000A送信機(XY-FSTという名前でも売られています)は、DATAピンに入る信号に合わせて433.92 MHzの搬送波をオン・オフします。細長いXY-MK-5V受信機は、空中のその信号を受け取り、DATAピンから再び0と1として出力します。つまり、モジュール自体にはプロトコルもアドレスもエラーチェックもありません。役割はデジタル信号を無線で相手側に届けることだけです。データをパケットにまとめ、確認し、復号するのはArduino側のライブラリの仕事です。通信は一方向です。送信機は送るだけ、受信機は聞くだけです。

項目FS1000A(送信機)XY-MK-5V(受信機)
周波数433.92 MHz(315 MHz版もあり)433.92 MHz
電源電圧3〜12 V5 V
電流送信中は約9〜40 mA(電圧による)約4 mA
変調方式ASK / OOKASK / OOK、超再生方式の受信機
通信速度最大約10 kbps(実用上は1〜4 kbps)送信機と同じ上限
出力 / 感度約10 mW、電圧が高いほど増加約−105 dBm
ピンDATA、VCC、GND+ANTのはんだ付けパッドVCC、DATA、DATA、GND+ANTのはんだ付けパッド
サイズ約19 × 19 mm約30 × 14 mm

受信機の2つのDATAピンはボード上でつながっているので、どちらを使ってもかまいません。XY-MK-5Vは安価ですが選択度の低い超再生方式の受信機です。周波数はボード上の調整用コイルで決まり、近くのノイズの影響を受けやすくなっています。このコイルのネジは回さないでください。工場出荷時の調整がずれると、受信機が送信機の信号を受け取れなくなります。より安定した結果がほしいなら、RXB6のようなスーパーヘテロダイン方式の受信機のほうが感度が高く、3.3 Vでも動作します。セットには315 MHz版もあります。送信機と受信機の周波数は同じでなければならず、送信機ボードの金属製の共振器には、たいてい周波数が印字されています。

ASK(OOK)変調:なぜライブラリが必要なのか

ASK(Amplitude Shift Keying、振幅偏移変調)のいちばん単純な形であるOOK(On-Off Keying)では、1のビットで搬送波をオンにし、0のビットでオフにします。簡単そうですが、受信機には癖があります。内部の自動利得制御(AGC)は、信号がないときに利得を最大まで上げ、空中のノイズをデータと勘違いして、DATAピンからランダムなパルスを出し続けます。そのため、送信機をArduinoのTXピンに、受信機をRXピンに直接つないでSerial.printで通信しようとしても、たいていは文字化けに終わります。

RadioHeadライブラリのRH_ASKドライバは、この問題を次のように解決します。各パケットの前に36ビットのプリアンブルと12ビットのスタートシンボルを送り、受信機の利得を落ち着かせます。次に、各バイトをDCバランスのとれた6ビットのシンボル2つに変換し(4ビットから6ビットへの符号化)、パケットの最後に16ビットのCRCを付けます。受信機はCRCが一致しないパケットを黙って捨てるので、正しいデータだけが届きます。一方、RCSwitchはリモコン用チップが使うパルス幅による符号を解読します。各ビットは、決まった時間だけHIGHとLOWを保つパルスで表されます。

433MHzのアンテナの長さ:なぜ17.3 cmなのか

モジュールにはアンテナが付いておらず、ANTと書かれたはんだ付けパッドがあるだけです。アンテナなしでは、セットは1〜3メートルしか届きません。いちばん効率のよい簡単なアンテナは、波長の4分の1の長さのまっすぐなワイヤーです。λ = c / f = 300,000,000 / 433,920,000 ≈ 0.69 mで、その4分の1は約17.3 cmになります。315 MHzのモジュールでは、同じ計算で23.8 cmです。単線の一端をANTパッドにはんだ付けし、ワイヤーをまっすぐ垂直に保ちます。受信機にも同じ長さのワイヤーをはんだ付けし、2本のアンテナを同じ向きにそろえます。

アンテナ長さおおよその通信距離(見通しのよい屋外)メモ
アンテナなし―1〜3 m机の上でのテスト専用
まっすぐなワイヤー(λ/4)、送信機は5 V17.3 cm20〜50 mいちばん簡単で効率のよい方法
まっすぐなワイヤー(λ/4)、送信機は9〜12 V17.3 cm50〜100 m以上見通しと設置の高さが大きく影響する
既製のヘリカル(スプリング)アンテナ長さ2〜4 cmまっすぐなワイヤーより短いケースの中に収まる

433MHz RFモジュールの配線:Arduino Uno、ESP32、Pico

モジュールのピンArduino Uno(RadioHead)Arduino Uno(RCSwitch)ESP32Raspberry Pi Pico
FS1000A VCC5Vまたは外部電源9〜12 V5VVIN(5 V)VBUS(5 V)
FS1000A DATAD12D10GPIO 26GP15
FS1000A GNDGNDGNDGNDGND
XY-MK-5V VCC5V5VVIN(5 V)VBUS(5 V)
XY-MK-5V DATAD11D2(割り込みピン)GPIO 27(分圧回路経由)GP14(分圧回路経由)
XY-MK-5V GNDGNDGNDGNDGND
XY-MK-5V受信機のDATA出力は5 Vまで上がります。ESP32とPicoのピンは5 V非対応なので、これらのボードに受信機をつなぐときは、DATAラインに必ず分圧回路を入れるか(たとえば上側10 kΩ、下側20 kΩで約3.3 V)、3.3 Vで動作する受信機を使ってください。送信機を12 Vで動かす場合は、その電圧を絶対にボードのピンに触れさせず、すべてのGNDを共通に接続します。

送信機はDATAピンに3.3 Vの信号が入っても問題なく動作します。そのため、ESP32とPicoでは送信機を5 Vで動かし、DATAをGPIOに直接つなげます。通信距離にいちばん大きく影響するのは送信機の電圧です。3.3 Vでは距離がはっきり短くなり、9〜12 Vでは数倍に伸びます。受信機のVCCピンとGNDピンのすぐそばに100 nFのセラミックコンデンサと10 µFの電解コンデンサを置くと、電源からのノイズが減り、受信状態が目に見えてよくなります。

RadioHeadで2台のArduino間にメッセージを送る

  1. Arduino IDEでライブラリマネージャを開き、RadioHeadを検索して、Mike McCauley氏のライブラリをインストールします。詳しくはArduinoにライブラリを追加する方法を参照してください。
  2. 1台目のArduinoに送信機をつなぎます:DATA → D12、VCC → 5V、GND → GND。
  3. 2台目のArduinoに受信機をつなぎます:DATA → D11、VCC → 5V、GND → GND。
  4. 両方のモジュールのANTパッドに、17.3 cmのワイヤーを1本ずつはんだ付けします。
  5. 送信側のコードを1台目のボードに、受信側のコードを2台目のボードに書き込み、受信側でシリアルモニタを9600ボーで開きます。
C++ (Arduino IDE)
1#include <RH_ASK.h>
2#include <SPI.h>                  // RadioHead derlemesi için / needed for RadioHead to compile
3
4RH_ASK rf(2000, 11, 12);          // hız (bps), RX pini, TX pini / speed (bps), RX pin, TX pin
5unsigned int sayac = 0;
6
7void setup() {
8  Serial.begin(9600);
9  if (!rf.init()) Serial.println("RF init hatasi / failed");
10}
11
12void loop() {
13  char mesaj[24];
14  snprintf(mesaj, sizeof(mesaj), "Merhaba %u", sayac++);
15  rf.send((uint8_t *)mesaj, strlen(mesaj));
16  rf.waitPacketSent();            // paket bitene kadar bekle / wait until the packet is sent
17  Serial.print("Gonderildi / sent: ");
18  Serial.println(mesaj);
19  delay(1000);
20}
C++ (Arduino IDE)
1#include <RH_ASK.h>
2#include <SPI.h>                  // RadioHead derlemesi için / needed for RadioHead to compile
3
4RH_ASK rf(2000, 11, 12);          // vericiyle aynı hız / same speed as the transmitter
5
6void setup() {
7  Serial.begin(9600);
8  if (!rf.init()) Serial.println("RF init hatasi / failed");
9}
10
11void loop() {
12  uint8_t buf[RH_ASK_MAX_MESSAGE_LEN + 1];   // +1: metin sonu için / +1 for the string terminator
13  uint8_t len = RH_ASK_MAX_MESSAGE_LEN;      // her turda yeniden ayarla / reset on every pass
14  if (rf.recv(buf, &len)) {                  // yalnız CRC doğruysa true / true only if the CRC is valid
15    buf[len] = '\0';
16    Serial.print("Alindi / received: ");
17    Serial.println((char *)buf);
18  }
19}
命令働き
RH_ASK rf(2000, 11, 12)速度2000 bps、受信機はD11、送信機はD12。速度は送受信の両側で同じにする
rf.init()(初期化)タイマーとピンを準備し、問題があればfalseを返す
rf.send(データ, 長さ)最大60バイトのパケットの送信を始める
rf.waitPacketSent()(送信完了まで待つ)パケットが完全に送信されるまで待つ
rf.recv(buf, &len)(受信)CRCが正しい新しいパケットがあれば、bufにコピーしてlenを更新し、trueを返す
RH_ASK_MAX_MESSAGE_LEN1つのパケットで運べる最大のデータ量:60バイト

受信側のコードでは、len変数を毎回の周回で設定し直すことが重要です。recv()はこの変数に受け取ったパケットのサイズを書き込み、次の呼び出しではその値がバッファの大きさとして扱われます。設定し直さないと、長いメッセージが途中で切れてしまいます。すべて正常なら、シリアルモニタに1秒ごとに「Merhaba 0」「Merhaba 1」(Merhabaはトルコ語で「こんにちは」)という行が表示されます。番号が飛んでいる場合は、途中でいくつかのパケットが失われています。その場合はアンテナと電源を確認してください。

Arduino UnoではRH_ASKがTimer1を使います。ServoライブラリもTimer1を必要とするため、この2つは同じスケッチでコンパイルできず、「multiple definition of `__vector_11'」(多重定義)エラーになります。また、D9とD10のPWMも動かなくなります。さらに、ドライバは初期設定でD10を送信機の有効化(PTT)ピンとしても使います。サーボが必要な場合は、RH_ASK.cppの先頭にあるRH_ASK_ARDUINO_USE_TIMER2の行のコメントを外すか(この場合tone()は動きません)、ServoTimer2ライブラリを使ってください。

センサーデータを送る:structを使ったパケット

実際のプロジェクトでは、テキストより数値を送るほうが効率的です。測定値をstructにまとめ、そのバイト列をそのまま送れます。下の送信側は、A0につないだLDRまたはポテンショメーターの値と、D2のボタンの状態を1秒に5回送ります。受信側は、離れた場所のボタンが押されるとD13のLEDを点灯し、失われたパケットにも気づきます。

C++ (Arduino IDE)
1#include <RH_ASK.h>
2#include <SPI.h>
3
4struct __attribute__((packed)) Paket {   // iki tarafta birebir aynı olmalı / must be identical on both sides
5  uint16_t no;                           // paket numarası / packet number
6  int16_t deger;                         // analog değer / analog value
7  uint8_t buton;                         // 1 = basılı / 1 = pressed
8};
9
10RH_ASK rf;                               // varsayılan: 2000 bps, RX 11, TX 12 / defaults
11Paket p = {0, 0, 0};
12
13void setup() {
14  pinMode(2, INPUT_PULLUP);              // buton D2-GND / button D2-GND
15  rf.init();
16}
17
18void loop() {
19  p.no++;
20  p.deger = analogRead(A0);              // örneğin LDR ya da potansiyometre / e.g. LDR or potentiometer
21  p.buton = (digitalRead(2) == LOW);
22  rf.send((uint8_t *)&p, sizeof(p));
23  rf.waitPacketSent();
24  delay(200);
25}
C++ (Arduino IDE)
1#include <RH_ASK.h>
2#include <SPI.h>
3
4struct __attribute__((packed)) Paket {
5  uint16_t no;
6  int16_t deger;
7  uint8_t buton;
8};
9
10RH_ASK rf;
11const int LED = 13;
12uint16_t sonNo = 0;
13
14void setup() {
15  Serial.begin(9600);
16  pinMode(LED, OUTPUT);
17  rf.init();
18}
19
20void loop() {
21  Paket p;
22  uint8_t len = sizeof(p);
23  if (rf.recv((uint8_t *)&p, &len) && len == sizeof(p)) {
24    digitalWrite(LED, p.buton ? HIGH : LOW);   // uzaktaki buton LED'i yakar / remote button lights the LED
25    if (sonNo != 0 && p.no != (uint16_t)(sonNo + 1)) {
26      Serial.println("Paket kaybi / packet lost");
27    }
28    sonNo = p.no;
29    Serial.print(p.no);
30    Serial.print("  A0 = ");
31    Serial.println(p.deger);
32  }
33}

__attribute__((packed))という指定は、コンパイラがフィールドの間に詰め物(パディング)を入れるのを防ぎます。これは重要です。同じstructでも、Arduino Unoでは5バイト、ESP32では6バイトになることがあり、異なる2種類のボードで通信するとデータがずれてしまいます。パケット番号のおかげで、受信側は途中で失われたパケットを数えられます。433MHzのモジュールには受信確認がないので、重要な命令は何回か繰り返して送る習慣をつけるとよいでしょう。両側に送信機と受信機の両方を付ければ、RadioHeadのRHReliableDatagramクラスで、受信確認と再送のある通信も組めます。

RCSwitchで既製のリモコンのコードを読み取る

リモコン式のコンセント、ワイヤレスチャイム、シャッターや門扉のリモコンの多く、そしてドアや窓、PIRの防犯センサーは、EV1527やPT2262のようなコード用チップを使っています。これらのチップは、ボタンが押されるたびに、同じ12〜24ビットのコードを間に同期用の空白をはさみながら繰り返し送ります。RCSwitchライブラリ(ライブラリマネージャではrc-switchという名前)は、このコードを解読します。Unoでは受信機のDATAピンを割り込みピン、つまりD2かD3につなぎ、次のコードを書き込みます。

C++ (Arduino IDE)
1#include <RCSwitch.h>
2
3RCSwitch rf = RCSwitch();
4
5void setup() {
6  Serial.begin(9600);
7  rf.enableReceive(digitalPinToInterrupt(2));   // alıcı DATA -> D2 (kesme pini) / receiver DATA -> D2 (interrupt pin)
8  Serial.println(F("Kumandanin tusuna bas / press a remote button"));
9}
10
11void loop() {
12  if (rf.available()) {
13    Serial.print(F("Kod / code: "));
14    Serial.print(rf.getReceivedValue());
15    Serial.print(F("  Bit: "));
16    Serial.print(rf.getReceivedBitlength());
17    Serial.print(F("  Protokol / protocol: "));
18    Serial.print(rf.getReceivedProtocol());
19    Serial.print(F("  Darbe / pulse: "));
20    Serial.print(rf.getReceivedDelay());
21    Serial.println(F(" us"));
22    rf.resetAvailable();                         // bir sonraki koda hazırlan / get ready for the next code
23  }
24}

シリアルモニタを開いてリモコンのボタンを押すと、「Kod / code: 5393 Bit: 24 Protokol / protocol: 1 Darbe / pulse: 350 us」のような行が表示されます。各ボタンのコード、ビット数、プロトコル、パルス幅をメモしておきましょう。コピーするときに4つとも必要になります。EV1527を使うリモコンでは、24ビットのうち最初の20ビットがリモコンのID、最後の4ビットが押されたボタンを表します。そのため、同じリモコンのボタンのコードはお互いにとても近い値になります。プロトコル1では1単位が約350 µsです。0のビットは1単位HIGHと3単位LOW、1のビットは3単位HIGHと1単位LOW、同期信号は1単位HIGHと31単位LOWです。

リモコンのチップコードの構成RCSwitchでコピーできるか
EV1527(学習コード)20ビットのID+4ビットのボタン、合計24ビットできる
PT2262 / SC22623値(0、1、F)のビットが12個。アドレスはDIPスイッチで設定できる
HT6P20B固定コード、RCSwitchのプロトコル6できる
HCS301(KeeLoq)などのローリングコードのチップ押すたびに変わる暗号化されたコードできない
車のキー、防犯アラームのリモコン、新しいガレージシャッターのリモコンはローリングコードを使っています。押すたびにコードが変わり、記録したコードは2回目には受け付けられません。こうしたシステムをコピーしようとしてもうまくいかず、他人の機器に対して行えば法的な問題にもなります。この方法は、自分のコンセント、チャイム、センサーにだけ使ってください。

リモコンのコードをArduinoから送る

読み取ったコードを送るには、送信機のDATAピンをD10に、2つのボタンをD4とD5それぞれとGNDの間につなぎます。ボタンを押すたびに、Arduinoはリモコンと同じようにコードを10回繰り返して送ります。これでコンセントのオンとオフのボタンがArduinoに移りました。

C++ (Arduino IDE)
1#include <RCSwitch.h>
2
3RCSwitch rf = RCSwitch();
4const int BTN_AC = 4;            // "aç" butonu D4-GND / "on" button D4-GND
5const int BTN_KAPAT = 5;         // "kapat" butonu D5-GND / "off" button D5-GND
6
7void setup() {
8  pinMode(BTN_AC, INPUT_PULLUP);
9  pinMode(BTN_KAPAT, INPUT_PULLUP);
10  rf.enableTransmit(10);         // verici DATA -> D10 / transmitter DATA -> D10
11  rf.setProtocol(1);             // önce protokol... / protocol first...
12  rf.setPulseLength(350);        // ...sonra okuduğun darbe süresi / ...then the pulse length you read
13  rf.setRepeatTransmit(10);      // her gönderim 10 kez tekrarlanır / each send is repeated 10 times
14}
15
16void loop() {
17  if (digitalRead(BTN_AC) == LOW) {
18    rf.send(5393, 24);           // okuduğun "aç" kodu ve bit sayısı / the "on" code and bit length you read
19    delay(300);
20  }
21  if (digitalRead(BTN_KAPAT) == LOW) {
22    rf.send(5396, 24);           // okuduğun "kapat" kodu / the "off" code you read
23    delay(300);
24  }
25}

setProtocol()はパルス幅をそのプロトコルの初期値に戻してしまうので、setPulseLength()は必ずその後に呼び出します。コンセントが反応しない場合は、まず読み取ったパルス幅(例:320や420 µs)をそのまま入力し、それから繰り返し回数を15に増やします。学習コード式のコンセントには、もう1つ便利な方法があります。コンセントを学習モードにしてArduinoから任意の24ビットのコードを送ると、コンセントがそのコードをメモリに登録します。つまり、リモコンを1つもコピーせずに、自分だけのコードを作れます。

ESP32で433MHzの受信機を使う:リモコンでリレーを操作

ESP32は、433MHzのリモコンをWi-Fiの世界につなぐ橋渡しにぴったりです。RCSwitchはESP32でも動き、ESP32のGPIOはすべて割り込みを使えるので、受信機は好きな安全なピンにつなげます。下のコードは、GPIO 27に(分圧回路経由で)つないだ受信機からコードを読み取ります。自分のリモコンのコードが届くと、GPIO 2のLEDまたはリレーモジュールのオン・オフを切り替えます。リモコンは1回押しただけでコードを何度も送るので、プログラムはコードが600 ms途切れるまで、次の切り替えを行いません。

C++ (Arduino IDE)
1#include <RCSwitch.h>
2
3RCSwitch rf = RCSwitch();
4const int RX_PIN = 27;              // alıcı DATA, gerilim bölücüyle / receiver DATA, through a divider
5const int ROLE_PIN = 2;             // dahili LED ya da röle girişi / onboard LED or relay input
6const unsigned long KOD = 5393;     // kendi kumandanın kodu / your own remote's code
7bool durum = false;
8unsigned long sonGorulme = 0;
9
10void setup() {
11  Serial.begin(115200);
12  pinMode(ROLE_PIN, OUTPUT);
13  rf.enableReceive(digitalPinToInterrupt(RX_PIN));   // ESP32'de her GPIO kesme alır / every GPIO takes interrupts on the ESP32
14}
15
16void loop() {
17  if (rf.available()) {
18    unsigned long kod = rf.getReceivedValue();
19    Serial.printf("Kod / code: %lu  %u bit  protokol %u\n", kod, rf.getReceivedBitlength(), rf.getReceivedProtocol());
20    if (kod == KOD) {
21      // kumanda kodu art arda tekrarlar; yalnız yeni basışta değiştir / the remote repeats the code; toggle only on a new press
22      if (millis() - sonGorulme > 600) {
23        durum = !durum;
24        digitalWrite(ROLE_PIN, durum ? HIGH : LOW);
25      }
26      sonGorulme = millis();
27    }
28    rf.resetAvailable();
29  }
30}

この土台の上には、いろいろなものを作れます。受け取ったコードをMQTTでHome Assistantに転送して安価な433MHzのドアセンサーをスマートホームに加えたり、GPIO 26につないだ送信機でコンセントをスマホから操作したりできます。RadioHeadもESP32に対応しています。違いは、コンストラクターでピンを明示的に書くことだけです:RH_ASK rf(2000, 27, 26, 25);(受信機は27、送信機は26、PTT用の空きピンとして25)。ESP32が初めてなら、ESP32とは?を読んでみてください。

Raspberry Pi PicoとMicroPythonで433MHzの送信機を使う

MicroPythonにはRCSwitchに相当する既製のライブラリはありませんが、プロトコル1のタイミングはとても単純なので、数行で自分で書けます。FS1000AのVCCをPicoのVBUS(5 V)ピンに、DATAをGP15に、ボタンをGP16とGNDの間につなぎます。ボタンを押すと、PicoはRCSwitchと同じように24ビットを最上位ビットから順に送り、最後に同期パルスを付け、パケット全体を10回繰り返します。PicoにMicroPythonを入れる方法をまだ知らない場合は、Raspberry Pi Picoとは?から始めてください。

MicroPython
1from machine import Pin
2import time
3
4tx = Pin(15, Pin.OUT, value=0)        # FS1000A DATA -> GP15
5buton = Pin(16, Pin.IN, Pin.PULL_UP)  # buton GP16-GND / button GP16-GND
6T = 350                               # darbe süresi µs (RCSwitch protokol 1) / pulse length µs (RCSwitch protocol 1)
7
8def darbe(yuksek, dusuk):             # süreler T cinsinden / durations in units of T
9    tx.value(1)
10    time.sleep_us(yuksek * T)
11    tx.value(0)
12    time.sleep_us(dusuk * T)
13
14def gonder(kod, bit=24, tekrar=10):
15    for _ in range(tekrar):
16        for i in range(bit - 1, -1, -1):   # en anlamlı bitten başla / start from the most significant bit
17            if (kod >> i) & 1:
18                darbe(3, 1)                # "1" biti: 3T HIGH, 1T LOW / bit "1"
19            else:
20                darbe(1, 3)                # "0" biti: 1T HIGH, 3T LOW / bit "0"
21        darbe(1, 31)                       # senkron: 1T HIGH, 31T LOW / sync
22
23while True:
24    if buton.value() == 0:                 # butona basıldı / button pressed
25        gonder(5393)                       # okuduğun kodu yaz / put the code you read here
26        time.sleep_ms(300)

Picoの125 MHzのプロセッサにとって、350 µsのパルスは余裕のある速さです。Pythonによる小さな遅れは、RCSwitchの受信側が許容する60%のタイミング誤差よりずっと小さく収まります。RCSwitchの読み取り用コードを書き込んだArduinoを横に置けば、すぐにコードをテストできます。シリアルモニタに、送った数値が表示されるはずです。受信側では、パルスの長さをタイムスタンプで測って解読する必要があります。この作業には、RCSwitchが動くArduinoやESP32のほうが手軽です。

通信距離とノイズ:信号をもっと遠くへ届ける

  • アンテナを忘れない:送信側と受信側の両方に、17.3 cmのまっすぐなワイヤーをはんだ付けします。通信距離にいちばん大きく影響するのはこれです。
  • 送信機の電圧を上げる:FS1000Aを9〜12 Vで動かすと、出力と通信距離がはっきり伸びます。GNDの共通接続を忘れないでください。
  • 速度を下げる:RadioHeadで2000 bpsの代わりに1000 bpsを使うと、1ビットあたりの時間が長くなり、受信機がより弱い信号も解読できるようになります。両側に同じ速度を設定してください。
  • 見通しと高さ:鉄筋コンクリートの壁、金属製のケース、地面に近い設置は、通信距離を半分にすることがあります。アンテナは金属ケースの外に出し、できるだけ高い位置に移しましょう。
  • 電源をきれいにする:モーター、リレー、スイッチング方式のACアダプターは受信機の感度を奪います。受信機にはフィルターを通した電源を与え、配線は短くしてください。
  • よりよい受信機を使う:XY-MK-5Vの代わりにRXB6のようなスーパーヘテロダイン方式の受信機を使うと、同じ送信機でも多くの場合はっきり遠くまで届きます。
  • もう一度送る:受信確認の仕組みがないので、重要な命令は3〜5回送り、受信側でパケット番号を使って重複を取り除きます。

433 MHzは共有の周波数帯であることを覚えておきましょう。近所の気象ステーション、車のキー、チャイムも、すべて同じ周波数で電波を出しています。ヨーロッパとトルコでは、433.05〜434.79 MHzの範囲が短距離無線機器向けに免許不要で使えますが、送信出力は10 mW(ERP、実効放射電力)までに制限され、チャンネルを常にふさがないようにする必要があります。ルールは国によって異なり、アメリカではリモコンに315 MHzが使われることが多くなっています。日本では433 MHz帯をこの用途で自由に使うことはできず、技適マークのない無線モジュールの使用は電波法で制限されています(国内のリモコンは主に315 MHz帯の特定小電力無線を使います)。データを送り続けるのではなく、一定の間隔で、または何かが変わったときだけ送るようにすれば、ルールを守れるうえに電池も長持ちします。電池で動く送信機には電池寿命計算ツールを使えます。

433MHz RFモジュールとnRF24L01、どちらを選ぶ?

nRF24L01 2.4 GHz無線通信モジュール
nRF24L01:SPIで接続し、双方向に通信でき、ハードウェアにエラーチェックを備えた2.4 GHzの選択肢です。
項目433MHz RF(FS1000A + XY-MK-5V)nRF24L01
周波数433.92 MHz2.4 GHz
変調方式ASK / OOKGFSK
通信の方向一方向(送信機と受信機は別のボード)双方向(1つのトランシーバーモジュール)
通信速度実用上は1〜4 kbps(RadioHeadの初期値は2 kbps)250 kbps〜2 Mbps
接続データピン1本SPI(配線7本)
電源送信機3〜12 V、受信機5 V1.9〜3.6 V
エラーチェックソフトウェアで行う(RadioHeadのCRC)ハードウェアのCRC、自動受信確認と再送
通信距離17.3 cmのアンテナで20〜100 m50〜100 m、PA+LNA版で約1 km
壁の透過比較的よい(周波数が低い)弱い
既製品との互換性コンセント、チャイム、センサーのリモコンなし
価格とても安い安い

まとめると、一方向で、たまにしか送らない小さなデータ(ボタン、温度の値、ドアが開いたという情報)を送りたい場合や、既製のコンセントやセンサーと組み合わせたい場合は、433MHzのモジュールがいちばん安くて簡単な解決策です。高速で双方向、受信確認つきの通信が必要なラジコンカー、ジョイスティック、複数ノードのセンサーネットワークには、nRF24L01のほうが適しています。何キロメートルもの距離が必要ならLoRaモジュールを検討してください。すべての選択肢を並べて比べるには、Arduinoの無線通信モジュールを読んでください。

433MHz RFモジュールを使ったプロジェクトのアイデア

  • ワイヤレスチャイム:門のボタンから信号が届いたら、家の中でメロディーを鳴らします。音を出すにはブザーで十分です。
  • Arduinoからコンセントを操作:リモコン式のコンセントのコードをコピーし、時刻や明るさに合わせて照明をオン・オフします。
  • ワイヤレスのドアセンサー:ドアにリードスイッチと送信機付きの小さなArduinoを取り付け、ドアが開いたら受信側で警報を鳴らします。
  • 家庭用の防犯システム:既製の433MHzのPIRセンサーやドアセンサーを1つの親機に集めるArduinoのアラームシステムを作ります。
  • 庭のセンサーステーション:電池で動く送信機で、土壌水分や温度を数分ごとに家へ送ります。
  • 433MHzとWi-Fiのブリッジ:ESP32を使って、家にあるすべての433MHz機器をスマホやスマートホームのシステムから操作します。

よくある失敗と対処法

症状考えられる原因対処法
受信機にパケットがまったく届かない(RadioHead)速度やピンが両側で異なる、アンテナがない両側で同じコンストラクター(2000, 11, 12)を使い、両方のモジュールに17.3 cmのワイヤーをはんだ付けする
数センチメートルの距離でしか動かないアンテナなしで使っている、または送信機の電圧が低いアンテナを付け、送信機を5〜12 Vで動かす
エラー:multiple definition of `__vector_11'(多重定義)RadioHeadとServoライブラリがTimer1を共有できないRH_ASK_ARDUINO_USE_TIMER2またはServoTimer2を使う
D9とD10のPWMが動かない、D10につないだ機器の動きがおかしいRH_ASKがTimer1とD10(PTT)を使っているこれらのピンを空けておくか、コンストラクターでPTT用に別のピンを選ぶ
RCSwitchにコードがまったく表示されない受信機のDATAが割り込みのないピンにつながっているUnoとNanoではD2かD3を使う
見覚えのないコードが表示される近所の気象ステーション、センサー、またはノイズ既知のコード、ビット数、プロトコルにだけ反応させる
コピーしたコードでコンセントが動かないパルス幅やプロトコルが違う、またはリモコンがローリングコード式getReceivedDelay()の値をsetPulseLength()に入れ、繰り返し回数を増やす
ESP32がコードを受け取らない、または動作が不安定5 Vの受信機の出力がGPIOに直接つながっている分圧回路か3.3 Vの受信機を使う
モーターが動くとデータが途切れる電源のノイズと電圧降下受信機に別の電源を用意し、100 nF+10 µFのコンデンサを追加する
トラブルシューティングでは、まず2つのモジュールを1メートル離し、アンテナを付けて5 Vで試します。この距離で動くなら、問題は配線ではなく通信距離とノイズです。距離を少しずつ広げながら、アンテナ、送信機の電圧、通信速度の影響を確かめましょう。まったく動かない場合は、ピン、速度の設定、ライブラリ付属のスケッチ例を確認してください。

433MHz RFモジュールは、わずかな費用でプロジェクトに無線の腕を与えてくれます。家にある既製のリモコン式の機器と通信できる、数少ないモジュールの1つでもあります。無線制御の考え方を理解すれば、赤外線リモコンやBluetoothなど、ほかの方法も簡単に身につけられます。BlueGraysアプリでは、「2台のArduinoで一方向通信」、「リモコンで220V電球を点灯・消灯」(日本の商用電源は100V(50/60Hz)です)、「リードスイッチ式ドアセンサー」、「ESP32の動体検知アラーム」などのプロジェクトを、回路図とステップごとのコードつきで見つけられます。

よくある質問

433MHz RFモジュールの通信距離はどのくらいですか?

アンテナなしでは、セットは1〜3メートルしか届きません。送信側と受信側の両方に17.3 cmのワイヤーアンテナをはんだ付けし、送信機を5 Vで動かすと、見通しのよい屋外で20〜50メートル、送信機を9〜12 Vで動かすと100メートル以上も可能です。屋内では壁やノイズのため、これらの値ははっきり小さくなります。

433MHzのアンテナの長さはどのくらいにすればいいですか?

いちばん効率のよい簡単なアンテナは、1/4波長のまっすぐなワイヤーです。433 MHzでは約17.3 cm、315 MHzでは23.8 cmです。ワイヤーをモジュールのANTパッドにはんだ付けし、まっすぐ垂直に保ちます。受信機と送信機のアンテナは同じ向きにそろえてください。

433MHzの送信機と受信機で双方向の通信はできますか?

1組のペアだけでは、通信は送信機から受信機への一方向だけです。両側に送信機と受信機の両方を付ければ双方向に通信でき、この構成ではRadioHeadのRHReliableDatagramクラスが受信確認と再送も行ってくれます。ただし、この用途には、最初から双方向に対応したnRF24L01やHC-12のようなモジュールのほうが手軽です。

433MHzのモジュールで車やガレージのリモコンをコピーできますか?

車のキーや最近のガレージのリモコンはローリングコードを使っています。押すたびにコードが変わり、記録したコードは拒否されるので、RCSwitchではコピーできません。一方、固定コードのコンセント、チャイム、センサーのリモコンはコピーできます。この方法は自分の機器にだけ使ってください。他人のシステムにアクセスしようとすると、法的な問題になります。

433MHz RFモジュールはESP32で使えますか?

使えます。FS1000A送信機は5 Vで動かし、DATAピンをGPIOに直接つなげます。3.3 Vの信号で十分です。XY-MK-5V受信機の出力は5 Vなので、分圧回路を入れるか、RXB6のように3.3 Vで動作する受信機を選んでください。RCSwitchとRadioHeadのライブラリは、どちらもESP32に対応しています。

433MHzと315MHzのモジュールの違いは何ですか?

どちらも同じ構造で、違うのは動作周波数だけです。ヨーロッパとトルコではリモコンの多くが433.92 MHzを使い、アメリカや一部のアジアの国では315 MHzが一般的です(日本のリモコンも主に315 MHz帯です)。送信機と受信機、またはコピーしたいリモコンの周波数は、完全に同じでなければなりません。

全プロジェクトを見る
2台のArduinoで一方向通信
#57中級
プレミアム

2台のArduinoで一方向通信

2台のArduinoを1本のワイヤーで通信させます。一方のボタンを押すともう一方のLEDが点灯し、もう一度押すと消灯します。送信側のボードがボタンの押下を短いメッセージで伝え、受信側のボードはそのメッセージを受け取るとLEDの点灯と消灯を切り替えます。機器同士が情報を伝える仕組みを、最もシンプルな形で確かめられます。

4.4(37)
50
2台のArduinoで双方向通信
#58中級
プレミアム

2台のArduinoで双方向通信

2台のArduinoをケーブルでつないで通信します。片方のボタンを押すともう片方のライトが点灯し、もう一度押すと消灯します。両方のボードで同じプログラムを動かすので、どちらからでもメッセージを送受信できます。ボード同士でメッセージをやり取りする仕組みを、シンプルな構成で学べます。

4.5(20)
26
リモコンで220V電球を点灯・消灯
#21上級
プレミアム

リモコンで220V電球を点灯・消灯

ソファに座ったまま、テレビのリモコンで家庭の電球を点灯・消灯します。Arduinoがリモコンから届く目に見えない光の信号を読み取り、電源ボタンを押すとリレーを動かして電球を点灯させ、消音ボタンを押すと消灯させます。家庭用電源を扱うため、配線は大人と一緒に、必ずプラグを抜いた状態で行ってください。

4.4(22)
30
リードスイッチ式ドアセンサー
#38初級
プレミアム

リードスイッチ式ドアセンサー

ライトを見るだけで、ドアが開いているか閉まっているか分かります。ドアに小さな磁石、ドア枠に磁石を検知するスイッチを取り付けます。ドアが閉まっているときは両者が並び、緑のLEDが点灯します。ドアが開いて磁石が離れると、赤いLEDが点灯します。家庭用警報装置のドアセンサーも、こんなシンプルな仕組みです。

4.7(34)
44
IR受信機とリモコンでLEDを点灯・消灯
#17中級
プレミアム

IR受信機とリモコンでLEDを点灯・消灯

椅子に座ったまま3つの照明を操作するように、リモコンの1、2、3のボタンで青、赤、緑のLEDを点灯させ、4、5、6のボタンで同じ順に消灯させます。電源ボタンで3つを一斉に点灯させ、消音ボタンですべて消灯させます。リモコンの信号を受け取るのは赤外線受信機です。家の機器をリモコンで操作するプロジェクトへの第一歩です。

4.7(45)
66
ESP32汎用IRリモコン(IR受信機 + リモコン + LED3個 + ブザー + OLED)
#143上級
プレミアム

ESP32汎用IRリモコン(IR受信機 + リモコン + LED3個 + ブザー + OLED)

ESP32で市販のIRリモコンの信号を読み取り、自作の機器を操作できます!このプロジェクトでは赤外線受信機(NECプロトコル、38 kHz)で20ボタンのIRリモコンの信号を受信します。各ボタンには異なる動作を割り当てています。1、2、3ボタンで3個のLEDをそれぞれオン・オフし、PWRボタンですべて消灯します。4~9の数字ボタンではOLEDに特別な表示を出します。SSD1306 OLEDには最後に押したボタンを大きく表示し、実行した動作の説明とLEDの状態もリアルタイムで表示します。未知のボタンを押すとOLEDにHEXコードを表示します。

4.5(9)
16
BluetoothでスマートフォンからLEDを操作
#34初級
プレミアム

BluetoothでスマートフォンからLEDを操作

スマートフォンで部屋の照明をつけたり消したりするための、小さな練習です。Bluetoothモジュールがスマートフォンから送られた文字をArduinoに伝えます。ある文字で赤いLEDが、別の文字で緑のLEDが点灯し、同じ文字を小文字で送ると消灯します。無線操作の仕組みを、ごくシンプルな形で学べます。

4.8(68)
89