Several changes to dimensioner hardware and software

This commit is contained in:
Skylar Ittner 2025-04-20 11:15:21 -06:00
parent 584da34666
commit 3c98242a82
10 changed files with 259 additions and 187 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

77
src/dimensioner/config.py Normal file
View File

@ -0,0 +1,77 @@
# Copyright 2025 PostalPortal LLC and Netsyms Technologies LLC
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that
# the following conditions are met:
# 1. Redistributions of source code must retain
# the above copyright notice, this list of conditions
# and the following disclaimer.
# 2. Redistributions in binary form must reproduce
# the above copyright notice, this list of conditions
# and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder
# nor the names of its contributors may be used
# to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
# CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
#
# Hardware configuration
#
SENSOR_TYPE = "US-100" # "PING" for Parallax PING))) or "US-100" for US-100
SENSOR_MAX_MM = 3000 # Maximum range sensor supports and is accurate within
SENSOR_MIN_MM = 100 # Minimum range below which sensor is not accurate
SENSOR_PIN = 17 # Analog pin for PING sensor
SENSOR_TX = 16 # Digital pin for US-100
SENSOR_RX = 17 # Digital pin for US-100
UART_ID = 0 # TX/RX: UART 0: 12/13, 16/17; UART 1: 4/5, 8/9
ZERO_RANGE_MM = 10 # +/- mm away from zero before a non-zero value is transmitted
SAMPLE_SIZE = 10 # Number of times to sample distance per reading, averaging the results
UNSTABLE_DELTA_MM = 50 # Max difference between largest and smallest samples (before averaging), larger than this will report as unstable
ZERO_BUTTON_PIN = 13 # Pin to read if hardware zero button is pressed
UNITS_BUTTON_PIN = 14 # Pin to read if hardware unit change button is pressed
FIRMWARE_VERSION = "1.0"
#
# USB configuration
#
VID = 0x1209 # USB Vendor ID
PID = 0xA002 # USB Product ID
MANU = "PostalPortal LLC" # USB manufacturer string
PROD = "PostalPoint Parcel Dimensioner" # USB product string
INTERFACE = "PostalPoint" # Interface string
USBHID_ENABLED = True # Disable USB, use serial output only (good for debugging)
#
# Display configuration
#
ENABLE_DISPLAY = True # Set to False to ignore display commands
DISPLAY_WIDTH = 128
DISPLAY_HEIGHT = 64
# Available pin combinations for I2C:
# I2C 0 SDA: GP0/GP4/GP8/GP12/GP16/GP20
# I2C 0 SCL: GP1/GP5/GP9/GP13/GP17/GP21
# I2C 1 SDA: GP2/GP6/GP10/GP14/GP18/GP26
# I2C 1 SCL: GP3/GP7/GP11/GP15/GP19/GP27
# Just don't conflict with the pin assignments for the sensor and buttons!
DISPLAY_SDA_PIN = 6
DISPLAY_SCL_PIN = 7
DISPLAY_I2C_CONTROLLER = 1
ENABLE_BUTTON_LEGEND = True # If true, will display onscreen labels for two buttons on the left side of the screen: top button zeros, bottom button changes units

View File

