sharpoblunto

Over the event horizon, toward the singularity

Forays into 3D printing

Posted on Jun 8, 2021 3dprinting

I’ve been interested in 3D printers for a while now, in particular the thought of being able to take some. of. my. hardware projects to the next level with custom printed cases & components was very compelling to me. So I decided recently to take the plunge and purchase my first 3D printer to see if my expectations matched whats available.

I decided to get the Creality Ender 3. Its one of the cheaper printers on the market, but its got a great reputation & a huge modding community that means you can with a few tweaks have access to features of much more expensive printers. The downside is that its very much the opposite of plug and play - expect to spend days or weeks putting it together, deciphering poor documentation, flashing custom firmware, wiring in mods, & printing out additional parts. With that said I kind of enjoy doing all of the aforementioned things and after spending a long weekend messing around with it, everything is running well.

What follows is a list of the various things I learned along the way & some of the mods & enhancements I added to get to my current setup

Everything set up

Gotchas
  • The Ender 3 comes in a number of different variants & its not clear which one you’ll be getting when you purchase one. The biggest difference I could see is that some older models come with an 8bit mainboard, whereas newer ones come with a 32bit mainboard (of which there are also two variants 4.2.2 and 4.2.7). The 32bit board is much better - it comes with a bootloader which means you can flash new firmware from the SD-Card & don’t need to load one with an Arduino. It’s also much easier to wire in mods like the BLTouch as it has a dedicated port and doesn’t need any adapter boards.
  • The default Creality firmware doesn’t save settings to EEPROM, it uses the SD card & they don’t seem to document this anywhere, so if you’re trying to save settings and its not working - thats why. In my case I use Octoprint to print from USB (more on that later), so I can just leave an SD-Card inserted at all times.
  • Ender 3 (& most consumer printers) are FDM printers which means they build a model by layering many layers of filament over one another. This means that printing certain geometry is difficult - things like overhangs or roofs will need support structures to stay up while printing & models without a firm base will need extra skirts to stick well to the printer bed. There’s usually an optimal way to design or align a model for printing that minimizes the amount of throwaway support material you’ll need.
  • 3D printers don’t typically print 100% solid parts, they save material by specifying a percentage of ‘infill’ and leave the rest of the internal structure of a model hollow. For most models that don’t need strength you can get away with 20% infill, but if your model needs more structural strength you’ll need to up this percentage.
Octoprint

Octoprint OctoPrint is a fantastic piece of software that allows you to remotely control your printer from a Raspberry Pi, including uploading new prints & even viewing a live video stream of the current print status. To set it up I used this guide, but I opted to use a different case for the Pi so I could side mount it and not have to run the camera cable underneath the printer.

  • Raspberry PI case
  • You’ll need to tape over 5v USB pin as sending power to the printer through the Pi does weird stuff like having the printer screen powered on while the main power supply is actually off.
  • Make sure the micro USB cable has data sync support, not just 5v/gnd otherwise OctoPrint will not be able to connect to the printer. You’d be surprised how many micro USB cables are charging only - I had to try 3 I had lying around until I found one.
  • Creality firmware sends doubled temperatures. OctoPrint warns you, but you’ll need to install this plugin to fix it.
Fire-safety

3D Printers get hot & the cheaper ones are often made with cheaper components, so you probably shouldn’t leave them running completely unattended for long periods of time & you should probably take some basic safety precautions to prevent the most likely causes of a fire.

  • Update the firmware to ensure you’ve got thermal runaway protection.
  • Add a fan shroud so that filament doesn’t get into the mainboard fan.
  • Upgrade the PSU if you want - here’s a guide to switch to a quieter and more reliable MeanWell PSU.
  • Get a smart plug to provide a direct power cutoff in case the printer PSU or mainboard has a failure. I used a hue switch like this.
  • Install OctoPrint ‘Temperature Failsafe’ plugin & Use a shell command in the plugin settings to the smart plug to disable the power if the temperature goes over what you expect (see here for how to get the user id & switch id for your Hue switch). Once this is set up you can install the ‘PSU control’ plugin and use a similar command to power the printer on/off remotely.
    curl -X PUT -d '{"on":false}' http://192.168.0.4/api/<hue-api-user-id>/lights/<switch-id>/state
    
Improve printing
  • Get an auto bed leveller like BLTouch. You’ll have to update the firmware for this, but it makes it much simpler on each print as you won’t have to manually level the bed. Also Note 4.2.2 boards don’t need a 27pin adapter, they have a dedicated port that you can just plug in directly.
  • Get a glass bed for better adhesion (I use this one - I also use it upside down as the non-coated side sticks better in my experience).
  • Move the filament spindle to the side for a better filament path. I used this bracket.
  • Swap out the default springs for a longer lasting level. I used these.
