Intelligent obstacle detection

There is an alternative design for the Joy-Car's ultrasonic sensor that enables intelligent obstacle detection. The ultrasonic sensor is mounted on a servomotor, which allows the sensor to move to the left and right.

This design significantly extends the functionality of the ultrasonic sensor, as it can not only measure the distance directly in front of the Joy-Car, but also detect obstacles in a wider field of view. The servo motor can rotate the sensor to different angles, creating a kind of “radar scan”. This method improves the Joy-Car's navigation and obstacle avoidance and is particularly suitable for applications where a more precise perception of the surroundings is required.

In the following code example, an intelligent obstacle avoidance system is implemented in which a servomotor and an ultrasonic sensor work together. The ultrasonic sensor is mounted on a servomotor that can move in different directions. This enables the sensor to detect obstacles at different angles by taking regular measurements.

As soon as the ultrasonic sensor detects an obstacle in a certain direction, the corresponding direction is visualized on the LED matrix of the micro:bit. This provides an intuitive display showing which direction the obstacle is coming from. The movements of the servo motor and the measurements of the sensor are controlled synchronously to ensure efficient coverage of the entire area.

The example is programmed to detect obstacles in the left, right or middle area and display these directions on the LED matrix using corresponding symbols or patterns. The implementation includes the control of the servo motor, the acquisition of distance measurements and the processing of the results to enable a real-time display of the obstacles.

Intelligent obstacle detection

This function returns a value that indicates whether something was detected and also from which direction the obstacle was detected.

 

Return value Direction
0 nothing recognized
1 left
2 front
3 right

Code example

let orientation = 0
JoyCar.initJoyCar(RevisionMainboard.OnepThree)
basic.forever(function () {
    orientation = JoyCar.collisionDetection()
    if (orientation == 1) {
        basic.showLeds(`
            . # . . .
            . # . . .
            . # . . .
            . # . . .
            . # # # .
            `)
    } else if (orientation == 2) {
        basic.showLeds(`
            # . . . #
            # # . # #
            # . # . #
            # . . . #
            # . . . #
            `)
    } else if (orientation == 3) {
        basic.showLeds(`
            . # # # .
            . # . # .
            . # # # .
            . # # . .
            . # . # .
            `)
    } else if (orientation == 0) {
        basic.showLeds(`
            . . . . .
            . . . . .
            . . . . .
            . . . . .
            . . . . .
            `)
    }
})

Intelligent obstacle detection

This function returns a value that indicates whether something was detected and also from which direction the obstacle was detected.

 

Return value Direction
0 nothing recognized
1 left
2 front
3 right

 

# Method for intelligent obstacle detection
# Variable for the method to compare when the servo last moved
last_obstcl_act = running_time()
# Array with possible servo positions & index
servo_pos = [0, 45, 90, 135, 180]
servo_pos_index = 0
def intelligent_detection():
    # to be able to change the global variable
    global last_obstcl_act, servo_pos_index
    # Activate garbage collector
    gc.collect()
    # Activation/deactivation of the servo after 500 ms
    if running_time() - last_obstcl_act >= 500:
        # increase index
        servo_pos_index += 1
        # If the index exceeds the length of the array, reset the index
        if servo_pos_index == len(servo_pos):
            servo_pos_index = 0
        # Move servo into position
        servo(1,servo_pos[servo_pos_index])
        sleep(200)
        # Set global variable to current runtime
        last_obstcl_act = running_time()
    # Measure distance with ultrasonic sensor
    distance = get_distance()
    # If distance is less than 20 cm
    if distance < 20:
        # if this happens on the right side return 3
        if servo_pos_index == 0 or servo_pos_index == 1:
            return 3
        # if this happens in the middle return 2
        elif servo_pos_index == 2:
            return 2
        # if this happens on the left side return 1
        else:
            return 1
    # If nothing is recognized, return 0
    else:
        return 0

Code example

# Import necessary libraries
from microbit import *
import gc
from machine import time_pulse_us

# Define your Joy-Car mainboard revision
joycar_rev = 1.3

# Initialization of the I2C interface for the Joy-Car mainboard
i2c.init(freq=400000, sda=pin20, scl=pin19)

# Set up pins for servomotor
pin1.set_analog_period(10)
pin13.set_analog_period(10)

# Define pins for ultrasonic sensor
trigger = pin8
echo = pin12

# Initialization of the pins for the ultrasonic sensor
trigger.write_digital(0)
echo.read_digital()

# Method for calculating the distance from the ultrasonic sensor
def get_distance():
    # Activate garbage collector
    gc.collect()
    # Set a short pulse on the trigger pin
    trigger.write_digital(1)
    trigger.write_digital(0)
    # Measurement of the time until the echo pin becomes high
    duration = time_pulse_us(echo, 1)
    # Calculate distance
    distance = ((duration / 1000000) * 34300) / 2
    # Return the distance, rounded to 2 decimal places
    return round(distance, 2)

# Method for changing the position of servomotors
def servo(channel, position):
    # Method for scaling from 0-180 (°) to 100-200 (us)
    def scale(num, in_min, in_max, out_min, out_max):
        # Return the value rounded to a whole number
        return (round((num - in_min) * (out_max - out_min) /
                (in_max - in_min) + out_min))
    # Check whether the position is within the range
    if position < 0 and position > 180:
        return "position not in range"
    # Send position to the selected channel
    if channel == 1:
        pin1.write_analog(scale(position, 0, 180, 100, 200))
    elif channel == 2:
        pin13.write_analog(scale(position, 0, 180, 100, 200))

# Method for intelligent obstacle detection
# Variable for the method to compare when the servo last moved
last_obstcl_act = running_time()
# Array with possible servo positions & index
servo_pos = [0, 45, 90, 135, 180]
servo_pos_index = 0
def intelligent_detection():
    # to be able to change the global variable
    global last_obstcl_act, servo_pos_index
    # Activate garbage collector
    gc.collect()
    # Activation/deactivation of the servo after 500 ms
    if running_time() - last_obstcl_act >= 500:
        # increase index
        servo_pos_index += 1
        # If the index exceeds the length of the array, reset the index
        if servo_pos_index == len(servo_pos):
            servo_pos_index = 0
        # Move servo into position
        servo(1,servo_pos[servo_pos_index])
        sleep(200)
        # Set global variable to current runtime
        last_obstcl_act = running_time()
    # Measure distance with ultrasonic sensor
    distance = get_distance()
    # If distance is less than 20 cm
    if distance < 20:
        # if this happens on the right side return 3
        if servo_pos_index == 0 or servo_pos_index == 1:
            return 3
        # if this happens in the middle return 2
        elif servo_pos_index == 2:
            return 2
        # if this happens on the left side return 1
        else:
            return 1
    # If nothing is recognized, return 0
    else:
        return 0


# Define images to be displayed on the LED matrix
left = Image("09000:"
              "09000:"
              "09000:"
              "09000:"
              "09990")
middle = Image("90009:"
             "99099:"
             "90909:"
             "90009:"
             "90009")
right = Image("09990:"
              "09090:"
              "09990:"
              "09900:"
              "09090")
none = Image("00000:"
              "00000:"
              "00000:"
              "00000:"
              "00000")

while True:
    # Call up intelligent obstacle detection and save return value
    orientation = intelligent_detection()
    # if no obstacle is detected
    if orientation == 0:
        display.show(none)
    # if an obstacle is detected on the left
    elif orientation == 1:
        display.show(left)
    # if an obstacle is detected at the front
    elif orientation == 2:
        display.show(middle)
    # if an obstacle is detected on the right
    elif orientation == 3:
        display.show(right)
    sleep(500)