Skip to menu

Robotics with Object Pascal

Controls

Ultrasonic with free pascal

2023.12.05 23:15

me Views:202

File : /pascalio/examples/ultrasonic/

(*) Result video of good/bad results are in attached files (*)

I believe the timer routine is not good.  The result is not good also.

Therefore, I have changed all the time routines & recalculated distance value to match an actual ruler.

I have succeed on this.

 

connection.jpg

 

 

pin_detail.png

 

 

 

{ Distance measurement with ultrasonic module HC-SR04
 
  Copyright (C) 20104 Simon Ameis simon.ameis@web.de
 
  Idea: http://www.gtkdb.de/index_36_2272.html
 
  This library is free software; you can redistribute it and/or modify it
  under the terms of the GNU Library General Public License as published by
  the Free Software Foundation; either version 2 of the License, or (at your
  option) any later version with the following modification:
 
  As a special exception, the copyright holders of this library give you
  permission to link this library with independent modules to produce an
  executable, regardless of the license terms of these independent modules,and
  to copy and distribute the resulting executable under terms of your choice,
  provided that you also meet, for each linked independent module, the terms
  and conditions of the license of that module. An independent module is a
  module which is not derived from or based on this library. If you modify
  this library, you may extend this exception to your version of the library,
  but you are not obligated to do so. If you do not wish to do so, delete this
  exception statement from your version.
 
  This program is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  for more details.
 
  You should have received a copy of the GNU Library General Public License
  along with this library; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
}

 
program ultrasonic;
 
uses sysutils, pascalio, fpgpio, baseunix, math;
 
const
  GPIO_TRIGGER = 52;  // pin #24 on orange pi 5
  GPIO_ECHO    = 35;  // pin #26 on orange pi 5
 
var
  trigger  : TGpioPin;
  echo     : TGpioPin;
  distance : Double;
 
procedure DoSigInt(sig: cint); cdecl;
begin
  Writeln('Signal ', sig, ' received.');
  raise Exception.Create('Signal received.');
end;
 
function MeasureDistance: Double;
var
  StartTime: TDateTime;
  StopTime: TDateTime;
  TimeElapsed: Extended;
begin
  trigger.Value := True;
  WriteLn(ErrOutput, 'TRIGGER set to: ', trigger.Value);
  Sleep(100);
  trigger.Value := False;
  WriteLn(ErrOutput, 'TRIGGER set to: ', trigger.Value);
 
  StartTime := Now;
 
  while not echo.Value do
    StartTime := Now;
 
  while echo.Value do
    StopTime := Now;
 
  TimeElapsed := StopTime - StartTime;
  Writeln(ErrOutput, '  StartTime: ', StartTime);
  Writeln(ErrOutput, '   StopTime: ', StopTime);
  Writeln(ErrOutput, 'TimeElapsed: ', TimeElapsed);
  Writeln(ErrOutput, 'TimeElapsed: ', TimeElapsed *24*60*60*(10**6),'us');
 
  Result := TimeElapsed * 24 * 60 * 60 * (10 ** 6) / 58;// 34300 / 2;
end;
 
begin
 
// Signal handler for SIG_INT (CTRL+C)
  FpSignal(SIGINT, @DoSigInt);
 
 
// setup GPIO pins
  trigger := TGpioLinuxPin.Create(GPIO_TRIGGER);
  trigger.Direction := gdOut;
  echo    := TGpioLinuxPin.Create(GPIO_ECHO   );
  echo.Direction    := gdIn;
 
  try
    while True do
    begin
      distance := MeasureDistance;
      Writeln(Format('Measured Distance = %4.2f cm', [distance]));
      FpSleep(1);
    end;
  except
    on Exception do
      WriteLn(ErrOutput, 'Terminated');
  end;
 
  trigger.Free;
  echo.Free;
end.


==  ABOVE HERE, IT PRODUCES BAD RESULT =========

