Modified Sonar code with the addition of the Modern Devices LCD117

Here’s the new sonar code with temp compensation and the addition of the Modern Devices LCD117. All of the references to the LCD library (#include <LiquidCrystal.h>) are gone and the “SoftwareSerial” header file is referenced instead (#include <SoftwareSerial.h>).

Additionally, notice I had to add a function to display floating point numbers. I visited Peter H. Anderson’s site for directions to display floating point numbers on the LCD117. (Peter is the designer of the LCD117).

http://phanderson.com/arduino/arduino_display.html

Note: I’ll likely take temperature compensation out to save memory when we move the code to the rover. I don’t think it’s really necessary for object avoidance in a fast moving robot. However, it was beneficial for the grandson to learn how temperature affects the speed of sound in air.

——————————————————————————-

// Sonar with temp compensated ping and addtiion of LCD117

// Jim Winburn > http://www.apphipania.com

#include <SoftwareSerial.h>

//constants

#define rxPin 4 // rxPin is immaterial – not used

#define txPin 14 // pin 14 is analog pin 0, use a 3 wire servo cable :) , see Reference pinMode

SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);

const float sensor_gap =0.2;

const int pingPin = 7; //ping sensor

const int tempPin = 1; //TMP36 temperature sensor

const float supplyv = 5.0; //suply voltage

const float ts_offset = 3.86515625; //TM136 calibration offset

const int ts_multi = 30; // TM136 temp multi (calibration)

const float cm_to_in = 0.3937008; //convert cm to inches

//variables

float current_temp;

float duration, inches, cm, temp_f, comp_duration, comp_inches;

//——————————————————–

void setup()

{

// establish variables for duration of the ping,

// and the distance result in inches and centimeters:

pinMode(txPin, OUTPUT);

mySerial.begin(9600); // 9600 baud is chip comm speed

mySerial.print(“?G420″); // set display geometry, 4 x 20 characters in this case

delay(500); // pause to allow LCD EEPROM to program

mySerial.print(“?Bff”); // set backlight to ff hex, maximum brightness

delay(1000); // pause to allow LCD EEPROM to program

mySerial.print(“?s6″); // set tabs to six spaces

delay(1000); // pause to allow LCD EEPROM to program

mySerial.print(“?f”); // clear the LCD

delay(10);

mySerial.print(“?x00?y0″); // cursor to first character of line 0

delay(10);

mySerial.print(“Distance to object:”);

}

//————————————————————-

void loop()

{

// get current temp

current_temp = get_temp();

// measure distance

float duration = measure_distance();

// convert the time into a distance in inches

inches = microsecondsToInches(duration);

// adjust speed of sound by temp

//mpcm = microseconds_per_cm();

// adjust duration in cm by temp and sensor offset

comp_duration = microseconds_to_cm(duration);

// convert the time into an adjusted distance in inches

comp_inches = (comp_duration * cm_to_in); // cm to inches

//—————————————

mySerial.print(“?x00?y1″); // cursor to first character of line 1

mySerial.print(” “);

mySerial.print(“?x00?y1″); // cursor to first character of line 1

print_float(inches,2); // print var in floating point with # decimal points

mySerial.print(“?x07?y1″); // cursor to first character of line 1

mySerial.print(” Inches”);

//—————————————-

mySerial.print(“?x00?y2″); // cursor to first character of line 2

mySerial.print(” “);

mySerial.print(“?x00?y2″); // cursor to first character of line 2

temp_f = current_temp * 9/5 + 32; //convert temp in c to f

print_float(temp_f,2); // print var in floating point with # decimal points

mySerial.print(“?x07?y2″); // cursor to first character of line 2

mySerial.print(” Deg F”);

//——————————————-

mySerial.print(“?x00?y3″); // cursor to first character of line 3

mySerial.print(” “);

mySerial.print(“?x00?y3″); // cursor to first character of line 3

print_float(comp_inches,2); // print var in floating point with # decimal points

mySerial.print(“?x07?y3″); // cursor to first character of line 3

mySerial.print(” Comp Inches”);

delay(500);

}

//———-functions—————–

float microsecondsToInches(float microseconds)

{

// According to Parallax’s datasheet for the PING))), there are

// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per

// second). This gives the distance travelled by the ping, outbound

// and return, so we divide by 2 to get the distance of the obstacle.

// See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf

return microseconds / 73.746 / 2;

}

//———————————————–

float get_temp() //return filtered temp in c

