Start

This will be a general-purpose log for 'projects' I will do. Part of the reason for making something like this is so that I'll be able to document progress on the way; another reason is so that, hopefully, the need to post and update will provide an additional incentive...

Posted by provolot on May 19, 2007 10:17 PM | | Comments (0) | TrackBacks (0)


toys

toys.

solder_torch.jpg
Butane-powered soldering torch, $20 from radioshack.

solder_torch_on.jpg
Also a blowtorch, as can see here. Creme brulee?

arduino_gps.jpg
Arduino NG (usb) board and GPS EM-406. Soon to interact.

Posted by provolot on May 20, 2007 1:35 PM | | Comments (0) | TrackBacks (0)


simple led stuff.

Based on the tutorials off the arduino website, some simple exercises. I don't have a breadboard or any wires on me right now, so anything more complicated is off-limits until I go to radioshack or order from digikey or whatnot.

Simple blinking LED, done with a simple delay statement.


Pulse Width Modulation dimming of two LEDs.
This didn't work until I realized that there are separate PWM input/outputs. Pins 3, 5, 6, 9, 10, 11 are able to do PWM as well as receive analog input. Interestingly, the Arduino website only states 9, 10, and 11 as PWM pins...

Posted by provolot on May 20, 2007 2:43 PM | | Comments (0) | TrackBacks (0)


Bidirectional led sensing

A while back I was reading about bidirectional led sensing. Basically, the idea is that you light the LED, and then switch the potential across it, setting the anode to low, and the cathode to high. Since it's a diode, the LED pulls the cathode low. Apparently, the time it takes for the cathode to fall low is dependent on the amount of ambient light -- if we measure that time, then we have a rudimentary sensor.

I tried coding it, and no matter what, it didn't work. I came across a Benoit Rousseau's post on the arduino forum about this. It turns out that there are pullup resistors built-into the Atmega168, and I believe this means that it'll interfere by pulling the cathode high, while sensing with the cathode...? I may be wrong. Anyhow, the solution is to disable those pull-up resistors with the code:

  _SFR_IO8(0x35) |= 4;
  _SFR_IO8(0x35) |= (1<<4); 

The final code was:

/* LED sensor -- photodiode.
*/

int anodePin = 2;
int cathodePin = 8;

int wait = 10;

int value;

void setup()
{

  //deactivates pullup resistors?
  _SFR_IO8(0x35) |= 4;
  _SFR_IO8(0x35) |= (1<<4); 

  pinMode(anodePin,   OUTPUT);      // sets the digital pin as output
  pinMode(cathodePin, OUTPUT);      // sets the digital pin as output
  
  Serial.begin(9600);
}

void loop()
{
  value = 0;
  
  //emit light
  digitalWrite(anodePin,   HIGH);
  digitalWrite(cathodePin, LOW);
  delay(50);
  
  //switch potentials -- charge LED to -5V
  digitalWrite(anodePin,   LOW);
  digitalWrite(cathodePin, HIGH);
  
  //measure time for potential to equalize (for cathode to be LOW)
  
  //switch pinmode 
  pinMode(cathodePin,  INPUT);
  
  //measure time it takes for cathodePin to go to zero
  //this value probably depends on the chip clock or something
  while(digitalRead(cathodePin) != 0)
    value++;
  pinMode(cathodePin,  OUTPUT);
  
  digitalWrite(anodePin,   HIGH);
  digitalWrite(cathodePin, LOW);
  Serial.println(value, DEC);
}

Success! I also added code later to light a separate LED when the time for the LED sensor's cathode to drop to low would be higher than a certain threshold:

Posted by provolot on May 20, 2007 3:13 PM | | Comments (3) | TrackBacks (0)


Bidirectional led sensing + Processing visualization

I wanted to combine the Arduino's led sensing capabilities with Processing. It's simpler than I thought.

Arduino can send serial signals back to the computer over USB, at 9600 baud. The arduino sends the value of the time it takes for the cathode of the sensor LED to fall. (What this 'value' is based on I'm not sure -- as seen in the post before, it's measured by a while loop that increments a counter with no delay. It probably depends on the clock of the chip or something like that.) We can send said values with Serial.print().

Processing has libraries for serial input that are built-in. Serial() is a constructor for a Serial class that initializes a serial connection, read() reads a value, et cetera. By checking whether or not the serial connection is available, then reading input, we can get the value of the input.

