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
import framebuf
import math
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
from config import *
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)
@ -62,152 +50,185 @@ oled = SSD1306_I2C(DISPLAY_WIDTH, DISPLAY_HEIGHT, i2c)
def bootDisplay(firmwareVersion):
if ENABLE_DISPLAY:
# Bootup dead pixel self-test
oled.fill(0)
oled.show()
oled.fill(1)
oled.show()
sleep_ms(500)
oled.fill(0)
oled.show()
# 128x32 PostalPoint logo bitmap
logo = bytearray([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0x40, 0x40, 0xc0, 0x80,
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, 0xfc, 0x0e, 0x0a, 0x1a, 0x13, 0xf1, 0x19, 0x08, 0x08, 0xfc, 0xfc, 0x0c, 0x08,
0x19, 0xf1, 0xf1, 0x1b, 0x0a, 0x0e, 0xfc, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf8, 0xf8,
0x1c, 0x1c, 0x1c, 0xf8, 0xf8, 0xf0, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0x00,
0x00, 0x00, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0x00, 0x00, 0x80, 0xf0, 0xf8, 0xf8, 0xe0, 0xe0,
0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0x40, 0x00, 0x00, 0xf0, 0xfc, 0xfe, 0x0e,
0x00, 0x00, 0xf0, 0xf8, 0xf8, 0x1c, 0x1c, 0x18, 0xf8, 0xf8, 0xf0, 0x00, 0x00, 0x80, 0xc0, 0xe0,
0xe0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0xc8, 0xfc, 0xfe, 0x0c, 0x00, 0xc0, 0xe0, 0xe0, 0xe0,
0xe0, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0xf0, 0xf8, 0xf8, 0xe0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7f, 0xc0, 0x80, 0x80, 0x80, 0x07, 0x0e, 0x0a, 0x1a, 0xf1, 0xf1, 0x1b, 0x0a,
0x0e, 0x0f, 0x07, 0x80, 0x80, 0xc0, 0x7f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7f, 0x3f, 0x07,
0x07, 0x07, 0x03, 0x03, 0x01, 0x00, 0x00, 0x1f, 0x3f, 0x7f, 0x70, 0x70, 0x38, 0x1f, 0x0f, 0x03,
0x20, 0x71, 0x73, 0x77, 0x76, 0x3e, 0x3c, 0x08, 0x00, 0x18, 0x3f, 0x7f, 0x73, 0x70, 0x30, 0x00,
0x0c, 0x3f, 0x7f, 0x73, 0x70, 0x30, 0x3f, 0x7f, 0x3f, 0x00, 0x00, 0x3f, 0x7f, 0x7f, 0x20, 0x00,
0x70, 0x7f, 0x7f, 0x0f, 0x07, 0x07, 0x07, 0x03, 0x03, 0x01, 0x00, 0x0c, 0x3f, 0x3f, 0x73, 0x70,
0x70, 0x3f, 0x1f, 0x0f, 0x00, 0x70, 0x7f, 0x3f, 0x0f, 0x00, 0x20, 0x7e, 0x7f, 0x1f, 0x01, 0x20,
0x7f, 0x7f, 0x0f, 0x00, 0x00, 0x3f, 0x7f, 0x7f, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x02, 0x06, 0x07, 0x07, 0x06, 0x02,
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])
fbuf = framebuf.FrameBuffer(logo, 128, 32, framebuf.MONO_VLSB)
oled.blit(fbuf, 0, 0, 0)
# Show info
oled.text(" Parcel", 0, 32, 1)
oled.text(" Dimensioner", 0, 40, 1)
firmVerStr = "FW Ver " + firmwareVersion
oled.text(f"{firmVerStr:^16}", 0, 56, 1)
oled.show()
sleep_ms(1500)
try:
# Bootup dead pixel self-test
oled.fill(0)
oled.show()
oled.fill(1)
oled.show()
sleep_ms(500)
oled.fill(0)
oled.show()
# 128x32 PostalPoint logo bitmap
logo = bytearray([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0x40, 0x40, 0xc0, 0x80,
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, 0xfc, 0x0e, 0x0a, 0x1a, 0x13, 0xf1, 0x19, 0x08, 0x08, 0xfc, 0xfc, 0x0c, 0x08,
0x19, 0xf1, 0xf1, 0x1b, 0x0a, 0x0e, 0xfc, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf8, 0xf8,
0x1c, 0x1c, 0x1c, 0xf8, 0xf8, 0xf0, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0x00,
0x00, 0x00, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0x00, 0x00, 0x80, 0xf0, 0xf8, 0xf8, 0xe0, 0xe0,
0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0x40, 0x00, 0x00, 0xf0, 0xfc, 0xfe, 0x0e,
0x00, 0x00, 0xf0, 0xf8, 0xf8, 0x1c, 0x1c, 0x18, 0xf8, 0xf8, 0xf0, 0x00, 0x00, 0x80, 0xc0, 0xe0,
0xe0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0xc8, 0xfc, 0xfe, 0x0c, 0x00, 0xc0, 0xe0, 0xe0, 0xe0,
0xe0, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0xf0, 0xf8, 0xf8, 0xe0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7f, 0xc0, 0x80, 0x80, 0x80, 0x07, 0x0e, 0x0a, 0x1a, 0xf1, 0xf1, 0x1b, 0x0a,
0x0e, 0x0f, 0x07, 0x80, 0x80, 0xc0, 0x7f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7f, 0x3f, 0x07,
0x07, 0x07, 0x03, 0x03, 0x01, 0x00, 0x00, 0x1f, 0x3f, 0x7f, 0x70, 0x70, 0x38, 0x1f, 0x0f, 0x03,
0x20, 0x71, 0x73, 0x77, 0x76, 0x3e, 0x3c, 0x08, 0x00, 0x18, 0x3f, 0x7f, 0x73, 0x70, 0x30, 0x00,
0x0c, 0x3f, 0x7f, 0x73, 0x70, 0x30, 0x3f, 0x7f, 0x3f, 0x00, 0x00, 0x3f, 0x7f, 0x7f, 0x20, 0x00,
0x70, 0x7f, 0x7f, 0x0f, 0x07, 0x07, 0x07, 0x03, 0x03, 0x01, 0x00, 0x0c, 0x3f, 0x3f, 0x73, 0x70,
0x70, 0x3f, 0x1f, 0x0f, 0x00, 0x70, 0x7f, 0x3f, 0x0f, 0x00, 0x20, 0x7e, 0x7f, 0x1f, 0x01, 0x20,
0x7f, 0x7f, 0x0f, 0x00, 0x00, 0x3f, 0x7f, 0x7f, 0x70, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x02, 0x06, 0x07, 0x07, 0x06, 0x02,
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])
fbuf = framebuf.FrameBuffer(logo, 128, 32, framebuf.MONO_VLSB)
oled.blit(fbuf, 0, 16, 0)
# Show info
oled.text(" Parcel", 0, 40, 1)
oled.text(" Dimensioner", 0, 48, 1)
firmVerStr = "FW Ver " + firmwareVersion
oled.text(f"{firmVerStr:^16}", 0, 56, 1)
oled.show()
sleep_ms(1500)
except:
pass
def errorDisplay(code, message = ""):
global oled
if ENABLE_DISPLAY:
setOLED(oled)
oled.fill(0)
if code == 1:
line1(" ERROR! ")
oled.text(message, 0, 22, 2)
if message == "Sensor timeout":
pass
elif code == 3:
line1("UNSTABLE")
oled.text("Distance is not", 0, 22, 2)
oled.text("stable. Waiting", 0, 30, 2)
oled.text("for it to settle", 0, 38, 2)
oled.text("down and stop", 0, 46, 2)
oled.text("moving around.", 0, 54, 2)
elif code == 5:
line1("UNDER 0!")
oled.text("Object farther", 0, 22, 2)
oled.text("from platform", 0, 30, 2)
oled.text("than it should", 0, 38, 2)
oled.text("be. Check and", 0, 46, 2)
oled.text("re-zero.", 0, 54, 2)
elif code == 6:
line1("TOO FAR!")
oled.text("Distance is too", 0, 22, 2)
oled.text("far from sensor", 0, 30, 2)
oled.text("for accurate", 0, 38, 2)
oled.text("measurement.", 0, 46, 2)
elif code == 7:
line1("TOO NEAR")
oled.text("Object is too", 0, 22, 2)
oled.text("close to sensor", 0, 30, 2)
oled.text("for accurate", 0, 38, 2)
oled.text("measurement.", 0, 46, 2)
elif code == 8:
line1("HOST ERR")
oled.text("Connected PC", 0, 22, 2)
oled.text("sent an invalid", 0, 30, 2)
oled.text("command.", 0, 38, 2)
elif code == 9:
line1("BAD UNIT")
oled.text("Measurement too", 0, 22, 2)
oled.text("large to display", 0, 30, 2)
oled.text("with current", 0, 38, 2)
oled.text("unit setting.", 0, 46, 2)
oled.text("Change units.", 0, 54, 2)
elif code == 0x4D:
line1(" REPL ")
oled.text("Device is in", 0, 22, 2)
oled.text("debugging mode.", 0, 30, 2)
oled.text("Power off and", 0, 38, 2)
oled.text("back on to", 0, 46, 2)
oled.text("cancel.", 0, 54, 2)
elif code == 0x50:
line1(" UPDATE ")
oled.text("Device is in", 0, 22, 2)
oled.text("firmware update", 0, 30, 2)
oled.text("mode. Power off", 0, 38, 2)
oled.text("and back on to", 0, 46, 2)
oled.text("cancel.", 0, 54, 2)
oled.show()
try:
setOLED(oled)
oled.fill(0)
if code == 1:
line1(" ERROR! ")
oled.text(message, 0, 22, 2)
if message == "Sensor timeout":
pass
elif code == 3:
line1("UNSTABLE")
oled.text("Distance is not", 0, 22, 2)
oled.text("stable. Waiting", 0, 30, 2)
oled.text("for it to settle", 0, 38, 2)
oled.text("down and stop", 0, 46, 2)
oled.text("moving around.", 0, 54, 2)
elif code == 5:
line1("UNDER 0!")
oled.text("Object farther", 0, 22, 2)
oled.text("from platform", 0, 30, 2)
oled.text("than it should", 0, 38, 2)
oled.text("be. Check and", 0, 46, 2)
oled.text("re-zero.", 0, 54, 2)
elif code == 6:
line1("TOO FAR!")
oled.text("Distance is too", 0, 22, 2)
oled.text("far from sensor", 0, 30, 2)
oled.text("for accurate", 0, 38, 2)
oled.text("measurement.", 0, 46, 2)
elif code == 7:
line1("TOO NEAR")
oled.text("Object is too", 0, 22, 2)
oled.text("close to sensor", 0, 30, 2)
oled.text("for accurate", 0, 38, 2)
oled.text("measurement.", 0, 46, 2)
elif code == 8:
line1("HOST ERR")
oled.text("Connected PC", 0, 22, 2)
oled.text("sent an invalid", 0, 30, 2)
oled.text("command.", 0, 38, 2)
elif code == 9:
line1("BAD UNIT")
oled.text("Measurement too", 0, 22, 2)
oled.text("large to display", 0, 30, 2)
oled.text("with current", 0, 38, 2)
oled.text("unit setting.", 0, 46, 2)
oled.text("Change units.", 0, 54, 2)
elif code == 0x4D:
line1(" REPL ")
oled.text("Device is in", 0, 22, 2)
oled.text("debugging mode.", 0, 30, 2)
oled.text("Power off and", 0, 38, 2)
oled.text("back on to", 0, 46, 2)
oled.text("cancel.", 0, 54, 2)
elif code == 0x50:
line1(" UPDATE ")
oled.text("Device is in", 0, 22, 2)
oled.text("firmware update", 0, 30, 2)
oled.text("mode. Power off", 0, 38, 2)
oled.text("and back on to", 0, 46, 2)
oled.text("cancel.", 0, 54, 2)
oled.show()
except:
pass
def updateDisplay(measurement, units, tempC):
def updateDisplay(measurement, units, tempC, unstable = False):
global oled
if ENABLE_DISPLAY:
setOLED(oled)
wholeNumber = str(math.floor(abs(measurement)))
decimalPart = int(abs(measurement % 1) * 100)
numberLine = " "
if measurement < 0:
numberLine = "-"
if decimalPart > 0:
decimalPart = 100 - decimalPart # Fix a bug where -.75 displays as -.25
if units == "mm":
numberLine = numberLine + f"{wholeNumber:>7}"
elif units == "cm":
numberLine = numberLine + f"{wholeNumber:>5}.{decimalPart:0<1}"
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
oled.show()
try:
setOLED(oled)
numberLine = " "
if unstable:
if units == "mm":
wholeNumber = "-------"
decimalPart = ""
elif units == "cm":
wholeNumber = "-----"
decimalPart = "-"
else:
wholeNumber = "----"
decimalPart = "--"
else:
wholeNumber = str(math.floor(abs(measurement)))
decimalPart = int(abs(measurement % 1) * 100)
if measurement < 0:
numberLine = "-"
if decimalPart > 0:
decimalPart = 100 - decimalPart # Fix a bug where -.75 displays as -.25
if units == "mm":
numberLine = numberLine + f"{wholeNumber:>7}"
elif units == "cm":
numberLine = numberLine + f"{wholeNumber:>5}.{decimalPart:0<1}"
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():
oled.fill(0)
oled.show()
try:
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
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
terminateThread = False # tell 'bufferSTDIN' function to terminate (True/False)
#
@ -131,7 +131,7 @@ def bufferSTDIN():
bufferNextIn = 0
#
# 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, ())

View File

@ -70,35 +70,8 @@ from usb.device.hid import HIDInterface
import ujson as json
from dimensioner_utils import *
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):
def __init__(self):
@ -222,8 +195,8 @@ def getAmbientTemp():
else:
return ambientTempC
def sendToDisplay(measurement):
updateDisplay(measurement, reportUnits, getAmbientTemp())
def sendToDisplay(measurement, unstable = False):
updateDisplay(measurement, reportUnits, getAmbientTemp(), unstable)
def setUnits(units):
global reportUnits
@ -302,7 +275,7 @@ def getAverageDistanceMM(samples = SAMPLE_SIZE):
maxV = sample
total = total + sample
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:
raise DeltaError
return total / samples
@ -421,7 +394,7 @@ try:
sendToDisplay(round(sizeInUnits, 2))
except DeltaError:
usbinterface.send_data(b'\x02\x03\x00\x00\x00\x00\x00')
errorDisplay(3)
sendToDisplay(999, True)
print("E3: Unstable")
except KeyboardInterrupt:
terminateThread = True

View File

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