Sunday, 20 January 2013

Raspberry Pi chats to Arduino

Well I got the Pi working, so what next? After a tiny amount of pondering I decided to get it chatting to an Arduino using the serial interface. I'll try and note down everything relevant so this'll be as much a guide to doing it as a recording of what I did!



Before proceeding If you have a Pi, you might ask why on earth I'd do this - surely the Raspberry Pi is so awesome, the Arduino is just wasting space? The answer is that while technically you probably could get it to do everything, that doesn't mean you should. The Pi is a high level computer, with lots of stuff happening in the background (like an operating system!) and isn't well suited to things like sending precisely timed intervals to a servo, or reading times in between pulses from sensors. Admittedly where there's a will there's a way, but I prefer the ways that require as little will as possible, so my robots down the line will generally feature 1 or more Pi's as the 'brains', with Arduinos doing the grunt work!

Overview

So, onto the actual job. The basic bits that needed doing were:
  • Connect the raspberry pi serial pins to the arduino serial pins via a logic level converter. We need the converter as the raspberry pi pins work at 3.3V, but the the Arduino works at 5V. Without it, dead Pi!
  • Disable some default settings that the raspberry pi has so that we can gain read/write access to the serial port, then use the 'minicom' app to interact with it
  • Write a little program on the Arduino to read serial data from the PI and echo it to the PC, and visa-versa
I used these web sites to gain enough info to do it:

In addition to a raspberry pi and an Arduino Uno, I also had a few wires, some jumper cables and crucially this logic level converter: https://www.sparkfun.com/products/8745. (although being in the uk I got mine from coolcomponents.co.uk).

The Circuit

This is the circuit I built in photo form - very simple really. It's ultimatley just connecting the raspberry pi serial Rx/Tx to 2 pins on the arduino, however to avoid circuit damage there's a logic level converter in the middle.


I'll upload a circuit diagram if I manage to get visio up and running again!

Note: In case you didn't know, with basic communications stuff,  'Tx' means 'transmit' and 'Rx' means 'receive'. The idea is to connect the 'Tx' of one device into the 'Rx' of another and visa versa so they can chat!

The Pi on the right looks slightly more complex than it needs to as I didn't have any single wire jumper cables. So while I've connected 9 actual pins to the breadboard, I'm really only using:
  • Pin 1: 3.3V, connects to LV (low voltage) on the level converter
  • Pin 6: 0V, connects to GND on level converter
  • Pin 8: UART Tx, connects to Tx1 on level converter
  • Pin 10: UART Rx, connects to Rx0 on level converter
The Arduino is very similar:
  • 5V goes to HV (high voltage) on the level converter
  • GND goes to GND on level converter
  • Pin 11 (using for software serial Tx) connects to Rx1 on level converter
  • Pin 10 (using for software serial Rx) connects to Tx0 on level converter
I highly recommend testing the circuit with a voltmeter as you go. I verified the raspberry pi 0V/3.3V signals with a multimeter, and as you can see here, used an oscilliscope to check the serial port output was happening:


I won't declare that's necessary, but it helps to be sure. You can test all points of your circuit with it, and check that 3.3V is what will be pumped into your Raspberry Pi before actually making the final connections.

Arduino Program

This is the very basic program used on the Arduino. It's just checking for data from either the PC (on hardware serial port) or Raspberry Pi (on the software serial port via pins 10 and 11).

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX


void setup() {
  // initialize hardware serial (arduino<->pc) and softare serial (arduino<->pi)
  Serial.begin(57600); //pc at 57600
  mySerial.begin(115200); //pi at 115200
}

void loop() {
  //check for data from pi
  if (mySerial.available())
  {
    unsigned char val = mySerial.read(); //read pi data
    Serial.write(val);    //send pi data to the pc
    mySerial.write(val);  //also echo it back to the pi, so it shows up as you type it
  }
  //check for data from pc
  if(Serial.available())
  {
    mySerial.write(Serial.read()); //send pc data to the pi
  }
}

The only slight oddity here is that I echo any data from the pi right back at it (in addition to forwarding it to pc). This is just so I can conveniently view it on the raspberry pi console and verify things are working even without the PC itself connected.

Preparing The Pi

I'm literally just repeating what I found on this very useful page: http://www.irrational.net/2012/04/19/using-the-raspberry-pis-serial-port/ in this section. Basically, bits of the default Pi setup reserve the serial port for stuff like kernel debugging and console output. We just need to disable those and restart it.

First up, I log into the Pi over SSH (search the web for how to do this - its very easy), as this gives me access to it from my PC, rather than having to actually hook it up to a tv/keyboard.


Now backup the old command line file in case I want it back!
sudo cp /boot/cmdline.txt /boot/cmdline_backup.txt

Edit the command line file:
sudo nano /boot/cmdline.txt

Remove the references to ttyAMA0. In my case this left me with:
dwc_otg.lpm_enable=0 rpitestmode=1 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait

Now edit the inittab file
sudo nano /etc/inittab

And comment out this:
2:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

Then finally, reboot:
sudo reboot

After rebooting I installed 'minicom' - a handy serial port utility:
sudo apt-get install minicom

And run it connecting to the serial port:
minicom -b 115200 -o -D /dev/ttyAMA0

Testing It

So, we now have:
  • An Arduino with my program on, connected to the pc with the serial monitor open
  • A Raspberry Pi running minicom (in my case connected to pc via SSH for ease of use)
  • A circuit that connects, via logic level converter the serial Rx/Tx of Raspberry Pi with pins 11/10 of Arduino
In theory, if you type in minicom, it should appear in the Arduino output, and visa versa! Here's a video to prove it - hope I didn't miss anything!


3 comments:

  1. Thanks for sharing
    To do the schematics you can use
    http://fritzing.org/
    You can import the adafruit draws:
    https://github.com/adafruit/Fritzing-Library

    Nice work
    PS: visio sucks

    ReplyDelete
  2. I have it to where I can send text from the arduino (in my case, a mega 1280, using rx1 and tx1 at pins 19 and 18, respectively, which are reflected in my code) to the pi, but minicom is not accepting text to send back. I am new to using minicom, is this a newbie mistake? How might I fix this?

    ReplyDelete
  3. Hi!
    Please check the formatting of the location for the logic level converter from Sparkfun. The original location shown had it down with this there, http://www.blogger.com/%C2%A0https://www.sparkfun.com/products/8745 .
    Sadly that produces the classic 404 error as the Blogger site can not parse what you're requesting. However this one,
    https://www.sparkfun.com/products/8745
    Does work.

    Otherwise good job and I don't recall how I came across your entry and ideas.

    ReplyDelete