buzzing mindfulness bracelet code plus some new functions

CircuitPython on hardware including Adafruit's boards, and CircuitPython libraries using Blinka on host computers.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
bozzaglia
 
Posts: 131
Joined: Mon Aug 01, 2022 6:14 am

Re: buzzing mindfulness bracelet code plus some new functions

Post by bozzaglia »

dastels wrote: Fri Sep 02, 2022 5:33 pm

Code: Select all

while True:  # loop
    switch.update()  # all'inizio di ogni loop controlla il pulsante
    timer = time.monotonic() - start_time                              // LINE 1
    
    time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + interval)  
    # NUOVO
    alarm.light_sleep_until_alarms(time_alarm)  # NUOVO                // LINE 2
    
    # definisce timer come il tempo trascorso in ogni loop
    if timer >= interval and timer <= (interval + buzz):               // LINE 3
  
When the loop starts (after updating the switch) you compute the value for timer based on the current elapsed time (LINE 1). Then you sleep for interval seconds (LINE 2). After returning from the sleep (interval seconds later) you use the value of timer that was computed interval seconds in the past.

Looking at it more, you are unconditionally sleeping for interval seconds each time through the loop. That's probably not what you want. You probably want that only when timer < interval.

Dave
Dave, going back at your last suggestion regarding the code, I changed it as recommended (sleep only when timer < interval), and I think that fixed the first sleep. But maybe I still have problems with the second sleep, the one after the buzzes and the button, until the end of the 30 minutes slice.
I post the current code.
What I am currently getting is only the first set of buzzes (it does only 3 buzzes instead of 4), it records regularly my button input, but then it doesn't seem to do anything else.
I tried to solve this by myself for several days, I broke down and played each step of the loop, but could not find the bug...

Code: Select all

import time
import board
import random
import alarm  # NUOVO
from digitalio import DigitalInOut, Direction, Pull
from adafruit_debouncer import Button

pulsante = DigitalInOut(board.A0)
pulsante.direction = Direction.INPUT
pulsante.pull = Pull.UP
vibrating_disc = DigitalInOut(board.A2)
vibrating_disc.direction = Direction.OUTPUT
switch = Button(pulsante)

buzz = 0.3  # buzz time
pause = 1.7  # pausa tra i buzz
interval = random.randint(1, 1732)  # 8" buzz, 60" attesa pulsante e complemento a 1800
contatore = 1  # serve per contare i buzz nel file
print_contatore = repr(contatore)  # converte variabile in stringa stampabile
delta = 1800 - (interval + 4 * buzz + 3 * pause + 60)  # NUOVO

start_time = time.monotonic()  # definisce start_time come il tempo attuale
while True:  # loop
    switch.update()  # all'inizio di ogni loop controlla il pulsante
    timer = time.monotonic() - start_time

    if timer <= interval:
        time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + interval)
        alarm.light_sleep_until_alarms(time_alarm)

    elif timer > interval and timer <= (interval + buzz):
        vibrating_disc.value = True  # buzz on

    elif timer >= (interval + buzz) and timer <= (interval + buzz + pause):
        vibrating_disc.value = False  # buzz off

    elif timer >= (interval + buzz + pause) and \
            timer <= (interval + buzz + pause + buzz):
        vibrating_disc.value = True

    elif timer >= (interval + buzz + pause + buzz) and \
            timer <= (interval + buzz + pause + buzz + pause):
        vibrating_disc.value = False

    elif timer >= (interval + buzz + pause + buzz + pause) and \
            timer <= (interval + buzz + pause + buzz + pause + buzz):
        vibrating_disc.value = True

    elif timer >= (interval + buzz + pause + buzz + pause + buzz) and \
            timer <= (interval + buzz + pause + buzz + pause + buzz + pause):
        vibrating_disc.value = False

    elif timer >= (interval + buzz + pause + buzz + pause + buzz + pause) and \
            timer <= (interval + buzz + pause + buzz + pause + buzz + pause + buzz):
        vibrating_disc.value = True

    elif timer >= (interval + buzz + pause + buzz + pause + buzz + pause + buzz) and \
            timer < (interval + buzz + pause + buzz + pause + buzz + pause + buzz + 60):
        vibrating_disc.value = False
        if switch.short_count == 1:
            file1 = open("mindfulness_log.txt", "a")
            file1.write(print_contatore + "ok ")
            file1.close()
        elif switch.short_count == 2:
            file1 = open("mindfulness_log.txt", "a")
            file1.write(print_contatore + "no ")
            file1.close()

    elif timer >= (interval + buzz + pause + buzz + pause + buzz + pause + buzz + 60) \
            and timer < 1800:
        time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + delta)
        alarm.light_sleep_until_alarms(time_alarm)  # NUOVO

    elif timer >= 1800:  # aggiornamento contatori per prossimo loop
        start_time = time.monotonic()
        interval = random.randint(1, 1732)
        contatore = (contatore + 1)
        print_contatore = repr(contatore)  # converte variabile in stringa stampabile
        delta = 1800 - (interval + 4 * buzz + 3 * pause + 60)  # NUOVO

User avatar
dastels
 
Posts: 15608
Joined: Tue Oct 20, 2015 3:22 pm

Re: buzzing mindfulness bracelet code plus some new functions

Post by dastels »

Nothing jumps out at me. But the code is so obtuse that it's hard to see much. I suggest you clean things up somewhat. That huge if tree can be simplified in various ways, but my first step would be to get rid of the math in the conditions, doing it in the two places start_time is assigned. Have variables such as start_buzz_1, end_buzz_1, start_buzz_2, etc. Then use them in the conditions. That would make it simpler and clearly communicate the intent. As it is now, it's a forest of buzzes and pauses.

Dave

User avatar
bozzaglia
 
Posts: 131
Joined: Mon Aug 01, 2022 6:14 am

Re: buzzing mindfulness bracelet code plus some new functions

Post by bozzaglia »

Yes, I know it didn’t look good at all, however I was really afraid to change the parts that I knew were working, even if being very ugly :-)

Now I have made the changes you recommended, however I wasn’t able to test it because the board started again having problems with the USB connection to my PC, and this time I am sure there was no accidental shorting because I have isolated the whole circuit with kapton tape.

Basically after a couple of normal plug/unplug cycles, I plug it again or I hit reset and the CIRCUITPY drive does not appear on reboot. The only way to make it appear again is to put the board in safe mode, but if I go back to normal mode by hitting reset, the drive disappears again.
If, however, while in safe mode I remove the boot.py file, or erase all files and copy new versions from the bundle, then CIRCUITPY reappears upon reset. Same happens if I wipe the USB devices from the pc with the cleaner software.
However after a couple of plug/unplug cycles I am back at square one with CIRCUITPY gone :-(

User avatar
dastels
 
Posts: 15608
Joined: Tue Oct 20, 2015 3:22 pm

Re: buzzing mindfulness bracelet code plus some new functions

Post by dastels »

Have you tried reinstalling CircuitPython (recopy the UF2)?

Dave

User avatar
bozzaglia
 
Posts: 131
Joined: Mon Aug 01, 2022 6:14 am

Re: buzzing mindfulness bracelet code plus some new functions

Post by bozzaglia »

if you mean dragging the UF2 file into the RPI-RP2 drive I've done like ten times... It worked the first couple of times (CIRCUITPY appeared) and then stopped working and nothing happened.

User avatar
dastels
 
Posts: 15608
Joined: Tue Oct 20, 2015 3:22 pm

Re: buzzing mindfulness bracelet code plus some new functions

Post by dastels »

Yeah, that's what I meant.

Try reinstalling the bootloader. Something low level might have gotten corrupted.

Dave

User avatar
bozzaglia
 
Posts: 131
Joined: Mon Aug 01, 2022 6:14 am

Re: buzzing mindfulness bracelet code plus some new functions

Post by bozzaglia »

Is this file the bootloader? adafruit-circuitpython-adafruit_qtpy_rp2040-it_IT-7.3.3.uf2

Is "reinstalling" different from dragging this file into the RPI-RP2 drive?

User avatar
dastels
 
Posts: 15608
Joined: Tue Oct 20, 2015 3:22 pm

Re: buzzing mindfulness bracelet code plus some new functions

Post by dastels »

No, that's CircuitPython.

Did you try the "Flash Resetting UF2"? https://learn.adafruit.com/adafruit-qt- ... f2-3091244

Reinstalling is usually a matter of copying the appropriate UF2.
Dave

User avatar
bozzaglia
 
Posts: 131
Joined: Mon Aug 01, 2022 6:14 am

Re: buzzing mindfulness bracelet code plus some new functions

Post by bozzaglia »

Ok, I think the nuke worked. At least so far :-)
As for the code, this is the version with the math cleaned up, but it's not buzzing at all...

