6th lesson of the Fab Academy. This time Networking & Communication, the fearsome exercise. I had heard from past Fab Academy students and from Emma herself that this was one of the most difficult week assignment, and it didn't arrive in the best moment since I am close to the Mid-Term Demo Day. So I decided to keep it simple...
There are various reasons why one would want to break a bigger system into subsystems that communicate with each other. The more obvious one is because different parts of the system need to be in different locations, but there are less evident reasons, mostly related to the need for simplification. Many small processors doing one task are easier to debug and give less problems with interferences that one big processor doing many tasks, for instance.
The intention of the assignment therefore was to design and build a wired and/or wireless network connecting at least two processors. Before I go on I would like to thank Loes Bogers for the splendid support and the reference to this very useful resource of Arduino knowledge.
Some info about the different communication protocols
The first thing worth mentioning is that the networking protocols for wired and wireless communication are the same but the wireless communication is enabled by an additional piece of hardware (radio, bluetooth, wifi...).
Asynchronous serial
Supported by all microcontrollers, the data is transferred without the support of an internal clock, which means that there needs to be an agreement between the devices based on some rules.
- Baud rate: how fast the data is sent. Measured on Bits per Second (BPS), some standard baud rates are 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200...
- Data bits, synchronization bits and parity bits: define the data package.
- UART (Universal Asynchronous Receiver and Transmitter): the piece of hardware inside some microcontrollers that regulates the communication traffic. If the piece of hardware is not included in the microcontroller the asynchronous communication can be enabled through software. Arduino IDE SoftwareSerial Library is one of them. I understand now why I had to call this library when I wanted to use the serial monitor to read values during week #3.
- 2 wires: Tx for transmit and Rx for receive. Communication only happens from Tx to Rx, which means that we need one cable for Tx and another for Rx.
- GND should be shared, like in real world. If humans would not share the same ground, communication would be pretty impossible...
- Pitfall: the main problems with the asynchronous serial communication are that the devices have to agree beforehand in the transmission speed, and the lack of clock can make the communication quite unstable.
SPI (Serial Peripheral Interface)
Synchronous data bus that uses separate lines for Data (MISO & MOSI) and Clock (SCK), as well as one line per slave (SS). It is not supported by every microcontroller (for instance ATTiny - see data sheet!).
- 4 wires (at least):
- SCK (Signal Clock): Master generates the clock signal.
- MISO (Master In Slave Out)
- MOSI (Master Out Slave In)
- SS (Slave Select): a wire is required for each slave, and therefore a pin in the microcontroller. Master pushes the line of the specific slave down when it wants to talk to it.
- Programing: SPI library (not for ATTiny) or shiftily() shiftOut() commands in Arduino IDE.
- Pitfall: the main problems with the SPI protocol is the need of so many pins (4 at least, plus one per extra slave).
I2C (Inter-Integrated Circuit)
Also called TWI (Two-Wire Serial Interface), it is probably the most powerful communication protocol. It can support up to 1008 devices with only... 2 wires!
- 2 wires
- SCL (Clock Signal)
- SDA (Data Signal): address bits and data bits. Different devices are identified with different addresses.
- Programing: TinyWireM and TinyWireS libraries (for ATTiny) as well as Wire library (for ATMega) in Arduino IDE.
- Check Loes documentation for more specific info.
The chosen connection: wireless SPI using the nRF24 radio module
This time I wasn't quite sure how I wanted to integrate the present exercise in my Final Project, so I decided to go for the wireless communication. Although I2C is the most interesting communication protocol to explore, a wire is a wire and if I want to make magic toys, some nice invisible communication might be useful in the near future.
I opted for the nRF24L01+ radio module, which besides the IC radio frequency transceiver (data sheet), has a built in antenna, on chip voltage regulator and can tolerate 5v inputs (so the microcontroler can still work at 5 volts!). This type of radio modules are produced in such quantity that it is impossible to make it any cheaper. Moreover, they include all the elements that the radio needs to function: oscillator, mixer, power amplifiers, low noise amplifiers, filters, antenna...
This specific model is ultra low power, supports high date range and uses SPI communication protocol, although the distance it can cover is relatively short. It works in the 2.4GHz license-free frequency band (quite busy) reserved worldwide for anyone's use and it is largely used in market applications such as simple remote controls (for doors and windows), wireless peripherals, voice transmission, wireless sensor networks... The only thing that needs to be made is the base board in which the modules are connected to the respective microcontrollers.
Setting up the hardware
I used a couple of radio modules (what is the point of having a radio talking to itself?) and two Arduinos, since the aim of this exercise for me was to understand the wireless communication protocol and its possibilities with the module, and not so much to build the boards myself. I will have plenty of opportunities to make boards for the different prototypes next semester. One of the things I am observing as I feel more and more confortable using Eagle and making my own boards, is that I dislike breadboarding more and more. However, making the boards from scratch is still a lot of work, so being able to quickly improvise dirty solutions for test with breadboards and wires is a good skill to have. The more resourceful I can be with basic electronics material, the better.
The first thing I realized was that with the 2x4 pin header, it was impossible to mount the modules on a breadboard, so I had to improvise a solution. Fortunately I had a rainbow cable with a 2x4 header and some borrowed alligator clips that I used to connect the pins of the board with the Arduino. As I said, quick and dirty. This is how the two modules looked after being connected (I had to use some insulation tape to make sure the aligator clips didn't touch each other!).
I hooked up the modules to the Arduino boards, with the pinout as seen in the picture and the specific Arduino pins for the updated RF24 library to work. Other available libraries were RF24Mesh and RF24Network, probably better for networks of more than 2 radio modules.
I learned (again) how to install the Arduino libraries from the Arduino IDE directly, quite handy to make sure you install them in the right directory. Simply by opening the Arduino IDE interface, Sketch > Include Library > Manage Libraries... and typing the name of the library you are looking for.
Important: libraries available through the IDE are not always the most recent and updated ones, so it is worth checking for the newest version outside the IDE, normally in GitHub. Sketch > Include Library > Add .ZIP library will place the download folder (not necessarily a .zip) automatically into the right place.
Getting the Arduinos to communicate through the modules
I started by trying the GettingStarted example from the RF24 library, a sort of ping-pong play between the two boards, sending and receiving bits respectively. The example makes use of the embedded auto-ack and auto-retry of the radio modules that enables them to feedback each other about the successfulness of the communication and try again if it failed. The example also allows ack-payloads (acknowledgement payloads) to be written, which enables primary receiver to switch to primary transmitter if wanting to initiate communication instead of only respond to a communication. This way both can be master and slave.
The key is to upload the same code to both microcontrollers, only making sure you give a unique number to each of them by commenting and uncommenting the following lines:
After that, and through a serial monitor set to 115200, the only thing that needs to be done is to press "T" for one of the microcontrollers to start sending. Everything went ok and the other microcontroler started receiving and sending response right away.
To officially complete the assignment, I wanted to have at least a led reacting to the wireless communication. After the piece of software that told the receiver to "pong back", I wrote a few lines that made a led connected to the board switch on and off every time there was a successful communication (ping - pong). You can find the hacked example here.
Sending sensor values
Still, If what I want in the future is to have two prototypes communicating in the distance, I need to send more complex messages than simple "Hello I am here - yeah me too". That would mean, for instance, sending variables from an analog sensor to a remote actuator.
With some help again, I started by trying to send a simple constant from one radio to the other using the same previously mentioned sketch. However, the experiment quite didn't work because I was somehow trying to fit a mono directional communication (sending a variable from one module to the other) into a bidirectional setup (ping-pong). After understanding this, I opted for trying a totally different code, much shorter and addressed to sending variable values, found in this tutorial. In the example, one radio sends the values of a joystick (basically two potentiometers) to a second radio that displays the values. I decided to use a potentiometer myself attached to an Arduino to control the brightness of the previously used led (attached to a second Arduino) and see if this was a good sketch for transmitting simple variables. As it turned out, it was.
Actually, they were, because two different sketches are necessary for master and slave. They include an extra library not present in the previous ping-pong sketch (nRF24L01.h - explanation in the link-) and I had to modify them to get rid of some bugs (common problem according to the comments on the tutorial itself).
The working code for the master (find here) relies on the function radio.write to send the values of an array previously declared ([1] represents the size > only 1 element in the array) without initializing it. potValue [0] means index 0 of the array, that is, the first element of line of variables. More info about the arrays can be found in the Arduino Playground.
Before that, the pipeline (or transmission line) was chosen to carry the alternating current of radio frequency necessary for the connection to happen between the radios.
The working code for the slave (find here) relies on the radio.read function to fetch the data payload from the previously defined array if the radio is available (again an array with only 1 variable, the value from the potentiometer at every given time), printing a signal of "No radio available" otherwise. It controls the brightness of the LED attached to a PWM pin and prints the values from the potentiometer as they are being read.
As an extra for the future, I like the idea of including the pinout of the hardware in the code.
At the end, the two sketches made for a successful wireless communication of the potentiometer values on the one side to an Arduino controlling the brightness of a led on the other, also displaying the values on the screen.
Workfiles
Añadir un comentario