CHAPTER 3

image

openFrameworks and Arduino

openFrameworks is a set of C++ libraries that provides an easy method of coding audio, video, and graphical components. openFrameworks provides mechanisms to easily connect serial devices and Arduinos to personal computers, making openFrameworks an invaluable tool for Arduino development and a useful next topic for discussion.

openFrameworks can be compared to interlocking plastic construction bricks in that using individual units does not require knowing how to make them. The libraries of openFrameworks are a lot like boxes of construction bricks, allowing creativity to flow without having to code from the ground up and always having a piece that will work. This is done by utilizing C++ object-oriented programming methods, which add abstraction and reusability. The advantage to openFrameworks in a development scene is that you can put together proofs of concept without having to do a lot of low-level coding. Working in openFrameworks also provides working code that can be used as a blueprint to migrate from when a final project goes into production and needs more optimizations.

Incorporating both openFrameworks and Arduino helps create a proof-of-concept environment for hardware and software interaction, which uses a development approach that “work fosters ideas”; an exploratory development style where ideas can be explored without waste. The key to this is reusability: not having to worry about permanently using a resource and having plenty components to play with. The combination of openFrameworks and Arduino is cross compatible on most systems.

The disadvantages to this setup are that it may not be production quality, optimized, reliable, or usable for the masses; things that are arguably less important than sharing and exploration in idea generation. The disadvantages are taken care of when moving away from the proof of concept to a prototype or putting the project into production. For developers, showing an idea is more impressive when that idea is something that can be fully manipulated. Physical models go a long way toward helping ideas to take life and can be easily created with clay, wood, 3D printing, or various other means. Adding openFrameworks and Arduinos to a physical model can, for example, help you create a new game controller design that can be used to play games.

Arduino and openFrameworks comprise a nice tool set to help breathe that extra life into an idea. With its simple code structure, designers, artists, it gives developers the ability to add buttons to make LEDs blink, create controllers to move virtual objects, and make systems that manipulate physical objects. Both Arduino and openFrameworks have vast online communities and a plethora of other documentation, making the knowledge to work and develop with these systems easily available. This chapter focuses on connecting the Arduino to computers via openFrameworks to expand the functionality of the Arduino.

Getting Started

