Check out the new projects site for A-i-S www.adventuresinsilicon.com

Sunday, December 20, 2009

Code below is for an Arduino Pro running at 16Mhz to sample a Maxsonic EZ0 Ultrasonic distance measuring device's PWM output.

This code is non-trivial as it takes 12 samples, determines the Interquartile Range of the dataset, then takes a mean of the Interquartile Range of the dataset and also calculates the Standard Deviation from the mean of that dataset.

The result is a robust measurement which has removed the influence of outliers in the data and can inform the user of the confidence of the single measurement number.

The code is generalised so that more accurate readings due to extra samples require only one line of code to be altered.
______________________________________________________________________

//Note - time to sample is not deterministic with this code, it will depend on the distance measured


int pin = 2; //pin revceiving PWM data from EZ0


void FindDistanceStdDev(int NUMOFSAMPLES);

void setup()
{
pinMode(pin, INPUT);
Serial.begin(9600);

}

void loop()
{

FindDistanceStdDev(12); //best to use number divisible by 4

delay(1);
}

//*********************************************************************************************************************
//
//
// Note: NUMOFSAPMLES should be divisible by 4
//*********************************************************************************************************************
void FindDistanceStdDev(int NUMOFSAMPLES)
{
float duration = 0.0f; //Variable to hold the delay in travel time of ultrasonic sound per sample (microseconds)
float distancefinal = 0.0f;

unsigned int count = 0; //variable to count samples
unsigned int CountSortInner = 0 ; //counter used to track inside loop for Bubble Sort
int SortCompleted = 0; //BOOL to track if bubblesort completed

float StdDevScratch = 0.0f;
const int SAMPLEDELAY = 1; //delay in millis between samples
float distancesamples[NUMOFSAMPLES]; //array to store samples in
float IQRScratch; //used for swaps inthe bubblesort
int IQRNUMOFSAMPLES = NUMOFSAMPLES/2;
float InterquartileArray[IQRNUMOFSAMPLES];
float mean = distancefinal;
float SamplesStdDevScratch[IQRNUMOFSAMPLES]; //array to hold intermediate values during calculations

// initialise array
for(count = 0; count < NUMOFSAMPLES; count++)
{
distancesamples[count] = 0;
}
count = 0;

//populate array with samples from the EZ0 hardware
count = 0;
for(count = 0; count < NUMOFSAMPLES; count++)
{
duration = 0;
duration = pulseIn(pin, HIGH);
distancesamples[count] = (duration/147.0f);
duration = 0;
delay(SAMPLEDELAY);
}

//DEBUG print sampled values
for(count = 0; count < NUMOFSAMPLES; count++)
{
Serial.print(" ");
Serial.print(distancesamples[count]);
Serial.print(" ");
}
Serial.print("\r\n");


//Cull array to leave only Interquartile Range
//Step 1 - Sort array
for(count = NUMOFSAMPLES - 1; count > 0; count--)
{
for(CountSortInner = 0; CountSortInner < count; CountSortInner++)
{
SortCompleted = 0;

if(distancesamples[CountSortInner] > distancesamples[CountSortInner+1])
{
IQRScratch = distancesamples[CountSortInner];
distancesamples[CountSortInner] = distancesamples[CountSortInner+1];
distancesamples[CountSortInner+1] = IQRScratch;
SortCompleted = 1;
}
}
if(SortCompleted = 0) break;

}

//DEBUG print out sorted values
for(count = 0; count < NUMOFSAMPLES; count++)
{
Serial.print(" ");
Serial.print(distancesamples[count]);
Serial.print(" ");
}
Serial.print("\r\n");

//Step 2 - populate new array by cutting the middle out of the sample array and pasting it into new array
int Temp = 0;
int TempStart = (NUMOFSAMPLES/4);
int TempEnd = (NUMOFSAMPLES - TempStart); //top and tail based on symmetrical array
for(count = TempStart; count < (TempStart + IQRNUMOFSAMPLES); count++)
{
InterquartileArray[Temp] = distancesamples[count];
Temp++;
}

for(count = 0; count < IQRNUMOFSAMPLES; count++)
{
Serial.print(" ");
Serial.print(InterquartileArray[count]);
Serial.print(" ");
}
Serial.print("\r\n");

//now average the samples to produce a mean
count = 0;
for(count = 0; count < IQRNUMOFSAMPLES; count++)
{
mean+=InterquartileArray[count];
}
mean = mean/IQRNUMOFSAMPLES;

//Compute the Standard Deviation of the IQR dataset
for(count = 0; count < IQRNUMOFSAMPLES; count++)
{
SamplesStdDevScratch[count] = (pow((InterquartileArray[count]-mean),2)); //take each sample away from the mean then square each result and save into a new array
}
//average these results to produce Std Dev
StdDevScratch = 0.0f;
for(count = 0; count < IQRNUMOFSAMPLES; count++)
{
StdDevScratch += SamplesStdDevScratch[count];
}
//divide by the number of samples
StdDevScratch = StdDevScratch / IQRNUMOFSAMPLES;
//square root this number
StdDevScratch = sqrt(StdDevScratch);

Serial.write("distance : ");
Serial.print(mean);
Serial.write(" inches to object with a Standard Deviation of ");
Serial.print(StdDevScratch);
Serial.write(" \r\n");
//print out the array of samples

}