Slicing & Cura

Once you’ve downloaded a 3D model, you’ll need to ‘slice’ it to convert it into GCode instructions that your printer will actually execute to print the model. A popular free program for doing this is Cura & below is the start and end snippets of GCode you can configure it to run before & after every print. These snippets are important as your printer needs to pre-heat, home itself, clean the hot end, and home itself before it will be able to print successfully.

Start GCode

; Ender 3 Custom Start G-code
M140 S{material_bed_temperature_layer_0} ; Set Heat Bed temperature
M190 S{material_bed_temperature_layer_0} ; Wait for Heat Bed temperature
M104 S160; start warming extruder to 160
G28 ; Home all axes
G29 ; Auto bed-level (BL-Touch)
G92 E0 ; Reset Extruder
M104 S{material_print_temperature_layer_0} ; Set Extruder temperature
G1 X0.1 Y20 Z0.3 F5000.0 ; Move to start position
M109 S{material_print_temperature_layer_0} ; Wait for Extruder temperature
; G1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed
G1 X0.1 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line
G1 X0.4 Y200.0 Z0.3 F5000.0 ; Move to side a little
G1 X0.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line
G92 E0 ; Reset Extruder
G1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed
; End of custom start GCode

End GCode

G91 ;Relative positioning
G1 E-2 F2700 ;Retract a bit
G1 E-2 Z0.2 F2400 ;Retract and raise Z
G1 X5 Y5 F3000 ;Wipe out
G1 Z10 ;Raise Z more
G90 ;Absolute positioning

G1 X0 Y{machine_depth} ;Present print
M106 S0 ;Turn-off fan
M104 S0 ;Turn-off hotend
M140 S0 ;Turn-off bed

M84 X Y E ;Disable all steppers but Z
Next steps

I’m now printing pretty reliably good prints with PLA, so the next thing is to familiarize myself with Blender so I can put together some custom 3D models to print. The first project I want to tackle is a custom tenting mount for my ZSA Moonlander keyboard - If thats successful I’ll post the results up here in future.

Redundancy

Posted on Apr 15, 2020 programming automation openwrt networking

So like most people at the moment I’m stuck at home as part of the ongoing quarantine for Covid 19 & thankfully I’m fortunate enough to have a job where I can work from home. Unfortunately having most of the neighborhood at home streaming, video-calling, and also working from home during the day is wreaking havoc with the local internet infrastructure and my ISP is not coping well with the added load. This has resulted in multiple several-hour dropouts of my connection and several days of work time effectively lost. Now with that said, I do have a backup connection in the form of my iPhones LTE connection which I can connect through using its wifi hotspot - but it’s limited in how many devices can connect to it concurrently & its also a pain to have to manually connect on every device that may need to access the internet during that time (especially home automation devices where switching WIFI is a pain).

So I decided to see if I could set up my home network with an automated failover system that would (in normal circumstances) have my main router use my cable internet as its WAN connection & then when that drops, have my router connect as a client to my phones WIFI hotspot and use that as its WAN connection. Also importantly I wanted to do this cheaply and not have to purchase any expensive enterprise networking hardware.

Client bridge Dual WAN

After investigating it turns out that my router does support Dual WAN failover, but it can’t connect to another WIFI network in client bridge mode to share the connection (well maybe it can with a different firmware like DD-WRT but I’m happy with the AsusWRT Merlin firmware I’m running, so I didn’t check). So I started looking around for a device that did support client bridge mode and came across this cheap TPLink travel router, you can pick one up for $35 and in addition to solving my main problem, its also a handy device to take with you when travelling for sharing WIFI & hotspot connections etc.

Client bridge Dual WAN

However once I actually got my hands on one I found a problem. For whatever reason, the stock firmware doesn’t work in the configuration I wanted. I set up the dual WAN on my Asus router & set the TPLink up to connect to my phones hotspot - but the Asus couldn’t get a DHCP lease from my phone and nothing connected to the Asus could access the WAN. I played around with all the settings I could, but couldn’t get it to work - so I decided to ditch the stock firmware on the TPLink and install OpenWRT instead to see if I would have any more luck. Getting OpenWRT installed was a bit quirky, but ultimately not too difficult - you just need to follow the instructions here.

