Experimenting with Python - Programming with Python - BeagleBone For Dummies (2015)

BeagleBone For Dummies (2015)

Part IV

Programming with Python

Chapter 10

Experimenting with Python

In this Chapter

Fading an RGB LED using PWM with Adafruit’s Python library

Employing the Python library to read analog inputs

Discovering Python’s capability for web projects by sending emails automatically

Figuring out how you can use functions to use various projects together

Getting acquainted with the powerful communication protocol UART

Chapter 10 covers Python and Adafruit’s BeagleBone Input/Output (BBIO) library, which enables you to control the BeagleBone’s General Purpose Input Output (GPIO) pins in a simple and straightforward manner. In this chapter, you get to know functions that allow you to do more complex and useful tasks.

The chapter starts in the analog world. For outputs you get to see Adafruit’s Python BBIO functions that deal with pulse-width modulation (PWM) by creating a project to fade an RGB LED. For inputs you find out how to measure analog quantities from temperature sensors. You also get to see the ease with which the BeagleBone can interact with the web, and you explore one of the BeagleBone’s communication protocols — UART — that makes data transfer between devices a breeze.

As we preach throughout this book, illustration and practice are great ways to understand and master important digital electronic concepts and the BeagleBone. Gather your tools; it’s wiring time!

Fading an RGB LED with Python

Light-emitting diodes (LEDs) are fun. RGB (red-green-blue) LEDs triple the fun with the possibility of creating some sweet color effects with three different colors.

This project consists of controlling which colors of the RGB LED are on and how bright they are through the use of pulse-width modulation (PWM) and Adafruit’s BeagleBone I/O Python Library.

If you have enough space to set aside the projects in this chapter without unwiring them, we recommend that you keep them intact. Later in the chapter is a section where you mix various projects together.

You need the following components:

· An RGB common cathode LED

· Three 220 Ω or 470 Ω resistors

· A breadboard

· Jumper wires

Wiring an RGB LED

This section assumes that you use an RGB common cathode LED. If you have only a common anode LED, your code and your wiring has to be slightly different from what is illustrated in the following sections. See Chapter 8for a description of RGB common cathode LEDs and RGB common anode LEDs.

The wiring for this project is exactly the same as the wiring for the RGB project in Chapter 8, but the project itself is quite different.

To wire everything together, follow these steps:

1. Use a jumper to connect P9_14 to a vertical row on your breadboard.

This pin is the one you use to control the red color of your RGB LED.

2. Use a jumper to connect P9_16 to a vertical row on your breadboard.

This pin is the one you use to control the green color of your RGB LED.

3. Use a jumper to connect P8_13 to a vertical row on your breadboard.

This pin is the one you use to control the blue color of your RGB LED.

Use color coding to keep yourself organized. In this scenario, using red jumper wires for P9_14, green jumper wires for P9_16, and blue jumper wires for P8_13 probably would be a good idea.

4. To each of these jumpers, wire a 220 Ω or 470 Ω resistor.

5. Wire the longer lead of your RGB LED to ground (GND) on the breadboard rail.

Figure 10-1 illustrates the correct wiring.

Trimming the long lead might make it easier to plug the RGB LED into the breadboard. If you do that, you can distinguish the GND lead by looking at the LED’s lens. The biggest chunk of lead inside the lens corresponds to the GND lead.

Figure 10-1: RGB wired to BeagleBone Black.

You can use eight pins as PWM pins. Read Chapter 6 for more information about the PWM pins.

Writing the code for fading an RGB LED

Create a script named RGB.py, and type the following:

#!/usr/bin/python
import Adafruit_BBIO.PWM as PWM
import time

RGB = ["P9_14", "P9_16", "P8_13"]
#RGB[0] controls red, RGB[1] controls green, RGB[2]controls blue

for i in range(0, 3): #runs the indented code below 3 times
PWM.start(RGB[i], 0) #initialize PWM with all leads OFF

#set initial conditions
c_initial = RGB[0]
c_next = RGB[1]
c_off = RGB[2]

while True:
PWM.set_duty_cycle(c_off, 0)
for i in range(0, 100):
PWM.set_duty_cycle(c_initial, 100-i)
PWM.set_duty_cycle(c_next, i)
time.sleep(0.05) #change this line for faster/slower fading speed
#swap the colors in the following order: R->G->B->Repeat
aux = c_initial
c_off = c_next
c_next = c_off
c_off = aux

The following sections break down the code for easier understanding.

Importing libraries

The first step after the shebang in a Python script is importing libraries. In this case, you want to import Adafruit’s library and define a PWM object, which you name PWM:

import Adafruit_BBIO.PWM as PWM
import time

Then you import the time library, which we cover in Chapter 9. This library enables you to halt the program for a set number of seconds, using the sleep() function:

Initializing PWM and setting initial conditions

The following chunk of code contains two Python concepts: lists and for loops:

RGB = ["P9_14", "P9_16", "P8_13"]
#RGB[0] controls red, RGB[1] controls green, RGB[2]controls blue

for i in range(0, 3): #runs the indented code below 3 times
PWM.start(RGB[i], 0) #initialize PWM with all leads OFF

A list is a compound data type. It’s a group of variables. Within a list, you can save more than one value. In this case, you create a list called RGB where you save the pins that are used in this project. You can access each individual value within a list by using a subscript. In this case, RGB[0] refers to "P9_14", RGB[1] refers to "P9_16", and RGB[2] refers to "P8_13". You can use each element of a list the same way that you use a regular variable.

In Python, the subscript that refers to the first element of a list is always 0, not 1.

You can use lists that consist of both text (strings) and numeric values, such as someList = [1, "hello" 35.117, 141, "bye"]. It’s often advisable, however, for a list to hold items of the same type.

Next comes the for loop:

for i in range(0, 3): #runs the indented code below 3 times
PWM.start(RGB[i], 0) #initialize PWM with all leads OFF

for loops are of extreme importance in the world of programming because they enable you to do stuff a set number of times while increasing a variable in every iteration of the code.

The code after this for loop runs three times, but it isn’t always exactly the same code. Because the variable i increases by 1 at each iteration, this loop goes through all elements of the RGB list and runs the function PWM.start(pin, duty) on each of them:

PWM.start(pin, duty)

This function takes two parameters:

· pin: The pin that you want to use as PWM.

· duty: The initial duty cycle, which goes from 0 for off to 100 for maximum.

Chapter 6 explains that the BeagleBone’s PWM default polarity is HIGH, which is somewhat counterintuitive. In the situation described in Chapter 6, the duty-cycle period is a period in which the voltage is LOW, so by default, setting a higher duty cycle on a BeagleBone PWM pin means a LOW voltage. Adafruit’s Python library (and BoneScript) functions work in reverse; the default polarity becomes LOW, so the duty cycle is a period in which the voltage is HIGH.

