PROJECT: Half-Life 2 AR2, Update #8 - Closed-loop Control

In this post I go over my current solenoid/firing pin control methodology and how I aim to improve it

With the current AR2 prototype I am driving the solenoid with a constant frequency/duty pulse, as there is no feedback in the engineering world this would be considered an open-loop system. Doing things this way is easy but as one might expect has some disadvantages, a couple of which are:

  1. The constant frequency/duty pulse must be carefully tuned, and once tuned the solenoid & spring must stay the same if you want reliable operation. For example set the pulse too fast/short and the firing pin would never reach the barrel, set it too slow/long and the solenoid could overheat
  2. As there is no feedback the system is unable to respond to changing/fault conditions. For example, say you are driving the solenoid directly from a lithium battery, well as the battery becomes more depleted the cell voltage will decrease. With an open-loop system this means your solenoid movement will become irregular unless you once again run through tuning

Hence the logical step was to introduce closed-loop control with the solenoid, as doing so would allow me to have the fastest possible firing rate while at the same time make the solenoid movement more resilient to external factors

Open-loop Control

As previously mentioned, this is how I was originally driving the solenoid, as in with no feedback. To go into a bit more detail, the control pulse had a period of ~190ms, ~80ms of which had the solenoid energized. The maximum reliable firing rate I could get in this configuration was ~5.3Hz (in HL2 the AR2 fires at ~9Hz)

Closed-loop Control (IR Photoreflector)

My first attempt at closed-loop control consisted of a couple of IR photoreflectors, one near the start position of the plunger and other near the end. The photoreflectors themselves consist of an IR emitter/LED paired with a matching (wavelength wise) sensor/photodiode, with both being positioned in such a way that the photodiode senses the IR light bounced from a reflective surface (like the polished solenoid plunger):

Results were somewhat promising though not as reliable as I had hoped, as the IR sensor kept getting confused by the non-reflective surface of the spring. Basically giving a fairly irregular firing rate:

Closed-loop Control (IR Photointerrupter)

With my second attempt I repositioned the IR emitter & sensor so that both were in a "line of sight" type of formation (more commonly known as an IR photointerrupter). With this arrangement the solenoid plunger now obstructs the IR light rather than reflect it:

This configuration proved to be way more reliable as the firing rate was now a consistent ~7Hz, which is a fairly good improvement over the original open-loop control ~5.3Hz

Other Options

Of course there are other ways to tackle this problem, for example Airzone has a very good video where he compares Hall effect & IR sensors. With that said here is my short summary of other methodologies:

  1. Using a Hall effect sensor to sense the slightly  magnetic plunger body. One thing to be wary of is that the solenoid will be producing it's own electromagnetic field, so you need to make sure that the Hall effect sensor does not get confused by it's presence (think sensor orientation & sensitivity)
  2. Using an Inductive sensor to sense the ferromagnetic plunger body. TI LDC0851 looks like a nifty sensor though to get best sensitivity it's best to use a planar inductor which increases the design complexity (as you need to use a 4L PCB if you want good accuracy)
  3. Using a Capacitive sensor to sense the metallic plunger body. Again TI has a cool IC, the FDC2214 which interestingly enough can also differentiate through a metallic sheet


RESEARCH: Sunglasses & Attenuation of UV/WHT Light

This project is part of the "why am I jumping to other projects before finishing off my old ones" series...

