diff --git a/oving_3/main.py b/oving_3/main.py index 9e9700f..e4b38bf 100644 --- a/oving_3/main.py +++ b/oving_3/main.py @@ -7,6 +7,10 @@ from pybricks.robotics import DriveBase from pybricks.media.ev3dev import SoundFile, ImageFile +from rtttl_player import RTTTLPlayer +from random import randint + + # This program requires LEGO EV3 MicroPython v2.0 or higher. # Click "Open user guide" on the EV3 extension tab for more information. @@ -15,6 +19,27 @@ # Create your objects here. ev3 = EV3Brick() +# Eksempelmelodi (Nokia) +#take_on_me = "Take On Me:o=5,d=8,b=160,b=160:f#,f#,f#,d,p,b4,p,e,p,e,p,e,g#,g#,a,b,a,a,a,e,p,d,p,f#,p,f#,p,f#,e,e,f#,e,f#,f#,f#,d,p,b4,p,e,p,e,p,e,g#,g#,a,b,a,a,a,e,p,d,p,f#,p,f#,p,f#,e,e5" +#postman_pat ="Postman Pat:o=5,d=16,b=100,b=100:f#,p,a,p,8b,8p,f#,p,a,p,8b,8p,f#,p,a,p,b,p,d6,d6,c#6,c#6,a,p,4b.,8p,32f#,g,p,a,p,b,p,g,p,8f#.,8e,8p,32f#,g,p,a,p,32b.,32b.,g,p,8f#.,8e,8p,32f#,g,p,a,p,b,p,g,p,f#,p,e,p,d,p,c#,p,2d" +#simpsons = "Simpsons:o=5,d=8,b=160,b=160:c6.,4e6,4f#6,a6,4g6.,4e6,4c6,a,f#,f#,f#,2g,p,p,f#,f#,f#,g,4a#.,c6,c6,c6,4c6" +#mission_impossible = "Mission Impossible:o=5,d=16,b=100,b=100:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,g,8p,g,8p,a#,p,c6,p,g,8p,g,8p,f,p,f#,p,g,8p,g,8p,a#,p,c6,p,g,8p,g,8p,f,p,f#,p,a#,g,2d,32p,a#,g,2c#,32p,a#,g,2c,p,a#4,c" + +songs = [ + "Take On Me:o=5,d=8,b=160,b=160:f#,f#,f#,d,p,b4,p,e,p,e,p,e,g#,g#,a,b,a,a,a,e,p,d,p,f#,p,f#,p,f#,e,e,f#,e,f#,f#,f#,d,p,b4,p,e,p,e,p,e,g#,g#,a,b,a,a,a,e,p,d,p,f#,p,f#,p,f#,e,e5", + "Postman Pat:o=5,d=16,b=100,b=100:f#,p,a,p,8b,8p,f#,p,a,p,8b,8p,f#,p,a,p,b,p,d6,d6,c#6,c#6,a,p,4b.,8p,32f#,g,p,a,p,b,p,g,p,8f#.,8e,8p,32f#,g,p,a,p,32b.,32b.,g,p,8f#.,8e,8p,32f#,g,p,a,p,b,p,g,p,f#,p,e,p,d,p,c#,p,2d", + "Simpsons:o=5,d=8,b=160,b=160:c6.,4e6,4f#6,a6,4g6.,4e6,4c6,a,f#,f#,f#,2g,p,p,f#,f#,f#,g,4a#.,c6,c6,c6,4c6", + "Mission Impossible:o=5,d=16,b=100,b=100:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,g,8p,g,8p,a#,p,c6,p,g,8p,g,8p,f,p,f#,p,g,8p,g,8p,a#,p,c6,p,g,8p,g,8p,f,p,f#,p,a#,g,2d,32p,a#,g,2c#,32p,a#,g,2c,p,a#4,c" +] + +# Lag spiller og kjør +player = RTTTLPlayer(ev3, songs[3]) +#ev3.screen.print("Spiller", player.name, "...") +#player.play() + +leftMotor = Motor(port=Port.A) +rightMotor = Motor(port=Port.B) + +robotDriveBase = DriveBase(leftMotor, rightMotor, wheel_diameter=56, axle_track=110) -# Write your program here. -ev3.speaker.beep() +robotDriveBase.drive(1000, 0) \ No newline at end of file diff --git a/oving_3/rtttl_player.py b/oving_3/rtttl_player.py new file mode 100644 index 0000000..8ca0e4f --- /dev/null +++ b/oving_3/rtttl_player.py @@ -0,0 +1,60 @@ +import re + + +class RTTTLPlayer: + NOTE_FREQS = { + 'c': 16.35, 'c#': 17.32, 'd': 18.35, 'd#': 19.45, + 'e': 20.60, 'f': 21.83, 'f#': 23.12, 'g': 24.50, + 'g#': 25.96, 'a': 27.50, 'a#': 29.14, 'b': 30.87 + } + + def __init__(self, ev3, rtttl: str): + """ + :param ev3: EV3Brick instance from pybricks.hubs + :param rtttl: RTTTL string (name:d=4,o=5,b=100:notes) + """ + self.ev3 = ev3 + self.name, self.defaults, self.notes = self.parse_rtttl(rtttl) + + def parse_rtttl(self, rtttl: str): + name, settings, notes = rtttl.split(':') + defaults = {} + for s in settings.split(','): + k, v = s.split('=') + defaults[k] = int(v) + notes = notes.split(',') + return name, defaults, notes + + def note_to_freq(self, note: str, octave: int): + """ + Convert note name + octave to frequency in Hz. + """ + base = self.NOTE_FREQS[note] + return round(base * (2 ** octave), 2) + + def play(self, tempo_scale: float = 1.0): + """ + Play the parsed RTTTL melody. + :param tempo_scale: Scale factor for speed (1.0 = normal, 2.0 = twice as fast, 0.5 = half speed) + """ + bpm = self.defaults.get('b', 63) + whole_note = (60 / bpm) * 4 * 1000 # ms + + for raw in self.notes: + match = re.match(r'(\d+)?([a-gp][#]?)(\d)?(\.*)?', raw.strip(), re.I) + if not match: + continue + + dur, note, octave, dot = match.groups() + dur = int(dur) if dur else self.defaults.get('d', 4) + octave = int(octave) if octave else self.defaults.get('o', 6) + + duration = (whole_note / dur) * tempo_scale + if dot: + duration *= 1.5 + + if note.lower() == 'p': # pause + self.ev3.speaker.beep(0, int(duration)) + else: + freq = self.note_to_freq(note.lower(), octave) + self.ev3.speaker.beep(int(freq), int(duration)) \ No newline at end of file