{

// apply smoothing filter

const int numReadings = 10;

int readings[numReadings]; // number of samples from temp sensor

int index = 0; // index of the current reading

int total = 0; // running total

int average = 0; // average

// initialize all the temp readings to 0:

for (int thisReading = 0; thisReading < numReadings; thisReading++)

{

readings[thisReading] = 0;

// apply filter and get current temp

total= total – readings[index];

// read from the sensor:

readings[index] = analogRead(tempPin);

// add the reading to the total:

total= total + readings[index];

// advance to the next position in the array:

index = index + 1;

// if we’re at the end of the array…

if (index >= numReadings)

{

// …wrap around to the beginning:

index = 0;

// calculate the average:

average = total / numReadings;

}

}

return average * supplyv * ts_multi /1024 + ts_offset; //tempc ;

}

//————————————————————–

const float microseconds_per_cm()

{

return 1/ ((331.5 +(0.6 * current_temp)) /10000);

}

//—————————————————————

const float sensor_offset()

{

return sensor_gap * microseconds_per_cm() * 2;

}

//—————————————————————

const float microseconds_to_cm(const unsigned long microseconds)

{

const float net_distance = microseconds-sensor_offset();

return net_distance/ microseconds_per_cm()/2;

}

//—————————————————————-

const unsigned long measure_distance()

{

// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.

// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:

pinMode(pingPin, OUTPUT);

digitalWrite(pingPin, LOW);

delayMicroseconds(2);

digitalWrite(pingPin, HIGH);

delayMicroseconds(5);

digitalWrite(pingPin, LOW);

// The same pin is used to read the signal from the PING))): a HIGH

// pulse whose duration is the time (in microseconds) from the sending

// of the ping to the reception of its echo off of an object.

pinMode(pingPin, INPUT);

// get return time duration

return pulseIn(pingPin, HIGH);

}

//—————————————————————————-

void print_float(float f, int num_digits)

{

int f_int;

int pows_of_ten[4] = {1, 10, 100, 1000};

int multiplier, whole, fract, d, n;

multiplier = pows_of_ten[num_digits];

if (f < 0.0)

{

f = -f;

mySerial.print(“-”);

}

whole = (int) f;

fract = (int) (multiplier * (f – (float)whole));

mySerial.print(whole);

mySerial.print(“.”);

for (n=num_digits-1; n>=0; n–) // print each digit with no leading zero suppression

{

d = fract / pows_of_ten[n];

mySerial.print(d);

fract = fract % pows_of_ten[n];

}

}

Weekend #3 – Saturday April 2, 2011

As planned for today, we tested the JeeLabs LCD plug and the Modern Devices LCD117. Both devices are designed to drive  any HD44780-based LCD. These are the most common LCDs.

The LDC117 was by far (In my opinion), the superior serial display driver interface. The LCD117 gives you a lot of display options and also allows for custom characters. See the bar graph demo photo below. Also this device only requires 5v, Gnd and a single serial data line. This significantly reduces the number of pins necessary to use an LCD display in a micro-controller project. I know we’ll need all available digital /analog >  inputs/ outputs soon.

http://shop.moderndevice.com/products/lcd117-kit

I’ll wrap up modifying the sonar code with the changes from including the LCD117 tomorrow, then we’ll start assembling the rover.

A few comments and photos from this weekend’s “fun” ;-)

A few comments:

This was a really productive weekend. I’m also really enjoying spending Saturday’s with my oldest grandson ;-) We started Saturday morning with a trip to Starbuck’s then on to Radio Shack for parts …

Thanks to Granny for being a real sport, letting us dominate the dining table most of Saturday … ;-)

The TMP36 temp sensor’s datasheet can be found at:

http://www.analog.com/en/temperature-sensing-and-thermal-management/digital-temperature-sensors/TMP36/products/product.html

During the upcoming week, I’ll convert the display to an I2C – Bus or Serial Interface so we’ll use fewer  digital input/outputs for the LCD display.  I’ll do this with a JeeLabs LCD plug or an LCD117 Serial LCD Kit from Modern Devices.

http://shop.moderndevice.com/products/jeelabs-lcdplug

http://shop.moderndevice.com/products/lcd117-kit

A few photos:

Fully functional compensated PING, Temperature verification (I use both a mercury F and C thermometer) and my notebook

Ping Sonar Code – with temp and gap compensation

This is our draft code for the temp & gap compensated Ping Sensor.

Still a bit of work to do. I’ll work on some integer magic to reduce dependency on floating point variables but it’s functional now.

I referenced many examples included with the Arduino IDE and site, Hacktronics LCD tutorial and  Maik Schmidt’s book; Arduino, A Quick-Start Guide. Excellent book but I disagree with the comments about not needing to calibrate the TMP36 temp sensor in section 5.4 and my code below reflects this. My reference was the TMP36 datasheet from Analog Devices.

