4  R and Arduino

Author

Eric Wanjau and Ian Muchiri

4.1 The R in Arduino

This notebook briefly describes how we set up a communication interface between R and a microcontroller ( Arduino). Most of it is based on a blog post we wrote a while back: What we R about when we R about R and Arduino.

Arduino is an open-source electronics platform based on easy-to-use hardware (Arduino Board) and software (Arduino IDE). One can tell the board what to do if one has the correct form of data and a set of instructions for processing the data and performing subsequent operations. The Arduino’s microcontroller is responsible for holding all your compiled code and executing the commands you specify. The Arduino Software on the other hand is the board’s IDE where one writes the set of instructions governing the board. The getting started guide would be a good place to start learning about the Arduino ecosystem.

Switching over to R, we couldn’t have found better words to summarize what R is than with these words found in the book Advanced R by Hadley Wickham: Despite its sometimes frustrating quirks, R is, at its heart, an elegant and beautiful language, well tailored for data science 🤗.

With all this said, a fine convergence can be struck between the two: data. Consider this very simple example. We want the Arduino board to turn an LED (Light Emitting Diode) ON once it receives a 1 and OFF once it receives a 0. If one can get a way of sending some data (1 or 0) to the board’s microcontroller, then, the set objective will be achieved sooner or later.

4.1.1 Setting up a serial connection between R and Arduino

Serial communication is the communication protocol that will be used between R and the Arduino software similar to what is used in the Arduino serial monitor. This communication interface will facilitate the transmission of data between the two interfaces.

The serial package (Seilmayer 2020) will be used to set up this comunication interface.

Let’s begin by loading the required packages.

Next, we’ll create a serial port object called arduino, which represents a serial client for communication with the USB serial port where our board is connected.

# See the ports available
listPorts()

Create an Arduino object and set up the interface parameters.

This is achieved using the serial::serialConnection function. The interface parameters are such that the baud rate (specifies the number of bits being transferred per second) is set to 9600, which is the same value in the Arduino script. Also, we have specified that the transmission ends with a new line and that the transmission is complete if the end of line symbol is the carriage return cr.

arduino <-  serialConnection(name = "aRduino",
                           port = "COM5",
                           mode = "9600,n,8,1" ,
                           buffering = "none",
                           newline = TRUE,
                           eof = "",
                           translation = "cr",
                           handshake = "none",
                           buffersize = 8096
                           
                           )

Now that the serial interface is in place, the next step is initialising the interface and keeping it open for later usage such as writing and reading data from it. Once serial::isOpen initialises the interface, the Arduino board blinks. This is because the board resets once a serial port is opened to allow the bootloader to receive a new sketch.

serial::isOpen tests whether the connection is open or not.

open(arduino)

# testing whether the connection is open or not
isOpen(arduino)

4.1.2 Writing data from RStudio to the serial interface

At this point, we are all set to write some data to the serial interface.

Let’s prepare some data to send to the serial interface.

## Create dummy data
n = 42
arduino_input <- tibble(
  c = sample(10:100, size = n, replace = T) %>%
                     paste('C', sep = ''))

The chunk below uses serial::write.serialConnection() to write the LED values to the serial port row by row.

close(arduino)
open(arduino)
Sys.sleep(3)
for (r in 1:nrow(arduino_input)){
  Sys.sleep(0.3)
  write.serialConnection(arduino, paste(arduino_input[r,], collapse = ''))
}
Sys.sleep(2)

4.1.3 Driving the manipulator’s servo motors

The Arduino board itself is a programmable platform. You can tell your board what to do by sending a set of instructions to the microcontroller on the board. To do so you use the Arduino programming language and the Arduino Software (IDE). Here are sample instructions that were uploaded to the microcontroller:


if(Serial.available()){ // checks data in serial

  static int t=0;

    char mychar=Serial.read(); // reads serial data

    switch(mychar){      

      case '0'...'9':

        t=t*10 + mychar - '0’; // parse integers​

        break;

      case 'A':

        {

            servoA.write(t,50,1); // write value to motor

            Serial.println(t); // print data to serial

        }

        t=0;

        break;

        ...

    }

On a very high level, the microcontroller:

  • Checks whether data is available on the serial interface.

  • Reads the data one byte at a time

  • Uses a series of switch case commands to

    • Parse integers

    • Write motor angles (send an electrical signal) to each respective motor based on the motor’s tag e.g A, B or C

So how do the servo motors actually rotate? Servos are controlled using adjustable pulse widths on the signal line. This is achieved using a technique called Pulse Width Modulation. PWM is a modulation technique that generates variable-width pulses to represent the amplitude of an analog input signal.

For a standard servo, sending a 1 ms 5V pulse turns the motor to 0 degrees, and sending a 2 ms 5V pulse turns the motor to 180 degrees, with pulse lengths in the middle scaling linearly. A 1.5 ms pulse, for example, turns the motor to 90 degrees. Once a pulse has been sent, the servo turns to that position and stays there until another pulse instruction is received. However, if you want a servo to “hold” its position (resist being pushed on and try to maintain the exact position), you just resend the command once every 20 ms. The Arduino servo commands e.g servo.write takes care of all this for you. To better understand how servo control works, please see the timing diagram:

Servo motor timing diagram: Jeremy Blum - Exploring Arduino

A great place to get started with Arduino and some hobby electronics projects would be Blum (2013).

4.1.4 Reading data sent from Arduino board

We can read the values sent to the serial port connection by Arduino script using read.serialConnection()

data_frm_arduino <- tibble(capture.output(cat(read.serialConnection(arduino)))) %>% 
  filter(if_any(where(is.character), ~ .x != ""))


data_frm_arduino

4.1.5 Summary

There we go! In this section, we leveraged Arduino’s capability to be programmed via a serial interface to send and receive data from R to the Arduino board.

Please do feel free to reach out in case of any questions, feedback and suggestions.

Happy Learning,

Eric.