Paragliding Visual Variometer for the Hearing Impaired

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

Variometer: "In aviation, a variometer – also known as a rate of climb and descent indicator (RCDI), rate-of-climb indicator, vertical speed indicator (VSI), or vertical velocity indicator (VVI) – is one of the flight instruments in an aircraft used to inform the pilot of the rate of descent or climb. It can be calibrated in metres per second, feet per minute (1 ft/min = 0.00508 m/s) or knots (1 kn ≈ 0.514 m/s), depending on country and type of aircraft. It is typically connected to the aircraft's external static pressure source." - Wikipedia

Summary for why this project exists: My wife is hearing impaired, we both want to get into paragliding (aka. parapente). While watching YouTube videos on the subject my wife could not hear the variometer beeping: "beep Beep BEEP" as the pilot got into lift, even with her hearing aids. Currently no visual variometer exists on the market for the hearing impaired other than some basic tiny LCD screen versions (and my wife wears glasses). So it's time to be a good husband and try to make something she can use (ie. better than nothing).

Project Goals: To use off the shelf Adafruit parts to make a visual variometer that is easy to see in sunlight, 3D print a case and go flying! Accessibility is key with as few roadblocks as possible. So far I have identified the QT Py RP2040 (yay STEMMA QT!) the DPS310 barometer, and the IS31FL3741 13x9 LED Matrix (no QT LED Stick is available for purchase, so this will have to do - I backordered the SparkFun Qwiick LED Stick though). I have ZERO ambition to make a commercial product, in fact the more accessible this project is to the paragliding hearing impaired the better (yay open source!). Plus it helps sell Adafruit products ;)

Current Progress: I got the parts yesterday and the example codes for the various breakouts and they seem to work. However I have very limited Circuit Python and coding experience and the documentation for these QT devices (at least the LED matrix) has me wishing I had a better reference, but that is no excuse for my own ignorance.

What I need help with: What is the best way to pull data from the barometer sensor and have it display on the 13x9 LED Matrix? Is that something that is animated? Uses sprites? Somehow assign individual LEDs? Do I somehow make pixel groups to go with various values so "beep Beep BEEP" is easily visually identifiable? You'd think 13x9 would be simple, but it provides for so many options! But I want to know what you think. Any and all help is greatly appreciated! If you know of a better part that would be better suited I am open to suggestions (I am a newbie after all).

THANK YOU for your time!

Example:
13x9_GreenUP.jpg
13x9_GreenUP.jpg (52.24 KiB) Viewed 312 times
13x9_GreenDown.jpg
13x9_GreenDown.jpg (55.09 KiB) Viewed 312 times

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by adafruit_support_mike »

The first thing to do is find an organization that trains paragliders and spend a LOT of time talking to them. Also find every company you can that makes variometers and try to find a point of contact with them.

What you're talking about is a piece of life-safety-critical equipment: if something goes wrong with it, or it isn't used properly, the user could die. It's also a piece of a larger system: at minimum it would have to be incorporated into a training program so the user can develop the muscle and procedural memory to use it correctly in a safety-critical situation.

That kind of thing isn't DIY-able by anyone.

A highly experienced engineer approaching that job would have an ethical duty to work with experts on the legal requirements and best practices, and to simulation-test the daylights out of such a device before ever letting it be used in real flight. The first thing they'd do is exactly what I mentioned above: find people who know the field and have spent time learning what can go wrong, and leverage the living hell out of their experience. There are no trade secrets in the field of safety. It's everyone who can make things safer against the laws of physics.

Working with the existing manufacturers will bring you the benefit of their experience, and just as importantly, give them the benefit of yours. You can help them develop a new product line, or improve something they already have.

User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

Hi Mike, I humbly disagree and must insist that it is NOT "life-safety equipment" (a reserve parachute would be). Some pilots fly without variometers (especially in glide-down hike & fly), they are used to let the pilot know if they are in lift or in sink to make entering thermals/lift easier. Worst case scenario is that your flight is not as long. Right now deaf and hearing impaired pilots DO NOT have an option for this, they would be dead right now if you were correct in your assumptions. These pilots use the harness and brake line "feedback" to feel the air and adjust accordingly, look at the terrain, etc. The constant beeping does not make a pilot alive or dead. If you're drifting towards the ground, you can see/feel it.

This is entirely DIY capable, if and only if I can get the LED Matrix to light up in the ways described in the original post. Do you know of a better place for documentation for the LED Matrix that utilizes sensor data? I seem to only find guides for displaying 8-bit images or to use them as an oscilloscope.

My brain seems to think the structure should be something like:

Code: Select all

If pressure sensor values are increasing by a value within a time range
 display these pixels

If pressure sensor values are increasing by larger values within a time range
 display these pixels and the previous pixels 

If pressure sensor values are increasing by values quickly within a time range
 display these pixels and the previous pixels plus the one before it

If pressure sensor values are decreasing by a value within a time range
 display these pixels

If pressure sensor values are decreasing by larger values within a time range
 display these pixels and the previous pixels 

If pressure sensor values are decreasing by values quickly within a time range
 display these pixels and the previous pixels plus the one before it
 
Else no change in pressure values within a time range
 display nothing
VisualVario_CaseMockUp.jpg
VisualVario_CaseMockUp.jpg (36.97 KiB) Viewed 294 times

User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

So I have kinda figured out how to use the 13x9 Matrix display, I sincerely wished I would have gotten some direction as to where to find the documentation, but this is what I have cobbled together so far:

Code: Select all

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

"""
Configure the sensor for continuous measurement with rates,
sampling counts and mode optimized for low power, as recommended
in Infineon's datasheet:
https://www.infineon.com/dgdl/Infineon-DPS310-DataSheet-v01_02-EN.pdf
"""

# (disable pylint warnings for adafruit_dps310.{SampleCount,Rate,Mode}.*
# as they are generated dynamically)
# pylint: disable=no-member

import time
import board
from adafruit_dps310 import advanced
import adafruit_is31fl3741
from adafruit_is31fl3741.adafruit_rgbmatrixqt import Adafruit_RGBMatrixQT


# Create I2C bus.
i2c = board.STEMMA_I2C()  # uses board.SCL and board.SDA

# Create sensor instance
is31 = adafruit_is31fl3741.IS31FL3741(board.STEMMA_I2C())
display = Adafruit_RGBMatrixQT(i2c)
dps310 = advanced.DPS310_Advanced(i2c)

# Pressure Sensor
dps310.reset()
dps310.pressure_oversample_count = advanced.SampleCount.COUNT_64
dps310.pressure_rate = advanced.Rate.RATE_1_HZ
dps310.temperature_oversample_count = advanced.SampleCount.COUNT_16
dps310.temperature_rate = advanced.Rate.RATE_1_HZ
dps310.mode = advanced.Mode.CONT_PRESTEMP
dps310.wait_temperature_ready()
dps310.wait_pressure_ready()

# LED Matrix Display
is31 = Adafruit_RGBMatrixQT(i2c, allocate=adafruit_is31fl3741.MUST_BUFFER)
is31.show() # clear any residue on startup
is31.set_led_scaling(0xFF)  # turn on LEDs all the way 0xFF
is31.global_current = 2  # set current to max 0xFF
is31.enable = True  # enable!

class Arrows(object):
    def UP1(self):
        display.pixel(3,8,0x00FF00)
        display.pixel(4,8,0x00FF00)
        display.pixel(4,7,0x00FF00)
        display.pixel(5,7,0x00FF00)
        display.pixel(5,6,0x00FF00)
        display.pixel(6,6,0x00FF00)
        display.pixel(6,5,0x00FF00)
        display.pixel(7,6,0x00FF00)
        display.pixel(7,7,0x00FF00)
        display.pixel(8,7,0x00FF00)
        display.pixel(8,8,0x00FF00)
        display.pixel(9,8,0x00FF00)
        
    def UP2(self):
        display.pixel(0,8,0x00FF00)
        display.pixel(0,7,0x00FF00)
        display.pixel(1,7,0x00FF00)
        display.pixel(1,6,0x00FF00)
        display.pixel(2,6,0x00FF00)
        display.pixel(2,5,0x00FF00)
        display.pixel(3,5,0x00FF00)
        display.pixel(3,4,0x00FF00)
        display.pixel(4,4,0x00FF00)
        display.pixel(4,3,0x00FF00)
        display.pixel(5,3,0x00FF00)
        display.pixel(5,2,0x00FF00)
        display.pixel(6,2,0x00FF00)   
        display.pixel(6,1,0x00FF00) 
        display.pixel(7,2,0x00FF00) 
        display.pixel(7,3,0x00FF00) 
        display.pixel(8,3,0x00FF00) 
        display.pixel(8,4,0x00FF00)  
        display.pixel(9,4,0x00FF00)   
        display.pixel(9,5,0x00FF00) 
        display.pixel(10,5,0x00FF00) 
        display.pixel(10,6,0x00FF00) 
        display.pixel(11,6,0x00FF00) 
        display.pixel(11,7,0x00FF00)
        display.pixel(12,7,0x00FF00)
        display.pixel(12,8,0x00FF00)
        
    def UP3(self):
        display.pixel(0,0,0x00FF00)
        display.pixel(0,1,0x00FF00)
        display.pixel(0,2,0x00FF00)
        display.pixel(0,3,0x00FF00)
        display.pixel(0,4,0x00FF00)
        display.pixel(1,0,0x00FF00)
        display.pixel(1,1,0x00FF00)
        display.pixel(1,2,0x00FF00)
        display.pixel(1,3,0x00FF00)
        display.pixel(2,0,0x00FF00)
        display.pixel(2,1,0x00FF00)
        display.pixel(2,2,0x00FF00)
        display.pixel(3,0,0x00FF00)   
        display.pixel(3,1,0x00FF00) 
        display.pixel(4,0,0x00FF00) 
        display.pixel(8,0,0x00FF00) 
        display.pixel(9,0,0x00FF00) 
        display.pixel(9,1,0x00FF00)  
        display.pixel(10,0,0x00FF00)   
        display.pixel(10,1,0x00FF00) 
        display.pixel(10,2,0x00FF00) 
        display.pixel(11,0,0x00FF00) 
        display.pixel(11,1,0x00FF00) 
        display.pixel(11,2,0x00FF00)
        display.pixel(11,3,0x00FF00)
        display.pixel(12,0,0x00FF00)
        display.pixel(12,1,0x00FF00)
        display.pixel(12,2,0x00FF00)
        display.pixel(12,3,0x00FF00)
        display.pixel(12,4,0x00FF00)
        
    def DOWN1(self):
        display.pixel(3,0,0xFF0000)
        display.pixel(4,0,0xFF0000)
        display.pixel(4,1,0xFF0000)
        display.pixel(5,1,0xFF0000)
        display.pixel(5,2,0xFF0000)
        display.pixel(6,2,0xFF0000)
        display.pixel(6,3,0xFF0000)
        display.pixel(7,2,0xFF0000)
        display.pixel(7,1,0xFF0000)
        display.pixel(8,1,0xFF0000)
        display.pixel(8,0,0xFF0000)
        display.pixel(9,0,0xFF0000)
        
    def DOWN2(self):
        display.pixel(0,0,0xFF0000)
        display.pixel(0,1,0xFF0000)
        display.pixel(1,1,0xFF0000)
        display.pixel(1,2,0xFF0000)
        display.pixel(2,2,0xFF0000)
        display.pixel(2,3,0xFF0000)
        display.pixel(3,3,0xFF0000)
        display.pixel(3,4,0xFF0000)
        display.pixel(4,4,0xFF0000)
        display.pixel(4,5,0xFF0000)
        display.pixel(5,5,0xFF0000)
        display.pixel(5,6,0xFF0000)
        display.pixel(6,6,0xFF0000)   
        display.pixel(6,7,0xFF0000) 
        display.pixel(7,6,0xFF0000) 
        display.pixel(7,5,0xFF0000) 
        display.pixel(8,5,0xFF0000) 
        display.pixel(8,4,0xFF0000)  
        display.pixel(9,4,0xFF0000)   
        display.pixel(9,3,0xFF0000) 
        display.pixel(10,3,0xFF0000) 
        display.pixel(10,2,0xFF0000) 
        display.pixel(11,2,0xFF0000) 
        display.pixel(11,1,0xFF0000)
        display.pixel(12,1,0xFF0000)
        display.pixel(12,0,0xFF0000)
        
    def DOWN3(self):
        display.pixel(0,8,0xFF0000)
        display.pixel(0,7,0xFF0000)
        display.pixel(0,6,0xFF0000)
        display.pixel(0,5,0xFF0000)
        display.pixel(0,4,0xFF0000)
        display.pixel(1,8,0xFF0000)
        display.pixel(1,7,0xFF0000)
        display.pixel(1,6,0xFF0000)
        display.pixel(1,5,0xFF0000)
        display.pixel(2,8,0xFF0000)
        display.pixel(2,7,0xFF0000)
        display.pixel(2,6,0xFF0000)
        display.pixel(3,8,0xFF0000)   
        display.pixel(3,7,0xFF0000) 
        display.pixel(4,8,0xFF0000) 
        display.pixel(8,8,0xFF0000) 
        display.pixel(9,8,0xFF0000) 
        display.pixel(9,7,0xFF0000)  
        display.pixel(10,8,0xFF0000)   
        display.pixel(10,7,0xFF0000) 
        display.pixel(10,6,0xFF0000) 
        display.pixel(11,8,0xFF0000) 
        display.pixel(11,7,0xFF0000) 
        display.pixel(11,6,0xFF0000)
        display.pixel(11,5,0xFF0000)
        display.pixel(12,8,0xFF0000)
        display.pixel(12,7,0xFF0000)
        display.pixel(12,6,0xFF0000)
        display.pixel(12,5,0xFF0000)
        display.pixel(12,4,0xFF0000)
    