Code: Select all

import time
import board
import random
import alarm  # NUOVO
from digitalio import DigitalInOut, Direction, Pull
from adafruit_debouncer import Button

pulsante = DigitalInOut(board.A0)
pulsante.direction = Direction.INPUT
pulsante.pull = Pull.UP
vibrating_disc = DigitalInOut(board.A2)
vibrating_disc.direction = Direction.OUTPUT
switch = Button(pulsante)

go_buzz_1 = random.randint(1, 1731)  # 6.3" buzz, 60" attesa pulsante e compl. a 1800
end_buzz_1 = go_buzz_1 + 0.3
go_buzz_2 = go_buzz_1 + 2
end_buzz_2 = go_buzz_1 + 2.3
go_buzz_3 = go_buzz_1 + 4
end_buzz_3 = go_buzz_1 + 4.3
go_buzz_4 = go_buzz_1 + 6
end_buzz_4 = go_buzz_1 + 6.3
contatore = 1  # serve per contare i buzz nel file
print_contatore = repr(contatore)  # converte variabile in stringa stampabile
delta = 1800 - (end_buzz_4 + 60)  # per sleep dopo buzz

start_time = time.monotonic()  # definisce start_time come il tempo attuale

while True:  # loop
    switch.update()  # all'inizio di ogni loop controlla il pulsante
    timer = time.monotonic() - start_time

    if timer <= go_buzz_1:
        time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + go_buzz_1)
        alarm.light_sleep_until_alarms(time_alarm)

    elif timer > go_buzz_1 and timer <= end_buzz_1:
        vibrating_disc.value = True

    elif timer >= end_buzz_1 and timer <= go_buzz_2:
        vibrating_disc.value = False

    elif timer >= go_buzz_2 and timer <= end_buzz_2:
        vibrating_disc.value = True

    elif timer >= end_buzz_2 and timer <= go_buzz_3:
        vibrating_disc.value = False

    elif timer >= go_buzz_3 and timer <= end_buzz_3:
        vibrating_disc.value = True

    elif timer >= end_buzz_3 and timer <= go_buzz_4:
        vibrating_disc.value = False

    elif timer >= go_buzz_4 and timer <= end_buzz_4:
        vibrating_disc.value = True

    elif timer >= end_buzz_4 and timer < (end_buzz_4 + 60):
        vibrating_disc.value = False
        if switch.short_count == 1:
            file1 = open("mindfulness_log.txt", "a")
            file1.write(print_contatore + "ok ")
            file1.close()
        elif switch.short_count == 2:
            file1 = open("mindfulness_log.txt", "a")
            file1.write(print_contatore + "no ")
            file1.close()

    elif timer >= (end_buzz_4 + 60) and timer < 1800:
        time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + delta)
        alarm.light_sleep_until_alarms(time_alarm)

    elif timer >= 1800:  # aggiornamento contatori per prossimo loop
        start_time = time.monotonic()
        go_buzz_1 = random.randint(1, 1731)  # 1731 come sopra
        end_buzz_1 = go_buzz_1 + 0.3
        go_buzz_2 = go_buzz_1 + 2
        end_buzz_2 = go_buzz_1 + 2.3
        go_buzz_3 = go_buzz_1 + 4
        end_buzz_3 = go_buzz_1 + 4.3
        go_buzz_4 = go_buzz_1 + 6
        end_buzz_4 = go_buzz_1 + 6.3
        contatore = (contatore + 1)
        print_contatore = repr(contatore)  # converte variabile in stringa stampabile
        delta = 1800 - (end_buzz_4 + 60)

User avatar
dastels
 
Posts: 15608
Joined: Tue Oct 20, 2015 3:22 pm

Re: buzzing mindfulness bracelet code plus some new functions

Post by dastels »

One possible problem (or at least minor incorrectness) is that you have the if conditions overlapping.

Code: Select all

elif timer > go_buzz_1 and timer <= end_buzz_1:
    vibrating_disc.value = True

elif timer >= end_buzz_1 and timer <= go_buzz_2:
    vibrating_disc.value = False
See how the first one is <= end_buzz_1 and the second is >= end_buzz_1. It's at the very least a matter of good form to have them completely disjoint with no overlap.

I would put a print call in each if branch, printing the value of timer and an indication of the branch (e.g. buzz 1 on). That will let you trace the logic itself.