The default might be different on your BeagleBone, and the functions of the libraries you are using might be of a different version that changed these defaults. That said, if things don’t work properly, you may have to reverse all the parts of the code that deal with PWM such that a higher duty cycle means lower brightness (100 is off and 0 is maximum).

Last, you define the initial conditions for the leads of your RGB LED:

#set initial conditions
c_initial = RGB[0]
c_next = RGB[1]
c_off = RGB[2]

Red is the first color, green is the second, and blue is off initially. Naturally, you can change this order as you want. You can also have the three colors on at the same time for different color effects.

Fading from one color to the next

For the while that loops forever, you start by turning one of the lights off; blue is defined as the one that stays off initially. Thus, you set the duty cycle of the PWM that controls blue to 0. Then you have a for loop that increments i from 0 to 100 in intervals of 0.05 seconds, increasing c_next’s duty cycle with i while c_initial’s decreases. This loop makes the RGB LED continually fade from c_initial (initially red) to c_next(initially green). The following snippet of code is responsible for that:

while True:
PWM.set_duty_cycle(c_off, 0)
for i in range(0, 100):
PWM.set_duty_cycle(c_initial, 100-i)
PWM.set_duty_cycle(c_next, i)
time.sleep(0.05) #change this line for faster/slower fading speed

Swapping the variables

Because you want the same code to run over and over with different colors and succession, this part of the code swaps the values of the variables around:

#swap the colors in the following order: R->G->B->Repeat
aux = c_initial
c_initial = c_next
c_next = c_off
c_off = aux

c_initial gets the value within c_next; c_next gets c_off; and c_off gets c_initial. An auxiliary variable named aux is used so that you don’t lose the value within c_initial when swapping the values.

Running the script for fading an RGB LED

Save the script, run it, and watch the show! Mess around with your code to see the LED fading faster, slower, and in a different order. Change the way duty cycles vary, and combine the three colors in different ways to create cool light effects.

If your circuit doesn’t work, you might need to troubleshoot it with a multimeter. Check www.dummies.com/extras/beaglebone to see how to do so.

If the LED is too dim, use a 220 Ω resistor rather than a 470 Ω resistor.

Working with Analog Sensors

Analog sensors measure many types of useful data, such as temperature, humidity, light, and distance. The simplest analog sensors work by outputting a voltage that depends on the data they measure. This relationship is often listed on the datasheet of the device as a mathematical formula or a graphical representation.

You work with different sensors in similar ways, as demonstrated by the two examples in the next sections. All you have to do is connect the sensor to one of the BeagleBone’s analog-to-digital converter (ADC) pins and read its voltage. Sometimes, there may be a difference in wiring, but the greatest difference is in the calculation that relates voltage to the data that the sensor measures. Figure 10-2 shows which of the BeagleBone’s pins can be used as analog inputs; they’re labeled from AIN0 to AIN6.

You need the following components:

· Temperature sensor: TMP36

· Infrared (IR) distance sensor: Sharp GP2Y0A21YK

· Two 10K Ω resistors

· A breadboard

· Jumper wires

Figure 10-2: BeagleBone GPIOs with the ADC pins.

If you can read and understand the important information in a datasheet, you should be able to use any other sensors by using the concepts shown in this section.

Using the right voltage for the ADC

The following information is so important that the section is one big Warning. Take heed!

Feeding a voltage higher than 1.8V to an ADC pin of the BeagleBone may be hazardous to your board. This situation is something of a nuisance, because most sensors output voltages up to 3.3V, which means that you can’t connect them to the ADC immediately. You need a circuit consisting of two resistances to eat up the extra voltage (see Figure 10-3). This circuit is called a voltage divider.

Because the ADC pin is in parallel to one of the resistances, it has the same voltage. When you have two resistors in series, the voltage dropped along one of them is the following:

Figure 10-3: Voltage-divider circuit.

The voltage on the resistor is the ratio of the total resistance. Using two equal resistors means that the ADC has 50 percent of the total voltage. If you’re dealing with 3.3V, half is 1.65V, which gives you a little leeway. Two 10K Ω resistors should do the trick. Don’t use resistors with smaller values!

If you use sensors that output a higher maximum voltage level, it’s imperative to determine the ratio of the resistances that you use. For a sensor that outputs 5V, for example, you have the following:

In this case, you should use a pair of resistors where the resistor that is in parallel with the ADC has to have at most 36 percent of the total resistance. You should use a value slightly smaller than the one calculated to have some leeway. A 10K Ω and a 22K Ω resistor achieve a ratio of 31.25 percent, which works just fine by setting the maximum voltage to 1.5625V.

Due to the imprecision of resistors, these values are always slightly different. That’s why it’s important to calculate for slightly less than 1.8V so that you have some safety margin.

Wiring an IR distance sensor

The IR sensor we use for this project is the Sharp GP2Y0A21YK (see Figure 10-4), due to the fact that it’s quite popular and easy to acquire. If you use another sensor, you should consult its datasheet to see which of its pins are GND (ground), Vcc (supply voltage), and Vo or Vout(output voltage). You also need to find the mathematical or graphical relationship between voltage and distance, which affects the last calculation in the code.

Figure 10-4: IR distance sensor: Sharp GP2Y0A21YK.

Follow these steps to prepare your breadboard to wire up the IR distance sensor Sharp GP2Y0A21YK:

1. Use a jumper to connect GND — P9_1, P9_2, P8_1, or P8_2 — to a horizontal track on your breadboard.

2. Use a jumper to connect 5V to another horizontal track on your breadboard.

Use P9_7 and P9_8 if you are powering the BeagleBone via USB and use P9_5 and P9_6 if you are powering it through an external voltage source.

3. Use a jumper to connect P9_40 to a vertical row on the breadboard.

This pin is the one that will read the analog input: AIN 1.

4. Divide the voltage by connecting two 10K Ω resistors to the jumper that comes from P9_40.

One resistor should connect to GND, and the other should connect to the output voltage that comes from the sensor.

To wire up the sensor, you need to know its pinout, which you can find on the datasheet. For the Sharp sensor we’re using for this project, refer to Table 10-1. The position described in the table is based on the connectors pointing toward you.

Table 10-1 Pinout of IR Distance Sensor Sharp GP2Y0A21YK

Position

Pin Number

Signal Name

Leftmost pin

1

Vo

Middle pin

2

GND

Rightmost pin

3

Vcc