while True:
    Arrows.UP1(1)
    Arrows.UP2(1)
    Arrows.UP3(1)
This gives me a result of:
PXL_20221116_182744497.jpg
PXL_20221116_182744497.jpg (611.37 KiB) Viewed 286 times
PXL_20221116_191928383.jpg
PXL_20221116_191928383.jpg (439.23 KiB) Viewed 286 times
PXL_20221116_193000312.jpg
PXL_20221116_193000312.jpg (521.95 KiB) Viewed 286 times

So my question now is, how do you compare sensor inputs? Would that be an array? I saw there was a tutorial on using microphone inputs to light up LEDs, is that a good place to start or should I try a different guide?

Thank you for your time.

User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

I don't think this is a problem for an array but for iterators:
https://learn.adafruit.com/circuitpytho ... /iterators

User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

So I have been finding several DIY or GNU variometers that are available, even some featured on Adafruit back in 2015! https://blog.adafruit.com/2015/10/05/fr ... r-gliders/

But all of them are in C++ and not Circuit Python. Is there a translator for such things? Or is it a tedious manual process?

User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

Current progress: I have managed to get the arrows to light up/down for a basic pressure change, though I don't know how to make the other values turn on, I assume that has something to do with Ranges, but the examples I have found don't seem to like floats? Is that normal? What would you recommend as a better starting point? Is this the right direction to go in?

Here is the code so far:

Code: Select all

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

"""
Configure the sensor for continuous measurement with rates,
sampling counts and mode optimized for low power, as recommended
in Infineon's datasheet:
https://www.infineon.com/dgdl/Infineon-DPS310-DataSheet-v01_02-EN.pdf
"""

# (disable pylint warnings for adafruit_dps310.{SampleCount,Rate,Mode}.*
# as they are generated dynamically)
# pylint: disable=no-member

import time
import board
from adafruit_itertools import count
from adafruit_dps310 import advanced
import adafruit_is31fl3741
from adafruit_is31fl3741.adafruit_rgbmatrixqt import Adafruit_RGBMatrixQT


# Create I2C bus.
i2c = board.STEMMA_I2C()  # uses board.SCL and board.SDA

# Create sensor instance
is31 = adafruit_is31fl3741.IS31FL3741(board.STEMMA_I2C())
display = Adafruit_RGBMatrixQT(i2c)
dps310 = advanced.DPS310_Advanced(i2c)

# Pressure Sensor
dps310.reset()
dps310.pressure_oversample_count = advanced.SampleCount.COUNT_64 #64 is considered high precision
dps310.pressure_rate = advanced.Rate.RATE_1_HZ
dps310.temperature_oversample_count = advanced.SampleCount.COUNT_16 #16 is considered standard
dps310.temperature_rate = advanced.Rate.RATE_1_HZ
dps310.mode = advanced.Mode.CONT_PRESTEMP
#dps310.wait_temperature_ready()
dps310.wait_pressure_ready()

# LED Matrix Display
is31 = Adafruit_RGBMatrixQT(i2c, allocate=adafruit_is31fl3741.MUST_BUFFER)
is31.show() # clear any residue on startup
is31.set_led_scaling(0xFF)  # turn on LEDs all the way 0xFF
is31.global_current = 200  # set current to max 0xFF - 255
is31.enable = True  # enable!

class Arrows(object):
    def UP1(self):
        display.pixel(3,8,0x00FF00)
        display.pixel(4,8,0x00FF00)
        display.pixel(4,7,0x00FF00)
        display.pixel(5,7,0x00FF00)
        display.pixel(5,6,0x00FF00)
        display.pixel(6,6,0x00FF00)
        display.pixel(6,5,0x00FF00)
        display.pixel(7,6,0x00FF00)
        display.pixel(7,7,0x00FF00)
        display.pixel(8,7,0x00FF00)
        display.pixel(8,8,0x00FF00)
        display.pixel(9,8,0x00FF00)

    def UP2(self):
        display.pixel(0,8,0x00FF00)
        display.pixel(0,7,0x00FF00)
        display.pixel(1,7,0x00FF00)
        display.pixel(1,6,0x00FF00)
        display.pixel(2,6,0x00FF00)
        display.pixel(2,5,0x00FF00)
        display.pixel(3,5,0x00FF00)
        display.pixel(3,4,0x00FF00)
        display.pixel(4,4,0x00FF00)
        display.pixel(4,3,0x00FF00)
        display.pixel(5,3,0x00FF00)
        display.pixel(5,2,0x00FF00)
        display.pixel(6,2,0x00FF00)
        display.pixel(6,1,0x00FF00)
        display.pixel(7,2,0x00FF00)
        display.pixel(7,3,0x00FF00)
        display.pixel(8,3,0x00FF00)
        display.pixel(8,4,0x00FF00)
        display.pixel(9,4,0x00FF00)
        display.pixel(9,5,0x00FF00)
        display.pixel(10,5,0x00FF00)
        display.pixel(10,6,0x00FF00)
        display.pixel(11,6,0x00FF00)
        display.pixel(11,7,0x00FF00)
        display.pixel(12,7,0x00FF00)
        display.pixel(12,8,0x00FF00)

    def UP3(self):
        display.pixel(0,0,0x00FF00)
        display.pixel(0,1,0x00FF00)
        display.pixel(0,2,0x00FF00)
        display.pixel(0,3,0x00FF00)
        display.pixel(0,4,0x00FF00)
        display.pixel(1,0,0x00FF00)
        display.pixel(1,1,0x00FF00)
        display.pixel(1,2,0x00FF00)
        display.pixel(1,3,0x00FF00)
        display.pixel(2,0,0x00FF00)
        display.pixel(2,1,0x00FF00)
        display.pixel(2,2,0x00FF00)
        display.pixel(3,0,0x00FF00)
        display.pixel(3,1,0x00FF00)
        display.pixel(4,0,0x00FF00)
        display.pixel(8,0,0x00FF00)
        display.pixel(9,0,0x00FF00)
        display.pixel(9,1,0x00FF00)
        display.pixel(10,0,0x00FF00)
        display.pixel(10,1,0x00FF00)
        display.pixel(10,2,0x00FF00)
        display.pixel(11,0,0x00FF00)
        display.pixel(11,1,0x00FF00)
        display.pixel(11,2,0x00FF00)
        display.pixel(11,3,0x00FF00)
        display.pixel(12,0,0x00FF00)
        display.pixel(12,1,0x00FF00)
        display.pixel(12,2,0x00FF00)
        display.pixel(12,3,0x00FF00)
        display.pixel(12,4,0x00FF00)

    def DOWN1(self):
        display.pixel(3,0,0xFF0000)
        display.pixel(4,0,0xFF0000)
        display.pixel(4,1,0xFF0000)
        display.pixel(5,1,0xFF0000)
        display.pixel(5,2,0xFF0000)
        display.pixel(6,2,0xFF0000)
        display.pixel(6,3,0xFF0000)
        display.pixel(7,2,0xFF0000)
        display.pixel(7,1,0xFF0000)
        display.pixel(8,1,0xFF0000)
        display.pixel(8,0,0xFF0000)
        display.pixel(9,0,0xFF0000)

    def DOWN2(self):
        display.pixel(0,0,0xFF0000)
        display.pixel(0,1,0xFF0000)
        display.pixel(1,1,0xFF0000)
        display.pixel(1,2,0xFF0000)
        display.pixel(2,2,0xFF0000)
        display.pixel(2,3,0xFF0000)
        display.pixel(3,3,0xFF0000)
        display.pixel(3,4,0xFF0000)
        display.pixel(4,4,0xFF0000)
        display.pixel(4,5,0xFF0000)
        display.pixel(5,5,0xFF0000)
        display.pixel(5,6,0xFF0000)
        display.pixel(6,6,0xFF0000)
        display.pixel(6,7,0xFF0000)
        display.pixel(7,6,0xFF0000)
        display.pixel(7,5,0xFF0000)
        display.pixel(8,5,0xFF0000)
        display.pixel(8,4,0xFF0000)
        display.pixel(9,4,0xFF0000)
        display.pixel(9,3,0xFF0000)
        display.pixel(10,3,0xFF0000)
        display.pixel(10,2,0xFF0000)
        display.pixel(11,2,0xFF0000)
        display.pixel(11,1,0xFF0000)
        display.pixel(12,1,0xFF0000)
        display.pixel(12,0,0xFF0000)

    def DOWN3(self):
        display.pixel(0,8,0xFF0000)
        display.pixel(0,7,0xFF0000)
        display.pixel(0,6,0xFF0000)
        display.pixel(0,5,0xFF0000)
        display.pixel(0,4,0xFF0000)
        display.pixel(1,8,0xFF0000)
        display.pixel(1,7,0xFF0000)
        display.pixel(1,6,0xFF0000)
        display.pixel(1,5,0xFF0000)
        display.pixel(2,8,0xFF0000)
        display.pixel(2,7,0xFF0000)
        display.pixel(2,6,0xFF0000)
        display.pixel(3,8,0xFF0000)
        display.pixel(3,7,0xFF0000)
        display.pixel(4,8,0xFF0000)
        display.pixel(8,8,0xFF0000)
        display.pixel(9,8,0xFF0000)
        display.pixel(9,7,0xFF0000)
        display.pixel(10,8,0xFF0000)
        display.pixel(10,7,0xFF0000)
        display.pixel(10,6,0xFF0000)
        display.pixel(11,8,0xFF0000)
        display.pixel(11,7,0xFF0000)
        display.pixel(11,6,0xFF0000)
        display.pixel(11,5,0xFF0000)
        display.pixel(12,8,0xFF0000)
        display.pixel(12,7,0xFF0000)
        display.pixel(12,6,0xFF0000)
        display.pixel(12,5,0xFF0000)
        display.pixel(12,4,0xFF0000)

x, last = 0, -1
while True:
    pressure = (round(dps310.pressure,2))
    reading = (last - pressure)
    if (reading > 0): Arrows.UP1(1)
    elif (reading < 0): Arrows.DOWN1(1)
    else: is31.show()
    last = pressure
    x += 1
    time.sleep(0.1)

User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

Code I've done so far for this Project:

Code: Select all

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

"""
Configure the sensor for continuous measurement with rates,
sampling counts and mode optimized for low power, as recommended
in Infineon's datasheet:
https://www.infineon.com/dgdl/Infineon-DPS310-DataSheet-v01_02-EN.pdf
"""

# (disable pylint warnings for adafruit_dps310.{SampleCount,Rate,Mode}.*
# as they are generated dynamically)
# pylint: disable=no-member

import time
import board
from adafruit_itertools import count
from adafruit_dps310 import advanced
import adafruit_is31fl3741
from adafruit_is31fl3741.adafruit_rgbmatrixqt import Adafruit_RGBMatrixQT


# Create I2C bus.
i2c = board.STEMMA_I2C()  # uses board.SCL and board.SDA

# Create sensor instance
is31 = adafruit_is31fl3741.IS31FL3741(board.STEMMA_I2C())
display = Adafruit_RGBMatrixQT(i2c)
dps310 = advanced.DPS310_Advanced(i2c)

