Compare commits

...

9 Commits
V1 ... main

38 changed files with 17366 additions and 296 deletions

View File

@ -0,0 +1,2 @@
(kicad_pcb (version 20240108) (generator "pcbnew") (generator_version "8.0")
)

View File

@ -0,0 +1,83 @@
{
"board": {
"active_layer": 0,
"active_layer_preset": "",
"auto_track_width": true,
"hidden_netclasses": [],
"hidden_nets": [],
"high_contrast_mode": 0,
"net_color_mode": 1,
"opacity": {
"images": 0.6,
"pads": 1.0,
"tracks": 1.0,
"vias": 1.0,
"zones": 0.6
},
"selection_filter": {
"dimensions": true,
"footprints": true,
"graphics": true,
"keepouts": true,
"lockedItems": false,
"otherItems": true,
"pads": true,
"text": true,
"tracks": true,
"vias": true,
"zones": true
},
"visible_items": [
0,
1,
2,
3,
4,
5,
8,
9,
10,
11,
12,
13,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
32,
33,
34,
35,
36,
39,
40
],
"visible_layers": "fffffff_ffffffff",
"zone_display_mode": 0
},
"git": {
"repo_password": "",
"repo_type": "",
"repo_username": "",
"ssh_key": ""
},
"meta": {
"filename": "pianist_robot.kicad_prl",
"version": 3
},
"project": {
"files": []
}
}

View File

@ -0,0 +1,392 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {},
"diff_pair_dimensions": [],
"drc_exclusions": [],
"rules": {},
"track_widths": [],
"via_dimensions": []
},
"ipc2581": {
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": ""
},
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"conflicting_netclasses": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"endpoint_off_grid": "warning",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"missing_bidi_pin": "warning",
"missing_input_pin": "warning",
"missing_power_pin": "error",
"missing_unit": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"simulation_model_issue": "ignore",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "pianist_robot.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2,
"via_diameter": 0.6,
"via_drill": 0.3,
"wire_width": 6
}
],
"meta": {
"version": 3
},
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"plot": "",
"pos_files": "",
"specctra_dsn": "",
"step": "",
"svg": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"bom_export_filename": "",
"bom_fmt_presets": [],
"bom_fmt_settings": {
"field_delimiter": ",",
"keep_line_breaks": false,
"keep_tabs": false,
"name": "CSV",
"ref_delimiter": ",",
"ref_range_delimiter": "",
"string_delimiter": "\""
},
"bom_presets": [],
"bom_settings": {
"exclude_dnp": false,
"fields_ordered": [
{
"group_by": false,
"label": "Reference",
"name": "Reference",
"show": true
},
{
"group_by": true,
"label": "Value",
"name": "Value",
"show": true
},
{
"group_by": false,
"label": "Datasheet",
"name": "Datasheet",
"show": true
},
{
"group_by": false,
"label": "Footprint",
"name": "Footprint",
"show": true
},
{
"group_by": false,
"label": "Qty",
"name": "${QUANTITY}",
"show": true
},
{
"group_by": true,
"label": "DNP",
"name": "${DNP}",
"show": true
}
],
"filter_string": "",
"group_symbols": true,
"name": "Grouped By Value",
"sort_asc": true,
"sort_field": "Reference"
},
"connection_grid_size": 50.0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"operating_point_overlay_i_precision": 3,
"operating_point_overlay_i_range": "~A",
"operating_point_overlay_v_precision": 3,
"operating_point_overlay_v_range": "~V",
"overbar_offset_ratio": 1.23,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"page_layout_descr_file": "",
"plot_directory": "",
"spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"",
"spice_model_current_sheet_as_root": true,
"spice_save_all_currents": false,
"spice_save_all_dissipations": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"80af7aa2-e50e-4aba-a849-d06f270efa9f",
"Root"
]
],
"text_variables": {}
}

File diff suppressed because it is too large Load Diff

