Monthly Archives: May 2013

Geiger Counter

My last project is a über-cool Geiger-Muller Counter.

My Geiger Counter

Final box, with a LCD showing the last average CPM every 6 secons and sending the info to the server every minute…

Hardware: Radio Hobby Store Geiger Counter Radiation DIY Kit (second edition)

Some weeks ago I suffered a radioactivity fever, so to speak. I backed the APOC Mini Radiation Detector at Kickstarter and also bought a Geiger Counter Radiation Detector DIY Kit from Radio Hobby Store at Ebay. The former has finished the funding with more than 11 times the pledged amount. The later arrived home some 10 days ago, so I just started playing with it.

Geiger Counter Radiation Detector DIY Kit by Radio Hobby Store

Geiger Counter Radiation Detector DIY Kit by Radio Hobby Store

The kit comes unassembled but every part is through hole and really easy to solder. The kit contains everything to get a basic Geiger Counter except for the SBM-20 Geiger-Muller tube, but those are easy to find at Ebay also and mine arrived just one day after the kit. Once assembled you get a Geiger counter that can be powered with 5V through USB or a terminal block and it beeps and flashes a LED every time a beta o gamma particle enters the tube… But, you also get a VCC and GND pins and an interrupt pin (labelled INT) to power and monitor the counts with your favourite controller. And that’s fun!

To build the kit follow the seller’s advice: take your time and enjoy. It has a bunch of parts but none is too hard to solder. It took me about an hour. The only problem I had was with IPA. IPA, or Isopropyl Alcohol (C3H7OH), is used to clean electronic boards and components. The people at Radio Hobby Store emphasize the use of IPA after soldering to wash any flux or any other potentially problematic residue since the board uses high voltage (~400V). Even thou my board was quite clean after the soldering I followed their advice.

It took me a couple of phone call and a one hour trip to get a bottle of IPA 99% in Barcelona… I’ve read you can find the in some drugstores but the one I was after had a a spray which I found very convenient. So I applied the IPA and is was a mess. I ended up with a cover of metal (?) dirt all over the board… It took me a while to clean it up again and check that nothing was desoldered or disconnected. I don’t know what happened but it was completely unexpected. My guess is that it had something to do with the type of solder I use (lead-free), but again I don’t know.

I need to know more about what IPA is useful for and how it actuates before trying it again. Alcohols might not be that dangerous but playing with chemicals requires a deeper understanding of what you are doing.

Anyway, after this trouble the board worked as it should. I calibrated the blue pot to get around 400V across the Geiger tube, switched it off, unplugged, installed the tube and plugged it again. Then, with an imaginary sound of drums, I switched it on and it began beeping! Yes!

Hardware: The Controller

I prototyped the counter with an Arduino Pro Mini and a Sparkfun Serial Enabled 16×2 LCD which uses simple serial commands to write characters on the LCD. Everything is 5V except for the Arduino but the LCD works with 3V3 TTL signals so no problem.

The first prototype was really easy to assemble. I had it working in less than half an hour, including a first version of the code to count and display the data on the LCD.

Geiger Counter Prototype with an Arduino Pro Mini

Geiger Counter Prototype with an Arduino Pro Mini

The first evolution was to substitute the Arduino Pro Mini with a bare ATmega328P, the very same micro but in a cheaper and bulkier package. I prototyped this second version in a breadboard adding the XBee. Now, the ATmega328P is 5V but the XBee is only 3V3. A TSC295033 linear voltage regulator lowers the voltage to 3V3 to power the radio and a diode and a pull-up resistor protect de DIN line. When the input is LOW the diode is transparent and the DIN pin of the radio sees the LOW and the resistor is dissipating ~10mW. When the input is HIGH (5V) the diode blocks the current and the resistor pulls up the line to 3V3.

I used a Zener in the first prototype and took the picture below before realising my mistake and replaced it with a 1N5819 Schottky diode. The Zener was a BZX85C 3V3, so it was permanently in avalanche breakdown. In fact you can use a Zener but in a different configuration, check Rob Faludi’s post about Xbee level shifting.