Follow these steps to connect the pins to the jumpers you pulled from the BeagleBone (see Figure 10-5):

1. Connect pin 1 of the IR sensor to the resistor that connects to P9_40.

2. Connect pin 2 of the IR sensor to GND.

3. Connect pin 3 of the IR sensor to 5V.

Figure 10-5: IR distance sensor wired to BeagleBone Black with a voltage divider.

Writing the code to measure distance

Create a script named IR.py, and type the following code:

#!/usr/bin/python
import Adafruit_BBIO.ADC as ADC
import time
import math

sensor = "P9_40" #or AIN1

ADC.setup()

while True:
reading = ADC.read(sensor) # values from 0 to 1
voltage = reading * 1.65 #values from 0 to 1.65V
distance = 13.93 * pow(voltage, -1.15)
if distance > 80:
print("Can't measure more than 80cm!")
else:
print("The reading, voltage and distance (in cm) are " + str(reading), str(voltage), str(distance))
time.sleep(0.05) #loop every 50 milliseconds.

This code is quite straightforward: It imports an object as ADC to access the ADC pins on the BeagleBone. A new library joins the fray: math. This library includes several functions that simplify complex calculations.

A variable named sensor defines the analog pin to be used, and you use ADC.setup(), which always needs to be present in a program before it starts reading from the ADCs.

You can write AIN0-6 in place of P9_33-40. Note, though, that the order of the numbering of the AINs does not correspond to the numbering of the P9 header: AIN4 is P9_33, and AIN5 is P9_36, for example. Refer to Figure 10-2 earlier in this chapter whenever you’re in doubt.

Then comes the while True: loop. The program reads the value of the ADC, which goes from 0 to 1 and represents the fraction of the voltage that’s read on the pin. Because that voltage always goes from 0 to 1.65, simply multiplying the reading by 1.65 gets you the real value.

Getting the actual voltage value isn’t necessary in many applications. In fact, working with percentages may be much easier.

You convert the voltage reading to the distance in centimeters. This calculation depends on the sensor you use. The pow() function is imported from the math library and calculates voltage to the power of -1.15. It works as follows:

result = pow(base, exponent)

This function has three variables:

· base: The number you want to elevate to the power of the exponent

· exponent: The exponent’s value

· result: The variable where the result will be saved

Python can make that calculation without resorting to functions, but the process is a bit messy and prone to bugs. Also, introducing the math library seems like a good idea, as the library features many other useful mathematical functions, such as sine(), cosine(), and root(). Your program would also work with voltage**-1.15 instead.

Sharp’s sensor datasheet provides only a graphical representation to convert voltage into distance, so the formula used in the example is a made-up workaround, which means the following:

· It isn’t 100 percent accurate.

· The graphic shows that some distances less than 6cm read the same voltage as distances greater than 6cm. Thus, this formula works only for distances greater than 6 cm.

· The 6cm distance is theoretical. In reality, this value will most likely be different — both because the sensor isn’t perfect and because you’re using a voltage divider. You can (and should) test what’s truly the minimum distance after you run the script.

At the end, you simply print everything and make the program sleep for 0.05 second after each iteration so as to not overburden the central processing unit (CPU).

If you can’t find the mathematical relationship for a given graphic, don’t fret. You can simply write a program consisting of intervals and if statements. For this project, if you check the IR’s datasheet, you see that a sensor output of 1V and 1.5V means a distance between ~15 cm and ~25 cm. Thus, you could create a program that works in the following fashion:

if distance > 15 and distance <= 25
do_something()
elif distance > 25 and distance <= 35
do_something_else()
#and so on so forth

Normally, though, it’s easy to find a mathematical relationship. If you don't see it on the datasheet, try an Internet search.

Running the script to measure distance

Save your script by pressing F5 or clicking Run. Move your hand or any other object close to and farther from your sensor to see that the values printed on your screen reflect different distance readings.

Play around with the IR sensor by moving an object very close to it — somewhere between 5cm and 15cm — and use a ruler to check the practical minimum value of distance that you read. This value will be useful in future programs. For us, the distance was a little bit over 9cm, so that’s the value we use as minimum.

Wiring a temperature sensor

The wiring for this project is simple. Start by checking your temperature sensor’s datasheet to see its pinout. If you’re using the TMP36 and looking at it from below, with the curved side facing you, you can refer to Table 10-2.

Table 10-2 Pinout of the Temperature Sensor TMP36

Position

Pin Number

Signal Name

Leftmost pin

1

Vcc

Middle pin

2

Vout

Rightmost pin

3

GND

The sensor we used in the example doesn’t require a voltage divider because its output surpasses 1.8V only for 266 degrees F (130 degrees C). If the one you use surpasses that voltage at a much lower temperature — or if you’re afraid that the TMP36 will read more than 266 degrees F — simply employ a voltage divider as described in the “Using the right voltage for the ADC” section. You can wire it to your circuit exactly as described in the “Writing the code to measure distance” section.

Follow these steps to wire your temperature sensor:

1. Connect the BeagleBone’s GND — pin P9_1, P9_2, P8_1, or P9_2 — to the sensor’s GND.

2. Connect the BeagleBone’s 3.3V supply — pins P9_3 and P9_4 — to the sensor’s Vcc.

3. Connect the BeagleBone’s AIN0 — pin P9_39 — to the sensor’s Vout (output).

Figure 10-6 shows a circuit diagram for this circuit.

Figure 10-6: Temperature sensor wired to BeagleBone Black.

Writing the code to read temperature

As we mention earlier in this chapter, the code you use to read from a sensor is always similar regardless of the type of sensor. The only important differences between this code and the code in the “Writing the code to measure distance” section are the calculations that give the temperature in different units. Refer to “Wiring an IR distance sensor” earlier in this section for a discussion of the code that deals with analog inputs.

To have your BeagleBone print the temperature values that the sensor reads, type the following code:

import Adafruit_BBIO.ADC as ADC
import time

sensor = "P9_39"

ADC.setup()

while True:
reading = ADC.read(sensor) # values from 0 to 1
voltage = reading * 3.3 #values from 0 to 3.3V, although this only surpasses 1.8V for temperatures over 266 degrees F

# the voltage/temperature relationship is as follows:
# Vo = 1/100 * Temperature + 0.5
temperatureC = (voltage - 0.5) * 100
temperatureF = (temperatureC * 9/5) + 32

print("The reading is: " + str(reading) + "which is, in Volts: " + str(voltage))
print("The temperature in Celsius is: " + str(temperatureC) + "; and in Fahrenheit: " + str(temperatureF))
time.sleep(0.05) #loop every 50 milliseconds.

