Electronic project using a laser beam to measure line following robot speeds


Laser Beam Timer was a really fun project. Shortly after finishing Crabby construction, I needed a way to measure the results of line following algorithm changes. Sitting there with a stopwatch and “paying attention” is for the birds. Instead, I designed and built a custom laser beam timing system.

The major pieces of this project are a laser and CdS photoresistor in a block of wood, a small mirror to reflect the laser back into the CdS, an Adafruit Trinket Arduino compatible controller, and an LCD. Due to low number of i/o pins on the controller, a basic analog comparator is used to monitor the battery level, and a face plate / pseudo enclosure was crafted from leftover plywood that was used for Crabby’s body.

Follow along my journey through two prototypes and a final production model that is in service as we speak, timing my robot around my floor tape course…

prototype arduino and breadboard

Prototype A

When first starting a project, I’m often frustrated by how feeble all the parts are. Sure, in the final production model, everything will be nice and squared away, but those first few components are just stuck together by pressure fit wires in a breadboard. Sneeze while holding it and it comes apart.

My LCD and Arduino kept separating and intermittently failing during early development, so I looked around the room and grabbed the first thing that came to mind: cardboard and zip ties! Worked amazing as a makeshift prototype board.

closeup of LCD display

At this stage of the project, I was using a 16x2 LCD with a many pin Hitachi interface. I was able to cram 3 different times, a lap count, a laser illumination ADC value, and a mode indicator into those 32 characters.

This version of prototype uses the classic Arduino UNO development board. Very handy for getting things up and running quickly, prove the basic concepts, and plan for bigger and better things to come.

The hardest thing to make work was soldering a wire to the casing of the laser pointer. The whole metal case serves as the positive connector, and it is a giant heat sink for my little 40w soldering iron.

Laser and Mirror Assembly

laser and mirror as seen from above
detail view of emitter/receiver block
small dental mirror reflecting laser

The switching part of the timing system is a very basic one. A source of illumination (laser pointer) normally shines on a CdS photoresistor. The photocell is arranged as a voltage divider in series with a fixed resistor, and the controller reads the brightness level. When something blocks the laser, such as a passing line following robot, the photoresistor goes dark and the controller can sense the change.

My very first iteration had the CdS wired and positioned right next to the controller. Long wires were then fed under the line following tiles (or under the tape on the carpet) to power the laser sitting in the middle of the robot course, aimed directly at the photocell. Kludgey, at best.

Rummage through the junk pile and find a little dental mirror on a telescoping stick. Rip that off the stick and mount it on a scrap piece of wood using some 14-gague copper wire. Reposition the CdS and Laser into the same block and aimed parallel to one another.

Now you can see the arrangement of the laser and photocell sitting right next to eachother snug in their 2x4 housing, and the reflector sits in the middle of the robot course, no awkward wires to deal with. The way the mirror is mounted, it can be positioned for fine tuning the aim and ensuring the CdS is fully illuminated when no obstruction is present. In the middle picture, you can see the laser emitter in the large/central hole, and the well-illuminated hidey hole for the sensor, bright red because the mirror is reflecting directly into the hole.

The deep hole and recessed mounting position does an excellent job of shielding it from ambient light. In the normal lighting conditions in a few rooms in my house I routinely get ADC readings below 20. When the laser hits the eye directly, values of 800 and above are normal. Given that, I built a threshold of 500 into the software.

Prototype B

cleaner prototype sitting on desk

With the concept successfully proven, it was time to move on to plan Prototype B. The first round was on the Arduino UNO “proper”. This next iteration of development needed to verify the following pieces that were destined for the production model:

  • Adafruit Trinket 5v controller - Fewer i/o lines and some other limitations when compared to the UNO (on the plus side, way smaller and less costly).

  • I2C 20x4 LCD - The A model used the Hitachi interface which requires too many pins, so this guy will use I2C and only 2 pins. Plus more character rows and columns.

  • Battery Power - Production is going to run off of a LiPo battery, so time to test it out in Proto B.

  • Battery Monitor - All out of i/o pins on the microcontroller, but I still want to protect my battery from death by low voltage. Enter a spare LM393 analog comparator, left over from a 10 year old Sandwich.


Getting the LiquidCrystal_I2C and TinyWire libraries to compile was a “treat”, but a little elbow grease and a handful of #ifdef directives and she compiled. And came in at 110% of available program memory! The Arduino UNO has 32K flash, but my little Trinket has only 8K. Inspecting the program, I was frivolous with my use of sprintf to zero-pad minutes, seconds, and hundredths of seconds. Replaced it with an ugly but compact series of if statements to manually pad out the values. Removing sprintf() bought me ~3K just by itself, and I now have memory to spare, in case I think of some new features.

On to the Production Model

silkscreen of component side of PCB

With all of the production components tested during Prototype B, it was time to get serious.