# Pressure Sensor
dps310.reset()
dps310.pressure_oversample_count = advanced.SampleCount.COUNT_64 #64 is considered high precision
dps310.pressure_rate = advanced.Rate.RATE_1_HZ
dps310.temperature_oversample_count = advanced.SampleCount.COUNT_16 #16 is considered standard
dps310.temperature_rate = advanced.Rate.RATE_1_HZ
dps310.mode = advanced.Mode.CONT_PRESTEMP
#dps310.wait_temperature_ready()
dps310.wait_pressure_ready()

# LED Matrix Display
is31 = Adafruit_RGBMatrixQT(i2c, allocate=adafruit_is31fl3741.MUST_BUFFER)
is31.show() # clear any residue on startup
is31.set_led_scaling(0xFF)  # turn on LEDs all the way 0xFF
is31.global_current = 200  # set current to max 0xFF - 255
is31.enable = True  # enable!

# Defined arrows, coordinates for LEDs and colors
class Arrows(object):
    def UP1(self):
        display.pixel(3,8,0x55FFFF)
        display.pixel(4,8,0x55FFFF)
        display.pixel(4,7,0x55FFFF)
        display.pixel(5,7,0x55FFFF)
        display.pixel(5,6,0x55FFFF)
        display.pixel(6,6,0x55FFFF)
        display.pixel(6,5,0x55FFFF)
        display.pixel(7,6,0x55FFFF)
        display.pixel(7,7,0x55FFFF)
        display.pixel(8,7,0x55FFFF)
        display.pixel(8,8,0x55FFFF)
        display.pixel(9,8,0x55FFFF)

    def UP2(self):
        display.pixel(0,8,0x55FFFF)
        display.pixel(0,7,0x55FFFF)
        display.pixel(1,7,0x55FFFF)
        display.pixel(1,6,0x55FFFF)
        display.pixel(2,6,0x55FFFF)
        display.pixel(2,5,0x55FFFF)
        display.pixel(3,5,0x55FFFF)
        display.pixel(3,4,0x55FFFF)
        display.pixel(4,4,0x55FFFF)
        display.pixel(4,3,0x55FFFF)
        display.pixel(5,3,0x55FFFF)
        display.pixel(5,2,0x55FFFF)
        display.pixel(6,2,0x55FFFF)
        display.pixel(6,1,0x55FFFF)
        display.pixel(7,2,0x55FFFF)
        display.pixel(7,3,0x55FFFF)
        display.pixel(8,3,0x55FFFF)
        display.pixel(8,4,0x55FFFF)
        display.pixel(9,4,0x55FFFF)
        display.pixel(9,5,0x55FFFF)
        display.pixel(10,5,0x55FFFF)
        display.pixel(10,6,0x55FFFF)
        display.pixel(11,6,0x55FFFF)
        display.pixel(11,7,0x55FFFF)
        display.pixel(12,7,0x55FFFF)
        display.pixel(12,8,0x55FFFF)

    def UP3(self):
        display.pixel(0,0,0x55FFFF)
        display.pixel(0,1,0x55FFFF)
        display.pixel(0,2,0x55FFFF)
        display.pixel(0,3,0x55FFFF)
        display.pixel(0,4,0x55FFFF)
        display.pixel(1,0,0x55FFFF)
        display.pixel(1,1,0x55FFFF)
        display.pixel(1,2,0x55FFFF)
        display.pixel(1,3,0x55FFFF)
        display.pixel(2,0,0x55FFFF)
        display.pixel(2,1,0x55FFFF)
        display.pixel(2,2,0x55FFFF)
        display.pixel(3,0,0x55FFFF)
        display.pixel(3,1,0x55FFFF)
        display.pixel(4,0,0x55FFFF)
        display.pixel(8,0,0x55FFFF)
        display.pixel(9,0,0x55FFFF)
        display.pixel(9,1,0x55FFFF)
        display.pixel(10,0,0x55FFFF)
        display.pixel(10,1,0x55FFFF)
        display.pixel(10,2,0x55FFFF)
        display.pixel(11,0,0x55FFFF)
        display.pixel(11,1,0x55FFFF)
        display.pixel(11,2,0x55FFFF)
        display.pixel(11,3,0x55FFFF)
        display.pixel(12,0,0x55FFFF)
        display.pixel(12,1,0x55FFFF)
        display.pixel(12,2,0x55FFFF)
        display.pixel(12,3,0x55FFFF)
        display.pixel(12,4,0x55FFFF)

    def DOWN1(self):
        display.pixel(3,0,0xFF0000)
        display.pixel(4,0,0xFF0000)
        display.pixel(4,1,0xFF0000)
        display.pixel(5,1,0xFF0000)
        display.pixel(5,2,0xFF0000)
        display.pixel(6,2,0xFF0000)
        display.pixel(6,3,0xFF0000)
        display.pixel(7,2,0xFF0000)
        display.pixel(7,1,0xFF0000)
        display.pixel(8,1,0xFF0000)
        display.pixel(8,0,0xFF0000)
        display.pixel(9,0,0xFF0000)

    def DOWN2(self):
        display.pixel(0,0,0xFF0000)
        display.pixel(0,1,0xFF0000)
        display.pixel(1,1,0xFF0000)
        display.pixel(1,2,0xFF0000)
        display.pixel(2,2,0xFF0000)
        display.pixel(2,3,0xFF0000)
        display.pixel(3,3,0xFF0000)
        display.pixel(3,4,0xFF0000)
        display.pixel(4,4,0xFF0000)
        display.pixel(4,5,0xFF0000)
        display.pixel(5,5,0xFF0000)
        display.pixel(5,6,0xFF0000)
        display.pixel(6,6,0xFF0000)
        display.pixel(6,7,0xFF0000)
        display.pixel(7,6,0xFF0000)
        display.pixel(7,5,0xFF0000)
        display.pixel(8,5,0xFF0000)
        display.pixel(8,4,0xFF0000)
        display.pixel(9,4,0xFF0000)
        display.pixel(9,3,0xFF0000)
        display.pixel(10,3,0xFF0000)
        display.pixel(10,2,0xFF0000)
        display.pixel(11,2,0xFF0000)
        display.pixel(11,1,0xFF0000)
        display.pixel(12,1,0xFF0000)
        display.pixel(12,0,0xFF0000)

    def DOWN3(self):
        display.pixel(0,8,0xFF0000)
        display.pixel(0,7,0xFF0000)
        display.pixel(0,6,0xFF0000)
        display.pixel(0,5,0xFF0000)
        display.pixel(0,4,0xFF0000)
        display.pixel(1,8,0xFF0000)
        display.pixel(1,7,0xFF0000)
        display.pixel(1,6,0xFF0000)
        display.pixel(1,5,0xFF0000)
        display.pixel(2,8,0xFF0000)
        display.pixel(2,7,0xFF0000)
        display.pixel(2,6,0xFF0000)
        display.pixel(3,8,0xFF0000)
        display.pixel(3,7,0xFF0000)
        display.pixel(4,8,0xFF0000)
        display.pixel(8,8,0xFF0000)
        display.pixel(9,8,0xFF0000)
        display.pixel(9,7,0xFF0000)
        display.pixel(10,8,0xFF0000)
        display.pixel(10,7,0xFF0000)
        display.pixel(10,6,0xFF0000)
        display.pixel(11,8,0xFF0000)
        display.pixel(11,7,0xFF0000)
        display.pixel(11,6,0xFF0000)
        display.pixel(11,5,0xFF0000)
        display.pixel(12,8,0xFF0000)
        display.pixel(12,7,0xFF0000)
        display.pixel(12,6,0xFF0000)
        display.pixel(12,5,0xFF0000)
        display.pixel(12,4,0xFF0000)

# The loop that compares the previous reading to the current reading and displays something.
x, last = 0, -1
while True:
    pressure = (round(dps310.pressure,2))
    reading = (last - pressure)
    if 0.02 <= reading <= 0.05: Arrows.UP1(1)
    elif 0.06 <= reading <= 0.1: Arrows.UP1(1),Arrows.UP2(1)
    elif 0.1 <= reading <= 100: Arrows.UP1(1),Arrows.UP2(1),Arrows.UP3(1)
    elif -0.02 >= reading >= -0.05: Arrows.DOWN1(1)
    elif -0.06 >= reading >= -0.1: Arrows.DOWN1(1),Arrows.DOWN2(1)
    elif -0.11 >= reading >= -100: Arrows.DOWN1(1),Arrows.DOWN2(1),Arrows.DOWN3(1)
    else: is31.show()
    last = pressure
    x += 1
    time.sleep(0.1)
I'm currently struggling with this bit here:

Code: Select all

x, last = 0, -1
while True:
    pressure = (round(dps310.pressure,2))
    reading = (last - pressure)
    if 0.02 <= reading <= 0.05: Arrows.UP1(1)
    elif 0.06 <= reading <= 0.1: Arrows.UP1(1),Arrows.UP2(1)
    elif 0.1 <= reading <= 100: Arrows.UP1(1),Arrows.UP2(1),Arrows.UP3(1)
    elif -0.02 >= reading >= -0.05: Arrows.DOWN1(1)
    elif -0.06 >= reading >= -0.1: Arrows.DOWN1(1),Arrows.DOWN2(1)
    elif -0.11 >= reading >= -100: Arrows.DOWN1(1),Arrows.DOWN2(1),Arrows.DOWN3(1)
    else: is31.show()
    last = pressure
    x += 1
    time.sleep(0.1)
The matrix display works with pressure differences, I've driven around hills and the up/down arrows will light up with slight or larger pressure changes as you increase and decrease in lift/sink (it even picked up a quite steep road dip at an intersection).

But my issue is that it's not the prettiest thing to look at, it flashes at your face every time it has an updated reading that was different from the previous one. Definitely not fast enough to induce Epilepsy, but not exactly reassuring when red arrows are frantically flashing "DOWN!".

Question: How do you display a previous reading while showing the current reading? For example: if there is a large increase in air pressure (you're in sink) the small down arrow, medium down arrow, should all be solid red and the highest down arrow is blinking. What I have now is everything just blinks, which again is usable, just not pleasant for my wife.

Thank you for your time.

Progress Pictures:
All lit up! I've changed the Green to White to avoid any issues with color visual impairment (Deuteranomaly). I also haven't inserted the LED diffuser acrylic from Adafruit as I currently blow on the matrix display to increase the pressure inside the case and testing the result (which turns red and then goes white as the pressure inside drops).
PXL_20221129_212752150.jpg
PXL_20221129_212752150.jpg (400.35 KiB) Viewed 248 times
PXL_20221129_211452457.jpg
PXL_20221129_211452457.jpg (399.4 KiB) Viewed 248 times
A modified audio/visual Adafruit case and the QT-Py snap-together case, I had to use my wooden recorder to smush the boards into the snaps. I was relieved when it turned on and worked! Current goal is NO soldering or hardware required for assembly, just a 3D printed case, STEMMA QT connectors, and the three Adafruit boards that make it work. :)

User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

Rendering of the end goal, though honestly, I am too lazy to change the filament to have a two-tone case, but having the option in the future is nice ;)
Render_M_larger.jpg
Render_M_larger.jpg (84.5 KiB) Viewed 247 times

User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

For those following along at home, here are the Visual Variometer snap-together case STEP and STL files that you can print. These are heavily borrowed from Adafruit's QT-Py snap together case and Adafruit's Audio Visualizer case:

STEP:
VisualVarioCase_STEP.zip
(266.63 KiB) Downloaded 1 time
STL:
VisualVarioCase_STL.zip
(321.28 KiB) Downloaded 1 time
If anyone wants to make a version using the Feather RP2040 with a battery pack that would be AMAZING!

User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

So I've been trying to learn from the Adafruit Mini Vu Meter guide found here:
https://learn.adafruit.com/neopixel-min ... i-vu-meter

However I feel quite confused as the guide is both using Neopixels (and I am using the 13x9 Matrix LEDs) as well as its processing audio signals/samples to create... something?

I feel the DPS310 pressure sensor does not experience dynamic and crazy signals like an audio signal would be, so I am left considering if I should skip/remove sections of this guide. But as a total newbie I don't think that would be advisable.

My current method appears to work, but its jerky non-smooth displaying has left me wanting. The Mini Vu Meter looks like it moves quickly and smoothly without the "blinks" between value changes like what I have currently.

So how should I go about switching an audio sensor for a pressure sensor and having different LEDs? Maybe mine is working correctly but just blinks because value changes are just that much slower than audio? What do you think?

Current Visual Vario loop:

Code: Select all

