Reading Serial Data from Arduino

I have a project that requires reading data from an Arduino and manipulating the playback of a video file in OpenFrameworks.

I have a rotary encoder on the Arduino that seems to be working properly when I look at the serial monitor through Arduino. I can dial it forward or backward and the number getting printed in the monitor responds the way I think is necessary. (My plan is to then use a function to map that number to the playback of the video)

My problem is that I have no idea how to get that number (it has a range of 0-60000 and starts in the middle) to be interpreted by OF. Any help would be greatly appreciated. Thanks!

Code in the Arduino:

  
  
#include <Boards.h>  
#include <Firmata.h>  
  
#define encoder0PinA  2  
#define encoder0PinB  4  
  
volatile unsigned int encoder0Pos = 0;  
  
void setup() {   
  
  
  pinMode(encoder0PinA, INPUT);   
  digitalWrite(encoder0PinA, HIGH);       // turn on pullup resistor  
  pinMode(encoder0PinB, INPUT);   
  digitalWrite(encoder0PinB, HIGH);       // turn on pullup resistor  
  
  attachInterrupt(0, doEncoder, CHANGE);  // encoder pin on interrupt 0 - pin 2  
  Serial.begin (9600);  
  Serial.println("start");                // a personal quirk  
    
  encoder0Pos = 30000;  
  
}   
  
void loop(){  
// do some stuff here - the joy of interrupts is that they take care of themselves  
}  
  
void doEncoder() {  
  if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {  
    encoder0Pos++;  
  } else {  
    encoder0Pos--;  
  }  
  
  Serial.println (encoder0Pos, DEC);  
}  
  
void doEncoder_Expanded(){  
  if (digitalRead(encoder0PinA) == HIGH) {   // found a low-to-high on channel A  
    if (digitalRead(encoder0PinB) == LOW) {  // check channel B to see which way  
                                             // encoder is turning  
      encoder0Pos = encoder0Pos - 1;         // CCW  
    }   
    else {  
      encoder0Pos = encoder0Pos + 1;         // CW  
    }  
  }  
  else                                        // found a high-to-low on channel A  
  {   
    if (digitalRead(encoder0PinB) == LOW) {   // check channel B to see which way  
                                              // encoder is turning    
      encoder0Pos = encoder0Pos + 1;          // CW  
    }   
    else {  
      encoder0Pos = encoder0Pos - 1;          // CCW  
    }  
  
  }  
  Serial.print(encoder0Pos);  
  Serial.write (encoder0Pos);  
}  
  

The OF Code:

  
  
#include "testApp.h"  
  
//--------------------------------------------------------------  
void testApp::setup(){  
  
    //I'm not sure what this does, but I've seen it alot so I'll include it  
    ofSetVerticalSync(true);  
      
    //Sets the color of BG  
    ofBackground(255, 255, 255);  
    //Don't know. Including it.  
    ofSetLogLevel(OF_LOG_NOTICE);  
      
    //--------  
    // Loading my own font here to double check things  
    font.loadFont("CODEbold.otf", 64);  
      
    //List all the Serial Devices  
    serial.listDevices();  
      
    //What does this do?  
    vector <ofSerialDeviceInfo> deviceList = serial.getDeviceList();  
      
      
    // Tells the computer which port to be listening to  
	serial.setup("/dev/cu.usbmodemfa131",9600);  
      
    memset(bytesReadString, 0, 6);  
      
      
}  
  
//--------------------------------------------------------------  
void testApp::update(){  
  
    if(bSendSerialMessage){  
        unsigned char bytesReturned[5];  
          
        memset(bytesReadString, 0, 6);  
        memset(bytesReturned, 0, 5);  
          
        memcpy(bytesReadString, bytesReturned, 5);  
          
          
        // I think this whole loop is to find the end of the string and stop listening  
        // Then when a new one starts in waits for it to finish  
        bSendSerialMessage = false;  
          
          
    }  
      
}  
  
  

Also, it seems like most of the code I have in the Arduino ought to be done by OF. I think it’d be a lot easier to just get the ‘encodePin’ stuff into OF right away and do all the processing in the program rather than Arduino…

if you add a DEC argument to Serial.print(), then you should be able to use ofToInt() to get an integer from the bytesReturned string.

i would use Serial.println(encoder0Pos, DEC) so that you can use the newline to distinguish between the encoder values.

and the extra Serial.write() is unnecessary, i think.

Thanks for the advice! I added that to the Arduino code and took out the extra serial.write line.

I also made the additions to the code in OF but there’s still no reaction.

  
  
#include "testApp.h"  
  
//--------------------------------------------------------------    
void testApp::setup(){    
       
    ofSetVerticalSync(true);    
    ofBackground(255, 255, 255);     
    ofSetLogLevel(OF_LOG_NOTICE);    
      
    //--------    
    font.loadFont("CODEbold.otf", 34);    
  
    serial.listDevices();    
       
    vector <ofSerialDeviceInfo> deviceList = serial.getDeviceList();    
      
      
    // Tells the computer which port to be listening to    
    serial.setup("/dev/cu.usbmodemfa131",9600);    
      
    memset(bytesReadString, 0, 6);    
      
      
}    
  
