Commanding the A2SCB or A2MCB From an Android Application

Controlling the A2SCB or A2MCB from Android is easy done by using the Android AudioTrack class ( http://developer.android.com/reference/android/media/AudioTrack.html ). Simply create a buffer with the desired tone sequence and play the buffer using the AudioTrack class. See the source for the RFO BASIC "servo" command below as an example of how to use the AudioTrack class to command an A2SCB or A2MCB.

//
// EMGRobotics
//
// servo side, servo1, <servo2>, <servo3>, <servo4>, <servo5>, <servo6>, <servo7>, <servo8>
//
private boolean executeSERVO()
{
//------------------------------------------------------------------------------------------
//
// Tone Generating Code
//
//------------------------------------------------------------------------------------------
final double HeaderDuration = 0.005; // Header Duration
final int HeaderFreq = 8500; // Header Frequency
final double SyncDuration = 0.005; // Sync Duration
final int SyncFreq = 9500; // Sync Frequency
final double DataDuration = 0.007; // Data Duration
// H + D1 + S + D2 + S + D3 + S + D4 + S + D5 + S + D6 + S + D7 + S + D8
final double MaxDuration = HeaderDuration+DataDuration+7*(DataDuration+SyncDuration);
final double sampleRate = 44100.0;
int numSamples;
double mMonoSamples[] = new double[(int)((MaxDuration*sampleRate)+10)];
double Channel1 = -1;
double Channel2 = -1;
double Channel3 = -1;
double Channel4 = -1;
double Channel5 = -1;
double Channel6 = -1;
double Channel7 = -1;
double Channel8 = -1;
double AudioChannel;
int NumberOfPackets;


// ChannelX must be between 5050 and 7950

// RFO Specific code - Start
if (!evalNumericExpression())return false;
AudioChannel = EvalNumericExpressionValue;

if (isNext(','))
{
if (!evalNumericExpression())return false; // Repeat
NumberOfPackets = EvalNumericExpressionValue.intValue();
if( NumberOfPackets < 1 ) return false;
}
else
return false;

// We translate 0 - 180 to 5050 - 7950 using freq = 5050+user*5
if (isNext(','))
{
if (!evalNumericExpression())return false; // Channel1
Channel1 = 5050+15*EvalNumericExpressionValue;
if( Channel1 > 7950 ) return false;
}
else
return false;

if (isNext(','))
{
if (!evalNumericExpression())return false; // Channel2
Channel2 = 5050+15*EvalNumericExpressionValue;
if( Channel2 > 7950 ) return false;
}

if (isNext(','))
{
if (!evalNumericExpression())return false; // Channel3
Channel3 = 5050+15*EvalNumericExpressionValue;
if( Channel3 > 7950 ) return false;
}

if (isNext(','))
{
if (!evalNumericExpression())return false; // Channel4
Channel4 = 5050+15*EvalNumericExpressionValue;
if( Channel4 > 7950 ) return false;
}

if (isNext(','))
{
if (!evalNumericExpression())return false; // Channel5
Channel5 = 5050+15*EvalNumericExpressionValue;
if( Channel5 > 7950 ) return false;
}

if (isNext(','))
{
if (!evalNumericExpression())return false; // Channel6
Channel6 = 5050+15*EvalNumericExpressionValue;
if( Channel6 > 7950 ) return false;
}

if (isNext(','))
{
if (!evalNumericExpression())return false; // Channel7
Channel7 = 5050+15*EvalNumericExpressionValue;
if( Channel7 > 7950 ) return false;
}

if (isNext(','))
{
if (!evalNumericExpression())return false; // Channel8
Channel8 = 5050+15*EvalNumericExpressionValue;
if( Channel8 > 7950 ) return false;
}
// RFO Specific code - End

Log.d( "EMG", "Servos = "+Channel1+","+Channel2+","+Channel3+","+Channel4+","+Channel5+","+Channel6+","+Channel7+","+Channel8);

int j;
for (numSamples = 0; numSamples < (HeaderDuration*sampleRate); ++numSamples) // Header
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/HeaderFreq));

