The MagPi Issue 9 en
The MagPi Issue 9 en
Meet
Ladyada
AAnn iinntteerrvviieew
ww
wiitthh
tthhee FFoouunnddeerr ooff
AAddaaffrruuiitt
IInndduussttrriieess
TThhiis IIsssue....
W
WeebIIO
OPi FFraam
mew
work
BBaacckkupp SSD carrdds
VVaallaa & LLeddBoorgg
SSccrraattcchh GPIO
O
RISCO
OSS
hhttttpp::///wwwwww..tthheem
maaggppii..ccoom
m
MagPi team
Guest writers
Alex Eames
Eric PTAK
Norman Dunbar
Pete Nowosad
Ross Taylor
Simon Walters
Contents
04 An interview with Limor Fried from Adafruit
Founder and engineer of Adafruit Industries Limor Fried talks to The MagPi.
Learn how to control the Raspberry Pi's GPIO interface from a web browser.
1 8 An introduction to RISCOS
A basic introduction to the RISCOS operating system, from SD card installation to the desktop.
Learn how to install Arch Linux, a barebones rolling Linux distribution on the Raspberry Pi.
Learn the first steps to GPIO control, allowing more complicated interfacing.
awarded
Entrepreneur
magazines
Entrepreneur of 201 2 last month. Do you
think this is the first sign of mainstream
acceptance of hacking, in its true definition
and the maker movement in general?
WebIOPi
WebIOPi - Raspberry Pi RESTframework
Tutorial: Remote controlled robot cam
WebIOPi is a REST framework which allows
you to control Raspberry Pis GPIO from a
browser. Its written in Javascript for the client
and in Python for the server.
You can fully customize and easily build your
own web app. You can even use all the power
of WebIOPi directly in your own Python script
and register your functions so you can call
them from the web app. WebIOPi also
includes some other features like software
PWM for all GPIO.
Installation
Installation on the Raspberry Pi is really easy,
as it only requires Python. On Raspbian
Wheezy, you can use the PiStore to download
and install WebIOPi. You can also install it
using a terminal or a SSH connection. Check
the project page for the latest version, then
type:
$ wget
http://webiopi.googlecode.com/files/
WebIOPi-0.5.3.tar.gz
$ tar xvzf WebIOPi-0.5.3.tar.gz
$ cd WebIOPi-0.5.3
$ sudo ./setup.sh
* Look in /home/pi/webiopi/examples
for Python library usage examples
at
First Use
Open a browser from any device on your
network and point it to the given URL:
http://[IP]:8000/webiopi/ or you can
use localhost if you are connected to your Pi
with a keyboard and a display plugged into it.
You will then be asked to log in, default user
is webiopi and password is raspberry.
You should see the default header app:
* To
sudo
* To
sudo
Robot Cam
The following parts of this article are about a
robotised webcam you can control from any
web browser. You will need:
- Chassis
- Raspberry Pi with WebIOPi
- Operational USB Webcam
- Operational USB WiFi adapter
- L293 H-Bridge
- 2 sets of motors, reducers and wheels
- Battery and power regulation
- Electronic prototyping parts
From an electronic point of view, L293
contains an electronic circuit similar to the
Skutters H-Bridge from the December MagPi
issue. L293 adds an enable input that can be
used with a PWM signal to limit the speed. It
also has two power inputs, one for the logic
(+V=5V), and one that suits the motors
(+Vmotor<36V).
10
GPIOs
IN1 on GPIO 9
IN2 on GPIO 10
EN1 on GPIO 11
motor GPIOs
L293 IN3 on GPIO 23
L293 IN4 on GPIO 24
L293 EN2 on GPIO 25
def left_forward():
GPIO.output(L1, GPIO.HIGH)
GPIO.output(L2, GPIO.LOW)
# Right motor functions
def right_stop():
GPIO.output(R1, GPIO.LOW)
GPIO.output(R2, GPIO.LOW)
def right_forward():
GPIO.output(R1, GPIO.HIGH)
GPIO.output(R2, GPIO.LOW)
# Set the motors speed
def set_speed(speed):
GPIO.pulseRatio(LS, speed)
GPIO.pulseRatio(RS, speed)
# Movement functions
def go_forward():
left_forward()
right_forward()
def stop():
left_stop()
right_stop()
11
A Few Caveats
Why Backup?
Windows Users
12
Start
8192
122880
End
122879
15523839
Blocks Id System
57344 c W95 FAT32 (LBA)
7700480 83 Linux
Make a Backup
13
14
Coming in Part 2
FEBRUARY COMPETITION
Once again The MagPi and PC Supplies Limited are proud to announce yet
another chance to win some fantastic Raspberry Pi goodies!
This month there are three prizes!
The first prize winner will receive one of
the new pre-assembled Gertboards!
The second and third prize winners will
receive a raspberry coloured PCSL case.
For a chance to take part in this month's
competition visit:
http://www.pcslshop.com/info/magpi
Closing date is 20th February 201 3.
Winners will be notified in next month's
magazine and by email. Good luck!
To see the large range of PCSL brand Raspberry Pi accessories visit
http://www.pcslshop.com
December's Winners!
There were over 540 entries! It was a difficult choice with so many great submissions.
The winner of the 51 2Mb Raspberry Pi Model B with 1 A 5V power supply and PCSL
Raspberry Pi case is Fiona Parker (Ilkley, UK) .
The 2nd and 3rd prize winners of the PCSL Raspberry Pi case are Damien Plunkett
(Flagstaff, USA) , and Nico van der Dussen (Pretoria, South Africa) .
Congratulations. We will be emailing you soon with details of how to claim your prizes!
15
Interface Build
The build was a pleasure. Id been teaching
my son to solder the day before, so Id left the
leaded solder out and the leaded bit on the
iron. I decided to go with those for this build.
The instructions are clear and the build is
quite easy. You could probably build it without
the instructions because the excellent silk
screen layout, printed on the board, shows
you what goes where. The only potential
16
Software Installation
The next step was to fully update Raspbian
and install some software to test the interface.
The instructions were excellent and software
installation worked flawlessly. The longest part
was doing the Raspbian package updates
(using sudo apt-get update and sudo
apt-get upgrade).
Testing Procedures
The following describes the test procedures
from the provided manual. Test commands
are given for switching the LED on/off and
reading
the
buttons
status
(pressed/unpressed). These worked perfectly
(although the LED on mine is not very bright).
Then you are invited to test your 5V FTDI
interface (a type of cable you can use to log in
directly with no network connection) if you
have one. Mine worked perfectly. I was able to
get a command line terminal login through the
serial port. And that completed the structured
test procedures. Everything passed.
RGB LED
So then I wrote a little script to blink a three
colour (Red, Green, Blue RGB) LED
different colour combinations using P7, P6 &
P5 (Quick2Wire numbering scheme) as
outputs. That also worked perfectly. Heres a
link to a video guided tour of the Quick2Wire
board with test programs in action.
http://youtu.be/JJuKtsdAerU
Conclusion
The Quick2Wire Pi Interface is a very nice
board with a lot of promise and what looks like
being a very good Python Applications
Programming Interface (API) behind it. Its
going to be priced cheaper than youd be able
to make one yourself. Being ultra-fussy, Id
prefer a more visible (brighter) LED. But thats
really the only thing Id change, which is
saying a lot!
The Future?
Theres a lot more Quick2Wire add-on boards
in the pipeline, including an analog to digital
converter (ADC), motor controllers, LCDs,
servo controllers etc. Its going to be a
modular system, easy to build and easy to
use. Theres even talk of a Scratch interface at
some point down the line.
All the hardware and software is open source.
The emphasis is on software libraries and
much needed free teaching resources. It looks
very much to me as if Quick2Wire is one to
watch. Their web site is at Quick2Wire.com.
DID YOU
KNOW?
The Quick2Wire team consists of nine
people, spanning a 7 hour time zone. They
live in Chicago, London, Bristol and the
Pyrenees.
They have never all been in one location!
17
18
Booting
RISC OS boots straight into a windows, icons,
menus, pointer (WIMP) desktop with a nice
Raspberry Pi background from which
applications can be launched. A strip at the
bottom of the screen known as the icon bar
holds devices at the left and running
applications at the right. Clicking on a device
icon (e.g. hard drive, SD card, RAM disc)
opens a filer window which can be used for
browsing and launching different types of file
such as BASIC programs, modules and
applications. Similarly, left clicking on an
application typically opens a window for the
user to interact with it, or clicking with the
middle button brings up a menu from which
configuration options can be set and actions
performed. Task windows open up a
command line interface (CLI) from which
many common tasks can be executed and
these can be grouped and packaged into
Obey files for convenience.
WIMP based applications co-operate through
the software interrupt (SWI) based WIMP
application programming interface (API) which
is documented in the Programmer Reference
Manuals (PRMs). These are available from
the foundation.riscos.com web site and run to
five large volumes effectively constituting the
equivalent of the bible for RISCOS application
developers.
Files can be pinned to the desktop for easy
access and wallpapers and screen savers can
be easily configured, so anyone familiar with
Windows or Unix will quickly feel at home.
Installation
Bundled applications include a text editor
!Edit, a drawing program !Draw and a painting
application !Paint, however a plethora of third
party applications are available including
games, music, DTP and art packages. Many
of the most used of these are freely installable
using the supplied package manager
application (!PackMan) which is styled on the
lines of Linux Update Manager.
19
I n stal l i n g &
c o n f i g u ri n g
Learn how to install Arch Linux, a barebones rolling LINUX
distribution.
Many people think of Linux as an operating system, but
in fact it's actually just a kernel, the base. To make it
into a proper operating system, you need to add a little
bit more. As Linux is free and open-source, many
people have done this, and each one has done it slightly
differently, creating many different 'distributions', or
'distros' for short.
The main Raspberry Pi distribution offered at
http://www.raspberrypi.org/downloads is Raspbian, a
version of Debian. However, if you scroll down a bit
more, you'll see some others, including one called Arch
Linux.
So what's the difference between Raspbian and Arch?
The main difference is the package managers and the
way updates are managed.
Debian, and therefore Raspbian, are very strict on
package updates. They have to go through testing, so
the maintainers can be sure they are stable and work
before releasing them to the regular users. This is good
because it means software is almost guaranteed to
work, but not so good as it means updates take a little
while to reach users.
Arch Linux is different in this respect, releasing updates
as soon as possible. For this reason it is called a
'rolling release' distro, since you only have to install it
once and then whenever a package gets an update you
can upgrade it there and then. This allows users to get
updates more quickly, although it means software is
more unstable. In case of trouble, you can simply
image the SD card again.
The other major difference between the two is that
Raspbian comes completely ready, while Arch comes
with the bare essentials, allowing users to pick what
they want to install. This makes setup harder for
newcomers, but this guide should help ease the
process.
First boot
The first boot might take a little while longer, just wait
until it's done. Once you get to the login screen, use the
user name root and the password root.
You will then have a terminal open. You will notice if you
try startx, it will not work. That gives you an idea of
how little Arch comes with. Don't worry though, we'll get
to installing a graphical user interface.
Before you begin doing anything, you may want to
change the keyboard layout to your country. This is
done by typing:
loadkeys country code
20
ls /usr/share/zoneinfo/area
ln -s /usr/share/zoneinfo/area/timezone
/etc/localtime
/etc/locale.gen
Using pacman
Arch Linux's package manager is called pacman, and
we use that to install packages. To install a package,
type:
pacman -S <package name>
This will allow you to edit the sudoers file with the
familiar nano editor. Find the line that says root
ALL=(ALL) ALL and copy it onto a different line,
replacing root with the user name of the new user. If you
would like to have it so sudo does not ask for your
password, like on the default Raspbian install, put
NOPASSWD: in front of the final ALL.
Finally, we can change the password for the root
account, using the command:
passwd root
to log out of root and login as the new user you set up.
cp /etc/skel/.xinitrc ~/.xinitrc
Then type:
and finally:
startx
21
Introducing Vala
Writing a simple web controller for the LedBorg RPi add-on
The Vala language is, as programming
languages go, very much a new kid on the
block and is still under many programmers'
radar. We will use Vala to communicate with
LedBorg from www.piborg.com/ledborg over
the internet. [Ed: also in this issue we will see
how we can perform a similar activity with
Python in The Python Pit.]
Vala is a C# style language built on the GLib
object system providing easy access to the
base GNOME libraries and subsystems. The
compiler, valac, turns the Vala code into C,
and in turn triggers the system's C compiler to
produce native code. This means that, unlike
C#, there is no .NET framework or virtual
machine. Effectively, it is a higher-level way of
writing C apps. The project's home page is
https://live.gnome.org/Vala .
Although Vala is based around the GLib and
GNOME libraries, it's not only for developing
GNOME desktop apps and is also good for
writing console-based apps and services.
LedBorg
The Code
Network Control
22
$ chmod +x compile.sh
// LedBorgSimpleServer.vala
// the namespaces we'll be using
using GLib;
using Soup;
// our main class
public class LedBorgSimpleServer :
GLib.Object {
// define the port number to listen on
static const int LISTEN_PORT = 9999;
// define the device file to write to
static const string DEVICE =
"/dev/ledborg";
// the method executed when run
public static int main (string[] args)
// do colour change
do_colour_change(colour);
}
}
// build the html for the client
string html = """
<html>
<head>
<title>LedBorgSimpleServer</title>
</head>
<body>
<form method="get" action="/">
Red:<select name="red">
<option value="0">Off</option>
<option value="1">1/2</option>
<option value="2">Full</option>
</select>
Green:<select name="green">
<option value="0">Off</option>
<option value="1">1/2</option>
<option value="2">Full</option>
</select>
Blue:<select name="blue">
<option value="0">Off</option>
<option value="1">1/2</option>
<option value="2">Full</option>
</select>
<input type="submit" name="action"
value="SetColour" />
</form>
</body>
</html>
""";
}
// do the colour change
public static void
do_colour_change(string colour)
{
/* Here we use posix file handling
to write to the file instead of
vala's gio file handling, as we
don't want the safety of
gio getting in the way when
operating in /dev */
// open the file for writing
Posix.FILE f = Posix.FILE.open(
DEVICE, "w");
23
Then this new section of the MagPi is for you! We aim to list Raspberry Jam events in your area,
providing you with a RPi calendar for the month ahead.
Are you in charge of running a Raspberry Pi event? Want to publicise it?
Email us at: [email protected]
24
25
Challenge solution
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<unistd.h>
<sys/sysinfo.h>
int main() {
int i = 0;
float ramUsed;
char gpCmdOne[250], gpCmdTwo[250], systemCmd[1000];
FILE *cmdPtr = 0, *outPtr = 0;
char c, fileName[100], *strPtr = 0;
struct sysinfo info; /* A sysinfo struct to hold the status. */
26
The solution includes functions and techniques discussed in previous tutorials. There are more simple ways to form
the file name from the host name. C provides a string.h header file which includes the declaration of several useful
functions for string operations. The full list of functions can be viewed by typing man string. Strings can be
concatenated by using strcat,
char fileName[100]="myHost", suffix[10]="-data.txt"
strcat(fileName,suffix); /* Append suffix to fileName, result in fileName. */
The host name can be read using fgets rather than fgetc,
where 1 00 is the size of the fileName character array. Lastly, the host name can also be read using the
gethostname function from unistd.h,
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int main() {
char fileName[100], suffix[10]="-data.txt";
gethostname(fileName,100);
strcat(fileName, suffix); /* Append the suffix to the fileName */
printf("%s\n",fileName);
return 0;
}
Structs
Structs were introduced quickly in the last article in issue 6, to allow the use of system information. Structs occupy a
continuous block of memory, similar to FORTRAN common blocks. The syntax of their usage is very similar to C++
classes with public data members. A struct is defined with a name and compound definition of variables. These
variables can also be structs. Starting with a simple struct,
struct dataPoint {
unsigned int timeSeconds;
float value;
};
The int timeSeconds is defined first in memory and then the float value. The size of a struct in memory is
the sum of the sizes of the variables. The definition of a struct should be made before its use and is typically found
in a header file, but can also be written in the same file before its usage. To test this simple struct,
int main() {
/* Declare a variable of "struct dataPoint" type. */
struct dataPoint s;
/* Assign the struct s some starting values. */
s.timeSeconds = 60;
s.value = 100.0;
return 0;
where the program assigns values and prints the memory locations to demonstrate the memory structure.
When structs are passed to functions, by default a local copy of the struct is made within the function. This means that
when the function finishes, the value of the struct in the function which called it is unchanged. This is the same
behaviour as if a basic variable had been passed to the function ,
Continued over page...
27
To modify the values of a struct within a function and retain these values, pointers can be used ,
void clearDataPoint(struct dataPoint *dp) {
dp->timeSeconds = 0;
dp->value = 0.;
}
where the dp->timeSeconds syntax is equivalent to (*dp).timeSeconds. Other than the short hand " ->" syntax,
the behaviour is exactly the same as that of simple variables discussed in Issue 5.
Header files
To illustrate the use of header files, the next example defines a histogram data structure and functions. Histograms
can be very useful to monitor long term experiments, provide summary figures or be used for data storage themselves.
Header files should be included to use functions within standard libraries or functions implemented within other C
source files. These files contain the declaration of functions and data structures, but do not contain the implementation
of the functions. The implementation is given within .c files, which are complied and built into static or dynamic
libraries or directly linked to. Similar to standard header files, additional header files can be written to contain function
definitions and data structures.
#ifndef HISTOGRAM_H
#define HISTOGRAM_H
is a header file called histogram.h, which defines a struct and declares functions, but does not implement the
functions it defines. In the case that the header file is included inside another header file, the header file might be
included in a program more than once. To prevent this double declaration, a precompiler ifndef case is used. This
case is true the first time the header file is included and false for additional include statements. The define statements
define values which are replaced when the precompiler runs, which is just before the compilation of the code. Since
dynamic memory allocation has not been discussed yet, a fixed size array is used for the binContents. Lastly
typedef is used to simplify the Histogram variable declaration. The header file must be included in a program before
the struct or functions are used .
#include "histogram.h"
#include <stdio.h>
#include <stdlib.h>
int main() {
unsigned int i;
Histogram h; /* Create a histogram struct */
initHist(&h,10,0.,10.); /* Initialise the histogram */
for(i=0;i<1000;i++) { /* Generate 1000 random points */
fillHist(&h,10*(float)rand()/RAND_MAX,1.0); /* Histogram each value. */
28
}
saveHist(&h,"Hist.txt"); /* Save the histogram. */
return 0;
This program histograms random numbers, which are generated between zero and one. The program cannot be run
without implementing functions defined in the histogram.h header file. This implementation should be given in a .c
file,
#include "histogram.h"
#include <stdio.h>
int initHist(Histogram *hist, unsigned int nBins, float xMin, float xMax) {
unsigned int i;
if((hist->nBins+2) >= MAX_BINS) {
printf("Error: too many bins requested.\n");
return 1; /* An error has occured. */
}
hist->nBins = nBins;
hist->xMin = xMin;
hist->xMax = xMax;
for(i=0;i<(hist->nBins+2);i++) hist->binContents[i] = 0.;
}
int fillHist(Histogram *hist, float value, float weight) {
unsigned int ibin;
float binSize;
if(value < hist->xMin) ibin = 0; /* Underflow */
else if(value >= hist->xMax) ibin = hist->nBins+1; /* Overflow */
else { /* Find the appropriate bin. */
ibin = 1;
binSize = (hist->xMax - hist->xMin)/hist->nBins;
while(value >= (ibin*binSize + hist->xMin) &&
ibin < hist->nBins && ibin < MAX_BINS) {
ibin++;
}
}
if(ibin >= MAX_BINS) { /* Stay within the array */
printf("Error: ibin = %u is out of range\n",ibin);
return 1; /* An error has occured. */
}
hist->binContents[ibin] += weight; /* Add the weight */
return 0;
}
int saveHist(Histogram *hist, const char *fileName) {
FILE *outputFile = 0;
unsigned int ibin;
float binSize;
outputFile = fopen(fileName, "w"); /* Open the output file. */
if(!outputFile) { /* If the file is not open.*/
printf ("Error: could not open %s for writing\n",fileName);
return 1; /* An error has occured. */
}
binSize = (hist->xMax - hist->xMin)/hist->nBins;
29
Rather than type gcc several times, a Makefile can be used to build the source files and produce the executable,
CC = gcc
TARGET = hist
OBJECTS = $(patsubst %.c,%.o, $(wildcard *.c))
$(TARGET): $(OBJECTS)
@echo "** Linking Executable"
$(CC) $(OBJECTS) -o $(TARGET)
clean:
@rm -f *.o *~
veryclean: clean
@rm -f $(TARGET)
%.o: %.c
@echo "** Compiling C Source"
$(CC) -c $<
where more information on make is given in issue 7. Put the two .c files in the same directory as the histogram.h
and Makefile. Then type make to build the executable. When the program runs it produces a text file which contains
the sum of the weights within the underflow, bins and overflow. The format is chosen to allow the histogram to be
plotted with gnuplot,
gnuplot
plot 'Hist.txt' with boxes
Similar to the previous tutorial, this plotting command could be added to a program also. The plot can be saved as a
png file by typing,
set term png
set output 'Hist.png'
replot
Challenge problem
Use the previous article and this article to histogram the system load for 30 minutes. Add functions to the
histogram.h and histogram.c files to calculate the mean and standard deviation of the distribution. The mean of
a histogram can be calculated from,
xMean = 0.;
for (i=1;i<=nBins;i++) { /* Skip underflow and overflow */
xMean += binContents[i]/nBins;
}
xStdDev = 0.;
for(i=1;i<=nBins;i++) { /* Skip underflow and overflow */
xStdDev += pow(xMean - binContents[i],2)/(nBins-1);
}
if(xStdDev > 0.) xStdDev = sqrt(xStdDev);
30
Article by W. H. Bell
HARDWARE
Interface board
I 2C Port Extender
Analogue board
SOFTWARE
I 2C,
For GPIO,
SPI
Device Libraries
Examples
SUPPORT
Articles
Tutorials
Forum
Interface board: 1 3.86 | Port Extender: 9.80 | Combo: 22.66 (save 1 .00)
Prices include UK VAT but exclude Postage and Packaging: from 2.70
Whilst the Raspberry Pi is a great tool for the creation of software, using
languages such as Scratch, Python, C etc., the best way to make it really come
alive and to add even more enjoyment to this cheap, credit card sized
computer is to start playing around with hardware hacking and physical
computing. This involves using the Raspberry Pi to control things like LEDs and
respond to switches and sensors. More often than not it also includes
knowledge and learning of both hardware and software in a very interesting
practical environment not just coding for the sake of coding but, for example,
creating robots and programming them to do cool things!
32
sudo /boot/install_scratch_gpio.sh
This will install all the necessary extra software and some simple examples.
(If you do not have internet on your Pi then put your SD card into a card
reader and try using your browser to right-click and save the script direct to
your SD card and then put it back into your Pi and run the second instruction)
Connecting Components Up
Extreme care should be taken when connecting hardware to the GPIO pins as
it can damage your Pi only do this if you're confident of your ability to follow
these instructions correctly. At a minimum you should get a breadboard and
use some female-male 0.1 leads (available from RS/CPC or your local Maplin).
Check out some GPIO pin guides to make sure you know what pins do what.
33
ledborg.py
34
on the form
html="Red", class_="btnRed"),
html="Green", class_="btnGreen"),
html="Off", class_="btnOff")
templates/index.html
Try adding a Random button to output any one of the 27 possible colours
from LedBorg shown in the image at the bottom of the previous page.
Web.py supports several other form elements including drop-down lists
and checkboxes. Full details can be found at www.webpy.org.
35
The MagPi is a trademark of The MagPi Ltd. Raspberry Pi is a trademark of the Raspberry Pi Foundation. The MagPi magazine is
collaboratively produced by an independent group of Raspberry Pi owners, and is not affiliated in any way with the Raspberry Pi
Foundation. It is prohibited to commercially produce this magazine without authorization from The MagPi Ltd. Printing for non
commercial purposes is agreeable under the Creative Commons license below. The MagPi does not accept ownership or
responsibility for the content or opinions expressed in any of the articles included in this issue. All articles are checked and tested
before the release deadline is met but some faults may remain. The reader is responsible for all consequences, both to software and
hardware, following the implementation of any of the advice or code printed. The MagPi does not claim to own any copyright licenses
and all content of the articles are submitted with the responsibility lying with that of the article writer.
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a copy of
this license, visit:
http://creativecommons.org/licenses/by-nc-sa/3.0/
Alternatively, send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041 , USA.
36