Thursday, September 8, 2022

Roomba 655 DIY virtual wall

 I had the good fortune to get a Roomba 655 from thrifting the other day.  Along with it, I got two Roomba bases and a Goovi F007 base, just in case I might find it useful.  I gave everything thorough cleaning and then started into the electronics.

Putting the Roomba onto the base, I would see it light up to charge, and then immediately turn off.  This is typical of fully discharged, rechargeable battery packs that no longer have (or can sustain) a minimum charge.  The Roomba bases appeared to be generating a clean 3+ VDC charge, so they looked ok.

I removed the underside panel per documentation, and found the power pack..  Sure enough, there wasn't any power coming from it.  I don't understand why the power packs have four contact points on the bottom.  One clearly seemed to be a direct connection to GND (based on ohming out the lines between the battery pads and the charger connection points), but the purpose of the other three wasn't clear.

I was hoping to find some instructions for refreshing a pack outside of the machine using a NiMh charger, but there wasn't one on the web.  So, I ended up ordering a $20 pack online.  It arrived, and I put it in, and charged it up.  With just that, the Roomba worked!

My next step was to build a virtual wall.  There are multiple pages out there, but they seem to root to https://github.com/MKme/Roomba and the YouTube video linked from there.

The very basic idea of this: use the IRremote library for an Arduino, run it at 38 kHz, and pulse one for a second, and then off for a second.  That's all.  You get an infrared LED, which can be pulled from most any remote (these show up regularly in the thrifting bins for cheap).  The anode connects to 5v and the cathode (the side with the visibly larger metal inside the LED) goes through a 110- or 220-ohm resistor to the IRremote output pin.

I verified I had working components by connecting the IR LED with 5v - anode - LED - cathode - resistor - GND, and then looked at the LED through my phone camera.  It would show up pink-ish there when on.  That way, I knew I had the orientation correct, and that the LED wasn't burnt out.

Attempt 1

I tried setting up the sketch for an Arduino Pro Micro, and connected to pin 3 as defined.  After wiring it up, I got no light from the LED.  I read some other articles indicating there were issues with the IRremote library and the Pro Micro (32U4).

Attempt 2

I then tried the same sketch using an Arduino Mega 2560.  Again, no luck.  I read one article saying that the Mega 2560 uses pin 9, and if I were to just pinMode(9,OUTPUT) and digitalWrite(9, LOW), it would work.  Uh, no.

For both Attempts 1 and 2, there were pages suggesting making modifications to the IRremote library directly.  I looked into that, and found the lines they were suggesting to modify weren't even in the library any more.

Somewhere in this, too, I saw an example referring to "IrSender" as a known object instance or there were class-level methods associated to it, whereas the original MKme code used Irsend.

At this point, I realized I might be working off of the wrong library version.

Attempt 3 (success)

For my third attempt, I went to a plain Arduino Uno.  It turns out I got one from thrifting.  It was within a Thames & Kosmos electronics kit.  Nice build.  The Uno is buried inside of a handheld gamepad-type thing, and has its own rechargeable battery under the board.  The one I got had a faulty roller switch thing, but the Uno worked.

I first got rid of the old IRremote library that was at

$ARDUINO_HOME/libraries/IRremote

Next, I downloaded the IRremote library version 3.9.0.  I installed it as

$ARDUINO_HOME/libraries/IRremote-3.9.0/{examples, pictures, src, etc.}

Then, I looked at the example

$ARDUINO_HOME/libraries/IRremote-3.9.0/examples/SendDemo/

In that folder you'll find  

PinDefinitionsAndMore.h

and

SendDemo.ino

The sketch first includes the .h file before including <IRremote.hpp>.  Then, it does things based on the pin definitions within setup().  I didn't really care about what it was doing in loop(), since I knew I'd be replacing that.

So, I created my own sketch, vwall2.ino.  As normal, once I saved it, it went into $ARDUINO_HOME/vwall2/.

I copied the example's PinDefinitionsAndMore.h into that folder.

Then the sketch basically was:

#include PinDefinitionsAndMore.h

#include <IRremote.hpp>

Duplicate (verbatim, I think), what's in setup().  Some of that stuff you don't necessarily need, but it didn't hurt to have it.  And, the diagnostic stuff printed to the Serial Monitor was interesting.

Then for the loop(), I did this:

