Introduction: Combine 1 or More Arduinos With a RaspberryPi

About: Jack passed away May 20, 2018 after a long battle with cancer. His Instructables site will be kept active and questions will be answered by our son-in-law, Terry Pilling. Most of Jack's instructables are tuto…

This instructable is a demonstration of the Drogon Remote Control (DRC) feature included with wiringPi.

The wiringPi libraries, written by Gordon Henderson, add the functions that allow you to program the GPIO pins on the RaspberryPi in C in a style similar to the Arduino IDE.

Drogon Remote Control consists of an Arduino program that handles USB communication between the Arduino(s) and the RaspberryPi. I will be running two arduinos, with the same DRC sketch on both of them. It's like the RaspberryPi and the Arduino(s) become one, giving you the power of both, and all the programming is done on the RaspberryPi. The documentation for DRC is located here:

https://projects.drogon.net/drogon-remote-control/

You can download the Arduino Sketch Here:

https://projects.drogon.net/drogon-remote-control/drc-downloads/

wiringPi must be installed. Instructions for download, installation and use are located at http://wiringpi.com

wiringPi uses it's own pin numbering scheme.

All RaspberryPi pin numbers are wiringPi numbers unless otherwise specified.

Once wiringPi is installed you can obtain a list of the pinouts for your particular model of RaspberryPi by opening a terminal and typing:

gpio readall

Step 1: The RaspberryPi Circuit

You will need a way to run wires from the RaspberryPi to the breadboard. You can use male/female jumper wires but one of the Pi Cobblers listed on this page from Adafruit will make it a lot easier: http://www.adafruit.com/search?q=cobbler

For the RaspberryP circuit you will also need:

  • RaspberryPi
  • Breadboard
  • Jumper wires
  • 2 - LEDs, I used one red and one green.
  • 2 - 330-560 Ohm resistors, for the LEDs.
  • 1 - Push button switch
  • 1 - 10K resistor, pull-down resistor for switch.

Use these parts to copy the circuit in the illustration above.

You can get everything you need, except the resistors from Adafruit at http://www.adafruit.com/

or at Sparkfun, https://www.sparkfun.com/

Sparkfun also carries a nice resistor assortment that includes 25 of every value of resistor you will ever need, you can find it here https://www.sparkfun.com/products/10969.

Step 2: The Arduino Circuit

The first Arduino makes use of pinMode(), digitalRead(), digitalWrite(), analogRead(), and pwmWrite() functions all called from the RaspberryPi. This is the easiest way I know of to add an analog to digital converter to the RaspberryPi. Notice that wiringPi uses pwmWrite instead of analogWrite, it's more accurate.

The second Arduino just blinks the built in LED on pin thirteen, completely under control of the RaspberryPi. This is just to show that it really can control multiple Arduinos. It also shows a good but simple use of wiringPi's ability to multi-thread.

If you only have one Arduino you can still try the program, step 5 is a program that uses one arduino.

I built the Arduino circuit on a prototyping shield but I show the circuit diagram on a breadboard for clarity.

For the Arduino circuit you will need:

  • 2 - Arduinos
  • 2 - USB cables to connect to the RaspberryPi
  • Breadboard
  • Jumper wires
  • 2 - LEDs, I used one red and one green.
  • 2 - 330-560 Ohm resistors, for the LEDs.
  • 1 - Push button switch
  • 1 - Resistive sensor
  • 2 - 10K resistors, pull-downs for switch and sensor.

Use these parts to copy the circuit in the illustration above.

I used a force sensitive resistor for the resistive sensor, but a photo cell or a bend sensor will work just as well. You can also use a potentiometer. To wire a potentiometer forget the 10K resistor, wire the middle lead to the pin, one end lead to the positive rail and the other to ground.

Step 3: The Code

Download this program for your RaspberryPi.

Compile it with the command:

gcc -o DRCtest DRCtest.c -lwiringPi -lpthread

And run it with the command:

sudo ./DRCtest

/************************************************************************
 * DRCtest.c - Test program for Drogon Remote Control. (DRC)
 *
 * On the first Arduino:
 * LEDs are connected to pins nine and eleven, with 560 Ohm current limiting resistors.
 * A push button switch is connected to pin five, with a 10K pull-down resistor.
 * A resistive sensor is connected to analog pin zero, with a 10K pull-down resistor.
 * The only connection to the RaspberryPi is the USB cable.
 * The program in the RaspberryPi is controling the Arduino.
 * The DRC.ino program must be installed and running.
 *
 * Nothing is connected to the second Arduino.
 *
 * On the RaspberryPi:
 * LEDs are connected to pins nine and eleven, with 560 Ohm current limiting resistors.
 * A push button switch is connected to pin five, with a 10K pull-down resistor.
 * The pin numbers for the RaspberryPi use the wiringPi pin numbering scheme.
 *
 * The loop() function does a digitalRead of the push button on the Arduino
 * and digitalWrites the value to the both red LEDs
 * Next it performs an analogRead of the force sensitive resistor, divides
 * the value by four, and pwmWrites the value to both green LEDs.
 * Then is does a digitalRead of the push button on the RaspberryPi
 * and digitalWrites the value to the both red LEDs
 *
 ************************************************************************/