Dave

User avatar
bozzaglia
 
Posts: 131
Joined: Mon Aug 01, 2022 6:14 am

Re: buzzing mindfulness bracelet code plus some new functions

Post by bozzaglia »

So I opened a rabbit hole!!
I had the program print time.monotonic and timer at each step (code below) and also on a simpler code (screnshot attached) and after several tests I found out (if I got it right...) that - probably because of the structure of the sleep / alarm sequence, where first you set the alarm time and on the next line you go to sleep - some time is lost in the processing and so the sleep is always slightly LESS than what you write in the monotonic_time element (in my case go_buzz_1 seconds). Because of this at the end of the sleep in the first IF, timer is still slightly less (the amount seems to vary and that I believe is a problem) than go_buzz_1 and therefore instead of jumping to the first ELIF and start the buzzing, the code goes back into sleep so it skips all the timer window of the buzzes...
I am trying to fix this by setting the alarm for a slightly larger time (using a go_buzz_0 as randint and a go_buzz_1 0.1 to 0.5 seconds greater), however I believe the delay varies and sometimes the code still skips the first ELIF (and first buzz) and only does the remaining three.
Also I had a feeling that the print calls take up some time from the code and slow it down additonally...

What do you think? Did I get it right? Is this a good approach or should I do it differently?

Code: Select all

import time
import board
import random
import alarm  # NUOVO
from digitalio import DigitalInOut, Direction, Pull
from adafruit_debouncer import Button

pulsante = DigitalInOut(board.A0)
pulsante.direction = Direction.INPUT
pulsante.pull = Pull.UP
vibrating_disc = DigitalInOut(board.A2)
vibrating_disc.direction = Direction.OUTPUT
switch = Button(pulsante)

go_buzz_0 = random.randint(1, 1731)  # 6.3" buzz, 60" attesa pulsante e compl. a 1800
go_buzz_1 = go_buzz_0 + 0.1
end_buzz_1 = go_buzz_1 + 0.3
go_buzz_2 = go_buzz_1 + 2
end_buzz_2 = go_buzz_1 + 2.3
go_buzz_3 = go_buzz_1 + 4
go_buzz_3 = go_buzz_1 + 4
go_buzz_3 = go_buzz_1 + 4
go_buzz_3 = go_buzz_1 + 4
end_buzz_3 = go_buzz_1 + 4.3
go_buzz_4 = go_buzz_1 + 6
end_buzz_4 = go_buzz_1 + 6.3
contatore = 1  # serve per contare i buzz nel file
print_contatore = repr(contatore)  # converte variabile in stringa stampabile
delta = 1800 - (end_buzz_4 + 60)  # per sleep dopo buzz

start_time = time.monotonic()  # definisce start_time come il tempo attuale
print('0', time.monotonic(), go_buzz_0)

