Skip navigation
2014

I finally found time to play with my Rapiro - Programmable DIY Robot Kit robot (thanks again Element14 for accepting me for this RoadTest!).

You can have a look at the review I wrote, but in a nutshell, after having figured out a few hardware issues, I was essentially ready to start hacking and code what I had in mind: I wanted my Rapiro to become an IoT (Internet of Things) device, that I could control for virtually anywhere in the world!

 

 

The project

190.JPG

Meet Rapiro. Rapiro is a nice little toy, that comes in a kit. It is, as you've guessed, a robot!

  • The robot itself consists of 12 servos (3 in each arm, 2 in each leg, 1 for the head and 1 for the waist), enabling a wide range of movements. Not-so-wide movements actually, the robots' limb are very short!
  • A Raspberry Pi, in the head of the robot, allows
  • A PiCam, a 5Mpix camera extension to the Raspberry Pi, allows to take pictures, records videos, ...
  • A USB WiFi dongle allows to control the robot completely wirelessly

 

I won't detail how to assemble the Rapiro, neither will I explain how to get your Raspberry Pi setup with a Linux distro since there are plenty of resources on the Internet. The fun part actually starts after you have finished assembling the Rapiro, and when the Raspberry Pi is properly running, allowing you to open a remote SSH connection to start hacking the beast!

 

The goal is very simple: my Rapiro is able to get Internet connectivity, thanks to its Raspberry Pi and WiFi dongle, so I want to make it controllable remotely. To that effect, I am going to use MQTT, a very lightweight protocol well-suited for Internet of Things communications, to send commands to the robot. Thanks to the PiCam, the robot should also, when asked to do so, take a picture and transmit it. I want to be able to open a browser from wherever in the world, and start controlling my Rapiro (because why not, eh? ), so I will develop a simple web UI to send the actual MQTT commands.

Steps

 

Install Eclipse Orion

Eclipse Orion is an IDE that you can run from your favorite web browser. Once you have Orion running on a device (here it's going to be on the Raspberry Pi attached to my Rapiro, obviously), all you really need is a browser for writing.

We are going to run Orion on top of Node.js so we are going to need Node.js first.

cd
wget http://nodejs.org/dist/v0.10.26/node-v0.10.26-linux-arm-pi.tar.gz
tar -xvzf node-v0.10.26-linux-arm-pi.tar.gz
sudo mv node-v0.10.26-linux-arm-pi /opt/node/
















 

In order to have the node and npm executables in your PATH, you can edit the /etc/profile file and add the following lines:

NODE_JS_HOME=/opt/node"
PATH="$PATH:$NODE_JS_HOME/bin"
export PATH
















 

Great! Node is now correctly installed, and we can use the standard package manager (npm) to install and start Orion.

npm install orion
npm start orion
















 

You should see an output similar to this:

> orion@0.0.30 start /home/pi/node_modules/orion
> node server.js

Using workspace: /home/pi/node_modules/orion/.workspace
Listening on port 8081...
















 

And if you open your favorite web browser (http://ip-address-of-your-raspberrypi:8081), you'll see that Orion is actually running – congrats!

Capture+d’écran+2014-04-28+à+19.04.53.png

So what's next? Orion is going to help us develop a very simple application that will expose Rapiro's Arduino-based controller, to the Internet.

Allow the Rapiro to be controlled from anywhere with MQTT

Rapiro built-in serial commands

By default, the Rapiro is meant to be controlled over a serial connection. Basically, the servo-motors are all attached to an Arduino board, onto which runs a program that listens to commands on the serial interface. These commands can be either built-in, like #M1 to start walking or #M5 to wave hands, or more complex sequences, like #PR000G255B000T010 to set the eyes LEDs to Green (R=0, G=255, B=0), in 10 units of time (T=10).

 

The Rapiro's head is home for its second brain, in addition to the Arduino controller:  a RaspberryPi. It is powered by the same battery pack than the robot, and connected to the Arduino's serial line meaning that I can actually send serial commands from virtually any program that I'd run on the Raspberry Pi. As a very first test, you can ask the Rapiro to start walking from the command line of your Raspberry Pi:

echo "#M1" | sudo minicom -b 57600 -o -D /dev/ttyAMA0








 

So now the goal is to use Orion to write a simple app that will use MQTT to listen to commands that a web UI is going to send, and forward these commands to the Arduino controller over the serial port.

In Orion, we're going to create a new project (File > New > Project > Basic).

Capture d’écran 2014-04-30 à 11.19.21.png

 

And in this project is going to be our main application, so let's create a file called e.g. main.js.

Capture d’écran 2014-04-30 à 11.20.11.png

 

 /*******************************************************************************
* Copyright (c) 2013, 2014 Benjamin Cabé and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Benjamin Cabé - initial API and implementation
*******************************************************************************/


/** Serial port configuration **/
var serialport = require("serialport");
var SerialPort = serialport.SerialPort; // localize object constructor
var sp = new SerialPort("/dev/ttyAMA0", {
    baudrate: 57600,
    parser: serialport.parsers.readline("\n")
});

/** MQTT client configuration **/
var mqtt = require('mqtt');

var mqttClient = mqtt.createClient(1883, 'iot.eclipse.org');
mqttClient.subscribe('benjamin/rapiro/command');

sp.on("open", function() {
    console.log('serial port opened');
});

function publishPicture(error, stdout, stderr) {
  console.log("... sending the picture")
  mqttClient.publish('benjamin/rapiro/pic', stdout);
  console.log("... picture sent!")
}

var sys = require('sys')
var exec = require('child_process').exec;

var cmd = function(topic, message) {
  if(message === "TAKE_PICTURE") {
    console.log("Taking a picture!")
    exec("raspistill -w 320 -h 240 -hf -vf -t 1 -o - | base64", publishPicture);
  } else {
    console.log("Asking Rapiro to execute command: " + message)
    sp.write(message + '\n');
  }
};

mqttClient.on('message', cmd);












 

Yes, it's that simple! Not even 50 lines of Javascript code, cool eh?

Basically, we're using two NodeJS modules: serialport for manipulating the serial port of the Raspberry Pi to which the Arduino controller is attached, and mqtt for doing... MQTT communications!

The code is pretty straight forward:

  • lines 14-19: we setup the serialport module, indicating the name of the serial port, its baudrate, ...
  • lines 22-25: we setup the MQTT client: we want to communicate with the MQTT broker available at iot.eclipse.org, and we subscribe to the topic where we are accepting to receive commands targeted at the controller
  • lines 40-50: on line 50 we indicate the Javascript callback for when a new MQTT message is receive.
    In the callback, if the message we received has a "TAKE_PICTURE" payload, we're using raspistill to take a picture and output the binary JPEG encoded in base64 on stdout. publishPicture callback then takes this output, and publishes it in an MQTT message (see Lines 31-35).
    If the payload is something else than "TAKE_PICTURE", we just use the serialport module to write this on the serial port, assuming it's a serial command – hopefuly it's something Rapiro can understand!

Use Orion shell to run the app

Now that we have written our MQTT-to-serial bridging application, it's time to use the Orion shell to actually launch it.

Capture d’écran 2014-04-30 à 11.25.43.png

 

Web UI

Capture d’écran 2014-04-29 à 18.59.31.png

Here the idea is pretty straightforward. I want a dead simple web UI that will allow me to publish MQTT messages, and receive base64-encoded images that I can display in my page.

In order to perform MQTT communications from a web page, there in Eclipse Paho, a Javascript client that allows to do MQTT over WebSockets.

Without further ado, here is the actual web UI for my page:

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-md-3">
      <p><a class="btn btn-default btn-lg btn-block" href="#" role="button" onclick='message = new Messaging.Message("#M0"); message.destinationName = "benjamin/rapiro/command"; client.send(message); '>STOP!</a></p>
    </div>
    <div class="col-xs-12 col-md-3">
      <p><a class="btn btn-default btn-lg btn-block" href="#" role="button" onclick='message = new Messaging.Message("#M5"); message.destinationName = "benjamin/rapiro/command"; client.send(message); '>Wave hands</a></p>
    </div>
    <div class="col-xs-12 col-md-3">
      <p><a class="btn btn-default btn-lg btn-block" href="#" role="button" onclick='message = new Messaging.Message("#M1"); message.destinationName = "benjamin/rapiro/command"; client.send(message); '>Walk</a></p>
    </div>
    <div class="col-xs-12 col-md-3">
      <p><a class="btn btn-default btn-lg btn-block" href="#" role="button" onclick='message = new Messaging.Message("TAKE_PICTURE"); message.destinationName = "benjamin/rapiro/command"; client.send(message); '>Picture</a></p>
    </div>
    <div class="col-xs-12 col-md-12">
      <img class="img-responsive" id="cam" src=""/>
    </div>
  </div>
</div>











 

It's very simple: when a button is clicked, an MQTT message is published on the topic benjamin/rapiro/command (remember that this is what my Rapiro's Raspberry Pi is subscribed to, right?), with a payload that is what action I want the Rapiro to perform

And below is the few lines of Javascript that will initialize my MQTT client, and listen to the topic on which a base64 image may show up.

<script type="text/javascript" src="http://iot.eclipse.org/demo/js/mqttws31.js"></script>
<script>
  client = new Messaging.Client("ws://iot.eclipse.org/ws", "rapiroweb" + new Date().getTime());
  client.onConnectionLost = onConnectionLost;
  client.onMessageArrived = onMessageArrived;
  client.connect({
    onSuccess: onConnect
  });

  function onConnect() {
    // Once a connection has been made, make a subscription and send a message.
    console.log("onConnect");
    client.subscribe("benjamin/rapiro/pic");
  };

  function onConnectionLost(responseObject) {
    if (responseObject.errorCode !== 0) {
      console.log("onConnectionLost:" + responseObject.errorMessage);
      // TODO reconnect??
    }
  };

  function onMessageArrived(message) {
    console.log('Receiving an image')
    var img = $("#cam");
    img.attr('src', 'data:image/jpeg;base64,' + message.payloadString);
  };
</script>












 

When actually using the Web UI, granted that the NodeJS app is still running on the Raspberry Pi, the Rapiro will start doing what you're asking it too, and obviously you can use the Orion shell output to troubleshoot what's happening.

Capture d’écran 2014-04-30 à 11.26.44.png

See it live!

So this is it! Check out the video below to see all of this in action!

More...

Possible improvements

It took me a couple hours to put together this project (and actually more than a couple hours to write this blog post!), so there is definitely room for improvement.

  • Sending raw instructions (e.g. #M0) over MQTT is pretty convenient and very versatile, but the Node.js MQTT-to-serial bridge could be smarter, and instead of naively "forwarding" instructions received via MQTT to the Rapiro over serial, it could understand more advanced commands that would be transmitted as part of the MQTT topic. That way, an MQTT message received on the topic benjamin/rapiro/command/walk would be translated into an #M1 command being written on the serial link.
  • Sending webcam images over MQTT works great, but it might be more appropriate to actually expose a live MJPEG stream to the Internet

Source code

The source code for the Web UI is on Github https://github.com/kartben/rapiro-web-ui – it's very simple, but eh, feel free to improve it!

Upcoming webinar

If you would like to ask me questions about that particular project, or if you'd like to learn more about some other cool IoT projects that are part of the Eclipse IoT initiative, please join my webinar next week, on May 7 – From Arduinos to Raspberry Pis, IoT-ize Your Embedded Projects with Open IoT software!

Previous entries in this blog series:

 

 

 

Enclosure

 

The dimensions of the enclosure were based on some rough estimations, now I had to make everything fit inside.

I puzzled a bit, figuring out how I would expose the controls, camera and LCD.

The solution I came up with can be seen in the pictures below. It's a bit big, but fully functional.

I even printed some buttons, as the keypad pushbuttons were no longer accessible because of the enclosure.

 

DSCN3067.JPGDSCN3068.JPG

DSCN3072.JPGDSCN3073.JPG

BlphtqECYAArvlA.pngDSCN3081.JPG

DSCN3083.JPG

 

 

RF433 I2C Board

 

As mentioned in previous blog post, I made a prototype of an I2C RF433 transmitter using an ATtiny85.

With the prototype working, I designed a small PCB using Fritzing and had it made.

 

The result (prototype left, custom PCB right)

DSCN3087.JPG

 

A short video of the board being controlled by the Pi via I2C to turn a light on and off:

 

 

 

Power and other pins

 

I wanted to power every component involved in the most simple way possible, using a single power supply.

For that purpose I made use of the power provided to the Pi Rack and distributed it to the different components by means of jumper wires in case they weren't directly connected to the Pi Rack.

The Pi is also powered by the Pi Rack by providing the power via the GPIO pins. Not ideal, but it works and was simple to achieve: on one of the jumper selections for power, I shorted all three pins in order to have the external power supply reach the Pi 5V GPIO pin and have the module attached still powered also.

 

Screen Shot 2014-04-23 at 21.49.02.png

 

Because the Arduino and the Adafruit LCD/Keypad cannot be connected directly to the Pi Rack, I used jumper wires to connect the necessary pins:

  • Adafruit LCD/Keypad: Power and Ground + I2C pins
  • Arduino with GSM Shield: Power and Ground + Serial pins

 

photo.JPG

 

I'll have to find a better way to fasten the jumper wires though, as they tended to come loose easily.

 

 

Testing

 

With all components enclosed, some tests were required to verify all connections were still functioning properly.

 

Using the "sudo i2cdetect -y 1" command, I verified both I2C modules (Adafruit LCD/Keypad and custom pcb) were detected properly.

 

Screen Shot 2014-04-20 at 21.44.35.png

 

The camera was tested using the "raspistill -o test.jpg" command. The picture and its orientation were correct.

Motion also provides a live stream of the camera feed, which worked properly.

 

A quick test of the LCD/Keypad:

 

 

With the enclosure done and the components working, it was time for a "field" test ...

 

 

Demos

 

Because the wireless sensors could detect our little burglar even before she reached the living room (and because there was not much for you to see), we allowed her to start from within the living room.

 

The system would still detect her, but at least we'd have her reaction on film

 

 

also good.jpg

Thanks to the pictures and videos, the burglar was identified and apprehended

 

 

Improvements

 

There are still quite some improvements to be done before this project becomes more than a game to play with my daughter:

  • As Mark suggested in a previous post: the wireless sensors should include a mechanism to check in periodically in order to know the batteries are not dead
  • The control unit with camera and controls should have some backup power: if the burglars turns off the electricity, the system should keep working for a (little) while
  • The solution is very bulky, mainly because all components used were used as is. A custom PCB with the different elements required could be more compact (and cheaper).
  • ...

 

Still, this was a great learning experience on different types of communication between the modules, and on the modules themselves.

 

 

Code

 

I'll be posting the full code on GitHub and provide the link when available.

 

The code consists of following parts:

  • Arduino sketch for RF433 sensor reception and GSM shield using UNO
  • Arduino sketch for the RF433 I2C transmitter using ATtiny85
  • Raspberry Pi python scripts to drive the LCD with keypad, the Piface digital, the lights and the sending of SMS

Previous entries in this blog series:

 

 

Sensors

 

In part 2 of this project, I prototyped two types of wireless sensors to be used with the alarm system.

 

Using a prototyping PCB leftover, I moved the circuit from the breadboard, trying to keep it as small as possible.

I then continued by printing some custom enclosures for my different sensors. Below you can see an example for the motion detector sensor.

 

It contains:

  • PIR sensor
  • RF433 transmitter
  • battery holder
  • ATtiny85 circuit

photo 1.JPGphoto 2.JPGphoto 3.JPG

 

The PIR sensor and the RF433 transmitter are not soldered directly to the PCB, instead I used some female headers for the sensor and transmitter to plug into.

This way, the components are replaceable in case of failure, etc ...

 

Control Unit

 

I have used a lot of different, mostly off the shelf, components for my control unit.

 

Below is a simple block diagram of how the different components are interconnected:

pi_security (1).png

It might not be the most efficient way to interconnect everything, however, I find it interesting to play with and learn about these different interfaces.

 

Pi NoIR

 

The Pi NoIR is there for motion detection and recording of possible evidence. Using "motion", the camera can be used as a motion detector, triggering a recording of the event.

Instructions on setting up "motion" on the Raspberry Pi with a Pi Camera (or Pi NoIR) are described in detail on codeproject.com.

 

Using simple oneliners, it is possible to enable or disable recordings generated by the "motion" application:

 

# Recordings ON
sudo sed -i -e 's/output_pictures.*/output_pictures best/g' -e 's/ffmpeg_output_movies.*/ffmpeg_output_movies on/g' /etc/motion.conf 


# Recordings OFF
sudo sed -i -e 's/output_pictures.*/output_pictures off/g' -e 's/ffmpeg_output_movies.*/ffmpeg_output_movies off/g' /etc/motion.conf





 

Adafruit LCD and Keypad

 

I've already elaborated on the assembly and getting the LCD/keypad up and running in my previous post.

You can find it here: Pi Alarm System - Part 3: Control unit

 

PiFace Digital

 

On top of what was explained in Pi Alarm System - Part 3: Control unit , I have connected a 12V rotating light on one of the relays.

The relay is activated when the alarm is triggered, causing the light to turn on.

 

To spare my family's hearing, I have not connected any siren to the system, but this would be set up in the same way as the light was.

 

Arduino UNO with GSM Shield

 

I played with the Arduino GSM shield and had some success in adapting the sample sketches to send and receive SMS messages.

 

However, after another test, I forgot to put the correct PIN code in the new sketch and managed to get my SIM locked ...

I have contacted the phone company and I either have to pay 10EUR to unlock the SIM or order a free new one, with a new phone number.

Since I was using a test SIM anyway, I'll go for option two. It may take some time before I get the new SIM though ...

 

The GSM shield will come in handy to receive notifications from the alarm system, or even send specific commands via SMS.

Until I have a new SIM, this is unfortunately on hold.

 

Prototype board: ATtiny85 with RF433 Transmitter

 

This prototype covers the possibility of sending on/off commands to power sockets via an RF transmitter on 433Mhz.

This functionality could have been merged with the Arduino, but using the ATtiny85, it is possible to keep the solution generic and to use it in combination with anything else that supports I2C such as a Raspberry Pi, an Arduino, etc ...

 

photo 1.JPG

 

I used two libraries to cover the needed functionality:

 

  • RemoteSwitch provides a generic class for simulation of common RF remote controls, like the 'Klik aan Klik uit'-system, used to remotely switch lights etc: RemoteSwitch v2.0.0 on GitHub
  • The ATtiny85 does not have I2C (or SPI) "built in". Instead it has a Universal Serial Interface (USI) that can be used to facilitate I2C and SPI: I2C (master and slave) on the ATtiny85

 

Using those library, I programmed my ATtiny85 with the following code:

 

#include "TinyWireS.h"                  // wrapper class for I2C slave routines
#include "RemoteSwitch.h"

#define I2C_SLAVE_ADDR  0x26            // i2c slave address (38)
KaKuSwitch kaKuSwitch(1); // pin 1

void setup(){
  TinyWireS.begin(I2C_SLAVE_ADDR);      // init I2C Slave mode
}

void loop(){
  if (TinyWireS.available()){           // got I2C input
    char house = TinyWireS.receive();
    int unit = TinyWireS.receive();
    int on = TinyWireS.receive();

    onOff(house,unit,on);
  }
}

void onOff(char house, int unit, int on){
  kaKuSwitch.sendSignal(house,unit,on);
}










 

A small Python script on the Raspberry Pi is then used to send commands to the ATtiny85 which will then send the correct codes to the sockets:

 

import smbus
import sys

bus = smbus.SMBus(0)
address = 38

house = int(sys.argv[1])
unit = int(sys.argv[2])
on = int(sys.argv[3])

bus.write_byte(address, house)
bus.write_byte(address, unit)
bus.write_byte(address, on)










 

The script is called as follows to turn unit 1 with house code A (decimal 65) off and on:


# Turn OFF

sudo python i2c.py 65 1 0

# Turn ON
sudo python i2c.py 65 1 1










 

Using a cron job, the functions will be called with a variable delay, to have following example behaviour:

  • at 19:00 + [0-60] minutes turn the lights on
  • at 22:00 + [0-60] minutes turn the lights off

 

 

What's next ?

 

In my next and final post on this project, I will be covering the build (my project box arrived today!) and have my little assistant test the system!

 

photo 2.JPG photo+3+(1).JPG

I recently got hold of a Wolfson Audio card and did a bit of trial recording using the command line - see http://www.element14.com/community/community/raspberry-pi/raspberrypi_projects/blog/2014/04/06/wolfson-audio-project.

That all works fine - but what I want to be able to do is use use my Pi as a mini-recorder, which means operating on its won, away from a monitor/screen/internet connection, etc. I decided that, as I have a smart phone with a browser, if I could create a network connection between the Pi and my phone, I could wrote some php pages to control the audio card.

 

To do this I need to

  • Configure the Pi as a wireless Access point
  • Be able to connect from my phone to the Pi
  • Have some php pages to allow me to record and playback

 

Setting up a wireless access point

 

I found some instructions from Adafruit at here

which give detailed steps for configuring a wireless access point. I followed these to the letter - and it didn't work completely   - I could see the network that I had created from my phone, but i couldn't connect to it. I suggest you do this, and then follow the extra steps below. At some point I will take a clean install and repeat this process, so that I can come up with a definitive list of steps to follow !

 

When I looked at the board, I realised that there were conflicting services running as daemons in the linux installation, which I identified by  installing rcconf and viewing the logs at /var/logs/messages and /var/logs/syslog and looking at the messages on boot up.

So I ran rcconf and I removed isc-dhcp-server and installed udhcpd. (rcconf is a run level configuration tool - see https://packages.debian.org/wheezy/rcconf ).

 

(isc-dhcp-server has been reported to just have problems by others online.)

 

I configured /etc/udhcpd.conf appropriately (see sample file attached), then ran rcconf and disabled dnsmasq , and made sure udhcpd was enabled.

 

I also disabled the hotplug line in /etc/network/interfaces and made sure all necessary options were there (see sample file attached). this final configuration proved a bit tricky - everything worked fine until I unplugged the pi from the network. I had had it connected so I could access it 'headless' via putty. I ended up with the following values in interfaces (comments in bold have been added for clarity - do not copy/paste this text but see sample attached !).

 

auto lo
iface lo inet loopback


Set a static IP address for the lan connection as we are not going to be connected to a network. This will stop the Pi trying to find a DHCP server

auto eth0
iface eth0 inet static
address 192.168.1.81
netmask 255.255.255.0

 

Set a static address for the wireless connection - this will be the IP address that we use on our phone

auto wlan0
#allow hotplug wlan0
iface wlan0 inet static
address 192.168.42.1
netmask 255.255.255.0
network 192.168.42.0
broadcast 192.168.42.255
gateway 192.168.42.1

 

 

Accessing from my phone

With the pi booted up, I can see the network, as shown below. When I click on the network it opens, I'm prompted for the password, and then the phone connects.

 

  IMG_1466.PNGIMG_1467.PNG

 

 

Ive written some PHP pages to control the Wolfson card, which I will go into m,roe detail about in a separate blog. These allow me to set the input gain and volume, and the playback volume, and to start/tops recording and playback. I also added some options to enable me to shutdown and reboot the Pi as its not going to have a keyboard attached!

 

This is what it looks like - this is very much a first go, and Im planning to make it look a bit less clunky. This isn;t a phone app !! - its a web page that I have loaded from the Pi - see the URL at the top of the page, which is the static IP of the Pi that I assigned in the etc/network/interfaces file

 

IMG_1468.PNG

 

 

Controlling  with a php script

 

The following is an explaination of how i have implemented one of the functions - i.e. start recording' It covers the main points of the application.

 

One of the things I want to do is to start a recording by pressing a button on the phone. To do that I want to do the following

 

  • Fire off a background job to start recording to a file
  • Change the page to show that the recording is running

 

 

I have written a shell script to run the recording, which takes a couple of parameters for gain and volume. I call a script to set the gain and recording volume on the card then use the arecord function to record to a date stamped file.

 

# Set up the card
/var/www/recording/use_case_scripts/Record_from_DMIC.sh $1 $2

# record to file - create one that is datestamped
OUTPUT_FILE="/var/www/recording/music/record_`date +%Y%m%d_%H_%M_%S`.wav";
arecord -Dhw:0 -r 44100 -c 2 -f S32_LE $OUTPUT_FILE

 

Within the php page, when I clock the 'record button, this executes some java script to change the display (i.e. put out a /'recording' message') and then calls a separate php page to call the above script. This php contains the following code to do that

 

/* Get the gain and level parameters, passed through in the request */
$gain = $_GET["gain"];
$inputLevel = $_GET["inputLevel"];
$playbackLevel = $_GET["playbackLevel"];

/* Spawn the recording job - the statement '  > /dev/null &' causes it to run in the background */
exec("sudo /var/www/recording/pe_record.sh $gain $inputLevel  > /dev/null &");

/* return to the main page - returning the current values paramrters so those don't get lost */
header( 'Location: recordingcontrol.php?gain=' . $gain . '&playbackLevel=' . $playbackLevel. '&inputLevel=' . $inputLevel.'&recordingStarted=true') ;

 

Permissions Considerations (use sudo visudo)

The web pages and their functions run under the default apache user www-data. this user must therefore be given sudo access to some functions. This is done by editing the sudo users file - e.g. use command sudo visudo. You will need to make changes as follows (this is required in order to execute the record shell script, as mentioned above).

 

www-data ALL=/var/www/recording/pe_record.sh
www-data ALL=NOPASSWD: /var/www/recording/pe_record.sh

This article assumes that you have already successfully installed your Wolfson audio card - if you haven't done that yet, there is an excellent blog by cstanton  at http://www.element14.com/community/community/raspberry-pi/raspberry-pi-accessories/wolfson_pi/blog/2014/03/14/can-you-hear-the-wolfson-calling-setting-up-and-using-the-wolfson-audio-card

 

Once you have your card set up you will want to start recording with it. Like may people, I run my card 'headless' via a Putty shell, and therefore I don't have a screen attached to control recording or playback. therefore i want to be able to record and playback straight from the card - i.e. without using players like Audacity. My eventual aim is to have a recorder controlled from my phone, but as a starting point I want to be able to at least record and playback with a minimum of effort.

 

This post explains how to make a recording and play it back, and how the recording parameters can be amended. Its only a basic guide but should help get you started - and there is an attached tar which contains an example of working record and playback scripts.

 

amixer recording control

The distribution comes with the amixer function, which is a bit like a command line mixing desk. There is some documentation available at http://www.linuxcommand.org/man_pages/amixer1.html and I used this to experiment with recording settings.

 

When recording sound there are two main settings to worry about - the 'gain' control which affects how much signal comes into the device, and the 'level' control which determines how much of that signal gets recorded. The gain should be set so that you get a clear signal - to much and it will be distorted, too little and there will be a lot of hiss and noise. Once the signal level is correct you then use the level control to decide how loud you want the recording to be. This second option really has more relevance with multi-channel recording - for instance if you want one source quieter than another.

 

The distribution comes packaged with some scripts in the use-cases directory - these allow you to set up the control for different types of record/playback. In my case I want to record in the onboard mics, and then pay back through the headphone jack.

 

 

Displaying current values and control parameters

 

Current values for a device can be be obtained by using the command amixer cget name='xxxxxxx', where xxxxxx is the name of the control.

For example, to get the current input gain settings use amixer cget name='IN2L Digital Volume' which returns the following :

 

recording1.png

From this we can see the current value (i.e. 128) and also the settings for this control - i.e.

  • Minimum value -64.0 dB
  • Increment value 0.50 dB
  • Max value 191 (which works out at around 31.5dB - i.e. -64 + (191/2)

 

So with a current value of 128, the input gain is set to (-64 + 128/2) - i.e. 0dB.

 

Setting Control Values

Control levels are set using command amixer -Dhw:0 cset name='xxxxxxx' nnn where

 

  • xxxxxxx is the name of the control
  • nnn is the value to assign

 

I.e. to set the input gain for the left hand onboard mic to 3dB us

 

amixer -Dhw:0 cset name='IN2L Digital Volume' 130

 

(NB value of 128 is 0dB for this control as explained above).

 

Gain Control

The gain for the on board mics is set using devices IN2L  and IN2R (i.e. for left and right).

The control name for the onboard mic gain is IN2L Digital Volume (for the left channel) and IN2R Digital Volume

 

Using command amixer cget name='IN2L Digital Volume' to get the current gain

 

Input Volume

The recording input level is set using devices AIF1TX1 Input 1 Volume and AIF1TX2 Input 1 Volume (i.e. for left and right).

The recording device has to be assigned to each control and then he level set.

 

E.g. to set up the left hand onboard mic (IN2L)

amixer -Dhw:0 cset name='AIF1TX2 Input 1' IN2L
amixer -Dhw:0 cset name='AIF1TX2 Input 1 Volume' 32



 

 

Preparing to record

Before a recording is made the appropriate commands must be set up to enable the correct devices and set the levels. The following example prepares for recording using the onboard mics, with input gain set at 5db, and the input volume at 8dB.

 

#!/bin/bash
#Record from onboard DMICs

# Gain Control
# 128 = 0db, increments in steps of 0.5db (starting from -64db)
# Max = 191 (i.e. +32db)
# (to see current setting, and documentation of values, use command "amixer cget name='IN2L Digital Volume'" )
#
amixer -Dhw:0 cset name='IN2L Digital Volume' 138
amixer -Dhw:0 cset name='IN2R Digital Volume' 138

#
# Input level : 32 = 0db, increments in steps of 1.0db, starting at -32db
# Max setting = 48 (=16Db)
# (to see current setting, and documentation of values, use command "amixer cget name='AIF1TX2 Input 1 Volume'" )
#
amixer -Dhw:0 cset name='AIF1TX1 Input 1' IN2R
amixer -Dhw:0 cset name='AIF1TX1 Input 1 Volume' 40
amixer -Dhw:0 cset name='AIF1TX2 Input 1' IN2L
amixer -Dhw:0 cset name='AIF1TX2 Input 1 Volume' 40
amixer -Dhw:0 cset name='DMIC Switch' on



 

Making a recording

 

To make a recording :

  • Initalise the sound card values
  • Set the recording parameters
  • Run the recording command

 

The distribution comes with a 'reset' script which will reset all the values.

Recording is achieved using the command

arecord -Dhw:0 -r 44100 -c 2 -f S32_LE output_file

 

e.g.

# Make sure card is set up to record from the onboard Mic
use_case_scripts/RESET.sh
use_case_scripts/Record_from_DMIC.sh


# record to file
arecord -Dhw:0 -r 44100 -c 2 -f S32_LE music/petemp.wav

 

PlayBack

To playback the recording use the command

aplay -Dhw:0 -r 44100 -c 2 -f S32_LE recorded file

 

Prior to playback the playback medium (e.g. the headset) must be enabled. The output volumes can be adjusted in the same way as the recording levels.

 

Example recording configuration

The attached tar file contains examples of recording and playback set up scripts, plus a couple of scripts which will record and playback. The recorded file is created in sub directory 'music'.

 

To install

 

  • Navigate to a directory on the pi where you want to install the example
  • Copy the attached file to that location (e.g. using ftp)
  • Un-tar using command

 

tar -xvf ~/recording_example.tar

 

This will create directory recording and 2 sub directories use_cases and music

 

To make a recording run pe_record.sh. To play back use pe_playback.sh. The recorded file is created as petemp.wav in sub directory music.

 

For more details, look inside the individual script files !

PEarle

Pi Webpage Reboot

Posted by PEarle Apr 2, 2014

I have recently set up a LAMP Raspberry Pi and am using this at work to monitor some servers (see Raspberry PI as a LAMP server and PI as a Web Server Monitor)

I'm running it 'headless' (i.e. without a keyboard or mouse attached). This is fine until I wanted to reboot it yesterday, and realised that I would have to go through the hassle of opening a Putty session, connecting to the server, logging on, and issuing the reboot command. How convenient it would be if i could just click on a web link ...

 

After some investigation I discovered that I couldn't simply write a .php page with something like 'sudo reboot' in it. What I needed to do was ;

 

  • Write a python script that would reboot the server
  • Write a php page to execute the python script.
  • I would also need to make some configuration changes to allow the reboot command to be run from a web application

 

Python Script

If I was booting from the command line I would enter sudo reboot. My python script therefore needs to allow me to run a system command. This is done by using the python subprocess command (there's a useful reference page at Subprocess and Shell Commands in Python ). With that knowledge, the resulting code is fairly easy to understand - see below. Note that the 'sudo' and  'reboot' commands are evaluated with their full paths.

 

command = "/usr/bin/sudo /sbin/reboot"
import subprocess
process = subprocess.Popen(command.split(), stdout=subprocess.PIPE)
output = process.communicate()[0]
print output





 

Time stamping

 

I decided that it would be nice to keep a record of the commands that were being issued as added a time stamp operation in the python code - this simply writes a line to a log file with the current date/time. I also found this useful when developing this mini app as I could have the script run (and see that it had run successfully!) without having to issue the 'reboot' command.

 

The timestamp code is as follows

 

#
# Construct a timestamp variable
#
import time
ts = time.time()
import datetime
st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')


#
# Open a file and allow content to be appended to it
#
f = open('/var/www/remotecontrol/logs/reboot.log', 'a')


# write the timestamp and text to the file
f.write(st)
f.write(' : REBOOT command issued\n')




 

For the entire script, see attached example.

 

PHP Page

 

Once I had the script, I needed a page to allow me to run it. Executing the script from a web page is quite straight forward - e.g.

 

<?php
 exec("python /var/www/remotecontrol/python/reboot.py");
?>





However I want to control the process so that the script only runs when a button is pressed. Therefore my page needs to :


  • Display a page with a button on it
  • When the user presses the button
    • Execute the script
    • Display a confirmation message


I achieved this with the following code :


Output a button - when it is clicked execute javascript function reboot().


<input type="button" id="reboot"  value="Reboot" onClick="reboot()"/>


The javascript function resubmits the page with an added parameter - i.e. status=reboot


<script>
  function reboot() {
       window.location="reboot.php?status=reboot";
  }
</script>




 


Php code in the page looks for the existence of the 'status' parameter and acts accordingly - note that it executes the script and puts out an indicationon the screen that the server is rebooting


<?php
   $status = $_GET["status"];

  if ($status == "reboot"){
       exec("python /var/www/remotecontrol/python/reboot.py");
       print '<h2>Server is rebooting ...</h2>';
  }
?>





The full code is attached below - note that the page offers two options reboot and shutdown. (The shutdown script is a clone of the reboot script - with the command changed to shutdown now.)

 

Configuration Changes

When I tried to run the function nothing happened - my page displayed the 'Server is rebooting' but the server didn't reboot. I looked in the logs and found sudo: no tty present and no askpass program specified. (NB the error.log file is located at /var/log/apache2). After some 'googling' I discovered that this was being issued because the current user doesn't have access to the command. although I always log on to the pi from the command line as the default user pi, this command is being issued by the web page via Apache - and with the default LAMP installation, Apache runs as user www.data, therefore, this user (i.e. Apache) needs to be given access to the sudo command to run the reboot command.


This is achieved as follows.

  • From a putty session use command sudo visudo
    • This will open up the sudo configuration file in the editor.
  • Go to the end of the file and add the following line


www-data ALL=/sbin/reboot
www-data ALL=NOPASSWD: /sbin/reboot



the effect of tis will be to enable user www-data to use the reboot command. if you want to issue other commands using sudo from Apache (e.g. shutdown, then add additional lines to the sudo configuration file.

 

When I had made the changes I rebooted the Pi to make sure the changes were applied.

 

 

That's it! - when I go to the url http://10.13.36.255/remotecontrol/reboot.php I see the following page; (I may add some styling to make it look better !)

 

reboot1.png

 

 

When I click on the 'reboot button I see this, and the Pi reboots !

 

reboot2.png

If this was anywhere other than in a very closed environment I would add some extra functionality to prevent the reboot page being actioned by unwanted users ! - but in this particular case I don't need to worry

 

Useful links

 

Raspberry Pi as a LAMP Serverhttp://www.element14.com/community/community/raspberry-pi/raspberrypi_projects/blog/2014/02/24/raspberry-pi-as-a-lamp-server
Pi as a Webserver Monitorhttp://www.element14.com/community/community/raspberry-pi/raspberrypi_projects/blog/2014/03/20/pi-as-a-web-server-monitor
Python Subprocess Commandhttp://www.pythonforbeginners.com/os/subprocess-for-system-administrators

 

 


 








Filter Blog

By date: By tag: