Milling The Board

Moving On

I decided to move on from the e-paper display for right now to focus on the servo and come back to the display later. I realized that the footprint for the SLIDE-SWITCH component in the fab library had the same SMD pads as I needed for three headers pins.

New Schematic New

When routing I realized that there were holes in the slide-switch footprint but I simply designed my routes around them and will simply not mill them when I cut out my board.

New Layout

New 3D PCB

I was going to mill this board on the Genmitsu 3020-Pro Max milling machine, so I went to the Manufacturing workspace and created a new Setup. I selected a boxpoint on the top of the stock to where the x and y axes were hugging the stock. I selected all the traces and the top face of the board to be the Model, changed the Stock Top Offset to 0mm.

I went back and made the traces larger in the layout then made sure to deselect Solder Masks after I pressed Push to 3D PCB.

I then created a 2D Contour. When I selected the tool, I went to Milling Tools (Metric) and copied the smallest Flat Endmill I could find (3mm Flat Endmill). I then copied and pasted it into my Local > Library tools and right-clicked it and selected Edit tool. I changed the Description to 0.8mm Flat Endmill, Diameter to 0.8mm in the Cutter menu, Spindle speed to 12000 rpm in the Cutting data menu, Cutting feedrate to 100 mm/min in the same menu, and Plunge feedrate to 100 mm/min in the same menu.I then pressed the blue Accept button. I selected the new tool and set the Coolant setting to Disabled. Then for the Contour Selection I pressed the Chain icon and selected one of the traces. I repeated this for the top outline of every trace I wanted milled, which took a fairly large amount of time.

Chain Selection & Chain Button

Next, under Top Height I set Offset to 0mm. I checked the Multiple Depths option (scroll down under the Passes menu) and set Maximum Roughing Stepdown to 0.4mm. I then pressed OK and activated the 2D Contour tool again. I selected the bottom outline of the board and used all the same other settings as the previous contour.

As I zoomed in I noticed that there were no blue lines around the second and third pads of the slide-switch component so I had to go back to the layout editor, decrease the DRC rules for minimum distance between a pad and a wire, then move the middle route in between the two switch holes. I also made all of the traces thicker. I then Pushed to 3D PCB again and made sure to uncheck Solder Mask. I got errors under the 2D Contour, so to recalculate I

Finally I right-clicked the previously-created Setup in the hierarchy and pressed Post Process. I made sure Post was set to Grbl / grbl and pressed Post.

The milling process was very smooth! I moved the z-axis high and zeroed it, then pressed Send to do an air cut. Everything looked OK so I moved the z-axis down until a piece of paper couldn't move in between the copper and the mill then zeroes the z-axis and moved the bit higher. I moved the x and y axes to the bottom left corner of the copper and zeroed them, as well. Then I pressed Reset and Send, and it worked! I occasionally vaccumed throughout the milling process.

Here's the result after rinsing in water!

The soldering process was very smooth.

Unfortunately I realized that the order of the wires didn't match up with the servo so connecting it directly like this wouldn't work - I'll correct this in the next iteration of the design. For now I'll connect the servo like this.

The next day when I took the board out of my bag to test I noticed the traces ripped! These were thinner than other traces I'd milled so that might be why.

I tried resoldering with a lot of solder to reach what was left of the traces, but this failed.

I then tried to desolder mistakes and failed again - I needed to make a new board.

Redesigning Again

Just to be sure everything will work OK I made the traces' width 50mil.

New New Layout

I milled the board, deburred it, washed it in soap and water, soldered it (very few connections to the pico so I could always unsolder if needed), and connected it to a servo motor. The only learning I had was that when I install a new tool I have to select the new tool button in the Bantam software then re-zero it. Also, I'd originally tried to only solder the corners and test the conections, but even though the other legs were touching, they weren't connected, so I soldered all of the legs that were connected to pin headers.

I tried plugging the board into my computer and nothing happened! I became very worried that I wasted another Pico, but tried a different chord, and it worked! I installed MicroPython using Thonny then ran the code from this website to operate a servo motor (I modified it to use GPIO 21). I copied and pasted both files into Thonny then saved them in the base directory of the Pico.

servo.py

from machine import Pin, PWM