@ -42,19 +42,7 @@ from time import sleep_ms
from ssd1306big import setOLED, line1, line2 from ssd1306big import setOLED, line1, line2
import framebuf import framebuf
import math import math
from config import *
ENABLE_DISPLAY = True # Set to False to ignore display commands
DISPLAY_WIDTH = 128
DISPLAY_HEIGHT = 64
# Available pin combinations for I2C:
# I2C 0 SDA: GP0/GP4/GP8/GP12/GP16/GP20
# I2C 0 SCL: GP1/GP5/GP9/GP13/GP17/GP21
# I2C 1 SDA: GP2/GP6/GP10/GP14/GP18/GP26
# I2C 1 SCL: GP3/GP7/GP11/GP15/GP19/GP27
# Just don't conflict with the pin assignments for the sensor and buttons!
DISPLAY_SDA_PIN = 6
DISPLAY_SCL_PIN = 7
DISPLAY_I2C_CONTROLLER = 1
i2c = I2C(DISPLAY_I2C_CONTROLLER, sda=Pin(DISPLAY_SDA_PIN), scl=Pin(DISPLAY_SCL_PIN), freq=400000) i2c = I2C(DISPLAY_I2C_CONTROLLER, sda=Pin(DISPLAY_SDA_PIN), scl=Pin(DISPLAY_SCL_PIN), freq=400000)
oled = SSD1306_I2C(DISPLAY_WIDTH, DISPLAY_HEIGHT, i2c) oled = SSD1306_I2C(DISPLAY_WIDTH, DISPLAY_HEIGHT, i2c)
@ -62,152 +50,185 @@ oled = SSD1306_I2C(DISPLAY_WIDTH, DISPLAY_HEIGHT, i2c)
def bootDisplay(firmwareVersion): def bootDisplay(firmwareVersion):
if ENABLE_DISPLAY: if ENABLE_DISPLAY:
# Bootup dead pixel self-test try:
oled.fill(0) # Bootup dead pixel self-test
oled.show() oled.fill(0)
oled.fill(1) oled.show()
oled.show() oled.fill(1)
sleep_ms(500) oled.show()
oled.fill(0) sleep_ms(500)
oled.show() oled.fill(0)
# 128x32 PostalPoint logo bitmap oled.show()
logo = bytearray([ # 128x32 PostalPoint logo bitmap
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0x40, 0x40, 0xc0, 0x80, logo = bytearray([
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0x40, 0x40, 0xc0, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfc, 0x0e, 0x0a, 0x1a, 0x13, 0xf1, 0x19, 0x08, 0x08, 0xfc, 0xfc, 0x0c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x19, 0xf1, 0xf1, 0x1b, 0x0a, 0x0e, 0xfc, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0xfc, 0x0e, 0x0a, 0x1a, 0x13, 0xf1, 0x19, 0x08, 0x08, 0xfc, 0xfc, 0x0c, 0x08,
0x1c, 0x1c, 0x1c, 0xf8, 0xf8, 0xf0, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0x00, 0x19, 0xf1, 0xf1, 0x1b, 0x0a, 0x0e, 0xfc, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf8, 0xf8,
0x00, 0x00, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0x00, 0x00, 0x80, 0xf0, 0xf8, 0xf8, 0xe0, 0xe0, 0x1c, 0x1c, 0x1c, 0xf8, 0xf8, 0xf0, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0x00,
0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0x40, 0x00, 0x00, 0xf0, 0xfc, 0xfe, 0x0e, 0x00, 0x00, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0x00, 0x00, 0x80, 0xf0, 0xf8, 0xf8, 0xe0, 0xe0,
0x00, 0x00, 0xf0, 0xf8, 0xf8, 0x1c, 0x1c, 0x18, 0xf8, 0xf8, 0xf0, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0x40, 0x00, 0x00, 0xf0, 0xfc, 0xfe, 0x0e,
0xe0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0xc8, 0xfc, 0xfe, 0x0c, 0x00, 0xc0, 0xe0, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf8, 0xf8, 0x1c, 0x1c, 0x18, 0xf8, 0xf8, 0xf0, 0x00, 0x00, 0x80, 0xc0, 0xe0,
0xe0, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0xf0, 0xf8, 0xf8, 0xe0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0xc8, 0xfc, 0xfe, 0x0c, 0x00, 0xc0, 0xe0, 0xe0, 0xe0,
0x00, 0x00, 0x00, 0x7f, 0xc0, 0x80, 0x80, 0x80, 0x07, 0x0e, 0x0a, 0x1a, 0xf1, 0xf1, 0x1b, 0x0a, 0xe0, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0xf0, 0xf8, 0xf8, 0xe0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0e, 0x0f, 0x07, 0x80, 0x80, 0xc0, 0x7f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7f, 0x3f, 0x07, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x80, 0x80, 0x80, 0x07, 0x0e, 0x0a, 0x1a, 0xf1, 0xf1, 0x1b, 0x0a,
0x07, 0x07, 0x03, 0x03, 0x01, 0x00, 0x00, 0x1f, 0x3f, 0x7f, 0x70, 0x70, 0x38, 0x1f, 0x0f, 0x03, 0x0e, 0x0f, 0x07, 0x80, 0x80, 0xc0, 0x7f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7f, 0x3f, 0x07,
0x20, 0x71, 0x73, 0x77, 0x76, 0x3e, 0x3c, 0x08, 0x00, 0x18, 0x3f, 0x7f, 0x73, 0x70, 0x30, 0x00, 0x07, 0x07, 0x03, 0x03, 0x01, 0x00, 0x00, 0x1f, 0x3f, 0x7f, 0x70, 0x70, 0x38, 0x1f, 0x0f, 0x03,
0x0c, 0x3f, 0x7f, 0x73, 0x70, 0x30, 0x3f, 0x7f, 0x3f, 0x00, 0x00, 0x3f, 0x7f, 0x7f, 0x20, 0x00, 0x20, 0x71, 0x73, 0x77, 0x76, 0x3e, 0x3c, 0x08, 0x00, 0x18, 0x3f, 0x7f, 0x73, 0x70, 0x30, 0x00,
0x70, 0x7f, 0x7f, 0x0f, 0x07, 0x07, 0x07, 0x03, 0x03, 0x01, 0x00, 0x0c, 0x3f, 0x3f, 0x73, 0x70, 0x0c, 0x3f, 0x7f, 0x73, 0x70, 0x30, 0x3f, 0x7f, 0x3f, 0x00, 0x00, 0x3f, 0x7f, 0x7f, 0x20, 0x00,
0x70, 0x3f, 0x1f, 0x0f, 0x00, 0x70, 0x7f, 0x3f, 0x0f, 0x00, 0x20, 0x7e, 0x7f, 0x1f, 0x01, 0x20, 0x70, 0x7f, 0x7f, 0x0f, 0x07, 0x07, 0x07, 0x03, 0x03, 0x01, 0x00, 0x0c, 0x3f, 0x3f, 0x73, 0x70,
0x7f, 0x7f, 0x0f, 0x00, 0x00, 0x3f, 0x7f, 0x7f, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x3f, 0x1f, 0x0f, 0x00, 0x70, 0x7f, 0x3f, 0x0f, 0x00, 0x20, 0x7e, 0x7f, 0x1f, 0x01, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x02, 0x06, 0x07, 0x07, 0x06, 0x02, 0x7f, 0x7f, 0x0f, 0x00, 0x00, 0x3f, 0x7f, 0x7f, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x02, 0x06, 0x07, 0x07, 0x06, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
fbuf = framebuf.FrameBuffer(logo, 128, 32, framebuf.MONO_VLSB) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
oled.blit(fbuf, 0, 0, 0) fbuf = framebuf.FrameBuffer(logo, 128, 32, framebuf.MONO_VLSB)
# Show info oled.blit(fbuf, 0, 16, 0)
oled.text(" Parcel", 0, 32, 1) # Show info
oled.text(" Dimensioner", 0, 40, 1) oled.text(" Parcel", 0, 40, 1)
firmVerStr = "FW Ver " + firmwareVersion oled.text(" Dimensioner", 0, 48, 1)
oled.text(f"{firmVerStr:^16}", 0, 56, 1) firmVerStr = "FW Ver " + firmwareVersion
oled.show() oled.text(f"{firmVerStr:^16}", 0, 56, 1)
sleep_ms(1500) oled.show()
sleep_ms(1500)
except:
pass
def errorDisplay(code, message = ""): def errorDisplay(code, message = ""):
global oled global oled
if ENABLE_DISPLAY: if ENABLE_DISPLAY:
setOLED(oled) try:
oled.fill(0) setOLED(oled)
if code == 1: oled.fill(0)
line1(" ERROR! ") if code == 1:
oled.text(message, 0, 22, 2) line1(" ERROR! ")
if message == "Sensor timeout": oled.text(message, 0, 22, 2)
pass if message == "Sensor timeout":
elif code == 3: pass
line1("UNSTABLE") elif code == 3:
oled.text("Distance is not", 0, 22, 2) line1("UNSTABLE")
oled.text("stable. Waiting", 0, 30, 2) oled.text("Distance is not", 0, 22, 2)
oled.text("for it to settle", 0, 38, 2) oled.text("stable. Waiting", 0, 30, 2)
oled.text("down and stop", 0, 46, 2) oled.text("for it to settle", 0, 38, 2)
oled.text("moving around.", 0, 54, 2) oled.text("down and stop", 0, 46, 2)
elif code == 5: oled.text("moving around.", 0, 54, 2)
line1("UNDER 0!") elif code == 5:
oled.text("Object farther", 0, 22, 2) line1("UNDER 0!")
oled.text("from platform", 0, 30, 2) oled.text("Object farther", 0, 22, 2)
oled.text("than it should", 0, 38, 2) oled.text("from platform", 0, 30, 2)
oled.text("be. Check and", 0, 46, 2) oled.text("than it should", 0, 38, 2)
oled.text("re-zero.", 0, 54, 2) oled.text("be. Check and", 0, 46, 2)
elif code == 6: oled.text("re-zero.", 0, 54, 2)
line1("TOO FAR!") elif code == 6:
oled.text("Distance is too", 0, 22, 2) line1("TOO FAR!")
oled.text("far from sensor", 0, 30, 2) oled.text("Distance is too", 0, 22, 2)
oled.text("for accurate", 0, 38, 2) oled.text("far from sensor", 0, 30, 2)
oled.text("measurement.", 0, 46, 2) oled.text("for accurate", 0, 38, 2)
elif code == 7: oled.text("measurement.", 0, 46, 2)
line1("TOO NEAR") elif code == 7:
oled.text("Object is too", 0, 22, 2) line1("TOO NEAR")
oled.text("close to sensor", 0, 30, 2) oled.text("Object is too", 0, 22, 2)
oled.text("for accurate", 0, 38, 2) oled.text("close to sensor", 0, 30, 2)
oled.text("measurement.", 0, 46, 2) oled.text("for accurate", 0, 38, 2)
elif code == 8: oled.text("measurement.", 0, 46, 2)
line1("HOST ERR") elif code == 8:
oled.text("Connected PC", 0, 22, 2) line1("HOST ERR")
oled.text("sent an invalid", 0, 30, 2) oled.text("Connected PC", 0, 22, 2)
oled.text("command.", 0, 38, 2) oled.text("sent an invalid", 0, 30, 2)
elif code == 9: oled.text("command.", 0, 38, 2)
line1("BAD UNIT") elif code == 9:
oled.text("Measurement too", 0, 22, 2) line1("BAD UNIT")
oled.text("large to display", 0, 30, 2) oled.text("Measurement too", 0, 22, 2)
oled.text("with current", 0, 38, 2) oled.text("large to display", 0, 30, 2)
oled.text("unit setting.", 0, 46, 2) oled.text("with current", 0, 38, 2)
oled.text("Change units.", 0, 54, 2) oled.text("unit setting.", 0, 46, 2)
elif code == 0x4D: oled.text("Change units.", 0, 54, 2)
line1(" REPL ") elif code == 0x4D:
oled.text("Device is in", 0, 22, 2) line1(" REPL ")
oled.text("debugging mode.", 0, 30, 2) oled.text("Device is in", 0, 22, 2)
oled.text("Power off and", 0, 38, 2) oled.text("debugging mode.", 0, 30, 2)
oled.text("back on to", 0, 46, 2) oled.text("Power off and", 0, 38, 2)
oled.text("cancel.", 0, 54, 2) oled.text("back on to", 0, 46, 2)
elif code == 0x50: oled.text("cancel.", 0, 54, 2)
line1(" UPDATE ") elif code == 0x50:
oled.text("Device is in", 0, 22, 2) line1(" UPDATE ")
oled.text("firmware update", 0, 30, 2) oled.text("Device is in", 0, 22, 2)
oled.text("mode. Power off", 0, 38, 2) oled.text("firmware update", 0, 30, 2)
oled.text("and back on to", 0, 46, 2) oled.text("mode. Power off", 0, 38, 2)
oled.text("cancel.", 0, 54, 2) oled.text("and back on to", 0, 46, 2)
oled.show() oled.text("cancel.", 0, 54, 2)
oled.show()
except:
pass
def updateDisplay(measurement, units, tempC): def updateDisplay(measurement, units, tempC, unstable = False):
global oled global oled
if ENABLE_DISPLAY: if ENABLE_DISPLAY:
setOLED(oled) try:
wholeNumber = str(math.floor(abs(measurement))) setOLED(oled)
decimalPart = int(abs(measurement % 1) * 100) numberLine = " "
numberLine = " " if unstable:
if measurement < 0: if units == "mm":
numberLine = "-" wholeNumber = "-------"
if decimalPart > 0: decimalPart = ""
decimalPart = 100 - decimalPart # Fix a bug where -.75 displays as -.25 elif units == "cm":
wholeNumber = "-----"
if units == "mm": decimalPart = "-"
numberLine = numberLine + f"{wholeNumber:>7}" else:
elif units == "cm": wholeNumber = "----"
numberLine = numberLine + f"{wholeNumber:>5}.{decimalPart:0<1}" decimalPart = "--"
elif units == "in": else:
numberLine = numberLine + f"{wholeNumber:>4}.{decimalPart:0<2}" wholeNumber = str(math.floor(abs(measurement)))
elif units == "ft": decimalPart = int(abs(measurement % 1) * 100)
numberLine = numberLine + f"{wholeNumber:>4}.{decimalPart:0<2}" if measurement < 0:
numberLine = "-"
oled.fill(0) # Fill with black to clear screen if decimalPart > 0:
line1(numberLine[:8]) # Write measurement to screen (but only first 8 chars to prevent IndexError: list index out of range) decimalPart = 100 - decimalPart # Fix a bug where -.75 displays as -.25
oled.text(f"{units:^16}", 0, 22, 1) # Write units centered below measurement
if measurement == 0: # Write zero indicator on right below measurement if units == "mm":
oled.text(" ZERO", 0, 22, 1) numberLine = numberLine + f"{wholeNumber:>7}"
tempStr = str(tempC) + "C" elif units == "cm":
oled.text(f"{tempStr:>16}", 0, 50, 1) # Write temperature in bottom-right corner numberLine = numberLine + f"{wholeNumber:>5}.{decimalPart:0<1}"
oled.show() elif units == "in":
numberLine = numberLine + f"{wholeNumber:>4}.{decimalPart:0<2}"
elif units == "ft":
numberLine = numberLine + f"{wholeNumber:>4}.{decimalPart:0<2}"
oled.fill(0) # Fill with black to clear screen
line1(numberLine[:8]) # Write measurement to screen (but only first 8 chars to prevent IndexError: list index out of range)
oled.text(f"{units:^16}", 0, 22, 1) # Write units centered below measurement
if measurement == 0: # Write zero indicator on right below measurement
oled.text(" ZERO", 0, 22, 1)
tempStr = str(tempC) + "C"
oled.text(f"{tempStr:>16}", 0, 50, 1) # Write temperature in bottom-right corner
if ENABLE_BUTTON_LEGEND:
# Draw a vertical, double-ended arrow for the two physical buttons
oled.line(5, 24, 5, 40, 1) # Vertical line for top arrow
oled.line(5, 46, 5, 62, 1) # Vertical line for top arrow
oled.line(0, 28, 5, 24, 1) # Left-top arrow part
oled.line(10, 28, 5, 24, 1) # Right-top arrow part
oled.line(0, 58, 5, 62, 1) # Left-bottom arrow part
oled.line(10, 58, 5, 62, 1) # Right-bottom arrow part
oled.text("SET 0", 10, 30, 1)
oled.text("UNITS", 10, 50, 1)
oled.show()
except:
pass
def clearDisplay(): def clearDisplay():
oled.fill(0) try:
oled.show() oled.fill(0)
oled.show()
except:
pass

View File

@ -111,7 +111,7 @@ def roundUnits(x, units):
# #
bufferSize = 1024 # size of circular buffer to allocate bufferSize = 1024 # size of circular buffer to allocate
buffer = [' '] * bufferSize # circuolar incomming USB serial data buffer (pre fill) buffer = [' '] * bufferSize # circuolar incomming USB serial data buffer (pre fill)
bufferEcho = True # USB serial port echo incooming characters (True/False) bufferEcho = False # USB serial port echo incooming characters (True/False)
bufferNextIn, bufferNextOut = 0,0 # pointers to next in/out character in circualr buffer bufferNextIn, bufferNextOut = 0,0 # pointers to next in/out character in circualr buffer
terminateThread = False # tell 'bufferSTDIN' function to terminate (True/False) terminateThread = False # tell 'bufferSTDIN' function to terminate (True/False)
# #
@ -131,7 +131,7 @@ def bufferSTDIN():
bufferNextIn = 0 bufferNextIn = 0
# #
# instantiate second 'background' thread on RD2040 dual processor to monitor and buffer # instantiate second 'background' thread on RD2040 dual processor to monitor and buffer
# incomming data from 'stdin' over USB serial port using bufferSTDIN function (above) # incoming data from 'stdin' over USB serial port using bufferSTDIN function (above)
# #
bufferSTDINthread = start_new_thread(bufferSTDIN, ()) bufferSTDINthread = start_new_thread(bufferSTDIN, ())

View File

@ -70,35 +70,8 @@ from usb.device.hid import HIDInterface
import ujson as json import ujson as json
from dimensioner_utils import * from dimensioner_utils import *
from dimensioner_screen import updateDisplay, errorDisplay, bootDisplay, clearDisplay from dimensioner_screen import updateDisplay, errorDisplay, bootDisplay, clearDisplay
from config import *
#
# Hardware configuration
#
SENSOR_TYPE = "US-100" # "PING" for Parallax PING))) or "US-100" for US-100
SENSOR_MAX_MM = 3000 # Maximum range sensor supports and is accurate within
SENSOR_MIN_MM = 100 # Minimum range below which sensor is not accurate
SENSOR_PIN = 17 # Analog pin for PING sensor
SENSOR_TX = 16 # Digital pin for US-100
SENSOR_RX = 17 # Digital pin for US-100
UART_ID = 0 # TX/RX: UART 0: 12/13, 16/17; UART 1: 4/5, 8/9
ZERO_RANGE_MM = 10 # +/- mm away from zero before a non-zero value is transmitted
SAMPLE_SIZE = 20 # Number of times to sample distance per reading, averaging the results
UNSTABLE_DELTA_MM = 50 # Max difference between largest and smallest samples (before averaging), larger than this will report as unstable
ZERO_BUTTON_PIN = 13 # Pin to read if hardware zero button is pressed
UNITS_BUTTON_PIN = 14 # Pin to read if hardware unit change button is pressed
FIRMWARE_VERSION = "1.0"
machine.freq(240000000) # Set CPU to 240MHz (about twice as fast as default)
#
# USB configuration
#
VID = 0x1209 # USB Vendor ID
PID = 0xA002 # USB Product ID
MANU = "PostalPortal LLC" # USB manufacturer string
PROD = "PostalPoint Parcel Dimensioner" # USB product string
INTERFACE = "PostalPoint" # Interface string
USBHID_ENABLED = True # Disable USB, use serial output only (good for debugging)
class USBHIDInterface(HIDInterface): class USBHIDInterface(HIDInterface):
def __init__(self): def __init__(self):
@ -222,8 +195,8 @@ def getAmbientTemp():
else: else:
return ambientTempC return ambientTempC
def sendToDisplay(measurement): def sendToDisplay(measurement, unstable = False):
updateDisplay(measurement, reportUnits, getAmbientTemp()) updateDisplay(measurement, reportUnits, getAmbientTemp(), unstable)
def setUnits(units): def setUnits(units):
global reportUnits global reportUnits
@ -302,7 +275,7 @@ def getAverageDistanceMM(samples = SAMPLE_SIZE):
maxV = sample maxV = sample
total = total + sample total = total + sample
i = i + 1 i = i + 1
sleep_us(1000) # PING datasheet says wait a minimum of 200us between measurements sleep_us(2000) # PING datasheet says wait a minimum of 200us between measurements
if abs(maxV - minV) > UNSTABLE_DELTA_MM: if abs(maxV - minV) > UNSTABLE_DELTA_MM:
raise DeltaError raise DeltaError
return total / samples return total / samples
@ -421,7 +394,7 @@ try:
sendToDisplay(round(sizeInUnits, 2)) sendToDisplay(round(sizeInUnits, 2))
except DeltaError: except DeltaError:
usbinterface.send_data(b'\x02\x03\x00\x00\x00\x00\x00') usbinterface.send_data(b'\x02\x03\x00\x00\x00\x00\x00')
errorDisplay(3) sendToDisplay(999, True)
print("E3: Unstable") print("E3: Unstable")
except KeyboardInterrupt: except KeyboardInterrupt:
terminateThread = True terminateThread = True

View File

@ -2,6 +2,7 @@
include("$(MPY_DIR)/ports/rp2/boards/manifest.py") include("$(MPY_DIR)/ports/rp2/boards/manifest.py")
require("usb-device-hid") require("usb-device-hid")
require("ssd1306") require("ssd1306")
module("config.py")
module("dimensioner_utils.py") module("dimensioner_utils.py")
module("dimensioner_screen.py") module("dimensioner_screen.py")
module("ssd1306big.py") module("ssd1306big.py")