Running the script to read temperature

Save and run your script, and watch your readings fill the screen. Touch your sensor with your finger, and notice that the values increase. If it’s chilly outside, and you’re using a laptop, take your circuit for a walk and see the values decreasing. The sensor should detect the temperature quickly.

Simply reading from sensors is fun, but getting stuff running based on readings is what the buzz is all about. Don’t unwire this circuit from your breadboard just yet. You use it in another project later in this chapter.


Deriving a formula from a linear graphic

The TMP36’s temperature-versus-voltage curve is a nice linear one. If you look at the graphic on its datasheet, and if you remember middle-school algebra, finding out the function that relates those variables isn’t hard. To continue reading this part, open TMP36’s datasheet and search for the output voltage-versus-temperature graphic.

Many sensors follow relationships like the one for the TMP36, so being able to find the relationship is quite handy. All linear relationships follow the formula y = mx + b. In this case, the value on the y-axis is Vo, and the value on the x-axis is the temperature in Celsius. b is the value that intersects the y-axis, which is 0.5V. m is the slope, which is the rate with which a variable changes in response to the other. To determine it, you need to choose two (x,y) points, called (x0, y0) and (x1, y2). Then simply employ the following formula:

This way, for the TMP36 temperature sensor, you end up with the formula


Sending an Email with Python

The BeagleBone is hands-down an exceptional platform for creating web-based projects, due to how easy it is to establish a connection with it. Moreover, Python hosts quite a few functions that greatly simplify matters. For this project, you use Python’s email library to create a program that sends emails.

Knowing the prerequisites

Before you get to write the code, there are some prerequisites you need to be aware of.

Finding your email’s SMTP server

SMTP stands for Simple Mail Transfer Protocol, a standard for email transmission. Each email provider has a different SMTP server, and you have to include the details in your code. The best bet for finding them is searching in the Internet for <e-mail provider> SMTP; the necessary details should come up right away.

Reading input from the keyboard

Chapter 9 explains how to read inputs from the world (such as buttons) and how to output text and anything else with the print command. To read input from the keyboard, you use the raw_input(message) function, which blocks the program until the user types something and presses Enter or Return:

data = raw_input(message)

Two variables are involved in this function:

· input: The message you want to use to prompt the user to type something

· data: The variable where the input is saved

Writing the code to send an email

Create a file called emailing.py, and type the following script:

import smtplib
from email.mime.text import MIMEText

my_email = raw_input("Insert your e-mail ")
my_password = raw_input("Insert your e-mail's password ")
subject = raw_input("Insert the subject ")
destination = raw_input("Insert the destination e-mail ")
text = raw_input("Insert the message ")

msg = MIMEText(text)

msg['Subject'] = subject
msg['From'] = my_email
msg['Reply-To'] = my_email
msg['To'] = destination

server = smtplib.SMTP("smtp.gmail.com", 587)
server.starttls()
server.login(my_email, my_password)
server.sendmail(my_email, destination, msg.as_string())
server.quit()

print("Your e-mail has been sent!")

The example code features Gmail’s SMTP server and port. If you use a different email provider, that part of the code needs to be changed as described in the “Finding your email’s SMTP server” section in this chapter.

Don’t create a file named email.py! This is the name of Python’s standard library module for emails, and your script won’t work. Avoid creating scripts with names that are too general.

For simplicity, we've broken this program into four parts, which are described in the following sections.


Beware of spam!

A program that automatically sends emails can easily fill your inbox if you’re not cautious. Simply creating a loop without any time.sleep() or wait.for.interrupt() function would result in your program’s writing emails as fast as the CPU can handle. Thousands of emails could be sent in less than a second!

In reality, email providers have defenses against spam, but your account would most likely be suspended, which you don’t want to happen.


Importing libraries

The first two lines of code import the required Python libraries to use SMTP and email-related functions. Specifically, email.mime.text imports an object (which you name MIMEText) that's required to build the email with the correct format:

import smtplib
from email.mime.text import MIMEText

Getting the email’s details

This snippet prompts the user to insert all the required data regarding the email and saves it in variables:

my_email = raw_input("Insert your e-mail ")
my_password = raw_input("Insert your e-mail's password ")
subject = raw_input("Insert the subject ")
destination = raw_input("Insert the destination e-mail ")
text = raw_input("Insert the message ")

To test this program, you can simply send the email to yourself by writing your own email address in the destination variable.

This general program allows you to use whatever emails you want and send whatever messages you want. You could simply use the following in your code:

my_email = "myemail@gmail.com"
my_password = "mypassword"
(...)

Typing this kind of code is known as hard-coding, which often makes things simpler but less general. The trade-off for this simplicity is having to change the code if you want to send a different text or subject, or want to use different email addresses.

If you hard-code, be sure to remove the while True: loop. Your program won’t block waiting for input, and if you don’ remove the loop you’ll spam the destination inbox.

Creating the email

The next part starts by creating an object named msg that allows you to create the email itself. MIMEText(text) takes the email’s body as a parameter. Then you build the fields in a standard email with the details that you provided earlier and saved in variables:

msg = MIMEText(text)

msg['Subject'] = subject
msg['From'] = my_email
msg['Reply-To'] = my_email
msg['To'] = destination

Sending the email

This section is where a connection to an SMTP server is established and the email is sent:

server = stmplib.SMTP("smtp.gmail.com", 587)
server.starttls()
server.login(my_email, my_password)
server.sendmail(my_email, destination, msg.as_string())
server.quit()

These functions have a few important, not-so-obvious details:

· stmplib.SMTP(SMTP server, port): This function connects to the SMTP server provided. Its parameters depend on the email provider you’re using.

· server.starttls(): This function is used for email providers only that use TLS (Transport Layer Security) to encrypt their messages. If yours doesn’t, you can simply remove this line of code. Generally, when you search for your email’s SMTP server you also find information on whether your email provider uses TLS.

· msg.as_string(): This function deals with all the complexities regarding the fact that msg is an object with multiple parts and isn’t defined as a message (that is, a string) to be sent.

Running the script to send an email

You’re all set to run the script. Save and simply press F5 or click the Run button, and look at your console. The program is waiting for your input. When you type that input, the program terminates and tells you that the email has been sent. Go check your inbox!

Mixing Up Projects and Creating Functions

The project in “Sending an Email with Python” earlier in this chapter enables you to send emails easily and automatically. Although that's cool, you could easily achieve the same thing by using a standard computer. One thing that makes the BeagleBone awesome is the ease with which your electrical projects in the real world can interact with the Internet. In this section, you see how to put two or more projects together through the use of functions. You can send the data read by the temperature sensor over email, as well as control the brightness and color of an RGB LED through the distance measured by the IR sensor.

Reading a temperature is a program of its own; so is sending an email. The same applies to reading the distance of an IR sensor or controlling the brightness of an RGB LED. These are all independent tasks that can be done without any of the other tasks. That’s why creating your own functions with Python is the best course of action here. Rather than creating an entire program in a linear process, you create different pieces of a puzzle and put them together in the end. When programs start to grow in size, it is definitely the best approach to divide the program into several tasks that can be tested independently and then put everything together in the end.

This section assumes you have gone through all the previous sections in this chapter because each independent task is a project built and tested in those sections. Through the use of functions, you add interaction between the different chunks of code.

Creating a function with Python

Functions are extremely useful to define tasks that you do often in your scripts. The following snippet of code shows an example of a good use of functions:

def calculator(operand1, operand2, operator):
print ("Calculating " + str(operand1) + str(operator) + str(operand2))
if operator == '+':
return operand1 + operand2
elif operator == '-':
return operand1 - operand2
elif operator == '*':
return operand1 * operand2
elif operator == '/':
return operand1 / operand2
elif operator == '%':
return operand1 % operand2
else:
return "invalid inputs!"

while True:
operand1 = raw_input("Introduce first operand ")
operand2 = raw_input("Introduce second operand ")
operator = raw_input("Introduce the operator ")
result = calculator(int(operand1), int(operand2), operator)
print(result)

This code should be quite easy to understand. Note three things, however:

· raw_input() always returns a string. For a computer, the number 2 and the character 2 are different things. Because strings are collections of characters, the value held in raw_input() is one or more character(s). To make math with that value, you have to convert it to an integer by using int() or to a floating-point number (a number with a decimal point) by using float().

· Normally, you want to use apostrophes: 'c' when referring to characters and quotation marks and "str" when referring to strings.

· The operation % is the modulo operation, which determines the remainder of a number when dividing it by another.

When you write a line of code that uses a function, such as my_email = input(“Insert your e-mail”), you’re executing a function call, which asks for a function to be executed. Functions are chunks of code that take parameters, make copies of those parameters, process those copies, and produce return values.

The functions used throughout this book are defined in the libraries you imported at the start of each program. Someone wrote these functions and saved them in those libraries. The projects in Chapter 6 control the GPIOs through writing and reading from files — a fact that’s completely transparent to you when you’re programming in Python. Someone else wrote the code that deals with the pesky complexities of using files and put it all in a function that anybody can use.


What changes when you mix the programs?

The answer is: very little. We need to note some changes, though. Some of these changes are merely organizational, whereas others are essential. They are

· The while True: loop must be changed to the main code; otherwise, the program will be stuck in one of the functions forever. This change is essential.

· Importing the libraries required for every function usually occurs at the start of the script, before the function definitions. It’s common for two different functions to require the same library, which is just a matter of organization.

· Normally, initial conditions and initialization of functions such as PWM() and ADC() are done right after the libraries are imported. Although your code would still work without this change, the change isn’t just merely about organization; it improves efficiency because these parts of the code need to happen only once. This function assures that they do indeed run only once instead of at every iteration of the while True: loop.


To create a function, use this structure:

def function_name(parameter1, parameter2, ...): #the function header
#all the function code goes here
return some_variable

Remember indentation! If you don’t indent when defining a function, the interpreter has no way to distinguish the rest of the code from the function code.

A line such as some_variable = function_name(parameter1, parameter2) would do the following:

1. Call your function.

2. Make copies of parameter1 and parameter2.

3. Process the values contained in the copies of parameter1 and parameter2.

4. Return a value that would be saved in some_variable.

Functions don’t necessarily require the return line or parameters. These functions are used simply to carry out tasks (such as setting some pins to HIGH or printing some output), not necessarily to process data and return something to be used in the main part of the code.

Sending temperature readings by email

Because this program is based on the ones in earlier sections of this chapter, the best strategy is to start by copying and pasting them under function definitions. Then move all the library importations to the start of the script. The code for the temperature sensor remains similar, but it doesn't have the while True: loop. The function that runs it should return the temperature at the end. The email part requires a slight change; you want to send the sensor temperature, not a message that you write. Besides the libraries imported at the start and while True: loop, the main code has two lines of code, consisting of the function calls. Type the following code for the combined programs:

import Adafruit_BBIO.ADC as ADC
import time
import math

import smtplib
from email.mime.text import MIMEText

sensor = "P9_39" #or AIN0

ADC.setup()

def read_temperature():
reading = ADC.read(sensor) # values from 0 to 1
voltage = reading * 1.8 #values from 0 to 1.8V

# the voltage/temperature relationship is as follows:
# Vo = 1/100 * Temperature + 0.5
temperature_c = (voltage - 0.5) * 100
temperature_f = (temperature_c * 9/5) + 32
return "the temperature in Celsius is" + temperature_c

def send_email(message)

my_email = raw_input("Insert your e-mail ")
my_password = raw_input("Insert your e-mail's password ")
subject = raw_input("Insert the subject ")
destination = raw_input("Insert the destination e-mail ")
text = message

msg = MIMEText(text)

msg['Subject'] = subject
msg['From'] = my_email
msg['Reply-To'] = my_email
msg['To'] = destination

server = smtplib.SMTP("smtp.gmail.com", 587)
server.starttls()
server.login(my_email, my_password)
server.sendmail(my_email, destination, msg.as_string())
server.quit()

print("Your e-mail has been sent!")

while True:
temperature = read_temperature();
send_email(temperature);

Note that the message variable of the send_email() function holds the same data as the temperature variable of the main code. When you send a variable as a parameter, you make a copy of it with whatever name you define in the function header. You’re not altering the variable temperature! It’s very important to remember that the variables within the code of a function are isolated from the rest of the world.

You could use the send_email() function with whatever message you desire; the code doesn’t care whether the message is a temperature or not. It just takes in a message — any message — and sends it. That’s the idea behind functions; they're chunks of code that can be used independently.

Getting lazy

Most likely, you always want to send sensor readings to your own email address and not to someone else’s, so having to type all the details is a tad tedious. You can simply hard-code the details in your email function, as follows:

def send_email(message)
my_email = "myEmail@gmail.com"
my_password = "my_password"
subject = "Temperature Reading"
destination = "myEmail@gmail.com"
text = "The reading is + str(message)" #this is the change

msg = MIMEText(text)

msg['Subject'] = subject
msg['From'] = my_email
msg['Reply-To'] = my_email
msg['To'] = destination

server = stmplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(my_email, my_password)
server.sendmail(my_email, destination, msg.as_string())
server.quit()

print("Your e-mail has been sent!")

This “lazy” version of the temperatureEmail.py script does not block waiting for input. It’s 100 percent automatic. Thus, it’s essential that you remove the while True: loop, lest you get your entire inbox spammed with temperature readings — or, more likely, get your email account suspended. Without the loop, the program sends the reading only one time.

Running the script to send the temperature

Save your program by pressing Ctrl+S or Cmd+S and run it by clicking on Run or pressing F5 several times, and see the results. Play around with the temperature sensor as to see different values.

Functions are great ways not only to keep your programs tidy and organized, but also to promote reusability. You could use the send_email(message) function to send the data read by a humidity or light sensor, for example. Conversely, you could use the read_temperature() function with a program that turns an air conditioner on or off, depending on the temperature.

Functions also make it simpler to work in a team whose members have different tasks. The person who programmed the air conditioner doesn’t need to have any clue about how his colleague got the temperature sensor working. Simply knowing what a function returns and what its parameters are gives you enough information to proceed.

Controlling an RGB LED with distance readings

Seeing the RGB LED’s brightness and color change as you move your hand around should be a fun thing to do. The good news is that if you’ve worked through this chapter in order, you already have a great deal of the code required to make this happen.

The circuit for this project is the same as the two circuits in the sections “Wiring an RGB LED” and “Wiring an IR distance sensor.” If you didn’t unwire them, you’re good to go. If you did unwire them, follow the earlier instructions or see Figure 10-7.

This section assumes you are using a common cathode RGB. If that isn’t the case, refer to the “Wiring an RGB LED” section to see what changes.

Rather than control the PWM’s duty cycle with time, you’re going to control it with the distance measured. The function that controls the LED needs to be changed to accommodate this fact. The code that measures distance remains the same as in the “Writing the code to measure distance” section, but no longer has the while True: loop. You also need to return the distance at the end of the function that runs the code. The biggest addition is the fact that you need to transform your distance measurement to a percentage; PWM doesn’t work with absolute values. That’s what the function absolute_to_percentage() in the following code is for.

Figure 10-7: RGB and IR distance sensor wired to BeagleBone Black.

Using your distance readings

The program works like this:

1. Import libraries.

2. Set initial conditions, and initialize ADC and PWM.

3. Run read_distance(), and save the distance measured.

4. Run absolute_to_percentage(), which takes the distance value in centimeters and transforms 10 to 80 cm to 0 to 100 percent.

5. Run control_LED(), which uses the distance measured to light up the LED.

6. Repeat Steps 3, 4, and 5 until interrupted.

The code is as follows:

#!/usr/bin/python
import Adafruit_BBIO.PWM as PWM
import time
import Adafruit_BBIO.ADC as ADC
import math

#setup RGB
RGB = ["P9_16", "P8_13", "P9_14"]
#RGB[0] controls red, RGB[1] controls green, RGB[2]controls blue

for i in range(0, 3): #runs the indented code below 3 times
PWM.start(RGB[i], 0) #initialize PWM with all leads OFF

#set initial conditions for RGB
c_initial = RGB[0]
c_next = RGB[1]
c_off = RGB[2]

#setup IR Sensor
sensor = "P9_40" #or AIN1
ADC.setup()

def read_distance():
reading = ADC.read(sensor) # values from 0 to 1
voltage = reading * 1.65 #values from 0 to 1.65V
distance = 13.93 * pow(voltage, -1.15) # values from 10 to 80 cm theoretically
return distance

def absolute_to_percentage(distance, minimum, maximum):
distance = distance - minimum #shift the 10-80 interval to 0-70
maximum = maximum - minimum #the maximum value, 80cm, is now 70
if distance > maximum: #after 80cm (which is 70 after the shift), values start being unreliable
distance = maximum #thus, everything after the max is the max itself.
return distance * 100/maximum # this puts the measured value in terms of 0 to 100 percent
# which is what PWM works with.
def control_LED(distance):
PWM.set_duty_cycle(c_off, 0)
for i in range(0, 100):
PWM.set_duty_cycle(c_initial, 100-distance)
PWM.set_duty_cycle(c_next, distance)
time.sleep(0.01)


while True:
distance = read_distance()
distance = absolute_to_percentage(distance, 9, 80)
print(distance)
if(distance > 0): #this happens like once in a million, if at all, but the program stops when it happens. And at 1GHz, a million is not so little!
control_LED(distance)
time.sleep(0.05)

# swap the colors in the following order: R->G->B->Repeat
aux = c_off
c_off = c_initial
c_initial = c_next
c_next = aux

The biggest addition here is the new function absolute_to_percentage(), which transforms absolute data readings into values ranging from 0 to 100 percent so that they’re ready to be used as PWM duty cycles.

Like any good function, absolute_to_percentage() promotes reusability. If you need to do the same thing with data read from any other type of sensor — distance, temperature, light, or whatever — you could use the same function without any changes. The following code includes comments with the values specific to the IR sensor to make it easier to understand:

def absolute_to_percentage(distance, minimum, maximum):
distance = distance - minimum #shift the 9-80 interval to 0-70
if distance > maximum: #after 80cm (which is 70 after the shift), values start being unreliable
distance = maximum #thus, everything after the max is the max itself.
return distance * 100/maximum # this puts the measured value in terms of 0 to 100 percent
# which is what PWM works with.

Note that there should be a minimum distance that the IR distance sensor can read. The way in which you determine this distance is covered in the “Running the script to measure distance” section. For us, this distance was 9 cm, and that’s what we use in the example. You can subtract 9 from your distance measured to ensure that the minimum value is 0. Just remember that the real distance is actually that value plus the minimum (9 in this case). This subtraction makes converting the absolute value of the distance into a percentage much, much easier:

distance = distance - minimum #shift the 9-80 interval to 0-70
maximum = maximum - minimum

Afterward, you check whether the distance measured is greater than 70 (which would be more than 80 cm). Because the sensor’s datasheet shows that values read after 80 cm start being unreliable, you set your maximum as 80 cm:

if distance > maximum: #after 80cm (which is 70 after the shift), values start being unreliable
distance = maximum #thus, everything after the max is the max itself.

Finally, you return a percentage value of the distance measured (with 100 percent being 80 cm or more):

return distance * 100/maximum # this puts the measured value in terms of 0 to 100 percent

It’s important to note that the variables are swapped outside the function. We do this because variables inside a function are called local variables. These variables not only are private to the function itself, but also reset every time the function call terminates.

