Modifying code from Networked Lamp example

My sister and I are trying to modify the code from the Networked Lamp in the Getting Started book. Instead of sending a string like "#aa3b78" from Processing which is then picked apart by Arduino, we're sending a string like "#075" which we then pick apart. We can verify that we're sending that string from Processing to the Serial port.

We're confused about how Arduino is receiving the information from the Serial port. In the original example, it looks for the marker (#) and then gets the next six characters. First, we tried sending an integer without the marker, then the integer with the marker, then we converted it to a string, figuring maybe that's the form Arduino was looking for.

As it stands, first we make sure its enough characters - so the return string is in the form of "#---" So, if its only two characters, we insert an extra zero at the start, such as "#0--" If its negative, we set it to zero: "#000" This is so we can break it apart by characters, and remake it into an integer in Arduino. (First character multiplied by 100 + next multiplied by 10 + last character) No matter what, the number we send from Processing does not come out as we expect it to from Arduino.

We've been troubleshooting what number it's sending by turning on an LED. The RX/TX lights are blinking and we have gotten the LED to turn on, but when that happened it was a negative number (and it shouldn't have been). Between the two of us one knows Arduino moderately and the other knows Java, PHP, ASP.NET, etc. and we're fumbling through Processing.

Our questions would be what form is Arduino expecting to read from the Serial port - is it expecting a byte translation of a integer? Or what? Also, as we've been staring at this forever, do you spot any other errors?

Arduino sketch (it's a bit messy...):

// Example 08B: Arduino Networked Lamp
//
// Copy and paste this example into an empty Arduino sketch

//#define SENSOR 0   
#define R_LED 13
//#define G_LED 10
//#define B_LED 11
//#define BUTTON 12

//int val = 0; // variable to store the value coming from the sensor

//int btn = LOW;
//int old_btn = LOW;
//int state = 0;
char buffer[4] ;
int pointer = 0;
byte inByte = 0;
int val = 0;

//byte r = 0;
//byte g = 0;
//byte b = 0;

void setup() {
  Serial.begin(9600);  // open the serial port
  //pinMode(BUTTON, INPUT);
  pinMode(R_LED, OUTPUT);
}

void loop() {
  //val2 = digitalRead(6); // read the value from the sensor
  //Serial.println(val2);      // print the value to
                            // the serial port

  if (Serial.available() >0) {

    // read the incoming byte:
    inByte = Serial.read();

    // If the marker's found, next 6 characters are the colour
    if (inByte == '#') {

      while (pointer < 4) { // accumulate 6 chars
        buffer[pointer] = Serial.read(); // store in the buffer
        pointer++; // move the pointer forward by 1
      }
 {
//val = int(inByte);
      val = (int(buffer[0])*100) + (int(buffer[1])*10) + (int(buffer[2]));
         Serial.println(val);
         
      // now we have the 3 numbers stored as hex numbers
      // we need to decode them into 3 bytes r, g and b
      //r = hex2dec(buffer[1]) + hex2dec(buffer[0]) * 16;
      //g = hex2dec(buffer[3]) + hex2dec(buffer[2]) * 16;
      //b = hex2dec(buffer[5]) + hex2dec(buffer[4]) * 16;
      
      pointer = 0; // reset the pointer so we can reuse the buffer
      
    }
  }   

  //btn = digitalRead(BUTTON); // read input value and store it

  // Check if there was a transition
  //if ((btn == HIGH) && (old_btn == LOW)){
  //  state = 1 - state;
  

  //old_btn = btn; // val is now old, let's store it

  //if (state == 1) { // if the lamp is on
{
 if(val <= 1) {
   analogWrite(R_LED, HIGH);  // turn the leds on
   /*delay(100);
   analogWrite(R_LED, LOW);
   delay(100);
   analogWrite(R_LED, HIGH);  // turn the leds on
   delay(100);
   analogWrite(R_LED, LOW);*/
   
 }
  /* 
   if(val > 401 &&  val < 700) {
     analogWrite(R_LED, HIGH);  // turn the leds on
     delay(200);
     analogWrite(R_LED, LOW);
   }
   if(val > 701) {
     analogWrite(R_LED, HIGH);  // turn the leds on
     delay(300);
     analogWrite(R_LED, LOW);
   }
   if(val < 100) {
     analogWrite(R_LED, LOW);
   }
   
    
   // analogWrite(G_LED, g);  // at the colour
   // analogWrite(B_LED, b);  // sent by the computer
 // } else {

    //analogWrite(R_LED, 0);  // otherwise turn off
    //analogWrite(G_LED, 0); 
    //analogWrite(B_LED, 0);
   //}
 */
  delay(100);                // wait 100ms between each send
  }
 }  
}

I'll post the whole processing sketch in a reply, but here is the portion where we manipulate the string we're sending to the serial port:

llstr = Integer.toString(water); // Prepare a string to be sent to Arduino
  if (llstr.length() == 3) {
    ll = "#" + llstr;}
  if (llstr.length() == 2 ){
    ll = "#0" + llstr;}
  if (llstr.length() == 1) {
    ll = "#00" + llstr;}
    
  if (abs(water) != water) {
    water = 0;}
    println(ll);

We're running Arduino-0017 and Processing1.0.7 on Windows XP SP2 with an Arduino Duemilanove.

The Processing sketch:

// Now editing for lake level, attempt 1

//Code modified from Arduino networked lamp in Getting Started
//with Arduino

import processing.serial.*;

String feed = "http://www2.mvr.usace.army.mil/WaterControl/stationinfo2.cfm?sid=85625&fid=&dt=S";

int interval = 600;  // retrieve feed every 60 minutes?;
int lastTime;       // the last time we fetched the content

int water    = 0;


//int light = 0;  // light level measured by the lamp

Serial port;
color c;
//String cs;
String ll = "";
String llstr = "";

String buffer = ""; // Accumulates characters coming from Arduino

PFont font;

void setup() {
  size(1055,480);
  frameRate(10);    // we don't need fast updates

  font = loadFont("LucidaBright-32.vlw");
  fill(255);
  textFont(font, 24);
  // IMPORTANT NOTE:
  // The first serial port retrieved by Serial.list()
  // should be your Arduino. If not, uncomment the next
  // line by deleting the // before it, and re-run the
  // sketch to see a list of serial ports. Then, change
  // the 0 in between [ and ] to the number of the port
  // that your Arduino is connected to.
  //println(Serial.list());
  String arduinoPort = Serial.list()[0];
  port = new Serial(this, arduinoPort, 9600); // connect to Arduino

  lastTime = 0;
  fetchData();
}

void draw() {
  background( c );
  int n = (interval - ((millis()-lastTime)/1000));

  // Build a colour based on the 3 values
  //c = color(peace, love, arduino);
  llstr = Integer.toString(water); // Prepare a string to be sent to Arduino
  if (llstr.length() == 3) {
    ll = "#" + llstr;}
  if (llstr.length() == 2 ){
    ll = "#0" + llstr;}
  if (llstr.length() == 1) {
    ll = "#00" + llstr;}
    
  if (abs(water) != water) {
    water = 0;}
    println(ll);
  

  text("Lake Ponchartrain Water Level", 10,40);
  text("Reading feed:", 10, 100);
  text(feed, 10, 140);

  text("Next update in "+ n + " seconds",10,450);
  text("Latest Stage" ,10,200);
  text(" " + water, 190, 200);
  rect(200,172, water, 28);

  // write the colour string to the screen
  text("sending", 10, 340);
  text(water, 200,340);

  //text("light level", 10, 380);
  //rect(200, 352,light/10.23,28); // this turns 1023 into 100

  if (n <= 0) {
    fetchData();
    lastTime = millis();
  }

  
  port.write(ll); // send data to Arduino
  delay(5000);
  if (port.available() > 0) { // check if there is data waiting
    int inByte = port.read(); // read one byte
    if (inByte != 10) { // if byte is not newline
      buffer = buffer + char(inByte); // just add it to the buffer
    }
        else {

     // newline reached, let's process the data
      if (buffer.length() > 1) { // make sure there is enough data

        // chop off the last character, it's a carriage return
        // (a carriage return is the character at the end of a
       // line of text)
       buffer = buffer.substring(0,buffer.length() -1);

       // turn the buffer from string into an integer number
        //light = int(buffer);

       // clean the buffer for the next read cycle
        buffer = "";

        // We're likely falling behind in taking readings
        // from Arduino. So let's clear the backlog of
        // incoming sensor readings so the next reading is
       // up-to-date.
        port.clear();
     }
    }
  } 

}

void fetchData() {
  // we use these strings to parse the feed
  String data;
  String chunk;

  // zero the counters
  water    = 0;
 // peace   = 0;
  //arduino = 0;
  try {
    URL url = new URL(feed);  // An object to represent the URL
    // prepare a connection 
    URLConnection conn = url.openConnection();
    conn.connect(); // now connect to the Website

    // this is a bit of virtual plumbing as we connect
    // the data coming from the connection to a buffered
    // reader that reads the data one line at a time.
    BufferedReader in = new
      BufferedReader(new InputStreamReader(conn.getInputStream()));

    // read each line from the feed
    while ((data = in.readLine()) != null) {

      StringTokenizer st =
        new StringTokenizer(data,">");// break it down just at >
      while (st.hasMoreTokens()) {
        // each chunk of data is made lowercase
        chunk= st.nextToken().toLowerCase() ;

        //if (chunk.indexOf("latest") >= 0 ) // found "Latest Stage"?
        //water++;    // increment love by 1
      
       if (chunk.indexOf("latest&nbsp;stage") >= 0) //if we've found the "latest stage" part
       {
         String number = "0";
         //then we need to go forward four ">" according to the HTML code to get to the chunk
         //with the number for feet of the current stage
         for (int i=0; i < 4; i++)
         {
           number = st.nextToken();
         }
         //we'll get back something like 1.48 Ft.</font... so we need the first 5 characters to just get the number
         number = number.substring(0,5);
         //now we'll convert it to a float, then an integer
         int thenumber = int(Float.parseFloat(number)*100);
         println(thenumber);
         water = thenumber;
        
       }
      }
    }

    /* Set 64 to be the maximum number of references we care about.
    if (peace > 64)   peace = 64;
    if (love > 64)    love = 64;
    if (arduino > 64) arduino = 64;*/

   // water = water * 4;     // multiply by 4 so that the max is 255,
  
  }
  catch (Exception ex) { // If there was an error, stop the sketch
    ex.printStackTrace();
    System.out.println("ERROR: "+ex.getMessage());
  }

}

Thanks for taking a look!

After reading each byte (character) on the Arduino, use Serial.print (or println) to print it out, using no qualifier and using the DEC qualifier:

Serial.print("Read character: ");
Serial.println(inByte);

Serial.print("Dec value: ");
Serial.println(inByte, DEC);

I think you will be able to see what you need to change to make it work.

If not, post the output.

Hey PaulS,

Thanks for your speedy reply. Should these results appear in the serial monitor? The problem we were running into before is that we cannot open the serial monitor while the Processing sketch is talking to Arduino because that port is already in use. If I quit the Processing sketch Arduino doesn't store the value from what I can tell. I am still quite new to all of this, though, and would not be surprised if I am missing something.

Thank you again!

That's a problem, then. Not that it matters. I see what's wrong. The processing program is writing 4 characters - for example: '#', '3', '6', '8'.

The Arduino is receiving the characters, and storing them in a character array. You are then treating the characters as numbers, and expecting that the number and the character are the same. They are not. The character is an ASCII value - '0' is ASCII code 48. So, then the processing program sends a '0', the Arduino receives a 48. Before using the character as an int, you need to convert it to a number, by subtracting 48 (or '0') from it. Subtracting '0', rather than 48, makes it clear(er) what you are doing.

Okay, here is what we modified on the Arduino code in void(loop):

char hundreds = buffer[0] - '0';
      char tens = buffer[1] - '0';
      char ones = buffer[2] - '0';
      val = (int(hundreds)*100) + (int(tens)*10) + (int(ones));
         Serial.println(val);

Based on the what Processing is sending (#000), we tested for (val == 0) but didn't get the LED to turn on.

Thanks again! Sorry if we are being dense - our brains are fried! :-/

hundreds, tens, and ones should be declared as ints, not chars. Then, there is no need to convert them to int in the val statement:

int hundreds = buffer[0] - '0';
int tens = buffer[1] - '0';
int ones = buffer[2] - '0';
val = hundreds*100 + tens*10 + ones;

Thank you, PaulS! We made your changes without any effect, so started to delve further into our code. We checked to see if it was finding the marker (#) by turning an LED on, and it doesn't appear that it is! We have more work to do.

We are baffled, as we worked on this a week ago and got some sort of response. Though we've been trying to take notes, neither of us can remember if that was before or after we added the marker.

In any case, it seems like it is either not transmitting or resetting or something. If you have any clues, let us know!

We really appreciate your help - we feel like we owe you cookies or something!

We checked to see if it was finding the marker (#) by turning an LED on, and it doesn't appear that it is

Please post that code.

Okay, well, I re-modified the Arduino code from the original source, and now the marker is being found. Here is the cleaned up code:

// Lake Level Indicator, code edited from the Arduino Networked Lamp

#define LED 13   

int val = 0; // variable to store the value coming from processing 
char buffer[4] ;
int pointer = 0;
byte inByte = 0;


void setup() {
  Serial.begin(9600);  // open the serial port
  pinMode(LED, OUTPUT);
}

void loop() {
  //val = analogRead(SENSOR); // read the value from the sensor
  //Serial.println(val);      // print the value to
                            // the serial port

  if (Serial.available() >0) {

    // read the incoming byte:
    inByte = Serial.read();

    // If the marker's found, next 3 characters are the lake level
    if (inByte == '#') {
      digitalWrite(LED, HIGH);
      while (pointer < 3) { // accumulate 3 chars
        buffer[pointer] = Serial.read(); // store in the buffer
        pointer++; // move the pointer forward by 1
      }
   {
     val = (int(buffer[0])*100) + (int(buffer[1])*10) + (int(buffer[2]));
     Serial.println(val);
      
      pointer = 0; // reset the pointer so we can reuse the buffer
     
    }
  }   

    if(val > 0) {
    //if(val > 101 && val < 400) {
      digitalWrite(LED, HIGH);
      delay (1000);
      diWrite(LED, LOW);
      delay(1000);
    }
 
  delay(100);                // wait 100ms between each send
  }


}

The Processing sketch is still the same, though. We still aren't getting the correct number through, but at least now we know something is getting through. We are going to work through the Processing sketch again.

Okay, disregard that last post because it did not include the changes that PaulS suggested previously. Upon adding that in, it works!

Thank you so much for your help! I'll try to post pictures of the project soon!