========================================================================================
==   BELOW HERE,  IT PRODUCES GOOD RESULT WITH NEW MODIFIED TIME ROUTINES  ===

 

program opi5_hc_sr04;  // Modified by Henry Kim

uses sysutils, pascalio, fpgpio, baseunix, unix, math;

const
   GPIO_TRIGGER = 52;
   GPIO_ECHO    = 35;

var
   trigger  : TGpioPin;
   echo     : TGpioPin;
   distance : Double;

procedure  millisecondSleep(const ms : real); // uses BaseUnix
   var
     
// .1 millisecond level sleep (warning 70 microsecond overhead)
      Reqested, Remaining : TimeSpec;
      ResultVal : Longint;
      NanoSecondVal : LongInt;
      ErrorOverhead : LongInt = 70000;  // 70 microsecond overhead
begin
  
// 1 milisecond = 1,000,000 nano second
   NanoSecondVal := round(ms * 1000000 - ErrorOverhead);
  
// Here, enter time to sleep (seconds + nanoseconds)
   with Reqested do begin
      tv_sec  := 0;
      tv_nsec := NanoSecondVal; // 200 microseconds = .2 milliseconds
   end;

  
// Sleep
   ResultVal:=(fpNanoSleep(@Reqested,@Remaining));

   if ResultVal <> 0 then begin
      writeln('Remaining nanoseconds : ',Remaining.tv_nsec);
      writeln('Remaining seconds     : ',Remaining.tv_sec);
   end;
end;

procedure DoSigInt(sig: cint); cdecl;
begin
   Writeln('Signal ', sig, ' received.');
   raise Exception.Create('Signal received.');
end;

function MeasureDistance: Double;
   var
      StartTime: TDateTime;
      StopTime: TDateTime;
      TimeElapsed: Extended;

      tvprev, tvcur : timeval;  // for fpgettimeofday
      microgap : Longint;
begin
   trigger.Value := True;
  
//WriteLn(ErrOutput, 'TRIGGER set to: ', trigger.Value);
   // Sleep(100);

   millisecondSleep(10);
   trigger.Value := False;
  
//WriteLn(ErrOutput, 'TRIGGER set to: ', trigger.Value);

   StartTime := Now;

   while not echo.Value do
     
// StartTime := Now;
      fpgettimeofday(@tvprev, nil);

   while echo.Value do
     
// StopTime := Now;
      fpgettimeofday(@tvcur, nil); // get timestamp AFTER sleep

  
// Get the gap only for microseconds which is my interest point.
   microgap := tvcur.tv_usec - tvprev.tv_usec;

  
// TimeElapsed := StopTime - StartTime;

{  Writeln(ErrOutput, '  StartTime: ', StartTime);
   Writeln(ErrOutput, '   StopTime: ', StopTime);
   Writeln(ErrOutput, 'TimeElapsed: ', TimeElapsed);
   Writeln(ErrOutput, 'TimeElapsed: ', TimeElapsed *24*60*60*(10**6),'us');
}
  
// Result := TimeElapsed * 24 * 60 * 60 * (10 ** 6) / 58;// 34300 / 2;
   Result := microgap / 60;
end;

begin
  
// Signal handler for SIG_INT (CTRL+C)
   FpSignal(SIGINT, @DoSigInt);

  
// setup GPIO pins
   trigger := TGpioLinuxPin.Create(GPIO_TRIGGER);
   trigger.Direction := gdOut;
   echo    := TGpioLinuxPin.Create(GPIO_ECHO   );
   echo.Direction    := gdIn;

   try
      while True do begin
         distance := MeasureDistance;
         Writeln(Format('Measured Distance = %4.2f cm', [distance]));
        
//FpSleep(1);
         Sleep(200);
      end;
   except
      on Exception do
         WriteLn(ErrOutput, 'Terminated');
   end;

   trigger.Free;
   echo.Free;
end.