A Mask For Every Occasion

A mask-mounted e-paper display, controlled from your phone.

Mask Construction

A fairly simple design done in OpenSCAD. It’s two parts; The cyan clip fits over the yellow assembly. The parts are printed in PLA so I glued the two parts together with dichloromethane solvent (available as Scigrip 16 at Amazon) and then cut the mask fabric out. The design file is here

Display Installation

Here is the mounted e-paper display with an adapter board also acting as strain relief:.

E-Paper Display and Driver

The e-paper display is a 2.9inch flexible display from Waveshare and Aliexpress

That connects to an ESP32 E-Paper driver board (Aliexpress). It’s an ESP32-WROOM-32 module with connector hardware.

Image Preparation

The e-paper display is 296 x 128. I couldn’t find any mouth images I liked on the net and I can’t draw mouths, so I took a picture of my own face, cropped my mouth and drew around it, then saved the result as a 1 bit BMP. I’ll spare you the original image, but here’s a processed example:

Once that’s done the image needs to be converted into a form suitable for inclusion into the code, and that’s done with a simple python script

#!/usr/bin/env python3

import os.path
import pdb
import sys
import scipy
from PIL import Image as PILImage 
from PIL import ImageOps

def main():
    if len(sys.argv) == 1:
        print("need a picture")
        return 1

    filename = sys.argv[1]
    base = os.path.basename(filename).split('.')[0]
    img = PILImage.open(filename).convert('L')
    img = ImageOps.invert(img)
    img = img.convert('1')

    img.save("{}_1bit.bmp".format(base))
    dd = ','.join([hex(~x & 0xff) for x in img.tobytes()])
    open('{}.h'.format(base),'w').write('const unsigned char {}_data[] = {{{}}};\n'.format(base, dd))

main()

Then I copy the generated header files into the ESP32 environment and bind them in.

ESP32 Software

The code is a mixture of the BLE client sample code that comes with the BLE library, the proof of concept code for the e-paper display, and my own logic. I would have like to use the GxEPD2 library but it doesn’t yet support my display. Instead I’ve hacked up the sample code from github. The screen refresh is pretty rough still.

I used arduino-cli in a Docker container to develop the ESP32 code. The code is here

Phone Control Javascript

The ESP32 module runs as a Bluetooth Low Energy (BLE) client. This allows control from the phone. The phone app is written using phonk.app, which allows most of the phone functions to be accessed using Javascript. This system is a work in progress but it’s very useful already.
The communication between the phone and the ESP32 is a simple serial command interface; the ESP responds to a set of simple commands and displays the selected image.

The phone code:

ui.addTitle('BlueMouth')

network.bluetoothLE.start()
var bleClient = network.bluetoothLE.createClient()

// -> Write here the BLE device MAC Address
// var deviceMacAddress = '24:6F:28:7A:5C:CE'
var deviceMacAddress = '4C:11:AE:79:8E:8A';
var serviceUUID = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
var characteristicUUID_TX = '6e400002-b5a3-f393-e0a9-e50e24dcca9e'
var characteristicUUID_RX = '6e400003-b5a3-f393-e0a9-e50e24dcca9e'

function setResources(data)
{
var list = ui.addList(0.1, 0.1, 0.85, 0.8).init(
  data,
  function () { // on create view`
    return ui.newView('button')
  },
  function (o) { // data binding
    var t = data[o.position]
    o.view.props.background = '#00FFFFFF'
    o.view.props.padding = 50
    o.view.text(t)
    o.view.onClick(function () {
      bleClient.write(t, deviceMacAddress, serviceUUID, characteristicUUID_TX)
    }
  )
  })}
  
network.bluetoothLE.start()
// scan bluetooth low energy networks
// this should show devices -> services -> characteristics
var btn = ui.addButton('Get', 0.1, 0.9, 0.4, 0.1).onClick(function () {
      bleClient.write("list", deviceMacAddress, serviceUUID, characteristicUUID_TX)
})

// connect to a device
ui.addToggle(['Connect', 'Disconnect'], 0.55, 0.9, 0.4, 0.1).onChange(function (e) {
  if (e.checked) {
    bleClient.connectDevice(deviceMacAddress)
  } else {
    bleClient.disconnectDevice(deviceMacAddress)
  }
})

