From df05420afc1182a528471434d5c71d29d4b16f66 Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Mon, 24 Jan 2022 18:58:53 +0100 Subject: [PATCH 01/19] Update README.md --- README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 696fa83..dd67bd7 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@

- - + +

@@ -37,10 +37,10 @@ This is the official repository for the **Hackability@Sherlock** project. The goal is to develop a **3D printed design object** which easily lets **visually impaired people** (but also normally sighted people) get a quick and informative **audio description of a small indoor space** - such as an hotel room, to get an understanding of where and which objects are present in the room. Sherlock will be composed of the following components: -* an audio speaker. -* an electronic circuit to "read" the user's input (through the pressing of buttons). -* a Raspberry Pi to control everything. -* a 3D printed casing, with buttons and Braille text. +* an **audio speaker**. +* an **electronic circuit** to "read" the user's input (through the pressing of **buttons**). +* a **Raspberry Pi** to control everything. +* a **3D printed casing**, with buttons and Braille text. We will try to make Sherlock as simple and yet configurable as possible, where users can just drag-and-drop their audio tracks to be reproduced and Sherlock will be able to reproduce them. @@ -48,22 +48,22 @@ Our vision is to create an object which integrates well into any environment and ## Installation -Make sure your electronic circuit and PCB is built following the schema in `SherlockSketch.fzz`. +0. Make sure your electronic circuit and PCB is built following the schema in `SherlockSketch.fzz`. -Open a terminal window in your RaspberryPi (you can either connect through `SSH` or directly to the device). +1. Open a terminal window in your RaspberryPi (you can either connect through `SSH` or directly to the device). -Clone the repository into your preferred location: +2. Clone the repository into your preferred location: ``` cd /path/to/your/folder git clone https://github.com/Quellichenonsannofareuncazzo/Sherlock cd Sherlock ``` -**[Optional]** Create a virtual environment for the project: +3. **[Optional]** Create a virtual environment for the project: ``` python3 -m venv source /bin/activate ``` -Install project dependencies: +4. Install project dependencies: ``` pip install -r requirements.txt ``` @@ -72,7 +72,7 @@ pip install -r requirements.txt From the command line, run: ``` -python3 main.py +python3 src/main.py ``` and enjoy the experience! @@ -89,7 +89,7 @@ Below, a non-comprehensive list of stuff we should do in the future: Use GH Issues to open MRs/PRs for new improvements and adding functionalities. -## Acknowledgements & Contacts +## Acknowledgements The Sherlock project was realized by [Hackability@Milano](http://www.hackability.it/hackabilitymilano/), in partnership with [Fondazione G. Brodolini](https://www.fondazionebrodolini.it/) and [Associazione Nazionale Subvedenti](https://www.subvedenti.it/), whose contributions were essential for the brainstorming and development of Sherlock. @@ -100,6 +100,7 @@ The project was initially ideated in the context of the [EU's ECOS4IN project](h Sherlock is a byproduct of the **ECOS4IN Workshop** organized by Fondazione G. Brodolini with makers from Hackability@Milano, and inclusion stakeholders from Associazione Nazionale Subvedenti. +## Contacts If you have any questions, want to contribute, or want more information, feel free to reach out to us. * **Hackability@Milano**, [milano@hackability.it](mailto:milano@hackability.it) * Teo Bistoni, [@TeoBistoni](https://github.com/TeoBistoni) From 0269879a9f4e46db3ae6bc9fd9428911a361b960 Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Mon, 24 Jan 2022 21:27:23 +0100 Subject: [PATCH 02/19] Initial commit for dev branch --- main.py | 51 --------------------------------------------------- 1 file changed, 51 deletions(-) delete mode 100644 main.py diff --git a/main.py b/main.py deleted file mode 100644 index e664e06..0000000 --- a/main.py +++ /dev/null @@ -1,51 +0,0 @@ -import pygame -import json -import glob -from time import sleep -import os -import sys -import RPi.GPIO as GPIO - -def play_music(index): - music.stop() - music.load("sound/"+soundtracks[index]) - music.play() - while music.get_busy() == True: - continue - -print("Ciao") -GPIO.setmode(GPIO.BOARD) -GPIO.setup(3,GPIO.IN,pull_up_down=GPIO.PUD_UP) -GPIO.setup(5,GPIO.IN,pull_up_down=GPIO.PUD_UP) -GPIO.setup(11,GPIO.IN,pull_up_down=GPIO.PUD_UP) -mixer = pygame.mixer -mixer.init() -music = mixer.music - -index_audio = 0 -soundtracks = os.listdir("./sound") -print(soundtracks) -while True: - if(GPIO.input(3) == GPIO.LOW): - if(index_audio == len(soundtracks)-1): - index_audio = 0 - else: - index_audio += 1 - print("avanti: " , index_audio) - play_music(index_audio) - - if(GPIO.input(5) == GPIO.LOW): - if(index_audio == 0): - index_audio = len(soundtracks)-1 - else: - index_audio -= 1 - print("indietro: " , index_audio) - play_music(index_audio) - - if(GPIO.input(11) == GPIO.LOW): - music.stop() - print("stop") - - - - From 7be20cc79e4fe0939a2005dee9f9aeef8f93d0c6 Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Mon, 24 Jan 2022 21:50:50 +0100 Subject: [PATCH 03/19] Define Sherlock class __init__ --- src/sherlock.py | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/sherlock.py diff --git a/src/sherlock.py b/src/sherlock.py new file mode 100644 index 0000000..a8fabdd --- /dev/null +++ b/src/sherlock.py @@ -0,0 +1,69 @@ +import glob +import json +import os +import sys +import time +from time import sleep + +import pygame +import RPi.GPIO as GPIO +from gpiozero import Button + +class Sherlock: + ''' + A Sherlock object contains all methods and attributes to setup and control + a Sherlock device. It builds upon the pygame.mixer object. + ''' + def __init__( + self, + TRACKS_DIR='./tracks', + FW_PIN=3, + BW_PIN=5, + PLAY_PIN=11, + OUT_PIN=13, + BOUNCE=200, # [milliseconds] + SKIP=10, # [seconds] + LONG_PRESS_TIME=2, # [seconds] + START_IDX=0, + PLAY_STATE=False + ): + ''' + Args: + FW_PIN (int) : RaspberryPi board pin for NEXT button + BW_PIN (int) : RaspberryPi board pin for BACK button + PLAY_PIN (int) : RaspberryPi board pin for PLAY/PAUSE button + OUT_PIN (int) : RaspberryPi board pin for OUTPUT + BOUNCE (int) : time delay (in [ms]) to compensate bounce effect + SKIP (int) : time (in [s]) to skip when long-pressing the NEXT button + LONG_PRESS_TIME (int): time (in [s]) to long-press the NEXT button before triggering the fast-forward + START_IDX (int) : index of track to start the playback (assuming tracks are ordered) + PLAY_STATE (bool) : flag for play/pause status + + ''' + # RaspberryPi board setup + self.fw_pin = FW_PIN # NEXT + self.bw_pin = BW_PIN # BACK + self.play_pin = PLAY_PIN # PLAY/PAUSE + self.out_pin = OUT_PIN # OUTPUT + + # Compensate bounce effect + self.bounce = BOUNCE + + # Initialize GPIO + self.init_board() + + # Store tracks + self.tracks = [os.path.join(TRACKS_DIR, track) for track in os.listdir(TRACKS_DIR)] + # How many seconds to skip forward when long-pressing NEXT button + self.fforward_skip = SKIP + self.long_press_time = LONG_PRESS_TIME + # From which track to start the playback (assuming the tracks in the folder are ordered) + self.start_idx = START_IDX + # Flag for play/pause status + self.is_playing = PLAY_STATE + + # Initialize pygame.mixer object + self.player = pygame.mixer.init().music + + + \ No newline at end of file From 09a7dbcea9f502536da37105d190bb80348c4c14 Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Mon, 24 Jan 2022 21:51:53 +0100 Subject: [PATCH 04/19] Implement Sherlock class circuit board init --- src/sherlock.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/sherlock.py b/src/sherlock.py index a8fabdd..b13fe1f 100644 --- a/src/sherlock.py +++ b/src/sherlock.py @@ -65,5 +65,28 @@ def __init__( # Initialize pygame.mixer object self.player = pygame.mixer.init().music + def init_board(self): + '''Initialize GPIO input/output pins and event detection.''' + ### GPIO SETUP ### + GPIO.setmode(GPIO.BOARD) + # Set pins modes + GPIO.setup(self.fw_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) + GPIO.setup(self.bw_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) + GPIO.setup(self.play_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) + GPIO.setup(self.out_pin, GPIO.OUT) + GPIO.output(self.out_pin, GPIO.HIGH) - \ No newline at end of file + # Detect button pressing events + GPIO.add_event_detect(self.fw_pin, GPIO.FALLING, callback = self._forward, bouncetime=self.bounce) + GPIO.add_event_detect(self.bw_pin, GPIO.FALLING, callback = self._backward, bouncetime=self.bounce) + GPIO.add_event_detect(self.play_pin, GPIO.FALLING, callback = self._play_pause, bouncetime=self.bounce) + + def init_player(self): + '''Initialize pygame.mixer object.''' + self.mixer = pygame.mixer + self.mixer.init() + + self.player = self.mixer.music + + + \ No newline at end of file From 50a2195ea66ba6bf6cb3aea2c125b9aeec3e5be3 Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Mon, 24 Jan 2022 22:57:43 +0100 Subject: [PATCH 05/19] Implement button events callbacks (forward, backward, pause) --- src/sherlock.py | 188 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 158 insertions(+), 30 deletions(-) diff --git a/src/sherlock.py b/src/sherlock.py index b13fe1f..d2dabd8 100644 --- a/src/sherlock.py +++ b/src/sherlock.py @@ -22,53 +22,59 @@ def __init__( PLAY_PIN=11, OUT_PIN=13, BOUNCE=200, # [milliseconds] - SKIP=10, # [seconds] + SKIP_TIME=10, # [seconds] LONG_PRESS_TIME=2, # [seconds] - START_IDX=0, - PLAY_STATE=False + CURRENT_IDX=0, + PLAY_STATE=False, + RESTART_TIME=2 # [seconds] ): ''' - Args: - FW_PIN (int) : RaspberryPi board pin for NEXT button - BW_PIN (int) : RaspberryPi board pin for BACK button - PLAY_PIN (int) : RaspberryPi board pin for PLAY/PAUSE button - OUT_PIN (int) : RaspberryPi board pin for OUTPUT - BOUNCE (int) : time delay (in [ms]) to compensate bounce effect - SKIP (int) : time (in [s]) to skip when long-pressing the NEXT button - LONG_PRESS_TIME (int): time (in [s]) to long-press the NEXT button before triggering the fast-forward - START_IDX (int) : index of track to start the playback (assuming tracks are ordered) - PLAY_STATE (bool) : flag for play/pause status + Store all parameters, then (1) initialize the board, (2) initialize + te pygame.mixer.music object. + Args: + TRACKS_DIR (str) : path to the folder where the tracks are stored + FW_PIN (int) : RaspberryPi board pin for NEXT button + BW_PIN (int) : RaspberryPi board pin for BACK button + PLAY_PIN (int) : RaspberryPi board pin for PLAY/PAUSE button + OUT_PIN (int) : RaspberryPi board pin for OUTPUT + BOUNCE (int) : time delay (in [ms]) to compensate bounce effect + SKIP_TIME (int) : time (in [s]) to skip when long-pressing the NEXT button + LONG_PRESS_TIME (int) : time (in [s]) to long-press the NEXT button before triggering the fast-forward + CURRENT_IDX (int) : index of track to start the playback (assuming tracks are ordered) + PLAY_STATE (bool) : flag for play/pause status + RESTART_TIME (int) : time (in [s]) AFTER which the BACK button restarts the current track instead of going back to the previous one ''' # RaspberryPi board setup self.fw_pin = FW_PIN # NEXT self.bw_pin = BW_PIN # BACK self.play_pin = PLAY_PIN # PLAY/PAUSE self.out_pin = OUT_PIN # OUTPUT + self.bounce = BOUNCE # Compensate bounce effect - # Compensate bounce effect - self.bounce = BOUNCE + # Other parameters + self.tracks = [os.path.join(TRACKS_DIR, track) for track in os.listdir(TRACKS_DIR)] # store tracks + self.skip_time = SKIP_TIME # How many seconds to skip forward when long-pressing NEXT button + self.long_press_time = LONG_PRESS_TIME # How long to keep pressing the NEXT button to trigger the fast-forward + self.current_idx = CURRENT_IDX # From which track to start the playback (assuming the tracks in the folder are ordered) + self.is_playing = PLAY_STATE # Flag for play/pause status + self.restart_track_time = RESTART_TIME # after how many seconds the BACK button pressing restarts the current track instead of going back to the previous track - # Initialize GPIO + ### INITIALIZATIONS ### + # 1. Initialize GPIO + print('Initializing board...') self.init_board() + # 2. Initialize audioplayer + print('Initializing audioplayer...') + self.init_player() - # Store tracks - self.tracks = [os.path.join(TRACKS_DIR, track) for track in os.listdir(TRACKS_DIR)] - # How many seconds to skip forward when long-pressing NEXT button - self.fforward_skip = SKIP - self.long_press_time = LONG_PRESS_TIME - # From which track to start the playback (assuming the tracks in the folder are ordered) - self.start_idx = START_IDX - # Flag for play/pause status - self.is_playing = PLAY_STATE - - # Initialize pygame.mixer object - self.player = pygame.mixer.init().music + print('Ready! Press the PLAY/PAUSE button to start!') def init_board(self): '''Initialize GPIO input/output pins and event detection.''' ### GPIO SETUP ### GPIO.setmode(GPIO.BOARD) + # Set pins modes GPIO.setup(self.fw_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(self.bw_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) @@ -83,10 +89,132 @@ def init_board(self): def init_player(self): '''Initialize pygame.mixer object.''' + ### PYGAME SETUP ### self.mixer = pygame.mixer self.mixer.init() - self.player = self.mixer.music + def _play(self): + '''Play the current track (self.current_idx).''' + # Stop the playback if it's playing + self.player.stop() + # Load the current track + self.player.load(self.tracks[self.current_idx]) + # Start playing + self.player.play() + + # Set is_playing flag + self.is_playing = True + + def _forward(self): + ''' + Pressing the NEXT button lets the user skip to the next track. + Long-pressing the NEXT button for `N` seconds lets the user fast-forward the track by `skip` seconds. + ''' + # Detect long-press + long_press_flag = self._long_press(self.fw_pin, fforward=True) + + # If single, short press, skip to next track + if (not long_press_flag): + if(self.current_idx == len(self.tracks)-1): + self.current_idx = 0 + else: + self.current_idx += 1 + # Play next track + self._play() + + print("Avanti: " , self.current_idx) + + def _fastforward(self): + ''' + Long-pressing the NEXT button for `N` seconds lets the user + fast-forward the current track by `self.skip_time` seconds. + + Note: depending on the audio format, pygame.mixer.music.set_pos + behaves differently. For .mp3 audio files, set_pos sets the new + position relatively to the current position - i.e., if you do + set_pos(5), it will skip to 5 seconds after the current position. + + More info on the official documentation: + https://www.pygame.org/docs/ref/music.html#pygame.mixer.music.set_pos + ''' + # Skip by 'fforward_skip' seconds + self.player.set_pos(self.skip_time) - \ No newline at end of file + def _backward(self): + ''' + Pressing the BACK button lets te user either restart the current track + or go back to the previous one if the time from the start of the current + track is less than a pre-defined time interval. + + Note: get_pos() returns time from start of playback in [milliseconds]. + ''' + # Detect long-press + long_press_flag = self._long_press(self.bw_pin, fforward=False) + + if (not long_press_flag): + # If self.restart_track_time has passed, then restart current track + if(self.player.get_pos()//1000 > self.restart_track_time): + self._play() + else: + # Go to previous track + if(self.current_idx == 0): + self.current_idx = len(self.tracks)-1 + else: + self.current_idx -= 1 + self._play() + print("Indietro: " , self.current_idx) + + def _fastbackward(self): + ''' + Long-pressing the BACK button for 'self.long_press_time' seconds + lets the user go back of the current track by 'self.skip_time' seconds. + + Note: see self._fastforward() note. + ''' + # Go back by 'self.skip_time' seconds + raise NotImplementedError + + def _play_pause(self): + ''' + Pressing the center PLAY/PAUSE button, plays or pauses the current track. + ''' + if(self.is_playing): + self.player.pause() + print("Pausa") + self.is_playing = False + else: + self.player.unpause() + print("Play") + self.is_playing = True + + def _long_press(self, pin, fforward): + ''' + Detect long-pressing of any button. + + Args: + pin (int) : pin to detect the long-pressing from + fforward (bool) : whether to fast-forward or fast-backward + + Returns: + long_press_flag (bool) : whether the long-press was detected or not + ''' + # Compute time from when button press is detected + start_press = time.time() + + # Detect if the NEXT button has been long-pressed + long_press_flag = False + + while GPIO.input(pin) == GPIO.LOW: + time.sleep(.5) + if(time.time()-start_press > self.long_press_time): + # Fast for-/back-ward the current track by N seconds + if fforward==True: + self._fastforward() + elif fforward==False: + self._fastbackward() + + # Do not go to the next track + long_press_flag = True + + return long_press_flag \ No newline at end of file From 681f26bd9e7015a44210b95174533e5c0856a28c Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Mon, 24 Jan 2022 23:04:11 +0100 Subject: [PATCH 06/19] Refactor main.py to use Sherlock class --- src/main.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/sherlock.py | 12 ++++++++---- 2 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 src/main.py diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..ffbc8af --- /dev/null +++ b/src/main.py @@ -0,0 +1,48 @@ +import glob +import json +import os +import sys +import time +from time import sleep + +import pygame +import RPi.GPIO as GPIO +from gpiozero import Button + +from sherlock import Sherlock + +if __name__=='__main__': + # Print instructions + print('#'*10) + print('WELCOME TO SHERLOCK') + print('#'*10) + print('\n') + print('#'*5) + print('INSTRUCTIONS') + print('#'*5) + print('1. Press the right button (NEXT) to skip to the next track.') + print('2. Press the central button (PLAY/PAUSE) to play/pause the track.') + print('3. Press the left button (BACK) to go back to the previous track.') + print('4. Long press the right button (NEXT) to fast-forward the current track.') + print('5. Long press the left button (BACK) to fast-backward the current track.') + print('\n') + print('Have fun!') + + # Initialize the device + sherlock = Sherlock( + TRACKS_DIR='./tracks', + FW_PIN=3, + BW_PIN=5, + PLAY_PIN=11, + OUT_PIN=13, + BOUNCE=200, # [milliseconds] + SKIP_TIME=10, # [seconds] + LONG_PRESS_TIME=2, # [seconds] + CURRENT_IDX=0, + PLAY_STATE=False, + RESTART_TIME=2 # [seconds] + ) + + # Start continuous loop + while True: + pass \ No newline at end of file diff --git a/src/sherlock.py b/src/sherlock.py index d2dabd8..75fb390 100644 --- a/src/sherlock.py +++ b/src/sherlock.py @@ -123,7 +123,9 @@ def _forward(self): # Play next track self._play() - print("Avanti: " , self.current_idx) + print(f"Avanti. Traccia corrente #{self.current_idx}") + elif long_press_flag: + print(f'Fast-forward. Traccia corrente #{self.current_idx}") def _fastforward(self): ''' @@ -163,7 +165,9 @@ def _backward(self): else: self.current_idx -= 1 self._play() - print("Indietro: " , self.current_idx) + print(f"Indietro. Traccia corrente #{self.current_idx}") + elif long_press_flag: + print(f'Fast-backward. Traccia corrente #{self.current_idx}") def _fastbackward(self): ''' @@ -181,11 +185,11 @@ def _play_pause(self): ''' if(self.is_playing): self.player.pause() - print("Pausa") + print(f"Pausa. Traccia corrente #{self.current_idx}") self.is_playing = False else: self.player.unpause() - print("Play") + print(f"Play. Traccia corrente #{self.current_idx}") self.is_playing = True def _long_press(self, pin, fforward): From df325382e1f15ee8f562f4eab6c00f4999c03dfb Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Mon, 24 Jan 2022 23:18:43 +0100 Subject: [PATCH 07/19] Add parameters.yaml file loading and support for external config --- config/sherlock_parameters.yaml | 11 +++++++++++ src/main.py | 19 ++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) create mode 100644 config/sherlock_parameters.yaml diff --git a/config/sherlock_parameters.yaml b/config/sherlock_parameters.yaml new file mode 100644 index 0000000..e78424f --- /dev/null +++ b/config/sherlock_parameters.yaml @@ -0,0 +1,11 @@ +TRACKS_DIR: './tracks' +FW_PIN: 3 +BW_PIN: 5 +PLAY_PIN: 11 +OUT_PIN: 13 +BOUNCE: 200 # [milliseconds] +SKIP_TIME: 10 # [seconds] +LONG_PRESS_TIME: 2 # [seconds] +CURRENT_IDX: 0 +PLAY_STATE: False +RESTART_TIME: 2 # [seconds] \ No newline at end of file diff --git a/src/main.py b/src/main.py index ffbc8af..0bf4268 100644 --- a/src/main.py +++ b/src/main.py @@ -3,6 +3,7 @@ import os import sys import time +import yaml from time import sleep import pygame @@ -28,20 +29,12 @@ print('\n') print('Have fun!') + # Load parameters file + with open('./config/sherlock_parameters.yaml', 'r') as param_file: + sherlock_params_dict = yaml.load(param_file, Loader=yaml.FullLoader) + # Initialize the device - sherlock = Sherlock( - TRACKS_DIR='./tracks', - FW_PIN=3, - BW_PIN=5, - PLAY_PIN=11, - OUT_PIN=13, - BOUNCE=200, # [milliseconds] - SKIP_TIME=10, # [seconds] - LONG_PRESS_TIME=2, # [seconds] - CURRENT_IDX=0, - PLAY_STATE=False, - RESTART_TIME=2 # [seconds] - ) + sherlock = Sherlock(**sherlock_params_dict) # Start continuous loop while True: From 355c75acfbca5af0fff3bd7bc956c6b6c2b9a622 Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Mon, 24 Jan 2022 23:18:57 +0100 Subject: [PATCH 08/19] Update README.md --- README.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index dd67bd7..8069901 100644 --- a/README.md +++ b/README.md @@ -76,19 +76,25 @@ python3 src/main.py ``` and enjoy the experience! +**N.B.**: at the moment, only `.mp3` audio files are supported. Please, do convert your audio files to the supported file formats. + ## To-do List Below, a non-comprehensive list of stuff we should do in the future: -* Update `README.md` with the exact RaspberryPi model used for prototyping and testing (including Ubuntu distro, Python version, etc.) for reproducibility purposes. -* Create a file with detailed technical specifications of the electronic components (resistors, LEDs, etc.). -* Clean and update `requirements.txt` and check all dependencies (eventually try to see if we can work with the latest releases to get better long-term support). -* Use conda venvs instead of python venv, so that we can also control the Python version -* Add the outer case 3D CAD model file to the repository. -* Add images of Sherlock's final prototype, and possibly of videos of it working. Also, add other images to use in the `README.md` file (e.g., ~~Sherlock and Hackability logos~~, electronic circuit, 3D CAD model, etc.). -* Add shields for release, license, etc. +* **[MEDIUM]** Update `README.md` with the exact RaspberryPi model used for prototyping and testing (including Ubuntu distro, Python version, etc.) for reproducibility purposes. +* **[LOW]** Create a file with detailed technical specifications of the electronic components (resistors, LEDs, etc.). +* **[MEDIUM]** Clean and update `requirements.txt` and check all dependencies (eventually try to see if we can work with the latest releases to get better long-term support). +* **[LOW]** Use conda venvs instead of python venv, so that we can also control the Python version +* **[MEDIUM]** Add the outer case 3D CAD model file to the repository. +* **[LOW]** Add images of Sherlock's final prototype, and possibly of videos of it working. Also, add other images to use in the `README.md` file (e.g., ~~Sherlock and Hackability logos~~, electronic circuit, 3D CAD model, etc.). +* **[VERY LOW]** Add shields for release, license, etc. +* **[HIGH]** Implement fast-backward. +* **[HIGH]** Test fast-for/backward functions when end/start of track is reached. Use GH Issues to open MRs/PRs for new improvements and adding functionalities. +Task priorities are in brackets. + ## Acknowledgements The Sherlock project was realized by [Hackability@Milano](http://www.hackability.it/hackabilitymilano/), in partnership with [Fondazione G. Brodolini](https://www.fondazionebrodolini.it/) and [Associazione Nazionale Subvedenti](https://www.subvedenti.it/), whose contributions were essential for the brainstorming and development of Sherlock. From 011bbaac8b684d3fac216d42a84ac7a500b20309 Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Mon, 24 Jan 2022 23:26:33 +0100 Subject: [PATCH 09/19] Fix error in print calls --- src/sherlock.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sherlock.py b/src/sherlock.py index 75fb390..bda8ffd 100644 --- a/src/sherlock.py +++ b/src/sherlock.py @@ -125,7 +125,7 @@ def _forward(self): print(f"Avanti. Traccia corrente #{self.current_idx}") elif long_press_flag: - print(f'Fast-forward. Traccia corrente #{self.current_idx}") + print(f'Fast-forward. Traccia corrente #{self.current_idx}') def _fastforward(self): ''' @@ -167,7 +167,7 @@ def _backward(self): self._play() print(f"Indietro. Traccia corrente #{self.current_idx}") elif long_press_flag: - print(f'Fast-backward. Traccia corrente #{self.current_idx}") + print(f'Fast-backward. Traccia corrente #{self.current_idx}') def _fastbackward(self): ''' From e5f017a6f577143b85128a6a0c409c55a8fb70f2 Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Mon, 24 Jan 2022 23:34:31 +0100 Subject: [PATCH 10/19] Update requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 5ce6a1e..5eacd18 100644 --- a/requirements.txt +++ b/requirements.txt @@ -56,6 +56,7 @@ pyinotify==0.9.6 PyJWT==1.7.0 pyOpenSSL==19.0.0 pyserial==3.4 +pyyaml pyxdg==0.25 rainbowhat==0.1.0 requests==2.21.0 From 5d69571be845eeedcc6a8b18af75d9af5251f99c Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Tue, 25 Jan 2022 21:53:17 +0100 Subject: [PATCH 11/19] Add try-except block to handle exceptions and KeyboardInterrupt --- src/main.py | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/main.py b/src/main.py index 0bf4268..5027d24 100644 --- a/src/main.py +++ b/src/main.py @@ -1,21 +1,13 @@ -import glob -import json import os -import sys -import time import yaml -from time import sleep - -import pygame -import RPi.GPIO as GPIO -from gpiozero import Button from sherlock import Sherlock -if __name__=='__main__': +def welcome_sherlock(): + '''Prints welcome and instructions for usage.''' # Print instructions print('#'*10) - print('WELCOME TO SHERLOCK') + print('WELCOME TO SHERLOCK! :)') print('#'*10) print('\n') print('#'*5) @@ -28,7 +20,16 @@ print('5. Long press the left button (BACK) to fast-backward the current track.') print('\n') print('Have fun!') + +def goodbye_sherlock(): + '''Prints closing message for KeyboardInterrupt exception.''' + # Print goodbye + print('#'*10) + print('GOODBYE! COME BACK SOON! :)') + print('#'*10) +def main(): + '''Starts main loop by initializing the Sherlock device.''' # Load parameters file with open('./config/sherlock_parameters.yaml', 'r') as param_file: sherlock_params_dict = yaml.load(param_file, Loader=yaml.FullLoader) @@ -36,6 +37,24 @@ # Initialize the device sherlock = Sherlock(**sherlock_params_dict) - # Start continuous loop + # Continue listening to events while True: - pass \ No newline at end of file + pass + +if __name__=='__main__': + ''' + Wraps main loop in a try-except exception handling to catch + KeyboardInterrupt as quit event. + ''' + try: + # Welcome message and instructions + welcome_sherlock() + # Start main loop + main() + # Catch CTRL+C command for quitting + except KeyboardInterrupt: + # Say goodbye + goodbye_sherlock() + # Deal elegantly with other errors and quit + except Exception as ex: + print('Encountered the following error: ', ex) \ No newline at end of file From c6c3ded33550c78060c6d4ed489c515ddd8f6460 Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Tue, 25 Jan 2022 22:18:10 +0100 Subject: [PATCH 12/19] Add SUPPORTED_FORMATS config parameters for permitted audio format check --- config/sherlock_parameters.yaml | 3 ++- src/main.py | 21 +++++++++++++++--- src/sherlock.py | 38 ++++++++++++++++----------------- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/config/sherlock_parameters.yaml b/config/sherlock_parameters.yaml index e78424f..b0bc4ab 100644 --- a/config/sherlock_parameters.yaml +++ b/config/sherlock_parameters.yaml @@ -8,4 +8,5 @@ SKIP_TIME: 10 # [seconds] LONG_PRESS_TIME: 2 # [seconds] CURRENT_IDX: 0 PLAY_STATE: False -RESTART_TIME: 2 # [seconds] \ No newline at end of file +RESTART_TIME: 2 # [seconds] +SUPPORTED_FORMATS: ['mp3'] \ No newline at end of file diff --git a/src/main.py b/src/main.py index 5027d24..831919e 100644 --- a/src/main.py +++ b/src/main.py @@ -28,11 +28,26 @@ def goodbye_sherlock(): print('GOODBYE! COME BACK SOON! :)') print('#'*10) +def read_yaml(config_path='./config/sherlock_parameters.yaml'): + ''' + Reads a .yaml file from the specified path. Returns a dict of parameters. + + Args: + config_path (str) : path to .yaml config file + + Returns: + params_dict (dict) : dict containing the parameters in config file + ''' + # Load parameters file + with open(config_path, 'r') as param_file: + params_dict = yaml.load(param_file, Loader=yaml.FullLoader) + + return params_dict + def main(): '''Starts main loop by initializing the Sherlock device.''' - # Load parameters file - with open('./config/sherlock_parameters.yaml', 'r') as param_file: - sherlock_params_dict = yaml.load(param_file, Loader=yaml.FullLoader) + # Load configuration parameters + sherlock_params_dict = read_yaml() # Initialize the device sherlock = Sherlock(**sherlock_params_dict) diff --git a/src/sherlock.py b/src/sherlock.py index bda8ffd..9acc6ba 100644 --- a/src/sherlock.py +++ b/src/sherlock.py @@ -1,9 +1,5 @@ -import glob -import json import os -import sys import time -from time import sleep import pygame import RPi.GPIO as GPIO @@ -16,34 +12,36 @@ class Sherlock: ''' def __init__( self, + FW_PIN, + BW_PIN, + PLAY_PIN, + OUT_PIN, TRACKS_DIR='./tracks', - FW_PIN=3, - BW_PIN=5, - PLAY_PIN=11, - OUT_PIN=13, BOUNCE=200, # [milliseconds] SKIP_TIME=10, # [seconds] LONG_PRESS_TIME=2, # [seconds] CURRENT_IDX=0, PLAY_STATE=False, RESTART_TIME=2 # [seconds] + SUPPORTED_FORMATS=['.mp3'] ): ''' Store all parameters, then (1) initialize the board, (2) initialize te pygame.mixer.music object. Args: - TRACKS_DIR (str) : path to the folder where the tracks are stored - FW_PIN (int) : RaspberryPi board pin for NEXT button - BW_PIN (int) : RaspberryPi board pin for BACK button - PLAY_PIN (int) : RaspberryPi board pin for PLAY/PAUSE button - OUT_PIN (int) : RaspberryPi board pin for OUTPUT - BOUNCE (int) : time delay (in [ms]) to compensate bounce effect - SKIP_TIME (int) : time (in [s]) to skip when long-pressing the NEXT button - LONG_PRESS_TIME (int) : time (in [s]) to long-press the NEXT button before triggering the fast-forward - CURRENT_IDX (int) : index of track to start the playback (assuming tracks are ordered) - PLAY_STATE (bool) : flag for play/pause status - RESTART_TIME (int) : time (in [s]) AFTER which the BACK button restarts the current track instead of going back to the previous one + FW_PIN (int) : RaspberryPi board pin for NEXT button. + BW_PIN (int) : RaspberryPi board pin for BACK button. + PLAY_PIN (int) : RaspberryPi board pin for PLAY/PAUSE button. + OUT_PIN (int) : RaspberryPi board pin for OUTPUT. + TRACKS_DIR (str) : path to the folder where the tracks are stored. Defaults to: '.tracks' + BOUNCE (int) : time delay (in [ms]) to compensate bounce effect. Defaults to: 200 + SKIP_TIME (int) : time (in [s]) to skip when long-pressing the NEXT button. Defaults to: 10 + LONG_PRESS_TIME (int) : time (in [s]) to long-press the NEXT button before triggering the fast-forward. Defaults to: 2 + CURRENT_IDX (int) : index of track to start the playback (assuming tracks are ordered). Defaults to: 0 + PLAY_STATE (bool) : flag for play/pause status. Defaults to: False + RESTART_TIME (int) : time (in [s]) AFTER which the BACK button restarts the current track instead of going back to the previous one. Defaults to: 2 + SUPPORTED_FORMATS (list): list of supported adio formats as strings. Defaults to: ['mp3'] ''' # RaspberryPi board setup self.fw_pin = FW_PIN # NEXT @@ -53,7 +51,7 @@ def __init__( self.bounce = BOUNCE # Compensate bounce effect # Other parameters - self.tracks = [os.path.join(TRACKS_DIR, track) for track in os.listdir(TRACKS_DIR)] # store tracks + self.tracks = [os.path.join(TRACKS_DIR, track) for track in os.listdir(TRACKS_DIR) for fmt in SUPPORTED_FORMATS if track.endswith(fmt)] # store tracks self.skip_time = SKIP_TIME # How many seconds to skip forward when long-pressing NEXT button self.long_press_time = LONG_PRESS_TIME # How long to keep pressing the NEXT button to trigger the fast-forward self.current_idx = CURRENT_IDX # From which track to start the playback (assuming the tracks in the folder are ordered) From 1f68b1fb9e1a4058f3194b85ddd658296a50876e Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Tue, 25 Jan 2022 22:36:00 +0100 Subject: [PATCH 13/19] Refactor _long_press method to accept any trigger action when long-pressing --- src/sherlock.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sherlock.py b/src/sherlock.py index 9acc6ba..bc1ebb9 100644 --- a/src/sherlock.py +++ b/src/sherlock.py @@ -110,7 +110,7 @@ def _forward(self): Long-pressing the NEXT button for `N` seconds lets the user fast-forward the track by `skip` seconds. ''' # Detect long-press - long_press_flag = self._long_press(self.fw_pin, fforward=True) + long_press_flag = self._long_press(self.fw_pin, self._fastforward) # If single, short press, skip to next track if (not long_press_flag): @@ -150,7 +150,7 @@ def _backward(self): Note: get_pos() returns time from start of playback in [milliseconds]. ''' # Detect long-press - long_press_flag = self._long_press(self.bw_pin, fforward=False) + long_press_flag = self._long_press(self.bw_pin, self._fastbackward) if (not long_press_flag): # If self.restart_track_time has passed, then restart current track @@ -190,13 +190,16 @@ def _play_pause(self): print(f"Play. Traccia corrente #{self.current_idx}") self.is_playing = True - def _long_press(self, pin, fforward): + def _long_press(self, pin, action, **action_kwargs): ''' - Detect long-pressing of any button. + Detect long-pressing of any button. + + Note: The action triggered by the long-pressing is repeated every half-second. Args: - pin (int) : pin to detect the long-pressing from - fforward (bool) : whether to fast-forward or fast-backward + pin (int) : board pin to detect the long-pressing from + action (function) : which action to trigger when long-pressing + action_kwargs (kwargs) : any kwargs needed by the action function (do not specify any if the function does not need any) Returns: long_press_flag (bool) : whether the long-press was detected or not @@ -210,11 +213,8 @@ def _long_press(self, pin, fforward): while GPIO.input(pin) == GPIO.LOW: time.sleep(.5) if(time.time()-start_press > self.long_press_time): - # Fast for-/back-ward the current track by N seconds - if fforward==True: - self._fastforward() - elif fforward==False: - self._fastbackward() + # Long-pressing triggers a specific action + action(**action_kwargs) # Do not go to the next track long_press_flag = True From 6b7a7212b3bfa5d6de4d16971bf0c5a9b0fd11c6 Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Tue, 25 Jan 2022 23:01:04 +0100 Subject: [PATCH 14/19] Improve Sherlock docstring --- src/sherlock.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/sherlock.py b/src/sherlock.py index bc1ebb9..06ef0cc 100644 --- a/src/sherlock.py +++ b/src/sherlock.py @@ -8,7 +8,7 @@ class Sherlock: ''' A Sherlock object contains all methods and attributes to setup and control - a Sherlock device. It builds upon the pygame.mixer object. + a Sherlock device. It builds upon the GPIO libray and the pygame.mixer object. ''' def __init__( self, @@ -23,7 +23,7 @@ def __init__( CURRENT_IDX=0, PLAY_STATE=False, RESTART_TIME=2 # [seconds] - SUPPORTED_FORMATS=['.mp3'] + SUPPORTED_FORMATS=['mp3'] ): ''' Store all parameters, then (1) initialize the board, (2) initialize @@ -42,6 +42,17 @@ def __init__( PLAY_STATE (bool) : flag for play/pause status. Defaults to: False RESTART_TIME (int) : time (in [s]) AFTER which the BACK button restarts the current track instead of going back to the previous one. Defaults to: 2 SUPPORTED_FORMATS (list): list of supported adio formats as strings. Defaults to: ['mp3'] + + Methods: + init_board : initializes RaspberryPi board + init_player : initializes pygame.mixer.music + _play : stops current track, loads track indicated by self.current_idx, then plays it + _forward : skips to next track or fast-forwards the current track. Used as callback in GPIO.add_event_detect + _fastforward : fast-forwards the current track by incrementing track position + _backward : restart current track or goes back to previous track. Used as callback in GPIO.add_event_detect + _fastbackward : fast-backwards the current track by decrementing track position + _play_pause : pause/unpause the current track. Used as callback in GPIO.add_event_detect + _long_press : detects long-pressing of any button and trigger specific action ''' # RaspberryPi board setup self.fw_pin = FW_PIN # NEXT From 135e2787ccdb55c27a2f160ec33839797b8174e2 Mon Sep 17 00:00:00 2001 From: Tam Huynh Date: Tue, 25 Jan 2022 23:07:25 +0100 Subject: [PATCH 15/19] Add examples to Sherlock docstring --- src/sherlock.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/sherlock.py b/src/sherlock.py index 06ef0cc..7547be0 100644 --- a/src/sherlock.py +++ b/src/sherlock.py @@ -9,6 +9,22 @@ class Sherlock: ''' A Sherlock object contains all methods and attributes to setup and control a Sherlock device. It builds upon the GPIO libray and the pygame.mixer object. + + Methods: + init_board : initializes RaspberryPi board + init_player : initializes pygame.mixer.music + _play : stops current track, loads track indicated by self.current_idx, then plays it + _forward : skips to next track or fast-forwards the current track. Used as callback in GPIO.add_event_detect + _fastforward : fast-forwards the current track by incrementing track position + _backward : restart current track or goes back to previous track. Used as callback in GPIO.add_event_detect + _fastbackward : fast-backwards the current track by decrementing track position + _play_pause : pause/unpause the current track. Used as callback in GPIO.add_event_detect + _long_press : detects long-pressing of any button and trigger specific action + + Examples: + >>> device1 = Sherlock(1, 2, 3, 4, 5) # dummy pins + >>> + >>> device2 = Sherlock(6, 7, 8, 9, 10, CURRENT_IDX=1, SUPPORTED_FORMATS=['wav', 'oog']) ''' def __init__( self, @@ -42,17 +58,6 @@ def __init__( PLAY_STATE (bool) : flag for play/pause status. Defaults to: False RESTART_TIME (int) : time (in [s]) AFTER which the BACK button restarts the current track instead of going back to the previous one. Defaults to: 2 SUPPORTED_FORMATS (list): list of supported adio formats as strings. Defaults to: ['mp3'] - - Methods: - init_board : initializes RaspberryPi board - init_player : initializes pygame.mixer.music - _play : stops current track, loads track indicated by self.current_idx, then plays it - _forward : skips to next track or fast-forwards the current track. Used as callback in GPIO.add_event_detect - _fastforward : fast-forwards the current track by incrementing track position - _backward : restart current track or goes back to previous track. Used as callback in GPIO.add_event_detect - _fastbackward : fast-backwards the current track by decrementing track position - _play_pause : pause/unpause the current track. Used as callback in GPIO.add_event_detect - _long_press : detects long-pressing of any button and trigger specific action ''' # RaspberryPi board setup self.fw_pin = FW_PIN # NEXT From 564cf39e38e2211b0ef2cc8248f353ce191bb2c4 Mon Sep 17 00:00:00 2001 From: Tam Huynh <64805016+mtdhuynh@users.noreply.github.com> Date: Thu, 3 Feb 2022 09:26:04 +0100 Subject: [PATCH 16/19] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8069901..18fc5b7 100644 --- a/README.md +++ b/README.md @@ -65,12 +65,13 @@ source /bin/activate ``` 4. Install project dependencies: ``` -pip install -r requirements.txt +pip3 install -r requirements.txt ``` ## Usage +1. Check and update the [`config/sherlock_parameters.yaml`](config/sherlock_parameters.yaml) configuration file with the actual pins used and with your preferred settings. More details on individual settings can be found in the `Sherlock` class [docstring](src/sherlock.py#L8). -From the command line, run: +2. From the command line, run: ``` python3 src/main.py ``` @@ -123,4 +124,4 @@ The Sherlock project is licensed under the [Creative Commons Attribution-NonComm [![CC BY-NC-SA 4.0][cc-by-nc-sa-image]][cc-by-nc-sa] [cc-by-nc-sa]: http://creativecommons.org/licenses/by-nc-sa/4.0/ -[cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png \ No newline at end of file +[cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png From 50959893fbd0476c4dc1348643cd5fc3938790af Mon Sep 17 00:00:00 2001 From: Tam Huynh <64805016+mtdhuynh@users.noreply.github.com> Date: Thu, 3 Feb 2022 19:39:59 +0100 Subject: [PATCH 17/19] Fix missing parameter in add_event_detect() callback --- src/sherlock.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/sherlock.py b/src/sherlock.py index 7547be0..e7dfd12 100644 --- a/src/sherlock.py +++ b/src/sherlock.py @@ -97,9 +97,9 @@ def init_board(self): GPIO.output(self.out_pin, GPIO.HIGH) # Detect button pressing events - GPIO.add_event_detect(self.fw_pin, GPIO.FALLING, callback = self._forward, bouncetime=self.bounce) - GPIO.add_event_detect(self.bw_pin, GPIO.FALLING, callback = self._backward, bouncetime=self.bounce) - GPIO.add_event_detect(self.play_pin, GPIO.FALLING, callback = self._play_pause, bouncetime=self.bounce) + GPIO.add_event_detect(self.fw_pin, GPIO.FALLING, callback=self._forward, bouncetime=self.bounce) + GPIO.add_event_detect(self.bw_pin, GPIO.FALLING, callback=self._backward, bouncetime=self.bounce) + GPIO.add_event_detect(self.play_pin, GPIO.FALLING, callback=self._play_pause, bouncetime=self.bounce) def init_player(self): '''Initialize pygame.mixer object.''' @@ -120,10 +120,13 @@ def _play(self): # Set is_playing flag self.is_playing = True - def _forward(self): + def _forward(self, channel): ''' Pressing the NEXT button lets the user skip to the next track. Long-pressing the NEXT button for `N` seconds lets the user fast-forward the track by `skip` seconds. + + Args: + channel: parameter passed by GPiO.add_event_detect callback. It is the pin number ''' # Detect long-press long_press_flag = self._long_press(self.fw_pin, self._fastforward) @@ -157,13 +160,16 @@ def _fastforward(self): # Skip by 'fforward_skip' seconds self.player.set_pos(self.skip_time) - def _backward(self): + def _backward(self, channel): ''' Pressing the BACK button lets te user either restart the current track or go back to the previous one if the time from the start of the current track is less than a pre-defined time interval. - Note: get_pos() returns time from start of playback in [milliseconds]. + Note: get_pos() returns time from start of playback in [milliseconds]. + + Args: + channel: parameter passed by GPiO.add_event_detect callback. It is the pin number ''' # Detect long-press long_press_flag = self._long_press(self.bw_pin, self._fastbackward) @@ -193,9 +199,12 @@ def _fastbackward(self): # Go back by 'self.skip_time' seconds raise NotImplementedError - def _play_pause(self): + def _play_pause(self, channel): ''' Pressing the center PLAY/PAUSE button, plays or pauses the current track. + + Args: + channel: parameter passed by GPiO.add_event_detect callback. It is the pin number ''' if(self.is_playing): self.player.pause() @@ -235,4 +244,4 @@ def _long_press(self, pin, action, **action_kwargs): # Do not go to the next track long_press_flag = True - return long_press_flag \ No newline at end of file + return long_press_flag From a9fb9239385e2be73fa88c467e90ca4b2a989e3d Mon Sep 17 00:00:00 2001 From: Tam Huynh <64805016+mtdhuynh@users.noreply.github.com> Date: Thu, 3 Feb 2022 19:45:42 +0100 Subject: [PATCH 18/19] Add more detailed print statements --- src/sherlock.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sherlock.py b/src/sherlock.py index e7dfd12..809bac4 100644 --- a/src/sherlock.py +++ b/src/sherlock.py @@ -38,7 +38,7 @@ def __init__( LONG_PRESS_TIME=2, # [seconds] CURRENT_IDX=0, PLAY_STATE=False, - RESTART_TIME=2 # [seconds] + RESTART_TIME=2, # [seconds] SUPPORTED_FORMATS=['mp3'] ): ''' @@ -140,9 +140,9 @@ def _forward(self, channel): # Play next track self._play() - print(f"Avanti. Traccia corrente #{self.current_idx}") + print(f"Avanti. Traccia corrente #{self.current_idx+1} - ({self.tracks[self.current_idx]})") elif long_press_flag: - print(f'Fast-forward. Traccia corrente #{self.current_idx}') + print(f'Fast-forward. Traccia corrente #{self.current_idx+1} - ({self.tracks[self.current_idx]})') def _fastforward(self): ''' @@ -185,9 +185,9 @@ def _backward(self, channel): else: self.current_idx -= 1 self._play() - print(f"Indietro. Traccia corrente #{self.current_idx}") + print(f"Indietro. Traccia corrente #{self.current_idx+1} - ({self.tracks[self.current_idx]})") elif long_press_flag: - print(f'Fast-backward. Traccia corrente #{self.current_idx}') + print(f'Fast-backward. Traccia corrente #{self.current_idx+1} - ({self.tracks[self.current_idx]})') def _fastbackward(self): ''' @@ -208,11 +208,11 @@ def _play_pause(self, channel): ''' if(self.is_playing): self.player.pause() - print(f"Pausa. Traccia corrente #{self.current_idx}") + print(f"Pausa. Traccia corrente #{self.current_idx+1} - ({self.tracks[self.current_idx]})") self.is_playing = False else: self.player.unpause() - print(f"Play. Traccia corrente #{self.current_idx}") + print(f"Play. Traccia corrente #{self.current_idx+1} - ({self.tracks[self.current_idx]})") self.is_playing = True def _long_press(self, pin, action, **action_kwargs): From 82989560f832ec01edd7ce006988e5b31fe49813 Mon Sep 17 00:00:00 2001 From: Tam Huynh <64805016+mtdhuynh@users.noreply.github.com> Date: Thu, 3 Feb 2022 20:03:43 +0100 Subject: [PATCH 19/19] Update README.md --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 18fc5b7..8e463ec 100644 --- a/README.md +++ b/README.md @@ -82,15 +82,20 @@ and enjoy the experience! ## To-do List Below, a non-comprehensive list of stuff we should do in the future: +* **[VERY HIGH]** `set_pos` only sets position with respect to `get_pos` (which does not update when calling `set_pos`). Therefore, need to define an attribute in the Sherlock class with the time from playback start (else, fast-forward/fast-backward won't work). + +* **[HIGH]** Implement fast-backward. +* **[HIGH]** Test fast-for/backward functions when end/start of track is reached. + * **[MEDIUM]** Update `README.md` with the exact RaspberryPi model used for prototyping and testing (including Ubuntu distro, Python version, etc.) for reproducibility purposes. -* **[LOW]** Create a file with detailed technical specifications of the electronic components (resistors, LEDs, etc.). * **[MEDIUM]** Clean and update `requirements.txt` and check all dependencies (eventually try to see if we can work with the latest releases to get better long-term support). -* **[LOW]** Use conda venvs instead of python venv, so that we can also control the Python version * **[MEDIUM]** Add the outer case 3D CAD model file to the repository. + +* **[LOW]** Create a file with detailed technical specifications of the electronic components (resistors, LEDs, etc.). +* **[LOW]** Use conda venvs instead of python venv, so that we can also control the Python version. * **[LOW]** Add images of Sherlock's final prototype, and possibly of videos of it working. Also, add other images to use in the `README.md` file (e.g., ~~Sherlock and Hackability logos~~, electronic circuit, 3D CAD model, etc.). + * **[VERY LOW]** Add shields for release, license, etc. -* **[HIGH]** Implement fast-backward. -* **[HIGH]** Test fast-for/backward functions when end/start of track is reached. Use GH Issues to open MRs/PRs for new improvements and adding functionalities.