How To: Setup a Sensorpedia Sensing Station (guide 1) 2 Comments
What is Sensorpedia without sensors? This article will be one of a series that detail how to talk to a few different types of sensors, calibrate their data, and interface them with Sensorpedia.
These are the sensors we will be connecting (this guide will focus on reading the LM34 analog temperature sensor):
- Irradiance (digital)
- Relative Humidity and Temperature (digital)
- Temperature (analog)
- Barometric Pressure (digital)
- Light Color (digital)
- Distance (digital)

One of the preferred data formats for Sensorpedia is GeoRSS. Simply put, a GeoRSS feed contains entries of data readings tagged with a specific time and spatial location. We can serve RSS or GeoRSS feeds to Sensorpedia, but first we need to have data to display in the feed. Since we can’t plug little sensor PCBs straight into the back of a server, we will need a bit of infrastructure to calibrate and relay the data. An ARM microcontroller board designed for the DIY/tinkering crowd called the Make Controller (henceforth referred to as “MC”) will serve as a middleman and communicate with a host server computer and the various sensors. It can poll analog sensors, digital sensors, control TTL, communicate via USB and Ethernet, and even control servos. The MC is a powerful little device.

Since Sensorpedia is designed to work with data wrapped as RSS or GeoRSS, we’ll need a server that can gather sensor readings, calibrate the data, and render them as an RSS file. Rather than output the RSS ourselves, we will just have our server gather sensor readings and post them to Twitter, which will in turn provide an RSS feed of each reading we send. Rather than having the MC act as a server itself–an option ideal for doing things like deploying sensor stations– we will be using a host computer to control the MC and post the data. This is a bit easier, as we can implement the server in Python. We will still need to program the MC itself for certain sensors, for a reason to be described in a later guide. Serving RSS directly will also be covered in a later guide.
We will be issuing OpenSound Control Commands over USB to control the MC. These commands are simple to issue, and are an easy way to poll and set pins, read in the A/D, and control fundamental board actions. They are specially-constructed messages that request certain addresses on the MC. We will use SimpleOSC to allow us to send OSC messages. Since the Make Controller is visible to the computer as a virtual serial port, we will also need the PySerial module to handle serial communication.
OSC addresses are constructed like this:
/subsystem/device/property
For example, the address used to set the state of the first LED of the zeroth-indexed array of onboard LEDs would look like this:
/appled/0/state 1
Using OSC commands, we can query the binary state of any of the digital inputs, and the value of the current voltage on any of the analog inputs. There are a few more commands, but we are essentially limited to querying state (once again, more on complex operations in a later guide). This first example will connect our analog temperature sensor, the LM34, and get its value from Python. First, we need to figure out how to connect it. The MC has quite a few inputs and outputs, and they are shown below (image from makingthings.com). The inputs can function as analog or digital inputs, while the outputs are strictly digital (Though they do support PWM.)

We will wire it up to one of the analog inputs as shown below (image from makingthings.com)

With the LM34 connected, we can use a small Python script to read in the value and output the corresponding temperature in degrees Fahrenheit. (Thanks to Oliver Smith at makingthings.com for the example from which this is derived)
import os
import sys
import time
import threading
import osc # simpleosc
import serial # pyserial
COM_PORT = '/dev/ttyACM0' # set this to the serial port to which the Make Controller is connected, something like "COM0" for windows or "/dev/ttyACM0" for POSIX
SLIP_END = '\xC0' #end of an OSC message with SLIP wrapping (USB only)
SLIP_ESC = '\xDB' # used to escape embedded OSC messages
class Lm34Read(object):
def __init__(self, comPortId):
self._initializeSerial(comPortId)
self._inBuffer = ''
def _initializeSerial(self, comPortId):
self._serial = serial.Serial(comPortId, 115200, timeout = 0) # open the virtual serial port created by the Make Controller's USB interface
def _write(self, address, value = None):
m = osc.OSC.OSCMessage() #create a new OSC messsage
m.setAddress(address) #set the address to the one specified by the parameter
if value is not None: # if we are passing a param along with the address...
m.append(value)
s = str(m).replace(SLIP_END, SLIP_ESC + SLIP_END) # escape any embedded SLIP_END characters in the message
self._serial.write(SLIP_END + s + SLIP_END) # begin and end with SLIP_END; doesn't seem to work otherwise
def _read(self):
if self._serial.inWaiting():
for c in self._serial.read(500): # read 500 bytes, or as much as is in the buffer
if c == SLIP_END and (len(self._inBuffer) == 0 or self._inBuffer[-1] != SLIP_ESC): #if the EOM char is in the message, and the buffer is empty or the last buffer char is not an escape character
self._handleInput() #process the data
else: #otherwise
self._inBuffer += c # append what was just read to the buffer
def _handleInput(self):
message = osc.OSC.decodeOSC(self._inBuffer) #decode the message and make an array of it
if len(message) != 0: #if the message is present
print str(message[2]*0.3222)+" degrees F"#print our temperature
self._inBuffer = '' #wipe the serial buffer
def run(self):
self._write('/analogin/0/value') #send a message requesting the value of the zeroth analog input
time.sleep(0.5) #give the Make Controller a chance to poll and respond (value in seconds)
self._read() # check for any new messages from the Make Controller
t = threading.Timer(1, self.run).start() #make a new timer to run 1 second after this function finishes execution
if __name__ == "__main__":
app = Lm34Read(comPortId = COM_PORT)
t = threading.Timer(1, app.run) #setup a timer to fire after 1.0 second
t.start() #start the timer
This will output the temperature each second:
71.5284 degrees F
71.5284 degrees F
71.2062 degrees F
71.5284 degrees F
71.5284 degrees F
71.5284 degrees F
71.5284 degrees F
71.5284 degrees F
71.5284 degrees F
To figure out how to calculate the temperature, we need to calculate the gain. This value is merely a scaling factor that adjusts the output temperature value as a function of the precision of the A/D and the supply voltage to the LM34. We can calculate the gain as follows:
The MC has a 10-bit analog-to-digital (A/D) converter. This means that it can represent input voltages as
discrete levels, from 0 to 1023. Since the SAM7 ARM microcontroller on the MC operates at LVTTL voltage levels, it expects a maximum of 3.3[V]. This means we should set the
jumper to supply 3.3[V] to LM34, just to be safe. The image below shows the jumper position for 3.3[V] (image from makingthings.com).