void loop()
{
  //These values should work for pre i models of roomba
  // See timeline at https://en.wikipedia.org/wiki/Roomba
  IrSender.mark(1000);
  IrSender.space(1000);
 
  //For "i" models (i3, i7 etc) use the following
//  irsend.mark(500);
//  irsend.space(7500);
 
}

So, basically, the loop is the same as MKme/Roomba's, but using IrSender.

Also, I googled the Roomba model timelines and found that the 655 preceded the "i" series, so I used the 1000 / 1000 timings.

With that sketch, the default output on an Arduino Uno is pin 3, and I got about 1.1 VDC by voltmeter, and observed the IR LED showing pink through the camera lens.

Physical build

I grabbed a chunk of 30-hole perfboard, and soldered things up.  At one end, I made a 5-pin edge connector with part of an old wire-wrap header.  I bent the pins (using another chunk of perfboard for spacing) so that the pins would end up parallel to the board.

 


The intent was to put the board in where the pins say 5v, reset, 3.3v, Aref, and 5v.  I chose to use 5 pins for the edge connection for stability -- but of course if you do the same, be sure to make sure you don't solder-bridge any of those pins.  The circuit only touches one 5v pin, and since that appears at either end, it makes it so that I could mount the board either way.  I like having it so that the board is on the inside of the headers, so I'm using the 5v pin that's closer to Aref.

Kosmoduino board.  Red = either 5v point.  Blue = used for support.  Pink = IR LED signal

 

The 5v pin then wires up to the top of the board, and connects to the anode.  The cathode side connects to the 110 ohm resistor (in the picture I have two 220 ohm resistors in parallel).  From there, I just soldered to a patch wire, so it lets me plug the other end of the patch wire to pin 3 on the Uno.  It's not as elegant as bulding a real Arduino Uno shield, but having the wire stick out is a hacky way of letting it be reversible.

That's all there was to it.  The great thing is that the Thames & Kosmos "gamepad" serves as a stable platform, and also provides a physical switch and a rechargeable battery pack.  So, I can just put it on the floor somewhere, turn it on, and point it where I want it.


 

The LED stands about 4.25" (11cm) above the floor, and that's tall enough for the Roomba to see it.

The LED points out from the perfboard, which means it's shining a cone of light that's roughly along a plane parallel to the floor.  I'm not sure what the specific field of view is for the LED -- that is, how wide the cone is -- but it's pretty tight.

Examples of light on/off as seen by the camera (not visible to the naked eye):



I'm also not sure how far the LED shines. In practice, it's at least 4' (1.2m), which is all I need to keep the Roomba from running down a hallway.

Thanks to MKme for the IR frequency and pulse info, and original code. 

Next steps

I think there are a couple of things I want to do next for this project.

First, I measured the floor-to-light height of the Roomba base itself, and it looks like the LED is at a height of around 9.5 or 10cm.

Second, I don't really need a circuit board for this, but I could use a proper shield.  So I might recraft this as a shield on the Uno, and then have a flexible, bendable thing that leads to the LED.

Where that takes things, then, is to make something more interesting as the virtual wall LED holder.  What kinds of things are 10cm floor to ground?  Well...

- Mrs Potato Head's hand is about that height.

- The face mask of my translucent robot dude might work.  But he is a little tippy.

- My Lego Ninjago clock dude.  His hand can be positioned to hold something.

Or, 3d-print something more interesting.  So many possibilities!

I also want to try to build this using something simpler than an Arduino.  I saw someone using an ESP32.  Something cheap, cheap, cheap.  I wonder if I could fake it out using some 555 timers.  Some of the IR remote controls I've broken open don't even have a crystal inside of them.  They use a dedicated IR chip that has a selectable frequency, and can be programmed to emit different things.  But that would get more expensive in terms of tooling...


Thursday, July 7, 2022

Reviving Thomas

Thomas the Tank Engine, large scale!

I had the good fortune of finding a Thomas the Tank Engine set while thrifting.  

Actually, all the trains shown here were in the thrifting bins, and I collected them up over two or three visits.  The big one is the one I'm talking about in this blog.  The most common type, I think, is the Brio-sized one with the silver, metal/magnetic bump on the front.  The small ones are here just to give a sense of scale.



Initially, I spotted train tracks and train cars strewn through the bins, but no engine.  I figured they were something nice, because of the metal edge along the tracks.

I collected all the pieces I could find into a plastic container, and also found an electronic thing that looked like the signal connector for power, though it oddly had a 1/8" stereo headphone kind of jack on the end.

The cars included coaches Annie and Clarabel, and ballast car S.C. Ruffey.  What I didn't find was Thomas.  Disappointed, I put the container back, and wandered around.  A few minutes later, I found Thomas on his own in a whole separate area.  I rushed back to my container, only to find all the pieces strewn about again.  Another person had taken Annie and Clarabel, hoping to turn them into succulent pots.  But, thankfully, she offered them back to me, and soon I had all the pieces together again.

On a quick inspection, I found that I had a reasonable number of curved track pieces to convince myself that a full circle could be made, plus a good and even number of straight tracks.

I didn't get special things, like switching tracks or elevated sections, and I did not get a variable power supply.

As it turns out, it's a Bachmann set, "large" scale or "G scale".  And those aren't cheap!  On seeing what people pay for these, it was tempting to put it on eBay right away.  But it also was really cool, so I started into repair mode.

1.  Wheels

At least a few of the train cars had wheels that were off kilter.  Fortunately, the axles themselves were straight, and the wheels were not bent off angle.  It only took some gentle prying of the plastic to snap the axles back into place.

2.  Tracks

The tracks mostly fit together well, but on closer inspection, there were a couple of things wrong.  Some were bent, but only slightly.  The tracks are made with a plastic base and an extruded metal rail.  At the end of each rail, there's a way in which they can connect, one sliding into another with a good bit of care.

Some of the tracks were bent such that the metal was lifted up at the end, and had come out of its securing, plastic clips.  Some gentle use of pliers and hand bending worked to get them flat again.

Then, there were pieces where the plastic clips were missing.  These pieces usually are slide inside the extruded metal, protruding out the end, and the interior side snicks into the plastic base so it doesn't move.  They help align one track to the next.

Also, I found that the metal rail could be slide gently along the plastic base's clips.  What was happening was that some tracks had the rail offset, so end distances weren't consistent.  The saving grace was that each had a clear midpoint in the metal, so I could align to that.

After some measuring and doing a few 3d-printed prototypes, I arrived at this design:


 

based on this sketch


 

with the base extruded 1.2mm and the top extruded 7.1mm.  The pointy "triangle" end was mirrored, and the entire length when done and adjusted was 36mm.   

These didn't have a clip or a button protruding at the bottom to help "snick" the connector into the plastic base's hole, but then I found the tolerances too tight to slide them in anyway, unless there were some kind of spring mechanism to the clip.  So, I chose to make the connectors easy to print, and I really cared, I could glue them into place.  I ended up printing about eight of these.

3. S.C. Ruffey bumper



The cars come with circular bumpers at each end.  One of those on the S.C. Ruffey car was severely bent, so I ended up breaking it off and re-glued it with CyanoAcrylate glue.  That worked well.  It's an area of the car that would only be under stress in a thrifting bin, not during normal operation.

4. Train car coupler springs

Each car has a latching connector that swivels left and right, and also bends up and down.  Many of these were broken. 

The mechanism basically relies on a spring made out of plastic.  My initial solution was to use a rubber band, but eventually I designed a simlar plastic spring.  Mostly, this was just a challenge to see if I could make one.

This is an example of a broken spring on a car.


 

This is the replacement "spring".


 

It's based on this design:


 The sketch for that looks like this:

Given the sketch, I used a "square pipe" operation along the curves to get the more challenging part of the piece built.  I chose a square pipe as opposed to a cylindrical one in order to avoid 3d printing problems.  

The curves were initially created using a bunch of circles, and then I trimmed away the arcs that I didn't want.

The central part with the screw hole is extruded 2.1mm.  The peg is extruded 2mm, but could be even smaller as it barely fits into the hook hole.

The challenge with this piece went further in that you have to be careful about thickness generated by your 3d printer.  You really want the curves to be a single line of filament thick.  If you have two lines, it gets too thick and inflexible.  After exporting this piece in .STL, I would load it up in PrusaSlicer and check to make sure what it was doing, and then iterate.

Here is the spring, mounted on the car.  You can see how it bends from the mounting plane in order to slot into the hook's hole, and on top of that, it has to be able to bend left or right as the car moves.

 



