River Sensor.

A group at the Oxford Hackspace would like to set up some sensors to monitor the height of the rivers around Oxford (which recently flooded). There are already a few monitors, but we'd like to supplement them and also develop a more generic distributed sensor system.

For our initial river height monitors I'm doing some prototyping using an mbed, Vodafone 3G dongle and a Seeed ultrasound range finder. The sensor needs to do the following:

  • Take regular measurements of the height of the river
  • Take regular measurements of the battery voltage
  • Buffer these data
  • Regularly connect to the 3G network and send the data to a remote server
  • Connect to the server to update any configuration (measurement/reporting frequency, etc)

The main constraints on the sensor are are production cost, running cost, and power consumption. I have a goal of the sensor running for a month on a single battery pack and costing £100 to construct and run for a year.

Breadboard Prototype

I've got a prototype system up and running. The hardware is pretty simple. The mbed connects to a USB socket breakout board, with the 3G dongle connected. This is powered by a 9 V battery via a 5 V regulator. The seeed ultrasound rangefinder and a potential divider on the battery line are also connected to the mbed to take measurements.


The software is pretty simple. The measurements are made and stored in an array (as are timestamps). The 3G is periodically connected and then the data is sent to a remote server as a UDP package with a data payload of the form "id=<sensor name>,time=<timestamp>,height=x,battery=y". I've configured a server so that it will dump these into a mongo databse. The data is stored as a document with an id, time and a map(string->float) of the data. So as long as I send an id and time I can also send any arbitrary data. Using UDP is attractive since the sensor can just fire off the data. It doesn't have to spend time waiting for acknowledgement from the server, and won't go screwy if the connection fails. Each data point is non critical, so it doesn't matter if there is a small rate of package loss.

Import programriversensor

A remote sensor to measure the height of a river and send the data using UDP over 3G.

Server code (in Go):

package main

import "fmt"
import "net"
import "strconv"
import "strings"
import "labix.org/v2/mgo"

type Datastuff struct {
    Identifier  string
    Time        int64
    Data        map[string] float64

func main() {
    localaddr, err := net.ResolveUDPAddr("udp", "serverurl:989812")
    con, err := net.ListenUDP("udp", localaddr)
    if err != nil   {
    data := make([]byte, 1024)
    for {
        n, addr, err := con.ReadFrom(data)
        fmt.Printf("Handling connection from %v\n", addr)
        if err != nil   {
        if (n > 0)  {
            datastr := string(data[:n])
            parts := strings.Split(datastr, ",")
            stuff := map[string] float64{}
            dataid := ""
            time := int64(-1)
            for _, p := range(parts)   {
                x := strings.Split(p, "=")
                if len(x) == 2  {
                    id := x[0]
                    if id == "id"   {
                        dataid = x[1]
                    }   else if id == "time"    {
                        value, err := strconv.ParseInt(x[1], 10, 64)
                        if err == nil   {
                            time = value
                    }   else    {
                        value, err := strconv.ParseFloat(x[1], 64)
                        if err  == nil  {
                            stuff[id] = value
                        }  else  {
                           fmt.Printf("Erro converting %v, %v: %v\n", id, x[1],err)
            if dataid != "" {
                if time != int64(-1)    {
                    ds := Datastuff{dataid, time, stuff}
                    fmt.Printf("Storing %v\n", ds)
                    mgoserver := "localhost"
                    session, err := mgo.Dial(mgoserver)
                    if err != nil   {
                    defer session.Close()
                    measurements := session.DB("test").C("testmeasurements")
                    if err = measurements.Insert(ds); err != nil    {

I haven't implemented a system for the server to configure the sensor yet, but I think I might use a TCP socket.

I haven't done any serious tests yet, but this hardware will only run on battery power for a short time (a couple of hours, say). I need to add in a transistor to power down the 3G dongle while it's not doing anything and think about power consumption in the mbed too.

The basic hardware costs are:

  • mbed - £40
  • 3G dongle - £25
  • ultrasound sensor - £10

Running costs are ~ £5/mn + battery

So a basic estimate of a cost for the year is £150.

Please log in to post comments.