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.