I'm by no means a developer. I find a great deal of enjoyment in 'tinkering' with different programming languages and I prefer to learn as a go. To me it's like visiting a new country and trying to learn the language on the fly rather than in a book. While there's a certain appeal to that approach it can have some downfalls such as inefficient code.
My first python scripts were functional, but UGLY so I've taken the time to rewrite them but realize there's still a ways to go. The goal is overall stability and performance.
There are two pieces of code that do all of the heavy lifting; the python script on the raspi's side and the arduino sketch.
- This is script is responsible for the following:
- Receive commands from the ultrasonic sensor via the arduino's serial interface
- Control the MPD interface
- Set system volume
- Retrieve/Send MPD information to the LCD via the arduino's serial interface
- Monitor time and act as an alarm clock
- Send Alarm Clock notification to the LCD/LED via the arduino's serial interface
import serial import mpd import subprocess import alsaaudio import os ser = serial.Serial('/dev/ttyS0', 9600) # Change /dev/* value to match your arduino serial interface device ser.timeout=.05 # Timeout reduces CPU usage mixer = alsaaudio.Mixer('PCM', 0) # Which audio mixer to control changecheck=" " # variable that 'watches' to see if the song has changed counter=0 # variable used to delay the time to redisplay the Artist/Song after changing volume client = mpd.MPDClient() client.connect("localhost", "6600") def translate(value, leftMin, leftMax, rightMin, rightMax): # Used to translate the value of volume to a 0-100 range for accurate display # Figure out how 'wide' each range is leftSpan = leftMax - leftMin rightSpan = rightMax - rightMin # Convert the left range into a 0-1 range (float) valueScaled = float(value - leftMin) / float(leftSpan) # Convert the 0-1 range into a value in the right range. return rightMin + (valueScaled * rightSpan) while True: snafu=ser.readline().decode('utf-8','ignore')[:-2] #Read serial input SongInfo=client.currentsong() #Pulls information from MPD artist=SongInfo['artist'] #Artist info song=SongInfo['title'] #Song info if len(song) > 16: #Chops artist length to LCD width (16 characters) choppedsong = song[0:15] else: choppedsong = song[0:(len(song))] if len(artist) > 16: #Chops artist length to LCD width (16 characters) choppedartist = artist[0:15] else: choppedartist = artist[0:(len(artist))] if counter==20: #Amount of time to redisplay the Artist/Song after volume change changecheck='' counter=counter+1 if counter>=21: counter=21 if changecheck != choppedsong: #If counter met or song changed write to LCD ser.write(choppedsong) ser.write('@') ser.write(choppedartist) ser.write('@') print choppedsong print choppedartist changecheck=choppedsong if snafu == 'Pause': #Read serial input for Pause, Next, or Volume client.pause(1) print(snafu) ser.write(' Paused') #Print to LCD ser.write('@') #'@' symbol tells the arduino to move to the next row on the LCD counter=21; elif snafu == 'Next': client.next() print(snafu) elif snafu.isdigit(): client.play() mixer.setvolume(int(snafu)) #Read serial input and set volume counter=0 ser.write('Vol: ') vol=str(int(translate(int(snafu),70,100,0,100))) print(vol) ser.write(vol) ser.write('@') #print(snafu)
This is the code to be uploaded to the arduino or arduino clone and is responsible for the following:
- Convert ultrasonic sensor distance reading into cm
- Adjust the brightness of the LED
- Transmit sensor data to raspi via serial interface
- Turn LCD backlight on/off
- Receive 'now playing' information from raspi to be displayed on the LCD
#include <SoftwareSerial.h> #include <LiquidCrystal.h> LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //pins for lcd int lcd_key = 0; //work in progress int adc_key_in = 0; //work in progress #define btnRIGHT 0 //work in progress #define btnUP 1 //work in progress #define btnDOWN 2 //work in progress #define btnLEFT 3 //work in progress #define btnSELECT 4 //work in progress #define btnNONE 5 //work in progress const int pingPinT = A4; //Ultrasonic Trigger Pin //const int pingPinR = A3; //Ultrasonic Echo Pin const int pingPinR = A4; //Ultrasonic Echo Pin const int ledPin = 3; //Fading LED pin const int ceiling = 80; //Highest point of detection (cm) const int volumemin = 10; //Lowest volume distance (cm) before pause const int volumemax = 45; //Highest volume distance (cm) before 'dead zone' const int nexttrack = 70; //Height until next track triggered (cm) int cm; // Distance variable int new_cm=54; //Second distance variable to determine if there's been a change since last loop int fadevalue; // LED brightness based on ultrasonic distance char buffer; //Serial buffer int old_cm; // WORK IN PROGRESS int read_LCD_buttons() { adc_key_in = analogRead(0); // read the value from the sensor // my buttons when read are centered at these valies: 0, 144, 329, 504, 741 // we add approx 50 to those values and check to see if we are close if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result if (adc_key_in < 50) return btnRIGHT; if (adc_key_in < 195) return btnUP; if (adc_key_in < 380) return btnDOWN; if (adc_key_in < 555) return btnLEFT; if (adc_key_in < 790) return btnSELECT; return btnNONE; // when all others fail, return this... } void setup() { delay(5000); lcd.begin(16,2); lcd.setCursor(0,0); lcd.print("All Your Base"); lcd.setCursor(0,1); lcd.print("are belong to us"); lcd.setCursor(0,0); // initialize serial communication: Serial.begin(9600); Serial.flush(); digitalWrite(10, LOW); } void loop() { // --------------PRINT TO LCD FROM SERIAL INPUT------------------- int count = Serial.available(); if (Serial.available()) { // wait a bit for the entire message to arrive lcd.clear(); delay(100); lcd.setCursor(0,0); while (Serial.available() > 0) { // display each character to the LCD buffer=Serial.read(); if(buffer=='@'){ //TRIGGER VALUE TO BREAK TO NEXT LCD ROW lcd.setCursor(0,1); } else if(buffer=='%'){ //ALARM CLOCK TRIGGER (WORK IN PROGRESS) new_cm=volumemax; //SET EVERYTHING TO HIGHEST (WORK IN PROGRESS) } else { lcd.print(buffer); //DISPLAY SERIAL DATA TO LCD } } } // --------------READ BUTTON------------------- // WORK IN PROGRESS lcd_key = read_LCD_buttons(); // read the buttons switch (lcd_key) // depending on which button was pushed, we perform an action { case btnRIGHT: { break; } case btnLEFT: { Serial.println("Love"); delay(500); break; } case btnUP: { break; } case btnDOWN: { break; } case btnSELECT: { Serial.println("Change"); delay(500); break; } case btnNONE: { break; } } // --------------GET DISTANCE FROM ULTRASONIC SENSOR------------------- long duration; pinMode(pingPinT, OUTPUT); digitalWrite(pingPinT, LOW); delayMicroseconds(2); digitalWrite(pingPinT, HIGH); delayMicroseconds(5); digitalWrite(pingPinT, LOW); pinMode(pingPinR, INPUT); duration = pulseIn(pingPinR, HIGH); // convert the time into a distance cm = microsecondsToCentimeters(duration); // --------------SET CEILING------------------- if (cm>ceiling){ cm=new_cm; } // --------------SET/FADE LED------------------- if (cm<nexttrack) { if ((cm<volumemin) &&(cm>0)){ analogWrite(ledPin, 0); //TURN LED OFF WHEN PAUSED cm=volumemin-1; } if ((cm>=volumemax)&&(cm<nexttrack)){ analogWrite(ledPin, 255); //TURN LCD TO BRIGHTEST AT MAX VOLUME pinMode(10, INPUT); digitalWrite(10, LOW); cm=volumemax; } if ((cm<volumemax)&&(cm>volumemin)){ fadevalue = map(cm , volumemin, volumemax, 0, 125); //TRANSLATES MIN/MAX VOLUME INTO LED BRIGHTNESS VALUES analogWrite(ledPin, fadevalue); //FADE LED ACCORDING TO VOLUME LEVEL } } else { analogWrite(ledPin, 0); cm=nexttrack; } // --------------SEND COMMANDS TO PI------------------- if (new_cm!=cm) { if ((cm < volumemin) && (cm>0)) { Serial.println("Pause"); //SEND PAUSE TO RASPI pinMode(10, OUTPUT); //TURN OFF LCD BACKLIGHT } if ((cm < volumemax) && (cm>=volumemin)) { Serial.println(map(cm, volumemin, volumemax, 70, 100)); //TRANSLATE MIN/MAX VOLUME TO ALSA VOLUME LEVELS AND SEND TO RASPI old_cm=cm; pinMode(10, INPUT); //TURN ON LCD BACKLIGHT digitalWrite(10, LOW); //TURN ON LCD BACKLIGHT } if ((cm >=volumemax) && (cm<nexttrack)) { //mySerial.write(17); // Turn backlight on Serial.println(100); //SEND MAX VOLUME TO RASPI pinMode(10, INPUT); //TURN ON LCD BACKLIGHT digitalWrite(10, LOW); //TURN ON LCD BACKLIGHT } if (cm >=nexttrack) { Serial.println("Next"); //SEND NEXT COMMAND TO RASPI delay(250); //BLINK LED AT MAX BRIGHTNESS analogWrite(ledPin, 255); delay(250); analogWrite(ledPin, 0); delay(250); analogWrite(ledPin, 255); delay(250); analogWrite(ledPin, 0); cm=old_cm; } } new_cm=cm; delay(50); // Short Delay allows for smoother fading } //End Loop //-------------Functions-------------------------------// long microsecondsToCentimeters(long microseconds) { // The speed of sound is 340 m/s or 29 microseconds per centimeter. // The ping travels out and back, so to find the distance of the // object we take half of the distance travelled. return microseconds / 29 / 2; } //------------End-Functions-------------------------------//
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.