Skip to content

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.
  • 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 for false.

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 see arduino_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.

(Arduino_Tutorials)_Arduino_Serial_Monitor_Menu.png

  • 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!

(Arduino_Tutorials)_Arduino_Serial_Monitor_Before_Send

(Arduino_Tutorials)_Arduino_Serial_Monitor_After_Send

  • 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 of char (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.

ASCII Table

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 need sudo).
  • Under 07 Arduino Labs/Sample Codes, you should see serial_talker.py and serial_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 of raw_input() in serial_talker.py
  • Use ser.write(s.encode()) instead of ser.write(s) in serial_talker.py
  • Use ser.read().decode() instead of ser.read() in serial_listener.py

For more information, google "Python UTF-8 encode" by yourself.

Some further elaboration:

  1. You need to include the serial library to use pyserial.
  2. Create a new serial object on the port /dev/ttyUSB0 and baudrate 9600.
  3. Write some data to the serial object.
  4. 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. Open serial_talker.py and serial_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) in serial_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 by serial_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.

(Arduino_Tutorials)_Arduino_ls_before

  • 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.

(Arduino_Tutorials)_Arduino_ls_after

  • 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 and ttyACM 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 kill serial_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
      
  • 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 kill serial_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.