if( Channel1 > 0 )
{
for( j=0; j<(DataDuration*sampleRate); ++j,++numSamples) // Servo 1
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/Channel1));
}

if( Channel2 > 0 )
{
for( j=0; j<(SyncDuration*sampleRate); ++j,++numSamples) // Sync
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/SyncFreq));
for( j=0; j<(DataDuration*sampleRate); ++j,++numSamples) // Servo 2
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/Channel2));
}

if( Channel3 > 0 )
{
for( j=0; j<(SyncDuration*sampleRate); ++j,++numSamples) // Sync
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/SyncFreq));
for( j=0; j<(DataDuration*sampleRate); ++j,++numSamples) // Servo 3
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/Channel3));
}

if( Channel4 > 0 )
{
for( j=0; j<(SyncDuration*sampleRate); ++j,++numSamples) // Sync
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/SyncFreq));
for( j=0; j<(DataDuration*sampleRate); ++j,++numSamples) // Servo 4
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/Channel4));
}

if( Channel5 > 0 )
{
for( j=0; j<(SyncDuration*sampleRate); ++j,++numSamples) // Sync
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/SyncFreq));
for( j=0; j<(DataDuration*sampleRate); ++j,++numSamples) // Servo 5
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/Channel5));
}

if( Channel6 > 0 )
{
for( j=0; j<(SyncDuration*sampleRate); ++j,++numSamples) // Sync
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/SyncFreq));
for( j=0; j<(DataDuration*sampleRate); ++j,++numSamples) // Servo 6
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/Channel6));
}

if( Channel7 > 0 )
{
for( j=0; j<(SyncDuration*sampleRate); ++j,++numSamples) // Sync
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/SyncFreq));
for( j=0; j<(DataDuration*sampleRate); ++j,++numSamples) // Servo 7
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/Channel7));
}

if( Channel8 > 0 )
{
for( j=0; j<(SyncDuration*sampleRate); ++j,++numSamples) // Sync
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/SyncFreq));
for( j=0; j<(DataDuration*sampleRate); ++j,++numSamples) // Servo 8
mMonoSamples[numSamples] = Math.sin(2 * Math.PI * numSamples / (sampleRate/Channel8));
}

byte Direct[] = new byte[4*NumberOfPackets*numSamples];
Log.d( "EMG", "Direct = "+(4*NumberOfPackets*numSamples));

// convert to 16 bit pcm sound array
// assumes the sample buffer is normalised.
int idx = 0;
short left, right;
for(int repeat=0; repeat<NumberOfPackets; ++repeat )
{
for (int i = 0; i < (numSamples); ++i)
{
// scale to maximum amplitude
if( AudioChannel == 1 )
{
left = (short) ((mMonoSamples[i] * 32767));
right = 0;
}
else if( AudioChannel == 2 )
{
right = (short) ((mMonoSamples[i] * 32767));
left = 0;
}
else
{
left = (short) ((mMonoSamples[i] * 32767));
right = (short) ((mMonoSamples[i] * 32767));
}

// in 16 bit wav PCM, first byte is the low order byte - Stereo
Direct[idx++] = (byte) (left & 0x00ff);
Direct[idx++] = (byte) ((left & 0xff00) >>> 8);
Direct[idx++] = (byte) (right & 0x00ff);
Direct[idx++] = (byte) ((right & 0xff00) >>> 8);
} // for
}
AudioTrack audioTrack = null; // Get audio track

try {
audioTrack = new AudioTrack( AudioManager.STREAM_MUSIC,
(int)sampleRate, AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, idx,
AudioTrack.MODE_STATIC );
audioTrack.write(Direct, 0, idx); // 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
break;
}while (x<(idx/4));

if (audioTrack != null) audioTrack.release(); // Track play done. Release track.

audioTrack = null; // Release storage
Direct= null;
mMonoSamples = null;
System.gc();

return true;
}

You can download the "servo" command code snippet for RFO BASIC here: AndroidAudioCommandCode.txt

Views: 306

Comment

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

EMGRobotics

© 2017   Created by eric gregori.   Powered by

Badges  |  Report an Issue  |  Terms of Service