class Servo:
    """ A simple class for controlling a 9g servo with the Raspberry Pi Pico.

    Attributes:

        minVal: An integer denoting the minimum duty value for the servo motor.

        maxVal: An integer denoting the maximum duty value for the servo motor.

    """

    def __init__(self, pin: int or Pin or PWM, minVal=2500, maxVal=7500):
        """ Creates a new Servo Object.

        args:

            pin (int or machine.Pin or machine.PWM): Either an integer denoting the number of the GPIO pin or an already constructed Pin or PWM object that is connected to the servo.

            minVal (int): Optional, denotes the minimum duty value to be used for this servo.

            maxVal (int): Optional, denotes the maximum duty value to be used for this servo.

        """

        if isinstance(pin, int):
            pin = Pin(pin, Pin.OUT)
        if isinstance(pin, Pin):
            self.__pwm = PWM(pin)
        if isinstance(pin, PWM):
            self.__pwm = pin
        self.__pwm.freq(50)
        self.minVal = minVal
        self.maxVal = maxVal

    def deinit(self):
        """ Deinitializes the underlying PWM object.

        """
        self.__pwm.deinit()

    def goto(self, value: int):
        """ Moves the servo to the specified position.

        args:

            value (int): The position to move to, represented by a value from 0 to 1024 (inclusive).

        """
        if value < 0:
            value = 0
        if value > 1024:
            value = 1024
        delta = self.maxVal-self.minVal
        target = int(self.minVal + ((value / 1024) * delta))
        self.__pwm.duty_u16(target)

    def middle(self):
        """ Moves the servo to the middle.
        """
        self.goto(512)

    def free(self):
        """ Allows the servo to be moved freely.
        """
        self.__pwm.duty_u16(0)

main.py

import utime
from servo import Servo

s1 = Servo(21)       # Servo pin is connected to GP21

def servo_Map(x, in_min, in_max, out_min, out_max):
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

def servo_Angle(angle):
    if angle < 0:
        angle = 0
    if angle > 180:
        angle = 180
    s1.goto(round(servo_Map(angle,0,180,0,1024))) # Convert range value to angle value

if __name__ == '__main__':
    while True:
        print("Turn left ...")
        for i in range(0,180,10):
            servo_Angle(i)
            utime.sleep(0.05)
        print("Turn right ...")
        for i in range(180,0,-10):
            servo_Angle(i)
            utime.sleep(0.05)

It worked! However, the servo movement was very jittery. To make sure this was a software problem and not a hardware problem, I modified main.py, and this reduced the jitteriness!

import utime
from servo import Servo

s1 = Servo(21)       # Servo pin is connected to GP21

def servo_Map(x, in_min, in_max, out_min, out_max):
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

def servo_Angle(angle):
    if angle < 0:
        angle = 0
    if angle > 180:
        angle = 180
    s1.goto(round(servo_Map(angle,0,180,0,1024))) # Convert range value to angle value

if __name__ == '__main__':
    while True:
        print("Turn left ...")
        for i in range(0,180,1):
            servo_Angle(i)
            utime.sleep(0.001)
        print("Turn right ...")
        for i in range(180,0,-10):
            servo_Angle(i)
            utime.sleep(0.001)

I tried making it even more smooth, but the servo wouldn't turn 180 deg, which I suspect is because 0.001sec is too short of a time for the servo to turn.

I modified the code to the following to test a functionality more similar to what I'll actually use.

import utime
from servo import Servo

s1 = Servo(21)       # Servo pin is connected to GP21

def servo_Map(x, in_min, in_max, out_min, out_max):
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

def servo_Angle(angle):
    if angle < 0:
        angle = 0
    if angle > 180:
        angle = 180
    s1.goto(round(servo_Map(angle,0,180,0,1024))) # Convert range value to angle value

if __name__ == '__main__':
    while True:
        try:
            servo_Angle(float(input(">> Angle? ")))
        except:
            print("Error: NaN")

This was a critical mistake! The program worked very well, and it moved up until 180 deg and wouldn't go below 0 deg, but I couldn't exit the program! Even when I tried to soft reboot in Thonny my program simply rejected the message since it wasn't a float. I tried re-entering bootloader mode and reinstalling MicroPython but the program simply started up again. Next I had an idea that if I installed a different version of MicroPython that wasn't compatible with the board it wouldn't know how to run my program, so I installed the Pico WH version of MicroPython and the program stopped! I then reinstalled the correct one and the problem was solved!

Redesigning The Driver-Side Board

I want to redesign my board from Week 8 to where I can use one of the pins with a built in pulldown resistor, D4. I'll come back to this if I have time this week and if not in the future.