The problem now is that I printed these out of PLA, and that gets brittle in a short amount of time.  Eventually, it breaks, like this:


 

So my next steps: re-print these in ABS, try "welding" the original springs in cases where I have them, and/or try to rebuild the whole car-to-car connector mechanism so I don't have these funky hooks.

5. Thomas - eyes

Thomas arrived a little scuffed up.  His eyes were poked in.  His top was missing.  And he was missing the "lantern" on the front right.

I also didn't really know how Thomas worked, electrically.

In order to fix Thomas's eyes, I unscrewed the base from the top, and found that each eye was just plastic semi-sphere connected to an arm with a funny rectangular "hook".  Since I had opened up the machine, it was plain to see that the train had some geared motors -- one to move the wheels, and another for the eyes.  I presumed they were DC motors.

With some patience, I was able to align the eyes while re-assembling the top and bottom.  That's just physical alignment, nothing special.

6. Thomas - power

After some reading I figured I was missing a 16 VDC variable power supply.  Ideally, that would have a reverse switch, too.  I noodled on this quite a bit, thinking I'd make a 555 timer PWM controller for it.  Some sites say PWM works on some trains, but some others have electronics (noises, smoke, etc.) that don't play nicely with PWM.  For this train, it's just engine power, so PWM would work.

I couldn't find my 555's -- I know they're around here somewhere... -- so I ended up just using a lab bench power supply to get the train moving.  I ohmed out the pins, and found that the 1/8" stereo connector was only using two of its three pins.  The tip was not connected.  The middle and "barrel" (the ring closest to the wire end) were.  I have the connector set up such that the power supply is outside the track oval, and that means I can use ground on the barrel and V+ on the middle ring to go forward.  

I just used alligator clips to connect the power supply to the 1/8" plug.  Some day, maybe I'll rip an 1/8" jack out of something, and make a proper connection with a DPDT switch so I can have movement in reverse without messing with the alligator clips.

With around 6V power, the engine ran!  It was a little squeaky, so I dabbed a little sewing machine oil at the points where the train arms connected to the wheels.

7. Thomas cab

Thomas was missing his cab front, back, and roof.


 

Fortunately, there are slots that the front and back walls can fit into.  Calipers provided a good idea of the distance of slot bottoms to the roof level.

For each, though, there are round portholes and it wasn't as easy to figure out how to position those.  What I did was find a head-on view of the train on the web.  That gave me rough proportional distances and sizes, so I could figure out reasonable porthole dimensions and positions.  That also gave me a decent idea of how high to make the top arch for those pieces.

The next problem was that the front wall would run into the cylindrical tank of the engine.  The good news there was that the tank's diameter was pretty cleanly measurable on the original, and using some proportional positioning, I could figure out its placement with respect to the roof height.

This is what the model looked like for the front and back walls.  I did the front wall first, and then copied it, and extended it downward (without the tank arch) to form the back wall.  Each is extruded to 1.6mm thickness.

This is the sketch of the front wall

The back wall ended up being 39.2mm from slot base to the place where the right/left sides meet the arch.

A few corrections on this could be made.  The front wall's tank arch is a little shallow, so the piece tips a bit.  Also, both front and back would have been modeled better with the right and left side walls taken into consideration, so that the roof would have had some overhang.

Both pieces were printed flat on the 3d printer, and the face that met the heated bed was used as the outside, since it came out smoothest.

The front and back walls were painted with Testors light blue enamel paint, blended with some dark blue paint.  But, I didn't notice that the light blue was flat, where I should have had glossy; and the dark blue paint was acrylic instead of enamel.  It's close, but not perfect.

The front, at least, is supposed to have yellow trim around the portholes.  I used Testors light yellow enamel for that.  

I printed another circle to go in the circle of the portholes, and added a 9/32" hole in the middle of it.  The disc went into the porthole, and then the whole thing went onto an old record player.  I got that spinning at 33-1/3 RPM and gave it a few coats.  

 



 

In retrospect, I would have been better served to have made a separate porthole trim piece, printed it and painted it separately, and glued it into the front wall's porthole.  That would have made for much cleaner painting, and of course dimensional accuracy (compared to me, holding a paint brush).

8.  Thomas roof

The roof piece was modeled after having created the front and back walls.  Those gave me the dimensions of the top arch.  The head-on picture from the internet gave me a sense for thickness.

Oddly, I don't have the 3d model for that part any more.

For 3d printing, I printed it vertically, so that the layer lines would go horizontally (port-starboard relative to the train, lowest layer in back, highest layer in front) with supports.  It printed well, though the area where were supports ended up wavy and ugly.  No matter, that part is hidden behind the cab's back wall.

I sanded the roof top down quite a bit, and then gave it several layers (thinned) of Testors glossy black enamel.

Prior to sanding and painting, things looked like this:


 

9.  Thomas lantern

After I was all done, I thought I'd build the lantern that was missing at the front of the train.

It's supposed to go where those holes are.  The holes are about 11mm apart, and can accommodate at least 1.6mm OD (including sheath) hobby wire.

Here are some iterations of prints that I did for the lantern.

 I looked at a bunch of videos and pictures, and modeled it initially as a sphere within a cylinder on top of a loft-extruded base.  I printed it with the base on the build plate.

There were holes on the original train that presumably held the old lantern in place.  In my v1 rendering, I just had holes in the base of the lantern, and thought I'd have screws coming up from underneath to hold it in place.

However, the base of my lantern was so thin (2mm extrusion) that I would have a hard time getting a screw to bite into the plastic and hold, and yet avoid poking through the top.

My v2 lantern used the same model as v1, but I just added pegs going down, and sliced it with a plane from left to right.  That allowed me to print both halves and glue them together.  In doing that, the holding pegs were also split in half.

That looked good and functioned pretty well, but the seam was quite visible.


 But I wasn't satisfied with that.  I decided I really wanted it to light up.  I re-modeled the lantern with the idea that I'd have an LED inside, rather than having the sphere.  This is what it ended up looking like.  Compared to v1, it obviously has a hole cut out for the LED, but also a more attractive side structure, and it's thicker in front. Why?  Because in its original form, the front was so thin that light would shine through the plastic.


The based of the lantern has some slots that lead to the points where the holes reside.

From there, I took an LED and carefully bent its legs so that they fit in the bottom slots.  This was tricky, because I had to make sure the right amount of LED bulb was visible within the lantern, and the wires slotted in properly, and then were bent so that they would go into the holes in the front of the train.

This is what it looks like, all mounted up.


 

Once I had that figured out, I moved on to the electronics part.  The main part was a little circuit board that came from some kind of solar-powered light.  It had a latching push-button switch, and a Q5252 circuit board on it, and a 4 ohm resistor.


 The Q5252 is a cute little thing with very poor documentation.  Basically, it appears that it can be powered from 0.5v to 1.5v, and then it provides a boost mechanism to get to higher voltage, if you attach an inductor.  I didn't have an inductor, and there wasn't one on the board so I left that off.

The Q5252 also provides contacts for connecting a solar panel to charge a little Lithium Ion battery.  The solar panel was missing, or I'd already snagged it for some other project.  I de-soldered the battery terminals, and wired those to a AA battery pack so that a single AA battery could power it.

In an isolated test, I verified that in that shape -- no inductor, no panel, single AA battery -- I could switch on an LED and leave it on safely without burning it out.

As such, I replaced the LED output of the board with wires connected to a screw-down terminal block.  I then added wiring from the lantern's LED legs and clamped them to the circuit, and tested it.  Satisfied with that, I 3d-printed some clips to hold the wiring, glued the lantern and clips in place, and then just put blue tape over the remaining wiring so that the battery pack and circuit could reside in the cab.

Here's what a clip looks like.  The shorter flat glues upward to the base of the train.  The slot size is specifically designed for the 24ga silicone-coated wires that I got for another project.  They measure out at about 1.6mm OD but can squish down to around 1.45mm.  As such, the entry point (top, left, in image below) has to be wide enough for the wire to get in, and the slot itself is a little tight so it holds on to the wire nicely.

While it'd be nice, visually, to have chamfered or filleted corners on this, I just left it as is.  I checked against how it'd actually be rendered in PrusaSlicer to make sure it'd be sturdy.  Having chamfers or fillets sometimes makes for more retractions and skips in the print.

This is what the clips and wiring look like under the engine (laid down sideways).

I chose to send the wiring up the side of the engine, rather than drill holes.  I also chose to use the AA battery pack to simplify the electronics.  If I were to run the light off of the track power, I'd have to contend with a +/-16VDC voltage swing -- so... rectifier, step-down, etc. -- and then drill a hole somewhere in the body to feed wires through.  That's all doable, but at this point I just have some things glued on, and no holes drilled.

