Archive for Infin1D

Infin1D

This is a follow up from Infin1D, Rev 0.5, where I threw together a proof of concept in a few hours. This is the one where I spent some actual time on it and built a base that, while still quite rough, can be incrementally improved to arrive at a final product.

This miiight have been the original inspiration I saw, but the video link is unfortunately dead.

Right off the bat, I should mention that PCBWay kindly sponsored the 4 layer PCB for this. In addition to using them for most of my personal stuff, I get more complicated professional boards assembled by them as well. The quality, speed, price, and communication are all better than what I’ve gotten domestically. So I’m genuinely happy to plug them, they rock.

 

 

On to it:

I mentioned previously that I’d like to use a scanner sensor instead of the easy line sensor module I had before. That previous module was 128 pixels long, greyscale, and $20, but also well documented, ubiquitous, and easy to use (mechanically and programmatically).

A linear CCD sensor out of a scanner, on the other hand, is almost the complete opposite. It’s huge (107,000 pixels long), poorly documented, electrically hard to control, full RGB, requires external optics, and needs to be mounted to a circuit board. It is also only really available via Taobao, but it is about $7 in singles. Or at least, the one I chose is.

I started by scavenging a bunch of scanners and seeing what was inside. Most of them happened to be the Epson Perfection 1250. I guess it was just an insanely popular scanner.

Searching “Epson Perfection 1250 Service Manual” yields excellent results, so this particular RGB linear CCD is a 22-pin package called ILX555K.

The main processor chip on the PCB is the National (now TI) LM9833, which is a little ridiculous. It contains an analog CCD reader, DRAM storage, high current stepper motor outputs, a USB interface, and even extra helper functions like paper load detect. Basically a single-chip scanner brain.

Initially, I didn’t even have to do any proper hardware hacking (sad day), because there are Linux drivers to talk directly to the chip. It uses something called SANE, an easy Linux scanner interface. SANE is actually a really nice codebase to hack on. Well laid out, clear, and simple.

There are also convenient Python bindings!

First:
sudo apt-get install python-dev libsane-dev sane-utils
git clone https://github.com/python-pillow/Sane
cd Sane python setup.py build
sudo python setup.py install
sudo pip install pillow
sudo pip install numpy
sudo mount --bind /dev/bus /proc/bus
sudo ln -s /sys/kernel/debug/usb/devices /proc/bus/usb/devices
sudo sane-find-scanner
> ...
> (vendor=0x04b8 [EPSON], product=0x010f [EPSON Scanner 010F]) at libusb:001:002
> ...
sudo nano /etc/sane.d/plustek.conf

That file gets modified with the found USB vendor/product/etc info.

And you’re done!

Running scanimage will run the scanner, including homing and making the carriage move, but it doesn’t provide the granularity we need. The source for that provides detail around line 1862, probably calling feed() or reset() / initialise cmd. Sending the initialise byte for a long scanner homing sequence is still pretty high level, so it must be handled within the IC.

That was a fun detour, but ultimately not what I wanted out of the system.

So I threw together a really quick PCB, and I made many mistakes. But that’s okay, that’s what revision 1 is for.

And it works! My initial firmware can display images and I also wrote a bitmap generator to save to the SD card.

A rudimentary interface:

Obviously lots of bodges had to be made. Mostly because of the many voltage rails – the sensor has 5V signaling, while the CCD itself is charged with 12V, the microcontroller is 3.3V, and there’s the whole 5V / battery voltage mess. So this board is more bodge wires and hot glue than PCB at this point.

So how well does it work?

Well, here’s another difference between the original module I used and this sensor: The sensor doesn’t have an integrated lens.

Due to ubiquity, I picked up an M42 camera lens mount for a couple bucks and found a $20 lens on Craigslist. The M42 lens is an old 35mm standard, which is coincidentally just the size of my sensor. Used to be very popular too, so good deals can be had.

However, I have not yet designed a chassis, so anything the image captures will be a blurry mess.

One more issue is that I’m still tweaking the hardware around the analog output. The sensor datasheet recommends feeding its output through the base of a BJT transistor as a sort of transimpedance amplifier. It’s kind of a strange way of doing that, so I’m playing around with proper op amp methods to do that consistently and repeatably. That requires a fair amount more tweaking though, as the datasheet has no information on the nature of the output that is expected. That’s just a matter of putting more time into the investigation, but in the meantime, I have poor dynamic range.

So here’s the first test image that came out of it:

 