BIN
Songs/NujabesFeather.mp3 Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,37 +0,0 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the convention is to give header files names that end with `.h'.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

View File

@ -1,46 +0,0 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into the executable file.
The source code of each library should be placed in a separate directory
("lib/your_library_name/[Code]").
For example, see the structure of the following example libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
Example contents of `src/main.c` using Foo and Bar:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
The PlatformIO Library Dependency Finder will find automatically dependent
libraries by scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

11007
notes_output.csv Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1 @@
OK

View File

@ -0,0 +1,2 @@
model_checkpoint_path: "model"
all_model_checkpoint_paths: "model"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
OK

View File

@ -0,0 +1,2 @@
model_checkpoint_path: "model"
all_model_checkpoint_paths: "model"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
OK

View File

@ -0,0 +1,2 @@
model_checkpoint_path: "model"
all_model_checkpoint_paths: "model"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -6,7 +6,7 @@ import serial.tools.list_ports
# Define the paths # Define the paths
#Short notes #Short notes
NOTES_PATH = "Player\\notes\\mp3-master\\" NOTES_PATH = "pysrc\\notes\\mp3-master\\"
#Long notes #Long notes
#NOTES_PATH = r"C:\Users\Balthazar\Shared\ECAM\Advance Robotique\Project\Player\notes\high-quality-master\renamed\\" #NOTES_PATH = r"C:\Users\Balthazar\Shared\ECAM\Advance Robotique\Project\Player\notes\high-quality-master\renamed\\"
SERIAL_PORT = "COM5" SERIAL_PORT = "COM5"

View File

@ -1,80 +0,0 @@
import serial
import time
import pygame
from pydub import AudioSegment
import serial.tools.list_ports
# Define the paths
#Short notes
NOTES_PATH = "Player\\notes\\mp3-master\\"
#Long notes
#NOTES_PATH = r"C:\Users\Balthazar\Shared\ECAM\Advance Robotique\Project\Player\notes\high-quality-master\renamed\\"
SERIAL_PORT = "COM5" #"COM3"
BAUD_RATE = 115200
# New Features
wait_note_finish = False # Set to False to play without waiting for the note to finish
keyboard_input = False # Set to False to disable keyboard note input
check_com3 = True # Set to False to skip COM3 check
pygame.mixer.init()
octave = 4
notes = ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"]
def play_note_with_pygame(note):
try:
pygame_sound = pygame.mixer.Sound(f"{NOTES_PATH}{note}.mp3")
pygame_sound.play()
if wait_note_finish:
while pygame.mixer.get_busy(): # Wait until sound is finished
pygame.time.Clock().tick(10)
except Exception as e:
print(f"Error playing {note}: {e}")
# Check if COM3 is connected
if check_com3:
ports = list(serial.tools.list_ports.comports())
com3_found = any(port.device == SERIAL_PORT for port in ports)
if not com3_found:
print(f"{SERIAL_PORT} not found. Switching to keyboard input mode.")
keyboard_input = True
try:
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
time.sleep(2)
except Exception as e:
print(f"Error opening {SERIAL_PORT}: {e}")
keyboard_input = True
print("Listening for Arduino input...")
while True:
try:
# Keyboard input for playing notes
if keyboard_input:
user_input = input("Enter note (C, Db, D, ... B) or 'q' to quit: ")
if user_input == 'q':
break
if user_input in notes:
play_note_with_pygame(f"{user_input}{octave}")
# Arduino input for playing notes
data = ser.readline().decode('utf-8', errors='ignore').strip()
if data:
print("data : " + data)
note = data
if note in notes:
play_note_with_pygame(f"{note}{octave}")
except KeyboardInterrupt:
print("Exiting...")
break
except Exception as e:
print(f"Error: {e}")
ser.close()

29
pysrc/Song_Spleeter.py Normal file
View File

@ -0,0 +1,29 @@
import subprocess
import os
import sys
def separate_audio(input_file,stems,output_folder="output"):
try:
# Create output directory if it doesn't exist
os.makedirs(output_folder, exist_ok=True)
input_file_name=input_file
input_file_name= input_file_name.replace(".mp3","")
# Use python -m to ensure the correct module is called
command = [
sys.executable, "-m", "spleeter", "separate",
"-o", output_folder+"\\"+input_file_name+stems,
"-p", "spleeter:"+stems,
"C:\\Users\\louis\\Desktop\\VScode\\Python\\Songs\\"+input_file,
]
print(f"Running command: {' '.join(command)}")
subprocess.run(command, check=True)
print(f"Separation complete! Files saved in {output_folder}/")
except subprocess.CalledProcessError as e:
print(f"Error running Spleeter: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
# Example usage
separate_audio("TheSylversRememberTheRain.mp3" , "4stems")

211
pysrc/WaveToNotesTests.py Normal file
View File

@ -0,0 +1,211 @@
import crepe
from scipy.io import wavfile
import json
import csv
import numpy as np
# Define file paths
fileName = "NujabesFeather4stems/other.wav"
audio_file = "output/"+fileName
# Replace the slash with nothing to flatten the path
flat_name = fileName.replace("/", "")
# Remove the .wav extension
without_extension = flat_name[:-4] # removes last 4 characters (.wav)
# Create the output filename
output_csv = "crepe_output" + without_extension + ".csv"
def getNotesFromFreq(freqNotesArray, freqNotesConfidence):
notes_json='''{
"notes": [
{"note": "A", "octave": 0, "frequency": 27.5},
{"note": "Bb", "octave": 0, "frequency": 29.135},
{"note": "B", "octave": 0, "frequency": 30.868},
{"note": "C", "octave": 1, "frequency": 32.703},
{"note": "Db", "octave": 1, "frequency": 34.648},
{"note": "D", "octave": 1, "frequency": 36.708},
{"note": "Eb", "octave": 1, "frequency": 38.891},
{"note": "E", "octave": 1, "frequency": 41.203},
{"note": "F", "octave": 1, "frequency": 43.654},
{"note": "Gb", "octave": 1, "frequency": 46.249},
{"note": "G", "octave": 1, "frequency": 48.999},
{"note": "Ab", "octave": 1, "frequency": 51.913},
{"note": "A", "octave": 1, "frequency": 55.0},
{"note": "Bb", "octave": 1, "frequency": 58.27},
{"note": "B", "octave": 1, "frequency": 61.735},
{"note": "C", "octave": 2, "frequency": 65.406},
{"note": "Db", "octave": 2, "frequency": 69.296},
{"note": "D", "octave": 2, "frequency": 73.416},
{"note": "Eb", "octave": 2, "frequency": 77.782},
{"note": "E", "octave": 2, "frequency": 82.407},
{"note": "F", "octave": 2, "frequency": 87.307},
{"note": "Gb", "octave": 2, "frequency": 92.499},
{"note": "G", "octave": 2, "frequency": 97.999},
{"note": "Ab", "octave": 2, "frequency": 103.826},
{"note": "A", "octave": 2, "frequency": 110.0},
{"note": "Bb", "octave": 2, "frequency": 116.541},
{"note": "B", "octave": 2, "frequency": 123.471},
{"note": "C", "octave": 3, "frequency": 130.813},
{"note": "Db", "octave": 3, "frequency": 138.591},
{"note": "D", "octave": 3, "frequency": 146.832},
{"note": "Eb", "octave": 3, "frequency": 155.563},
{"note": "E", "octave": 3, "frequency": 164.814},
{"note": "F", "octave": 3, "frequency": 174.614},
{"note": "Gb", "octave": 3, "frequency": 184.997},
{"note": "G", "octave": 3, "frequency": 195.998},
{"note": "Ab", "octave": 3, "frequency": 207.652},
{"note": "A", "octave": 3, "frequency": 220.0},
{"note": "Bb", "octave": 3, "frequency": 233.082},
{"note": "B", "octave": 3, "frequency": 246.942},
{"note": "C", "octave": 4, "frequency": 261.626},
{"note": "Db", "octave": 4, "frequency": 277.183},
{"note": "D", "octave": 4, "frequency": 293.665},
{"note": "Eb", "octave": 4, "frequency": 311.127},
{"note": "E", "octave": 4, "frequency": 329.628},
{"note": "F", "octave": 4, "frequency": 349.228},
{"note": "Gb", "octave": 4, "frequency": 369.994},
{"note": "G", "octave": 4, "frequency": 391.995},
{"note": "Ab", "octave": 4, "frequency": 415.305},
{"note": "A", "octave": 4, "frequency": 440.0},
{"note": "Bb", "octave": 4, "frequency": 466.164},
{"note": "B", "octave": 4, "frequency": 493.883},
{"note": "C", "octave": 5, "frequency": 523.251},
{"note": "Db", "octave": 5, "frequency": 554.365},
{"note": "D", "octave": 5, "frequency": 587.33},
{"note": "Eb", "octave": 5, "frequency": 622.254},
{"note": "E", "octave": 5, "frequency": 659.255},
{"note": "F", "octave": 5, "frequency": 698.456},
{"note": "Gb", "octave": 5, "frequency": 739.989},
{"note": "G", "octave": 5, "frequency": 783.991},
{"note": "Ab", "octave": 5, "frequency": 830.609},
{"note": "A", "octave": 5, "frequency": 880.0},
{"note": "Bb", "octave": 5, "frequency": 932.328},
{"note": "B", "octave": 5, "frequency": 987.767},
{"note": "C", "octave": 6, "frequency": 1046.502},
{"note": "Db", "octave": 6, "frequency": 1108.731},
{"note": "D", "octave": 6, "frequency": 1174.659},
{"note": "Eb", "octave": 6, "frequency": 1244.508},
{"note": "E", "octave": 6, "frequency": 1318.51},
{"note": "F", "octave": 6, "frequency": 1396.913},
{"note": "Gb", "octave": 6, "frequency": 1479.978},
{"note": "G", "octave": 6, "frequency": 1567.982},
{"note": "Ab", "octave": 6, "frequency": 1661.219},
{"note": "A", "octave": 6, "frequency": 1760.0},
{"note": "Bb", "octave": 6, "frequency": 1864.655},
{"note": "B", "octave": 6, "frequency": 1975.533},
{"note": "C", "octave": 7, "frequency": 2093.005},
{"note": "Db", "octave": 7, "frequency": 2217.461},
{"note": "D", "octave": 7, "frequency": 2349.318},
{"note": "Eb", "octave": 7, "frequency": 2489.016},
{"note": "E", "octave": 7, "frequency": 2637.021},
{"note": "F", "octave": 7, "frequency": 2793.826},
{"note": "Gb", "octave": 7, "frequency": 2959.955},
{"note": "G", "octave": 7, "frequency": 3135.964},
{"note": "Ab", "octave": 7, "frequency": 3322.438},
{"note": "A", "octave": 7, "frequency": 3520.0},
{"note": "Bb", "octave": 7, "frequency": 3729.31},
{"note": "B", "octave": 7, "frequency": 3951.066},
{"note": "C", "octave": 8, "frequency": 4186.009}
]
}'''
notes_data = json.loads(notes_json)
finalNoteArray = []
for i, freq in enumerate(freqNotesArray):
bestFreqDif = float('inf')
if freqNotesConfidence[i] < 0.5:
finalNote = "NoNoteFound"
else :
for note_data in notes_data['notes']:
freqDif = abs(note_data['frequency'] - freq)
if freqDif < bestFreqDif:
bestFreqDif = freqDif
finalNote = note_data['note']
finalNoteArray.append(finalNote)
return finalNoteArray
try:
# Try to read existing CSV
with open(output_csv, newline='') as csvfile:
reader = csv.DictReader(csvfile)
data = list(reader)
# Extract frequency and confidence from CSV
time = [float(row['time']) for row in data]
frequency = [float(row['frequency']) for row in data]
confidence = [float(row['confidence']) for row in data]
print(f"Loaded {len(frequency)} data points from existing CSV")
except (FileNotFoundError, KeyError) as e:
# If file doesn't exist or has incorrect format, process the audio
print(f"Processing audio file: {audio_file}")
# Read audio file
sr, audio = wavfile.read(audio_file)
# Ensure audio is mono (if stereo, take first channel)
if len(audio.shape) > 1 and audio.shape[1] > 1:
audio = audio[:, 0]
# Convert audio to float32 if needed
if audio.dtype != np.float32:
# Normalize based on data type
if audio.dtype == np.int16:
audio = audio.astype(np.float32) / 32768.0
elif audio.dtype == np.int32:
audio = audio.astype(np.float32) / 2147483648.0
# Run CREPE pitch detection
time, frequency, confidence, activation = crepe.predict(audio, sr, viterbi=True)
# Write results to CSV
with open(output_csv, 'w', newline='') as csvfile:
fieldnames = ['time', 'frequency', 'confidence']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for i,ArrayCombined in enumerate(zip(time, frequency, confidence)):
if confidence[i] >= 0.5:
writer.writerow({
'time': ArrayCombined[0],
'frequency': ArrayCombined[1],
'confidence': ArrayCombined[2]
})
print(f"Saved {len(frequency)} data points to {output_csv}")
# Convert frequencies to notes
notes = getNotesFromFreq(frequency, confidence)
# Save notes to another CSV file
notes_csv = "notes_output.csv"
with open(notes_csv, 'w', newline='') as csvfile:
fieldnames = ['time', 'frequency', 'confidence', 'note']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for i,ArrayCombined in enumerate(zip(time, frequency, confidence, notes)):
if confidence[i] >= 0.5:
writer.writerow({
'time': ArrayCombined[0],
'frequency': ArrayCombined[1],
'confidence': ArrayCombined[2],
'note': ArrayCombined[3]
})
print(frequency[:30])
print(f"Saved {len(notes)} notes to {notes_csv}")
print(f"Sample of notes: {notes[:10]}")

254
pysrc/robotController_V2.py Normal file
View File

@ -0,0 +1,254 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import json
import time
# Read the sensors positions from the sensor_positions.json file
with open('sensor_positions.json', 'r') as f:
config = json.load(f)
###########################################################################
## SET THE NOTES TO PLAY AS SUCH:
## notes_to_play = [NOTE1, NOTE2,...,NOTEx]
## with the notes being
## C, C#, D, D#, E, F, F#, G, G#, A, A#, B
## = 1, 2 , 3, 4 , 5, 6, 7 , 8, 9 ,10, 11, 12
##
## To play at rythm, the duration of a note must be added after the ID
## like so: notes_to_play = [NOTE1, NOTE2,'half', NOTE3, 'eigth',...,NOTEx]
## to play NOTE2 for longer and NOTE3 faster
###########################################################################
#note_to_play = 2 #note id to play (see sensor_positions.json)
#notes_to_play = [1,2,3,4,5,6,7,8,9,10,11,12]
#play Au clair de la Lune
#notes_to_play = [1, 1, 1, 3, 5,'half', 3,'half', 1, 5, 3, 3, 1, 'half']
#play Ode yo Joy
#notes_to_play = [5, 5, 6, 8, 8, 6, 5, 3, 1, 1, 3, 5, 5, 3, 3, 'half', 5, 5, 6, 8, 8, 6, 5, 3, 1, 1, 3, 5, 3, 1, 1, 'half', 3, 3, 5, 1, 3, 5,'eigth', 6,'eigth', 5, 1, 3, 5,'eigth', 6,'eigth', 5, 3, 1, 3, 8, 'half', 5, 5, 6, 8, 8, 6, 5, 3, 1, 1, 3, 5, 3, 1, 1]
#play Happy Birthday
notes_to_play = [1, 1, 3, 1, 6, 5,'half', 1, 1, 3, 1, 8, 6,'half', 1, 1, 10, 8, 6, 5, 3,'eigth', 3,'half', 11, 11, 10, 6, 8, 6]
#play megalovania
#notes_to_play = [3, 3, 10, 9, 8, 6, 3, 6, 8]
notes_to_play = [3,3, 5,3, 10 ,5 ,10,12,6,5,3]
notes_to_play.append('end') #to know when it is the end of the array
delay = 0.1
note_delay = 0.2 #delay between notes, corresponding to tempo
init_note_delay = note_delay
if os.name == 'nt':
import msvcrt
def getch():
return msvcrt.getch().decode()
else:
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
def getch():
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
from dynamixel_sdk import * # Uses Dynamixel SDK library
# Control table address
ADDR_PRO_TORQUE_ENABLE = 24 # Control table address is different in Dynamixel model
ADDR_PRO_GOAL_POSITION = 30
ADDR_PRO_PRESENT_POSITION = 37
# Protocol version
PROTOCOL_VERSION = 2.0 # See which protocol version is used in the Dynamixel
# Set Dynamixel motors IDs
DXL1_ID = 1
DXL2_ID = 2
DXL3_ID = 3
BAUDRATE = 1000000 # Dynamixel baudrate : 1000000
DEVICENAME = 'COM10' # Check which port is being used on your controller
# ex) Windows: "COM1" Linux: "/dev/ttyUSB0" Mac: "/dev/tty.usbserial-*"
TORQUE_ENABLE = 1 # Value for enabling the torque
TORQUE_DISABLE = 0 # Value for disabling the torque
#CONNECT TO ROBOT
# Initialize PortHandler instance
# Set the port path
# Get methods and members of PortHandlerLinux or PortHandlerWindows
portHandler = PortHandler(DEVICENAME)
# Initialize PacketHandler instance
# Set the protocol version
# Get methods and members of Protocol1PacketHandler or Protocol2PacketHandler
packetHandler = PacketHandler(PROTOCOL_VERSION)
# Open port
if portHandler.openPort():
print("Succeeded to open the port")
else:
print("Failed to open the port")
print("Press any key to terminate...")
getch()
quit()
# Set port baudrate
if portHandler.setBaudRate(BAUDRATE):
print("Succeeded to change the baudrate")
else:
print("Failed to change the baudrate")
print("Press any key to terminate...")
getch()
quit()
#ENABLE TORQUES
# Enable Dynamixel#1 Torque
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_ENABLE)
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
else:
print("Dynamixel#%d has been successfully connected" % DXL1_ID)
# Enable Dynamixel#2 Torque
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_ENABLE)
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
else:
print("Dynamixel#%d has been successfully connected" % DXL2_ID)
# Enable Dynamixel#3 Torque
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_ENABLE)
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
else:
print("Dynamixel#%d has been successfully connected" % DXL3_ID)
#PLAY NOTES
index = 0
dxl2_goal_position = config["sensors"][0]["q2"] # Goal position 2
while index < len(notes_to_play):
if notes_to_play[index]=='end': #end the loop if after last note
break
time.sleep(note_delay)
note_delay = init_note_delay
packetHandler.write4ByteTxRx(portHandler, 2, ADDR_PRO_GOAL_POSITION, dxl2_goal_position-80) #move up between notes to avoid collisions
note_to_play = notes_to_play[index] #check the current note
if note_to_play == 'half' or note_to_play == 'eigth': #skip the position if it is a 'half' or an 'eigth'
index = index+1
note_to_play = notes_to_play[index]
if notes_to_play[index+1] == 'half': #if the next position is /'half' wait longer/ after playing the current note
note_delay = init_note_delay*4
elif notes_to_play[index+1] == 'eigth': #if the next position is /'eigth' wait less/ after playing the current note
note_delay = init_note_delay/4
#Get note joint values from Json file
dxl1_goal_position = config["sensors"][note_to_play-1]["q1"] # Goal position 1
dxl2_goal_position = config["sensors"][note_to_play-1]["q2"] # Goal position 2
dxl3_goal_position = config["sensors"][note_to_play-1]["q3"] # Goal position 3
while 1:
#print("Press any key to continue! (or press ESC to quit!)") #
#if getch() == chr(0x1b): #causes errors
# break #
# Move motor 1, then 3, and then 2 to avoid collisions
# Motor 1
# Write goal position 1
dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_GOAL_POSITION, dxl1_goal_position)
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
time.sleep(delay)
# Motor 3
# Write goal position 3
dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_GOAL_POSITION, dxl3_goal_position)
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
time.sleep(delay)
# Motor 2
# Write goal position 2
dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_GOAL_POSITION, dxl2_goal_position)
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
time.sleep(delay)
index = index + 1
break
# go to next position
#GO TO MIDDLE POSITION
dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_GOAL_POSITION, 30)
time.sleep(0.5)
dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_GOAL_POSITION, 500)
time.sleep(0.5)
dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_GOAL_POSITION, 500)
time.sleep(0.5)
# DISABLE DYNAMIXEL TORQUES 1 2 3
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL1_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL2_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL3_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
# Close port
portHandler.closePort()

100
pysrc/sensor_positions.json Normal file
View File

@ -0,0 +1,100 @@
{
"sensors": [
{
"id": 1,
"note": "C",
"type": "natural",
"q1": 770,
"q2": 170,
"q3": 530
},
{
"id": 2,
"note": "C",
"type": "sharp",
"q1": 800,
"q2": 89,
"q3": 735
},
{
"id": 3,
"note": "D",
"type": "natural",
"q1": 715,
"q2": 170,
"q3": 530
},
{
"id": 4,
"note": "D",
"type": "sharp",
"q1": 650,
"q2": 89,
"q3": 735
},
{
"id": 5,
"note": "E",
"type": "natural",
"q1": 600 ,
"q2": 170,
"q3": 530
},
{
"id": 6,
"note": "F",
"type": "natural",
"q1": 520,
"q2": 170,
"q3": 530
},
{
"id": 7,
"note": "F",
"type": "sharp",
"q1": 516,
"q2": 89,
"q3": 735
},
{
"id": 8,
"note": "G",
"type": "natural",
"q1": 445,
"q2": 170,
"q3": 530
},
{
"id": 9,
"note": "G",
"type": "sharp",
"q1": 360,
"q2": 89,
"q3": 735
},
{
"id": 10,
"note": "A",
"type": "natural",
"q1": 333,
"q2": 170,
"q3": 530
},
{
"id": 11,
"note": "A",
"type": "sharp",
"q1": 229,
"q2": 89,
"q3": 735
},
{
"id": 12,
"note": "B",
"type": "natural",
"q1": 270,
"q2": 170,
"q3": 530
}
]
}

View File

@ -1,62 +0,0 @@
/**
* This file is used for debugging the analog values of the pins on the ESP32.
* It reads the analog values from the specified pins and prints them to the Serial Monitor.
* The values are color-coded based on a defined threshold.
* Values below the threshold are printed in green, while values above the threshold are printed in red.
*/
#include <Arduino.h>
#define THRESHOLD 3000 // Define the threshold value for analog readings
#define COLOR_RED "\033[31m" // ANSI escape code for red color
#define COLOR_GREEN "\033[32m" // ANSI escape code for green color
#define COLOR_RST "\033[0m" // ANSI escape code to reset color
//const int pinList[] = {34, 35, 32, 33, 25, 26, 27, 14, 15, 2, 0, 4}; // Array of the pins you want to use
const int pinList[] = {4, 0, 2, 15, 14, 27, 26, 25, 33, 32, 35, 34}; // Array of the pins you want to use
const int numPins = sizeof(pinList) / sizeof(pinList[0]); // Number of pins in the array
int ArrayStates[numPins]; // Array to store previous states of pins
float ArrayValues[numPins]; // Array to store analog values of pins
template <typename T>
void printArray(T array[], int size);
void setup() {
Serial.begin(115200);
// Initialize each pin in the pinList as an input
for (int i = 0; i < numPins; i++) {
pinMode(pinList[i], INPUT); // Set pins as input
ArrayStates[i] = 0; // Set initial state to 0
}
}
void loop() {
for (int i = 0; i < numPins; i++) {
int analogValue = analogRead(pinList[i]); // Read the analog value of the pin
ArrayStates[i] = (analogValue < THRESHOLD) ? 1 : 0; // Compare with threshold
ArrayValues[i] = analogValue; // Store the analog value
}
printArray(ArrayValues, numPins);
//Serial.print(">States: ");
//printArray(ArrayStates, numPins);
//delay(0); // Add a small delay to avoid flooding the output
}
template <typename T>
void printArray(T array[], int size) {
Serial.print("["); // Start of the message
for (int i = 0; i < size; i++) {
if (array[i] < THRESHOLD) {
Serial.print(COLOR_GREEN); // Change color to red if below threshold
} else {
Serial.print(COLOR_RED); // Change color to green if above threshold
}
Serial.print(array[i]); // Print the value
Serial.print(COLOR_RST); // Reset color to default
if (i < size - 1) {
Serial.print(", "); // Add a comma and space if it's not the last element
}
}
Serial.println("]"); // End of the message
}

View File

@ -1,59 +0,0 @@
/**
* This file is used for debugging the analog values of the pins on the ESP32.
* It reads the analog values from the specified pins and prints them to the Serial Monitor.
* The values are color-coded based on a defined threshold.
* Values below the threshold are printed in green, while values above the threshold are printed in red.
*/
#include <Arduino.h>
#define THRESHOLD 3000 // Define the threshold value for analog readings
//const int pinList[] = {34, 35, 32, 33, 25, 26, 27, 14, 15, 2, 0, 4}; // Array of the pins you want to use
const int pinList[] = {4, 0, 2, 15, 14, 27, 26, 25, 33, 32, 35, 34}; // Array of the pins you want to use
const int numPins = sizeof(pinList) / sizeof(pinList[0]); // Number of pins in the array
const char* noteList[] = {"C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"}; // Array of note names
int ArrayStates[numPins]; // Array to store previous states of pins
int LastSentStates[numPins]; // Array to store last sent states of pins
float ArrayValues[numPins]; // Array to store analog values of pins
bool isArrayEmpty(int array[], int size) {
for (int i = 0; i < size; i++) {
if (array[i] != 0) { // Check if any element is not zero
return false; // Array is not empty
}
}
return true; // Array is empty
}
void setup() {
Serial.begin(115200);
// Initialize each pin in the pinList as an input
for (int i = 0; i < numPins; i++) {
pinMode(pinList[i], INPUT); // Set pins as input
ArrayStates[i] = 0; // Set initial state to 0
}
Serial.println("Starting up..."); // Print a message indicating startup
}
void loop() {
for (int i = 0; i < numPins; i++) {
int analogValue = analogRead(pinList[i]); // Read the analog value of the pin
ArrayStates[i] = (analogValue < THRESHOLD) ? 1 : 0; // Compare with threshold
ArrayValues[i] = analogValue; // Store the analog value
}
if (memcmp(ArrayStates, LastSentStates, sizeof(ArrayStates)) != 0) {
memcpy(LastSentStates, ArrayStates, sizeof(ArrayStates)); // Update last sent states
if (isArrayEmpty(ArrayStates, numPins) == false) {
for (int i = 0; i < numPins; i++) {
if (ArrayStates[i] == 1) {
Serial.print(noteList[i]); // Print the note name if the state is 1
Serial.print(" "); // Add a space between note names
}
}
Serial.println(); // Print a new line after printing all note names
delay(250); //avoid flickering in the sensing
}
}
}

View File

@ -1,11 +0,0 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html