Here's a side view, where you can see the battery pack, etc., ingloriously lumped into the cab. 

And here's a view with the light turned on.



Done for now!

Here's Thomas running at about 10.5v.  He has a tendency to de-rail currently, probably because several of the PLA coupler springs are broken.  Or, maybe he de-rails because he's trying to stay true to the original TV series.



Will I sell the set?  Probably not.  It's nice enough to think of taking it out each Christmas.

Friday, June 10, 2022

Drilled dithered dog

I was presented with a wonderful little 3018 ProVer CNC mill a little while ago.

After a test run with it, where it cut really clean isolation channels for a PCB, I figured I could move on to doing something artistic.

I decided to make a "grayscale" image of a dog by drilling lots of holes in a black surface.  The black surface I found was a "chalkboard" from the $1.25 store.  It's basically 3mm pressboard with some kind of plastic surface.

The variations of light would be achieved by using different size drill bits: 0.6mm, 0.8mm, and 1.0mm.

Here's an example dog:


In order to get a good result, I did some Photoshop magic to eliminate details:

Then, I converted to grayscale and assigned a black background:


and then rotated the image to match the layout of the physical material that I'd be drilling:

Through experimentation, I found that playing with lightness and contrast on specific areas, and adding a bright highlight edge would provide a better result in the end.  Note how I brightened the eyes, and upped the contrast overall here.

Coding

To reduce the image in resolution and color space, and to generate gcode for drilling, I used a combination of Python 3.9, Python image library (PIL) and numpy.  For a coding environment, I just used IDLE.

Hexagonal pixels

My thought around how to lay out the drill holes was to use a pixel pattern comprised of equilateral triangles, rather than the typical "square pixel" kind of layout we're used to.

The holes ended up being 1.4mm apart so that if I had several 1mm drill holes next to each other, there still would be enough "wall" remaining to prevent breakage.

If I were to have a traditional X/Y grid of pixels, each hole might be 1.4mm apart along X or Y, but along the diagonal, a hole would be 1.4mm * sqrt(2) from its neighbor.

Instead, I chose to use equilateral triangles.  That means each hole center is 1.4mm from all six of its neighboring holes.

To achieve this, I could march 1.4mm along a given "scanline" on the X axis.  As I'd move Y along, it would move that step amount (1.4mm) * sqrt(0.75).  Do some geometry and you'll see where that came from.  On every other scanline, X's starting location would be half of the step amount.

Each drill point could then be mapped to the original image resolution, or vice-versa.

Averaging

I take the center point of the mapped pixels in the original image, and grab a square of pixels from it.  Then, I use numpy to logically "AND" that with a (255,255,255) circle whose diameter is the same as the square.  It's not exactly the hexagonal pixel it should be, but it's close enough.

Once I'm done with that, I have only a "circle" of the grabbed pixels, and I can just compute an average of the non-black pixels.

Since I'm dealing in grayscale values -- but with an RGB-type image -- I end up with pixel values like (5,5,5) or (142,142,142).  All the R, G, and B values are the same for each pixel, and each is in the range 0..255.

From there, I make a crude attempt at mapping the 0..255 values to the drill bit size that would emit a corresponding amount of light.  I'm doing that very crudely right now, just dividing the 0..255 value by a divisor.  The higher the divisor, the darker the result, and vice-versa.

Visualization

I added a few things to help visualize what was going on.  At first, I printed an ASCII character to represent the darkness and lightness of the holes as they were being generated.  These wouldn't come out in a triangular/hexagonal grid, but would give me a rough idea if I was getting the right result.  Also, it would be more vertical than horizontal because of how our fonts work, typically.  This is an example of some of the output:



(The numbers on the left of each line were just confirming to me that I was alternating X positions on every other scanline.)

Image rendering

Once I was satisfied with that, I added code that would construct an actual image, creating white circles of appropriate size for each drill point.  This is a more accurate representation of what the physical result would be.

The initial implementation did straight-up averaging and no error distribution (dithering).  I found that generally a lower divisor would give a better result.  This image is no dithering, divisor 3.65.



 

Dithering