——————————————————————————————–

// Temp compensated distance measurement with Ping
// Jim Winburn > http://www.apphipania.com

#include <LiquidCrystal.h>

// Connections:
// rs (LCD pin 4) to Arduino pin 12
// rw (LCD pin 5) to Arduino pin 11
// enable (LCD pin 6) to Arduino pin 10
// LCD pin 15 to Arduino pin 13
// LCD pins d4, d5, d6, d7 to Arduino pins 5, 4, 3, 2

LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

//constants

const float sensor_gap =0.2;
const int pingPin = 7; //ping sensor
const int tempPin = 0; //TMP36 temperature sensor
const float supplyv = 5.0; //suply voltage
const float ts_offset = 3.86515625; //TMP36 calibration offset
const int ts_multi = 30; // TMP36 temp multi (calibration)
const float cm_to_in = 0.3937008; //convert cm to inches
int backLight = 13; // pin 13 will control the backlight

//variables

float current_temp;

float duration, inches, cm, temp_f, comp_duration, comp_inches;

void setup()
{
// Set up static screen for 20/4 blue LCD

pinMode(backLight, OUTPUT);
digitalWrite(backLight, HIGH); // turn backlight on
lcd.begin(20,4); // columns, rows
lcd.clear(); // start with a blank screen
lcd.setCursor(0,0); // set cursor to column 0, row 0 (the first row)
lcd.print(“Distance to object:”);

}

void loop()
{

// get current temp
current_temp = get_temp();

// measure distance
float duration = measure_distance();

// convert duration of return pulse into distance in inches
inches = microsecondsToInches(duration);

// adjust duration in cm by temp and sensor offset
comp_duration = microseconds_to_cm(duration); // comp_duration is in cm now

// convert the comp_duration into adjusted distance in inches
comp_inches = (comp_duration * cm_to_in); // cm to inches

// display results
pinMode(backLight, OUTPUT);
digitalWrite(backLight, HIGH); // ensure backlight is on

lcd.setCursor(0,1); // set cursor to column 0, row 1
lcd.print(” “);
lcd.setCursor(0,1);
lcd.print(inches);
lcd.setCursor(7,1);
lcd.print(” Inches”); // display uncompensated distance

lcd.setCursor(0,2); // set cursor to column 0, row 2
lcd.print(” “);
lcd.setCursor(0,2);
temp_f = current_temp * 9/5 + 32; //convert temp in c to f
lcd.print(temp_f );
lcd.setCursor(7,2);
lcd.print(” Deg F”); // display current temp in F

lcd.setCursor(0,3); // set cursor to column 0, row 3
lcd.print(” “);
lcd.setCursor(0,3);
lcd.print(comp_inches);
lcd.setCursor(7,3);
lcd.print(” Comp Inches”); // display compensated distance (adjusted by temp and physical sensor offset)

delay(1000);

}

//———-functions—————–

float microsecondsToInches(float microseconds)
{
// According to Parallax’s datasheet for the PING))), there are
// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
// second). This gives the distance travelled by the ping, outbound
// and return, so we divide by 2 to get the distance of the obstacle.
// See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
return microseconds / 73.746 / 2;
}

float get_temp() //return filtered temp in c
{

//———————————-
// apply smoothing filter
const int numReadings = 10;
int readings[numReadings]; // number of samples from temp sensor
int index = 0; // index of the current reading
int total = 0; // running total
int average = 0; // average

// initialize all the temp readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++)

{

readings[thisReading] = 0;

// apply filter and get current temp

total= total – readings[index];

// read from the sensor:

readings[index] = analogRead(tempPin);

// add the reading to the total:

total= total + readings[index];

// advance to the next position in the array:

index = index + 1;

// if we’re at the end of the array… if (index >= numReadings)
{
// …wrap around to the beginning:
index = 0;

// calculate the average:
average = total / numReadings;
}
}

return average * supplyv * ts_multi /1024 + ts_offset; //return temp in c ;

}

const float microseconds_per_cm()
{
return 1/ ((331.5 +(0.6 * current_temp)) /10000);
}

const float sensor_offset()
{
return sensor_gap * microseconds_per_cm() * 2;
}

const float microseconds_to_cm(const unsigned long microseconds)
{
const float net_distance = microseconds-sensor_offset();
return net_distance/ microseconds_per_cm()/2;
}

const unsigned long measure_distance()
{
// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:

pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);

// The same pin is used to read the signal from the PING))): a HIGH
// pulse whose duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(pingPin, INPUT);

// get return time duration
return pulseIn(pingPin, HIGH);
}

Follow

Get every new post delivered to your Inbox.