Once I had OpenWRT up and running I had to set up two network interfaces. A bridged LAN that runs on the 5GHz radio and the ethernet port, and a WAN that runs on the 2.4GHz radio. Once that’s set up you just need to set up the 2.4GHz wireless to connect in client mode to the hotspot (and I also set up the 5GHz wireless as an access point to my existing WIFI network).

WIFI interfaces WIFI

Finally the TPLink has a slider switch that allows you to switch ‘modes’ (i.e. access point, ethernet sharing, hotspot) when using the stock firmware - this is a useful feature but doesn’t work out of the box with OpenWRT, but since I only want the 5GHz radio running as an access point when I’m travelling (I already have good coverage at home with my existing router, so I don’t need the extra access point) - I wanted to be able to switch this on/off without having to log into the configuration UI. To do this there’s an open source package called openwrt-slide-switch which adds support for this. To install I needed to enable SSH on the TPLink and once logged in run:

opkg update
opkg install slide-switch

You then need to configure the actions to take when the slide switch mode is changed. To do this, you need to add a couple of files into /etc/rc.button (and make sure they are chmodded to +x). The README on the github page above has all the details, but I ended up adding two ‘modes’ - one which enables the 5Ghz access point, and one which disables it.

/etc/rc.button/mode-ap

#!/bin/sh
[ "${ACTION}" = "pressed" ] || exit 0
uci set [email protected][1].disabled='1'
uci set wireles[email protected][1].disabled='1'
uci commit wireless
wifi
return 0

/etc/rc.button/mode-share-hotspot

#!/bin/sh
[ "${ACTION}" = "pressed" ] || exit 0
uci delete [email protected][1].disabled
uci delete wir[email protected][1].disabled
uci commit wireless
wifi
return 0

With all this configured if my main internet connection goes down, I just need to enable my phones wireless hotspot and the TPLink will connect and automatically bridge the connection to all devices in the house until the main connection comes back online again.

Digital shades

Posted on Jan 22, 2018 programming automation hue

So of late I’ve been on a bit of a home automation binge. I’ve added a bunch of Philips Hue bulbs around the house along with some smart switches and light sensors. While you can integrate these in with a first party Philips app, Apples HomeKit, or Google Home and configure some pretty interesting stuff including timers, IFTTT triggers, & voice control - I wanted some very specific behavior for the backlighting strip I installed in my home-office that would require some manual hacking. Lights on, Lights off Specifically, I wanted the strip light to switch on and off automatically based upon whether my desktop PC was powered on or asleep and since the Philips Hue accessories can be fully controlled via a JSON API, it was pretty simple to whip up a quick c# script to accomplish this. I’ve included the full source below, but the basic jist is that the script is set to run as a windows Startup item & listens for power events and tells the Hue Bridge to toggle the specified light based on whether the PC is powering off or waking up.

Source code
using Microsoft.Win32;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace LogoffLightsOut
{
    static class Program
    {
        // put in the IP address of your Hue bridge here
        private static readonly string HueBridge = "http://<ip_address_of_hue_bridge";

        // put in the user ID & UID of the light you want to control here
        // You can find these values by following the getting started guide here
        // https://developers.meethue.com/documentation/getting-started
        private static readonly string HueUserId = "hue_user_id";
        private static readonly string HueLightUid = "hue_light_uid";

        private static readonly HttpClient _client = new HttpClient();
        private static string _hueLightIndex;
        private static bool _exiting = false;

        [STAThread]
        static void Main()
        {
            _hueLightIndex = Task.Run(async () => await GetLightIndex()).Result;
            Console.WriteLine($"Found light at index: {_hueLightIndex}");
            Console.WriteLine("enabling light...");
            Task.Run(async () => await SetLightState(true, 4));

            SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
            SystemEvents.SessionEnding += SystemEvents_SessionEnding;

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            while (!_exiting)
            {
                Application.DoEvents();
                Thread.Sleep(1000);
            }
        }

        private static async void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
        {
            await SetLightState(false, 0);
            _exiting = true;
        }

        private static async Task<string> GetLightIndex()
        {
            var getLights = await _client.GetAsync($"{HueBridge}/api/{HueUserId}/lights");
            var response = await getLights.Content.ReadAsStringAsync();
            var parsed = JObject.Parse(response);
            var light = parsed.Properties().FirstOrDefault(p => parsed[p.Name]["uniqueid"].Value<string>() == HueLightUid);
            return light?.Name;
        }

        private static async Task SetLightState(bool on, int retries)
        {
            while (retries >= 0)
            {
                try
                {
                    var body = $"{{\"on\":{(on ? "true" : "false")}}}";
                    var url = $"{HueBridge}/api/{HueUserId}/lights/{_hueLightIndex}/state";

                    Console.WriteLine($"{url} - {body}");
                    await _client.PutAsync(
                        url,
                        new StringContent(
                            body,
                            System.Text.Encoding.UTF8,
                            "application/json"
                        )
                    );
                    return;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                    --retries;
                    await Task.Delay(2000);
                }
            }
        }

        private static async void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
        {
            Console.WriteLine("power event");
            if (e.Mode == PowerModes.Resume)
            {
                Console.WriteLine("enabling light...");
                await SetLightState(true, 4);
            }
            else if (e.Mode == PowerModes.Suspend)
            {
                Console.WriteLine("disabling light...");
                await SetLightState(false, 0);
            }
        }
    }
}

Come on and Slam and welcome to the (game) Jam

Posted on Jul 23, 2016 gamedev webgl javascript

Project image

Source code

Star Follow @mrsharpoblunto

As part of work I recently had a chance to participate in a 3 day game-jam. In the past I’ve always steered clear of game jams because the ideas I’m usually interested in building have no way of being realized within the time limits. This time however I decided to give it a shot and decided to build a 3D game in the browser using webGL.

The initial idea revolved around driving a robotic rover that could transition from multi-legged movement into a crazy monowheel (inspired by a desert spider that does backflips to evade predators).

Mono-wheel

I didn’t really have many gameplay ideas in mind other than trying to make it a fun and satisfying experience to just cruise around and get used to the weird locomotion mechanics. I figured if I got as far as having terrain generation working and a competent third person camera set up by the end of the jam that I would have exceeded my expectations.

With this in mind, I put together a nice WebGL starter framework based on the Component Entity System pattern - the really great thing about this pattern is that it completely separates state from logic - meaning that with the help of Webpack, one can implement hot reloading of all game logic while the game is running (without resetting the current game state). This is really cool and makes it easy to iterate on systems and effectively build the game while it runs. Check out the GitHub repo if you’re interested in finding out more.

Now that you have an idea of what I wanted to build, and how I went about building it - check out what I actually ended up building, subject to the constraints of time. While its not the most fun game in the world, I’m happy with how it turned out and I have a new appreciation for the effort it takes to convey a fun sense of motion through controls, physics, and a camera.

I had so much fun building the game, that I’m considering starting work on the procedural mad-max-meets-kerbal-space-program-on-a-road-trip sim I’ve been thinking about for a while. I think it would be really cool to build a fully fledged game in the browser, with all the inherent advantages in rapid development that javascript & the browser offer, combined with all the performance problems that come with it that need to be overcome.

Building an automated garden watering system with a Raspberry Pi, Node, React & HomeKit

Posted on Jan 31, 2016 raspberrypi react redux node

Project image

Get the source code and schematics here

Star Follow @mrsharpoblunto

While I’ve always been interested in electronics, I mainly got into software because software affords the flexibility to make mistakes. The cost of failure is low and there is room for experimentation without the risk of wrecking anything expensive (most of the time). While this is great, I always get the gnawing feeling that somehow the things I build are less real, or least less understood than building physical objects. At the very least, hacking away on a keyboard is much less romantic than hammering & soldering in a workshop with some high voltage apparatus. So for someone like myself, the appearance of low cost general purpose computers such as the Raspberry Pi has been really exciting. It lowers that cost of failure in electronics and allows a pathway for bringing things I build into the physical world.

The thought of building something that was more than just software has been eating up real estate in the back of my mind for some time now, so I finally decided that I would make my contribution to the Internet of things. As someone who has began dabbling in gardening, and has also had to weather (pardon the pun) high water costs due to Californias drought - I decided to build some sort of intelligent drip irrigation system that would only water when weather conditions required it, saving myself the time of daily watering, and also some water (and $) in the process.

The general design I came up with was to use the Raspberry Pi running a web server, this server would host a web interface and a scheduler and would control a solenoid water valve attached to the Pi. I’d place the completed device in a waterproof enclosure attached to the water supply a set of drip irrigation piping. With this in mind I put together my initial shopping list.


The hardware