while True:  # loop
    switch.update()  # all'inizio di ogni loop controlla il pulsante
    timer = time.monotonic() - start_time

    if timer < go_buzz_0:
        time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + go_buzz_1)
        print('1', time.monotonic(), timer)
        alarm.light_sleep_until_alarms(time_alarm)
        print('1bis', time.monotonic(), timer, 'go_buzz_0', go_buzz_0)

    # elif timer >= go_buzz_0 and timer < go_buzz_1
    
    elif timer >= go_buzz_1 and timer < end_buzz_1:
        vibrating_disc.value = True
        print('2', time.monotonic(), timer, 'go_buzz_1bis', go_buzz_1)

    elif timer >= end_buzz_1 and timer < go_buzz_2:
        vibrating_disc.value = False
        print('3', time.monotonic(), timer, 'end_buzz_1', end_buzz_1)

    elif timer >= go_buzz_2 and timer < end_buzz_2:
        vibrating_disc.value = True
        print('4', timer, 'go_buzz_2', go_buzz_2)

    elif timer >= end_buzz_2 and timer < go_buzz_3:
        vibrating_disc.value = False
        print('5', timer, 'end_buzz_2', end_buzz_2)

    elif timer >= go_buzz_3 and timer < end_buzz_3:
        vibrating_disc.value = True
        print('6', timer, 'go_buzz_3', go_buzz_3)

    elif timer >= end_buzz_3 and timer < go_buzz_4:
        vibrating_disc.value = False
        print('7', timer, 'end_buzz_3', end_buzz_3)

    elif timer >= go_buzz_4 and timer < end_buzz_4:
        vibrating_disc.value = True
        print('8', timer, 'go_buzz_4', go_buzz_4)

    elif timer >= end_buzz_4 and timer < (end_buzz_4 + 60):
        vibrating_disc.value = False
        if switch.short_count == 1:
            file1 = open("mindfulness_log.txt", "a")
            file1.write(print_contatore + "ok ")
            file1.close()
        elif switch.short_count == 2:
            file1 = open("mindfulness_log.txt", "a")
            file1.write(print_contatore + "no ")
            file1.close()
        print('9', timer, 'end_buzz_4', end_buzz_4)

    elif timer >= (end_buzz_4 + 60) and timer < 1800:
        time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + delta)
        alarm.light_sleep_until_alarms(time_alarm)
        print('10', timer, 'end_buzz_4 + 60', (end_buzz_4 + 60))

    elif timer >= 1800:  # aggiornamento contatori per prossimo loop
        start_time = time.monotonic()
        go_buzz_1 = random.randint(1, 1731)  # 1731 come sopra
        end_buzz_1 = go_buzz_1 + 0.3
        go_buzz_2 = go_buzz_1 + 2
        end_buzz_2 = go_buzz_1 + 2.3
        go_buzz_3 = go_buzz_1 + 4
        end_buzz_3 = go_buzz_1 + 4.3
        go_buzz_4 = go_buzz_1 + 6
        end_buzz_4 = go_buzz_1 + 6.3
        contatore = (contatore + 1)
        print_contatore = repr(contatore)  # converte variabile in stringa stampabile
        delta = 1800 - (end_buzz_4 + 60)
        print(timer, 'end loop')
Attachments
screenshot sleep alarm.png
screenshot sleep alarm.png (198.99 KiB) Viewed 94 times

User avatar
dastels
 
Posts: 15608
Joined: Tue Oct 20, 2015 3:22 pm

Re: buzzing mindfulness bracelet code plus some new functions

Post by dastels »

Interesting. You could try setting a flag (a True/False variable) to True after the sleep, and only have it do the sleep if the flag is False. Set it to False before the loop. You could call it something like already_slept (or well_rested if you want to be a bit funny). That way it will only sleep once per cycle. Of course, you'll have to set it to False again at the end of the cycle when you reassign all the timing variables.

Dave

User avatar
bozzaglia
 
Posts: 131
Joined: Mon Aug 01, 2022 6:14 am

Re: buzzing mindfulness bracelet code plus some new functions

Post by bozzaglia »

That’s a great tip!
I’ll try that tomorrow and let you know. Thanks!

User avatar
bozzaglia
 
Posts: 131
Joined: Mon Aug 01, 2022 6:14 am

Re: buzzing mindfulness bracelet code plus some new functions

Post by bozzaglia »

Today I added the flag to the code and it looks like it’s working perfectly now!
However I’m afraid I ran into another issue: I tested the battery duration and it looks like there wasn’t any improvement compared to the code without sleep. I am always getting about 5 to 6 hours on a 100 mAh battery, which I would really prefer not to change.
So first of all I am wondering if this is possible, or there is some problem causing an abnormal power consumption.
Secondly I am starting to think about implementing deep sleep: In that case my understanding is that I should get rid of the while loop and the IF/ELIF construct and build the whole sequence starting with a deep sleep for a random number of seconds, followed by a sequence of buzzes and time.sleeps, a window to input my feedback through the button and another deep sleep until 30 minutes are passed.
However I understand that with deep sleep the code is basically restarting every time, and in order to make it “remember” variables I have to use the sleep memory, which requires a specific format which is new for me...
And what about remembering the sequence of actions to be performed, i.e. first determine the length of the sleeps, then do the first sleep, wake up and start buzzing, then do the second sleep, and so on...
Any thoughts/suggestions?
Thanks always Dave :-)

User avatar
dastels
 
Posts: 15608
Joined: Tue Oct 20, 2015 3:22 pm

Re: buzzing mindfulness bracelet code plus some new functions

Post by dastels »

Using deep sleep will require a complete redesign/rewrite since the code starts fresh when it comes back from sleep (which is a lot like turning off the power). There's a way to persist variable across the sleeps, though.

You might want to measure current usage to get a clearer picture of what's happening. It's hard/guesswork to try to optimize something you aren't measuring.

Dave

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

Return to “Adafruit CircuitPython”