I whipped something up that takes the values of the input and stores them in an ArrayList, deleting the oldest value, and adding the newest one. This way, deleting elements and adding them are constant-time. The bars representing the older values are darker, while the newer values are lighter, and for the sake of being pretty, I mirrored everything.

Here's the Processing code.


And here's what it looks like:

My hand is unnaturally yellow, and that isn't James Brown in the background but Justice.

Posted by provolot on May 20, 2007 3:47 PM | | Comments (0) | TrackBacks (0)


more stuff purchased

spools_breadboard.jpg
Time to start interfacing the EM406 and the Arduino with serial...

Posted by provolot on May 20, 2007 6:02 PM | | Comments (0) | TrackBacks (0)


things connected, not working.

before_after_gpsconnector.jpg
before:wires stripped after: soldered to 22 guage wire, then wrapped around with scotch tape. I don't have electrical tape or shrink tubing on me now, nor the automotive operational skills to get any...

gps_breadboard.jpg
connector and arduino plugged into the breadboard.

Things aren't working! I tried connecting the GPS module to the connector. The red led lit up, then after a while started blinking, which according to the datasheet means that the position is fixed. Yay! That's great.

As for communicating with the EM406 chip via serial, it's not working. The arduino is supposed to communicate through serial, at 4800 baud, but I can't find the protocol online to request data. I swear that I found a series of timing diagrams on a pdf somewhere with the signals that have to go to rx and tx pins, but I can't find it now.

Benedetta Simeonidis was also working on interfacing the Arduino and the EM406. She seems to have got it working, but her code doesn't work for me. I tried my own code, which doesn't work either. Here's the code anyways.



#define rxPin 7
#define txPin 8
#define ledPin 13

#define bit4800Delay 188 
#define halfBit4800Delay 94 
//definitions for 4800 baud communication

byte val;
boolean ledPinOn;

void setup()  {
  // define pin modes for tx, rx, led pins:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  digitalWrite(txPin,  HIGH); //set transmit pin to high
  digitalWrite(ledPin,  HIGH); //turn on debug led  
  ledPinOn = true;
  
  // set the data rate for the SoftwareSerial port
  Serial.begin(4800); //4800 is the baud rate for EM306
}

int SWread()
{
  byte val = 0;
  Serial.println("waiting for start bit");
  
  while (digitalRead(rxPin))
  {
    Serial.println(digitalRead(rxPin), BIN);
  }
  //wait for start bit
  
  Serial.println("done waiting");
  
  
  if (digitalRead(rxPin) == LOW) {
    
    Serial.println("rxPin is low");
    
    delayMicroseconds(halfBit4800Delay);
    for (int offset = 0; offset < 8; offset++) {
     delayMicroseconds(bit4800Delay);
     val |= digitalRead(rxPin) << offset; 
     //iterate through bit mask.
     //Or, in other words, each bit is sent after a bit4800delay,
     //from MSB to LSB. get the first most significant bit, shift it left, etc.
    }
    //wait for stop bit + extra
    delayMicroseconds(bit4800Delay); 
    delayMicroseconds(bit4800Delay);
    Serial.println("got data");
    return val;
  }
  Serial.println("rxPin is not low");
}

void loop() {
  Serial.println("started loop");
  Serial.print(SWread(), BYTE); 
  if(ledPinOn == true) ledPinOn = false;
  else ledPinOn = true;
  digitalWrite(ledPin,  ledPinOn);
 
  // toggle an LED just so you see the thing's alive.  
  // this LED will go on with every OTHER character received:
  

}

The point at which things get stuck is at

  while (digitalRead(rxPin));
  //wait for start bit
where the protocol for communicating with the GPS chip seems to involve waiting for the receiving rx pin to be low briefly, then to initiate data input. This seems strange.

Where can I find that datasheet??


update: it works.

Posted by provolot on May 21, 2007 1:56 AM | | Comments (2) | TrackBacks (0)


WORKS!1

holy smokes, it works! GPS EM-406 to Arduino:



#define rxPin 7
#define txPin 8
#define ledPin 13

#define bit4800Delay 188 
#define halfBit4800Delay 94 
//definitions for 4800 baud communication

byte val;
boolean ledPinOn;

void setup()  {
  // define pin modes for tx, rx, led pins:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  digitalWrite(txPin,  HIGH); //set transmit pin to high
  digitalWrite(ledPin,  HIGH); //turn on debug led  
  ledPinOn = true;
  
  // set the data rate for the SoftwareSerial port
  Serial.begin(4800); //4800 is the baud rate for EM306
}

int SWread()
{
  byte val = 0;
  
  while (digitalRead(rxPin));
  //wait for start bit
  
  
  if (digitalRead(rxPin) == LOW) {
    
    
    delayMicroseconds(halfBit4800Delay);
    for (int offset = 0; offset < 8; offset++) {
     delayMicroseconds(bit4800Delay);
     val |= digitalRead(rxPin) << offset; 
     //iterate through bit mask.
     //Or, in other words, each bit is sent after a bit4800delay,
     //from MSB to LSB. get the first most significant bit, shift it left, etc.
    }
    //wait for stop bit + extra
    delayMicroseconds(bit4800Delay); 
    delayMicroseconds(bit4800Delay);
    return val;
  }

}

void loop() {
  Serial.print(SWread(), BYTE); 
  if(ledPinOn == true) ledPinOn = false;
  else ledPinOn = true;
  digitalWrite(ledPin,  ledPinOn);
 
  // toggle an LED just so you see the thing's alive.  
  // this LED will go on with every OTHER character received:
  

}

output (but with no spaces between commas):
$GPGGA,062032.000,3922.1678,N,07640.0290,W,1,06,1.5,132.3,M,-33.6,M,,0000*6D $GPGSA,A,3,28,11,17,08,27,19,,,,,,,2.4,1.5,1.9*31 $GPRMC,062032.000,A,3922.1678,N,07640.0290,W,0.16,134.81,210507,,*11 $GPGGA,062033.000,3922.1678,N,07640.0290,W,1,06,1.5,132.3,M,-33.6,M,,0000*6C $GPGSA,A,3,28,11,17,08,27,19,,,,,,,2.4,1.5,1.9*31 $GPGSV,3,1,09,28,70,332,41,11,57,067,43,08,49,205,38,17,43,269,26*7D $GPGSV,3,2,09,27,29,187,29,20,14,122,,19,09,063,24,26,05,289,*7C $GPGSV,3,3,09,29,04,281,*44 $GPRMC,062033.000,A,3922.1678,N,07640.0290,W,0.18,139.48,210507,,*16

Now, to parse the $GPRMC -- the recommended minimum specific gnss data...

Posted by provolot on May 21, 2007 2:21 AM | | Comments (0) | TrackBacks (0)


GPS logging parsing

Okay, this code parses the data for a proper message, then gets only the lines starting with that message. This was relatively messy, especially in C/C++. Note that the function filterForMessage doesn't pass a value really, but instead just modifies a global variable. I tried messing with pointers, but I don't think Arduino's code can handle them.



#define rxPin 7
#define txPin 8
#define ledPin 13

//definitions for 4800 baud communication
#define bit4800Delay 188 
#define halfBit4800Delay 94 

//The type of message we want. Edit this for other forms of GPS data.
char wantedMessage[7] = "$GPRMC";

// thisMessage is a global variable -- I didn't want to deal with returning
// strings, as properly object-oriented it would be. 
char thisMessage[100];
boolean ledPinOn;

void setup()  {
  // define pin modes for tx, rx, led pins:
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  digitalWrite(txPin,  HIGH); //set transmit pin to high
  digitalWrite(ledPin,  HIGH); //turn on debug led  
  ledPinOn = true;
  
  // set the data rate for the SoftwareSerial port
  Serial.begin(4800); //4800 is the baud rate for EM306
}

int SWread()
{
  byte val = 0;
  
  while (digitalRead(rxPin));
  //wait for start bit
  
  
  if (digitalRead(rxPin) == LOW) {  
  //okay, so now that it's low
    delayMicroseconds(halfBit4800Delay);
    //wait for a tiny bit, then get data
    for (int offset = 0; offset < 8; offset++) {
     //iterate through bit mask.
     //Or, in other words, each bit is sent after a bit4800delay,
     //from MSB to LSB. get the first most significant bit, shift it left, etc.
     delayMicroseconds(bit4800Delay);
     val |= digitalRead(rxPin) << offset; 
    }
    //wait for stop bit + extra
    delayMicroseconds(bit4800Delay); 
    delayMicroseconds(bit4800Delay);
    return val;
  }

}

