8. sonar.py
ModuleΒΆ
In the previous project, we learned how the sonar scanner detects obstacles. That is the servo is turned from left to right and the ultrasonic module detects every specific angle, then several sets of distance values are output at once.
However, this kind of data is not very convenient for calculation, so in practice, we can set a threshold value, and then compare the detected distance against this threshold value, and then output a 0
or 1
.
In this way, we encapsulate the sonar scanning code into a library and then add more calculations to it, so that it can be easily imported for use in the project.
Note
The final encapsulated library sonar.py
has been saved in pico_4wd_car-v2.0\libs
, which may differ from the ones shown in the course, so please refer to the file under libs
path when using it.
You can learn how sonar.py
is encapsulated in the following steps.
1. Determine if there are obstacles
Most of the time, the car only needs to know whether there are obstacles in all directions.
So here set a distance threshold with the variable
SONAR_REFERENCE
.And then create the function
get_sonar_status()
to determine if the distance is greater than the threshold, then output1
, otherwise output0
.Then output the processed data at once, and you get array like this
[1, 0, 0, 1, 1, 1, 1]
.from servo import Servo from ultrasonic import Ultrasonic import time servo = Servo(18) ultrasonic = Ultrasonic(6, 7) sonar_angle = 0 sonar_step = 30 SONAR_MAX_ANGLE = 90 SONAR_MIN_ANGLE = -90 SONAR_REFERENCE = 20 sonar_data =[] for i in range((SONAR_MAX_ANGLE-SONAR_MIN_ANGLE)/sonar_step+1): sonar_data.append(None) def get_distance_at(angle): global sonar_angle sonar_angle = angle servo.set_angle(sonar_angle) #time.sleep(0.04) distance = ultrasonic.get_distance() if distance < 0: return -1 else: return distance def sonar_move(): global sonar_angle, sonar_step if sonar_angle >= SONAR_MAX_ANGLE: sonar_angle = SONAR_MAX_ANGLE sonar_step = -abs(sonar_step) elif sonar_angle <= SONAR_MIN_ANGLE: sonar_angle = SONAR_MIN_ANGLE sonar_step = abs(sonar_step) sonar_angle += sonar_step def get_sonar_status(distance): if distance > SONAR_REFERENCE or distance < 0: return 1 else: return 0 def mapping(x, in_min, in_max, out_min, out_max): return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min def sonar_scan(): global sonar_data sonar_move() distance = get_distance_at(sonar_angle) index= int(mapping(sonar_angle, SONAR_MIN_ANGLE, SONAR_MAX_ANGLE, 0, len(sonar_data)-1)) status=get_sonar_status(distance) sonar_data[index]=status return sonar_data while True: print(sonar_scan()) time.sleep(0.1)
2. Get complete data before judging
Additionally, if we use
sonar_data
directly for obstacle determination, the data on the left becomes an interference item when the left side obstacle disappears and the sonar scans the right side.It makes more sense to determine an obstacle after a sonar cycle has been scanned and complete data has been collected.
... ... def get_distance_at(angle): ... def sonar_move(): ... def get_sonar_status(distance): ... def mapping(x, in_min, in_max, out_min, out_max): ... def sonar_scan(): global sonar_data sonar_move() distance = get_distance_at(sonar_angle) index=int(mapping(sonar_angle, SONAR_MIN_ANGLE, SONAR_MAX_ANGLE, 0, len(sonar_data)-1)) status=get_sonar_status(distance) sonar_data[index]=status if (index == 0 or index == len(sonar_data)-1) and None not in sonar_data: return sonar_angle,distance,sonar_data else: return sonar_angle,distance,status while True: _,_,result = sonar_scan() if type(result) is not int: print(result) time.sleep(0.1)
3. Further optimization
In order to be compatible with more complex programs, we created two more functions to modify the rotation rules and distance determination of the sonar.
... ... def get_distance_at(angle): ... def sonar_move(): ... def get_sonar_status(distance): ... def mapping(x, in_min, in_max, out_min, out_max): ... def sonar_scan(): ... def set_sonar_scan_config(scan_range=None,step=None): global SONAR_MAX_ANGLE, SONAR_MIN_ANGLE, sonar_angle, sonar_step, sonar_data # update changed item = 0 if scan_range is None or scan_range is SONAR_MAX_ANGLE-SONAR_MIN_ANGLE: item+=1 else: SONAR_MAX_ANGLE = int(scan_range / 2) SONAR_MIN_ANGLE = SONAR_MAX_ANGLE-scan_range if step is None or abs(sonar_step) is abs(step): item+=1 else: sonar_step=int(step) if item is 2: # if nothing change, return return # re-create the data list sonar_data =[] for i in range(scan_range/abs(sonar_step) +1): sonar_data.append(None) sonar_angle=0 servo.set_angle(sonar_angle) def set_SONAR_REFERENCE(ref): global SONAR_REFERENCE SONAR_REFERENCE = int(ref) if __name__ == '__main__': try: set_sonar_scan_config(180,30) set_SONAR_REFERENCE(20) while True: _,_,status = sonar_scan() if type(status) is not int: print(status) time.sleep(0.1) finally: servo.set_angle(0)