Level shifting is a great topic to learn basic stuff about electronics. Whenever there is a question on any forum about this there are tens of different answers. Just give a try to some of them!

The final prototype with a bare ATmega328P

The final prototype with a bare ATmega328P (note the fail: the diode in the DIN line of the XBee has to be a Schottky, not a Zener!)

Eagle schema

Eagle schema

This is the first project where I use this level shifting technique. I had used the simple resistor divider in other projects before (like the Rentalito) but the resistors slow down the signal and can be a problem when using higher baud rates. Also, my first idea was to use the XBee internal pull-ups for level shifting instead of an external one but finally I opted for the second option because the 30K pull-up was too high and resulted in a less than 3V HIGH value in the DIN input. A 1K2 external resistor solved this problem and removed the dependency on configuration.

Finally I moved everything to a stripboard. To design the stripboard I used VeeCAD, a stripboard editor, and it really helped me. There was little room inside the box and my first design was too big. It would have been a nightmare to erase and redraw everything several times in paper but in the computer everything was simpler and I could play with different designs until I found the one that was both clean and small. The free version is good enough to design anything on a stripboard but the commercial version (26.26 USD) adds some goodies that can make the difference: color, net tracing and the ability to place elements diagonally.

But, I made a mistake. I crossed the RX and TX lines between the controller and the FTDI header and I didn’t realize it until I tried to reprogram the chip. Anyway it was easy to fix and in the layout below, generated with VeeCAD, this mistake has been fixed.

Stripboard layout (powered by VeeCAD)

Stripboard layout (capture from VeeCAD). The RX and TX lines between the ATmega328P and the FTDI header are right

The real thing, note the fix for the RX/TX mistake:

The real thing

The controler board with the ATmega328P and the XBee. Note the green cable I used to fix the RX/TX error.

Hardware: The LCD

Sparkfun’s Serial LCD is really easy to use, but I wanted to give a chance to some cheap LCDs and I2C serial boards I had recently bought at Ebay. I had already done some tests the night I received them. The seller provides a library and some sample code but I was not able to make it work and I quitted to go to bed.

So this was a second chance to make the think work. The boards I had bought to drive the LCD were I2C serial interface boards (just search for “IIC/I2C/TWI/SP​​I Serial Interface Board Module” at Ebay). These boards use a PCF8574, an 8 bit I/O expander with I2C interface, basically it lets you drive the LCD with just 2 wires for power and ground and 2 more for data (SDA) and clock (SCL).

IIC/I2C/TWI/SP​​I Serial Interface Board Module

IIC/I2C/TWI/SP​​I Serial Interface Board Module bought at Ebay. The solder job could have been better…

None of the libraries for Arduino I tested worked with the board. After googling a bit I found a thread on the Arduino Forum where a user (Riva, thanks!) had found out that the connections were not what the library he was using expected. So I grabbed the tester, put it in continuity mode, and checked what connections led where. The library I wanted to use (NewLiquidCrystal) has a constructor where you can explicitly define the pins so I just instantiated my LCD object with the right pin assignments and voilà.

The initialization code for the LCD is as follows:

// Thanks to Riva for pointing out the wrong pin order
// 0 -> RS
// 1 -> RW
// 2 -> EN
// 3 -> LED
// 4 -> D4
// 5 -> D5
// 6 -> D6
// 7 -> D7
// Constructor with backlight control
// LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw, uint8_t Rs,.
//                  uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
//                  uint8_t backlighPin, t_backlighPol pol);