Since the LM34 is designed to operate with a range of 0-5[V] and we will only be giving it 3.3[V], we will be unable to measure higher temperatures than about 200 [°F]. This is perfectly acceptable for measuring ambient room temperature. Now that we know the supply voltage and the number of values the A/D can output, we can figure out how to calculate the incoming voltage:
![]()
Each increase in A/D value represents an increase in voltage of 3.22[mV]. The LM34′s responsivity is
. Knowing both the input voltage and the sensor responsivity, we can find the temperature in [°F] from a given A/D value; we just need to calculate the gain. Since the LM34 is factory-calibrated, this value should be pretty accurate.
For an example, let’s calculate the current room temperature when the A/D outputs a value of 229:
![]()
Now let’s do something fun: Make our Python script update Twitter with the Sensorpedia lab’s current temperature. We will need to import two new Python modules, python-twitter and its dependency, simplejson. From here we are a simple few lines away from tweeting:
We’ll import the modules:
import simplejson #simplejson
import twitter # python-twitter
Make a Twitter API object:
twitterObj = twitter.Api("username", "password")
Set up the tweet:
temperature = "It is "+str(message[2]*0.3222)+" degrees F in the Sensorpedia lab."
twitterObj.PostUpdate(temperature)
All together, it looks like this:
import os
import sys
import time
import threading
import osc # simpleosc
import serial # pyserial
import simplejson #simplejson
import twitter # python-twitter
COM_PORT = '/dev/ttyACM0' # set this to the serial port to which the Make Controller is connected, something like "COM0" for windows or "/dev/ttyACM0" for POSIX
SLIP_END = '\xC0' #end of an OSC message with SLIP wrapping (USB only)
SLIP_ESC = '\xDB' # used to escape embedded OSC messages
class Lm34Read(object):
def __init__(self, comPortId):
self._initializeSerial(comPortId)
self._inBuffer = ''
def _initializeSerial(self, comPortId):
self._serial = serial.Serial(comPortId, 115200, timeout = 0) # open the virtual serial port created by the Make Controller's USB interface
def _write(self, address, value = None):
m = osc.OSC.OSCMessage() #create a new OSC messsage
m.setAddress(address) #set the address to the one specified by the parameter
if value is not None: # if we are passing a param along with the address...
m.append(value)
s = str(m).replace(SLIP_END, SLIP_ESC + SLIP_END) # escape any embedded SLIP_END characters in the message
self._serial.write(SLIP_END + s + SLIP_END) # begin and end with SLIP_END; doesn't seem to work otherwise
def _read(self):
if self._serial.inWaiting():
for c in self._serial.read(500): # read 500 bytes, or as much as is in the buffer
if c == SLIP_END and (len(self._inBuffer) == 0 or self._inBuffer[-1] != SLIP_ESC): #if the EOM char is in the message, and the buffer is empty or the last buffer char is not an escape character
self._handleInput() #process the data
else: #otherwise
self._inBuffer += c # append what was just read to the buffer
def _handleInput(self):
message = osc.OSC.decodeOSC(self._inBuffer) #decode the message and make an array of it
if len(message) != 0: #if the message is present
temperature = "It is "+str(message[2]*0.3222)+" degrees F in the Sensorpedia lab."
twitterObj.PostUpdate(temperature)
print temperature#print our temperature
self._inBuffer = '' #wipe the serial buffer
def run(self):
self._write('/analogin/0/value') #send a message requesting the value of the zeroth analog input
time.sleep(0.5) #give the Make Controller a chance to poll and respond (value in seconds)
self._read() # check for any new messages from the Make Controller
t = threading.Timer(600, self.run).start() #make a new timer to run 1 second after this function finishes execution
if __name__ == "__main__":
app = Lm34Read(comPortId = COM_PORT)
twitterObj = twitter.Api("username", "password")
t = threading.Timer(1, app.run) #setup a timer to fire after 1.0 second
t.start() #start the timer
Now we can view the current temperature in the twitterstream:
Since Twitter provides an RSS feed, we can import these readings straight into Sensorpedia!