To get started, make sure that the openFrameworks and Arduino software are set up and working, and also make sure there is a compatible Arduino board (e.g., an Uno, Leonardo or Nano) available. To download and install openFrameworks, go to www.openframeworks.cc and follow the setup instructions for your system. openFrameworks requires C++ and is built for integrated development environments (IDEs) such as Code::Blocks (www.codeblocks.org), Visual C++ (www.microsoft.com/express), and Xcode (http://developer.apple.com/xcode/).

The first four examples in this chapter (Listings 3-1 to 3-4) show how to set up serial communications. All the examples are written using Arduino 1.0.1 and openFrameworks version 0071 but have been tested with Arduino 1.5.1r2 and openFrameworks 0073.

Arduino Code

Listing 3-1 shows the code to set up the Arduino, connect to a push button on pin 8, and check if the button is pressed or released and report the change in this state to a serial connection using a character. The code also checks for an incoming character from the serial; a and s signify turning on and off an LED on pin 13, respectively. This passing of characters is important when developing code for openFrameworks to control the Arduino, thus making the Arduino a possible controller for a game, a sensor for a door, and so on.

Listing 3-1.  Arduino Sketch That Sets Upthe Arduino

int button = 8 , ledPin = 13; // pin assignments: button on pin 8,LED on pin 13
boolean oldState = 0 , newState = 0;     // state change variables
voidsetup() {
  pinMode(button, INPUT);     ////////////////////////////
  pinMode(ledPin,OUTPUT);     // set pin I/O types
  Serial.begin(9600);         // starts serial at baud rate 9600
} // end setup()
voidloop() {
  newState = digitalRead(button); // save current button state
    if(newState != oldState){     // test for change in button state
      if (newState  == true)      // for button press, send the "h" to serial
        Serial.print('h'),
      if (newState  == false)    // for button release, send the "l" to serial
        Serial.print('l'),
    } // end if(state0 != state1)
  oldState = newState;          // save new state to old state for comparison
  delay(40);                    // delay for bounce control
} // end void loop()
voidserialEvent() { // called upon incoming serial
  switch (Serial.read()){  // determine if serial is one of the required inputs
    case 'a':  digitalWrite(ledPin, HIGH);
      break;                  // for input of "a", turn on LED
    case 's':  digitalWrite(ledPin, LOW);
      break;                  // for input of "s", turn off LED
  }   // end switch (Serial.read())
}     // end serialEvent()

image Note  The serialEvent() function does not work with the Leonardo board. To convert for the Leonardo board change void serialEvent() to if (Serial.available() > 0) and move the loop ending bracket to below the ex void serialEvent() function.

Verifying the Code

Load Listing 3-1 and hook up the Arduino with a momentary push-button switch and a pull-down resistor hooked to pin 8. The LED set up on pin 13 is optional because the Arduino has one on the board. With the board set up as per Figure 3-1 and plugged in, start the serial monitor in the Arduino IDE and match the baud rate of 9600. When the button is pressed, it causes an h or an l character to be displayed for a high or low state change. Sending the Arduino an a or an s will turn on or off the LED.

9781430239390_Fig03-01.jpg

Figure 3-1 .  Arduino circuit for Listing 3-1

Arduino Serial Functions

Listed following is a reference of Arduino serial functions and what they are used for. These functions reside in the predefined Serial object. To call any of the serial functions, use Serial. before the name, like so:

Serial.begin(9600);

  • void begin(speed): Opens and sets a serial port at a baud speed equal to an unsigned long. Returns nothing.
  • void end(): Closes the serial connection, releasing the TX and RX pins.
  • int available(): Checks for data in the serial buffer and returns the number of bytes in the buffer.
  • int read(): Returns the first incoming byte in the serial buffer as an int, and then removes the byte. Successive reads will move through the buffer, much like dealing a deck of cards.
  • int peek(): Reads the incoming serial buffer’s first byte, returns as an int, and leaves the data in the buffer. This function is like peeking at the top card of a deck of cards.
  • void flush(): Clears the serial buffer’s data. flush() will clear data after the buffer data is sent out.
  • size_t print / println (value, format): Sends a human-readable translation of data. Digits are sent as ASCII-equivalent strings, and characters are sent as bytes. This function can have a format of DEC, HEX, BIN, or OCT. format can also be used to define the number of bytes to send. println is the same as print, except it sends a new line to the end of the value. Returns the number of bytes sent; reading is not required.
  • size_t write(value, size): Sends data in binary bytes instead of ASCII. write() can send a single byte value, in which case size is not needed. A string and buffer are sent as a series of bytes. size declares the buffer’s number of bytes to send. Returns the number of bytes sent.
  • void serialEvent(){ }: Can be added to a sketch that is called any time there is incoming serial activity.

openFrameworks Setup

With the Arduino code outputting and accepting input from the serial monitor, other programs can be developed using C, C++, Java, or any other computer language from scratch to connect the Arduino to the computer. Coding from scratch, however, can be a bit tedious for a proof-of-concept project. openFrameworks provides a nice prebuilt interface for programming serial with C++ and also adds many other useful tidbits for audio and graphics. The next set of examples will show how the openFrameworks libraries can be used to connect to the Arduino and the sketch from Listing 3-1.

To verify that openFrameworks is working properly and the library is compiled, make a copy of the empty example folder in the openFrameworks distribution; keep the folder in the same directory and rename it to ch3.

image Note  The examples are located in the openFrameworks examples directory. An empty example to start with is located in the apps/myApps subdirectory of the openFrameworks main directory.

Open the workspace for Code::Blocks or the VC++ project file in the renamed folder, and then compile. Two things should compile: emptyexample and libopenFrameworks. After both parts are compiled successfully, openFrameworks is ready for new code. Coding the examples in this chapter for openFrameworks applications is done in the Code::Blocks project file or the Microsoft Visual Studio solution (not the one named libopenFrameworks, but the one named after the project—e.g., emptyexample.workspace). The files for the examples in this chapter are available for download from www.apress.com/9781430239390 and are contained in three files: main.cpp, testapp.cpp,and testapp.h. These three files can replace the files with the same name that are in the renamed folder src directory.

image Caution  Moving and compiling projects outside of the openFrameworks apps/examples directory may cause dependencies issues. To solve this, point all the dependencies to the location of the openFrameworks main directory.

Connecting to the Arduino from openFrameworks

Listings 3-2 through 3-4 make up the three files to create and run a basic openFrameworks program to connect to an Arduino to send and receive data without having to use the serial monitor or console, while also providing extra computing power by allowing the Arduino to connect to a C++ program.

Listing 3-2.  main.cpp

#include "ofMain.h"           // include files
#include "testApp.h"          // declarations for the testapp class
#include "ofAppGlutWindow.h"  // for using OpenGL and creating windows
int main() {
   ofAppGlutWindow window;    // sets up an OpenGL window object
   ofSetupOpenGL(&window,200,100, OF_WINDOW);  //sets window size in pixels
   ofRunApp(new testApp());   // create testapp object & enter program loop
} // end int main()

openFrameworks code is set up to be event driven and window based, the same as other graphical-interface programs. The main.cpp file contains the main() function, which is the entry point to the openFrameworks programs. The main() function sets parameters for the window, including the window size and window mode. It is rare to make many changes in main.cpp; most of the time the only thing that will change is the window size.

Listing 3-3.  testapp.h

#include "ofMain.h"
class testApp : public ofBaseApp{
  public:
    void setup();          // for setting initial parameters
    void update();         // code in this function is constantly run, events will interrupt
    void draw();           // runs after update,this updates & creates the window objects
    void mousePressed(int x, int y, int button);  // on event function
    bool SendSerialMessage;         // signals that data needs to be sent
    char ledcommand ;               // hold what state the LED is in
    char Returned;                  // hold returned char from Arduino
    ofSerial serial;                // this is the object to handle serial
};// end class testApp : public ofBaseApp

The testApp class inherits common functionality from the ofBaseApp class. This is where the function prototypes are created. Variables that will be used in many functions can be declared here. There is a set of functions that are called when events occur, such as mouse movement or using the keyboard. Note the line where you need to change COM4 to match your Arduino setup.

Listing 3-4.  testapp.cpp

#include "testApp.h"
void testApp::setup(){
  ofSetVerticalSync(true);      // helps to smooth out object drawing
  ofBackground(255,255,255);    // set background color to an RGB value
  serial.setup("COM7", 9600);   // change "COM7" to match where the Arduino is
  ledcommand = 's';             // set initial state of the LED
  serial.writeByte(ledcommand); // tell Arduino of the initial state
  SendSerialMessage = false;    // nothing to send yet
} // end void testApp::setup()
 void testApp::update(){
  if (SendSerialMessage)          // is there serial information that needs to be sent
   serial.writeByte(ledcommand);  // tell the Arduino to change LED state
  if (serial.available())         // check to see if there is incoming data
    Returned = serial.readByte(); // save the incoming data
  SendSerialMessage = false;      // reset the need to send data to the Arduino
}//end testApp::update
void testApp::draw(){    // defines placement and draws objects in the window
  ofFill();                  // fills geometry with a solid color
    if (Returned == 'h')     // is the button on the Arduino being pressed
      ofSetColor(0,0,255);   // set the first circle color to full blue
    else                     // the button is not pressed or the state is not known
      ofSetColor(0,0,127);   // set the first circle color to 1/2 blue
  ofCircle(50,50, 50);       // draw the first circle at last set color
    if (ledcommand == 'a')   // should the LED be on
      ofSetColor(0,255,0);   // set color to full green for the second circle
    else                     // LED should be off or not known
      ofSetColor(0,127,0);   // set color to 1/2 green for the second circle
   ofCircle(150,50, 50);     // draw the second circle at last set color
} //end void testApp::draw()
void testApp::mousePressed(int x, int y, int button){
  SendSerialMessage = true;  // inform update function that there is data to send
  if(ledcommand == 'a')      // if the LED is ON
    ledcommand = 's';        // change LED to be OFF
  else                       // if the LED is OFF
    ledcommand = 'a';        // change LED to be ON
} //end testApp::mousePressed

Verifying the Code

Make sure that the Arduino that was set up in Listing 3-1 is plugged into the computer and take note of the port that it is plugged into.

  • COM* is for Windows
  • /dev/tty* is used for Linux/Unix and Mac OS X

Change the serial.setup(COM4,9600) line in Listing 3-4 to match the Arduino’s connecting point. Once the test app is set to know where the Arduino is, compile the examples. Running the program will open a window frame that looks like Figure 3-2, with the first circle representing the push button and the second circle showing the state of the LED. To change the LED state, click in the window with the mouse.

9781430239390_Fig03-02.jpg

Figure 3-2 .  Example of the running program

openFrameworks Serial Functions

The following reference list is for the openFrameworks serial functions. Most of the functions work just like the Arduino’s counterpart functions. The serial object must be declared before using and calling the openFrameworks serial functions. The serial object comes from the ofSerial class; just as a variable is declared, a serial object is created by using the following:

ofSerial serial;

To use any of the functions, use the name declared for the object—for example, serial.setup();. Here are the functions:

  • void enumerateDevices(): Lists the available serial devices.
  • void close(): Closes the serial connection.
  • bool setup(int, int): Connects to the device number corresponding to the list outputted by enumerateDevices() at the desired baud speed.
  • bool setup(): Opens a serial connection on the first available device at baud 9600 and returns a fail or succeed.
  • bool setup(string, int): Uses a string to declare what serial device to connect to. The second parameter sets the baud speed and returns a fail or succeed.
  • int readBytes(unsigned char, int): Takes a pointer to an array of characters, attempts to retrieve the number of bytes equal to the second parameter, and returns the number of actual bytes read (compare to the requested amount of bytes to error-check).
  • int readByte(): Returns a single byte from the connected device.
  • int writeBytes(unsigned char, int): Takes a character array or string and an amount of bytes to write, and returns the amount written for error checking.
  • bool writeByte(unsigned char): Sends a single byte to the connected device and returns a fail or succeed.
  • void flush(bool, bool): Clears one or both of the serial buffers (one buffer for send, one buffer for receive).
  • int available(): Returns the number of available bytes in the receive buffer.

Coding Once Using Firmata and ofArduino

In keeping with the spirit of “work fosters ideas,” working with two different pieces of code (one on the Arduino and one using openFrameworks) is a bit inefficient for exploring ideas, especially when changing things frequently. Luckily, there are items included with the Arduino IDE and openFrameworks (a program for the Arduino and a built-in class for openFrameworks) that make it possible to write single programs that take care of having to separately code the Arduino.

  • Firmata is a communication protocol for the Arduino that allows for on-the-fly configurations without having to restart or reprogram the Arduino. Standard Firmata is included with the Arduino IDE.
  • openFrameworks complements Firmata by including a class called ofArduino, which handles both communication and configuration of the Arduino.

Setting Up Firmata

Set up the Arduino board with the components connected as in the schematic in Figure 3-3, and then upload the Standard Firmata sketch. The sketch is located in the Arduino IDE under File image Examples image Firmata image StandardFirmata.

9781430239390_Fig03-03.jpg

Figure 3-3 .  Arduino circuit for Listing 3-5

To verify that Firmata is working on the Arduino, download and run the test app from www.firmata.org/. Select the port to connect to from the drop-down menu, and the app will show all the pins, which have drop-down boxes for pin configuration and buttons for output values, as shown in Figure 3-4.

image Note  The Leonardo need the Firmata library updated. Instructions and updated library available at www.github.com/soundanalogous/Breakout/wiki/Updating-Firmata-in-Arduino

9781430239390_Fig03-04.jpg

Figure 3-4 .  Firmata testing application

The Firmata test app is especially usefully for testing out component setups that use multiple pins, such as a three- to eight-line MUXs, seven-segment displays , keypads, and servomotors.

Controlling the Arduino with openFrameworks

The code in the next example uses the same main.cpp as Listing 3-2. The header file testapp.h in Listing 3-5 still declares the class function prototypessetup(),update(),draw(), and mousePressed(). The two new function prototypes are set up to mimic the Arduino’s coding structure. The function arduinoSetup() is for initializing pin configurations, and the function arduinoLoop() is the equivalent to loop in Arduino sketches.

Listing 3-5.  testapp.hfor the Standard Firmata Sketch Communication

#include "ofMain.h"
#include "ofEvents.h"
class testApp : public ofBaseApp {
  public:
    void setup();
    void update();
    void draw();
    void mousePressed(int x, int y, int button);
    void arduinoSetup(const int & version); // Arduino equivalent setup function
    void arduinoLoop(); // Arduino-equivalent loop function
    bool ledcommand;
    bool pin13; // pin13 data container
    bool pin8; // pin8 data container
    float analogPin0; // pin8 data container
    bool isArduinoSet; // flag to know when Arduino is connected and configured
    ofArduino arduino; // the Arduino object
}; // end class testApp : public ofBaseApp

In testapp.cpp of Listing 3-6, the functions arduinoSetup() and arduinoLoop() perform the same functions of an Arduino sketch with openFrameworks on top of the Arduino-style functions. Firmata and the openFrameworks ofArduino class make the serial communication less apparent. By carefully mimicking the same structure as an Arduino sketch, the conversion to an actual Arduino sketch is made simpler if the conversion becomes necessary, as when moving to a more professional setup. Keep in mind it is possible to develop code in openFrameworks that may require more space and computing power than might be available on the Arduino. This is especially important to remember when using Firmata as a tool in making proofs of concept to eventually be used solely on the Arduino.

image Note  Firmata is capable of using I2C and other communication functionality; however, openFrameworks does not currently support I2C functionality (as of version 0071).

Example 3-6.  testapp.cppfor Standard Firmata Communication

#include "testApp.h"
void testApp::setup() {
  arduino.connect("COM7"); // remember! change this to the proper port
  ofAddListener(arduino.EInitialized, this, &testApp::arduinoSetup);
  /*the ofAddListener waits for the Arduino to perform a handshake telling the program that it is ready to be configured and set up. This will call arduinoSetup*/
  isArduinoSet = false; // this flag is set false until the Arduino is set up
} // end void testApp::setup()
void testApp::update() {
  testApp::arduinoLoop();// perform the Arduino-style code
} // end void testApp::update()
void testApp::draw() { // objects are drawn to the screen in the order called
  if (isArduinoSet){ // do not run this code until Arduino is operating
    ofFill();
    if(pin8 == ARD_HIGH)
      ofSetColor(0,0,255);// if button on pin8 pressed, brighten the circle
    else
      ofSetColor(0,0,127);// blue is dim if button is released
    ofCircle(50,50,50); // draw circle at (x,y,radius) in pixels for button
    if(pin13 == ARD_HIGH)
      ofSetColor(0,255,0); // when LED is on, draw full green
    else
      ofSetColor(0,127,0);// green is dimmed when LED is off
    ofCircle(150,50, 50); // draw circle at (x,y,radius) in pixels for LED
    ofSetColor(255,0,0); // set color for analog potentiometer
                                // draw rectangle with corners at (x1,y1,x2,y2)
    ofRect(0, 45 ,(analogPin0*200) , 10); // rectangle is dynamic on the x-axis
             // analogPin0 is a percentage multiplied by window width
  } // end if (isArduinoSet)
}// end void testApp::draw()
void testApp::mousePressed(int x, int y, int button) {
    if(ledcommand == true) // if LED is ON
      ledcommand = false ;   // flag the LED to turn OFF
    else // the LED is OFF
      ledcommand = true; // flag the LED to turn ON
}// end testApp::mousePressed
void testApp::arduinoSetup(const int & version) {
  ofRemoveListener(arduino.EInitialized, this, &testApp::arduinoSetup);
  // there is no need to continue to listen for the Arduino, so clear memory
  arduino.sendAnalogPinReporting(0, ARD_ANALOG);// turn on analog pin0
  arduino.sendDigitalPinMode(8, ARD_INPUT);// set digital pin8 as input
  arduino.sendDigitalPinMode(13, ARD_OUTPUT);// set digital pin13 as output
  isArduinoSet = true;// inform the rest of the program that Arduino is ready
}//end void testApp::arduinoSetup(
void testApp::arduinoLoop() {
// do not run this code until Arduino is operating
    if (isArduinoSet){
     pin8 = arduino.getDigital(8);// digital read pin8
    pin13 = arduino.getDigital(13);// digital read pin13 verifying state
    analogPin0 = arduino.getAnalog(0)/1023.0; // analog read A0
    arduino.sendDigital(13, ledcommand);// digital write new state
    }// end if (isArduinoSet)
    arduino.update();// get any changes that the Arduino might have
}// end void testApp::arduinoLoop()

Verifying the Code

When done looking over and compiling the code, plug in the Arduino with the components set up in as Figure 3-3 and the standard Firmata sketch uploaded. When running, the program will open a window with the same size as the prior example. The program will also have the same two circles representing the button and LED, respectively performing the same functions. A red bar is added to the program that will go from side to side, representing the full sweep of the potentiometer.

image Note  The Arduino may be required to reset, via the reset button, before the listener initializes and recognizes the Arduino. The listener is built into openFrameworks to listen for an Arduino on the connection.

Key Constants Used by ofArduino

ofArduino defines some useful constants for more readable code. The following list is a reference of names and values of the constants. The first part of the constants, ARD, is short for Arduino, and is a reminder that this is dealing with the hardware. The second part is the type—for example, the pin modes or state declarations.

  • Pin modes:
  • ARD_INPUT = 0x00
  • ARD_OUTPUT = 0x01
  • ARD_ANALOG = 0x02
  • ARD_PWM = 0x03
  • ARD_SERVO = 0x04
  • Pin states:
  • ARD_HIGH or ARD_ON = 1
  • ARD_LOW or ARD_OFF = 0

ofArduino Reference of Class Functions

The following list is a reference for the class functions that make up the ofArduino class. The functions that are included in the ofArduino class are used to control and connect to Arduinos that have the standard Firmata sketch loaded. Most of the functions are a direct counterpart of the functions used in the Arduino IDE and work the same way; for example, sendDigital() is the same as digitalWrite(). The functions require an ofArduino object declared before they can be used. You can connect multiple Arduinos to the same computer by declaring separate objects for each Arduino.

  • bool Connect(port, speed): Opens an Arduino connection on a serial port and takes a string for the device connection, such as /dev/ttyUSB0, COM4 or /dev/tty.usbserial-A4001JEC. The second parameter is for nondefault baud speeds and can be omitted in standard configurations.
  • void disconnect(): Releases the Arduino connection.
  • bool isInitialized(): Returns true if a successful connection has been established and the Arduino has reported that firmware from the Firmata sketch has been uploaded.
  • void update(): Used to update the current state of the Arduino’s incoming information; this should be called regularly.
  • void sendDigitalPinMode(pin, mode): Sets the pin mode of a digital pin (one of pins 2 through 13) and sets the pin as one of the digital modes of ARD_INPUT, ARD_OUTPUT, ARD_PWM, or ARD_SERVO. If the pin is an input, the reporting will be turned on.
  • void sendAnalogPinReporting(pin, mode): For analog pins 0 through 5, turns the reporting to ARD_ON or ARD_OFF. Analog pins can be used as digital pins 16 through 21 or as PWM pins. The whole group is either analog or digital.
  • void sendDigital(pin, state): Sets the state of the specified digital pin to either ARD_LOW or ARD_HIGH.
  • void sendPwm(pin, value): Sets the PWM value for pins set to ADR_PWM (chosen from pins 3, 5, 6, 9, 10, and 11); the value is between ON (255) and OFF (0).
  • void sendServo(pin, sweep): Uses pin 9 or 10 and sends servo signals between 0 and sweep-angle default 180.
  • void sendServoAttach(pin, min, max, sweep): Defines the following servo parameters:
  • The pin
  • Minimum pulse width (defaults to 544)
  • Maximum pulse width (defaults to 2400)
  • Angle of sweep (defaults to 180)
  • int getDigital(pin): Used on pins 2 through 13:
  • For pins set as ARD_INPUT returns the last state the pin reported
  • For pins set as ARD_OUTPUT returns the last value sent to the pin
  • int getPwm(pin): For pins set as ARD_PWM, returns the last set PWM value for the pin requested (usable pins are 3, 5, 6, 9, 10 and 11, or pins 16 through 21 if analog pins 0 through 5 are set as digital pins).
  • int getServo(pin): Returns the last value the servo was set to.
  • int getAnalog(pin): Used for analog pins 0 through 5 and returns a value between 0 and1023.
  • string getString(): Returns the last string received.
  • int getDigitalPinMode(pin): Returns ARD_INPUT, ARD_OUTPUT, ARD_PWM, ARD_SERVO, or ARD_ANALOG.
  • int getAnalogPinReporting(pin). For analog pins 0 through 5, returns ARD_ON or ARD_OFF.

Expanding on the Idea

We now have openFrameworks controlling the Arduino, which is running the standard Firmata sketch. The next example illustrates the increase of efficiency that can be gained in development by having Arduino and openFrameworks integrated.

  1. Start the next example by attaching a servo to pin 10 and another LED to pin 3, in addition to the other components from the last example. Use Figure 3-5 for reference.
  2. After the two new components are in place, start the Firmata test app to check that all the components are working.
  3. Set the pins to the following configuration:
  • pin3 = PWM
  • pin8 = input
  • pin10 = servo
  • pin13 = output
  • Analog pin 0

9781430239390_Fig03-05.jpg

Figure 3-5 .  Arduino circuit for the “Expanding on the Idea” example

For the rest of this example, the only changes are going to be to the code.

For the hardware, the potentiometer is going to control the servo, while the brightness of the LED on pin 3 will represent the position of the servo. When the button is pressed, the LED on pin 13 will turn on; at the same time, the servo and the other LED will pause and stop accepting new values from the potentiometer until the button is released.

Changing Code

While openFrameworks is controlling the Arduino, it will simultaneously be displaying a representation of what the hardware is doing. The program will have a window the same size as the two prior examples, with shapes representing the button, the LED, and the potentiometer’s position. The only change to the graphics is that we will dynamically change the color of the bar to represent the new brightness value for the LED, with the color fading from black to full red with the servo and potentiometer’s full swing.

Open the project from Listings 3-5 and 3-6. The same main.cpp will be used without alteration. Within testapp.cpp, the entire mousePressed() function can be removed or commented out, along with its prototype in testapp.h. You can omit the following line from the arduinoLoop() function:

arduino.sendDigital(13, ledcommand);

The last thing to comment out is the variable declaration bool ledcommand; from testapp.h. With the code that is no longer needed out of the way, change the line ofSetColor(255,0,0);, located in the draw() function, to

ofSetColor((analogPin0*255),0,0);

This change takes advantage of the analog percent value to evenly change the color in proportion to the bar.

Add the following code to the arduinoSetup() function below the code line arduino.sendDigitalPinMode(13, ARD_OUTPUT); defining the new componets. Note that the text following the comment delimiters (//) is optional.


arduino.sendDigitalPinMode(3, ARD_PWM); // set pin 3 for PWM
arduino.sendDigitalPinMode(10, ARD_SERVO);// set pin 10 to accept a servo
arduino.sendServoAttach(10);// define servo information as default
isArduinoSet = true;

Listing 3-7 shows the next portion of code to add, which is the last for this example. The code handles the button pause, the servo, and the PWM LED, and gets inserted into the arduinoLoop() function before the ending bracket of the if (isArduinoSet) statement and after analogPin0 = arduino.getAnalog(0)/1023.0;.

Listing 3-7.  The End of “Expanding on the Idea” Example

  if (pin8 == ARD_HIGH){ // check if button is being pressed
    pin13 = true; // flag the draw function to change
    arduino.sendDigital(13, ARD_HIGH);// turn on LED
  } // end if pin8 == ARD_HIGH)
  else {
    arduino.sendDigital(13, ARD_LOW);
    arduino.sendPwm(3,analogPin0*255);
    arduino.sendServo(10, analogPin0*180);
  } // end else

Verifying the Code

With all the code changed and compiled, start the program with the Arduino plugged in. The program should look like Figure 3-6. When the screen is fully drawn, the pause button will have to be pressed to get the servo and the LED to activate.

9781430239390_Fig03-06.jpg

Figure 3-6 .  The look of the final example

The changes that were made make the Arduino act differently without your having to upload a new sketch. Note that the changes now allow the potentiometer to control the sweep of the servo and the brightness of the LED when the potentiometer is swept from maximum to minimum. Also take note of the behavior when the pause is held while the potentiometer is being moved.

More Ideas to Work With

openFrameworks has a lot more functionality than described in this chapter. openFrameworks can manipulate sound images or even 3D objects, and the connection to serial devices or Arduinos allows controllers to be built that can control the computer. You can create programs to control the Arduino as well. With all the possible projects that you can create using Arduinos, the extra features that openFrameworks provides may make it hard to decide where to go and what to do. Try out some of the ideas listed below; they came up during a few brainstorming sessions. These ideas should help further your exploration of openFrameworks while providing more experience with the platform.

  • Use a keypad to select a song from a playlist (i.e., make a jukebox).
  • Make a small game using an old hard drive motor for the input controls.
  • Create a logging system that records data to a database such as MySQL using Arduino and openFrameworks.
  • Build a dynamic scrolling LED marquee that also displays the characters being typed on the computer screen.
  • Create an RGB LED array to build a mood light that changes in response to audio or visual cues.

Summary

This chapter discussed the fundamental steps to integrate openFrameworks with Arduino. As a development tool, openFrameworks may provide the catalyst that can take a good idea to the next step. Its versatility is only increased by providing two great ways to develop: using serial or Firmata. With time and use, most developers will find a preference for one method over the other.

openFrameworks has a lot more functionality than can be covered here, but this chapter should provide you the knowledge and confidence to delve deeper into openFrameworks. Also check out other resources available; the forums at www.arduino.cc/ and www.openframeworks.cc/ are great places to find more information. The examples included with openFrameworks can also provide excellent insight.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset