Python is an interpreted, high level language that emphasises on the code readability and its functions rather than the syntax. It also has a lot of built-in methods and tools that allow programmers to express their code in very less lines of code. For this reason, it has been widely used for various purposes. It is also supported by the open source community and because of this, you will find modules for everything right from email fetching to complex tasks like image recognition.
Raspberry Pi can be programmed using the Python language as well as the new, feature rich Wolfram language.
The customary starting point of learning any programming language: Printing 'hello world!'
print 'hello world!'
hello world!
In Python, you don't have to worry about memory allocation or specifying the data type of variables unlike commonly used languages like C, C++ and Java. This makes it easy for beginners and experts to concentrate on their code functionality. Also, Python uses indentation to specify blocks(instead of semicolons and brackets).
a = 10
print type(a) #type() returns the type of the variable.
<type 'int'>
b = 10.01
print type(b)
<type 'float'>
c = 'python'
print type(c)
<type 'str'>
d = 'p'
print type(d)
<type 'str'>
Note that, in Python, string and character are not different data types.
listExample = [1, 2, 3] #list is the Python equivalent of arrays in C, C++, etc.
The only difference is that, in Python, lists can be heterogeneous in nature. That is, a list's can have elements of different data types.
listExample = [1, 'a', 1.9]
The variable's data type can also be changed when necessary.
integer = 5
print type(integer)
<type 'int'>
integer = 'changing the type'
print type(integer)
<type 'str'>
variable = raw_input()
8
print type(variable)
<type 'str'>
Note that the raw_input() function stores values as strings by default.
To change this, use the following built in methods.
variable = int(raw_input())
6
print type(variable)
<type 'int'>
variable = float(raw_input())
8
print variable, type(variable)
8.0 <type 'float'>
Note that, the print function can be used to print multiple values by separating them with a comma.
To display a prompt to the user while getting input, specifying the prompt string like:
a = raw_input("Enter your name")
Enter your nameEnsemble Tech
a
'Ensemble Tech'
list = [1, 3, 5, 2, 4, 1]
list.count(1) #the count of the element 1 in the list
2
list.sort() #sorts the list
list #the list has been sorted
[1, 1, 2, 3, 4, 5]
list.append(6) #add an element to the end of the list.
In Python, a string is basically a list of characters. For this reason, list methods can also be used for strings. There are also some extra methods.
string = "this is an example"
string.capitalize() #capitalizes the first letter of the string
'This is an example'
string = 'single quotes can also be used'
But make sure that you don't use ' and " together. For example,
dontDoThis = 'look at the error"
File "<ipython-input-23-1868471ea474>", line 1
dontDoThis = 'look at the error"
^
SyntaxError: EOL while scanning string literal
If, if..else, nested if:
if True:
print 'this'
this
if False:
print 'hello'
else:
print 'hello world'
hello world
a = 5
if a > 5:
print 'this computer is very poor at Math'
else:
print 'Come on! Even a kid can say this'
Come on! Even a kid can say this
Nested if is achieved by using elif statements.
#this example uses whatever we have learnt till now
#can you guess the output without scrolling down?
userInput = int(raw_input("Enter something"))
inType = type(userInput)
if inType == str: #== is used for checking equality. Use = only for assignment
print "you entered a string" #or maybe you forgot to cast it to the required type. Use int() or float()
elif inType == float:
print "you entered a float value"
elif inType == list:
print "that is a list"
else:
print "This is an integer." #properly typed because this is the right output.
Enter somethingsomething
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-31-2d0aa59e6b53> in <module>()
1 #this example uses whatever we have learnt till now
2 #can you guess the output without scrolling down?
----> 3 userInput = int(raw_input("Enter something"))
4 inType = type(userInput)
5 if inType == str: #== is used for checking equality. Use = only for assignment
ValueError: invalid literal for int() with base 10: 'something'
No, I was cheating. You can't convert a string to an integer unless it has only numbers. For example, you can change '9898' to a string but changing 'asdasdsad' to a number is not possible.
#this example uses whatever we have learnt till now
#can you guess the output without scrolling down?
userInput = int(raw_input("Enter something: "))
inType = type(userInput)
if inType == str: #== is used for checking equality. Use = only for assignment
print "you entered a string" #or maybe you forgot to cast it to the required type. Use int() or float()
elif inType == float:
print "you entered a float value"
elif inType == list:
print "that is a list"
else:
print "This is an integer." #properly typed because this is the right output.
Enter something: 123
This is an integer.
For loop: Uses range() and xrange() to iterate through a series of values.
range(1, 10) #series of values from 1 upto 10(excluding 10)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
xrange(1, 10)
xrange(1, 10)
The difference between range() and xrange() is beyond the scope of Python application in RPi. However, in brief, use range() in situations where you need the values in the series(like printing numbers from 1 to 100). Use xrange() when you don't need the values(like printing hello world 100 times). You can use any of the two but using them according to the above guidelines will result in an optimised code.
for number in range(2):
print number
0
1
Note that the arguments of both range() and xrange() is of the form (x)range(start, stop[, step]). Here the stop parameter is mandatory. The start parameter is 0 by default. step parameter allows you to go through the list in increments. For example,
range(0, 10, 2) #note that the start parameter is needed if a step is provided.
[0, 2, 4, 6, 8]
a = 5
while a < 10:
print a
a += 1 #the increment and decrement operators are not present in Python
5
6
7
8
9
Python doesn't provide a switch case construct. Use nested if(with elif) when necessary.
The basic syntax is :
def functionName(optional, parameters, if, needed): the function does this
def evenCheck(number):
if (number % 2) == 0:
return True
else:
return False
def anotherImplementation(number):
if (number % 2) == 0:
return "even"
else:
return "odd"
for testCase in xrange(2):
n = int(raw_input())
if evenCheck(n):
print "the number is even"
else:
print "the number is odd"
result = anotherImplementation(n)
print "The number is " + result #string concatenation can be done with the + operator
print "The number %d is %s" %(n, result)
3
the number is odd
The number is odd
The number 3 is odd
4
the number is even
The number is even
The number 4 is even
In combination with the above mentioned Python basics, you can use the RPi.GPIO module to program the GPIO pins of the Raspberry Pi. This module is already available in RPi so you don't have to install it. If you need any additional modules, launch the terminal in the RPi and use the command sudo pip install moduleName
import RPi.GPIO as GPIO #imports the module. using the 'as GPIO' makes it possible to use all the
#module components as GPIO.something instead of RPi.GPIO.something
The following are some basics. An extensive documentation can be found here: http://pythonhosted.org/RPIO/
GPIO.setmode(GPIO.BOARD) #sets the numbering scheme according to the board
GPIO.setwarnings(False) #sets warnings to false. cleaner ouput.
GPIO.setup(7, GPIO.OUT) #set pin 7 as output
GPIO.output(7, True) #Set the output as true. In simple terms, light on
GPIO.output(7, False) #sets the output to false. In simple terms, light off
GPIO.cleanup() #reset every channel that has been set up by this program,
# and unexport interrupt gpio interfaces
Make sure you don't use the wrong pins. This image from http://www.raspberrypi- spy.co.uk/2014/07/raspberry-pi-b-gpio-header-details-and-pinout/ should give you an idea of what to use and what not to use.
Here is a simple program to turn on an LED.
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(7, GPIO.OUT)
GPIO.output(7, True)
time.sleep(3)
GPIO.output(7, False)
This program turns on the LED, keeps it on for 3 seconds and then turns it off.
To make the LED blink at specific time intervals(say blink thrice. once in every two seconds)
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(7, GPIO.OUT)
for blink in xrange(3):
GPIO.output(7, True)
time.sleep(0.5)
GPIO.output(7, False)
time.sleep(2)
To do the same with multiple LEDS,
#one led blinks, then the next..waits
#for two seconds and then repeats it.
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(3, GPIO.OUT)
GPIO.setup(7, GPIO.OUT)
for blink in xrange(3):
GPIO.output(7, True)
time.sleep(0.5)
GPIO.output(7, False)
GPIO.output(3, True)
time.sleep(0.5)
GPIO.output(3, False)
time.sleep(2)
To do the same with a user input for the number of times and the blink duration, use the following code.
import RPi.GPIO as GPIO
import time
#turns on and blinks an LED for a number of times
#specified by the user.
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(7, GPIO.OUT)
try:
noOfTimes = int(raw_input("Enter the number of blinks"))
except:
print 'Please enter an integer value'
try:
blinkDuration = float(raw_input("Enter the duration of the blinks"))
except:
print 'Please enter a number'
for n in xrange(noOfTimes):
GPIO.output(7, True)
time.sleep(blinkDuration)
GPIO.output(7, False)
time.sleep(blinkDuration)
Here is a simple program to control LED in a Rasberry Pi using your voice
This uses SL4A, a scripting tool for Android with Python for Android enabled in it. The setup is pretty easy and straightforward. Along with it, use the following commands in your RPi to install the required modules.
sudo apt-get python-pip
sudo pip install pygmail
Enter the following command in your SL4A interpreter
import os
import glob
import mimetypes
from email import encoders
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
def attach_files(msg, attachements):
for attachment in attachments:
attachment = attachment.strip()
for path in glob.glob(attachment):
filename = os.path.basename(path)
if not os.path.isfile(path):
continue
# Guess the content type based on the file's extension. Encoding
# will be ignored, although we should check for simple things like
# gzip'd or compressed files.
ctype, encoding = mimetypes.guess_type(path)
if ctype is None or encoding is not None:
# No guess could be made, or the file is encoded (compressed), so
# use a generic bag-of-bits type.
ctype = 'application/octet-stream'
maintype, subtype = ctype.split('/', 1)
if maintype == 'text':
fp = open(path)
# Note: we should handle calculating the charset
part = MIMEText(fp.read(), _subtype=subtype)
fp.close()
elif maintype == 'image':
fp = open(path, 'rb')
part = MIMEImage(fp.read(), _subtype=subtype)
fp.close()
elif maintype == 'audio':
fp = open(path, 'rb')
part = MIMEAudio(fp.read(), _subtype=subtype)
fp.close()
else:
fp = open(path, 'rb')
part = MIMEBase(maintype, subtype)
part.set_payload(fp.read())
fp.close()
# Encode the payload using Base64
encoders.encode_base64(part)
# Set the filename parameter
part.add_header('Content-Disposition', 'attachment', filename=filename)
msg.attach(part)
def sendemail(email_name, email_user, email_pswd, mailto, subject, body, attachments):
import smtplib
# DON'T CHANGE THIS!
# ...unless you're rewriting this script for your own SMTP server!
smtp_server = 'smtp.gmail.com'
smtp_port = 587
# Build an SMTP compatible message
msg = MIMEMultipart()
msg['Subject'] = subject
msg['To'] = mailto
msg['From'] = email_name + " <" + email_user + ">"
msg.attach(MIMEText(body, 'plain'))
attach_files(msg, attachments)
# Attempt to connect and send the email
try:
smtpObj = '' # Declare within this block.
# Check for SMTP over SSL by port number and connect accordingly
if( smtp_port == 465):
smtpObj = smtplib.SMTP_SSL(smtp_server,smtp_port)
else:
smtpObj = smtplib.SMTP(smtp_server,smtp_port)
smtpObj.ehlo()
# StartTLS if using the default TLS port number
if(smtp_port == 587):
smtpObj.starttls()
smtpObj.ehlo
# Login, send and close the connection.
smtpObj.login(email_user, email_pswd)
smtpObj.sendmail(email_user, mailto, msg.as_string())
smtpObj.close()
return 1 # Return 1 to denote success!
except Exception, err:
# Print error and return 0 on failure.
print err
return 0
import sys
import android
droid = android.Android()
email_name = "Your Name"
email_user = "emailid@gmail.com"
email_pswd = "password"
mailto = "emailid@gmail.com"
subject = "LED"
attachments = ''
body = droid.recognizeSpeech().result
if (sendemail(email_name, email_user, email_pswd, mailto, subject, body, attachments)):
sys.exit(0)
else:
droid.makeToast("Failed to send email")
And save the following code in your Raspberry Pi
import gmail
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(7, GPIO.OUT)
print 'authenticating. please wait'
g = gmail.login('username', 'password')
while True:
commandMails = g.inbox().mail(unread = True, sender = 'sourceEmailgmail.com', subject = 'LED')
try:
commandMails[0].fetch()
command = commandMails[0].body.lower()
commandMails[0].delete()
if 'light' in command or 'lite' in command:
if 'on' in command:
GPIO.output(7, True)
if 'off' in command or 'of' in command:
GPIO.output(7, False)
else:
pass
except:
time.sleep(10)
Run both the codes and see the magic. You can easily modify this code to control more than one LED. By adding a few more if..elif..else or the more complex set intersection approach, you can create something like a home automation system.
Till now, we have only seen how to control the RPi using the internet. We used an email based approach which may not be effective all the time. A better approach would be to use the RPi's networking capabilities and use some other device connected to the same local network that the RPi is in to control the GPIO pins.
You can use either Python or nodeJS(a Javascript based runtime environment for server-side and networking applications).
Here is a Python based approach.
We will be using lighttpd to run a server on the Raspberry Pi. To install lighttpd, use
sudo apt-get install lighttpd
Now open the file browser in your RPi and type this in the address bar:
/var/www/
Create an index.html with contents according to your wish.
<title>Ensemble Tech</title>If you are not able to create this file, use the following commands after starting the terminal.
cd /var/www/
chmod -R 777
and then create the index.html file.
To test this, open the terminal and run
sudo service lighttpd start
Now using any device that is connected to the same local network that the RPi is
in, open a web browser of your choice and type the IP address of the RPi in the
address bar. You can find this using the ip addr show
command. If all goes
well(it usually does if you have followed the instructions), you will be able to
see the index file you had created previously.
We will using FastCGI to run our Python program on the server. To install, use
sudo apt-get install python-flup
Create the following file in the /var/www/ path and change its permissions to
755. Use chmod -R led.py
. Note that you can give any file name but remember
this for later use.
#!/usr/bin/pythonRoot
import RPi.GPIO as GPIO
from flup.server.fcgi import WSGIServer
import sys
import urlparse
# set up our GPIO pins
GPIO.setmode(G.BOARD)
GPIO.setup(7, GPIO.OUT) #use any GPIO pin
def app(environ, start_response):
start_response("200 OK", [("Content-Type", "text/html")])
i = urlparse.parse_qs(environ["QUERY_STRING"])
yield (' ')
if "led" in i:
if i["led"][0] == "on":
GPIO.output(7, True) # Turn it on
elif i["led"][0] == "off":
GPIO.output(7, False) # Turn it off
WSGIServer(app).run()
We need to run Python for this script. However, doing so with default settings will result in security issues as you will have to provide sudo rights to control GPIO with Python. To avoid this,
ls -l /usr/bin/python
Note the version of your Python from the result of the above command. Use that version number(for eg. if it is 2.7) as
sudo cp /usr/bin/python2.7 /usr/bin/pythonRoot sudo chmod u+s /usr/bin/pythonRoot
Go to the directory /etc/lighttpd in the file browser and change the file permissions as mentioned earlier. This is to enable editing of the lighttpd.conf file.
Open the lighttpd.conf file and add mod_fastcgi to the server.modules list.
Then, add this to the conf file at the end.
fastcgi.server = ( ".py" => ( "python-fcgi" => ( "socket" => "/tmp/fastcgi.python.socket", "bin-path" => "/var/www/doStuff.py", "check-local" => "disable", "max-procs" => 1) ) )
To test this, you will have to restart the server. To do so, use any of the two following techniques(the former is an obviously better approach):
sudo service lighttpd restart
Or
sudo service lighttpd stop
sudo service lighttpd start
If you open the same address in your browser(192.168.0.32 in my case), you will
see the same index.html. Now do the following in the URL.
192.168.0.32/led.py?led=on
The LED will now turn on.
192.168.0.32/led.py?led=off
The LED will now turn off.
import io
import socket
import struct
from PIL import Image
import os
# Start a socket listening for connections on 0.0.0.0:8000 (0.0.0.0 means
# all interfaces)
server_socket = socket.socket()
server_socket.bind(('0.0.0.0', 8000))
server_socket.listen(0)
# Accept a single connection and make a file-like object out of it
connection = server_socket.accept()[0].makefile('rb')
try:
os.mkdir('RPi')
except:
os.chdir('RPi')
count = 1
try:
while True:
# Read the length of the image as a 32-bit unsigned int. If the
# length is zero, quit the loop
image_len = struct.unpack('<L', connection.read(struct.calcsize('<L')))[0]
if not image_len:
break
# Construct a stream to hold the image data and read the image
# data from the connection
image_stream = io.BytesIO()
image_stream.write(connection.read(image_len))
# Rewind the stream, open it as an image with PIL and do some
# processing on it
image_stream.seek(0)
image = Image.open(image_stream)
image.save(str(count) + '.jpg')
count += 1
print('Image is %dx%d' % image.size)
image.verify()
print('Image is verified')
finally:
connection.close()
server_socket.close()
On the Raspberry pi, use the following code. In the place of my_server, use the ip address of your server. Run ifconfig to find out the IP.
import io
import socket
import struct
import time
import picamera
# Connect a client socket to my_server:8000 (change my_server to the
# hostname of your server)
client_socket = socket.socket()
client_socket.connect(('my_server', 8000))
# Make a file-like object out of the connection
connection = client_socket.makefile('wb')
try:
with picamera.PiCamera() as camera:
camera.resolution = (640, 480)
# Start a preview and let the camera warm up for 2 seconds
camera.start_preview()
time.sleep(2)
# Note the start time and construct a stream to hold image data
# temporarily (we could write it directly to connection but in this
# case we want to find out the size of each capture first to keep
# our protocol simple)
start = time.time()
stream = io.BytesIO()
for foo in camera.capture_continuous(stream, 'jpeg'):
# Write the length of the capture to the stream and flush to
# ensure it actually gets sent
connection.write(struct.pack('<L', stream.tell()))
connection.flush()
# Rewind the stream and send the image data over the wire
stream.seek(0)
connection.write(stream.read())
# If we've been capturing for more than 30 seconds, quit
if time.time() - start > 30:
break
# Reset the stream for the next capture
stream.seek(0)
stream.truncate()
# Write a length of zero to the stream to signal we're done
connection.write(struct.pack('<L', 0))
finally:
connection.close()
client_socket.close()
First setup the serial pins on RPi
sudo cp /boot/cmdline.txt /boot/cmdline_backup.txt
sudo nano /boot/cmdline.txt
Change this
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait
To
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait
sudo nano /etc/inittab
Search for ttyAMA0 and comment out that line by including a # in the beginning of that line.
Connect the TX pin of the Arduino to RX of the RPi. Make sure that the ground of RPi is connected to the RPi as well.
Consider the following example where the temperature readings are recorded and shared over a server. The client then plots a graph with that output data.
#!/usr/bin/python
import web
import serial
import time
urls = ('/', 'index')
class index:
def GET(self):
s = serial.Serial('/dev/ttyAMA0')
temp = int(s.readline().strip('\n')) / 2
return str(temp)
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
import urllib2
import time
import matplotlib.pyplot as plt
t = []
tempValues = []
print 'please wait..values are being read'
for x in range(1, 10):
t.append(x)
temp = int(urllib2.urlopen('http://192.168.0.32:8080').read())
print ldr
tempValues.append(ldr)
plt.plot(t, lightValues)
plt.show()
Communicating with Arduino over serial port:
void setup()
{
Serial.begin(9600);
}
void loop()
{
if(Serial.available())
{
while(Serial.available()>0)
{
char inByte = Serial.read();
Serial.print(inByte);
}
Serial.print('\n');
Serial.flush();
}
delay(3000);
}
Use crontab -e. Scroll to the bottom and type @reboot command file &
Press
ctrl+o, enter and then ctrl+x. You can use the same to run a particular script
at various time intervals.