With a little bit of coding, I added dithering, which would distributes the light energy error to neighboring pixels (one to the right, and two below).  "Error" here is defined by the amount of light coming out of a given hole (math out the PI*r^2 of each drill bit) compared to the average light value I computed for the average of the pixels in a chunk from the original image.

Each of the right, down-left and down-right pixels receives 1/6th of the error energy, so it's all done in one pass from top to bottom.

The image below has dithering turned on, 1/6th distribution of error to neighbors, and a 3.95 divisor.



The overall result from dithering is noisier but, in ways, more detailed.  You can see a little bit more detail in the dog's nose, ears, and chest "coloring" with dithering turned on.

Satisfied with the simulation, I did a simple conversion to gcode.  As I would draw each dot on the simulation, I would add the location to the appropriate drill bit's set of coordinates.  So, each drill bit gets its own array of places to drill.  

I then iterate.  Each drill bit gets its own gcode file.  I then walk through each location and issue the appropriate commands to lift the milling head, move, descend slowly to the surface, and then drill through the material.

I thought about making the code a little smarter about nearest neighbor computation to reduce the travel time of the milling head, but decided that's not worth the effort.  I can just let the mill robot its way through, and perhaps it makes for a more accurate result if I'm primarily moving left to right.  (Backlash by doing lots of pos/neg movements might make the result wiggly.)

Milled result

The milled result is pretty darned good.  The only real problem is that the surface of the "chalkboard" has a tendency to tear, so I ended up having to use a Sharpie to blacken the pressboard where the surface was lost.


Lighting

While the initial result was pretty cool, the better result comes from backlighting.  Here's what it looks like with just monitor white behind it.


Shadow boxing and more lighting

I headed out to the nearby Goodwill and found a few shadow boxes that I could repurpose.  That would serve as the frame.  It was a cheapie home decor item with some kind of thing that would seem cultural inside.  I used my hot air gun to melt the hot glue that held the back in place.

I also had had the good fortune to have found a Lampeez "3D Lamp" on a prior thrifting adventure.  Those lamps just edge-lit acrylic with a drawing on top, laser-cut (apparently) to the borders of the drawing.  They're not really "3D", in my opinion.  They're about a 3D as my dog chalkboard.

The Lampeez base has interesting stuff in it.  It's powered by battery or USB, and it just has a board inside that does some magic and turns on some SMD LEDs.  There's a touchless switch mechanism that uses a single wire like an antenna.  Newer ones come with a remote control and the board sports an IR receiver.

I took the Lampeez PCB and desoldered its touch sensor and IR receiver, and then added extension wires to each.  The touch sensor wire's end is connected to a small piece of metal -- just a 1" x 1" piece of aluminum foil is all it takes -- in order to work again.

I taped a sheet of white printer paper on the back of the dog chalkboard to help diffuse the light.  Then, I mounted the Lampeez PCB to the back panel of the shadow box.  I cut a little hole in the back of that panel to allow the USB power line to come out.  (If someone wants, this could be replaced by battery power and a switch, instead, but you'd have to make it rechargeable.)

The aluminum foil antenna is just taped to another place inside the back panel.  A touch on the outside of the panel activates the switch, and pressing and holding there will turn off the device.

The IR receiver is taped to the back panel, and faces the front of the box.  As it turns out, the holes in the dog chalkboard let the remote control signal through to the IR receiver, so that works like magic without have to add a special hole just for that component.

The end result currently looks like this.  It's presenting a square result right now, just because that's how I found the matte of the shadow box.  I might change that up so more of the dog can be seen.  The remote control lets me set different colors, or go into a mode where it fades across different colors.




Before and after

"Pixel" shape variations

The original code just drew a circle for each chunk of original image pixels that would be averaged.

I tried a few alternate implementations where I draw a hexagon -- either with flat top or flat sides.  In theory, that would provide a more accurate representation of the original data.  But that doesn't necessarily mean you get a more aesthetically pleasing result.

What it means is that along with choice of physical size, dithering, and divisor (aka gray-to-bit size mapping), the chunk pixel shape can provide more options for how the end image will be built.

Here are comparisons.  In order, they are pixelShape = circle, flat-top hex, flat-side hex.  If you look closely, you'll see differences in the dog's right eye, brow, and nose.  If these were overlaid, you'd see many other subtle differences.

 
pixelShape = circle


Saturday, March 19, 2022

An IR receiver marked CHQA

 I was given an inoperative little mini drone.

It has a little hockey puck activator like this:

Starter for drone

 

I left that alone, but took the drone itself apart, and found a little lithium battery that probably had drained beyond rechargeability.   I made a few attempts to recharge it, and gave up.

The inner circuit board was cute.  It had an LED tower set up as a PCB mounted orthogonally to the main PCB.  That LED tower is removed, but you can see the rectangular hole where it once was, and the solder points on the back where it was attached.

drone board top and bottom

 

I've removed the motor mechanism and propellers.  I also have de-soldered the IR LED receiver, and what appears to have been an IR LED transmitter.  The transmitter pointed downwards and could have been used for sensing distance to the floor.  (I don't know if this particular drone had side sensing ability.)