//--------------------------------------------------------------    
void testApp::update(){    
      
    if(bSendSerialMessage){    
        unsigned char bytesReturned[5];    
          
        memset(bytesReadString, 0, 6);    
        memset(bytesReturned, 0, 5);    
          
        memcpy(bytesReadString, bytesReturned, 5);    
          
          
            //----- Here's the new line  
            rotaryValue = ofToInt(bytesReadString);  
    
          
        bSendSerialMessage = false;    
          
          
    }    
      
}    
  
//--------------------------------------------------------------  
void testApp::draw(){  
  
    ofSetColor(0);  
    font.drawString("The Rotary Value is: " + rotaryValue, 50,100);  
      
}  
  

Couple thoughts:

You can’t read from the serial port unless you’ve checked that there’s something available by calling serial.available()

  
  
// is there anything in the serial port?  
if(serial.available()){      
        unsigned char bytesReturned[5];      
            
        memset(bytesReadString, 0, 6);      
        memset(bytesReturned, 0, 5);  
  
        // read from the serial port  
        serial.readBytes(bytesReturned, 5);  
            
        memcpy(bytesReadString, bytesReturned, 5); // not sure what this is for     
  
        string serialData = bytesReturned; // if you want a string, do this  
        //----- Here's the new line    
        rotaryValue = ofToInt(bytesReadString);   
  

also, you usually don’t want the cu address but the tty address:

  
/dev/tty.usbmodemfa131  

Hope that helps.

On line 12 it’s giving me an error:
“No viable conversion from ‘unsigned char [5]’ to ‘string’ (aka ‘basic_string’)”

I thought the CU and TTY were just different USB ports?

  
  
void testApp::update(){    
      
    if(serial.available()){        
        unsigned char bytesReturned[5];        
          
        memset(bytesReadString, 0, 6);        
        memset(bytesReturned, 0, 5);    
          
        // read from the serial port    
        serial.readBytes(bytesReturned, 5);    
          
        string serialData = bytesReturned; // if you want a string, do this    
        //----- Here's the new line      
        rotaryValue = ofToInt(bytesReadString);    
      
      
    if(bSendSerialMessage){    
        unsigned char bytesReturned[5];    
          
        memset(bytesReadString, 0, 6);    
        memset(bytesReturned, 0, 5);    
          
        memcpy(bytesReadString, bytesReturned, 5);    
          
          
            //----- Here's the new line  
            rotaryValue = ofToInt(bytesReadString);  
    
          
        bSendSerialMessage = false;    
          
          
    }    
      
    }    
}  
  

Ah, I didn’t realize that was unsigned char. Then it should just be:

  
void testApp::update(){      
        
    if(serial.available()){          
        unsigned char bytesReturned[5];          
            
        memset(bytesReadString, 0, 6);          
        memset(bytesReturned, 0, 5);      
            
        // read from the serial port      
        serial.readBytes(bytesReturned, 5);      
            
        string serialData = (char*) bytesReturned; // cast to char  
    
        rotaryValue = ofToInt(serialData);      
        
    }      
}    

You don’t need the rest of that method, it’s not doing anything.

You might be able to get it to work using the cu, but generally tty works better with the Arduino because you want the Arduino to be forced to hardware handshake. There’s more info on this here: http://stuffthingsandjunk.blogspot.com/2009/03/devcu-vs-devtty-osx-serial-ports.html

1 Like

After much help from some of the great faculty at Parsons I have the rotary encoder working with oF. For the sake of posterity I thought I’d post what we came up with.

Arduino:

  
  
void loop(){    
// if we get a valid byte  
 if (Serial.available() > 0) {  
    // get incoming byte:  
  Serial.print(encoder0Pos);    
 // Serial.println();  
  Serial.flush();  
  }  
  

oF:

  
  
void testApp::update(){    
      
    //This gets sent to arduino, calling for a new set of readings  
    serial.writeByte('a');  
      
    if(serial.available()){        
        unsigned char bytesReturned[3];        
          
        memset(bytesReadString, 0, 3);        
        memset(bytesReturned, 0, 4);    
      
        // This reads the data now that arduino is sending a response,     
        serial.readBytes(bytesReturned, 4);    
        string serialData = (char*) bytesReturned;          
        rotaryValue = ofToInt(serialData);    
          
        //This was allows for the whole process to repeat without  
        // getting strange overlapping readings from the encoder:  
        serial.flush();  
           
    }    
}   
  

The rest of the Arduino and oF code remained the same. Right now I have the encoder making a rect grow or shrink and the results are pretty consistently accurate. If you keep twisting it very fast or very slow there are some occasional hiccups, but I think its working well enough for my purposes.

Huge thanks to Zach, Joe, Katherine, Sven and the oF forum for helping me with all this! If anyone is trying this and running into problems feel free to contact me.

3 Likes

Hi there,

I tried as suggested above and could manage to work without Serial.available() > 0 in Arduino.
But if I include this, Arduino doesn’t seem to receive any bytes despite the fact I’m sending them successfully in serial.writeByte(‘1’) inside ofApp::update().

I felt Serial.available() > 0 is kind of influenced by the interrupt.
Without this, there’s so many noises so it’s unusable.

Any ideas please?

Have you tried ofxSerial? It has flow control, and you can set timeouts, use buffers, etc.

1 Like

Super helpful, thanks !