code.py
  1  # SPDX-FileCopyrightText: 2018 Mikey Sklar for Adafruit Industries
  2  #
  3  # SPDX-License-Identifier: MIT
  4  
  5  """
  6  This Code uses the:
  7  * Adafruit LCD backpack using MCP23008 I2C expander
  8  * Maxbotic LV-EZ1 Ultrasonic Sensor
  9  
 10  Tested with the Trinket M0
 11  The ultrasonic sensor and pin use should be Gemma M0 compatible
 12  This sketch reads the LV-EZ1 by pulse count
 13  Then prints the distance to the LCD and python console
 14  
 15  The circuit:
 16  * 5V to Trinket M0 USB or BAT pin, I2C Backpack 5V and EZ1 +5
 17  * GND to Trinket M0 GND pin, I2C Backpack GND and EZ1 GND
 18  * Display I2C Backpack SLK to Trinket GPIO #2
 19  * Display I2C backpack SDA to Trinket GPIO #0
 20  * LV-EZ1 Ultrasonic Sensor PW pin to Trinket GPIO #1
 21  * Backlight can be hard wired by connecting LCD pin 16, 17 or 18 to GND
 22  """
 23  
 24  import time
 25  
 26  import adafruit_character_lcd
 27  import board
 28  import busio
 29  import pulseio
 30  
 31  ez1pin = board.D1  # Trinket GPIO #1
 32  
 33  # i2c LCD initialize bus and class
 34  i2c = busio.I2C(board.SCL, board.SDA)
 35  cols = 16
 36  rows = 2
 37  lcd = adafruit_character_lcd.Character_LCD_I2C(i2c, cols, rows)
 38  
 39  # calculated mode or median distance
 40  mode_result = 0
 41  
 42  # pulseio can store multiple pulses
 43  # read in time for pin to transition
 44  samples = 18
 45  pulses = pulseio.PulseIn(board.D1, maxlen=samples)
 46  
 47  # sensor reads which are in range will be stored here
 48  rangevalue = [0, 0, 0, 0, 0, 0, 0, 0, 0]
 49  
 50  # 25ms sensor power up pause
 51  time.sleep(.25)
 52  
 53  
 54  def tof_cm(time_of_flight):
 55      """
 56      EZ1 ultrasonic sensor is measuring "time of flight"
 57      Converts time of flight into distance in centimeters
 58      """
 59      convert_to_cm = 58
 60      cm = time_of_flight / convert_to_cm
 61  
 62      return cm
 63  
 64  
 65  def tof_inches(time_of_flight):
 66      """
 67      EZ1 ultrasonic sensor is measuring "time of flight"
 68      Converts time of flight into distance in inches
 69      """
 70      convert_to_inches = 147
 71      inches = time_of_flight / convert_to_inches
 72  
 73      return inches
 74  
 75  
 76  def find_mode(x):
 77      """
 78      find the mode (most common value reported)
 79      will return median (center of sorted list)
 80      should mode not be found
 81      """
 82      n = len(x)
 83  
 84      if n == 0:  # If somehow there is a null array
 85          return 0
 86  
 87      if n == 1:       # In trivial case of a one element array
 88          return x[0]  # just return the element as the mode.
 89  
 90      max_count = 0
 91      mode = 0
 92      bimodal = 0
 93      counter = 0
 94      index = 0
 95  
 96      while index < (n - 1):
 97          prev_count = counter
 98          counter = 0
 99  
100          while (x[index]) == (x[index + 1]):
101              counter += 1
102              index += 1
103  
104          if (counter > prev_count) and (counter > max_count):
105              mode = x[index]
106              max_count = counter
107              bimodal = 0
108  
109          if counter == 0:
110              index += 1
111  
112          # If the dataset has 2 or more modes.
113          if counter == max_count:
114              bimodal = 1
115  
116          # Return the median if there is no mode.
117          if (mode == 0) or (bimodal == 1):
118              mode = x[int(n / 2)]
119  
120          return mode
121  
122  
123  while True:
124  
125      # wait between samples
126      time.sleep(.5)
127  
128      if len(pulses) == samples:
129          j = 0  # rangevalue array counter
130  
131          # only save the values within range
132          # range readings take 49mS
133          # pulse width is .88mS to 37.5mS
134          for i in range(0, samples):
135              tof = pulses[i]  # time of flight - PWM HIGH
136  
137              if 880 < tof < 37500:
138                  if j < len(rangevalue):
139                      rangevalue[j] = tof_cm(tof)
140                      j += 1
141  
142          # clear pulse samples
143          pulses.clear()  # clear all values in pulses[]
144  
145          # sort samples
146          rangevalue = sorted(rangevalue)
147  
148          # returns mode or median
149          mode_result = int(find_mode(rangevalue))
150  
151          # python console prints both centimeter and inches distance
152          cm2in = .393701
153          mode_result_in = mode_result * cm2in
154          print(mode_result, "cm", "\t\t", int(mode_result_in), "in")
155  
156          # result must be in char/string format for LCD printing
157          digit_string = str(mode_result)
158  
159          lcd.clear()
160          lcd.message("Range: ")  # write to LCD
161          lcd.message("    ")
162          lcd.message(digit_string)
163          lcd.message("cm")
164  
165          time.sleep(2)