The IR LED transmitter is a simple two-wire device with a 1.0v voltage drop, determined by voltmeter testing.

The IR LED receiver was marked QCHA on the top, and I didn't find any clear specs on the web.

CHQA IR receiver

 

After doing a bit of track tracing (and roughly remembering how the device was originally oriented -- should have taken pictures before de-soldering) I figured the middle pin would be ground.  It seemed to hit larger tracks.

I then made a crazy guess about which of the other two were power vs. signal.  Both continuity-tested to points on the unlabeled, 4x2 SMD on the board.  One touched the corner, and another touched one of the middle pins.  Just based on that, I guessed that the corner-touching pin would be Vdd, and the other would be signal.

I put the device onto a breadboard as shown, but before applying any power, I just set my voltmeter in voltage mode, connected COM to the middle pin, and V to the blue wire.  Nothing was connected to the red wire (presumed Vdd).  Then, I pointed a random IR remote control at it, and pressed a button, and I could see a response in the voltage.

So with that, I set up the Eventer KPS305D power supply, measured its output at 3.3v, hooked up power to the IR receiver, and fired it up.  Whew, no magic smoke.

I then attached checked the voltmeter and found it running at a steady 3.3v.

When I pointed the remote control at the device and did various button presses, I was the voltage drop to various levels, typically around 2.5v.  Assuming my voltmeter is precise enough, I was getting various voltages on the different lines.  I suppose that is indicative of the different wave forms -- perhaps even serialized binary values -- generated by each button.

So, now on to scoping it and seeing how it behaves.  I know, lots of people have done this IR stuff before, and there are libraries.  But I wanted to see if I could do this on the cheap with a salvaged receiver.

My main surprise thus far is that the signal line was giving me a steady 3.3v but then maybe it means there's a pull-up built into the device.  Or, it just means that I really should put in a pull-up or pull-down of my own.  I'll have to go read some specs to get a better guess as to what device I have.

Which device?

The Vishay TSOP34438 (TSOP344 and TSOP348) seems to have the same pinouts and form factor as the one I have.

The suggested circuit diagram on its datasheet suggests that the OUT pin is connected directly to the receiving microprocessor, and an internal 30k resistor between Vs and OUT is built into the device.  So that makes me comfortable that I'm seeing the voltage value sitting at Vs when idle.

The remote control I was testing with was a Sony Audio System RM-S102.  I suppose if I look more closely at it, I can figure out the carrier frequency (30, 33, 36, 38, 40, or 56 kHz) and thereby nail down the more specific IR receiver module.  Or, I can just be satisfied that it appears to react to that remote control, and play with it.

The application circuit on the provided diagram suggests R1 and C1, but says I should choose them to "reduce supply ripple for Vs < 2.8V".  Since I have Vs higher than that, I think I can do without R1 and C1 entirely, though I want to see the signals on a scope, and see if there's too much noise.

Next steps

1.  Plug it into a scope and see what happens

Yep, getting clean readings.  I took these pictures using a :Logitech webcam pointed at the oscilloscope and using the Microsoft Camera app.  It puts pictures into the Pictures\Camera Roll folder.  Because of how the scanline traces run through, and the brightness of my environment, I took about 6 to 8 pictures per shot, and picked the one that showed the trace best.

Examples of buttons and their IR readings:

POWER:


 

PLAY:

PREV:



NEXT:


VOL_UP:


VOL_DOWN:


STOP:


The drone starting fob gave a momentary wave form:

2.  Plug it into an Arduino and see if I can get a simple sketch together (using examples provided by many others, and an existing library) to reuse the buttons of the remote control.