#include <stdio.h>
#include <wiringPi.h>
#include <drcserial.h>

#define    BASE    100
#define    BASE2    200
/*****************************************************************************
 * The second thread blinks the built in LED on pin 13 of the Second Arduino.  
 * The code here runs concurrently with the main program in an infinite loop.
 *****************************************************************************/
PI_THREAD(arduino2)
{
  for(;;)
  { 
    digitalWrite(BASE2+13, HIGH); // Turn pin 13 on.
    delay(500);
    digitalWrite(BASE2+13, LOW); // Turn pin 13 off.
    delay(500);
  }
}
/**************************************************************************
 * setup() function
 **************************************************************************/
void setup(void)
{
  wiringPiSetup();
  drcSetupSerial(BASE, 20, "/dev/ttyACM0", 115200);
  drcSetupSerial(BASE2, 20, "/dev/ttyACM1", 115200);

  int x = piThreadCreate(arduino2); // Start second thread.
  if (x != 0) printf("It didn't start.\n");

// Pins on Arduino:
  pinMode (BASE+11, PWM_OUTPUT);    // Reset pin to maximum value
  pwmWrite(BASE+11, 255);           // after PWM write.
 
  pinMode (BASE+5, INPUT);          // Pin 5 used for digitalRead.

  pinMode (BASE+9, PWM_OUTPUT);     // Pin 9 used for pwmWrite.
                                    // Pin A0 is used for analogRead.
// Pins on second Arduino:
  pinMode (BASE2+13, OUTPUT);       // Pin 13 used for digitalWrite.
   
// Pins on RaspberryPi:
  pinMode(0, OUTPUT);               // Pin 0 used for digitalWrite.              
  pinMode(5, INPUT);                // Pin 5 used for digitalRead.

  pinMode(1, PWM_OUTPUT);           // Pin 1 used for pwmWrite.
}
/**************************************************************************
 * loop() function
 **************************************************************************/
void loop(void)
{
  digitalWrite(BASE+11, digitalRead(BASE+5)); // If Arduino button is pressed
  digitalWrite(0, digitalRead(BASE+5));       // turn on both red LEDs.

  pwmWrite(BASE+9, (analogRead(BASE)/4));     // Varies the brightness of both green
  pwmWrite(1, (analogRead(BASE)/4));          // LEDs according to pressure applied 
                                              // to the force sensitive resistor.

  digitalWrite(BASE+11, digitalRead(5));      // If RaspberryPi button is pressed
  digitalWrite(0, digitalRead(5));            // turn on both red LEDs.
}
/**************************************************************************
 * main() function
 **************************************************************************/
int main (void)
{
  setup();
  for(;;)
  {
    loop();
  }
  return 0 ;
}

Step 4: Putting It All Together

Upload the Arduino sketch in step six to the Arduino(s) you will be using.

Turn off the RaspberryPi and connect the RaspberryPi circuit. The RaspberryPi must be turned off before plugging in the USB ports or it will not register them as the right device. The first Arduino is /dev/ttyACM0, and the second is /dev/ttyACM1. If you don't have the Arduinos plugged into the right USB ports it sends the commands to the wrong Arduino. On the model B+ the first Arduino is in the top USB port on the same side as the GPIO header. The second Arduino is in the bottom USB port underneath. If you are using a USB hub you will have to switch ports around to see what works.

Turn on the RaspberryPi and run the program with the command:

sudo ./DRCtest

Pressing the button on the RaspberryPi circuit should light the red LED on both the RaspberryPi circuit and the first Arduino.

Pressing the button on the first Arduino will also light both red LEDs.

Varying the resistive sensor will cause the green LEDs to vary in brightness.

On the second Arduino the on board pin 13 indicator LED should blink on and off.

If it doesn't work the first time turn everything off and reverse the USB ports.

Step 5: Running the Program With One Arduino

If you don't have a second Arduino you can still try the demonstration.

Download this version of the program and compile it with the command:

gcc -o DRCtest-1 DRCtest-1.c -lwiringPi

And run the program with the command:

sudo ./DRCtest-1

With only one Arduino you can plug the Arduino into any USB port with the power off and it will work.

Step 6: Arduino Code

This is the sketch for the Arduino(s).