x, last = 0, -1
while True:
    pressure = (round(dps310.pressure,2))
    reading = (last - pressure)
    if 0.02 <= reading <= 0.08: Arrows.UP1(1)
    elif 0.09 <= reading <= 0.2: Arrows.UP1(1),Arrows.UP2(1)
    elif 0.21 <= reading <= 100: Arrows.UP1(1),Arrows.UP2(1),Arrows.UP3(1)
    elif -0.02 >= reading >= -0.08: Arrows.DOWN1(1)
    elif -0.09 >= reading >= -0.2: Arrows.DOWN1(1),Arrows.DOWN2(1)
    elif -0.21 >= reading >= -100: Arrows.DOWN1(1),Arrows.DOWN2(1),Arrows.DOWN3(1)
    else: is31.show()
    last = pressure
    x += 1
    time.sleep(0.02)
Mini Vu Meter loop:

Code: Select all

if last_input != input_val:
        for i in range(input_val):
            #  if the level is lower...
            if last_input > input_val:
                for z in range(last_input):
                    #  turn those pixels off
                    pixels[z] = (OFF)
            #  turn on pixels using the colors array
            pixels[i] = (colors[i])
            pixels.show()
            #  update last_input
            last_input = input_val

    time.sleep(0.01)

User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

Okay, I'v been watching a lot of Python videos this weekend to better understand what I am looking at. I realized that I don't need function Classes, but the definitions were giving me trouble as they wouldn't turn the LED's on (error in the REPL). So I set "self=1" and that seems to turn them ON. Then I played around with the Else section of my while loop and made it just "pass". This turned on the arrows as I breathed on the pressure sensor, but it left the arrows ON, overlapping even. So I set it back to the is31.show() to bring back the blinking behavior (that I am still trying to fix).

This is a real head scratcher for me, mainly because this is my first project and first time really coding anything. Should I be focusing on using the definitions for the arrow values instead of the While Loop, or should I be trying to figure out how to turn the def's ON/OFF with some kind of delay? Or is all of that just a lost cause because my is31.show() is just going to clear everything anyway?

Code: Select all

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

"""
Configure the sensor for continuous measurement with rates,
sampling counts and mode optimized for low power, as recommended
in Infineon's datasheet:
https://www.infineon.com/dgdl/Infineon-DPS310-DataSheet-v01_02-EN.pdf
"""

# (disable pylint warnings for adafruit_dps310.{SampleCount,Rate,Mode}.*
# as they are generated dynamically)
# pylint: disable=no-member

import time
import board
from adafruit_dps310 import advanced
import adafruit_is31fl3741
from adafruit_is31fl3741.adafruit_rgbmatrixqt import Adafruit_RGBMatrixQT


# Create I2C bus.
i2c = board.STEMMA_I2C()  # uses board.SCL and board.SDA

# Create sensor instance
is31 = adafruit_is31fl3741.IS31FL3741(board.STEMMA_I2C())
display = Adafruit_RGBMatrixQT(i2c)
dps310 = advanced.DPS310_Advanced(i2c)

# Pressure Sensor
dps310.reset()
dps310.pressure_oversample_count = advanced.SampleCount.COUNT_64  # 64 is considered high precision
dps310.pressure_rate = advanced.Rate.RATE_1_HZ
dps310.temperature_oversample_count = advanced.SampleCount.COUNT_16  # 16 is considered standard
dps310.temperature_rate = advanced.Rate.RATE_1_HZ
dps310.mode = advanced.Mode.CONT_PRESTEMP
# dps310.wait_temperature_ready()
dps310.wait_pressure_ready()

# LED Matrix Display
is31 = Adafruit_RGBMatrixQT(i2c, allocate=adafruit_is31fl3741.MUST_BUFFER)
is31.show()  # clear any residue on startup
is31.set_led_scaling(0xFF)  # turn on LEDs all the way 0xFF
is31.global_current = 200  # set current to max 0xFF - 255
is31.enable = True  # enable!

# Defined arrows, coordinates for LEDs and colors
def UP1(self=1):
    display.pixel(3,8,0x55FFFF)
    display.pixel(4,8,0x55FFFF)
    display.pixel(4,7,0x55FFFF)
    display.pixel(5,7,0x55FFFF)
    display.pixel(5,6,0x55FFFF)
    display.pixel(6,6,0x55FFFF)
    display.pixel(6,5,0x55FFFF)
    display.pixel(7,6,0x55FFFF)
    display.pixel(7,7,0x55FFFF)
    display.pixel(8,7,0x55FFFF)
    display.pixel(8,8,0x55FFFF)
    display.pixel(9,8,0x55FFFF)


def UP2(self=1):
    display.pixel(0,8,0x55FFFF)
    display.pixel(0,7,0x55FFFF)
    display.pixel(1,7,0x55FFFF)
    display.pixel(1,6,0x55FFFF)
    display.pixel(2,6,0x55FFFF)
    display.pixel(2,5,0x55FFFF)
    display.pixel(3,5,0x55FFFF)
    display.pixel(3,4,0x55FFFF)
    display.pixel(4,4,0x55FFFF)
    display.pixel(4,3,0x55FFFF)
    display.pixel(5,3,0x55FFFF)
    display.pixel(5,2,0x55FFFF)
    display.pixel(6,2,0x55FFFF)
    display.pixel(6,1,0x55FFFF)
    display.pixel(7,2,0x55FFFF)
    display.pixel(7,3,0x55FFFF)
    display.pixel(8,3,0x55FFFF)
    display.pixel(8,4,0x55FFFF)
    display.pixel(9,4,0x55FFFF)
    display.pixel(9,5,0x55FFFF)
    display.pixel(10,5,0x55FFFF)
    display.pixel(10,6,0x55FFFF)
    display.pixel(11,6,0x55FFFF)
    display.pixel(11,7,0x55FFFF)
    display.pixel(12,7,0x55FFFF)
    display.pixel(12,8,0x55FFFF)


def UP3(self=1):
    display.pixel(0,0,0x55FFFF)
    display.pixel(0,1,0x55FFFF)
    display.pixel(0,2,0x55FFFF)
    display.pixel(0,3,0x55FFFF)
    display.pixel(0,4,0x55FFFF)
    display.pixel(1,0,0x55FFFF)
    display.pixel(1,1,0x55FFFF)
    display.pixel(1,2,0x55FFFF)
    display.pixel(1,3,0x55FFFF)
    display.pixel(2,0,0x55FFFF)
    display.pixel(2,1,0x55FFFF)
    display.pixel(2,2,0x55FFFF)
    display.pixel(3,0,0x55FFFF)
    display.pixel(3,1,0x55FFFF)
    display.pixel(4,0,0x55FFFF)
    display.pixel(8,0,0x55FFFF)
    display.pixel(9,0,0x55FFFF)
    display.pixel(9,1,0x55FFFF)
    display.pixel(10,0,0x55FFFF)
    display.pixel(10,1,0x55FFFF)
    display.pixel(10,2,0x55FFFF)
    display.pixel(11,0,0x55FFFF)
    display.pixel(11,1,0x55FFFF)
    display.pixel(11,2,0x55FFFF)
    display.pixel(11,3,0x55FFFF)
    display.pixel(12,0,0x55FFFF)
    display.pixel(12,1,0x55FFFF)
    display.pixel(12,2,0x55FFFF)
    display.pixel(12,3,0x55FFFF)
    display.pixel(12,4,0x55FFFF)


def DOWN1(self=1):
    display.pixel(3,0,0xFF0000)
    display.pixel(4,0,0xFF0000)
    display.pixel(4,1,0xFF0000)
    display.pixel(5,1,0xFF0000)
    display.pixel(5,2,0xFF0000)
    display.pixel(6,2,0xFF0000)
    display.pixel(6,3,0xFF0000)
    display.pixel(7,2,0xFF0000)
    display.pixel(7,1,0xFF0000)
    display.pixel(8,1,0xFF0000)
    display.pixel(8,0,0xFF0000)
    display.pixel(9,0,0xFF0000)


def DOWN2(self=1):
    display.pixel(0,0,0xFF0000)
    display.pixel(0,1,0xFF0000)
    display.pixel(1,1,0xFF0000)
    display.pixel(1,2,0xFF0000)
    display.pixel(2,2,0xFF0000)
    display.pixel(2,3,0xFF0000)
    display.pixel(3,3,0xFF0000)
    display.pixel(3,4,0xFF0000)
    display.pixel(4,4,0xFF0000)
    display.pixel(4,5,0xFF0000)
    display.pixel(5,5,0xFF0000)
    display.pixel(5,6,0xFF0000)
    display.pixel(6,6,0xFF0000)
    display.pixel(6,7,0xFF0000)
    display.pixel(7,6,0xFF0000)
    display.pixel(7,5,0xFF0000)
    display.pixel(8,5,0xFF0000)
    display.pixel(8,4,0xFF0000)
    display.pixel(9,4,0xFF0000)
    display.pixel(9,3,0xFF0000)
    display.pixel(10,3,0xFF0000)
    display.pixel(10,2,0xFF0000)
    display.pixel(11,2,0xFF0000)
    display.pixel(11,1,0xFF0000)
    display.pixel(12,1,0xFF0000)
    display.pixel(12,0,0xFF0000)


def DOWN3(self=1):
    display.pixel(0,8,0xFF0000)
    display.pixel(0,7,0xFF0000)
    display.pixel(0,6,0xFF0000)
    display.pixel(0,5,0xFF0000)
    display.pixel(0,4,0xFF0000)
    display.pixel(1,8,0xFF0000)
    display.pixel(1,7,0xFF0000)
    display.pixel(1,6,0xFF0000)
    display.pixel(1,5,0xFF0000)
    display.pixel(2,8,0xFF0000)
    display.pixel(2,7,0xFF0000)
    display.pixel(2,6,0xFF0000)
    display.pixel(3,8,0xFF0000)
    display.pixel(3,7,0xFF0000)
    display.pixel(4,8,0xFF0000)
    display.pixel(8,8,0xFF0000)
    display.pixel(9,8,0xFF0000)
    display.pixel(9,7,0xFF0000)
    display.pixel(10,8,0xFF0000)
    display.pixel(10,7,0xFF0000)
    display.pixel(10,6,0xFF0000)
    display.pixel(11,8,0xFF0000)
    display.pixel(11,7,0xFF0000)
    display.pixel(11,6,0xFF0000)
    display.pixel(11,5,0xFF0000)
    display.pixel(12,8,0xFF0000)
    display.pixel(12,7,0xFF0000)
    display.pixel(12,6,0xFF0000)
    display.pixel(12,5,0xFF0000)
    display.pixel(12,4,0xFF0000)


# The loop that compares the previous reading to the current reading and displays something.
x, last = 0, -1
while True:
    pressure = (round(dps310.pressure, 2))
    reading = (last - pressure)
    if 0.02 <= reading <= 0.08: UP1()
    elif 0.09 <= reading <= 0.2: UP1(), UP2()
    elif 0.21 <= reading <= 100: UP1(), UP2(), UP3()
    elif -0.02 >= reading >= -0.08: DOWN1()
    elif -0.09 >= reading >= -0.2: DOWN1(), DOWN2()
    elif -0.21 >= reading >= -100: DOWN1(), DOWN2(), DOWN3()
    else: is31.show()
    last = pressure
    x += 1
    time.sleep(0.02)

User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

Okay, a friend of mine took hours out of their evening/day to put this together. We had some hilarious bugs but it was a fun process to work out the issues one by one. I wouldn't call this complete yet, but it feels like a big step in the correct direction:

Code: Select all

# This code implements a visual vario (vertical climb/sink indicator).
# It runs on Adafruit_dps310 board with a a DSP310 for pressure input (measure altitude) and an Adafruit RGB matrix display (9x13 LEDS)
# to display climb/sink. Both devices interface to the board over the I2C bus.
#
# Up arrows indicate a climb. Down arrows indicate sink. More arrows indicate greater climb/sink.
# Climb and sink use different colors.


# Get/Import the libraries.
import time
import board
from adafruit_dps310 import advanced
import adafruit_is31fl3741
from adafruit_is31fl3741.adafruit_rgbmatrixqt import Adafruit_RGBMatrixQT


# ----------------

# Display color RGB constants.
COLOR_RED = 0xFF0000
COLOR_WHITE = 0x55FFFF
COLOR_BLACK = 0x000000

COLOR_UP = COLOR_WHITE
COLOR_DOWN = COLOR_RED

# State machine constants.
STATE_BLANK = 0
STATE_UP_1_ARROW = 1
STATE_UP_2_ARROWS = 2
STATE_UP_3_ARROWS = 3
STATE_DWN_1_ARROW = 4
STATE_DWN_2_ARROWS = 5
STATE_DWN_3_ARROWS = 6