LiquidCrystal_I2C lcd(0x20, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

Hardware: The Box

I happened to have the perfect box for this project. It is transparent, elegant and everything fits inside like if it was designed for the project. The only trouble was finding a way to place the cables so they do not cover the tube or the radio antennae.

Everything fits nicely in the box

Everything fits nicely in the box


The code is very simple. There are only a couple of things worth noticing: the LCD connection mentioned before and the ring buffer implemented to store partial readings. The reason for the ring buffer is that I wanted to update the display more often than once every minute with a “moving sum” of counts.

Basically there are 10 cells that store partial counts. Every 6 seconds the code stores the current pulses count value in a cell of the ring, overwriting the previous value. So the sum of the cells values is the count value for the last 60 seconds. To avoid having to sum all the cells on every update, the sum gets updated before pushing the new value to the cell by subtracting the current value for that cell and adding the new one.

// calculate the moving sum of counts
cpm = cpm - ring[pointer] + pulses;

// store the current period value
ring[pointer] = pulses;

// reset the interrupt counter
pulses = 0;

// move the pointer to the next position in the ring
pointer = (pointer + 1) % UPDATES_PER_PERIOD;

That’s it. There isn’t much more to say. As always, the code, schematics and other documentation, are available at github.

One last thing about the software: I have started using Ino Toolkit for this project. If you have it installed you can run “ino build” from the code folder to get the binaries. I don’t like the Arduino IDE: it is very feature limited, the editor is clumsy and the whole thing is too heavy. I’ve always used different command line tools like Arduino Makefile. My first impressions are good, it has better library discovery capabilities but I missed the “make size” command to know how much free space left you have to code more features…

Testing it!

I was going to add some theory explaining the different types of radiation, how a Geiger-Muller tube works and some reference levels but there are plenty of pages on the internet about the subject and I will not add anything new. Instead I can recommend you to read this tutorial that the people from Cooking Hacks have put together for their Arduino geiger counter shield.

There are a number of natural radioactivity sources. The first of them being the background radiation which you will always get. With my detector this background radiation averages 26 CPM over long periods (more than one day). Then you have some commonly available sources like smoke alarms, some paint used in pottery, luminous displays from old watches or compasses, gas mantles or anything with potassium, like some low-sodium kitchen salt or even bananas.


Low sodium salt (66% of potassium salt)

This low-sodium salt is the easiest to find in Barcelona (apart from bananas) so I just went to the supermarket and bought a tin of LoSalt “The Original” (sic). Then I poured some salt on a self-sealing bag and put it over the Geiger-Muller tube. In any given sample, every 8547 atoms of potassium there is one isotope of 40K, which is radioactive. Potassium 40 is a very interesting isotope, it represents the largest source of radioactivity in human body and has a half-life of 1,250·109 years (if you have a sample of 40K, after one thousand million years only half of its atoms will have gone through a radioactive decay). The counts with the potassium salt bag near the tube raised to almost 139 CPM on average over a 10 minutes record. That is more than 5 times the background noise…

The Geiger counter with a sample of LoSalt

The Geiger counter with a sample of LoSalt. The display reads 139 CPM.

To get a higher count sample I went to Ebay and bought one Thorium Latern Mantle or Gas Mantle. Funny enough, even though these mantles were pretty common here 20 years ago I had to go to an USA supplier to get one. These mantles are impregnated with thorium dioxide to produce a brighter white light. They were retired, mainly because the safety concerns for people involved in the manufacture. Thorium (232Th) is a radioactive element, part of the Thorium decay chain which undergoes several alpha and beta decays until it stabilizes as Lead (208Pb). The test with the Thorium Mantle was impressive. The seller said the set of mantles he had read between 1100 and 2100 CPM. Mine read an average of 1662 CPM over a 5 minutes test but wrapping it around the tube I got up to 1903 CPM.

The Geiger counter with a Thorium Gas Mantle covering it

The Geiger counter with a Thorium Gas Mantle covering it

Thorium gas mantle reading

In the picture the display reads 1823 CPM, it peaked 1903 CPM.

I repeated the tests isolating the gas mantle (it was already inside a plastic bag) from the counter with a paper first and then with a couple of layers of aluminium foil. The experiment set up was not quite right because the readings with the paper were about a 33% lower than without it and that makes no sense since the paper would have blocked only alpha radiation and the tube is sensitive to beta and gamma. Nevertheless I think it is worth it to post here the results. In the graphic below, the first bump is the Potassium salt sample, the second is the thorium gas mantle only with the plastic cover, then with the paper and then with the aluminium foil.

The first bump is due to a sample of KCl, the second, third and forth bumps are a Thorium Gas Mantle with plastic, paper and aluminium foil shielding.

Of course, the sensor is also reporting to my home MQTT network and then the readings are sent to Cosm Xively in almost real-time, here you have the last 24 hours of readings:

Weather Station

Keeping on registering data from different sensors my next project has been the all-time favourite weather station. This time I wanted to build an 100% autonomous outdoor sensor.

To achieve this goal I started playing with a LiPo battery and a solar panel. The Arduino Fio looked like the perfect out-of-the-box platform to be the center of the project. It’s a ATmega328P (the same micro as the UNO), has a connection for a LiPo battery, a charge circuit based on the MAX1555 (with an USB connector) and a socket for an XBee radio module. So I just really had to wire things up and work on the code to reduce the power consumption to its minimum.


This first version of the weather station uses two sensors: a DHT22 and a BMP085. The former is a temperature and humidity sensor that uses a custom one wire digital protocol. The later is a barometric pressure sensor with I2C protocol. Both sensors are 3V3 compatible (like the Fio) and very easy to set up. Adafruit has tutorials and libraries for the two of them here and here.

Weather Station Schema

The schema is so simple I thought it could be a good opportunity to give Fritzing a try. The result could be better. You have to imagine that the CHG and ON holes are connected to the input of the two voltage dividers on the right to check the voltage from the solar panel and the LiPo battery. The other connector by the on/off switch is there to provide an external on/off switch in the future.

Here you have a picture of the sensor. I think I haven’t said this before: I prefer stripboards (veroboards) over perfboards because they are very suitable for rapid development and the final layout is cleaner.

Weather Station sensor

Power management

The main issue with this sensor is power management. The goal was to have an autonomous sensor that will not require battery replacements. Given that Sun is a natural resource freely available most days here in Barcelona that shouldn’t be a problem.

To provide power I chose the Medium 6V 2W solar panel from Adafruit. The Fio charging voltage requirement goes from 3.7V to 7V and this panel fits quite well in that range. The only drawback is the 3.5×1.3 jack connector – a mini USB would have been a perfect match. No worries, the Fio provides a place holder to connect a custom charging source.

And to store energy I’m using a Lithium-Polymer battery rated 3.7V 850mAh. That’s enough power to make it last for weeks applying simple sleeping strategies. When in power down mode the circuitry consumes a negligible amount of energy (not measurable by my instruments, something around 10 uA?). The problem arises when it wakes up.

The DHT22 sensor is a little picky. It requires a warm-up lapse before reading anything and you cannot perform two readings in a row without another delay in between. After some testing I found out that a 2 seconds warm-up time after wake-up produced constant reliable results. Besides, the reading itself is also time (and power) consuming. At the end every time the Arduino wakes up it waits 2 seconds for the DHT22 to warm-up and 2 more seconds to get the reading from it. The reading from the BMP085 is fast (in comparison) and then sending the data by radio produces a burst of ~55mA for 10 millisecs.

State mA ms/event events/h ms/h mA (avg)
Arduino (and XBee) sleeping ~0 - - 3474488 ~0
Warm-up 10 2000 60 120000 0.333
DHT22 reading 12.5 2000 60 120000 0.417
BMP085 reading 10 10 60 600 0.002
XBee awake 25 80 60 4800 0.033
XBee transmitting 54 10 12 120 0.002

The average is ~0.8mA which means around 44 days for a 850mAh battery. Note than 93% of the power consumption is due to the DHT22 reading process. So here there is a big source for power management improvement, but… don’t optimize until you need it.

Since I still had to buy the solar panel and while I was waiting for it to arrive, I powered the sensor and it started transmitting data. I carried the experiment for some weeks until the voltage from the battery fell below 3300mV and the Fio stopped working. It lasted for 37 days, quite accurate.

Then I plugged the solar panel and (after some trouble shooting) it has never gone below 4200mV except twice where it fell well below 3700mV for a short time. So apparently the current set up is more than good enough. I’m even slightly concerned about continuously charging the LiPo battery but the MAX1555 in the Fio should take care of that.


The software is pretty straight forward. I’m using Ben Adams’ DHT22 library and Adafruit’s BMP085 library to interface the sensors. Like in the Smartmeter Pulse Counter project, I’m using Rocket Scream’s Low Power library to put the Fio to sleep. It’s a very useful one-liner to turn ADC and BOD off and put the Arduino to sleep for two seconds (SLEEP_INTERVAL constant). The every 28 (MEASURE_EVERY constant) intervals it gets a reading from the sensors. Since the reading takes 4 seconds that’s roughly one reading per minute. Every 5 (SEND_EVERY constant) measures it awakes the Xbee and sends the average for all the magnitudes.

void loop() {
    if (interval % MEASURE_EVERY == 0) {
        interval = 0;
        if (measures % SEND_EVERY == 0) {
            measures = 0;
    LowPower.powerDown(SLEEP_INTERVAL, ADC_OFF, BOD_OFF);

The data for each magnitude is stored in a structure with 4 values: maximum and minimum values, sum of all values and number of readings so far. Then, when the code is ready to send the data it subtracts the maximum and minimum values from the sum and averages over the rest of values. This way it gets rid of inconsistent readings and the final value is smoother.

The voltage readings for the solar panel and the battery al calculated based on the actual value of the resistors in each voltage divider and they are expressed as constants in the code (BATT_VOLTAGE_FACTOR and PANEL_VOLTAGE_FACTOR).

Finally, I’ve added some code from Tinker London to get the values from the interval thermometer and voltmeter of the ATmega328.

All the code, along with the Fritzing schema and the XBee configuration file is available in Github.

Boxing it

The sensor is housed in a box to prevent direct Sun exposure. It’s common to use a Stevenson Screen as a shelter for a weather station. The “professional” screens are waaaay too expensive (in the 400€ and above range). There are kits online (most notably this one) to build your own shelter or you can always build one buying the parts from the carpenter or repurposing other items. A good source to get ideas and instructions is this site aimed to schools.

I built mine from scratch. It has slats on three sides (the other is attached to the building facade) and holes on the bottom to ease the air flow inside the box. It doesn’t have double roof or chimney since I have glued the solar panel to the top with a methacrylate stand to make it perpendicular to the winter sun. The solar panel angle was a hard decision but since there is a maximum of power I can store I decided it made more sense to get the maximum from the Sun in that not-so-bright days of winter. The perpendicular of the solar panel points SSW, almost 30 degrees above the horizon, to the winter afternoon Sun…

You will have to let me not showing you any pictures of the final box… it fulfils the requirements but it’s ugly as slapping a father with a wet sock (local quote). Definitely  carpentry is not for me.

To do

It would be interesting to add some sort of power monitoring to the solar panel. Right now I only get voltage readings but most of the time the panel is in nearly open circuit mode. Being able of actually get readings for the power it is providing to the charging circuit (in mW) will provide a more accurate view of the and maybe increase the performance or under-scale the solution (maybe a smaller battery or solar panel would do the job).

I’m also planning to add an anemometer to measure wind speed and a rain gauge. The readings from these two sensors will not be very significant, since the whole building could block the rain or the wind or even create twisted flows of wind around it that will fool the sensor but it will be fun nonetheless. If the battery, backed by the solar panel, has enough juice to permanently power the Arduino (that is, not in sleep mode) I could even get readings for maximum speed of wind gusts, if not I might use a binary counter IC or two (74HC590 will be perfect) to store the counts from the anemometer and get the readings from the Arduino once a minute, avoiding the use of interrupts in the code.

Finally, the data from the sensor is public and available in