In the article "Build a Low-Cost Smartphone Based Robot Tank Using the EMGRobotics... I wrote about building a low cost smartphone controlled robot tank for less than $50.00. In this article I am going to cover programming the tank using a free BASIC programming language for Android called RFO Basic.
After following the step-by-step instruction in the "Build a Low-Cost Smartphone Based Robot Tank Using the EMGRobotics... article covering the actual construction of the tank and replacement of the electronics with the EMGRobotics ADMCB board from www.emgrobotics.com. you will need to install the RFO BASIC application on your Android device. The official RFO release can only generate low frequency tones (less than 2000hz). To generate the higher frequency tones required by the ADMCB board/robot I modified the open source RFO project and created my own APK. The only difference between my RFO BASIC release and the official release concerns changes in the tone command.
You can download the modified RFO BASIC here: Basic.apk
After downloading and installing RFO BASIC execute the application by clicking on the icon:
Use the editor to write your code, then select "save" from the menu to save your code in your phone. Be sure the volume is turned all the way up, plug the ADMCB into your Android's headphone jack and select "run" from the menu.
The key to using RFO BASIC with the ADMCB board is the RFO BASIC "tone" command. The tone command is used to generate sound in the frequency range of 1000hz to 10000hz required by the ADMCB board. The table below shows the ADMCB actions associated with each frequency.
The format for the tone command is as follows:
tone <frequency> <duration in ms>
To make the robot go forward for 5 seconds use the following command:
tone 8500, 5000
5000ms is 5 seconds. You can replace the numbers with RFO BASIC variables making the possibilities endless. You can learn more about other commands and features in RFO BASIC here: http://laughton.com/basic/
You can learn more about the EMGRobotics ADMCB board here:
http://buildsmartrobots.ning.com/profiles/blogs/the-emgrobotics-aud...
My changes to the RFO BASIC source were limited to the executeTONE() function in the run.java module.
I modified the function to use a sample rate of 44100hz and output in stereo.
I also removed the ramp up and ramp down as this can cause problems with the ADMCB board not getting solid edges.
See my modified code below.
private boolean executeTONE(){
double duration = 1; // seconds
double freqOfTone = 1000; // hz
int sampleRate = 44100; // a number
if (!evalNumericExpression())return false; // Get frequency
freqOfTone = EvalNumericExpressionValue;
if (!isNext(',')) return false;
if (!evalNumericExpression())return false; // Get duration
duration= EvalNumericExpressionValue/1000 ;
double dnumSamples = duration * sampleRate;
dnumSamples = Math.ceil(dnumSamples);
int numSamples = (int) dnumSamples;
double sample[] = new double[numSamples];
byte generatedSnd[] = new byte[4 * numSamples];
boolean flagMinBuff = true;// Optionally skip checking min buffer size
if (isNext(',')) {
if (!evalNumericExpression()) return false;
if (EvalNumericExpressionValue == 0 )
flagMinBuff = false;
}
if (flagMinBuff) {
int minBuffer = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT);
if (numSamples< minBuffer){
double minDuration = Math.ceil(1000 * (double)minBuffer/(double)sampleRate);
RunTimeError("Minimum tone duration for this device: " + (int) minDuration + " milliseconds");
return false;
}
}
if (!checkEOL()) return false;// No more parameters expected
for (int i = 0; i < numSamples; ++i) { // Fill the sample array
sample[i] = Math.sin(freqOfTone * 2 * Math.PI * i / (sampleRate));
}
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalized.
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalised.
int idx = 0;
int i = 0 ;
// int ramp = numSamples / 20 ; // Amplitude ramp as a percent of sample count
// for (i = 0; i< ramp; ++i) { // Ramp amplitude up (to avoid clicks)
// double dVal = sample[i];
// Ramp up to maximum
// final short val = (short) ((dVal * 32767 * i/ramp));
// in 16 bit wav PCM, first byte is the low order byte
// generatedSnd[idx++] = (byte) (val & 0x00ff);
// generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
// }
for (i = 0; i< numSamples; ++i) { // Max amplitude for most of the samples
double dVal = sample[i];
// scale to maximum amplitude
final short val = (short) ((dVal * 32767));
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
// for (i = i; i< numSamples; ++i) { // Ramp amplitude down
// double dVal = sample[i];
// Ramp down to zero
// final short val = (short) ((dVal * 32767 * (numSamples-i)/ramp ));
// in 16 bit wav PCM, first byte is the low order byte
// generatedSnd[idx++] = (byte) (val & 0x00ff);
// generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
// }
AudioTrack audioTrack = null; // Get audio track
try {
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, (int)numSamples*4,
AudioTrack.MODE_STATIC);
audioTrack.write(generatedSnd, 0, generatedSnd.length); // Load the track
audioTrack.play(); // Play the track
}
catch (Exception e){
return RunTimeError(e);
}
int x =0;
do{// Montior playback to find when done
if (audioTrack != null)
x = audioTrack.getPlaybackHeadPosition();
else
x = numSamples;
}while (x<numSamples);
if (audioTrack != null) audioTrack.release(); // Track play done. Release track.
audioTrack = null; // Release storage
generatedSnd = null;
sample = null;
System.gc();
return true;
}
Comment
© 2013 Created by eric gregori.

You need to be a member of buildsmartrobots to add comments!
Join buildsmartrobots