< back

Week 9: Input Devices

DIY Ecototem

November 23, 2015


Well, I'm inevitably back to bicycles. During my year in the Netherlands I spent quite a bit of time reading about different ways of measuring bicycle activity. I learned that beyond commuter surveys, bicycle counters like the Ecototem are the state of the art. (I should note that there are a number of up-and-coming projects that are trying to take a more distributed, sensor-based approach, but as far as I'm aware, these are mostly experimental/ small-scale efforts right now). While the Ecototem - or similar bike counters - is certainly a net positive for cities (it provides good longitudinal data for a single site, and it raises awareness about cycling), I've always been of the opinion that it doesn't do enough for the price. For a price of $20,000 to $30,000, the Ecototem only keeps track of one type of data, in only one place. Ultimately, I don't think these counters provide data that is geographically distributed enough to be particularly interesting or useful.

Given these thoughts, I thought it would be interesting to try to make a "cheap and dirty" bike sensor that could be installed in multiple locations. I plan to use a capacitive touch sensor to detect the bike, as well as a sonar distance sensor. I also plan to use Bluetooth communication to communicate sensor readings to a computer or phone (though this functionality can be added in later if necessary). Last week I spent some time learning about capacitive touch sensing and Bluetooth, and I figured I could use some of Neil's boards as guidelines. One worry I have up front is that a bicycle will not be enough of a reflective surface for the sonar sensor to accurately capture...but I will cross that bridge when I get there! To start, I designed a new board in Eagle (using tips and tricks from Week 5).

This board was, thankfully, much easier to lay out and route than last week's. I combined elements from Neil's loading capacitive touch board and the sonar distance sensor circuit. I also used 1k pull-up resistors so that I could reuse the MISO and MOSI pins on the ATTiny45 (it was hard to get clear information on this technique, but it seems like the resistor will basically isolate your output functionality while you are using MISO/ MOSI to program the board). I cleaned up the board, which included removing the extra traces for the sonar header. Now to mill, stuff, program, and test!

Milling and stuffing went relatively well and quickly. I used the Modela MX-20 (the one of the left in the CBA shop) and got a mediocre, but passable, board. The board had a lot of burrs, and not particularly clean traces, but I figured it would get the job done. I spent some time "de-burring" it with a ruler and water. I also was pleased that I figured out the board cut-out issue that plagued me in Week 5. I realized that the size of the png images for the traces and the board come from the dimension in Eagle, which needs to be adjusted appropriately around the traces. The png images need to be exactly the same size and the position of the board and the traces should match up between the images.

After stuffing the board, I decided to test the different sensor functionalities separately to make sure they were working individually. I downloaded Neil's sonar code and capacitive touch sensor code and modified them to use the pins I was using. I used the avr-gcc toolchain, as in past weeks, and was able to successfully program my board. The sonar sensor worked pretty well (see video below), though it's certainly somewhat finicky in that it requires a flat, non-reflective surface. I'll be interested to see how/ if this actually works with a bicycle.


I had a little more trouble getting the capacitive touch sensing to work. It was not intuitive to me from Neil's documentation (or others I found on the fab site) how I should connect my board to the capacitive touch sensor. I tried a few different configurations, and found that when I just had the "sense" pin connected to the sensor, and nothing else, I would see changes in the reading. After a bit more investigation (the PSoC CapSense Design Guide - thanks Eric! - and Matt Keeter's Capacitive Multitouch page were both helpful), I became more comfortable with the idea of just using a single wire. The capacitor that is formed with your finger and the sensor pad is grounded through your body. You would only really need to use the "shield" electrode if you were worried about water droplets affecting the sensing.

[Update 11/25/15: I asked this question on the class listserv, and got the following reply from Neil: "I recommend using transmit-receive, in which you control both sides, rather than loading, which relies on room ground. Either way, there's an output pin for the drive, and an input pin for sensing. The shield connection is only if you need a driven shield for a long cable run, but it's much better to the put the processor at the electrode. And the ground is just a convenience for testing and calibration, to apply known loads." At this point, I'm too far into this project to switch to using the Tx-Rx board, but this is good information to keep in mind for my final project.]

Even though I think I have the correct setup now, the readings from the touch sensor do seem inconsistent and/ or finicky. For example, the range of the readings changes depending where the sensor is placed, and the readings only seem to range from about ~200 to ~500. One resource I looked at also suggested have a small capacitor between the sensor and ground, to help smooth out readings. Perhaps I will try that next time...


Now that I know that both sensors are working, I will need to find a threshold for detecting a bike using each sensor, integrate the code for the two sensors, and modify the GUI to "count bikes" instead of just displaying readings.

Capacitive touch sensor: After testing, for the "charge delay 1" reading, the sensor seems to detect a bike when it drops from a reading of ~405-407 to ~395-400. This reading is carried out with the sensor placed on the carpet and covered by a single sheet of printer paper.

Sonar sensor: I placed the sonar at a height of ~6 inches. The sensor reading (with no bike) is >100 cm. When the bike passes by, the reading jumps down to < 100 cm. The sensing of the bike is noticeable though variable; it jumps around because the sonar presumably detects parts of the bike at different distances. If the bike were passing by at a different distance, I think the readings would be higher. For the time being, I think < 100 cm is a safe threshold because bikes will have to pass over the capacitive touch sensor anyways. In a real-life situation, the threshold difference might be the width of a bike lane.

I combined Neil's sonar sensor code and capacitive touch sensor code into a new program that reads and sends readings from both sensors. The capactive sensor uses the A/D converter, and the sensor reading just uses a timer. I also combined his Python sonar sensor GUI and capacitive touch sensor GUI into a GUI that displays one capacitive touch reading, one sonar reading, and the number of "bikes" that have passed the sensor. I calculate the bike count with the following:

 # Bike count calculation and canvas
   if filter1 < cap_thresh and cm < sonar_thresh:
      reading_cnt += 1
      if reading_cnt == READ_TIME:
         bike_cnt += 1
         reading_cnt = 0

That is, if the readings are below the threshold values for a certain number of readings, I count that as a bicycle. The threshold values can be easily changed based on the sensor setting. This is admittedly extremely low-resolution, poorly calibrated, and probably error-prone...but I think it's a good start given the constraints of this project. You can find my C code here and my GUI code here.

I am still trying to debug one error where my sonar reading gets stuck on the value "14". It looks like this is happening when the "high" reading is 255. I think this probably has to do with either the counter maxing out, or some sort of weird communication glitch related to timing. More investigation to come...


Design Files & Code