165 lines
4 KiB
Python
165 lines
4 KiB
Python
# SPDX-FileCopyrightText: 2018 Mikey Sklar for Adafruit Industries
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
"""
|
|
This Code uses the:
|
|
* Adafruit LCD backpack using MCP23008 I2C expander
|
|
* Maxbotic LV-EZ1 Ultrasonic Sensor
|
|
|
|
Tested with the Trinket M0
|
|
The ultrasonic sensor and pin use should be Gemma M0 compatible
|
|
This sketch reads the LV-EZ1 by pulse count
|
|
Then prints the distance to the LCD and python console
|
|
|
|
The circuit:
|
|
* 5V to Trinket M0 USB or BAT pin, I2C Backpack 5V and EZ1 +5
|
|
* GND to Trinket M0 GND pin, I2C Backpack GND and EZ1 GND
|
|
* Display I2C Backpack SLK to Trinket GPIO #2
|
|
* Display I2C backpack SDA to Trinket GPIO #0
|
|
* LV-EZ1 Ultrasonic Sensor PW pin to Trinket GPIO #1
|
|
* Backlight can be hard wired by connecting LCD pin 16, 17 or 18 to GND
|
|
"""
|
|
|
|
import time
|
|
|
|
import adafruit_character_lcd
|
|
import board
|
|
import busio
|
|
import pulseio
|
|
|
|
ez1pin = board.D1 # Trinket GPIO #1
|
|
|
|
# i2c LCD initialize bus and class
|
|
i2c = busio.I2C(board.SCL, board.SDA)
|
|
cols = 16
|
|
rows = 2
|
|
lcd = adafruit_character_lcd.Character_LCD_I2C(i2c, cols, rows)
|
|
|
|
# calculated mode or median distance
|
|
mode_result = 0
|
|
|
|
# pulseio can store multiple pulses
|
|
# read in time for pin to transition
|
|
samples = 18
|
|
pulses = pulseio.PulseIn(board.D1, maxlen=samples)
|
|
|
|
# sensor reads which are in range will be stored here
|
|
rangevalue = [0, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
|
|
# 25ms sensor power up pause
|
|
time.sleep(.25)
|
|
|
|
|
|
def tof_cm(time_of_flight):
|
|
"""
|
|
EZ1 ultrasonic sensor is measuring "time of flight"
|
|
Converts time of flight into distance in centimeters
|
|
"""
|
|
convert_to_cm = 58
|
|
cm = time_of_flight / convert_to_cm
|
|
|
|
return cm
|
|
|
|
|
|
def tof_inches(time_of_flight):
|
|
"""
|
|
EZ1 ultrasonic sensor is measuring "time of flight"
|
|
Converts time of flight into distance in inches
|
|
"""
|
|
convert_to_inches = 147
|
|
inches = time_of_flight / convert_to_inches
|
|
|
|
return inches
|
|
|
|
|
|
def find_mode(x):
|
|
"""
|
|
find the mode (most common value reported)
|
|
will return median (center of sorted list)
|
|
should mode not be found
|
|
"""
|
|
n = len(x)
|
|
|
|
if n == 0: # If somehow there is a null array
|
|
return 0
|
|
|
|
if n == 1: # In trivial case of a one element array
|
|
return x[0] # just return the element as the mode.
|
|
|
|
max_count = 0
|
|
mode = 0
|
|
bimodal = 0
|
|
counter = 0
|
|
index = 0
|
|
|
|
while index < (n - 1):
|
|
prev_count = counter
|
|
counter = 0
|
|
|
|
while (x[index]) == (x[index + 1]):
|
|
counter += 1
|
|
index += 1
|
|
|
|
if (counter > prev_count) and (counter > max_count):
|
|
mode = x[index]
|
|
max_count = counter
|
|
bimodal = 0
|
|
|
|
if counter == 0:
|
|
index += 1
|
|
|
|
# If the dataset has 2 or more modes.
|
|
if counter == max_count:
|
|
bimodal = 1
|
|
|
|
# Return the median if there is no mode.
|
|
if (mode == 0) or (bimodal == 1):
|
|
mode = x[int(n / 2)]
|
|
|
|
return mode
|
|
|
|
|
|
while True:
|
|
|
|
# wait between samples
|
|
time.sleep(.5)
|
|
|
|
if len(pulses) == samples:
|
|
j = 0 # rangevalue array counter
|
|
|
|
# only save the values within range
|
|
# range readings take 49mS
|
|
# pulse width is .88mS to 37.5mS
|
|
for i in range(0, samples):
|
|
tof = pulses[i] # time of flight - PWM HIGH
|
|
|
|
if 880 < tof < 37500:
|
|
if j < len(rangevalue):
|
|
rangevalue[j] = tof_cm(tof)
|
|
j += 1
|
|
|
|
# clear pulse samples
|
|
pulses.clear() # clear all values in pulses[]
|
|
|
|
# sort samples
|
|
rangevalue = sorted(rangevalue)
|
|
|
|
# returns mode or median
|
|
mode_result = int(find_mode(rangevalue))
|
|
|
|
# python console prints both centimeter and inches distance
|
|
cm2in = .393701
|
|
mode_result_in = mode_result * cm2in
|
|
print(mode_result, "cm", "\t\t", int(mode_result_in), "in")
|
|
|
|
# result must be in char/string format for LCD printing
|
|
digit_string = str(mode_result)
|
|
|
|
lcd.clear()
|
|
lcd.message("Range: ") # write to LCD
|
|
lcd.message(" ")
|
|
lcd.message(digit_string)
|
|
lcd.message("cm")
|
|
|
|
time.sleep(2)
|