Tuesday, December 15, 2009

Code below will let your Arduino poll a Maxsonic EZ0 distance sensor and read the PWM to intelligently report back the distance (uses multiple samples and calculates standard deviation as well to report of how confident you can be it got it right).

//Note - time to sample is not deterministic with this code, it will depend on the distance measured


int pin = 2; //pin revceiving PWM data from EZ0
const int NUMOFSAMPLES = 15; //number of samples to take
const int SAMPLEDELAY = 0; //delay in millis between samples
unsigned int count = 0; //variable to count samples

float duration = 0.0f; //Variable to hold the delay in travel time of ultrasonic sound per sample (microseconds)

float distancesample1 = 0.0f;
float distancesample2 = 0.0f;
float distancesample3 = 0.0f;
float distancefinal = 0.0f;


float distancesamples[NUMOFSAMPLES];

void setup()
{
pinMode(pin, INPUT);
Serial.begin(9600);

// initialise array
for(count = 0; count < NUMOFSAMPLES; count++)
{
distancesamples[count] = 0;
}
count = 0;
}

void loop()
{
//populate array with samples from the EZ0 hardware
count = 0;
for(count = 0; count < NUMOFSAMPLES; count++)
{
duration = 0;
duration = pulseIn(pin, HIGH);
distancesamples[count] = (duration/58.0f); //147us/inch or 58us/cm
duration = 0;
delay(SAMPLEDELAY);
}
//now average the samples to produce the final result
//Note no attempt to remove outliers yet
count = 0;
for(count = 0; count < NUMOFSAMPLES; count++)
{
distancefinal+=distancesamples[count];
}
distancefinal = distancefinal/NUMOFSAMPLES;

//Compute the Standard Deviation of the dataset
float mean = distancefinal;
float SamplesStdDevScratch[NUMOFSAMPLES]; //array to hold intermediate values during calculations
float StdDevScratch = 0.0f;

for(count = 0; count < NUMOFSAMPLES; count++)
{
SamplesStdDevScratch[count] = (pow((distancesamples[count]-mean),2.0f));
}
//now add these up
StdDevScratch = 0.0f;
for(count = 0; count < NUMOFSAMPLES; count++)
{
StdDevScratch += SamplesStdDevScratch[count];
}
//divide by the number of samples
StdDevScratch = StdDevScratch / NUMOFSAMPLES;
//square root this number
StdDevScratch = sqrt(StdDevScratch);

Serial.write("distance : ");
Serial.print(distancefinal);
Serial.write(" cm to object with a Standard Deviation of ");
Serial.print(StdDevScratch);
Serial.write(" \r\n");



delay(100);
}

Saturday, October 3, 2009

Arduino code to control the SpeakJet chip

The following code controls the SpeakJet chip to say "Good luck and good hunting". It sends the correct codes from the TX pin (1). Otherwise just follow the diagram on page 3 of the SpeakJet datasheet.

//test of the SpeakJet chip
//Dingo_aus 3 October 2009

//connect the SpaekJet as per page 3 of its datasheet

#define WP 5

uint8_t announce[] = {
//game =\Slow \GE \EYIY \MM
//8, 178, 154, 140, WP,
//starts = \SE \TT \AW \RR \TS
//187,191,136,148, 193, WP,
WP,WP,WP,
//good =\Slow \GO \UH \UH \OD
8, 179, 138, 138, 177, WP,
//luck
8, 145, 8, 134, 7, 184, 196, WP,
//and
8, 132, 8, 141, 177, WP,
//good =\Slow \GO \UH \UH \OD
8, 179, 138, 138, 177, WP,
//hunting
8, 184, 8, 134, 141, 141, 8, 191, 8, 14, 143, 14, 143, 14, 143

};



int announce_len = 0;

void setup()
{
Serial.begin(9600);
announce_len = sizeof(announce);

}


