4-Channel Long Range 433 MHz Remote Control With QDEN
by TomGoff in Circuits > Arduino
1030 Views, 8 Favorites, 0 Comments
4-Channel Long Range 433 MHz Remote Control With QDEN
I'm sure that there has been a multitude of projects on Instructables for Arduino based remote controls however hopefully this one is a little different. For this project I wanted to explore two novel ideas. Firstly I wanted the remote control to have a unique pairing encoding protocol and secondly I wanted to experiment with a Superheterodyne receiver working with ASK radio Protocol (Amplitude Shift Keying).
The remote control transmitter / receiver pair I have designed is multipurpose and could have a range of uses varying from launching model rockets (see video), controlling lights, watering your plants and many many more applications. The receiver PCB is equipped with four power relays capable of switching 10A at 250V so it can be used to control some quite substantial loads.
So, now I'm sure you are asking yourself what does QDEN stand for? It's a protocol of my own design for pairing an individual Transmitter with a specific Receiver so that it prevents cross-talk if more than one Transmitter is being used locally. QDEN is and acronym that simply sands for Quick and Dirty ENcoding and I will go into this DIY encoding protocol later in this Instructable. The data sent from the transmitter to the receiver is encoded but not encrypted, however I think my "quirky" self-taught code provides a degree of security though obfuscation!
This project is has a reasonable amount of complexity in respect to electronics and coding however I have tried to keep it as simple as possible so that it can be understood by individuals who have been hacking on electronics and microcontrollers for a couple of years.
Note: This project experiments with radio frequency (RF) transmission and different countries have different laws in respect to RF. Please make sure you are not breaking any laws when working with RF!
Supplies
Here's a list of all the materials and tools I used for this project.
Transmitter Module (Mix of SMD and Through Hole)
- ATMega328P-AU Micro Controller IC SMD Package
- 16MHz 2-Pin Crystal Oscillator
- 10uF Electrolytic 5x5.4 x 2 SMD
- 100nF Ceramic Capacitor 0805 SMD x 2
- 22pF Ceramic Capacitor 0805 SMD x 2
- 470 ohm Resistor 0805 SMD x 1
- 10K Resistor 0805 SMD x 5
- 4x2 Male Pin Header (Programming Connection)
- 2-Way Screw Terminal Block (5.08mm Pitch) x 3
- 4-Way Screw Terminal Block (5.08mm Pitch) x 1
- AMS1117-5.0 SMD Voltage Regulator x 1
- 433MHz Radio Transmitter x 1
- Telescopic Radio Antenna x 1
- 12mm Gland x 1
- Low Profile Round 12mm Momentary Push Button Switch 1.5A SPST x 4
- Enclosure - Hammond Soft Sided Handheld Enclosure with Battery Door 117 x 79 x 33mm (1553CBKBAT)
- 5mm LED in bezel x 1
- Miniature Rectangle Rocker Power Switch SPDT x 1
- PCB
- 9V Battery x 1
Receiver Module (All components Through Hole)
- ATMega328P-PU Micro Controller IC DIP Package
- 16MHz 2-Pin Crystal Oscillator
- 22pF Ceramic Capacitors x 2
- 100nF Ceramic Capacitor x 1
- 4x2 Male Pin Header (Programming Connection)
- 4x1 Female Pin Header x 2 To connect Receiver
- 2-Way Screw Terminal Block (5.08mm Pitch) x 1
- 3-Way Screw Terminal Block (5.08mm Pitch) x 4
- 4-Way Screw Terminal Block (5.08mm Pitch) x 1
- 5V SPDT PCB Mount Relays x 3
- 3mm LEDs x 6
- 330 ohm Resistors 0.25W x 6
- 1k Resistors 0.25W x 6
- 10k Resistor 0.25W x 1
- 1N4001 Diodes x 4 (freewheel diodes on relay)
- Transistor 2n2222 x 4
- LM7805 TO-220 Voltage Regulator x 1
- 0.1uF Electrolytic Capacitor x 1
- 0.33uF Electrolytic Capacitor x 1
- Superheterodyne receiver x 1
- PCB Mounted Momentary Push Buttons x 2 (For Pairing and Reset)
- PCB
- 9V Battery x 1
Tools, Consumables and Equipment
- Soldering Iron
- Solder
- Solder Flux
- Soldering Fume Extractor
- Tweezers
- Electronics Cutters
- Magnifying Glass
- Laptop
- Arduino IDE
- TinyUSB ICSP Programming Tool
Understanding ASK and Superheterodyne Receivers
I have used many radio protocols for my projects such as LoRa and NRF24 however I particularly like the ASK protocol because of it's elegant simplicity. I think it gets overlooked for many projects because the cheap transmitter / receiver pairs you can buy online are supplied with absolutely terrible receiver modules. These poor quality poor quality receivers ruin the whole experience. When the receiver is replaced with a superior module the quality improves greatly.
What is the ASK protocol?
Amplitude Shift Keying (ASK) is a modulation technique used in radio communication. ASK varies the amplitude of a carrier wave in accordance with the data being sent. The "shift keying" part of ASK is the process of changing (or shifting) the amplitude of a carrier wave to represent data. In ASK, the amplitude of the signal is switched between two or more levels, typically between "on" (high amplitude) and "off" (low or zero amplitude), to represent binary data (1s and 0s). The term "shift keying" emphasizes the discrete shifts in the signal's property (amplitude, in this case) to encode information. It is very similar to transferring Serial data. You can actually test your ASK code without any radio modules because you can simply connect a wire from the Tx pin (typically pin 11 on an Arduino Uno) of the transmitter microcontroller to the Rx pin of the receiver module (typically pin 11 on an Arduino Uno). You can then send and receive data just as though the microcontrollers were connected by radio.
For my project I used the amazing Arduino RadioHead library to implement ASK. The RadioHead library for Arduino supports ASK modulation via the RH_ASK driver. This allows low-cost data transmission using simple 433 MHz RF modules. The RadioHead ASK library handles modulation, demodulation, and packetizing of the data being sent. making ASK communication efficient and reliable. It supports features like message addressing, acknowledgment, and error detection. The RadioHead ASK driver is ideal my remote controls application but could also be used for other applications such as sensor networking or IoT.
Why use a Superheterodyne Receiver?
The data from the Transmitter is received by a superheterodyne receiver instead of the standard receiver you get with the 433MHz transmitter / receiver pairs you can buy online. A superheterodyne receiver makes the 433MHz radio system work far better and I get a range over over 200m and the signal can easily be detected through walls and inside building.
A superheterodyne receiver is better than a non-superheterodyne receiver because it allows for better amplification of weak signals, making it more sensitive. It also has superior selectivity, by converting signals to a fixed intermediate frequency (IF), it provides more effective filtering and rejection of unwanted signals. In addition superheterodyne receivers also have stable frequency response, less noise and easier tuning (the tuning is already done by the module and not used in this project)..
I found that the RXB6 superhet receiver worked very well. The RXB6 receiver requires 5V and ground and the data pin is connected to the data pin of the microcontroller. The other pins are left unconnected.
The standard cheap transmitter modules work fine and are more powerful the greater the supply voltage is. These transmitters can work up to 12V however I was using 9V for the transmitter power supply.
Antenna Length
I set the transmitter antenna at 17.3cm because it closely matches the wavelength of the signal of a 433 MHz radio transmitter. The wavelength for 433 MHz is about 69.23 cm, and a quarter-wavelength antenna (69.23 cm ÷ 4 ≈ 17.3 cm) improves signal efficiency, with 17.3 cm being a practical compromise.
QDEN Explained!
As mentioned earlier, QDEN is and acronym that simply sands for Quick and Dirty ENcoding. I wanted a way to add some encoding to to the messages so that the transmitter and receiver are paired together so that if either another transmitter or receiver is in the local area you do not get cross-talk (interference). The encoding is not really there to provide message security through encryption, it's just there to stop cross-talk between devices.
Encoding is different from encryption as it is the process of converting data into a different format for efficient transmission or storage, without hiding the information. Encryption, on the other hand, transforms data into an unreadable format using a secret key to protect the information, ensuring only authorized parties can decode it.
QDEN works by the transmitter prepending the message with a short key (adding to the beginning), for example if the message is "A" it is prepended with "123" so the new message is "A123". When the receiver receives a message it checks that the message starts with the key and then removes it and only uses the data after the key.
How it works....
Both the transmitter and receiver are both initially hard coded with the key"123" so that you don't need to pair the devices on start-up. When you decided to pair the devices you press buttons "A" and "B" simultaneously on the transmitter and the "Pair" button on the receiver. The transmitter microcontroller then calls the generateKey() function. This function reads the millis() value on the micro controller which is the amount of time the microcontroller has been on in milliseconds. I decided to use this value because I think it's probably more secure than the random number generator on the Arduino which is not really that random. Once the millis() value has been read I then want to turn it in to just the last three characters. I do this by either truncating (cutting it down) it if it is longer than three characters or padding it with 0's if it is shorter than 3 characters (this is impossible however I left this code in in case I wanted to use a longer key in the future). Once the key is generated a for loop is called and sends the key out 10 times. While the key is being sent the getNewKey() function is being called on the receiver. This function checks the new key is only three characters and if it is it then saves it as the new key and then will only receive new commands if the message is prepended with the new key.
I am well aware that this is not the best way to send keys between devices and a better way would be to send a rolling key that changes every time a message is sent. The problem is that the radio system I am using only has a transmitter on the transmitter and only a receiver on the receiver. If the radios were transceivers (able to both transmit and receiver) you could send an acknowledgment from the receiver to confirm the message was sent ok, this means you can then implement an algorithm on both the transmitter and receiver that changes the key in unison every time a message is sent. This is how most modern communication protocols work. I however wanted to come up with a simple, quick and dirty protocol that works with simple 433MHz radio modules.
I have attached a video showing the pairing process.
Transmitter PCB
This PCB is very similar to an Arduino Uno Microcontroller, it is simply designed on a custom PCB. I decided to use mostly surface mount (SMD) components for this PCB as I wanted to keep it as compact as possible and also wanted to use the PCB manufacturer to assemble the SMD components. The PCB is at the heart of this project and it comprises of an ATMega328p Microcontroller, the same as that used for the Arduino Uno. It has a 16MHz crystal oscillator to provide the clock with corresponding 22pF capacitors. The microcontroller takes in inputs from the push buttons, then outputs to a 433MHz radio transmitter.
A power switch and power LED is taken off the PCB via screw terminals.
The power to the PCB is taken from a 9V PP3 battery. The voltage from the battery is reduced to 5V DC by a AMS1117-5.0 SMD Voltage Regulator. This is setup with the standard data sheet configuration with electrolytic capacitors on the input and output power terminals.
A 3x2 header pin programming port is provided to connect a USB Tiny ICSP (In Circuit Serial Programmer).
I find it best to describe a system such as this in terms of its inputs and outputs.
Inputs
The Inputs come from four push buttons that are mounted on the enclosure and connect to the PCB via screw terminals. These push buttons determine the signal sent from the transmitter and allow it to go into pairing mode.
Outputs
The microcontroller simply outputs to a 433MHz radio transmitter mounted to the PCB on header pins. This radio module has an antenna wire soldered to it to connect to a telescopic external antenna to improve range.
I had the PCB made by JLC PCB but you could easily have it made by PCBWay or one of the other manufacturers. I had JLC PCB assemble the SMD components then hand soldered all the trough hole components.
Transmitter Code
The code for the transmitter was written using the Arduino IDE, as mentioned earlier, it uses the RadioHead library to implement wireless communication with Amplitude Shift Keying (ASK) modulation. The code reads the states of four buttons and sends a message over the air depending on the button pressed. Additionally, it can generate and broadcast a new secret key to pair with the receiver when two buttons are pressed together.
Here's a deep dive into what each section of the code does:
Libraries and Initialization:
The code includes the RadioHead ASK library (RH_ASK.h) and SPI.h (which isn't used directly but is required for the library to compile).
The RH_ASK rf_driver object is initialized to handle ASK modulation for wireless communication.
Pin Configuration:
Four buttons (A, B, C, and D) are connected to digital pins 2, 3, 4, and 5, respectively (these are Pins PD2, PD3, PD4 and PD5 if you are working with the microcontrollers true pinout). These buttons use INPUT_PULLUP mode, meaning the pins are normally HIGH and go LOW when pressed.
Setting Variables:
buttonPressTime: Stores the timestamp (from millis()) when buttons are pressed, used in the generateKey() function.
flag: A Boolean variable used to avoid repeatedly sending "E" when no buttons are pressed.
keyString: A string that stores a 3-character secret key, initially set to "123".
Setup Function:
Serial communication is initialized for debugging (Serial.begin(9600)).
Button pins are set up using pinMode().
The ASK driver is initialized, and a failure message is printed if it doesn’t start correctly.
Main Loop:
The code continuously checks the state of the buttons:
- If buttons A and B are pressed together, it generates a new secret key using the generateKey() function. This key is derived from the current millis() value and truncated/padded to exactly 3 characters.
- If only one button (A, B, C, or D) is pressed, the corresponding message is created by appending the button's letter (A, B, C, or D) to the secret key. The flag is also set to 1 when a button is pressed.
- If no buttons are pressed and the flag is set (flag == 1), it sends the key with the letter "E". The flag is then reset to avoid repeatedly sending the message and flooding the airwaves with data.
Send a message:
- If a message is generated (non-empty msg), it is sent over the air using the rf_driver.send() function. The waitPacketSent() ensures the message is fully transmitted before proceeding.
- A short delay (delay(50)) is added to debounce the button presses.
Key Generation (generateKey() function):
- This function generates a new key based on the current millis() value.
- The millis value is converted to a string, then truncated or padded with zeros to ensure it is exactly 3 characters long.
- The new key is sent 10 times to the receiver, with a 1-second delay between transmissions.
Code Summary:
The code listens for button presses and sends a message wirelessly using ASK modulation. If buttons A and B are pressed together, a new 3-character secret key is generated based on the current millis() value. The messages sent combine the secret key with a letter indicating the pressed button (A, B, C, D, or E). A flag mechanism ensures that when no buttons are pressed, the message "E" is sent only once until another button press occurs.
A copy of the code is attached if you wan to take a closer look.
Downloads
Receiver PCB
As with the transmitter PCB, this PCB is also very similar to an Arduino Uno Microcontroller, again designed on a custom PCB. I decided to use through hole components on this PCB because, unlike the transmitter, it's likely that any future receiver PCBs will be custom for the required application. This PCB also did not have the space constraints of the transmitter PCB. This PCB also utilises an ATMega328p Microcontroller, this time the through hole DIP package. It has a 16MHz crystal oscillator to provide the clock with corresponding 22pF capacitors. The microcontroller takes in inputs from a 433MHz superhet radio receiver and then outputs to 4 relays with corresponding LED lamps.
The power to the PCB is also meant to taken from a 9V PP3 battery, however because the power is connected through two screw terminals you could use other power supplies between 6 and 12V DC. The voltage from the battery is reduced to 5V DC by a LM7805 Voltage regulator. This is setup with the standard data sheet configuration with a 0.1uF Capacitor on the input and a 0.33uF capacitor on the output.
A 3x2 header pin programming port is provided to connect a USB Tiny ICSP (In Circuit Serial Programmer).
Here are the details of the inputs and outputs.
Inputs
The Superhet Receiver is connected to pin PB3 9Arduino equivalent Pin D11) of the micro controller to send the received data.
A Pairing switch is connected to the microcontroller to call the pairing function (on pin PD8, or Arduino equivalent Pin D8).
A reset pushbutton is connected, this is normally held high and is connected to ground to reset the microcontroller.
Outputs
The microcontroller outputs digital signals that activate four relays. Each relay is switched on with a NPN 2N2222 transistor. The relay coil is placed in series with the transistor collector pin and 5V. The emitter of the transistor is connected to ground. The transistor is switched on when corresponding pin of the microcontroller goes high. The output pin of the ATMega328 microcontroller is connected to the base of the transistor through a 1k ohm resistor. There is also a diode across the coil of the resistor. The cathode of the diode (negative) is connected to the positive of the relay and the anode (positive) terminal of the diode is connected to the negative terminal of the relay. When the relay switches off it can generate a very high voltage in the opposite direction of the supply voltage. The diode causes this voltage to be recirculated around the relay coil so that it does not damage more sensitive components in the circuit. A LED is placed in series with the relay transistor with a current limiting resistor so that there is indication when the relay is activated.
There is also an LED with current limiting resistor connected to the microcontroller to indicate that it is in pair mode (PD7, or Arduino equivalent Pin D7).
Additional GPIO
In addition to the I/O detailed above I have also included some screw terminals connected to 5V, Ground, Pins PC4/SDA and PC5/SCL. I do not use these connections in this project however I wanted to add them to allow for additional functionality in the future as they also give access to the I2C microcontroller pins. This I/O could then be used for multiple functions in the future such as connecting a display and / or sensors. The beauty of adding the I2C pins as extra I/O is that it's a communications bus and lots of devices can then be connected with just the two pins.
I decided to design this PCB out of through hole components so that it is easy to assemble for myself and for people who want to make it themselves. It is also easier to repair if it gets damaged.
I had the PCB made by JLC PCB but you could easily have it made by PCBWay or one of the other manufacturers.
Uploading the Code
I have included a programming port on both PCB designs to allow for the uploading of the code using a USBTiny ICSP (In Circuit Serial Programmer). Please take a look at the short video attached to see how the code is uploaded to the microcontroller.
Receiver Code
As with the transmitter code, this code was also written in the Arduino IDE. This code is designed to use a 433 MHz receiver to receive wireless messages encoded using Amplitude Shift Keying (ASK) with the RadioHead library. It listens for commands sent over the air, and only accepts messages that begin with a predefined secret key. It also has the ability to pair with a new secret key when a button is pressed.
Libraries and Initialization:
- The code includes the RH_ASK library for ASK modulation and demodulation, and SPI.h (though SPI isn't directly used here, it's required by the library).
- The RH_ASK RF_driver object is initialized for wireless communication using ASK at 2000 bps.
Pin Assignments:
- pairPin: Button for pairing a new secret key, connected to pin 8.
- pairLED: LED connected to pin 7, used to indicate when the device is waiting for a new secret key.
- LED1, LED2, LED3, LED4: These pins (2, 3, 4, and 5) control relays via transistors and are used to control external devices or indicators. The LED's are connected in parallel to the relays so when a relay is energised the corresponding LED lights up.
Global Variables:
- receivedData: Stores the received data from the radio.
- secretKey: Initially set to "123", this string is used to authenticate received messages. Changes when the getNewKey() function is called.
- waitingForNewKey: A flag that indicates whether the system is waiting to pair with a new key.
Main loop() Function:
Button Press Detection:
- When the pairing button is pressed (pin pairPin reads LOW), the getNewKey() function is called to wait for and receive a new secret key.
Normal Operation (Receiving Data):
- If the device is not waiting for a new key (waitingForNewKey == false), it listens for messages from the radio using RF_driver.recv().
- The received message is stored in receivedData and converted into a string.
Message Processing:
- If the received message starts with the correct secretKey, the program processes the next character in the message (the command).
- Commands ('A', 'B', 'C', 'D', 'E') correspond to turning the relays on or off:
- 'A', 'B', 'C', and 'D' turn on relays 1 to 4, respectively.
- 'E' turns off all relays.
Error Handling:
- If the received message does not begin with the correct secretKey, or the command is unknown, an error message is printed.
getNewKey() Function:
- Pairing Mode:
- When the button is pressed, the system enters pairing mode, turning on the pairLED and setting the waitingForNewKey flag to true.
- The system waits for a new secret key to be received from the transmitter.
- Key Validation:
- The code waits in a loop, continuously listening for a valid 3-character key.
- If the received key is exactly 3 characters long, it updates the secretKey and exits pairing mode.
- If an invalid key is received, the code waits for a valid one.
- Exit Pairing Mode:
- Once a valid key is set, the system turns off the pairLED and returns to normal operation.
Code Summary:
The code listens for wireless messages using ASK modulation. It then verifies that each message starts with a predefined secret key, and then processes a command ('A' to 'E') to control relays. A pairing mode allows for updating the secret key by pressing a button and receiving a new 3-character key over the air. The system validates the new key and only accepts it if it's exactly 3 characters long.
A copy of the code is attached if you wan to take a closer look.
Downloads
Testing and Conclusion
I've attached a video showing the transmitter and receiver working with small solenoids connected to the output relays. I also did a field test launching a model rocket at a distance. I am very pleased with the operation of this project and have tested the range of the system and found that, thanks to the Superhet receiver, it works up to 200m range with fairly poor line of site.
There are several improvements I could make to the project, here's a few ideas I have:
- Save the key to the internal eeprom on both the transmitter and receiver. This enables any new keys to be stored on the device even if it's powered off.
- On the receiver IC I could remove the relay driver transistors and swap them for an Integrated Circuit (IC) with a smaller footprint.
- Both PCBs could have a more modern power efficient power supply.
A big thankyou to my daughter again for doing some wonderful artwork showing our family rocket launch with our dog Dougie.