• It's alive!

    RobG05/23/2024 at 06:10 0 comments

    First time putting together all the parts:

  • Coming together now

    RobG05/20/2024 at 07:17 0 comments

    I've chopped up something like 2.5metres of 2020 aluminium extrusion and turned it into a more permanent, more rigid frame for the drum feeder, vibration feeder and sensor head:

    The drum is belt driven from a DC motor/reducer gearbox running at about 200rpm. I needn't have worried about the belt wandering off the drum - it's absolutely fine, without any need for additional guides or track to keep it centred. 

    Everything's adjustable - angles, clearances, etc. - so the next steps are to do some tuning to get it feeding reliably and quickly, before finally integrating it with the diverter and output bins.

  • Drum feeder (2)

    RobG05/13/2024 at 08:08 0 comments

    The drum feeder is looking good now. After a bit of trial and error making paddles/scoops from card I've committed to a 3D printed design that works well enough for a first attempt. Physically positioning all the various parts was getting really tricky using the wooden lash-up so have also started the 'finished' build in 2020 profile and M5 fittings.

    I think I'll try a belt-drive to power it, from a DC motor and reducing gearbox. Only problem with a belt is that the drum has a slight draft to the sides, meaning that the belt will undoubtedly tend to wander off...

  • Drum feeder (1)

    RobG05/08/2024 at 20:12 0 comments

    So after a long break to get some other projects finished, I'm back to the Lego sorter and its drum feeder. 

    It may look like a food container, sat on some rollers, and with a hole in the lid, but it's much more than that! Actually, not really. That's exactly what it is.

  • Adding a motor controller

    RobG02/17/2024 at 16:05 0 comments

    Using a bench supply to control the current (and therefore speed/vibration frequency) of the vibrating feeder was getting a bit annoying, so I finally took the plunge and added an H-bridge driver and PWM control. Initially I tried an L9110S-based module (very cheap on the 'bay) but it wasn't up to it and kept overheating. Plus it doesn't support 'coasting' so ended up being quite noisy and inefficient.

    I swapped it out for an L298N-based module (almost as cheap) which is much better. By driving the ENABLE line with PWM, and holding the IN1/IN2 inputs H/L for fixed direction, it's possible to employ coasting, which keeps the motor happier.

    However, the Arduino's built in PWM frequency (977Hz) is very noisy, and changing the prescaler to get other values is no better (3.9kHz is also noisy, 31kHz is too fast for the driver). So ended up with a bit of code to set it at about 15kHz, which is perfect. Pretty much silent (to my deaf ears anyway) but with smooth power control and no overheating.

    Plus, the L298N has dual outputs, so I've still got a spare channel I can use to control the drum feeder's motor, when I get to that stage.

  • Vibrating feeder first try

    RobG01/26/2024 at 12:51 0 comments

    After quite a lot of trial and error on the feeder, I've settled on a design where one end is a hinge, forcing the vibrating motion to be confined to up-down only, and with low amplitude at the hinge end, and a large amplitude at the free end. It seems to work well at separating parts as long as there aren't too many at once:

    Obvs this is a dirty quick prototype using scraps lying around, I'll do a neat version one day out of profile aluminium...

  • Colour sensing (5)

    RobG01/24/2024 at 09:04 0 comments

    Ok, definitely last log on colour sensing! I think it's good enough now.

    I've significantly sped up the colour sampling code by using the low-level read16() rather than the getRawData() library function, since the latter includes an unnecessary delay equal to the integration time. Another significant step is to read a few (e.g. 5) samples in quick succession starting as soon as the brick's presence is detected, and then picking the RGB measurement corresponding to the brightest (largest C) of the series. Colour accuracy seems best when the reflectance is as high as possible.

    Timing was still a bit tight, but I noticed that I could make the diverter stepper motor go a bit faster than previously thought - the battery I'd been using was flat! Charging it up made quite a difference. Using the slo-mo mode on my phone, and stepping through the videos frame-by-frame, I've measured the time it takes for a piece to fall through the diverter at 160-190ms. By contrast, the diverter takes - at most - 125ms to move. In fact, when it only needs to move one place (nearest neighbour) it has finished moving before the piece even enters the top of the tube! Eeeek that's fast!

    A bespoke, 3D-printed 'hood' and 'scoop' part, painted inside with BLK3.0, now cuts out most of the stray light, and helps funnel the pieces into the diverter.

    Oh, one last thing, for pieces that are classified by hue as "white, grey or black" the code now does an additional classification based on brightness to attempt to distinguish between black and white/grey.

    Video to follow....

  • Colour sensing (4)

    RobG01/17/2024 at 14:35 0 comments

    With a light sensor positioned to detect the light from the illuminating LED it can now sense when a brick arrives and leaves. If two bricks come down together (of different colours) we need to make sure the diverter isn't moving whilst one is in transit else it will jam. So we need to implement a 'hold off' period where new bricks don't trigger a change of position:

    This can be implemented using a state machine, with rising- and falling-edge interrupts driving some of the changes of state:

    This is now coded up and seems to work ok, just need to adjust the value of T (about 100ms) to get the best compromise between fast changing of output bins and no jamming. (Note that the sensor output is inverted: high level means brick present, low = no brick.)

    Also, I've added a thin piece of black card between the light source and colour sensing chip, plus BLK3.0 black paint on all the surfaces, to try and block any direct illumination which I'm sure will help:

    [Update: this is now working very nicely, with pretty much zero instances of jamming the mechanism. Even the very smallest Lego pieces (4-5mm) get correctly detected. The remaining challenge is to ensure they are fed in one-at-a-time with ~100msec or more gaps between them.]

  • Colour sensing (3)

    RobG01/11/2024 at 15:48 0 comments

    I've implemented an algorithm for colour classification that seems to work ok:

    1. detect brightness changes from below to above threshold, i.e. a piece arrives at the sensor
    2. each sample is matched to nearest colour in a library of about 30, using 'redmean' distance
    3. wait until M out of the last N samples are the same (because the detected colour can change significantly as the piece arrives and as it leaves the sensor, where it's only partly in the field of view)
    4. determine output bin and move diverter
    5. wait small fixed delay for piece to fall down diverter
    6. repeat.

    This seems to work ok for big bricks, but small pieces will be a problem because they are moving too quickly to get more than 2 or 3 samples total, so the "M out of N" consistency check will fail. This is exacerbated by using a fixed (non-vibrating) section of feeder which needs to be at a fairly steep angle to ensure pieces don't stop, but means they're moving pretty fast by the time they reach the sensor:

    • smallest piece/dimension: 8mm
    • max. speed of travel along feeder: 0.8m/s
    • min. time passing sensor: 8mm / 800mm/s = 10ms.
    • sensor rate: 5ms/sample (including processing)
    • min. number of samples: 10 / 5 = 2

    But it works well enough as a starting point:

    An alternative plan I'll try next is to position a second light sensor above the feeder, trained to detect the light from the illuminating LED. When the light dims sufficiently, we can be pretty sure there's a piece in just the right place, so should be able to exactly time a single colour measurement (taking only 5msec) rather than needing a whole string of them. [Update: yes this approach works very well! More to follow in next log.]

  • Colour sensing (2)

    RobG01/10/2024 at 09:32 0 comments

    Trying a different approach, I took a whole bunch of raw sensor readings whilst holding/moving/rotating different coloured bricks in front of the sensor, at a variety of distances from 5mm to about 20mm. Then imported the readings into Matlab so that I could scatterplot them in 3D (rgb-space) and observed that all the points relating to a certain brick formed a straight line. One end tends towards the origin (black, i.e. poor illumination) but the other end does not tend towards (1,1,1) i.e. white. This means that the shade or hue(1) of each brick does not change with distance or brightness of illumination. We humans might see a white, specular flash from a shiny face, but the sensor just sees brighter red (or whatever colour). I'm sure this effect is obvious and well-known, just not to me.

    RGB values normalised to unit magnitude (very low brightness outliers removed)

    I think it means, as I suspected, that I can classify the bricks' colours by normalising the rgb values to account for brightness of illumination, resulting simply in hue and ignoring brightness. The down-side is that black, grey and white bricks all get classified the same, and cannot be separated. Maybe that's not a problem, at least for now.

    It's also surprising how much 'desaturation' there is, e.g. the green and blue channels show significant responses when shown a 'red' brick. Perhaps it's correct, or perhaps I'm getting light from the illuminator LED scattering directly onto the sensor by accident.

    (1) Not really 'hue', since it includes all levels of saturation including grey, so really it's a mix of hue and saturation.