void loop()
{
Serial.write(announce, announce_len);

while(1)
{

}

}

Sunday, July 26, 2009

Quotes

"Every government interference in the economy consists of giving an unearned benefit, extorted by force, to some men at the expense of others."

Ayn Rand

"There is a similar effect when personal incomes are taxed 50, 60 or 70 percent. People begin to ask themselves why they should work six, eight or nine months of the entire year for the government, and only six, four or three months for themselves and their families. If they lose the whole dollar when they lose, but can keep only a fraction of it when they win, they decide that it is foolish to take risks with their capital. In addition, the capital available for risk-taking itself shrinks enormously. It is being taxed away before it can be accumulated. In brief, capital to provide new private jobs is first prevented from coming into existence, and the part that does come into existence is then discouraged from starting new enterprises. The government spenders create the very problem of unemployment that they profess to solve." - Hazlitt

"Just as man can't exist without his body, so no rights can exist without the right to translate one's rights into reality, to think, to work and keep the results, which means: the right of property."
Ayn Rand

"The smallest minority on earth is the individual. Those who deny individual rights cannot claim to be defenders of minorities."
Ayn Rand

"My politics are based...on things I and millions like me were brought up with. An honest day's work for an honest day's pay; live within your means; put by a nest egg for a rainy day; pay your bills on time; support the police."
Margaret Thatcher (1981)

"There can be no liberty unless there is economic liberty."
Margaret Thatcher

"To wear your heart on your sleeve isn't a very good plan; you should wear it inside, where it functions best."
Margaret Thatcher

Freedom is never more than one generation away from extinction. We didn’t pass it on to our children in the bloodstream. It must be fought for, protected, and handed on for them to do the same, or one day we will spend our sunset years telling our children what it was once like in the United States when men were free.
R. Regan

"Throughout the centuries there were men who took first steps down new roads armed with nothing but their own vision."
Ayn Rand, from "The Foutainhead"

Saturday, July 25, 2009

Great quote

"Every government interference in the economy consists of giving an unearned benefit, extorted by force, to some men at the expense of others."

Ayn Rand

Thursday, July 23, 2009

Motors are never linear

With PWM, the output is never linear to the input.

You usually get the motors kicking in at around 60%

Saturday, July 18, 2009

ERE Board ports and my L293D board

This is a note about the wiring on the Tank Bot.

The ERE Board ports have Vcc above the number 7 pin (last pin). Due to the fact I was replicating the ERE Board ports on my L293D driver board, a two wire connector (the home made blue and yellow ones) can be connected directly as it will feed the Vcc on the L293D board.

Just be aware the in this case a light blue wire is carrying Vcc not Gnd like all the others,

Wednesday, July 15, 2009

Timer problem, timer solution

With an AVR Mega32, when using a timer such as Timer2 (8-bit), you do not want to toggle the output pin as this will only give you a 50% duty cycle and you will only be able to control the frequency of that 50% cycle.

This is because the pin is cleared on reaching TOP. So you want to set the pin on match and let it automatically clear on top.

So for Timer2 on the Mega 32 you want to set the TCCR2 register to something like this

TCCR2 = 0b01111011; //0x7B

Magic code

Give your fingers a break and let the web do the typing.

The following website will generate code for an AVR Mega32. It will setup all three timers, the UART and TWI peripherals and ADCs

http://www.jarkonkotisivu.org/AVRcoder

A timer for all occasions

Ok, FreeRTOS is great but not so great if you need to use timers on an AVR to control PWM for motors.

- The Goal -
Run FreeRTOS on a Mega32 and also control DC motors via a L293D using PWM

- The Challenges -
FreeRTOS uses Timer1 to control the FreeRTOS kernel. This leaves Timer0 and Timer2 (both 8 bit) for PWM. Timer0 and Timer1 share a common pre-scaler.

Note that FreeRTOS set the Timer1 pre-scaler in the port.c file via the portCLOCK_PRESCALER and other defines.

Apart from this Timer0 and Timer2 appear to by unmolested by FreeRTOS.

Tuesday, June 9, 2009

If the force is with you, can you feel it?

Next project is a part of a larger puzzle. You can use the force in your car but you want to measure it, log it even then average it. You also want to send the data out on the 433Mhz waves. These are not the droids you are looking for...

Sunday, January 4, 2009

Penguins like things that blink

Well after a day and a half of networking dramas, busybox issues and ftp problems I was able to actually create a C program to blink an LED on the NGW100 board. The source and binary can be found here:

http://users.on.net/~symes/AVR32/blink_AVR32_linux.tar.bz2

I will upload to AVRFreaks as a project but it is currently down at the moment.