Go Down

Topic: Sonar (Read 108 times) previous topic - next topic

antotabo

May 01, 2015, 05:49 am Last Edit: May 01, 2015, 06:38 am by antotabo Reason: Added setup picture.
Hi, I would like to show off the project I'm currently working on.

The idea is that I want to produce an image of the surroundings using ultrasound. I basically want to make a sonar capable of producing sector scans (s-scans) like so:



This is how I will try to accomplish my final goal:

Both a transmitting and a receiving piezo transducers will be mounted onto a servo motor. The servo will sweep the sector as the piezos will sense the surrounding in a series of consecutive A-scans. Those A-scans will be transmitted to MATLAB in realtime in order to collect the data and generate the s-scan image.


Hardware:

- 2 Piezoelectric transducers (from aliexpress, I think they are the same as on the PING ultrasonic distance sensor, they are tuned at 40kHz)
-Arduino Mega (what I have on hands, I think lower ones like the UNO should do the job too)
-NPN transistor BD137 (to drive the TX piezo at higher voltage)
-OP-Amp TL072 arranged as a differential amplifier (to amplify RX piezo signal)
- Servo motor


Progress:

In a couple of days (yes days, I'm a beginner in electronics), I have managed to;
1. Drive the TX trough a transistor.
2. Read the RX trough a op-amp.
3. Send the data to MATLAB.
4. Produce A-scans plot.

Here is the setup thus far:



Arduino Code:

The first tricky part here is to upgrade the sample rate of the arduino by reducing the ADC prescaler. This allows the Arduino to sample at roughly 60KHz instead of the usual 9KHz.
The second tricky part is to send the data as an array of bytes fast enough. The terminal of the arduino IDE seems to suggest a maximum baudrate of 115200. By trial and error, I have managed to push the baudrate up to 691200, or 6 times higher, with reliable receive on the MATLAB side.

Code: [Select]

/* _________Sonar_Test_________

Code:
  - Produce a sonar burst at 40 KHz (digitalWrite).
  - Sample the transducer at around 50 KHz (analogRead) to produce an A-Scan.
  - Send the A-scan data over serial to be retrieved by MATLAB.
  
Hardware:
  - TX piezo connected to digital pin 22 trough a power transistor to be driven by higher voltage (12 V).
  - RX piezo connected to analog pin 10 trough an op-amp configured as a differential amplifier (G : ~30x).
  - Connected via USB to computer running MATLAB script to retrieve data.
  
*/

// Defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif



// Constants
const int piezoPin =  22;
const int potPin =  10;
const int frequency = 40000;           // Hz
const int pulseInterval = 80;         // millis
const int pulseWidth = 3;     // micros * (prescale factor 128 / 16 = 8)
const int nbSamples = 600;

// Variables
unsigned long previousMillis = 0;
unsigned long currentMillis =0;
unsigned int samples[nbSamples + 4];
int txTime = 1;


void setup() {
  // set the digital pin as output:
  pinMode(piezoPin, OUTPUT);
  
  // Fast ADC : set ADC prescale to 16 (default 128)
  sbi(ADCSRA,ADPS2) ;
  cbi(ADCSRA,ADPS1) ;
  cbi(ADCSRA,ADPS0) ;
  
  Serial.begin(691200);   // Max Arduino terminal is : 115200 ( 6x slower! )
}


void loop()
{
  
  currentMillis = millis();
  if(currentMillis - previousMillis >= pulseInterval) {
    previousMillis = currentMillis;  
    
    // Sonic Burst
    tone(piezoPin,frequency,pulseWidth);
    
    // Samples
    unsigned long spTime = micros();
    for (int i=0; i<nbSamples; i++){
    samples[i+1] = analogRead(potPin);
    }
    spTime = micros()-spTime;
    
    // Turn off ultrasound
    // noTone(piezoPin);
    
    // Send serial data as an array of bytes
    unsigned long timer2 = millis();
    samples[0]=1025;                   // start synchro padding
    samples[nbSamples+1] = spTime;       // Sampling Time metadata
    samples[nbSamples+2] = txTime;       // Transmit Time metadata
    samples[nbSamples+3] = 1025;       // end synchro padding
    Serial.flush();
    Serial.write((uint8_t*)samples, sizeof(samples));
    txTime = millis()-timer2;
    
    // Print debug info
//    Serial.println();
//    Serial.print("Sampling Time [us] : "); Serial.println(spTime);
//    Serial.print("Sampling Freq [Hz] : "); Serial.println(nbSamples*1000000/timer1);
//    Serial.print("Sampling Dist [m]  : "); Serial.println(spTime*.000344/2);
//    Serial.print("Transmit Time [ms] : "); Serial.println(txTime);
    
  }
}



MATLAB code:

Code: [Select]

% Reset
snew = instrfind;
if ~isempty(snew);
    fclose(snew);
end
close all;
clear all;
clc;

% Constants
nbData = 600;
nbMeta = 4;
sonicSpeed = 344;

% Variables
data(nbData + nbMeta,1) = 0;
sample(nbData) = 0;
spTime = 11.6;
txTime = 0;
oldFPS = 0;
newFPS = 0;
FPS = 0;
FPS_Period = 1;
strFPS = 'FPS = xx';
error = 0;
strError = 'Error = 0';
range = 0;
samplingFreq = 0;

% Define port
port = serial('COM4', 'BaudRate', 691200);
port.InputBufferSize = 5000;
port.timeout = 2;

% Define figure
scrsz = get(groot,'ScreenSize');
figure1 = figure('OuterPosition',[1 scrsz(4)*.05 scrsz(3) scrsz(4)*.95],'CurrentCharacter','a');
whitebg('white');
t = [spTime/nbData:spTime/nbData:spTime];

% Initialize plots
rawPlot = plot(t,sample, 'b');
hold on;
%absPlot = plot(t,sample, 'c');
%avgPlot = plot(t,sample,'r');
%maxPlot = plot(t,sample,'g');
maxAvgPlot = plot(t,sample,'r');
% Figure setup
axis([0,spTime,-.2,.2]);
xlabel('Time [ms]');
ylabel('Volt [v]');
grid on;
% Add annotations
text = annotation(figure1,'textbox',[.01 .6 .08 .2],'FitBoxToText','off');
set(text,'String',strFPS);
drawnow;
hold off;

fopen(port);
while double(get(gcf,'CurrentCharacter'))~=27
    tic;
    % Read data
    flushinput(port);
    data = fread(port, nbData + nbMeta, 'int16');
    
    % Extract samples, padding & metaData
    padding = [data(1), data(nbData + nbMeta)];
    
    % Validation
    maxValue = max(data(2:nbData+1));
    if padding(1) == 1025 && padding(2) == 1025 && maxValue <= 1024
        spTime = data(nbData+2);
        txTime = data(nbData+3);
        sample = data(2:nbData+1)/1023*5;
        range = spTime * sonicSpeed /1000000 / 2;
        samplingFreq = nbData * 1000000 / spTime;
        whitebg('white');
    else
        whitebg('red');
        error = error + 1;
    end
    
    % Filter Data
    sample = sample + (-2.5 + .017);
    absSample = abs(sample);
    movAvg = smooth(t,absSample,6,'moving');
    t2 = t;
    sample2 = absSample;
    
    for j = 1 : nbData
        if absSample(j) < movAvg(j) -.002
            sample2(j) = NaN;
            t2(j) = NaN;
        end
    end
    
    sample2=sample2(~isnan(sample2));
    t2=t2(~isnan(t2));
    filtMovAvg = smooth(t2,sample2,10,'moving');
    
    % Refresh figure  
    set(rawPlot,'YData',sample);
    hold on;
    %set(absPlot,'YData',absSample);
    %set(avgPlot,'YData',movAvg);
    %set(maxPlot,'XData',t2)
    %set(maxPlot,'YData',sample2)
    set(maxAvgPlot,'XData',t2)
    set(maxAvgPlot,'YData',filtMovAvg)
    
    % Update Text
    strFPS = ['FPS = ',int2str(FPS)];
    strFreq = ['spFreq = ',num2str(samplingFreq/1000,3), ' kHz'];
    strTime = ['sptime = ',num2str(spTime/1000,3), ' ms'];
    strRange = ['spRange = ',num2str(range,3), ' m'];
    strError = ['Error = ',int2str(error)];
    str = {strFPS, strFreq, strTime, strRange, strError};
    set(text,'String',str);
    
    drawnow;
    hold off;
    
    oldFPS = newFPS;
    newFPS = 1/FPS_Period;
    FPS = mean([oldFPS,newFPS]);
    FPS_Period = toc;
end

% Close port
fclose(port);
close all;


So far I am able to produce the A-scans with MATLAB, this is an actual screenshot:

The first blob is the initial burst, the second one is my hand at roughly 2 feet away from the sensors, the third one is the ceiling at roughly 5 feet above the sensors.


So I am quite impressed by the results thus far and also by myself, given my background.


To do:

5. Drive the servo to sweep the sector.
6. Produce S-scans images (this sounds quite tricky  :smiley-confuse:  )

Hopefully this post will help at least one person on this planet.
Feel free to comment on any improvements, though, or whatever.
cheers!

TonyD

Cool project.

We used something similar with our mechanically scanned sonar's on our subsea ROV's

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy