Overview
With CircuitPython, you can read the information from a Nunchuck controller, control servos, and turn pins on and off, so why not combine those and control a laser. Sure, you could always get a regular old laser pointer and just use your hand to move it, but that lacks the fun factor.
This project uses the ESP32-S2 Feather and one of the reasons for choosing it was due to the built-in STEMMA QT port, but another great reason is because of the WiFi support. This means you could expand the project with another ESP32-S2 Feather and control it over WiFi. Try doing that with a laser pointer!
Page last edited March 08, 2024
Text editor powered by tinymce.
3D Printing
CAD Parts List
STL files for 3D printing are oriented to print "as-is" on FDM style machines. The laser holder is designed to 3D print without any support material, but supports are recommended on the project base. Original design source may be downloaded using the links below:
- Project Base
- Laser Holder
Build Volume
The parts require a 3D printer with a minimum build volume.
- 75mm (X) x 95mm (Y) x 30mm (Z)
Slicing the Base
For best results, supports are suggested with printing the base because of the overhangs.
Page last edited March 08, 2024
Text editor powered by tinymce.
Circuit Diagram
This circuit takes advantage of the PWM FeatherWing to not only move the servos, but to also dim the laser. In order to connect the laser to the PWM FeatherWing easily, you will need to solder a 3-pin servo connector to the laser module.
The easiest way to do that is to get a Servo Extension cable, cut the cable in half, solder the end that plugs into the PWM FeatherWing onto the laser, and insulate the solder joints with some heat shrink tubing or tape.
After that, everything can be connected by plugging it in or using screw terminals.
For the PWM FeatherWing, use the following connections:
- Plug the servo that controls the horizontal motion PWM channel 0
- Plug the servo that controls the vertical motion PWM channel 1
- Plug the laser into PWM channel 2
The Nunchuck Adapter should be connected directly to the Feather ESP32-S2's STEMMA QT port.
A 5V Power adapter should be connected to the 2.1mm terminal adapter and is used to power the servos and the laser.
Page last edited March 08, 2024
Text editor powered by tinymce.
CircuitPython
CircuitPython is a derivative of MicroPython designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the CIRCUITPY drive to iterate.
CircuitPython Quickstart
Follow this step-by-step to quickly get CircuitPython running on your board.
Click the link above to download the latest CircuitPython UF2 file.
Save it wherever is convenient for you.
Plug your board into your computer, using a known-good data-sync cable, directly, or via an adapter if needed.
Click the reset button once (highlighted in red above), and then click it again when you see the RGB status LED(s) (highlighted in green above) turn purple (approximately half a second later). Sometimes it helps to think of it as a "slow double-click" of the reset button.
If you do not see the LED turning purple, you will need to reinstall the UF2 bootloader. See the Factory Reset page in this guide for details.
On some very old versions of the UF2 bootloader, the status LED turns red instead of purple.
Once successful, you will see the RGB status LED(s) turn green (highlighted in green above), and a disk drive ending in "...BOOT" should appear on your host computer. If you see red, try another port, or if you're using an adapter or hub, try without the hub, or different adapter or hub.
If double-clicking doesn't work the first time, try again. Sometimes it can take a few tries to get the rhythm right!
A lot of people end up using charge-only USB cables and it is very frustrating! Make sure you have a USB cable you know is good for data sync.
You will see a new disk drive appear called FTHRS2BOOT.
Drag the adafruit_circuitpython_etc.uf2 file to FTHRS2BOOT.
Copy or drag the UF2 file you downloaded to the BOOT drive.
Page last edited March 08, 2024
Text editor powered by tinymce.
Coding the Nunchuck Laser
Once you have CircuitPython installed on your device, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download as a zipped folder.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
import time
import board
import digitalio
import simpleio
import adafruit_nunchuk
import adafruit_pca9685
import adafruit_motor.servo
PITCH_OFFSET = 45 # The offset for the pitch
PITCH_RANGE = 90 # The range the servo can rotate up and down in degrees
YAW_RANGE = 90 # The range the servo can rotate side to side in degrees
INVERT_PITCH = False
# STEMMA QT 3V needs to be activated
i2c_power = digitalio.DigitalInOut(board.I2C_POWER)
i2c_power.switch_to_output(value=False)
i2c = board.I2C() # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller
wing = adafruit_pca9685.PCA9685(i2c)
wing.frequency = 50
servo_yaw = adafruit_motor.servo.Servo(wing.channels[0])
servo_pitch = adafruit_motor.servo.Servo(wing.channels[1])
laser = wing.channels[2]
nc = adafruit_nunchuk.Nunchuk(i2c)
# Pre-calculate the angles
min_yaw_angle = YAW_RANGE / 2
max_yaw_angle = 180 - (YAW_RANGE / 2)
min_pitch_angle = PITCH_OFFSET + (PITCH_RANGE / 2)
max_pitch_angle = PITCH_OFFSET + 180 - (PITCH_RANGE / 2)
pitch_inputs = [0, 255]
if INVERT_PITCH: # Swap the Min and Max Values
pitch_inputs[0], pitch_inputs[1] = pitch_inputs[1], pitch_inputs[0]
brightness = 0xFFFF # Initial brightness value
while True:
x, y = nc.joystick
servo_yaw.angle = simpleio.map_range(255 - x, 0, 255, min_yaw_angle, max_yaw_angle)
servo_pitch.angle = simpleio.map_range(
y, pitch_inputs[0], pitch_inputs[1], min_pitch_angle, max_pitch_angle
)
ax = nc.acceleration[0]
if nc.buttons.Z: # Z-Button sets laser PWM to current brightness
laser.duty_cycle = brightness
elif nc.buttons.C: # C-Button sets laser brightness to value of the nunchuck roll position
brightness = int(simpleio.map_range(ax, 250, 750, 0, 0xFFFF))
laser.duty_cycle = brightness
else: # No button pressed sets laser to off
laser.duty_cycle = 0
time.sleep(0.01)
Upload the Code and Libraries to the ESP32-S2 Feather
After downloading the Project Bundle, plug your ESP32-S2 Feather into the computer USB port. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the ESP32-S2 Feather's CIRCUITPY drive.
- lib folder
- code.py
Your ESP32-S2 Feather CIRCUITPY drive should look like this after copying the lib folder and code.py file.
Settings
There's a few variables you can adjust in code.py which will be covered in this section.
PITCH_OFFSET is the offset of the pitch range from the horizontal axis. Increasing this will tilt the servo more vertical and decreasing will make it more horizontal.
PITCH_RANGE is the full range of motion that the vertically tilting servo will move. If you want to increase the range of motion, you can increase this value and if you want to decrease it to make the laser easier to control, you can decrease it.
YAW_RANGE is the full range of motion that the horizontally panning servo will move. This should be close to the PITCH_RANGE setting so the pointer moves in a circle instead of an ellipse.
INVERT_PITCH will invert the direction that vertically moving the stick on the nunchuck causes the laser to tilt. This is useful if you mount the laser so it is pointing down.
Usage
The usage is pretty straightforward, but this section will go over it so you can understand everything it can do.
Moving the joystick on the nunchuck causes the laser to move where it is pointing.
To cause the laser to show, just hold the Z-Button on the nunchuck and let go to turn it off. It is off by default for safety reasons. When the laser appears, it will be at the last brightness setting.
To adjust the brightness, hold the c-button down and twist your wrist. The laser will show while doing this so you can see how bright it is. Currently the brightness setting isn't saved, so resetting the feather will put it back at full brightness.
Ideas for Extending the Project
This project has a lot of possibilities, but here are a few ideas to take it to the next level.
You could build a second one and then have the two communicate over WiFi so it could remotely be controlled.
You could hook a PowerBoost 1000C up so you could make the project battery powered.
You could edit the code to store the last brightness value by using the nvm module.
It might be a bit too slow, but perhaps you could try and use the pan and tilt mechanism as a XY driver to draw patterns with the laser.
Store a series of movements and then have it play those back in a loop so your pet can play for hours unattended.
Page last edited March 08, 2024
Text editor powered by tinymce.
Assembly
You will need 4 x M2.5 6mm long M-F Hex Standoffs, 4 x M2.5 10mm long M-F Hex Standoffs, and 8 x M2.5 Hex Nuts.
Place the 10mm long standoffs in the holes of the smaller rectangle and the 6mm long standoffs in the larger rectangle. Use the nuts on the underside to secure them in place.
Next you will need 8 x 4mm long M2.5 screws, the wii nunchuck adapter, and an assembled FeatherWing Doubler.
Secure the doubler in place in such a way that the USB port of the feather is towards the outside edge of the base.
For the Nunchuck adapter, the connector should face away from the doubler and can otherwise be secured with the STEMMA QT ports facing either up or down.
Place the Feather and PWM FeatherWing into the doubler with the Feather in between the PWM Wing and the Nunchuck Adapter.
Slide the Pan and Tilt Assembly into the slot. It can fit in either way, but you will need to update the firmware to invert the pitch if you have it pointing downwards.
Plug the panning servo into PWM channel 0 and the tilting servo into PWM channel 1.
Next take the laser module with the connector soldered on and the laser holder. If the laser is a bit tight, you can apply some pressure to open the gap a bit.
Insert the laser holder and laser into the top of the pan and tilt assembly and the two clips should hold it in place.
Plug the laser into channel 2 on the PWM FeatherWing.
Use a screwdriver to connect the 2.1mm barrel connector adapter to the PWM FeatherWing. Make sure the polarity of the wires is correct!
Connect the STEMMA QT cable between the Feather and the Nunchuck adapter.
Connect the Nunchuck to the adapter board with the notch facing the direction indicated on your board.
Page last edited March 08, 2024
Text editor powered by tinymce.