Otherwise, there aren’t many changes in the code you used previously for the RGB, in the “Writing the code for fading an RGB LED” section. One difference is that the duty cycle depends on distance rather than i, which, in the previous case, was a variable that increments every 0.05 second.

Running the script to fade an RGB LED with an IR distance sensor.

Save the program and start it by clicking Run or pressing F5. Move your hand or an object closer to or farther from the IR sensor, and you should see the brightness of the RGB LED changing accordingly. Its color still changes periodically, though.

What if the LED didn’t change color the color periodically? What if everything — the color and the brightness — was controlled by your hand? Sound fun? Let’s roll.

Enhancing the project

Quite a few parts of this code go beyond gluing the previous two projects together with minor changes, simply due to the fact that we wanted to do a cool thing. Without further ado, here’s what the control_LED() function for this program does.

You should save the following script in a new file. We named ours enhRGBInfraRed.py:

#!/usr/bin/python
import Adafruit_BBIO.PWM as PWM
import time
import Adafruit_BBIO.ADC as ADC
import math

#setup RGB
RGB = ["P9_16", "P8_13", "P9_14"]
#RGB[0] controls red, RGB[1] controls green, RGB[2]controls blue

for i in range(0, 3): #runs the indented code below 3 times
PWM.start(RGB[i], 0) #initialize PWM with all leads OFF

#set initial conditions for RGB
c_red = RGB[0]
c_green = RGB[1]
c_blue = RGB[2]


#setup IR Sensor
sensor = "P9_40" #or AIN1
ADC.setup()

def read_distance():
reading = ADC.read(sensor) # values from 0 to 1
voltage = reading * 1.65 #values from 0 to 1.65V
distance = 13.93 * pow(voltage, -1.15) # values from 10 to 80 cm theoretically
return distance

def absolute_to_percentage(distance, minimum, maximum):
distance = distance - minimum #shift the 10-80 interval to 0-70
maximum = maximum - minimum #the maximum value, 80cm, is now 70
if distance > maximum: #after 80cm (which is 70 after the shift), values start being unreliable
distance = maximum #thus, everything after the max is the max itself.
return distance * 100/maximum # this puts the measured value in terms of 0 to 100 percent
# which is what PWM works with.


def control_LED(distance):

if distance <= 33.3:
PWM.set_duty_cycle(c_red, 100 - distance*3)
PWM.set_duty_cycle(c_green, distance*3)
PWM.set_duty_cycle(c_blue, 0)
elif distance > 33.3 and distance <= 66.7:
distance = distance - 33.3
PWM.set_duty_cycle(c_green, 100 - distance*3)
PWM.set_duty_cycle(c_blue, distance * 3)
PWM.set_duty_cycle(c_red, 0)
elif distance > 66.7:
distance = distance - 66.7
PWM.set_duty_cycle(c_blue, 100 - distance*3)
PWM.set_duty_cycle(c_red, distance*3)
PWM.set_duty_cycle(c_green, 0)

while True:
distance = read_distance()
distance = absolute_to_percentage(distance, 9, 80)
print(distance)
if(distance > 0): #this happens like once in a million, if at all, but the program stops when it happens. And at 1GHz, a million is not so little!
control_LED(distance)
time.sleep(0.05)

Everything that deals with distance readings is exactly the same. The function that controls the LED, however, has changed significantly:

def control_LED(distance):

if distance <= 33.3:
PWM.set_duty_cycle(c_red, 100 - distance*3)
PWM.set_duty_cycle(c_green, distance*3)
PWM.set_duty_cycle(c_blue, 0)
elif distance > 33.3 and distance <= 66.7:
distance = distance - 33.3
PWM.set_duty_cycle(c_green, 100 - distance*3)
PWM.set_duty_cycle(c_blue, distance * 3)
PWM.set_duty_cycle(c_red, 0)
elif distance > 66.7:
distance = distance - 66.7
PWM.set_duty_cycle(c_blue, 100 - distance*3)
PWM.set_duty_cycle(c_red, distance*3)
PWM.set_duty_cycle(c_green, 0)

This part of the code runs the show. This an enhanced version of the control_LED() function receives a value of 0 to 100 to set the PWM of the pins that control the RGB and decides how they’re used.

This function could be written in many ways to produce different color effects with the RGB. In this case, the LED fades from one color to the next, depending on the distance from an object. If you place your hand near the sensor and move it away slowly up to 80 cm or more, you should see the LED fade from red to green to blue to red again.

You divide the 0-to-100 interval by 3 so that only two colors are active at any interval. What happens for each interval is decided by if and elif statements. The first 0if checks whether the distance measured is less than 33.3 percent of 8 cm. If so, blue is off, and the LED fades from red to green gradually:

if distance <= 33.3:
PWM.set_duty_cycle(c_red, 100 - distance*3)
PWM.set_duty_cycle(c_green, distance*3)
PWM.set_duty_cycle(c_blue, 0)


Creating permanent connections

If you enjoyed the projects provided throughout this chapter, you may be interested in creating something more permanent than the prototypes you've built with the breadboard. To do so, you need to know how to use a soldering iron. You can learn more about working with a soldering iron at www.dummies.com/extras/beaglebone.


The next two chunks of code do the same thing for the remaining intervals:

elif distance > 33.3 and distance <= 66.7:
distance = distance - 33.3
PWM.set_duty_cycle(c_green, 100 - distance*3)
PWM.set_duty_cycle(c_blue, distance * 3)
PWM.set_duty_cycle(c_red, 0)
elif distance > 66.7:
distance = distance - 66.7
PWM.set_duty_cycle(c_blue, 100 - distance*3)
PWM.set_duty_cycle(c_red, distance*3)
PWM.set_duty_cycle(c_green, 0)

Note that you always shift the distance reading to a value of 0 to 33 (percent) — so that you are always working with the same values, making the code simpler — but you multiply it by 3 so that the PWM duty cycle that it sets is still 0 to 100 (percent).

Running the script for the enhanced version to fade an RGB LED with an IR distance sensor

Save and run the script, and experiment! Feel free to alter the code — namely, the duty cycles of the PWM — and save and run it again to see different results.

For fun, you could also try to change the RGB LED program to choose its color and/or brightness depending on the temperature readings.

Introducing UART

UART, which stands for universal asynchronous receiver/transmitter, is a well-known, commonly used way for different devices to communicate through serial. Many of UART’s parameters, such as the data format and speed of transmission (baud rate, which is the same as bits per second), are configurable, which is why universal is part of its title.

Devices communicate through the use of RX (receive) and TX (transmit) pins. To make two devices send data to each other, you merely need to cross these pins: One device’s RX connects to the other device’s TX, and the first device’s TX connects to the second’s RX. The process is quite intuitive: You wire the pin that transmits the data of one device to the pin that receives data of the other device.

