Friday, January 31, 2014

Got parts

Just received the missing parts for my grooveshark radio project: 16x2 LCD and rotary encoder from http://www.dx.com and USB soundcard with optical output from eBay. The fun starts now!!!


Thursday, January 23, 2014

Capacitance measurement with the Arduino Uno

I guess this opens up a new section... "how did THEY do that?"
Now this is a cool use of arduino for those of us doing also analog stuff:

http://wordpress.codewrite.co.uk/pic/2014/01/21/cap-meter-with-arduino-uno/

The cap meter in my multimeter kind of sucks, so I will definatelly try this.

Friday, January 17, 2014

Using REST for communication between AVR and Linux

I changed my code on my previous post to use REST as a way to communicate between Arduino and Linux. REST is basically a web server running on the linux side which allows access to key/value pairs via web or through serial from Arduino. In particular I am using this now for sending the info about the song that is playing. From my python script I am calling curl to POST the info to the REST website and from Arduino I am doing Bridge.get calls to receive the data.

Here is the new python script:


from __future__ import print_function
import urllib
import urllib2
import subprocess
import sys

from grooveshark import Client
from grooveshark.classes import Radio

client = Client()
client.init()
cmdargs = str(sys.argv)

url_name='http://localhost/data/put/songName/'
url_artist='http://localhost/data/put/songArtist/'
url_album='http://localhost/data/put/songAlbum/'

for song in client.radio(sys.argv[1]):
    
    song_name = unicode(song.name).encode("utf-8")
    song_artist_name = unicode(song.artist.name).encode("utf-8")
    song_album_name = unicode(song.album.name).encode("utf-8")


    print(song_name)
    print(song_artist_name)
    print(song_album_name)

    url_name_curl = url_name + urllib.quote(song_name)
    urllib2.urlopen(url_name_curl)
    url_artist_curl = url_artist + urllib.quote(song_artist_name)
    urllib2.urlopen(url_artist_curl)
    url_album_curl = url_album + urllib.quote(song_album_name)
    urllib2.urlopen(url_album_curl)

    sys.stdout.flush()
    subprocess.call(['mpg123', song.stream.url])


UPDATE:
There is a pycurl library that I could have used instead (and there seem to be other alternatives, I am just not a python expert), but this seemed quicker to implement at the time. Will find an alternative... 
I am using urllib2 to do the POST requests to the REST website. Originally I was using curl (running it in a subprocess) but urllib2 avoids calling a separate process.
Important thing is to remember calling urllib.quote on the text to POST, as you will need to convert special characters to "%XX" to make it a valid URL.

On the Arduino side I am only getting the song name, but it is enough to get the idea of how this is done. This is how my sketch looks like now:


#include <FileIO.h>

#define    GENRE_NONE             0
#define    GENRE_ROCK             12
#define    GENRE_BLUES            230
#define    GENRE_ELECTRONICA      67
#define    GENRE_CLASSICROCK      3529
#define    GENRE_INDIE            136
#define    GENRE_METAL            17


int stations[] = { GENRE_NONE,
    GENRE_ROCK,
    GENRE_BLUES,
    GENRE_ELECTRONICA,
    GENRE_CLASSICROCK,
    GENRE_INDIE,
    GENRE_METAL };

int genres;
int val = 0;
int prevVal = 0;
Process radio_process;
String label;

void setup() {
  genres = sizeof(stations)/sizeof(int);
  Bridge.begin();
  Serial.begin(9600);

  while(!Serial);  // wait for Serial port to connect.
  Serial.println("Grooveshark Radio example");

  start_radio(val);  
}

void loop() {
  val = analogRead(3);
  val = (val*genres)/1023;

  
  if(val != prevVal) {
    String text;
    text = "Value: ";
    text += val;
    Serial.println(text);

    start_radio(val);
    
    prevVal = val;
  }
// removed old code to print the output of the script: 
/*
  while(radio_process.available() > 0){
    char c = radio_process.read();
    Serial.print(c);
  }
*/
  char labelbuffer[256];
  Bridge.get("songName", labelbuffer, 256); 

  if (String(labelbuffer).length() > 0 && label != String(labelbuffer)){
    label = String(labelbuffer);
    
    Serial.println(label);

  }
  
  
  delay(400);
}

void start_radio(int val) {
    String parameter = "";
    radio_process.close();
    Process killer;
    killer.begin("killall");
    killer.addParameter("mpg123");
    killer.run();
    if(stations[val] != 0) {
      radio_process.begin("python");
      radio_process.addParameter("/root/examples-pygrooveshark/radio_mpg123.py");
      parameter+= stations[val];
      radio_process.addParameter(parameter);
      radio_process.runAsynchronously();
    }
    else {
      radio_process.begin("echo");
      radio_process.addParameter("Do Nothing!!!");
      radio_process.runAsynchronously();
    }
}

Wednesday, January 15, 2014

Arduino Yun Grooveshark Radio


I got an Arduino Yun as Christmas preset this year. After a few days playing around with it, I decided that I wanted to turn it into an internet audio playback device. I found there is a cool python library to access Grooveshark, which is even cooler than traditional internet radios... I will explain here the steps to get it to work. I assume basic Linux and programming knowledge in my explanation.

The first step was to get USB audio working as per the explanations in here... easy...

Next step was to get some audio player running on the Linux side which would play an mp3 from a URL (rather than from file as madplay). I checked on the available packages and there was no mplayer, no vlc, no mpg123... crap... so I checked on how to compile my own packages. The first step was to compile linino image and packages:

git clone https://github.com/arduino/linino.git
cd linino/trunk
./scripts/feeds uninstall -a  
rm -rf feeds
./scripts/feeds update -a
./scripts/feeds install -a
rm -f .config
git checkout .config
make oldconfig
make V=s

During this process I found some compile issues, in fact I did not get to build all the packages, but seems like it was enough to later build mpg123.

In order to build the mpg123 package, I got the makefile from here, copied it inside my linino tree in linino/trunk/package/feeds/packages/mpg123/ and then did:

make package/mpg123/compile V=s

Somehow that did not create a .ipk file to install in the yun, as I was expecting, but everything from the ipk package that should have been created was available in linino/trunk/build_dir/target-mips_r2_uClibc-0.9.33.2/mpg123-1.13.2/ipkg-install/, so I just had to copy that folder into a pen drive and from there into the yun filesystem.

When I tried to run mpg123 I faced another issue, libltdl shared library was missing. Seems like that library was built during the linino image compilation here: linino/trunk/staging_dir/target-mips_r2_uClibc-0.9.33.2/usr/lib/libltdl.so.7.3.0. As with mpg123 before, I copied it into a pen drive and into the filesystem of the yun. Et voila... mpg123 was working.

Unfortunately, sound quality alternated between OK and very bad (with stuttering sound). In  order to fix this, I created the file /etc/asound.conf with the following contents:

pcm.dmixer {
    type dmix
    ipc_key 1024
    ipc_key_add_uid false
    ipc_perm 0666
    slave {
        pcm "hw:0,0"
        ### WARNING: do NOT add period_time, period_size or buffer_size here!!! ###
        rate 44100
    }
    bindings {
        0 0
        1 1
    }
}

pcm.dsp0 {
    type plug
    slave.pcm "dmixer"
}

pcm.!default {
    type plug
    slave.pcm "dmixer"
}

pcm.default {
   type plug
   slave.pcm "dmixer"
}

ctl.mixer0 {
    type hw
    card 0
}

This came from here. That seemed to fix the issues.

OK, so we now have mpg123 working, yuhuuu... next step was pygrooveshark. I downloaded it from here, put it into a pendrive and did:

python setup.py install

Based on the pygrooveshark radio example, I made this python script in /root/examples-pygrooveshark/radio_mpg123.py which takes a number representing the radio genre as parameter (17 is for METAL, if you want to try it from the command line):

from __future__ import print_function

import subprocess
import sys

from grooveshark import Client
from grooveshark.classes import Radio

client = Client()
client.init()
cmdargs = str(sys.argv)

for song in client.radio(sys.argv[1]):
    print(song.name)
    print(song.artist.name)
    print(song.album.name)
    sys.stdout.flush()
    subprocess.call(['mpg123', song.stream.url])

Tried running it but found another issue. Do not remember the exact error, but basically python on the yun was built without SSL support. The solution was to copy the file linino/trunk/staging_dir/target-mips_r2_uClibc-0.9.33.2/root-ar71xx/usr/lib/python2.7/lib-dynload/_ssl.so in /usr/lib/python2.7/lib-dynload/_ssl.so in the yun filesystem. Once that was done, I was able to run pygrooveshark scripts from the yun linux terminal.

Last step was to get some way of launching the different radio genres from the arduino/AVR side. Here is the hardware setup:



And here the sketch running on the AVR side:


#include <FileIO.h>

#define    GENRE_NONE             0
#define    GENRE_ROCK             12
#define    GENRE_BLUES            230
#define    GENRE_ELECTRONICA      67
#define    GENRE_CLASSICROCK      3529
#define    GENRE_INDIE            136
#define    GENRE_METAL            17


int stations[] = { GENRE_NONE,
    GENRE_ROCK,
    GENRE_BLUES,
    GENRE_ELECTRONICA,
    GENRE_CLASSICROCK,
    GENRE_INDIE,
    GENRE_METAL };

int genres;
int val = 0;
int prevVal = 0;
Process radio_process;

void setup() {
  genres = sizeof(stations)/sizeof(int);
  Bridge.begin();
  Serial.begin(9600);

  while(!Serial);  // wait for Serial port to connect.
  Serial.println("Grooveshark Radio example");

  start_radio(val);  
}

void loop() {
  val = analogRead(3);
  val = (val*genres)/1023;

  
  if(val != prevVal) {
    String text;
    text = "Value: ";
    text += val;
    Serial.println(text);

    start_radio(val);
    
    prevVal = val;
  } 

  while(radio_process.available() > 0){
    char c = radio_process.read();
    Serial.print(c);
  }
  delay(400);
}

void start_radio(int val) {
    String parameter = "";
    radio_process.close();
    Process killer;
    killer.begin("killall");
    killer.addParameter("mpg123");
    killer.run();
    if(stations[val] != 0) {
      radio_process.begin("python");
      radio_process.addParameter("/root/examples-pygrooveshark/radio_mpg123.py");
      parameter+= stations[val];
      radio_process.addParameter(parameter);
      radio_process.runAsynchronously();
    }
    else {
      radio_process.begin("echo");
      radio_process.addParameter("Do Nothing!!!");
      radio_process.runAsynchronously();
    }
}

I can change grooveshark radios by moving the potentiometer.

What is next? I have ordered an LCD screen and a rotary encoder for user interface. My plan is to allow playback of grooveshark user favourites and playlists, but that requires a lot more changes in both the AVR and Linux.

Sunday, January 12, 2014

Introduction

Hello...
Here is an embedded software engineer who also enjoys hardware stuf... This blog is a way for me to remember how I did my DIY projects. Hopefully somebody will also find this tricks and tips useful.