The components
  • 1 Raspberry Pi (Running Raspbian Jessie lite)
  • 1 x 32GB SD card
  • 1 24V AC Solenoid water valve
  • 1 protoboard
  • 3 x 3.3V LEDs
  • 5 x 1.2 kOhm resistors
  • 1 x 2N2222 transistors
  • 1 x 1N4148 diode
  • 1 x 5V relay
  • 1 x 5V DC micro USB power supply
  • 1 x 24V AC transformer
  • 1 x plastic electronics enclosure
  • 1 x outdoor extension cord
  • 1 x power splitter
  • 1 x USB wifi dongle


Controlling the switch

I decided to use a 24V AC relay as it is the most commonly available solenoid valve. This meant that I was going to need to devise some control circuitry as the Raspberry Pi runs at 5.5v and its GPIO ports can only supply 3.3v so I wouldn’t just be able to hook it up directly. The way I did this was to use a relay that would activate when 5v was put across one side, this would be used as a switch to control the 24vac switch. To activate the relay I used a transistor with the base attached to one of the Raspberry Pi’s GPIO ports - the 3.3v is enough to energize the base of the transistor, which would complete the circuit to ground providing the 5v across the relay, letting us switch the solenoid via a single GPIO port being on/off. The circuit diagram for this is shown below.

The sprinkler circuit


Status LEDs

As a last minute addition I noticed that once all the components were sealed away there would be no way of knowing if it was running or what the software was doing, so I decided to add a set of 3 status LED’s. One LED would indicate power, one would indicate that the server software was running, and the 3rd would illuminate when the solenoid switch was activated. The circuit diagram for this is shown below.

Status circuit


Initial testing

To control the GPIO ports I used the onoff library which makes it simple to set the state of any of the Raspberry Pi’s GPIO ports. I wrote the following test script to test my initial circuit. When running it toggles GPIO port 22 once every second, which meant that once I attached the circuit above, I should hear the relay click on and off once per second like a metronome.

import onoff from 'onoff';

output = new onoff.Gpio(22,'out');

let value = 0;
setInterval(() => {
  value = value ? 0 : 1;
  output.writeSync(value);
},1000);

process.on('SIGINT',() => output.unexport());

Initially nothing worked, I found after some multimeter testing that I had soldered the pin header on backwards so none of the outputs were going where I expected them to. After filing off the notch key on the parallel cable connecting the Pi to the protoboard and plugging it in the other way, everything worked! The relay clicked happily every time I ran my test script. After determining that everything was working, and with the help of some epoxy cement, superglue, silicon sealant, and some old parts from a PC case I got everything attached securely into the plastic enclosure and added waterproof cable glands to the entry points for the power and solenoid cables.


The web UI

Libraries/software used

As mentioned previously, the idea was to build a server that would run a scheduler and a web UI, so you can set up an automated schedule as well as control the device directly from a PC or smart phone. To put the web UI part of this together I used React.js, Redux, and MaterializeCSS on the front-end, and an Express based http server on the backend. With these together I was able to put together a nice responsive interface in a short amount of time. The most complex part of the UI was implementing the configuration interface for the weather based intelligent watering (I didn’t want to water the garden if it was already raining). To do this I used the Google maps API along with the HTML5 geolocation API to determine the users current location when they elect to switch on intelligent watering in the settings. With this I could collect the users latitude and longitude coordinates which I could pass into the OpenWeatherMap API to determine the weather in the users area. In addition to the web UI I implemented a scheduler which wakes up periodically to see if the user scheduled any waterings for the current time and runs the valve for a preset interval, unless of course intelligent watering is enabled, in which case it checks if its already raining and if it is, it doesn’t bother watering.


HomeKit and voice activated control

Libraries/apps used

While having an intelligent watering device with a webUI was pretty cool, I wanted to take it to the next level by adding integration with Apples HomeKit, and enable voice activated control via Siri. For this to work I needed to implement a server that implemented the HomeKit accessory protocol. Luckily theres a really good library for Node.js called HAP-NodeJS which makes this a fairly simple process. You need to feed into it some configuration information about your accessory, and provide some callbacks into the HomeKit events such as toggling the power status. The second step is that you need an app to add the accessory to your HomeKit ‘home’ (For some reason Apple don’t provide a built in app to do this), so in order to do this I downloaded the free Elegato Eve app. I can’t really speak to its quality for the more advanced HomeKit features, but its free and it did what I wanted which was to register my accessory with HomeKit, so I could use Siri to control the valve. Adding the accessory was simple - once I had the Hap-NodeJS server running on the PI, the water valve showed up as an accessory in the Eve app which I then added to my ‘home’. Once I did that I could tell Siri to switch the valve on and off, and it worked!

Get the source code and schematics here

Star Follow @mrsharpoblunto

Latest tweet

News Archive