2020-10-18

Lean back to scroll

You know those days when lifting a finger to scroll a website seems like to much of an effort? No, of course not, me neither. But just in case I made this so I can scroll just by leaning back in my chair:

If you look closely there's Adafruit's Feather nRF52840 Sense board attached to the back of the chair. It uses the onboard sensors to figure out the angle of the chair's back and if it's over a threshold it sends scroll down events to the computer (using the standard Bluetooth mouse protocol so it works with any OS). To set the "zero" position you press the "user switch" button on the board.

Here's the Arduino code.

2020-09-27

Hat mouse

I've been playing around with orientation sensors and Bluetooth HID recently. Today I'd like to show you what is perhaps my most practical application of those yet. I made a head mouse, also known as an air mouse, or in my case, a hat mouse:

The device is attached to a hat and you move your head around to move the mouse cursor on the screen. It uses the standard Bluetooth mouse protocol so it works with Windows, Mac and Linux with no additional software running on the computer. The board used is Adafruit's Feather nRF52840 Sense. The way it works is it reads accelerometer, gyroscope and magnetometer data, puts it through a sensor fusion algorithm to get orientation and then uses the yaw and pitch values to position the mouse cursor on the screen. It uses absolute cursor positioning so any given head orientation corresponds to a fixed cursor position on the screen. To reset the center position, you press the "user switch" button on the board.

Here's the Arduino code. In addition to the Feather board we need some way to power it. I used this lipo battery, but the board can also be powered over the USB port so a small power bank could work as well.

As with some of my previous custom devices that work as a mouse, unfortuntely the hat mouse has no way of performing button clicks yet. In the video above I'm using a separate USB foot switch for clicking. Depending on the movement limitations of the user, something like a sip-and-puff switch might be more appropriate (same goes for the orientation reset button that's currently located on the board). The Feather nRF52840 Sense board has a lot of sensors in addition to those that we're currently using for the orientation. Perhaps the pressure sensor or the light sensor or even the microphone could be used to make entirely head-operated switches. I have some ideas, but I decided to treat that as a separate project.

2020-09-21

Plotting sensor data with MS Paint and Bluetooth HID

I have recently discovered that the HID mouse protocol supports absolute cursor positioning in addition to the more common relative mode. I think that opens interesting possibilities, one of them being we can plot real-time charts in MS Paint with no additional software running on the computer, using just the standard Bluetooth mouse protocol:

The board used above is Adafruit's Feather nRF52840 Sense, which has Bluetooth LE and lots of sensors. On the video we're plotting readings from the accelerometer. The chart is drawn by simulating mouse and keyboard inputs (keyboard is used to clear the screen when we reach the right edge).

Here's the Arduino code.

2020-09-20

USB "rubber ducky" with mouse input

Perhaps you're familiar with a type of device commonly referred to as a USB rubber ducky. It's a seemingly innocent device that looks like a regular USB drive, but when connected to a computer, it acts as a USB keyboard and sends malicious keystrokes to the victim's machine, as if a human typed them (but faster). The commands sent can download some unwanted software or open a reverse shell and do nasty stuff in general.

So I thought why stop at keyboard, why not also pretend to be a mouse, launch Paint and draw something funny:

The main challenge here is that a regular mouse doesn't really know where the cursor is on the screen. It only sends relative position changes like "move the cursor 7 units to the right and 2 units down". Depending on the sensitivity setting on the user's system, it might correspond to a different distance in pixels. When you add mouse acceleration into the mix, it's not really practical to try and guess where the cursor will end up being.

But, as is turns out, the mouse HID protocol also allows for absolute cursor positioning and all the major desktop operating systems support this mode (perhaps because touchscreens and graphics tablets use it?). With that knowledge, the task becomes easy, as we can just say "move the cursor to position X, Y".

I used a Digispark with a modified version of Adafruit's TrinketHidCombo library for the demo above. Here's the Arduino code.

2020-09-08

Human trackball

Remember Logitech's April Fools' video from 2017? The one where the gym ball works as a trackball? I made that for real:

I did this as kind of a detour while working on the next version of my Bluetooth trackball from last year (stay tuned for that). I found a board on AliExpress that has the nRF52832 Bluetooth chip from Nordic, an MPU-9250 9DOF sensor, a built-in battery charging circuit and comes with a lipo battery attached. Originally a development board for a fitness bracelet, it looked like a pretty good match for my needs.

For this application I just attached the board to the gym ball using scotch tape (and tried to avoid sitting on it or crushing it by rolling the ball).

The software is derived from my previous IMU-based Bluetooth trackball attempt. This time I decided to do the sensor fusion algorithm in software - even though the MPU-9250 is better than the MPU-6050 because it has a magnetometer (3 more DOFs!), its onboard algorithm was not updated to make use of it - it still only uses the accelerometer and gyroscope. So I used Adafruit's library implementing Sebastian Madgwick's sensor fusion algorithm. I also used Sandeep Mistry's Arduino core for the nRF52832 chip and his BLEPeripheral library for Bluetooth. I programmed the board using Nordic's nRF52 DK development kit.