/*
* drcAduino: * Arduino code to implement DRC - The Drogon Remote Control. * Allow another device talking to us over the serial port to control the IO pins. * * Copyright (c) 2012 Gordon Henderson * * Full details at: * http://projects.drogon.net/drogon-remote-control/... * * Commands: * @: 0x40 Ping Send back #: 0x23 * 0: 0x30 0xNN Set Pin NN OFF * 1: 0x31 0xNN Set Pin NN ON * i: 0x69 0xNN Set Pin NN as Input * o: 0x6F 0xNN Set Pin NN as Output * p: 0x6F 0xNN Set Pin NN as PWM * v: 0x6F 0xNN Set PWM value on Pin NN * r: 0x72 0xNN Read back digital Pin NN Send back 0: 0x30 or 1: 0x31 * a: 0x61 0xNN Read back analogue pin NN Send back binary 2 bytes, Hi first. * ********************************************************************************* * This file is part of drcAduino: * Drogon Remote Control for Arduino * http://projects.drogon.net/drogon-remote-control/... * * drcAduino is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * drcAduino is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with drcAduino. If not, see . ********************************************************************************* *
/ Serial commands
#define CMD_PING        '@'
#define CMD_PIN_0       '0'
#define CMD_PIN_1       '1'
#define CMD_PIN_I       'i'
#define CMD_PIN_O       'o'
#define CMD_RD_PIN      'r'
#define CMD_RA_PIN      'a'
#define CMD_PWM_PIN     'p'
#define CMD_PWM_VAL_PIN  'v'
#define CMD_DEBUG_DIGITAL       'D'
#define CMD_DEBUG_ANALOGUE      'A'
// Arduino with a 168 or 328 chip
//      ie. Arduino Classic, Demi, Uno.
#define MIN_APIN         0
#define MAX_APIN         5
#define MIN_DPIN         2
#define MAX_DPIN        13
void setup ()
{
  int pin ;
  
  Serial.begin (115200) ;
  Serial.println ("DRC Arduino 1.0") ;
  pinMode (13, OUTPUT) ;
  digitalWrite (13, HIGH) ;
  for (pin = 2 ; pin < 13 ; ++pin)
  {
    digitalWrite (pin, LOW) ;
    pinMode (pin, INPUT) ;
  }
  analogReference (DEFAULT) ;
}
int myGetchar ()
{
  int x ;
  while ((x = Serial.read ()) == -1)
    ;
  return x ;
}
void loop ()
{
  unsigned int pin ;
  unsigned int aVal, dVal ;
  
  for (;;)
  {
    if (Serial.available () > 0)
    {
      switch (myGetchar ())
      {
        case CMD_PING:
          Serial.write (CMD_PING) ;
          continue ;
        case CMD_PIN_O:
          pin = Serial.read () ;
          if ((pin >= MIN_DPIN) && (pin <= MAX_DPIN))
            pinMode (pin, OUTPUT) ;
          continue ;
        case CMD_PIN_I:
          pin = myGetchar () ;
          if ((pin >= MIN_DPIN) && (pin <= MAX_DPIN))
            pinMode (pin, INPUT) ;
          continue ;
        case CMD_PIN_0:
          pin = myGetchar () ;
          if ((pin >= MIN_DPIN) && (pin <= MAX_DPIN))
            digitalWrite (pin, LOW) ;
          continue ;
        case CMD_PIN_1:
          pin = myGetchar () ;
          if ((pin >= MIN_DPIN) && (pin <= MAX_DPIN))
            digitalWrite (pin, HIGH) ;
          continue ;
        case CMD_RD_PIN:
          pin = myGetchar () ;
          if ((pin >= MIN_DPIN) && (pin <= MAX_DPIN))
            dVal = digitalRead (pin) ;
          else
            dVal = LOW ;
          Serial.write ((dVal == HIGH) ? '1' : '0') ;
          continue ;
        case CMD_RA_PIN:
          pin = myGetchar () ;
          if ((pin >= MIN_APIN) && (pin <= MAX_APIN))
            aVal = analogRead (pin) ;
          else
            aVal = 0 ;
          Serial.write ((aVal & 0xFF00) >> 8) ;        // High byte first
          Serial.write ( aVal & 0x00FF      ) ;
          continue ;
        case CMD_PWM_PIN:       
          pin = myGetchar () ;
          if ((pin >= MIN_DPIN) && (pin <= MAX_DPIN))
            pinMode (pin, OUTPUT) ;
          continue ;
        case CMD_PWM_VAL_PIN:
          pin  = myGetchar () ;
          dVal = myGetchar () ;
          if ((pin >= MIN_DPIN) && (pin <= MAX_DPIN))
            analogWrite (pin, dVal) ;
          continue ;
      }
    }
  }
}

Attachments