# Climb/Sink rate boundries
RATE_1 = 0.02
RATE_2 = 0.08
RATE_3 = 0.2

#----------------

# Create instances of the 'board', the I2C bus, and the RGB display. and pressure sensor.

# Create I2C bus.
i2c = board.STEMMA_I2C()  # uses board.SCL and board.SDA

# Create the RGB Display instance.
display = Adafruit_RGBMatrixQT(i2c, allocate=adafruit_is31fl3741.MUST_BUFFER)

# Create sensor instance
dps310 = advanced.DPS310_Advanced(i2c)

def init_devices ():
    dps310.reset()
    dps310.pressure_oversample_count = advanced.SampleCount.COUNT_64  # 64 is considered high precision
    dps310.pressure_rate = advanced.Rate.RATE_1_HZ
    dps310.temperature_oversample_count = advanced.SampleCount.COUNT_16  # 16 is considered standard
    dps310.temperature_rate = advanced.Rate.RATE_1_HZ
    dps310.mode = advanced.Mode.CONT_PRESTEMP
    # dps310.wait_temperature_ready()
    dps310.wait_pressure_ready()

    display.show()  # clear any residue on startup
    display.set_led_scaling(0xFF)  # turn on LEDs all the way 0xFF
    display.global_current = 200  # set current to max 0xFF - 255
    display.enable = True  # enable!

#============================

# Display 1st Arrow UP,
# color: the RGB color to use for the arrow.
def UP1(color):
    display.pixel(3,8, color)
    display.pixel(4,8, color)
    display.pixel(4,7, color)
    display.pixel(5,7, color)
    display.pixel(5,6, color)
    display.pixel(6,6, color)
    display.pixel(6,5, color)
    display.pixel(7,6, color)
    display.pixel(7,7, color)
    display.pixel(8,7, color)
    display.pixel(8,8, color)
    display.pixel(9,8, color)


# Display the 2nd Arrow UP,
# color: the RGB color to use for the arrow.
def UP2(color):
    display.pixel(0,8,color)
    display.pixel(0,7,color)
    display.pixel(1,7,color)
    display.pixel(1,6,color)
    display.pixel(2,6,color)
    display.pixel(2,5,color)
    display.pixel(3,5,color)
    display.pixel(3,4,color)
    display.pixel(4,4,color)
    display.pixel(4,3,color)
    display.pixel(5,3,color)
    display.pixel(5,2,color)
    display.pixel(6,2,color)
    display.pixel(6,1,color)
    display.pixel(7,2,color)
    display.pixel(7,3,color)
    display.pixel(8,3,color)
    display.pixel(8,4,color)
    display.pixel(9,4,color)
    display.pixel(9,5,color)
    display.pixel(10,5,color)
    display.pixel(10,6,color)
    display.pixel(11,6,color)
    display.pixel(11,7,color)
    display.pixel(12,7,color)
    display.pixel(12,8,color)

# Display the 3rd Arrow UP,
# color: the RGB color to use for the arrow.
def UP3(color):
    display.pixel(0,0,color)
    display.pixel(0,1,color)
    display.pixel(0,2,color)
    display.pixel(0,3,color)
    display.pixel(0,4,color)
    display.pixel(1,0,color)
    display.pixel(1,1,color)
    display.pixel(1,2,color)
    display.pixel(1,3,color)
    display.pixel(2,0,color)
    display.pixel(2,1,color)
    display.pixel(2,2,color)
    display.pixel(3,0,color)
    display.pixel(3,1,color)
    display.pixel(4,0,color)
    display.pixel(8,0,color)
    display.pixel(9,0,color)
    display.pixel(9,1,color)
    display.pixel(10,0,color)
    display.pixel(10,1,color)
    display.pixel(10,2,color)
    display.pixel(11,0,color)
    display.pixel(11,1,color)
    display.pixel(11,2,color)
    display.pixel(11,3,color)
    display.pixel(12,0,color)
    display.pixel(12,1,color)
    display.pixel(12,2,color)
    display.pixel(12,3,color)
    display.pixel(12,4,color)

# Display 1st Arrow Down,
# color: the RGB color to use for the arrow.
def DOWN1(color):
    display.pixel(3,0,color)
    display.pixel(4,0,color)
    display.pixel(4,1,color)
    display.pixel(5,1,color)
    display.pixel(5,2,color)
    display.pixel(6,2,color)
    display.pixel(6,3,color)
    display.pixel(7,2,color)
    display.pixel(7,1,color)
    display.pixel(8,1,color)
    display.pixel(8,0,color)
    display.pixel(9,0,color)

# Display 2nd Arrow Down,
# color: the RGB color to use for the arrow.
def DOWN2(color):
    display.pixel(0,0,color)
    display.pixel(0,1,color)
    display.pixel(1,1,color)
    display.pixel(1,2,color)
    display.pixel(2,2,color)
    display.pixel(2,3,color)
    display.pixel(3,3,color)
    display.pixel(3,4,color)
    display.pixel(4,4,color)
    display.pixel(4,5,color)
    display.pixel(5,5,color)
    display.pixel(5,6,color)
    display.pixel(6,6,color)
    display.pixel(6,7,color)
    display.pixel(7,6,color)
    display.pixel(7,5,color)
    display.pixel(8,5,color)
    display.pixel(8,4,color)
    display.pixel(9,4,color)
    display.pixel(9,3,color)
    display.pixel(10,3,color)
    display.pixel(10,2,color)
    display.pixel(11,2,color)
    display.pixel(11,1,color)
    display.pixel(12,1,color)
    display.pixel(12,0,color)

# Display 3rd Arrow Down,
# color: the RGB color to use for the arrow.
def DOWN3(color):
    display.pixel(0,8,color)
    display.pixel(0,7,color)
    display.pixel(0,6,color)
    display.pixel(0,5,color)
    display.pixel(0,4,color)
    display.pixel(1,8,color)
    display.pixel(1,7,color)
    display.pixel(1,6,color)
    display.pixel(1,5,color)
    display.pixel(2,8,color)
    display.pixel(2,7,color)
    display.pixel(2,6,color)
    display.pixel(3,8,color)
    display.pixel(3,7,color)
    display.pixel(4,8,color)
    display.pixel(8,8,color)
    display.pixel(9,8,color)
    display.pixel(9,7,color)
    display.pixel(10,8,color)
    display.pixel(10,7,color)
    display.pixel(10,6,color)
    display.pixel(11,8,color)
    display.pixel(11,7,color)
    display.pixel(11,6,color)
    display.pixel(11,5,color)
    display.pixel(12,8,color)
    display.pixel(12,7,color)
    display.pixel(12,6,color)
    display.pixel(12,5,color)
    display.pixel(12,4,color)



# =========================================
# The Main loop

init_devices()
last_state = STATE_BLANK
curr_state = STATE_BLANK
last_pressure = (round(dps310.pressure, 2))