You can find the code here. Also included is a sketch for calibrating the magnetometer that sends the data over Bluetooth serial (I used Adafruit's Bluefruit Connect app to read the data). And since the gym ball itself has no way of performing button clicks, I used a foot switch connected to a Digispark for clicking the mouse. A sketch for that is also included.

Even though it looks like a trackball, the ball works more like a joystick in this case: when you tilt it to the right, the cursor moves as long as the ball is kept in that position and stops moving when it is returned to the neutral starting position. Right now it's not really a practical mouse or trackball replacement, but I believe that with some fine tuning it might become a viable option. Another possibility would be to only use it for scrolling, not moving the cursor, which I haven't tested, but it should be an easy modification.

Can't wait for Logitech's next year April Fools' video!

2020-03-09

Bathroom occupancy monitor

Don't you hate it when you get up from your desk at work to go to the bathroom, only to find out that all the stalls are occupied? I did, so I made a website that shows the current status of each stall. It normally looks something like this:

To make this possible, I installed a 433 MHz door/window sensor on each stall door. Somewhere nearby I put an ESP8266 module with a 433 MHz receiver board. Each time a stall door is locked or unlocked, the module gets a signal from the sensor and passes it on to a Firebase cloud function that saves the current state and timestamp in a database. Finally there's a website that reads the database and displays the current status for everyone to see.

Even though the sensors I used are normally meant to detect when a door (or window) is opened, what I really wanted to detect in this case is whether the doors are locked. I achieved that using a zip tie and a neodymium magnet attached to the door lock:

What's nice about these sensors is that they're cheap, require no modification, and will run on a single AAA battery for many months. One thing to keep in mind is that it's important that the sensors send a signal every time they detect a state change in any direction, not just when they detect that the door/window has just been opened. Not all of the sensors on the market do that and sometimes it's not clear from the description.

The ESP8266 board I used was a Wemos D1 mini clone, here's what it looks like with the 433 MHz receiver board:

The rest is software, the ESP8266 is running an Arduino sketch and the web part uses Firebase. You can see the whole thing here. The cloud function part isn't strictly necessary, the ESP8266 could write to the Firebase database directly, but it was much easier for me to do it this way.

Right now I'm only using the website to know if the bathroom is occupied, but it might be interesting to gather some statistics, such as the average time people spend in the bathroom or how likely it is to be occupied depending on time of day.

2020-02-15

Darkroom enlarger timer

I have recently started making traditional prints of my analog photos and it is a lot of fun in itself, but naturally I am also treating it as an excuse to play with some electronics. I have previously described a simple timer I made for measuring how much time each print spends in the developer and fixer trays. Today I'd like to present my solution for the more important type of darkroom timer: the one that controls the exposure time on the enlarger. Here's what my setup looks like:

The enlarger lamp is connected through a reprogrammed Sonoff S20 wifi smart plug. It runs a simple HTTP server written in MicroPython. It responds to three commands: "on", "off" and "expose". The last one takes a duration in milliseconds and switches the lamp on for that time.

The second component is a smartphone app written in Flutter, so it should in theory run on both Android an iOS, but I have only tested on Android. It lets the user specify the exposure time, either directly or using a simple test strip mode. In test strip mode, exposures are made in such a way that if you cover a larger part of the paper before each exposure, the resulting exposure times of each part will be increasing in configured fractions of a stop.

Finally there's a footswitch, which is just a pedal converted into a USB keyboard using a Digispark (which is an ATtiny85 board in the shape of a USB plug that can be programmed with Arduino). Whenever the pedal is pressed, the Digispark sends an "Enter" keystroke and the smartphone app reacts as if the "START" button was tapped and starts the next exposure.

The code for all three components is available here. To run the Python code on the smart plug, first it needs to be flashed with MicroPython firmware. The smartphone app is pretty basic right now and doesn't have fancy features like dry down compensation, saving dodge/burn programs or any split-grade automation. Another useful feature would be to have the safelight connected through another smart plug and turn it off when the enlarger lamp is turned on for focusing.

Oh, and even though the app's interface is all red, it's still probably not safe for photographic paper, so it's best to cover the phone's screen when the paper is out.

2020-02-01

Darkroom tray timer

Two kinds of timers are used in a darkroom when making prints. One for controlling the exposure time on the enlarger and one for measuring the time the print spends in the developer, stop bath and fixer trays. Arguably the second kind is not as critical as the first, as any clock that displays seconds can be used for that purpose. Nevertheless I've made such a timer and I'm using it regularly when making prints. Here's what it looks like:

As you can see it is operated with a foot switch and has no display. Instead it beeps when it's time to move the print to the next tray. Each press of the switch triggers the start of the next timer: first it measures 60 seconds for the developer, then 10 seconds for the stop bath, then 60 seconds for the fixer and finally 120 seconds for the wash (I'm using RC paper). After that it goes back to the first timer. A sequence of short beeps at the start confirms which timer we're currently on.

The case was designed in Fusion 360 and 3D printed in PETG. Inside there's an ATtiny85 chip, a piezo buzzer and a CR2032 battery. The code running on the ATtiny85 can be found here and a schematic of the connections is shown below. When the timer is not active it goes into deep sleep so the battery should hopefully last a long time. One thing to keep in mind when programming the ATtiny85 with Arduino is that not every core supports the tone() function, used to make sound with the buzzer. I'm using this one.

Stay tuned for the next episode in which I show my solution for the enlarger timer.