I designed the PCB using Robot Room Copper Connection (sadly does not exist anymore). With some experience using CC for Crabby and my UV exposure unit Bronzer, this was golden. A relatively simple circuit, however some notable things about this board:

  • Mounting Holes - The production model will have the LCD mounted directly above the PCB using standoffs. The LCD has pre-existing holes manufactured into it, so I took some care to line up mounting holes on the PCB to match.

  • Reset Button - The Adafruit Trinket requires a manual reset to enter programming mode. She has a built-in reset button, however in my final configuration it would be difficult to press with my oversized fingers. Instead, I added my own reset button and soldered it to the bottom side, where it would be more easy to reach once installed in the assembled unit. The way the little tactile spider buttons are, very easy to do a layout with it on the top layer, but then swap it during soldering time.

pcb, battery, and LCD with no enclosure
  • Reserved Space - To keep things compact in the final unit, I needed to allow for the I2C breakout board that is on the bottom of the LCD unit. The big rectangle area in the upper left ensured I did not put any bulky components where they would obstruct and thereby require larger standoffs and a taller final assembly.

  • Lots o’ Connectors - Such a small project, and yet 7 connectors were used. I wanted the final face plate to be removable for whatever reason (inspection, repairs, showing off to spectators, etc), so all the peripherals like LEDs, buttons and switches all use headers/connectors. Overkill, but I’m happy with how it worked out.

  • Large Traces and Pads - Breaking from my tradition of trying to make traces and pads as small as possible, I went big this time. Manually enlarged all pads and traces, used a large clearance for the copper pour. This allowed the etching and drilling process to be very relaxed. Soldering onto large pads was splendid.


masked and cut front panel before adding components

The PCB is designed, printed on transparency, UV exposed, developed, etched, cleaned, silkscreened, drilled, populated, soldered, and tested. Life is good, if only I could hold all these peripheral components together. Rather than a traditional enclosure, I went with a faceplate, some standoffs and a baseplate.

The faceplate was one of the more technically challenging parts (for me). I used some leftover plywood from Crabby’s body.

  • Coated it in masking tape so I could write all over it without fear of marring the final product.

  • Started with the LCD rectangle. A t-square and ruler got me the basic shape. A drill and a coping saw removed the rough interior. A file and a dremel finished things off.

masked panel test fitting the LCD
  • Totally messed up the measurement for the push button and drilled a giant hole for it. Oops. Quick thinking, the power and laser switches can make use of a hole that large, so I rearranged things and was back in business. Saved me from nibbling a rectangle for the switches, which I was not looking forward to.

Side view shows some beautiful (IMO) use of heat shrink. I only melted one fingernail while heating those. One day I’ll learn to use a tool to hold the target of focused heat.

In the bottom picture, you can see the main UI components:

  • Laser Lock Indicator - Green LED lights up green when ADC reads >500, meaning laser is hitting the CdS.

  • Low Battery Indicator - Red LED lights up red when battery drops below 6.7v. My LiPo battery has high capacity, so it’ll be a while before I can test this with real values. And by “test” I mean “encounter for the first time in the production model”. I did test it with some dummy resistor values that measure close to full charge, but didn’t have a battery discharged enough to test the 6.7v cutoff. When I flip the power switch off, the comparator chip enables the LED for a brief moment (likely due to switch causing perceived battery voltage to instantly hit zero, while the 5v reference on the Trinket has some capacitors so it lags in its drop to zero) so I know it is wired correctly.

side view of the open edges of the enclosure
  • Power Switch - A DPST switch (well, technically DPDT, but I’m only using one of the “throws”) between the battery and the rest. Allows me to completely disconnect the battery for charging without physically removing it from the enclosure.

  • Laser Switch - SPST switch, not really necessary, but she’s a power switch for the laser. I figured that would be good Range Safety Officer feature to include, allowing the laser to be enabled only when safely aimed away from human and k9 eyes.

  • Mode Button - Momentary pushbutton (debounced in software) to arm the system after manual laser alignment is complete, and to reset the timers in between trials or robots or when one of the dogs steps in the beam and invalidates the current test :-) not that that ever happens.

On the LCD you can see:

front view of the user interface panel
  • AVG - Average time for the recorded laps.
  • LAP - Time for the most recent completed lap.
  • RUN - Running time for current lap. You can see some blurriness in the hundredths, its updating on the fly.
  • LAPS - count of how many laps since reset.
  • LASER - the ADC reading on the photocell voltage divider. Anything over 500 is considered “unobstructed”, and less than 500 means a robot is passing by.
  • X - The lower right is a mode indicator. In the pic it reads “X” for executing. Other values are “I” for Idle or “A” for Armed.

There’s an empty void in the upper right of the LCD, I really need to put a funny or a smiley (or are the kids calling those emojies now?) or something there. Maybe I can fit “San Dimas High School Football Rules!”?