Lab 7.2. Arduino Serial Communication
Estimated time to complete this lab: 1 hour
Objectives
At the end of this self-learning lab, you should be able to:
- Send / receive data between your computer and Arduino
Background. Why do we need serial communication?
- Arduino has limited processing power (20MHz CPU clock rate) and our PC has limited I/O capability with hardware devices (e.g. few motors support USB directly).
- To allow them to work together, we require serial communication.
- For example, the Arduino can be responsible for collect sensor readings. It then sends this data back to the PC where data processing is done, which afterwards commands will be sent from the PC to the Arduino to control output devices accordingly.
Prerequisites
- We will assume you are using Linux in this lab.
- Arduino runs on a modified version of C++. But even if you haven’t learnt C++ before, the examples below should still make sense. Still, you are recommended (but not required) to see this tutorial on the m2_wiki about C++ programming afterwards.
Section 1. Basic Data Types
- Data types on different platforms may be implemented differently.
- For example,
int
is 2 bytes long on Arduino, but it is 4 bytes long on x86.
- For example,
- Therefore, it is recommended to explicitly tell the complier the variable length.
- The minimum unit of data storage in computer is byte (8 bits).
Common C language data types
Type | Length | Range |
---|---|---|
uint8_t | 8 bits (1 byte) | 0 - 255(2^8 -1) |
uint16_t | 16 bits (2 bytes) | 0 - 65535 (2^16 -1) |
int8_t | 8 bits (1 byte) | -128 - 127 (-2^7-1 to 2^7) 1 bit for the sign |
int16_t | 16 bits (2 bytes) | -32768 - 32767 (- 2^15 - 1to 2^15) |
char (an ASCII character) | 8 bit (1 byte) | 0 - 255 |
float (IEEE standard) | 32 bits (4 bytes) | 3.4E-38 to 3.4E+38 |
- The 'u' stands for unsigned.
- C doesn't have the boolean data type. Use any non-zero value for
true
, zero forfalse
.
Section 2. Serial communication using Arduino and Serial Monitor
- The Arduino IDE supports sending data to the Arduino via USB Serial. Let's try it!
- Under
07 Arduino Labs/Sample Codes
, you should seearduino_serial_demo.ino
. Open this file in the Arduino IDE and upload it to the Arduino Board. We will explain the code on the next page.
Bug
If you don't see the sample codes folder, please pull again the package from m2prog_training_2021
. Some updates have been made.
- While the Arduino is plugged into the computer (and attached to your Linux VM),
open the Serial Monitor under
Tools → Serial Monitor
.
- At the lower right corner, set the baudrate to be "9600 baud".
- Try to send the message "abc". You should see some text show up. That is the message sent by the Arduino!
- You may notice that the TX and RX LED light up on the Arduino when you click "send". This is because TX and RX indicate serial communication.
arduino_serial_demo.ino
int incomingByte = 0; // for incoming serial data
void setup() {
Serial.begin(9600); // opens serial port, with 9600 baudrate
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}
The comments should be self-explanatory. Some further elaboration is given below:
- 9600bps baudrate means that the serial communication speed is 9600 bits per second.
Serial.print()
essentially writes a c-string to the serial output, which is actually a sequence ofchar
(1 byte).
The meaning of I received 97
in the serial monitor is that 97
is the decimal form of
the character a
in ASCII. In ASCII, every character is assigned a number from 0 to 127.
Try it yourself 1
- Rewire the Arduino with an LED like that in Lab 7.1.
- Now, modify the above (or write a new) program such that the brightness of the LED
is changed (using
analogWrite()
) based on the serial input that is received. - After the brightness is changed, the Arduino should send a response message
Updated to %d
(where%d
is replaced by the brightness) via serial. - Perform serial I/O via the Serial Monitor.
- Hint: You need to use a function that translates c-string to integer (and perhaps vice-versa).
Section 3. Using Python for serial communication with Arduino
- Although we can use the Arduino IDE Serial Monitor to send and receive data between Arduino and PC, this way of communication is only suitable for fast prototyping, and is not efficient nor flexible in production code (e.g. ROS node).
- We can also use the
pyserial
library in python to perform communication on the serial port. This can allow us to bridge Arduino board and the computer by ourselves.pyserial
is a library which allows python programs to access the serial port.- Install
pyserial
via$ pip install pyserial
(may needsudo
).
- Under
07 Arduino Labs/Sample Codes
, you should seeserial_talker.py
andserial_listener.py
.
serial_talker.py
# Talker: send char through USB Serial
import serial
ser = serial.Serial('/dev/ttyUSB0', 9600) # port name
while True:
s = raw_input("Enter your input: ")
ser.write(s)
serial_listener.py
# Listener: read char from USB Serial
from __future__ import print_function
import serial
ser = serial.Serial('/dev/ttyUSB0', 9600) # port name
while True:
print(ser.read(), end="")
Bug
Due to differences in python version, you may have to make changes to the above code, e.g.
- Use
input()
instead ofraw_input()
inserial_talker.py
- Use
ser.write(s.encode())
instead ofser.write(s)
inserial_talker.py
- Use
ser.read().decode()
instead ofser.read()
inserial_listener.py
For more information, google "Python UTF-8 encode" by yourself.
Some further elaboration:
- You need to include the serial library to use pyserial.
- Create a new serial object on the port /dev/ttyUSB0 and baudrate 9600.
- Write some data to the serial object.
- Read data from the serial object.
Let's run the code:
- Connect the Arduino to Linux (plug it into your computer and attach it in the VM).
- Obtain the port name (e.g.
/dev/ttyUSB0
) from the Arduino IDE or using the method in the next section Devices in Linux. Openserial_talker.py
andserial_listener.py
, and replace/dev/ttyUSB0
with the port name you obtained. - Run
$ sudo chmod 777 /dev/ttyUSB0
(change the port name as appropriate). - Run the two python programs on two separate terminals respectively:
$ python serial_talker.py
$ python serial_listener.py
- Type some text (e.g.
abc
) inserial_talker
and press[Enter]
.
$ python serial_talker.py
Enter your input: abc
$ python serial_listener.py
I received: 97
I received: 98
I received: 99
- You should see the serial output of the Arduino displayed on the terminal screen of
serial_listener
. - The data flow is: Serial write by
serial_talker
→ Serial read by Arduino → Serial write by Arduino → Serial read byserial_listener
.
Try it yourself 2
- You should have finished Try it yourself 1.
- Now, modify the above (or write a new) Python program (with the Arduino program unchanged) such that the brightness of the LED will fade dark and fade bright alternatively (just like the Fade example, but the fade logic is on the PC).
Section 4. Devices in Linux
- Every device in Linux is a file.
- To read from a device, the programmer should "read" from that file.
- To write to a device, the programmer should "write" to that file.
- When you plug the Arduino into the PC (and attach it in the VM, if applicable), the system will allocate a file to the Arduino.
- In the Arduino IDE, you may notice that the port name is in the format of
/dev/ttyUSB0
or/dev/ttyACM0
(with 0 replaced by some number). Actually/dev/ttyUSB0
(or/dev/ttyACM0
) are actual files in the system.
Try it yourself
- To demonstrate this, first remove the Arduino from your computer.
- Now, run
ls /dev
on a new terminal.
- Connect the Arduino to your computer (and attach it in the VM).
- Run
ls /dev
on your terminal again. You should see that a new file (ttyUSB2
in the below screenshot) has been listed.
- This is because Linux has detected the newly connected device (the Arduino) and has allocated a file
/dev/ttyUSB2
to it.
- Recall that on Linux you need to perform
$ sudo chmod 777 /dev/ttyUSB0
for the device to become usable. Actually, this command is to give the device file the appropriate permissions so that the device is readable and writable. - The difference between
ttyUSB
andttyACM
is beyond the scope of this training. - There is a method to fix the "arbitrary" device name to another name of your choice based on the fingerprint of the device using udev rules, but that is also beyond scope.
You can also try to use Linux bash shell file manipulation commands (run in Terminal, not python) you learnt previously to "communicate" with the Arduino, because the Arduino is a file in Linux.
Reading from a device by reading from a file
- Run the python program
serial_talker.py
, and killserial_listener.py
. - Type some text (e.g.
abc
) in serial_talker and press[Enter]
. - On a new terminal, run the shell command
$ cat /dev/ttyUSB0
(your port).- Recall that
$ cat [file]
outputs the content of[file]
.$ python serial_talker.py Enter your input: abc
$ cat /dev/ttyUSB0 I received: 97 I received: 98 I received: 99
- Recall that
- You should see the serial output of the Arduino displayed on the terminal screen. This
is because the serial output is stored in
/dev/ttyUSB0
.
Writing to a device by writing to a file
- Run the python program
serial_listener.py
, and killserial_talker.py
. - On a new terminal, run the shell command
$ echo 'a ' > /dev/ttyUSB0
. (your port) - Recall that
$ echo [text]
outputs[text]
. - Recall that
>
redirects output from a command to a file. (see 03 L5)$ python serial_listener.py I received: 97 I received: 10
$ echo 'a ' > /dev/ttyUSB0
- You should see the serial output of the Arduino displayed on the python program. This is because the Arduino has received data by us writing to the file, and has sent a response via serial which is received by the python program.