Sniff is a "Scratch-like" programming language that's designed to help Scratchers move gently from Scratch to more conventional languages. They can start writing programs, without having to learn a new language because Sniff is based on Scratch. They learn a little more about variables, compiling, syntax errors (!), and they can have fun controlling real hardware while they're doing it.

Friday, 2 December 2016

Motorised Pot

I've been looking at a lot of smart home stuff recently and having fun with things like the Philips Hue and cheer lights. Ironically one of the best features of Hue is its light switch! It shouldn't come as much as a surprise that the best way to turn lights on and off is with a switch! Taking your phone out of your pocket is way too clunky. Even using Siri on Apple Watch you need to press the button and say "turn on the lights", when you could just press a button in the first place!

That's not to say Hue isn't really great - it is really great (and addictive and expensive!), but the best bits are having lights turn off automatically in rooms you're not using, being able to dim them exactly as you want, and turning on and off lamps from the switch by the door. Seriously that lamp in the far corner will see a lot more use when you don't have to turn on the main lights, walk across the room, turn it on, walk back then turn off the main light, then walk back and sit down! (then repeat when its time to leave).

Most of the cool tricks involve being able to control the lights in more flexible ways in addition to just a basic switch (and the ability to place that switch anywhere).

We've already implemented Hue support in Sniff so you can use and Arduino or PC as part of that control mechanism. Specifically I wanted to be able to use a Pot connected to an Arduino to dim lights. While an up/button works OK, the good old fashioned dial is something that's sorely missing from our modern lives. It would be really easy to have a pot connected to an Arduino, control the brightness of a Hue light, but with physical controls there's a big catch - turning the dial can easily dim the lights, but what happens when I dim the lights on my phone? Now the dial is out of sync with the lights...

What we need is a motorised pot - which is exactly what it sounds like: a Pot with a motor attached. These can be quite expensive, but I found a cheap source on eBay and picked one up for about £3.

Conceptually they couldn't be easier - the pot at the front can be driven by the motor at the back. The only tricky part was figuring out the pins, as for some reason there are 8 pins on the pot instead of the usual 3. With a bit of googling and poking around with a multi-meter, I found the connections I've penciled on in the picture:
  • Pin 2: V+
  • Pin 6: 0V
  • Pin 7: Signal

Signal just connects to any analog in, and we can read the position of the pot.

make dial analog input A0

when start
..say [dial]
..wait 1 secs

Hooking up the motor is simple but requires a motor driver. I could have used a motor shield, but I had some stand alone boards around. We don't need much power, so I just powered the motor board from the 5V of the Arduino. Connect the motor wires to the outputs of the board, and then connect two wires from Arduino digital pins to the control pins of the motor board.

Coding this is simple but quite fun:

make dial analog input A0
make motorCW digital output D2
make motorCCW digital output D3

make targetDial number

Here I've set up the pins, and created a variable targetDial. The only thing to watch is that the motor pins are the correct way around, and CW does turn the pot clockwise and CCW counter-clockwise (and similarly that turning CW increases the value of dial). Now we need to just change dial until it matches targetDial:

when adjustDial
.repeat until abs of (dial-targetDial)<0.01
..set motorCW to targetDial>dial
..set motorCCW to targetDial<dial
.set motorCW to no
.set motorCCW to no

We've made a loop, and we keep going round the loop until the difference between the desired and actual values are less than 0.01. We use abs because we don't care if the difference is positive or negative.

The contents of the loop might look a bit odd, but its really pretty simple. When ever we use a greater than (or less than) its actually testing something to see if its true or false, so the answer to the question "is targetDial>dial" is either a yes or a no. So if targetDial is bigger than the actual position (dial) then we set motorCW to yes, and the motor turns clockwise. If it isn't then motorCW becomes no, but motorCCW probably becomes less and we turn the pot CCW.

This will keep adjusting the dial until it reaches the target position. The neat thing is that if it overshoots, then it will adjust back the other way automatically, until its in exactly the right position and the loop exits. Then we turn the motor off, and we're done.

when start
..say ""
..say join "Current Val:" [dial]
..set targetDial to ( pick random 0 to 10 ) *0.1
..say join "Target Val:" [targetDial]
..broadcast adjustDial and wait
..say [dial]
..wait 5 secs

To test the adjustDial script I wrote the start script above. It picks a random value between 0 and 1, and adjusts the dial to that position. It then waits 5 seconds (during which you can turn the dial manually) before starting over again.

The next step would be to read values from the Hue system, and move the pot appropriately, and when the pot is turned, push values form the pot back to Hue. There are some updates in the next release to make that all very easy, so I'll cover that another time, but in the mean time consider what else needs a nice rotary control...

No comments:

Post a Comment