bleClient.onNewDeviceStatus(function (e) {
  // double check if is the device we want to connect
  if (e.deviceMac === deviceMacAddress && e.status === 'connected') {
    bleClient.readFromCharacteristic(deviceMacAddress, serviceUUID, characteristicUUID_RX)
    //txt.add('connected to ' + e.deviceName)
  }
})

bleClient.onNewData(function (e) {
  console.log("newData");
  var value = util.parseBytes(e.value, 'string')
  elems = value.split(',')
  if ("list" == elems[0])
  {
    setResources(elems.slice(1,))
  }
})

PocketChip Keyboard

Pocket Chip

The Pocket Chip is fun to play with but that keyboard is nearly unusable. I designed a magnetically attached removable replacement that goes on top of the metal domes and provides a good positive click action. I find 3D printed keys are pretty annoying and I needed space to print the key legends, so I’ve used genuine buttoncaps. They feel better and leave room for legends.

OpenSCAD keyboard model

I found the PCB layout files and extracted the pad coordinates to design a keyboard. The hexagonal and round projections fit into the holes in the Pocket Chip.

Keyboard top side

Here is the print. I sanded the top and then ironed it to provide a smooth surface for the vinyl to stick to.

Here’s the underside showing the projections, the holes for the keys and the parts for the magnets.

Here is the CriCut vinyl printer/cutter printing legends on the adhesive vinyle sheet. I modified the cutter to use permanent markers (the provided markers are water-based and won’t print on vinyl at all), but the ink will still smear after a while so I cut clear vinyl to provide a protective layer. I used the extracted pad coordinates as input into a script to programmatically generate an SVG file which can be imported into CriCut’s design software. This is pushing what the design software is built to do so there were a lot of iterations.

I made a template to position the vinyl layer and let me accurately place it on the keyboard.

The keys took a lot of experimentation with different parts to get right. The top part is 100PCS For 6*6Round Tact Switch A101 Plastic Switch Button Caps from Ali Express, link here. The inserts are Fastex 207-080551-00 Plastic Plug 1/8 Hole Round Head. They fit together to make a solid key with a good click feel.

Here’s the populated keyboard. You can also see the magnets used to hold the keyboard onto the pocket chip. At the bottom of the image are retaining bars which, once glued in place, stop the keys from falling out.

Pocket Chip with Keyboard

Here’s the completed unit. I glued magnets onto the underside of the board, and between those and the round/hexagonal inserts.

This isn’t quite finished as the legends look pretty rough. The Cricut is really at its limit drawing characters this small, so I think it would be better to print onto laser print onto a large label and protect that with the clear vinyl layer. If this is the last paragraph then I haven’t done that yet.

The OpenSCAD files are at https://github.com/mdaughtrey/openscad/tree/master/pocketchip

Tentacle now has terrifying flashing lights

I switched from micropython to regular Arduino code as the garbage collection isn’t quite ready for prime time. I also added a ring of WS2812 LEDs controlled via the Neopixel library.

Samsung NX300 Automatically Copy Images to Your Computer

I’ve written a python script to act as a server to the Samsung NX300 DSLR so that it will automatically copy photos to your local computer.

Power on the NX300 and hit the ‘Direct Link’ button. Then connect to the ‘AP_SSC_NX300_*’ access point and run the script. It will connect to the camera and wait for downloaded images.

Github here

3D Printed Klann Linkage Demo

Linkage Calculation Spreadsheet
Sketchup 3D Warehouse Info

Latest on the 8mm film converter

Extensive work since the last post – here’s a quick look while I get my act together.

img_20160719_172716

Tentacle Has A Heartbeat

The Webbed Tentacle

Here’s the inspiration:

I’ve decided to expand on it a little. It’s an ESP8266 WIFI module running Micropython. The node is an AP and serves up a simple AJAX web page allowing for manual control

Battery holder, base and servo motor

Battery holder, base and servo motor

Rotor mounted on servo

Rotor mounted on servo

This guy delivers parcels

And I have absolute faith in him.

20130701-182359.jpg

A Small Interruption to the Swimming Season

Hm.

20130620-140549.jpg