while True:
    # What arrows state should we have based on the climb/sink rate
    pressure = (round(dps310.pressure, 2))
    rate = (last_pressure - pressure)

    if rate > RATE_1 and rate <= RATE_2:
        curr_state = STATE_UP_1_ARROW
    elif rate > RATE_2 and rate <= RATE_3:
        curr_state = STATE_UP_2_ARROWS
    elif rate > RATE_3:
        curr_state = STATE_UP_3_ARROWS
    elif rate < -RATE_1 and rate >= -RATE_2:
        curr_state = STATE_DWN_1_ARROW
    elif rate < -RATE_2 and rate >= -RATE_3:
        curr_state = STATE_DWN_2_ARROWS
    elif rate < -RATE_3:
        curr_state = STATE_DWN_3_ARROWS
    else:
        curr_state = STATE_BLANK
        
    
    #
    # We don't need to turn anything off if the current state is the same as the last state
    #
    if curr_state != last_state:
        if curr_state == STATE_BLANK:
            # get rid of any arrows that are currently being shown.
            if last_state == STATE_UP_1_ARROW:
                UP1(COLOR_BLACK)
            elif last_state == STATE_UP_2_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
            elif last_state == STATE_UP_3_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
                UP3(COLOR_BLACK)
            elif last_state == STATE_DWN_1_ARROW:
                DOWN1(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_UP_1_ARROW:
            if last_state == STATE_BLANK:
                pass # nothing to do.
            elif last_state == STATE_UP_2_ARROWS:
                UP2(COLOR_BLACK) # Don't need the 2nd arrow
            elif last_state == STATE_UP_3_ARROWS:
                UP2(COLOR_BLACK) # Don't need the 2nd
                UP3(COLOR_BLACK) # or 3rd arrow.
            elif last_state == STATE_DWN_1_ARROW:
                DOWN1(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

            # Add needed Arrows
            if last_state == STATE_BLANK or last_state == STATE_DWN_1_ARROW or last_state == STATE_DWN_2_ARROWS or last_state == STATE_DWN_3_ARROWS:
                UP1(COLOR_UP)
            elif last_state == STATE_UP_2_ARROWS or last_state == STATE_UP_3_ARROWS:
                pass # Nothing to do. The 1st arrow is already being shown.
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_UP_2_ARROWS:
            # Get rid of unneeded old arrows.
            if last_state == STATE_UP_3_ARROWS:
                UP3(COLOR_BLACK)
            elif last_state == STATE_DWN_1_ARROW:
                DOWN1(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            elif last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW:
                pass # Do Nothing
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

            # Light up the needed arrows
            if last_state == STATE_BLANK or last_state == STATE_DWN_1_ARROW or last_state == STATE_DWN_2_ARROWS or last_state == STATE_DWN_3_ARROWS:
                UP1(COLOR_UP)
                UP2(COLOR_UP)
            elif last_state == STATE_UP_1_ARROW:
                UP2(COLOR_UP)
            elif last_state == STATE_UP_3_ARROWS:
                pass # Do nothing, already have the 2 arrows showing
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_UP_3_ARROWS:
            # get rid of unwanted arrows for the 3 arrows up case
            if last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW or last_state == STATE_UP_2_ARROWS:
                pass # Do nothing, there are now arrows to erase.
            elif last_state == STATE_DWN_1_ARROW:
                DOWN1(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

            # Light up the needed arrows.
            if last_state == STATE_BLANK or last_state == STATE_DWN_1_ARROW or last_state == STATE_DWN_2_ARROWS or last_state == STATE_DWN_3_ARROWS:
                UP1(COLOR_UP)
                UP2(COLOR_UP)
                UP3(COLOR_UP)
            elif last_state == STATE_UP_1_ARROW:
                UP2(COLOR_UP)
                UP3(COLOR_UP)
            elif last_state == STATE_UP_2_ARROWS:
                UP3(COLOR_UP)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_DWN_1_ARROW:
            # Get rid of the unwanted arrows for the 1 arrow down case
            if last_state == STATE_BLANK:
                pass # Do nothing
            elif last_state == STATE_UP_1_ARROW:
                UP1(COLOR_BLACK)
            elif last_state == STATE_UP_2_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
            elif last_state == STATE_UP_3_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
                UP3(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            else:
                 raise Exception("Unexpected state=%d in match statement." %(last_state))

            # now light up the needed arrow
            if last_state == STATE_DWN_2_ARROWS or last_state == STATE_DWN_3_ARROWS:
                 pass # Do nothing
            elif last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW or last_state == STATE_UP_2_ARROWS or last_state == STATE_UP_3_ARROWS:
                DOWN1(COLOR_DOWN)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_DWN_2_ARROWS:
            # get rid of old unneeded arrows
            if last_state == STATE_BLANK or last_state == STATE_DWN_1_ARROW:
                pass # Do nothing
            elif last_state == STATE_UP_1_ARROW:
                UP1(COLOR_BLACK)
            elif last_state == STATE_UP_2_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
            elif last_state == STATE_UP_3_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
                UP3(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

            # now light up the needed arrows for 2 arrows down
            if last_state == STATE_DWN_3_ARROWS:
                pass # Do Nothing
            elif last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW or last_state == STATE_UP_2_ARROWS or last_state == STATE_UP_3_ARROWS:
                DOWN1(COLOR_DOWN)
                DOWN2(COLOR_DOWN)
            elif last_state == STATE_DWN_1_ARROW:
                DOWN2(COLOR_DOWN)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_DWN_3_ARROWS:
            # get rid of old unneeded arrows
            if last_state == STATE_BLANK  or last_state == STATE_DWN_1_ARROW  or last_state == STATE_DWN_2_ARROWS:
                pass # Do nothing
            elif last_state == STATE_UP_1_ARROW:
                UP1(COLOR_BLACK)
            elif last_state ==  STATE_UP_2_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
            elif last_state == STATE_UP_3_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
                UP3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

                # now light up the needed arrows for 3 arrows down
            if last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW or last_state == STATE_UP_2_ARROWS or last_state == STATE_UP_3_ARROWS:
                DOWN1(COLOR_DOWN)
                DOWN2(COLOR_DOWN)
                DOWN3(COLOR_DOWN)
            elif last_state == STATE_DWN_1_ARROW:
                DOWN2(COLOR_DOWN)
                DOWN3(COLOR_DOWN)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN3(COLOR_DOWN)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))
        else:
            raise Exception("Unexpected state=%d in match statement." %(last_state))

        # The I2C buffer for the display may not be have all been sent so send it.
        display.show()

    #remember the current state and the current pressure
    last_state = curr_state
    last_pressure = pressure

    # give the user some time to see the arrows.
    time.sleep(0.02)
They also had me test some code they wrote to demonstrate the desired effect of the direction arrows going UP/DOWN:

Code: Select all

# This code implements a visual vario (vertical climb/sink indicator).
# It runs on Adafruit_dps310 board with a a DSP310 for pressure input (measure altitude) and an Adafruit RGB matrix display (9x13 LEDS)
# to display climb/sink. Both devices interface to the board over the I2C bus.
#
# Up arrows indicate a climb. Down arrows indicate sink. More arrows indicate greater climb/sink.
# Climb and sink use different colors.


# Get/Import the libraries.
import time
import board
from adafruit_dps310 import advanced
import adafruit_is31fl3741
from adafruit_is31fl3741.adafruit_rgbmatrixqt import Adafruit_RGBMatrixQT


# ----------------

# Display color RGB constants.
COLOR_RED = 0xFF0000
COLOR_WHITE = 0x55FFFF
COLOR_BLACK = 0x000000

COLOR_UP = COLOR_WHITE
COLOR_DOWN = COLOR_RED

# State machine constants.
STATE_BLANK = 0
STATE_UP_1_ARROW = 1
STATE_UP_2_ARROWS = 2
STATE_UP_3_ARROWS = 3
STATE_DWN_1_ARROW = 4
STATE_DWN_2_ARROWS = 5
STATE_DWN_3_ARROWS = 6

# Climb/Sink rate boundries
RATE_1 = 0.02
RATE_2 = 0.08
RATE_3 = 0.2

#----------------

# Create instances of the 'board', the I2C bus, and the RGB display. and pressure sensor.

# Create I2C bus.
i2c = board.STEMMA_I2C()  # uses board.SCL and board.SDA

# Create the RGB Display instance.
#display = adafruit_is31fl3741.IS31FL3741(i2c)
display = Adafruit_RGBMatrixQT(i2c, allocate=adafruit_is31fl3741.MUST_BUFFER)

# Create sensor instance
dps310 = advanced.DPS310_Advanced(i2c)

def init_devices ():
    dps310.reset()
    dps310.pressure_oversample_count = advanced.SampleCount.COUNT_64  # 64 is considered high precision
    dps310.pressure_rate = advanced.Rate.RATE_1_HZ
    dps310.temperature_oversample_count = advanced.SampleCount.COUNT_16  # 16 is considered standard
    dps310.temperature_rate = advanced.Rate.RATE_1_HZ
    dps310.mode = advanced.Mode.CONT_PRESTEMP
    # dps310.wait_temperature_ready()
    dps310.wait_pressure_ready()

    display.show()  # clear any residue on startup
    display.set_led_scaling(0xFF)  # turn on LEDs all the way 0xFF
    display.global_current = 200  # set current to max 0xFF - 255
    display.enable = True  # enable!

#============================

# Display 1st Arrow UP,
# color: the RGB color to use for the arrow.
def UP1(color):
    display.pixel(3,8, color)
    display.pixel(4,8, color)
    display.pixel(4,7, color)
    display.pixel(5,7, color)
    display.pixel(5,6, color)
    display.pixel(6,6, color)
    display.pixel(6,5, color)
    display.pixel(7,6, color)
    display.pixel(7,7, color)
    display.pixel(8,7, color)
    display.pixel(8,8, color)
    display.pixel(9,8, color)


# Display the 2nd Arrow UP,
# color: the RGB color to use for the arrow.
def UP2(color):
    display.pixel(0,8,color)
    display.pixel(0,7,color)
    display.pixel(1,7,color)
    display.pixel(1,6,color)
    display.pixel(2,6,color)
    display.pixel(2,5,color)
    display.pixel(3,5,color)
    display.pixel(3,4,color)
    display.pixel(4,4,color)
    display.pixel(4,3,color)
    display.pixel(5,3,color)
    display.pixel(5,2,color)
    display.pixel(6,2,color)
    display.pixel(6,1,color)
    display.pixel(7,2,color)
    display.pixel(7,3,color)
    display.pixel(8,3,color)
    display.pixel(8,4,color)
    display.pixel(9,4,color)
    display.pixel(9,5,color)
    display.pixel(10,5,color)
    display.pixel(10,6,color)
    display.pixel(11,6,color)
    display.pixel(11,7,color)
    display.pixel(12,7,color)
    display.pixel(12,8,color)

# Display the 3rd Arrow UP,
# color: the RGB color to use for the arrow.
def UP3(color):
    display.pixel(0,0,color)
    display.pixel(0,1,color)
    display.pixel(0,2,color)
    display.pixel(0,3,color)
    display.pixel(0,4,color)
    display.pixel(1,0,color)
    display.pixel(1,1,color)
    display.pixel(1,2,color)
    display.pixel(1,3,color)
    display.pixel(2,0,color)
    display.pixel(2,1,color)
    display.pixel(2,2,color)
    display.pixel(3,0,color)
    display.pixel(3,1,color)
    display.pixel(4,0,color)
    display.pixel(8,0,color)
    display.pixel(9,0,color)
    display.pixel(9,1,color)
    display.pixel(10,0,color)
    display.pixel(10,1,color)
    display.pixel(10,2,color)
    display.pixel(11,0,color)
    display.pixel(11,1,color)
    display.pixel(11,2,color)
    display.pixel(11,3,color)
    display.pixel(12,0,color)
    display.pixel(12,1,color)
    display.pixel(12,2,color)
    display.pixel(12,3,color)
    display.pixel(12,4,color)

# Display 1st Arrow Down,
# color: the RGB color to use for the arrow.
def DOWN1(color):
    display.pixel(3,0,color)
    display.pixel(4,0,color)
    display.pixel(4,1,color)
    display.pixel(5,1,color)
    display.pixel(5,2,color)
    display.pixel(6,2,color)
    display.pixel(6,3,color)
    display.pixel(7,2,color)
    display.pixel(7,1,color)
    display.pixel(8,1,color)
    display.pixel(8,0,color)
    display.pixel(9,0,color)

# Display 2nd Arrow Down,
# color: the RGB color to use for the arrow.
def DOWN2(color):
    display.pixel(0,0,color)
    display.pixel(0,1,color)
    display.pixel(1,1,color)
    display.pixel(1,2,color)
    display.pixel(2,2,color)
    display.pixel(2,3,color)
    display.pixel(3,3,color)
    display.pixel(3,4,color)
    display.pixel(4,4,color)
    display.pixel(4,5,color)
    display.pixel(5,5,color)
    display.pixel(5,6,color)
    display.pixel(6,6,color)
    display.pixel(6,7,color)
    display.pixel(7,6,color)
    display.pixel(7,5,color)
    display.pixel(8,5,color)
    display.pixel(8,4,color)
    display.pixel(9,4,color)
    display.pixel(9,3,color)
    display.pixel(10,3,color)
    display.pixel(10,2,color)
    display.pixel(11,2,color)
    display.pixel(11,1,color)
    display.pixel(12,1,color)
    display.pixel(12,0,color)

# Display 3rd Arrow Down,
# color: the RGB color to use for the arrow.
def DOWN3(color):
    display.pixel(0,8,color)
    display.pixel(0,7,color)
    display.pixel(0,6,color)
    display.pixel(0,5,color)
    display.pixel(0,4,color)
    display.pixel(1,8,color)
    display.pixel(1,7,color)
    display.pixel(1,6,color)
    display.pixel(1,5,color)
    display.pixel(2,8,color)
    display.pixel(2,7,color)
    display.pixel(2,6,color)
    display.pixel(3,8,color)
    display.pixel(3,7,color)
    display.pixel(4,8,color)
    display.pixel(8,8,color)
    display.pixel(9,8,color)
    display.pixel(9,7,color)
    display.pixel(10,8,color)
    display.pixel(10,7,color)
    display.pixel(10,6,color)
    display.pixel(11,8,color)
    display.pixel(11,7,color)
    display.pixel(11,6,color)
    display.pixel(11,5,color)
    display.pixel(12,8,color)
    display.pixel(12,7,color)
    display.pixel(12,6,color)
    display.pixel(12,5,color)
    display.pixel(12,4,color)



# =========================================
# The Main loop

init_devices()
last_state = STATE_BLANK
curr_state = STATE_BLANK
last_pressure = (round(dps310.pressure, 2))
state_list = [STATE_UP_1_ARROW, STATE_UP_2_ARROWS, STATE_UP_3_ARROWS, STATE_UP_2_ARROWS, STATE_UP_1_ARROW, STATE_BLANK, \
    STATE_DWN_1_ARROW,  STATE_DWN_2_ARROWS, STATE_DWN_3_ARROWS, STATE_DWN_2_ARROWS, STATE_DWN_1_ARROW, STATE_BLANK]
index = 0

while True:
    # What arrows state should we have based on the climb/sink rate
    pressure = (round(dps310.pressure, 2))
    rate = (last_pressure - pressure)

    if index == len(state_list) :
        index = 0
    curr_state = state_list[index]
    index = index + 1
        
    
    #
    # We don't need to turn anything off if the current state is the same as the last state
    #
    if curr_state != last_state:
        if curr_state == STATE_BLANK:
            # get rid of any arrows that are currently being shown.
            if last_state == STATE_UP_1_ARROW:
                UP1(COLOR_BLACK)
            elif last_state == STATE_UP_2_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
            elif last_state == STATE_UP_3_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
                UP3(COLOR_BLACK)
            elif last_state == STATE_DWN_1_ARROW:
                DOWN1(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_UP_1_ARROW:
            if last_state == STATE_BLANK:
                pass # nothing to do.
            elif last_state == STATE_UP_2_ARROWS:
                UP2(COLOR_BLACK) # Don't need the 2nd arrow
            elif last_state == STATE_UP_3_ARROWS:
                UP2(COLOR_BLACK) # Don't need the 2nd
                UP3(COLOR_BLACK) # or 3rd arrow.
            elif last_state == STATE_DWN_1_ARROW:
                DOWN1(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

            # Add needed Arrows
            if last_state == STATE_BLANK or last_state == STATE_DWN_1_ARROW or last_state == STATE_DWN_2_ARROWS or last_state == STATE_DWN_3_ARROWS:
                UP1(COLOR_UP)
            elif last_state == STATE_UP_2_ARROWS or last_state == STATE_UP_3_ARROWS:
                pass # Nothing to do. The 1st arrow is already being shown.
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_UP_2_ARROWS:
            # Get rid of unneeded old arrows.
            if last_state == STATE_UP_3_ARROWS:
                UP3(COLOR_BLACK)
            elif last_state == STATE_DWN_1_ARROW:
                DOWN1(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            elif last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW:
                pass # Do Nothing
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

            # Light up the needed arrows
            if last_state == STATE_BLANK or last_state == STATE_DWN_1_ARROW or last_state == STATE_DWN_2_ARROWS or last_state == STATE_DWN_3_ARROWS:
                UP1(COLOR_UP)
                UP2(COLOR_UP)
            elif last_state == STATE_UP_1_ARROW:
                UP2(COLOR_UP)
            elif last_state == STATE_UP_3_ARROWS:
                pass # Do nothing, already have the 2 arrows showing
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_UP_3_ARROWS:
            # get rid of unwanted arrows for the 3 arrows up case
            if last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW or last_state == STATE_UP_2_ARROWS:
                pass # Do nothing, there are now arrows to erase.
            elif last_state == STATE_DWN_1_ARROW:
                DOWN1(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

            # Light up the needed arrows.
            if last_state == STATE_BLANK or last_state == STATE_DWN_1_ARROW or last_state == STATE_DWN_2_ARROWS or last_state == STATE_DWN_3_ARROWS:
                UP1(COLOR_UP)
                UP2(COLOR_UP)
                UP3(COLOR_UP)
            elif last_state == STATE_UP_1_ARROW:
                UP2(COLOR_UP)
                UP3(COLOR_UP)
            elif last_state == STATE_UP_2_ARROWS:
                UP3(COLOR_UP)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_DWN_1_ARROW:
            # Get rid of the unwanted arrows for the 1 arrow down case
            if last_state == STATE_BLANK:
                pass # Do nothing
            elif last_state == STATE_UP_1_ARROW:
                UP1(COLOR_BLACK)
            elif last_state == STATE_UP_2_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
            elif last_state == STATE_UP_3_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
                UP3(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            else:
                 raise Exception("Unexpected state=%d in match statement." %(last_state))

            # now light up the needed arrow
            if last_state == STATE_DWN_2_ARROWS or last_state == STATE_DWN_3_ARROWS:
                 pass # Do nothing
            elif last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW or last_state == STATE_UP_2_ARROWS or last_state == STATE_UP_3_ARROWS:
                DOWN1(COLOR_DOWN)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_DWN_2_ARROWS:
            # get rid of old unneeded arrows
            if last_state == STATE_BLANK or last_state == STATE_DWN_1_ARROW:
                pass # Do nothing
            elif last_state == STATE_UP_1_ARROW:
                UP1(COLOR_BLACK)
            elif last_state == STATE_UP_2_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
            elif last_state == STATE_UP_3_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
                UP3(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

            # now light up the needed arrows for 2 arrows down
            if last_state == STATE_DWN_3_ARROWS:
                pass # Do Nothing
            elif last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW or last_state == STATE_UP_2_ARROWS or last_state == STATE_UP_3_ARROWS:
                DOWN1(COLOR_DOWN)
                DOWN2(COLOR_DOWN)
            elif last_state == STATE_DWN_1_ARROW:
                DOWN2(COLOR_DOWN)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_DWN_3_ARROWS:
            # get rid of old unneeded arrows
            if last_state == STATE_BLANK  or last_state == STATE_DWN_1_ARROW  or last_state == STATE_DWN_2_ARROWS:
                pass # Do nothing
            elif last_state == STATE_UP_1_ARROW:
                UP1(COLOR_BLACK)
            elif last_state ==  STATE_UP_2_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
            elif last_state == STATE_UP_3_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
                UP3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

                # now light up the needed arrows for 3 arrows down
            if last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW or last_state == STATE_UP_2_ARROWS or last_state == STATE_UP_3_ARROWS:
                DOWN1(COLOR_DOWN)
                DOWN2(COLOR_DOWN)
                DOWN3(COLOR_DOWN)
            elif last_state == STATE_DWN_1_ARROW:
                DOWN2(COLOR_DOWN)
                DOWN3(COLOR_DOWN)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN3(COLOR_DOWN)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))
        else:
            raise Exception("Unexpected state=%d in match statement." %(last_state))

        # The I2C buffer for the display may not be have all been sent so send it.
        display.show()

    #remember the current state and the current pressure
    last_state = curr_state
    last_pressure = pressure

    # give the user some time to see the arrows.
    time.sleep(0.2)
It still feels a bit "blinky" to me still, and I am sure we might continue to take a stab at it later. It's quite possible this is working as intended but me blowing on a sensor isn't exactly the best method for testing. The alternative is driving around with it over the valley hills. IF it is working correctly the next step will be to dial in the values for each pressure change range for the different arrows.

User avatar
goney3
 
Posts: 16
Joined: Tue Nov 08, 2022 2:34 pm

Re: Paragliding Visual Variometer for the Hearing Impaired

Post by goney3 »

This feels essentially complete now, though I think the RATE_1 through RATE_3 need some adjustment, driving around over hills shows a good result with the first and second arrows, but the third arrow only activates when extremely steep. But since this code is adjustable, it should be easy enough to dial in:

Code: Select all

# This code implements a visual vario (vertical climb/sink indicator).
# It runs on Adafruit_dps310 board with a a DSP310 for pressure input (measure altitude) and an Adafruit RGB matrix display (9x13 LEDS)
# to display climb/sink. Both devices interface to the board over the I2C bus.
#
# Up arrows indicate a climb. Down arrows indicate sink. More arrows indicate greater climb/sink.
# Climb and sink use different colors.


# Get/Import the libraries.
import time
import board
from adafruit_dps310 import advanced
import adafruit_is31fl3741
from adafruit_is31fl3741.adafruit_rgbmatrixqt import Adafruit_RGBMatrixQT


# ----------------

# Display color RGB constants.
COLOR_RED = 0xFF0000
COLOR_WHITE = 0x55FFFF
COLOR_BLACK = 0x000000

COLOR_UP = COLOR_WHITE
COLOR_DOWN = COLOR_RED

# State machine constants.
STATE_BLANK = 0
STATE_UP_1_ARROW = 1
STATE_UP_2_ARROWS = 2
STATE_UP_3_ARROWS = 3
STATE_DWN_1_ARROW = 4
STATE_DWN_2_ARROWS = 5
STATE_DWN_3_ARROWS = 6

# Climb/Sink rate boundries, ft/min
RATE_1 = 50.0 # one arrow
RATE_2 = 200.0 # two arrows
RATE_3 = 500.0 # three arrows

# Display update period (seconds)
DISPLAY_PERIOD = 0.3 
# Number of measurements to average over during a display period.
# NOTE: that DISPALY_PERIOD / MEASUREMENTS_IN_DISPLAY_PERIOD must be > 0.016 since the
# fastest that the 310 can measure pressure is every 0.016 seconds.
MEASUREMENTS_IN_DISPLAY_PERIOD = 10

# hPa (air pressure) to feet altitude table.
# Each row is a different air pressure, with each row an increment ot 50 hPa
# [hPa, ft]
HPA_INDEX = 0 # The pressure is in the 1st item in the row.
ALTITUDE_INDEX = 1 # the altitude is the second item in the row.
altitude_table = [\
    [50.0, 63394.79],\
    [100.0, 51828.43],\
    [150.0, 44320.73],\
    [200.0, 38631.54],\
    [250.0, 33999.14],\
    [300.0, 30065.46],\
    [350.0, 26631.44],\
    [400.0, 23574.25],\
    [450.0, 20812.39],\
    [500.0, 18288.83],\
    [550.0, 15961.99],\
    [600.0, 13800.60],\
    [650.0, 11780.46],\
    [700.0, 9882.48],\
    [750.0, 8091.29],\
    [800.0, 6394.32],\
    [850.0, 4781.17],\
    [900.0, 3243.11],\
    [950.0, 1772.76],\
    [1000.0, 363.79],\
    [1050.0, -989.23]\
    ]

# Coefficient of 1st order low pass IIR (Infinit implulse response) filter for pressure
# measurements.
# A value of 1.0 does no filtering of the pressure data.
# A value of 0.0 will completely stop the pressure data. 
# A higher value gives more weight to the most resent pressures measured. This means that
# changes in measured pressure are seen quicker on the display but may be more jumpy.
# A lower value means that pressure changes take longer to show up on the display. But the
# pressure output will be much smoother.
IIR_COEFF = 0.20

#----------------

# Create instances of the 'board', the I2C bus, and the RGB display. and pressure sensor.

# Create I2C bus.
i2c = board.STEMMA_I2C()  # uses board.SCL and board.SDA

# Create the RGB Display instance.
#display = adafruit_is31fl3741.IS31FL3741(i2c)
display = Adafruit_RGBMatrixQT(i2c, allocate=adafruit_is31fl3741.MUST_BUFFER)

# Create sensor instance
dps310 = advanced.DPS310_Advanced(i2c)

def init_devices ():
    dps310.reset()
    dps310.pressure_oversample_count = advanced.SampleCount.COUNT_64  # 64 is considered high precision
    dps310.pressure_rate = advanced.Rate.RATE_1_HZ
    dps310.temperature_oversample_count = advanced.SampleCount.COUNT_16  # 16 is considered standard
    dps310.temperature_rate = advanced.Rate.RATE_1_HZ
    dps310.mode = advanced.Mode.CONT_PRESTEMP
    # dps310.wait_temperature_ready()
    dps310.wait_pressure_ready()

    display.show()  # clear any residue on startup
    display.set_led_scaling(0xFF)  # turn on LEDs all the way 0xFF
    display.global_current = 200  # set current to max 0xFF - 255
    display.enable = True  # enable!

#============================

# Display 1st Arrow UP,
# color: the RGB color to use for the arrow.
def UP1(color):
    display.pixel(3,8, color)
    display.pixel(4,8, color)
    display.pixel(4,7, color)
    display.pixel(5,7, color)
    display.pixel(5,6, color)
    display.pixel(6,6, color)
    display.pixel(6,5, color)
    display.pixel(7,6, color)
    display.pixel(7,7, color)
    display.pixel(8,7, color)
    display.pixel(8,8, color)
    display.pixel(9,8, color)


# Display the 2nd Arrow UP,
# color: the RGB color to use for the arrow.
def UP2(color):
    display.pixel(0,8,color)
    display.pixel(0,7,color)
    display.pixel(1,7,color)
    display.pixel(1,6,color)
    display.pixel(2,6,color)
    display.pixel(2,5,color)
    display.pixel(3,5,color)
    display.pixel(3,4,color)
    display.pixel(4,4,color)
    display.pixel(4,3,color)
    display.pixel(5,3,color)
    display.pixel(5,2,color)
    display.pixel(6,2,color)
    display.pixel(6,1,color)
    display.pixel(7,2,color)
    display.pixel(7,3,color)
    display.pixel(8,3,color)
    display.pixel(8,4,color)
    display.pixel(9,4,color)
    display.pixel(9,5,color)
    display.pixel(10,5,color)
    display.pixel(10,6,color)
    display.pixel(11,6,color)
    display.pixel(11,7,color)
    display.pixel(12,7,color)
    display.pixel(12,8,color)

# Display the 3rd Arrow UP,
# color: the RGB color to use for the arrow.
def UP3(color):
    display.pixel(0,0,color)
    display.pixel(0,1,color)
    display.pixel(0,2,color)
    display.pixel(0,3,color)
    display.pixel(0,4,color)
    display.pixel(1,0,color)
    display.pixel(1,1,color)
    display.pixel(1,2,color)
    display.pixel(1,3,color)
    display.pixel(2,0,color)
    display.pixel(2,1,color)
    display.pixel(2,2,color)
    display.pixel(3,0,color)
    display.pixel(3,1,color)
    display.pixel(4,0,color)
    display.pixel(8,0,color)
    display.pixel(9,0,color)
    display.pixel(9,1,color)
    display.pixel(10,0,color)
    display.pixel(10,1,color)
    display.pixel(10,2,color)
    display.pixel(11,0,color)
    display.pixel(11,1,color)
    display.pixel(11,2,color)
    display.pixel(11,3,color)
    display.pixel(12,0,color)
    display.pixel(12,1,color)
    display.pixel(12,2,color)
    display.pixel(12,3,color)
    display.pixel(12,4,color)

# Display 1st Arrow Down,
# color: the RGB color to use for the arrow.
def DOWN1(color):
    display.pixel(3,0,color)
    display.pixel(4,0,color)
    display.pixel(4,1,color)
    display.pixel(5,1,color)
    display.pixel(5,2,color)
    display.pixel(6,2,color)
    display.pixel(6,3,color)
    display.pixel(7,2,color)
    display.pixel(7,1,color)
    display.pixel(8,1,color)
    display.pixel(8,0,color)
    display.pixel(9,0,color)

# Display 2nd Arrow Down,
# color: the RGB color to use for the arrow.
def DOWN2(color):
    display.pixel(0,0,color)
    display.pixel(0,1,color)
    display.pixel(1,1,color)
    display.pixel(1,2,color)
    display.pixel(2,2,color)
    display.pixel(2,3,color)
    display.pixel(3,3,color)
    display.pixel(3,4,color)
    display.pixel(4,4,color)
    display.pixel(4,5,color)
    display.pixel(5,5,color)
    display.pixel(5,6,color)
    display.pixel(6,6,color)
    display.pixel(6,7,color)
    display.pixel(7,6,color)
    display.pixel(7,5,color)
    display.pixel(8,5,color)
    display.pixel(8,4,color)
    display.pixel(9,4,color)
    display.pixel(9,3,color)
    display.pixel(10,3,color)
    display.pixel(10,2,color)
    display.pixel(11,2,color)
    display.pixel(11,1,color)
    display.pixel(12,1,color)
    display.pixel(12,0,color)

# Display 3rd Arrow Down,
# color: the RGB color to use for the arrow.
def DOWN3(color):
    display.pixel(0,8,color)
    display.pixel(0,7,color)
    display.pixel(0,6,color)
    display.pixel(0,5,color)
    display.pixel(0,4,color)
    display.pixel(1,8,color)
    display.pixel(1,7,color)
    display.pixel(1,6,color)
    display.pixel(1,5,color)
    display.pixel(2,8,color)
    display.pixel(2,7,color)
    display.pixel(2,6,color)
    display.pixel(3,8,color)
    display.pixel(3,7,color)
    display.pixel(4,8,color)
    display.pixel(8,8,color)
    display.pixel(9,8,color)
    display.pixel(9,7,color)
    display.pixel(10,8,color)
    display.pixel(10,7,color)
    display.pixel(10,6,color)
    display.pixel(11,8,color)
    display.pixel(11,7,color)
    display.pixel(11,6,color)
    display.pixel(11,5,color)
    display.pixel(12,8,color)
    display.pixel(12,7,color)
    display.pixel(12,6,color)
    display.pixel(12,5,color)
    display.pixel(12,4,color)

# calculate the altitude in ft based on the pressure (in units of hPa)
def hPa2feet (hPa):
    # First detemine which row of the look up table to use .
    # Row [0] is 50 hPa. Each successive row is 50 hPa more.
    hPa_row0_index = int((hPa - 50.0) * 0.02) # Note: 1/50 = 0.02
    hPa_row1_index = hPa_row0_index + 1
    # Get the pressure in the two rows that bracet our pressure measurement
    hPa0 = altitude_table[hPa_row0_index][HPA_INDEX]
    hPa1 = altitude_table[hPa_row1_index][HPA_INDEX]
    # Get the two altitudes that bracket out pressure measurement.
    feet0 = altitude_table[hPa_row0_index][ALTITUDE_INDEX]
    feet1 = altitude_table[hPa_row1_index][ALTITUDE_INDEX]

    # Now linter interpolate to get the actual altitude
    altitude_feet = ((feet1 - feet0)*(hPa - hPa0)/(hPa1 - hPa0))+feet0
    return altitude_feet


# Show the ARROWS so we know they are working
def start_screen():
    sleep_time_between_changes = 0.3 # seconds

    # Up and down arrows at the same time
    UP1(COLOR_UP)
    DOWN1(COLOR_DOWN)
    display.show()
    time.sleep(sleep_time_between_changes)

    # Add in the 2nd up and down arrows
    UP1(COLOR_BLACK)
    DOWN1(COLOR_BLACK)
    UP2(COLOR_UP)
    DOWN2(COLOR_DOWN)
    display.show()
    time.sleep(sleep_time_between_changes)

    # Add in the 3rd up and down arrows.
    UP2(COLOR_BLACK)
    DOWN2(COLOR_BLACK)
    UP3(COLOR_UP)
    DOWN3(COLOR_DOWN)
    display.show()
    time.sleep(sleep_time_between_changes)

    # Make the screen blank
    UP3(COLOR_BLACK)
    DOWN3(COLOR_BLACK)
    display.show()
    time.sleep(sleep_time_between_changes)

# =========================================
# The Main loop

assert IIR_COEFF <= 1.0, "The IIR_COEFF can not be > 1.0"
assert IIR_COEFF > 0.0, "The IIR_COEFF can not be <= 0.0"

# Make sure that some constants make sense
assert RATE_1 < RATE_2, "RATE_1 must be less than RATE_2"
assert RATE_2 < RATE_3, "RATE_2 must be less than RATE_3"

# We used the number of measurements and the display period to determine
# how long each measurement should take. After all the measurements have
# been taken it is then time to update the display.
measurement_period = DISPLAY_PERIOD / MEASUREMENTS_IN_DISPLAY_PERIOD
assert measurement_period > 0.016, "pressure measurement period must be > 0.016ms"

# It is faster to multipley than to divide so do the division here
# and then multply later to get the average.
measurement_averaging_factor = 1.0 / MEASUREMENTS_IN_DISPLAY_PERIOD

# We need a conversion factor to convert the difference from one altitude
# to the next (occurs over the time DISPLAY_PERIOD) into a ft/minute value.
displayTime2ftPerMinute = 60.0 / DISPLAY_PERIOD

last_state = STATE_BLANK
curr_state = STATE_BLANK

init_devices()
start_screen()

last_pressure = (round(dps310.pressure, 2))
last_altitude = hPa2feet(round(dps310.pressure, 2))




while True:

    # Average a bunch of pressure measurements between display updates.
    meas_id = 0
    pressure = 0.0
    while meas_id < MEASUREMENTS_IN_DISPLAY_PERIOD:
        pressure += (round(dps310.pressure, 2))
        meas_id += 1
        time.sleep(measurement_period)
    pressure *= measurement_averaging_factor

    print ("Altitude ft (before filter)%f" %(hPa2feet(pressure)))

    # Now run the pressure data through an IIR 1st order filter.
    pressure = pressure * IIR_COEFF + last_pressure * (1.0 - IIR_COEFF)

    # Convert the pressure measurements to altitude in ft.
    altitude_ft = hPa2feet(pressure)

    print("altitude ft (after filter)=%f" %(altitude_ft))

    # Now we need to determine our climb/sink rate in ft/minute.
    rate = (altitude_ft - last_altitude) * displayTime2ftPerMinute
    print("climb/sink (ft/min)=%f" %(rate))


    # What arrows state should we have based on the climb/sink rate

    if rate > RATE_1 and rate <= RATE_2:
        curr_state = STATE_UP_1_ARROW
    elif rate > RATE_2 and rate <= RATE_3:
        curr_state = STATE_UP_2_ARROWS
    elif rate > RATE_3:
        curr_state = STATE_UP_3_ARROWS
    elif rate < -RATE_1 and rate >= -RATE_2:
        curr_state = STATE_DWN_1_ARROW
    elif rate < -RATE_2 and rate >= -RATE_3:
        curr_state = STATE_DWN_2_ARROWS
    elif rate < -RATE_3:
        curr_state = STATE_DWN_3_ARROWS
    else:
        curr_state = STATE_BLANK
        
    print("curr_state = %d" %(curr_state))

    #
    # We don't need to turn anything off if the current state is the same as the last state
    #
    if curr_state != last_state:
        if curr_state == STATE_BLANK:
            # get rid of any arrows that are currently being shown.
            if last_state == STATE_UP_1_ARROW:
                UP1(COLOR_BLACK)
            elif last_state == STATE_UP_2_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
            elif last_state == STATE_UP_3_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
                UP3(COLOR_BLACK)
            elif last_state == STATE_DWN_1_ARROW:
                DOWN1(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_UP_1_ARROW:
            if last_state == STATE_BLANK:
                pass # nothing to do.
            elif last_state == STATE_UP_2_ARROWS:
                UP2(COLOR_BLACK) # Don't need the 2nd arrow
            elif last_state == STATE_UP_3_ARROWS:
                UP2(COLOR_BLACK) # Don't need the 2nd
                UP3(COLOR_BLACK) # or 3rd arrow.
            elif last_state == STATE_DWN_1_ARROW:
                DOWN1(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

            # Add needed Arrows
            if last_state == STATE_BLANK or last_state == STATE_DWN_1_ARROW or last_state == STATE_DWN_2_ARROWS or last_state == STATE_DWN_3_ARROWS:
                UP1(COLOR_UP)
            elif last_state == STATE_UP_2_ARROWS or last_state == STATE_UP_3_ARROWS:
                pass # Nothing to do. The 1st arrow is already being shown.
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_UP_2_ARROWS:
            # Get rid of unneeded old arrows.
            if last_state == STATE_UP_3_ARROWS:
                UP3(COLOR_BLACK)
            elif last_state == STATE_DWN_1_ARROW:
                DOWN1(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            elif last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW:
                pass # Do Nothing
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

            # Light up the needed arrows
            if last_state == STATE_BLANK or last_state == STATE_DWN_1_ARROW or last_state == STATE_DWN_2_ARROWS or last_state == STATE_DWN_3_ARROWS:
                UP1(COLOR_UP)
                UP2(COLOR_UP)
            elif last_state == STATE_UP_1_ARROW:
                UP2(COLOR_UP)
            elif last_state == STATE_UP_3_ARROWS:
                pass # Do nothing, already have the 2 arrows showing
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_UP_3_ARROWS:
            # get rid of unwanted arrows for the 3 arrows up case
            if last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW or last_state == STATE_UP_2_ARROWS:
                pass # Do nothing, there are now arrows to erase.
            elif last_state == STATE_DWN_1_ARROW:
                DOWN1(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN1(COLOR_BLACK)
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

            # Light up the needed arrows.
            if last_state == STATE_BLANK or last_state == STATE_DWN_1_ARROW or last_state == STATE_DWN_2_ARROWS or last_state == STATE_DWN_3_ARROWS:
                UP1(COLOR_UP)
                UP2(COLOR_UP)
                UP3(COLOR_UP)
            elif last_state == STATE_UP_1_ARROW:
                UP2(COLOR_UP)
                UP3(COLOR_UP)
            elif last_state == STATE_UP_2_ARROWS:
                UP3(COLOR_UP)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_DWN_1_ARROW:
            # Get rid of the unwanted arrows for the 1 arrow down case
            if last_state == STATE_BLANK:
                pass # Do nothing
            elif last_state == STATE_UP_1_ARROW:
                UP1(COLOR_BLACK)
            elif last_state == STATE_UP_2_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
            elif last_state == STATE_UP_3_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
                UP3(COLOR_BLACK)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN2(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN2(COLOR_BLACK)
                DOWN3(COLOR_BLACK)
            else:
                 raise Exception("Unexpected state=%d in match statement." %(last_state))

            # now light up the needed arrow
            if last_state == STATE_DWN_2_ARROWS or last_state == STATE_DWN_3_ARROWS:
                 pass # Do nothing
            elif last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW or last_state == STATE_UP_2_ARROWS or last_state == STATE_UP_3_ARROWS:
                DOWN1(COLOR_DOWN)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_DWN_2_ARROWS:
            # get rid of old unneeded arrows
            if last_state == STATE_BLANK or last_state == STATE_DWN_1_ARROW:
                pass # Do nothing
            elif last_state == STATE_UP_1_ARROW:
                UP1(COLOR_BLACK)
            elif last_state == STATE_UP_2_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
            elif last_state == STATE_UP_3_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
                UP3(COLOR_BLACK)
            elif last_state == STATE_DWN_3_ARROWS:
                DOWN3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

            # now light up the needed arrows for 2 arrows down
            if last_state == STATE_DWN_3_ARROWS:
                pass # Do Nothing
            elif last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW or last_state == STATE_UP_2_ARROWS or last_state == STATE_UP_3_ARROWS:
                DOWN1(COLOR_DOWN)
                DOWN2(COLOR_DOWN)
            elif last_state == STATE_DWN_1_ARROW:
                DOWN2(COLOR_DOWN)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

        elif curr_state == STATE_DWN_3_ARROWS:
            # get rid of old unneeded arrows
            if last_state == STATE_BLANK  or last_state == STATE_DWN_1_ARROW  or last_state == STATE_DWN_2_ARROWS:
                pass # Do nothing
            elif last_state == STATE_UP_1_ARROW:
                UP1(COLOR_BLACK)
            elif last_state ==  STATE_UP_2_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
            elif last_state == STATE_UP_3_ARROWS:
                UP1(COLOR_BLACK)
                UP2(COLOR_BLACK)
                UP3(COLOR_BLACK)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))

                # now light up the needed arrows for 3 arrows down
            if last_state == STATE_BLANK or last_state == STATE_UP_1_ARROW or last_state == STATE_UP_2_ARROWS or last_state == STATE_UP_3_ARROWS:
                DOWN1(COLOR_DOWN)
                DOWN2(COLOR_DOWN)
                DOWN3(COLOR_DOWN)
            elif last_state == STATE_DWN_1_ARROW:
                DOWN2(COLOR_DOWN)
                DOWN3(COLOR_DOWN)
            elif last_state == STATE_DWN_2_ARROWS:
                DOWN3(COLOR_DOWN)
            else:
                raise Exception("Unexpected state=%d in match statement." %(last_state))
        else:
            raise Exception("Unexpected state=%d in match statement." %(last_state))

        # The I2C buffer for the display may not be have all been sent so send it.
        display.show()

    #remember the current state and the current pressure
    last_state = curr_state
    last_pressure = pressure
    last_altitude = altitude_ft

Locked
Please be positive and constructive with your questions and comments.

Return to “General Project help”