The scan is the red channel only, from left to right. Starting with something dark covering the sensor, and at a very obvious point in time, I removed it and put an object centre of the sensor. I would consider that a success, albeit not as pretty as I’d hoped.

Here’s the object:

In addition to the many above changes, some software updates I’ll write down the line are to integrate better the two obvious viewing modes: waterfall, and histogram. The histogram mode is useful for getting focus right, and then switching over to waterfall mode (as shown above) to see images.

Histograms, similar to the feature that is often available in DSLRs, could show the sensor input intensity as a vertical line on a graph, with pixel position on the horizontal. The steeper the histogram, the sharper the focus.

Infin1D, Rev 0.5

Before YouTube existed, I saw a video online. There was no spoken dialog, just subtitles in Japanese, with upbeat music in the background. It shows pictures of point-to-point soldering of a document scanner’s sensor and some sort of microcontroller. Then the single line sensor is put into a box (with a lense) and taken for an adventure.

I’d love to find this video again, but the main takeaways were that by reducing your camera to one dimension, you can fake the second dimension to create infinitely long images.

The creator of that original video set it up beside some train tracks, and got a long image of an entire train as it drove past the camera. Similarly, you could put it beside a road and get images of cars, or in the playa at Burning Man and capture the eccentric costumes as Burners ride past on bikes.

 

I wanted to build a quick test. Lurking in my parts bins, I have a single-line camera module, and a massive pile of old LCDs. For this, I selected an Arduino shield labelled MCUFRIEND 3.6″.

Searching around reveals that this model doesn’t actually seem to exist, but okay! The standard method of most Arduino LCD shield driving is to find example libraries that look like they have a reasonable chance of working, and then try them all until something does. I had to borrow an Arduino, because I’m not a huge fan, so I don’t even own one. How embarrassing.

In this case, the official-looking repository by prenticedavid is here, and GLUE_Demo_400x240 seemed to do a good job of driving this one. The code initialises it as 0x9327, which is the ILI9327 LCD driver. The datasheet for the ILI9327 is very good, so I may keep the LCD and write my own drivers for whatever non-Arduino architecture I eventually go with.

I did attempt to follow the maze of #defines in the Arduino library code, but I don’t recommend anyone do that if they value their sanity. I also put a logic analyser on it to grab just the output; this resulted similarly convoluted and unhelpful results.

 

 

While I’ll eventually be using a sensor designed for document scanners (lots more on that, stay tuned), the TSL1401 is a bespoke solution good for this test.

 

All-in-one sensor, lens, and brains that take logic level timing, and spits out analog values. 127 pixels tall, greyscale, and tiny, it’s objectively kind of bad, but fits the bill for now. I got it up and running in an hour or two.

 

Cool! That means I have a reference implementation. I’m not running this on an Arduino in the final version, but it got the job done in a quick-and-dirty way.

The whole thing was modeled up in SolidWorks, along with dimensionally accurate stand-ins for the electronics.

 

There are two 3D printer parts, adapted from the models of earlier jigs I’ve done, in keeping with the ethos of this test: quick and dirty.

I typically design around M3 screws, and used brass heat-set inserts to turn 3D printed cavities into threaded holes. As much as I dislike 3D printing, it has its uses.

 

Both halves of the 3D printed enclosure failed while doing some of the top few layers, but the baseplates are there so nothing that can’t be fixed with some standoffs and hot glue.

 

The results from this test project, predictably, are pretty bad.

This is a handheld scan across my keyboard.

 

As a stepping off point, it’s served its purpose. Here is an incomplete list of changes that future prototypes will feature:

  • A better microcontroller. Probably an STM32F1 or STM32 F4 series. I like the flexible memory controller, which can be used to map virtual memory regions to LCD driver chips.
  • A better sensor. The current one is only 128 pixels tall, greyscale, poor quality, and relatively expensive for what you get.
  • UX – rotary encoders, buttons, LCD widgets:
    • Start/stop capture
    • Speed up/slow down scan/capture rate
    • Integration time adjustment
    • Post capture stretch/compress
    • Histogram
  • Saving to SD card
  • Battery power

Changing the sensor might not actually make it to the next rev, it’s a big project on its own. Sourcing a sensor through Taobao probably, figuring out how it works, driving it, building a board to work with it, and all the mechanical work of lens selection, mounting, and measuring.

Either way, I’m happy to leave this for now, and return to it when I have cleared out some of my project backlog.