Wiring the BeagleBone to an UART device

The BeagleBone features five serial UARTs, although UART0 is reserved for communication with the computer (if you connect it through USB, that is). Also, UART3 features only a TX pin. People often say that the BeagleBone actually has 4.5 serial UARTs for this reason.

As stated in the preceding section, you want to cross the TX and RX pins of each device. Also, the device you’re connecting to the BeagleBone needs to be powered, usually requiring a supply of 3.3V or 5V, and a GND pin that needs to be connected. So to use the BeagleBone’s UART1, for example, you make the connections shown in Table 10-3.

Table 10-3 Connecting the BeagleBone’s UART1 to a device

BeagleBone

Device

P9_24 (UART1_TX)

Device’s RX pin

P9_26 (UART1_RX)

Device’s TX pin

P9_7 or P9_8 (5V through USB) or P9_5 or P9_6 (external supply) for a 5V device. P9_3 or P9_4 for a 3.3V device.

Device’s 5V or 3.3V power supply

P9_1, P9_2, P8_1, or P8_2

Device’s GND pin

If you use a 5V device, be extremely careful with your wiring! Feeding 5V wires into the BeagleBone will severely damage it.

To work with and test UART communication on the BeagleBone, you’ll be using two of its serial UARTs: UART1 and UART2. If you pretend that UART2 is another device altogether, you can easily use UART1 to write into it (see Figure 10-8). The wiring is as follows:

· Connect P9_24 (UART1_TX) to P9_22 (UART2_RX).

· Connect P9_26 (UART1_RX) to P9_21 (UART2_TX).

Figure 10-8: UART communication established on a BeagleBone Black.

Writing the code to test UART

To verify that communication is happening, you create two programs and run them at the same time. The programs are very similar; the difference is that one deals with UART1 and the other with UART2. We named our programs UART1_test.py and UART2_test.py.

Before you get into coding, make sure that you have the necessary Python library installed. Type the following code in the command line:

pip install pyserial

The code for UART1_test.py is the following:

import Adafruit_BBIO.UART as UART
import serial
import time

UART.setup("UART1")

ser1 = serial.Serial(port = "/dev/ttyO1", baudrate=9600)

ser1.close()

ser1.open()

while True:
if ser1.isOpen():
ser1.write("This is a message from UART1!\n")
rxbuf = ser1.readline()
print(rxbuf)
time.sleep(0.05)

The code for UART2_test.py is very similar:

import Adafruit_BBIO.UART as UART
import serial
import time

UART.setup("UART2")

ser2 = serial.Serial(port = "/dev/ttyO2", baudrate=9600)

ser2.close()

ser2.open()

while True:
if ser2.isOpen():
ser2.write("This is a message from UART2!\n")
rxbuf = ser2.readline()
print(rxbuf)
time.sleep(0.05)

As usual, the code starts with importing libraries. This time, you define an object named UART and initialize it with the serial UART that you’ll be using (either 1 or 2):

UART.setup("UART1")

Next, you create a variable named ser1 that actually serves as an object (a variable that contains multiple fields):

objectName.field1
objectName.field2
objectName.field3

That variable saves the value returned from a function:

ser1 = serial.Serial(port = "/dev/ttyO1", baudrate=9600)

The function takes the following parameters:

· port: The serial UART that you’re using. After using UART.setup(“UART#”), you create a file in the /dev directory. This file is always /dev/ttyO#. Note that the filename contains the letter O, not the digit 0.

· baudrate: The speed at which you want to establish the communication. The BeagleBone supports the following baud rates:

· 9600

· 14440

· 19200

· 28800

· 38400

· 56000

· 57600

· 115200

If you have two devices operating at two different baud rates, the communication won’t work! You can test this fact by giving different baud rates to UART1_test.py and UART2_test.py. Most of the time, it’s easier to alter the baud rate of the BeagleBone’s UART than it is to change the device’s baud rate.

If you have issues with communication, try lowering the baud rate.

Next, you close the serial port to reset it (in case it was used previously and data was still inside) and then reopen it:

ser1.close()

ser1.open()

Then comes the while True: loop, in which each UART writes a message to its TX pin and reads a message from its RX pin. This message is saved in the rxbuf variable. Finally, you print the message that was read from the RX pin.

In computer science, a buffer is often a block of memory used to save data temporarily, which is why we call the variable rxbuf.

Notice two important details in this last section of the code:

· if ser1.isOpen(): If nothing wrong happened, ser1.isOpen() is the same as True, so that if will happen all the time. If something went wrong with accessing the serial port, however, ser1.isOpen() holds False, so it ensures that the program won’t do anything.

· ser1.write("This is a message from UART1!\n"): The \n stands for newline — a special character that represents pressing the Enter key on your computer keyboard. Without this character, the program wouldn’t work, because rxbuf = ser1.readline() reads data until it finds \n — that is, it reads an entire line. For this reason, the message you send requires \n. Without that character, all data would be sent on the same line, and this function would stay blocked forever because it would never find the \n.

Running the script to test UART

Select each script, and press F5 or click Run after saving. Nothing happens if you run just one script; it blocks at the readline() function, waiting for a message. When you run the two scripts, you see the messages being printed. This is a message from UART1! is printed in UART2’s program (see Figure 10-9), and This is a message from UART2! is printed in UART1’s program.

Figure 10-9: The UART2 program receiving a message from the UART1 program.

Feel free to experiment with other baud rates, although you won’t notice the change immediately because the programs have the time.sleep(0.05) function slowing things down. If you increase the baud rate, data is transmitted faster.

Understanding UART's uses

Simply put, UART is awesome. It’s simple and asynchronous, allowing for fast communications without much effort on your part.

Many devices communicate through UART. The BeagleBone, for example, communicates this way with your computer. Other examples include GPS modules, wireless modules (such as Bluetooth and Wi-Fi), and some sensors that are more complex than analog ones that simply relate data to a voltage level.

If you wired the BeagleBone to a GPS module, for example, you could easily read all the information it provided — normally, much more than merely longitude and latitude — with code very similar to the code in the “Writing the code to test UART” section. The only differences are that you want only to read from it, and you have to change the baud rate to make it the same as the GPS’s:

import Adafruit_BBIO.UART as UART
import serial
import time

UART.setup("UART1")

ser1 = serial.Serial(port = "/dev/ttyO1", baudrate=9600) #change according to the GPS's baudrate

ser1.close()

ser1.open()

while True:
if ser1.isOpen():
rxbuf = ser1.readline()
print(rxbuf)
time.sleep(0.05)