Ultrasonic scanner (Part 2)

Part 1, 2

Most of the electronic diagram shown here should look familiar to the readers of arduinoos posts. The ultrasonic sensor is added to what was described as the test bench for stepper motors.

ultrasound-scanner_1

Here is the list of the required components:

  • An Arduino UNO baord (Should I introduce it to you ?)
    • A bread board featuring a switching voltage regulator
    • A stepper motor driver (in this case a A4988)
  • A stepper motor (Cheap 5 V, 1024 steps per turn stepper motor)
  • A 3D printed base plate and a 3D printed wheel
  • A 12 V DC power supply which current rating is compatible with the stepper motor (Do  not expect to feed the stepper through the USB 5 V!)
  • A HC-SR04 ultrasonic sensor.

Running the whole assembly requires some lines of code. This code features specific commands for the HC-SR04: any working library will do the job. The rest is a mix of stepper motor driving functions and some maths.

Next is an extract from the header section of the sketch:

/* Create objects */
/* Change parameters according to hardware configuration */
PlainHCSR04 SONAR; /* Create an instance of the SONAR object */
const uint32_t _oneSecond = 1000000; /* In us */
uint16_t _frequency = 500; /* Rotational speed */
const uint8_t _pulseDelay = 1; /* In us */
const uint16_t _motorStepsPerRound = 1024;
const float _sweepRad = (TWO_PI / 1.0); 
const float _sweepRadResolution = (TWO_PI / 90.0); 
const uint16_t _motorStepsPerSweepStep = uint16_t((_motorStepsPerRound * _sweepRadResolution) / TWO_PI);
const uint8_t _ultraSoundSensorSamples = 4;
const uint16_t _stabilizationDelay = 10; /* In ms */
/* Direction port and pin */
volatile uint8_t *_dirCtrlPort = &PORTB;
const uint8_t _directionPinMask = (1 << PINB0);
/* Pulse port and pin */
volatile uint8_t *_stepCtrlPort = &PORTB;
const uint8_t _stepPinMask = ( 1 << PINB1);  
/* Enable port and pin */
volatile uint8_t *_enablePort = &PORTB;
const uint8_t _enablePinMask = ( 1 << PINB2);  

Check some of the critical variables:

  • _frequency set the rotational speed
  • _motorStepsPerRound defines the number of steps per round (1024 in my case)
  • _sweepRad defines the full rotational swing for each scan
  • _sweepRadResolution defines the rotational angle between two distance measurements
  • _ultraSoundSensorSamples defines the number of samples acquired for each distance measurements: the more samples the better the accuracy, the longer the measurement time

The set section initializes the ultrasonic sensor and the stepper motor driver:

void setup(void) 
{
	Serial.begin(115200);
	SONAR.HCSR04Initialization(&PORTD, 6, 7);
	/* Set direction ports and pins */
	*(_enablePort - 1) |= _enablePinMask; /* EnableStepper pin */
	*(_enablePort) |= _enablePinMask; /* Disable driver */
	*(_dirCtrlPort - 1) |= _directionPinMask;
	*(_dirCtrlPort) |= _directionPinMask; /* Set default direction */
	*(_stepCtrlPort - 1) |= _stepPinMask; /* Set pin direction */
	*(_stepCtrlPort) &= ~_stepPinMask; /* Set default pin state to LOW */	
	while(Serial.available()) {
		Serial.read(); /* Empty buffer */
	}
}

And here is the loop section which is executed any time any character is entered on the console. The console outputs the data acquired during a whole scan:

void loop(void) 
{
	if (Serial.available()) {
		while(Serial.available()) {
			Serial.read(); /* Empty buffer */
		}
		EnableStepper(1);
		float totalSweepRad = 0.0;
		uint16_t sweepSteps = 0;
		/* Sweep forward */
		do {
			/* Wait for stabilization before acquiring data */
			delay(_stabilizationDelay);
			/* Acquire distance */
			float distance = (SONAR.Distance(_ultraSoundSensorSamples) / 1000.0);
			/* Rotate stepper forward to next sub division */
			RotateStepper(1, _motorStepsPerSweepStep);
			/* Compute angle and cartesian coordinates */
			float x = (sin(totalSweepRad) * distance);
			float y = (cos(totalSweepRad) * distance);
			/* Upload data */
			Serial.print(sweepSteps);
			Serial.print(';');
			Serial.print(totalSweepRad, 3);
			Serial.print(';');
			Serial.print(distance, 3);
			Serial.print(';');
			Serial.print(x, 3);
			Serial.print(';');
			Serial.print(y, 3);
			Serial.println();
			/* Update variables */
			sweepSteps += 1;
			totalSweepRad = (_sweepRadResolution * sweepSteps);
		} while (totalSweepRad <= _sweepRad);
		/* Sweep back */
		RotateStepper(0, (_motorStepsPerSweepStep * sweepSteps));
		EnableStepper(0);
	}
}

The console will output fields delimited with a semi-colon. The first field contains the measurement index. Next two fields are the polar coordinates (angle and distance) while the newt two fields contain the Cartesian coordinates (so as to say x and y). In this way, it is easy to build a graph out of the acquired data such as this one, using any spreadsheet editor:

scanner_6

Enjoy !

 

 

Leave a Reply

You must be logged in to post a comment.