I have always wanted a compact UV capable flash light and last week got the JETBeam MINI ONE SE (it's surprising how much they managed to cram into this thing...). Well after playing around with the UV light I soon found that I am quite sensitive to it, which would explain why I tend to get headaches after spending a good portion of the day outside

To help with these headaches I have some clip on polarizing sunglasses, and now that I have a UV source I was curious how well they attenuated UV (365nm) & WHT light. So I used my works spectrometer to get some cool spectra plots

Ambient Light

Here is the ambient light spectrum after the spectrometer was zeroed (below is a roughly overlaid humanly visible spectrum)

UV Light (365nm)

0.42W/m² → 0.05W/m² (~89% reduction)

NOTE: 365nm is a bit too close to the spectrometer limits, so there is a bit of clipping happening

WHT Light

75.31W/m² → 22.12W/m² (~71% reduction)


PROJECT: Turnigy Accucell-6 FW Update & Calibration

This project is part of the "why am I jumping to other projects before finishing off my old ones" series...

Many moons ago I tried using my Turnigy Accucell-6 battery charger to log charge/discharge data via DataExplorer, though sadly I could never get it working properly. Well it turns out that the Turnigy Accucell-6 (along with a bunch of other 4 button chargers according to my colleague) is basically a rebranded SkyRC iMax B6 mini, which is fully compatible with DataExplorer :D

So here I attempt to flash the iMax B6 mini FW and calibrate the charger

FW Update (v1.12 → v1.14)

The FW on my charger was changed from:

  • Turnigy Accucell-6 v1.12 (this would have been the original FW charger came with)
  • SkyRC iMax B6 mini v1.14

Interestingly the product page for SkyRC iMax B6 mini shows v1.13 as the latest FW, however only v1.14 has calibration functionality. Also updating the FW is super simple, you just need to connect your charger to the PC (via USB) and run the flash utility "B6mini_SK1.14.exe"


This step is a bit more tricky, luckily SkyRC have a video describing the whole process:

Things you will need to run through calibration:
  1. A charged 6S LiPo battery. Since I did not have one on hand I tried "simulating" one by pumping ~4.2mA into 6 1K resistors in series, but this did not work as the load/resistance (and thus "cell" voltage) changes as soon as you connected it to the charger; meaning you will need to have a voltage source at a minimum. So again my colleague was kind enough to let me borrow his 6S LiPo battery
  2. A calibrated multimeter. I used my trusty EEVblog 121GW which I verified against a calibrated multimeter (Keysight U1241B) at work

From then you basically record the voltage of each cell (remember cell 1 is the one closest to GND) with the multimeter, and then calibrate the charger by going into "BATT METER" and holding "Enter". At this point you enter the voltage (in mV not V) you read with the multimeter for each cell via +/- keys, and once you are happy hold "Enter" again to save & exit the calibration menu

Here is how my charger performed before/after calibration:

Cell # Volt. 121GW, [V] Volt. before CAL, [V] Err. before CAL, [%] Volt. after CAL, [V] Err. after CAL, [%]
Cell 1 4.1865 4.18 +0.16 4.18 +0.16
Cell 2 4.1910 4.19 +0.02 4.19 +0.02
Cell 3 4.1879 4.17 +0.43 4.18 +0.19
Cell 4 4.1909 4.18 +0.26 4.19 +0.02
Cell 5 4.1966 4.19 +0.16 4.19 +0.16
Cell 6 4.1958 4.17 +0.62 4.19 +0.14

So running the charger through calibration reduced the error range from 0.59% to 0.17%, and given this is a hobbyist-tier piece of equipment I am quite happy with the <1% accuracy

A couple of extra points about calibration results:

  1. It looks like the charger ADC/MCU likes to round the voltage down in a curious way. For example:
    • 4191mV will be rounded down (as expected) to 4190mV (4.19V on charger)
    • 4188mV will be rounded down to 4180mV (4.18V on charger, not 4.19V)
    • 4197mV will be rounded down to 4190mV (4.19V on charger, not 4.20V)
  2. If you perform calibration more than once you might notice that the mV reading is not quite the same as the multimeter value. Lot's of other people (see video comments) report the same "issue", which I suspect is totally normal for this hobbyist-tier piece of equipment
  3. I will be mainly using this charger for LiFePO4 batteries which are typically charged to 3.65V ± 0.05V per cell. Knowing that at worst the charger error is +0.19% this means when I charge to 3.65V the actual cell voltage will be more like 3.6569V, which is well within the ± 0.05V limit

Data Logging

As expected DataExplorer now talks without any issues. Here is me charging and discharging a 2S LiFePO4 battery:

NOTE: You can plot fancier looking graphs by exporting the data as .csv and plotting it in your favorite package 


PROJECT: Woodworking & 3D Printing

Sometime in late 2018 my wife and I decided to upgrade her workspace. The initial plan was to tackle this in several sections:

  1. Build the left (self-contained) shelf
  2. Build the right (self-contained) shelf
  3. Bridge the two with a desk

Well we managed to complete left shelf within a couple of months, as for the last two... they basically took us till late 2020. Surprisingly we have COVID to thank for that, as being locked inside with nothing to do gave us a wee boost :D

An interesting aspect I wanted to try with this project is merging woodworking with 3D printing, as I felt the two could complement each other reasonably well especially with smaller fittings. So below I document such 3D printed items:

Small Drawers

Probably the only exception to the "smaller fittings" description. The larger drawer measures 320 x 300 x 70mm and both had to be split into several parts. The only things not 3D printed with these was the metal rods running through the body (for extra support), and the MDF base. Also the body is printed in PETG and fastened with Loctite Control Gel Super Glue

Drawer Handles

Wife wanted something flush yet accessible, so came up with this simplistic design

Drawer Supports

A while back we found a bamboo tray (on the street!) which we decided to convert into a drawer. Initially we were going to mount the drawer slides onto another piece of wood, but after realising how much work would be involved (and how uncool it would look) we decided to 3D print the supports instead

KVM Switch Bracket

Couple of brackets that hold a KVM switch (Unnlink 2 port). Side note, the switch makes it incredibly easy to jump between the laptop & desktop

HDMI Splitter Bracket

Couple of brackets that hold an HDMI splitter (CABLETIME C355). Again super useful for changing between the TV and monitor

Cable Holders

Super simple cable holder. Initially this was twice as tall (so you could cram more cables) but someone wanted a more flush design...

Outlet Bracket

Couple of brackets that hold an 8 way outlet (HPM D105PA8CC). The cylindrical cut-outs act as a cable runway (unfortunately the outlet mains cable was on wrong side...)

Wood Spacer

This one is probably the most "pure" merger of woodworking and 3D printing, a simple 7mm thick spacer that allows the desk and shelf surface to be level 


Fern Pot Brackets

Don't recall the exact plant pot & saucer combo, but suspect it's something like this & this

Laptop Stand (ゴ ゴ ゴ ゴ ゴ ゴ...)

Simple Metabox Alpha N850HJ stand, same one shown here

Desktop USB & HDMI Bracket

Makes USB (2.0 & 3.0) & HDMI ports more accessible, again same one shown here


PROJECT: PC Upgrade & Benchmark Results

Since 2011 I have been rocking on an Intel i5 2500K (man this thing should go into a museum for how well it has aged...), and only a couple of years ago did I "upgrade" to a Intel i7 3770K. I did this primarily for VR, as my old motherboard did not support the correct USB 3.0 specification... 

Well early this year I decided to do a proper upgrade, but before doing so I ran some benchmarks to compare the old/new PC. Turns out the new hardware is at least twice as fast, so I am a happy camper :D

Old/New PC Specifications

  Old PC Specs New PC Specs
CPU Intel i7 3770K Intel i7 10700KF
CPU Cooler Hyper 212 EVO be quiet! Dark Rock 4
RAM Kingston HyperX Beast 2x8GB 2133MHz DDR3 Team T-Force Dark Z 2x8GB 3200MHz DDR4
GPU ASUS GTX 1060 6GB Gigabyte RTX 3070 Gaming OC 8GB
SSD Samsung 860 Evo SATA III 250GB SSD Kingston A2000 M.2 NVMe 1TB SSD
MOBO Gigabyte GA-Z77MX-D3H Gigabyte Z490-GAMING-X
PSU Corsair HX650W 650W Gigabyte AP850GM 850W

Benchmark Results

  Old PC New PC
3DMark CPU ("Time Spy" test) 4398 9857
3DMark GPU ("Time Spy" test) 4162 14086
Steam VR Score 7.1 11.0
SOLIDWORKS (_AR2_Assembly.SLDASM) 17sec 12sec
Altium (Solar-heart_MAIN_v11b.PcbDoc) 12sec 3sec

Benchmark Results (Extra)