Categories
Microcontrollers

Beverage-o-Meter

I have too many little dev boards and breakout boards and other components laying around here, picked up from cheap Hong Kong-based suppliers. I buy them thinking “oh yes, that would be handy” and then never do anything with them.
Today I have used two in one go. Blam! I made this, the Beverage-o-Meter:

Beverage-o-Meter

One Arduino, called the server (although the wireless boards are just peers with respect to each other), sends changes in the potentiometer’s position to the client (shown above), which rotates a stepper motor in sympathy, as it were, pointing at the beverage
desired. It is probably not that diplomatic a thing to plonk down in front of someone, so before deploying, work out a rota of who gets to hold the control.

So the two things I had that birthed this silly idea, were two Nordic Semi NRF24L01 breakout boards, and a miniature Switec stepper motor.

The Radio

The wireless side of things is taken care of by a pair of Nordic Semiconductor NRF24L01 chips. Sadly, not the + revision, which offers an extra sensitive lower (250kbps) data rate, which would have extended the range a bit, at no disadvantage to this project.
These operate in the 2.4GHz ISM band (where wi-fi and your microwave oven live), and you talk to them via SPI. They top out at a 2Mbps data rate. And there’s a library out there for the Arduino. How handy. The example sketches allowed me to quickly verify that my soldering had done the job, pinging each other merrily. I could wander the house, mapping out the coverage with the “client” plugged into the laptop, so I could watch the activity via the serial monitor. They couldn’t hold a candle to the 802.11n wi-fi range I have here, but I could reach it from one floor away, no problem.
The radios have a lot of functionality not revealed as yet by the library, but there’s nothing to stop a chap from hacking on the library, or simply accessing the chip registers.
If you really need more range, you can find them paired with a low noise amplifier and larger antenna, but for around five times the price.

The Motor

These tiny stepper motors were designed with one purpose- to operate the dials on a car’s dashboard. Indeed, they have so little torque, they can hardly do anything else. But the upside to that, is the very low power
requirements. So low, in fact, that they can be powered directly off the Arduino’s pins.
I very much liked the idea of the faux-analogue readout, as opposed to an LCD display or somesuch alternative. It has a similar aesthetic to the engine speed “control” that used to be seen in old steamships. I’m not suggesting this is fulfilling a genuine need of the world. But come on, it is pretty cute, right?
You’ll never guess, but there’s a library for this family of steppers, too- it’s called Gaugette. So the project involved nothing more than some literal and metaphorical glue. Which you can do when it’s open source and you’re not being assessed. Yes, students-of-mine, this is aimed at you.
So, without further ado, the code…

The Server

[code lang=”cpp”]/*
* Beverage-o-meter (server)
*
* This sketch is loaded on the command device, the one
* connected to the potentiometer which sets
the
* desired beverage.
* It performs two functions. One is to watch out for
* changes in the pot’s position, and send that.
* The other is to listen for "hello" packets, which
* indicate a new client wanting to hear the position.
*
*/
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
// Using a LED on the protoboard to show when I’m sending
#define TXLED 6
unsigned int reading, prev_reading;
boolean forceSend = true;
void setup(){
/*
* Set the SPI Driver.
*/
Mirf.spi = &MirfHardwareSpi;
/*
* Setup pins / SPI.
*/
Mirf.init();
/*
* Configure reciving address.
*/
Mirf.setRADDR((byte *)"server");
/*
* Set the send address.
*/
Mirf.setTADDR((byte *)"client");
/*
* Set the payload length to 2 bytes, plenty for
* the reading from the analog pin, plus six
* control bits.
*
* NB: payload on client and server must be the same.
*/
Mirf.payload = 2;
/*
* Write channel and payload config then power up reciver.
*/
Mirf.config();
prev_reading = analogRead(0);
pinMode(TXLED, OUTPUT);
}
void loop(){
byte data[Mirf.payload];
// We send a message on start up, just in case the
// client beats us to it.
reading = analogRead(0);
if (Mirf.dataReady()) {
// This can only be a hello packet. But no-one ever
// got fired for wearing belt and braces.
Mirf.getData((byte *) &data);
if (data[1] == 0x80) {
forceSend = true;
}
}
digitalWrite(TXLED, LOW);
if(((abs(reading – prev_reading) > 5) || forceSend) && !Mirf.isSending()) {
forceSend = false;
prev_reading = reading;
/*
* Send the data back to the client.
*/
data[0] = (reading &
0x00FF);
data[1] = (reading & 0xFF00) >> 8;
Mirf.send(data);
digitalWrite(TXLED, HIGH);
// Mainly because you can’t adjust the pot fast enough with your
// puny human hands, there is no need for a delay here, the LED
// shows up just fine.
}
}[/code]

The Client

[code lang=”cpp”]/*
* Beverage-o-meter (client)
*
* This sketch is loaded on the display device, the one
* connected to the modified clock.
*
* Once turned on, it should send a "hello" packet to
* the server, which responds with the current setting.
*
*/
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include <SwitecX25.h>
// standard X25.168 stepper motor range 315 degrees at 1/3 degree steps
#define STEPS (315*3)
// Yes, I’m using the analog pins as digital pins.
// Also, I don’t care for olives.
SwitecX25 motor(STEPS,14, 15, 16, 17);
nbyte data[] = {0x0, 0x0};
void setup(){
motor.zero();
Mirf.spi = &MirfHardwareSpi;
Mirf.csnPin =6;
Mirf.cePin =7;
Mirf.init();
/*
* Configure receiving address.
*/
Mirf.setRADDR((byte *)"client");
/*
* Set the payload length to 2 bytes.
*
* NB: payload on client and server must be the same.
*/
Mirf.payload = 2;
/*
* Write channel and payload config then power up receiver.
*/
Mirf.config();
// As we just switching on, we need to know the initial position
Mirf.setTADDR((byte *)"server");
data[1] = 0x80; // Setting the highest bit is how we say hello. Pip-pip!
Mirf.send(data);
while (Mirf.isSending()) {
// Wait until we’ve sent the message, and put us back into listen mode.
}
}
void loop(){
float pc;
while(!Mirf.dataReady()){
motor.update();
}
Mirf.getData((byte *) &
data);
pc = (data[0] | (data[1] << 8));
pc /= 1024.0;
motor.setPosition((int)(pc * STEPS));
}[/code]
And here’s the Inkscape file I created for the faceplate and pointer:
beverage.svg

4 replies on “Beverage-o-Meter”

Leave a Reply

Your email address will not be published. Required fields are marked *