Building an Android Basic Programmable Tank for Less Than $50.00

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...

Views: 1090

Tags: ADMCB, Android, BASIC, RFO, emgrobotics, tank

Comment by eric gregori on March 3, 2013 at 11:40am

Comment by eric gregori on March 3, 2013 at 8:00pm

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

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

EMGRobotics

© 2014   Created by eric gregori.

Badges  |  Report an Issue  |  Terms of Service