boolean filterForMessage()
{
  int tempVal;
  int counter;
  char tempString[100]; //max string length is 100.
  
  tempVal = SWread(); //convert byte from GPS to character
  if(tempVal == '$') //if byte is a start of a new line 
  {
    counter = 1;
    tempString[0] = '$'; //add the dollar sign
    
    //while we're reading input, and the input isn't a newline (10 is ascii newline)
    while((tempVal = SWread()) && (tempVal != 10)) {
      tempString[counter++] = tempVal; //add current character to temporary string
    }
    tempString[counter] = '\0'; //end string with null char
    
    //now, do we want this line? let's compare the first 6 chars with wantedMessage.
    if(strncmp(wantedMessage, tempString, 6) == 0) {
      //if we do want this line, then copy the message into the global variable
      //so we can 'pass' it to the callee of this function.
      strcpy(thisMessage, tempString); 
      return true;
    }
    else
      return false;
     
  }
 
}
        
      
void loop() {
  
  //if our message matches our wanted message, print it out!
  if(filterForMessage() == true) {
    Serial.println(thisMessage); 
  
    // toggle an LED so that we can see that it's working
    // the LED will go on with every other proper message match
    if(ledPinOn == true) ledPinOn = false;
    else ledPinOn = true;
    digitalWrite(ledPin,  ledPinOn);
  }

}

So, let's look at the data. An example line:
$GPRMC,083739.000,A,3922.17xx,N,07640.02xx,W,0.38,32.39,210507,,*26
Clearly I'm not here right now or anything.

The reference manual for the NMEA standard details the RMC format in page 16. This page has it as well.

A bit of data parsing in Processing led to this code. String manipulation in Java is more awkward than I remembered -- I can't seem to be able to use 'split' well.

 boolean parseRMCData(String raw) {
    
    Date tempDate;
    
    String [] values = raw.split(","); //split values around comma
    
    if(values[2].equals("V")) return false; //status is invalid!
    
    
    //convert values into date. GAH! there should be a better way,
    //but split wasn't working properly.
    int h; int m; int s; int y; int mon; int d;
    h = parseInt(values[1].substring(0, 2));
    m = parseInt(values[1].substring(2, 4));
    s = parseInt(values[1].substring(4, 6));
    d = parseInt(values[9].substring(0, 2));
    mon = parseInt(values[9].substring(2, 4));
    y = parseInt(values[9].substring(4, 6)) + 100;
    
    timeDate = new Date(y, mon, d, h, m, s);
    //100 + y is done because y is two-digits, and the Date class
    //automatically adds 1900 to the year value. Adding 100 corrects this all.
    
   
    //// CONFUSING TIMEZONE CONVERSION COMING RIGHT UP
    
    // configure a SimpleDateFormat to recognize our certain format
    SimpleDateFormat sdf = new SimpleDateFormat("y M d H m s");
    
    // configure a time zone that is EST and with dst built in.
    
    // Base GMT offset: -5:00
    // DST starts:      at 2:00am in standard time
    //                  on the second Sunday in March
    // DST ends:        at 2:00am in daylight time
    //                  on the first Sunday in November
    // Save:            1 hour
    SimpleTimeZone stz = new SimpleTimeZone(-18000000,
                              "EST",
                              Calendar.MARCH, 2, -Calendar.SUNDAY,
                              7200000,
                              Calendar.NOVEMBER, 1, -Calendar.SUNDAY,
                              7200000,
                              3600000);
    
    // configure our SimpleDateFormat to recieve GMT input
    sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
    
    // make our SimpleDateFormat parse our date as GMT
    try {
      tempDate = sdf.parse(y + " " + mon + " " + d + " " + h + " " + m + " " + s);
    }
    catch (Exception e) {
      tempDate = new Date();
    }
    
    // convert SimpleDateFormat to EST with EDT
    sdf.setTimeZone(stz);
    
    // change display pattern of our format 
    sdf.applyPattern("E M/W/y H:m:s z");
    
    // convert the date to EST with EDT, and in our certain pattern
   print(sdf.format(tempDate));

   print("  |  Lat : " + values[3] + values[4] + "  |  Long : " + values[5] + values[6]);
   
   float  vel = Float.parseFloat(values[7]) * 1.852;
   println("  |  Velocity : " + vel + " km/h in the direction " + values[8] + " degrees from north");
  
   return true; //status is valid, of course
    
  }

Posted by provolot on May 21, 2007 3:51 AM | | Comments (0) | TrackBacks (0)