Introduction: Ultrasonic Sensor in OpenFrameworks Using Arduino

This instructable will enable you to send range finding data to openFrameworks (oF) by way of an Arduino interfacing with an ultrasonic sensor, specifically the HC-SR04. This sensor is known for its trouble communicating with the standard Arduino ofx library Firmata and this is an alternative approach without using Firmata.

I hope this can enlighten those of us who have blindly trusted in Firamta and oF to keep our Arduino under control, and thus causing many frustrating hours on forums.

You will need the following

Hardware

  • Arduino
  • Ultrasonic sensor (I am using an HC-SR04, can use others)
  • Breadboard
  • Jumper cables
  • USB cable

Software

  • Arduino IDE (https://www.arduino.cc/en/Main/Software)
  • New Ping Library for Arduino IDE (http://playground.arduino.cc/Code/NewPing)
  • Visual Studios 2015 (Windows 10 and 8 - https://www.visualstudio.com/)
    or Xcode (Mac - https://developer.apple.com/xcode/)
  • openFrameworks installed on one of the above (http://openframeworks.cc/)

Step 1: Setting Up Your Arduino

To start you need to set up your Arduino so that it can interact properly with the ultrasonic senor. This step is very important and must not be skipped. *HAZARD WARNING* If step 2 is skipped you may find many unused parts strewn around your kitchen cupboards.

Connection List - See above mock up for reference.

Ard = Arduino

BB = Breadboard

Ard 5V Pin -> BB Power strip

Ard GND Pin -> BB Ground strip

Ard Digital Pin 11 -> HC-SR04 Echo Pin

Ard Digital Pin 12 -> HC-SR04 Trig Pin

BB Power strip -> HC-SR04 Vcc Pin

Ard Ground strip -> HC-SR04 GND Pin

Step 2: Programming Your Arduino

No that you have finished step two we need something to turn your brand spanking new Arduino project into something that talks. To do this you need to throw that notion of Firmata out the window! (Can you tell I am a little bitter?).

Lets start by added the New Ping Library to your Arduino IDE. This library helps interface with many ultrasonic sensors.

  1. Download the library (http://playground.arduino.cc/Code/NewPing)
  2. Extract folder
  3. Copy to YourPC\Arduino\libraries

The library can now be included in your sketches. You can also browse the examples for using the library.

Now you need to download attached file "serialPingOF.ino" and open with the Arduino IDE. You will find commented code that prepares the Arduino for communicating the distances found. See code for detailed line by line comments.

In brief you start of by adding the New Ping library and defining which pins of the Arduino will be assigned to the Trigger and Echo pins on the ultrasonic sensor.

You then write the ping_cm() function to an int variable that prepares it for transfer over serial, this function gets the time between the chirp of the Trig pin and the chirp returning to the echo pin. It then returns it in cm, you can use ping_in() for inches.

The program then writes that distance as an int to the serial. When you write the variable to the serial port you are effectively sending it as a byte or a series of bytes. In the next step we are going to see how we can pick up those bytes on the other side of the USB through openFrameworks.

Before the next step plug your Arduino via USB to your computer and upload the code you have just written. Yahooo! we are almost there!

Arduino Code

//Cormac Joyce 2015
//initialising library. #include
// Arduino pin assigned to trigger pin on the ultrasonic sensor.
#define TRIGGER_PIN  12  
// Arduino pin assigned to echo pin on the ultrasonic sensor.
#define ECHO_PIN     11  
// Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
#define MAX_DISTANCE 500 
//int for reading the distance in cm into.
int dist;
// NewPing setup of pins and maximum distance.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
void setup() {
  Serial.begin(9600); // Open serial monitor at 115200 baud to see ping results.
}
void loop() {
  
  // ( setting ping distance in cm to dist variable (0 = outside set distance range).
  dist = sonar.ping_cm();
  // Wait 50ms between pings (about 20 pings/sec).
  delay(50);
  //here the dist variable is being written in bytes so that is can be read in oF as an int.                       
  Serial.write(dist); 
}

Step 3: OpenFrameworks: the Final Frontier

Now you have your code uploaded onto your Arduino we now need to prepare the other side, in this case, openFrameworks.

Go ahead and generate a new blank oF project. Download and paste the code attached into the relevant pages of your app, main.cpp to main.cpp. Copying and pasting is always easier as oF can bit troublesome if you attempt to move files around.

The code is commented line by line so that you can understand exactly what is happening. But for now the most important line is "serial.setup("COM3", 9600);". This line is part of the ofSerial library and is connecting to a specific port at as particular baud rate. In this case the port in COM3 as I am on Windows, on Mac and Linux it is closer to "/dev/cu.USA19H181P1.1". The baud is at which rate data is transferred through the port, in this case it is 9600 bits per second.

The second most important line is "byteData = serial.readByte();". This is the function that reads the bytes coming from the connected port. We are then assigning the bytes into an int variable and also converting it into a string. The int will be used from math and the string can be used to print on screen which it is when ran.

main.cpp

#include "ofMain.h"
#include "ofApp.h"
//========================================================================
int main( ){
    //Using small window to just show serial message.
    ofSetupOpenGL(500,200,OF_WINDOW);            // <-------- setup the GL context
    // this kicks off the running of my app
    // can be OF_WINDOW or OF_FULLSCREEN
    // pass in width and height too:
    ofRunApp(new ofApp());
}


ofApp.cpp

#include "ofApp.h"
//int for storing the byte data from Arduino. int byteData; //-------------------------------------------------------------- void ofApp::setup(){ //General setup of look of window. ofBackground(255); font.loadFont("verdana.ttf", 64); ofSetColor(0);
    //serial port setup. using COM3 for Windows port.
    //Also using baud rate 9600, same in Arduino sketch.
    serial.setup("COM3", 9600);
}
//--------------------------------------------------------------
void ofApp::update(){
    //Simple if statement to inform user if Arduino is sending serial messages. 
    if (serial.available() < 0) {
        msg = "Arduino Error";
    }
    else {
        //While statement looping through serial messages when serial is being provided.
        while (serial.available() > 0) {
            //byte data is being writen into byteData as int.
            byteData = serial.readByte();
            
            //byteData is converted into a string for drawing later.
            msg = "cm: " + ofToString(byteData);
        }
    }
    
}
//--------------------------------------------------------------
void ofApp::draw(){
    //drawing the string version pf byteData on oF window.
    font.drawString(msg, 50, 100);
    
    //printing byteData into console.
    cout << byteData << endl;
}

ofApp.h

#pragma once
#include "ofMain.h"
class ofApp : public ofBaseApp{
    public:
        //Standard oF functions.
        void setup();
        void update();
        void draw();
        void keyPressed(int key);
        void keyReleased(int key);
        void mouseMoved(int x, int y );
        void mouseDragged(int x, int y, int button);
        void mousePressed(int x, int y, int button);
        void mouseReleased(int x, int y, int button);
        void mouseEntered(int x, int y);
        void mouseExited(int x, int y);
        void windowResized(int w, int h);
        void dragEvent(ofDragInfo dragInfo);
        void gotMessage(ofMessage msg);
        //Custom variables for on screen string and font.
        string msg;
        ofTrueTypeFont font;
        //New serial object.
        ofSerial serial;
        
};

Step 4: Finishing Up

There you have it! The distance coming straight into your own openFrameworks project. To recap we have done the following.

  1. Setup and wired the Arduino.
  2. Written custom functions in the Arduino IDE and uploaded them. This is where the Processing of data happens and so any changes to the data coming from the ultrasonic sensor must come from here.
  3. Connected our oF project to the correct serial port and read the bytes coming through and finally translated them into ints and strings

I hope this has been informative and fun!