Assignment 12 - Mechanical/Machine Design

Machine Building Week - FabLab Kamp-Lintfort

The group page for the machine is this page here, as I worked alone on it!

Disclaimer

When this week began, we were two people, at the end I sadly was alone, so the text might speak of a group in the beginning.

The idea for the machine is to recreate a simple two axis (If the time allows it even three axis) machine that can take gcode and draw on a piece of paper as a proof of concept. Since we are only two people on site at Kamp-Lintfort, the work was divided like follows:

  • Electronics and if the time allows, a Z-Axis
  • General strcuture and X/Y-axis

My part was the electronics part where I had the idea of creating my own CNC shield witht the microcontroller directly on board as to only have a single PCB that would control the machine. Sadly I had many things happen privately during this assignment, I could not really finish my task and so the machine is more or less not present at this time. I will try my best to catch up this week, though.

Electronics

I started my project of the CNC shield by taking a look at the ones that were commercially available. On these Breakout Boards one can find four "slots" where the stepper motor driver blocks would fit in, as well as a handfull of pinouts, reaching from the enabling of the driver blocks to limit switches and even pins for controlling a coolant system. What all of these boards had in common however was the fact that they were seated ontop of an Arduino Uno, taking advantage of almost every pinout the Arduino has to offer. With this setup and a software called "GRBL" (can be found here) up to four stepper motors and six limit switches can be adressed and controlled through gcode when told so through a serial connection. Here the biggest problem I would have to face could have been easily preventable. I was under the assumption that I could just pcik every pin I want (as long as it supported what it needed to support for its functioning), so that I could freely design my own Board. As it turns out, this is sadly not the case. While you can change the pins you want to use, there are some rules that need to be followed. First and foremost the rule, that the pins for the steps of the driver blocks and their direction pins all need to be on one port respectively. Having two step pins on one, and the thrid pin on another port is not supported by GRBL. I have not seen this restriction at this time and so designed my Board with a lot more freedom for pin placerment in mind. I started the design process by adding the microcontroller that I was going to use for this project: The ATMega328p. I did not have a huge choice here, as GRBL is primarily setup for the Arduino Uno and so for the ATMega328p. After reading the most important bits and pieces from the Microcontrollers Datasheet and taking a look at the SatshaKit by Daniele Ingrassia, I felt ready to now come up with my own design. There were some things I had to have in mind, that were different to my Boards up until this point. For one, I needed to have a 12V input source as the motors were relying on this voltage. After taking a look at the parts we had on hand at the lab, I noticed that we had small screw terminals, so I used one of them in KiCAD as the port for the incoming Voltage. In order to not fry the microcontroller in the process, I also added a linear voltage regulator (L7805) that steps the voltage down to 5V from 12V-36V. With this regulator I could now create tow seperate voltage lines on the microcontroller. 5V for the microcontroller and 12V for the stepper drivers powering the stepper motors. I added the needed capacitors for the power delivery and moved onto the stepper driver blocks. My plan was to create a two by eight row of female pin headers for each driver block as I have seen them on the commercial boards and thought it was neat that you could just change out a driver block if it fails or for any other reasons. Since I could not find a ready to use footprint for the driver blocks, I measured the distance between the legs on one of the driver blocks in the lab and approximated the distance between the two eight pin rows, which came out to be around 12.7mm. Since we had no plan to use a second helping motor for any of the axis, I created three of these female pin headers with the stepper drivers we wanted to use in mind (SilentStepStick TMC2100). It was at this time, that I noticed that it would not be a trivial task to route all of this later on. Before thinking too much about this however, I added the last few parts, that I needed. I added a power indication LED, a 16Mhz crystal of which I also did not find a footprint and just created my own from one of the available ones, as well as a reset button. I also added six pairs of one by two pin headers for the limit switches (X+/- | Y+/- | Z+/-). On top of that I added a one by four pinheader to programm the microcontroller using the reset, the MISO/MOSI as well as the SCK pins from the MCU. Last but not least, I added a one by three pinheader with RX/TX and Reset, to later on use my own FTDI Cat to use serial communication. In the end, this was my final schematic:

Schematic of the Stepper driver board

As it turned out, I was right earlier on, when I already thought, that the routing of all the tracks would be very hard. I tried my best to route everything the way I wanted, but in the end I was unsuccessfull. I first thought about using a multitude of zero Ohm resistors to bridge between all the tracks I needed, but this seemed like a stupid idea. It would take really long to solder all these resistors and on top of that the resulting board would look very crowded and just not as nice as it could be looking. My second thought directly fell onto using vias and creating a second side of the Board where everything that I could not route over the top layer, could be routed through the bottom layer of the copper. After asking my instructor about this, he said to me that this would be not so easy, but certainly doable. So I went ahead and created vias where they were needed. With this approach I was able to route evrything to my liking. After going over the board with Ahmed, it was pointed out to me that the vias were far too small and the trace for the 12V system would also need to be bigger as to reduce overheating. After I made changed to the board accordingly, this was my final layout:

Design of the Stepper driver board in KICAD

In contrast to all my other boards up unitl now, I now needed to export the front and the back copper layer as SVGs. After going through the process of creating PNGs out of the SVGs and changing spacing and colours to use in Mods, I was ready to create the toolpaths. Instead of drilling by hand I also created a drill PNG, as the number of drill holes was just far to great and the precision for the vias was needed in Order to fit in the rivets later on. To see how the machine would perform with the 0.4mm milling bit, I set the double sided copper plate down with adhesive tape, set the home position for X and Y, set the home position for Z and started milling the backside copper traces, as they would be faster to mill, so every mistake on the other side would be less time wasted than the other way around. The milling went really good and so did the drilling of the holes. What did not go really good was the Cutout however. Everything was set up correctly and we used the same zeroing method for the 1mm cutout bit, we did before: Using the zeroing probe which is sat ontop of the sacrificial layer and moving the zero point up manually by 1.85mm to accomodate for the copper plate. I started the Cutout and with just oine side of the cutout done, the power was cut from the building. As it later turned out, the power was cut for all of Kamp-Lintfort. I knew from speaking with Ahmed that this could potentially mean that the machine has completly lost its knwoledge of its zero point. The power cut was ongoing for about one hour, in which I just sat there, thinking about possible solutions if a problem would come up. After the power returned, I started the CNC back up and it moved to the point where it thought zero would be. While the X-Axis looked correct, the Y axis was off quite a bit. Since the copperplate had space on the upper part, Ahemd suggested, we just let the CNC run the Cutout job again and use see how much more the Cutout is moving in the Y direction. As the previous operation stopped while cutting out the upper most edge, we would then be able to measure the difference between both cuts and adjust the Y positioning manually. With this plan, I started the cutout job again. I immediatly noticed, that the X-Axis was also off by a few hundreds of a mm. Since there was enough copper to test around with the values a little bit, I changed the X values manually until the milling bit went through the previous cut with as little cut away as possible. After I managed to do this, we measured the Y offset and changed the zero position manually here as well. As with the X axis, this was not perfect the first few times around, but got better and better until the point where Ahmed said, that this little of an offset would not be so bad. I finally could finish the cutout operation and sadly had to go almost immediatly afterwards, as I had to evacuate my flat at home due to a newly found WW2-Bomb nearby. This meant I had to finish the other side of the board the next day. The plan for milling the other side was to very carefully lift the cut board out of the rest of the copperplate to leaver the rest of the stock in place. This worked really good. Afterwards, I cleaned the Board. Since we used the 1mm milling bit to cut out the Board, the plan was to use 1mm thick measuring instruments to allign the board right back into place and then hotglueing it onto the remaining stock, to keep it in place. I honestly thought this would almost certainly introduce some kind of Offset, but it really did not. After attaching the 0.2mm-0.5mm V-bit (to get access to the pin area of the microcontroller), we started with the front cutout. Shortly after the cutout started, Ahmed told me, it would be beneficial to to this board in two seperate runs. One run using the 0.4mm bit for everything but the MCU and the surrounding Area, and another run using the V-Shaped bit for the MCU and the traces around it. For this, i masked the MCU area in the PNG and coloured it flat so that mods would not "see" any traces in this area. At the same time I amde a reverse selection and painted everything but the MCU area in a flat colour. With these two new images, we started milling again, but this time with the 0.4mm bit. We immediatly could notice that the boards allignment was correct, as all the drilling holes were alligned on the newly created pads almost perfectly. The milling process for the 0.4mm bit took quite long as it had to do many long traces. After it was finished, I changed the tool to the V-Bit and started the second job. Here everything went also very smooth and I at this moment havent noticed any major things missing. Shortly before removing the board however, I noticed two mistakes, which both were my fault. One of the errors was, that there were traces missing, that were meant to connect the motor pins to the stepper driver block for the z axis. I redid the traces for this shortly before finishing the KiCAD project and just havent pressed "B" again, to reflow the ground layer, which meant, that the traces were invisble when creating the SVG. Since all of the stepper driver blocks and motor headers have the same layout, I just cutout the missing part from the y-axis and implanted it over the missing traces for the z-axis. I selected the part I wanted to be milled, reverse selected, so that I had everything selected but the part i was about to mill, and coloured it flat. This image, i then used inside mods, which then only generated the toolpath for the missing traces. I started the job on the cnc and merely one minute later the traces were on the board just like they were ther when I had pressed the "B" key before exporting. The other huge mistake was, that I did not notice two traces not being cut correctly when overlooking the toolpath for the V-Bit in mods. No matter what settings I changed, I just was not able to get this one cut between the two traces to happen with mods. Ahmed the told me, that we had a 0.1mm milling bit, so I chose this as the size in Mods. This resulted in the traces being cut (according to mods atleast). After downloading the toolpath and inserting it into the machine, I started this hopefully last cutting operation. As it turns out, It was very good to have the hand on the EStop again. The milling operation was somehow completely offset. We noticed this pretty quickly and stopped the machine. Since we could not find the problem in mods or any of the other steps, we decided to do the craziest thing yet: Cutting the trace manually. Since the missing cut was just a very small part and exactly 45 degrees, we could jog the machine manually with the spindle running using the 45 degree movements.With the help of a few people in the lab, we managed to allign the machine perfectly and also cut the trace perfectly. I was so amazed by this. The board looked just like it was cut by the machine. No trace of manually cut stuff at all. With this final step done, this poor board of copper was finally freed from the CNC. All in all, this board was inside the machine for almost two full days, needed seven different toolpaths and survived a mid cut pwer loss of the CNC. This board went through alot to come out like this:

The finished and soldered Board

With the cut Board i now went to our rivet punching machine and inserted all the needed rivets inside the vias. This went really smooth with no huge problem. After inserting all the rivets, I went ahead and used pressured air to get all of the gunk and dirt out of the holes, before I could move on to soldering. I began soldering quite late this day sadly. I only managed to solder the most important parts onto the board. So we could "speak" to the MCU and burn a bootloader onto it. To burn a Bootloader onto this blank chip, we used another Arduino UNO. With the UNO connected to the Reset, SCK, MISO and MOSI pins in the following way, we were able to burn a bootloader onto the blank chip:

  • Arduino Uno Pin 10 to Reset
  • Arduino Uno Pin 11 to MOSI
  • Arduino Uno Pin 12 to MISO
  • Arduino Uno Pin 13 to SCK

At first we got an error when trying to burn the bootloader. The error we got told by the arduino IDE was that the chip had a wrong signature:

One of the errors we got while burning the bootloader
The other error we got while burning the bootloader

As it turned out, the reset pin on the new board had a bad connection through the vias to the pin on the MCU. With this problem solved by just using a little bit of solder on both sides of the vias, the bootloader burned just fine. At this time it was very late and the lab closed. Since the next few days were local holidays, the lab was closed. I asked to take a soldering station and other equipment with me to finsih the board at home. I finished the Board at home but shortly afterwards noticed my first huge mistake I already talked about in the beginning. My pinout structure was flat out incompatible with GRBL. I atleast tried to get X and Y to work as these were on the same Port for steps and directions respectively, but to no avail. When I uploaded GRBL through the Arduino UNO, I was just greeted with Gibberish in the serial monitor. No command I sent to the chip yielded any kind of answer. After reassuring that the code itself worked fine by uploading GRBL to an Arduino UNO and being able to read the welcome message and send GCode commands, I waited for the next day in the lab to troubleshoot with my instructor.

In the lab we were able to almost immediatly get the Board to show the GRBL welcome message through serial. While I redid all the Vias with solder and checked every connection at home, we did this again and were able to read out over serial. What wasnt possible however was sending Gcode or any kind of GRBL commands like "$" or "$$". The whole day was then used for troubleshooting the board as a whole. The steps we undertook were the following:

  • Reflowed all the vias again
  • Reflowed the MCU connections
  • Reinforced thin traces with cables
  • Swapped out the Crystal

In the end we werent even able to get the Bootloader to the chip again. Everytime we tried we were greeted with this false signature error from above. It was at this time that Ahmed suggested to take a closer look at the reset circuit. And here was the big problem. I designed the reset circuitry completely wrong. Instead of pulling down the reset pin with each button press, the button shorted VCC to GND. Thuis mistake is so stupid that I am really ashamed this happened. This meant more or less, that the MCU was fried and that I had killed a 328p. The solution was rather simple. I just had to relocate the pull up resistor to sit between the button and VCC instead of between the button and RST. This was possible due to lucky pad distancing on the board. I could just switch them around and only had to trim one trace with the manual drill at the lab. After I have done this I desoldered the dead 328p and soldered on a new one. After we thoroughly checked, that the reset was now working and not shorting VCC to GND anymore, we tried burning the bootloader again. Again, no luck. We still got the error from above, actually multiple variations of this error:

  • Device Signature: 0xffffff
  • Device Signature: 0x000000
  • Device Signature: 0xXXXXXX, where the row of X's were seemingly randomized

At the end I think I dont get around to redo the whole Board. Redo the mapping to conform to GRBLs standard, fix the Reset circuitry to completely, get the crystal closer to the Chip, not use six seperate pins for the limit switches, but share X+ and X- on one pin. Sadly this whole troubleshooting thing took place on the thursday before the lecture, so im still in the middle of redesigning the Board. I will update the page here with the redesigned Board and the working machine however.

In the meantime, to get to know GRBl, I used one of the industruial CNC shields we had at the lab. I did not notice it at all, but the first one I got had a tripped fuse and so was not giving power to the motors. After some time of troubleshooting with Ahmed we noticed the tripped Fuse and got another Shield. With this it was really easy to get the motors to move. I installed GRBL on the UNO, plugged in the Shield, plugged in the motor drivers and plugged in the motors next to the drivers. For controlling GRBL I was recommended to use Universal Gcode Sender. After connecting to the serial port within the application I was able to move the motors just fine:

Finally moving the motors, although sadly not with my own board

Update

After the sad ending of V1 of my Board, I sat down and created a second version with the GRBL prinout in mind. Apart from the pinout, and the creation of pinheaders for the config of the motor drivers, nothing much changed! None the less I want to show you the new schematic and PCB design for V2.

Schematic of the V2 Version
PCB Design of the V2 Version

I milled the Board in exactly the same way as described above, which worked really good again. After stuffing the Board and loading up GRBL, again, nothing seemed to work. I debugged for a few days at least and finally was able to pinpoint the problem to dirty Vias, that were somehow not allowing the signal to be transmitted properly between the MCU and the Stepper Mptor Drivers (Silent StepStick). After cleaning everything thoproughly and reflowing every not working Via, I was able to FINALLY move something with my own Board. Sadly by this time, it was already Apllication and Interface week. In the time between before the update and now, the plan for the machine to be built has changed numerous times. Driven by my idea from Networks and Communications week and the idea from one of our instructors Marcello Tania to just reuse this idea for the machine, I planned on doing a Hardware ISS tracker. Since I was majorly behind for this task, I really sped up the process. I quickly threw together everything needed in Fusion. I relied on Wood and aluminum framing. For moving the tool, I relied on ballscrews. The Fusion360 project can be downloaded below.

The Fusion360 File of the ISS Tracker

Full Model of ISS Tracker

Cutting the Wooden pieces was a very straight forward process. As was the process of Building the Machine:

The ISS Tracker Parts on the CNC

The CNC cut parts of the ISS Tracker

The ISS Tracker Mid Assembly

As you can see when looking at the model, I had to make a few considerations while designing. The first big problem is, that I thought I could attach the stepper motor through its bottom, which was clearly not the case. This is why I had to design the Motor Mount which is now also part of the 3D CAD model above. I exported the motor mount as an STL file and printed it on one of the labs Ultimaker S5s. I honestly thought Iwould need multiple prints to get the tolerances to work the way I wanted to, but to my surprise, the mount fit perfectly. The only thing that needed change, were the mounting holes. I just used a drill bit to make them a tiny bit wider to fit the screws. I also 3D printed the Mount for the Laserpointer I had lying around at home. The shape of the laserpointer allowed me to just print a long bar with a cutout half circle! And again because of the shape of the Laserpointer, this way, I could mount it with the laser button pushed in. I then just had to turn on the laserpointer with the ON/OFF switch to enable the laser. Now that everything was mounted it was finally time for a first test! I plugged everything into my GRBL Board and fired up Universaal GCode Sender. It quickly found the GRBL installation through Serial and I was off to test the axes:

Moving both axes with GRBL on my own Board!

With the axes now working, I could start changing settings and implement a few safety features. I began by set the ESTEPS correctly. Through this Tutorial, I learned how to measure and calculate current and wished ESTEPS. I did so and was very happy with the result. After that I installed the Endstops for both Axes. This would allow me to run a homing cycle, so that the machine knows where its tool is positioned after a power loss. On top of that this also allows me to set upper soft limits in GRBL so that the machine does not crash into the positive end of each axis. I quickly set the limit switches up and they worked like a charme after I resoldered them once. I accidently soldered them the wrong way, which meant that GRBL would always see them as tripped, when they were in fact not tripped. With that fixed, I set up the homing cycle according to GRBLs Wiki and set upper soft limits for each axis by driving the axes manually up to a point where I thought that this would be enough. To get the correct Commands to GRBL, I used a changed up version of my Code from Application and Interface programming week. The code for this you can see below. The main diffreences are the following:

  • Serial implementation changed a little bit, to allow the program to quit on error when opening serial port
  • Program now starts with a series of commands sent over serial to home the machine
  • After homing the "normal" will then start
  • Next to displaying the current position in program, it also sends the current position as GCode to machine

						
# All needed imports
from tkinter import *
from PIL import ImageTk, Image
import PositionTracker
import time
import serial

# Global Variables
x = 0
y = 0
machineX = 287
machineY = 143.5
OffsetX=5
OffsetY=22
answer = ""

# Serial port to GRBL Board on my Machine
port = '/dev/cu.usbserial-D30ABOB9'


# Try to open the Serial port, if not possible quit
try:
    print("Opening Serial Port!")
    ser = serial.Serial(port, 115200, timeout=None)
except:
    print("Error opening serial port!11")
    quit()

# Main Application Window on Laptop (Runs simultaniously with machine)
root = Tk()
root.title("ISS Tracker")
root.geometry("1500x750")
root.resizable(0, 0)
root.iconphoto(False, ImageTk.PhotoImage(Image.open("ISS.png").resize((50, 50))))
img = ImageTk.PhotoImage(Image.open("WorldMap.jpg").resize((1500, 750)))
mapCanvas = Canvas(root, width=1500, height=750, bg="white")
mapCanvas.pack(pady=20)
bgImage = mapCanvas.create_image(0, 0, anchor=NW, image=img)
iss = ImageTk.PhotoImage(Image.open("ISS.png").resize((50, 50)))
x = int(750)
y = int(375)
issImage = mapCanvas.create_image(x, y, image=iss)

# Function to update the ISS position every two and a halve seconds
def updatePosition():
    positions = PositionTracker.gatherPositionAPI()
    mapCanvas.delete('all')
    bgImage = mapCanvas.create_image(0, 0, anchor=NW, image=img)
    issImage = mapCanvas.create_image(int(positions[0]), int(positions[1]), image=iss)
    mapCanvas.create_text(225, 15, font="Times 20 italic bold",
    text='latitude: ' + positions[2] + ' | longitude: ' + positions[3])
    if ser.isOpen():
        sendPositionToMachine(positions)
    root.after(2500, updatePosition)


# Function to send the current ISS Position as GCode to the machine	
def sendPositionToMachine(positions):
    command = "G90"
    machinePositions = PositionTracker.convertLatLon(positions[2], positions[3], machineX, machineY)
    xValue = str(round(machinePositions[0] + OffsetX, 3))
    yValue = str(round(machineY - machinePositions[1] + OffsetY, 3))
    command += "X" + xValue + "Y" + yValue + "\n"
    if machinePositions[0] + OffsetX < 270 and machineY - machinePositions[1] + OffsetY < 170:
        print(command)
        ser.write(bytearray(command.encode()))
    else:
        print("Coordinate " + positions[2] + " ; " + positions[3] + " can not be reached by the machine! Command is not being sent.")


# Function that runs the initial GRBL homing Cycle and waits for it to finish
def wakeUpAndHome():
    ser.write(bytearray("\r\n\r\n".encode()))
    time.sleep(2)
    ser.flushInput()
    ser.write(bytearray("$G\n".encode()))
    print("w")
    answer = ser.readline()
    print("r")
    ser.flush()
    answer = ser.readline()
    print("Sending WakeUp Messages...")
    if answer.decode("utf-8").strip() == "ok":
        print("Wake up received!")
        answer = ""
        ser.flush()
        ser.write(bytearray("$X\n".encode()))
        answer = ser.readline()
        if answer.decode("utf-8").strip() == "ok":
            print("Starting the Homing Cycle...")
            answer = ""
            ser.flush()
            ser.write(bytearray("$H\n".encode()))
            answer = ser.readline()
            if answer.decode("utf-8").strip() == "ok":
                print("Offsetting the machine to go to the Edge of the Map")
                mapEdgeMoveCommand = "G90X" + str(OffsetX) + "Y" + str(OffsetY) + "\n"
                ser.write(bytearray(mapEdgeMoveCommand.encode()))
                time.sleep(5)
                ser.flushInput()
                print("Starting main program loop...")
                updatePosition()
                root.mainloop()
            else:
                print("Error when writing/reading Homing Cycle Message")
        else:
            print("Error when writing/reading $X")
    else:
        print("Error when writing/reading $G")


# If serial port is opened, start homing cycle (Within homing cycle routine, the main program will start)
if ser.isOpen():
    print("Serial opened!")
    wakeUpAndHome()
else:
    print("Error opening Serial Port!")
    quit()
						
					

In the end the Machine was finally working, and I couldnt be any happier. I did all this by myself with the help of Ahmed and I am really proud of the outcome:

The Machine finally working. You can see the homing cycle and after that the move to the current position. Every movement afterwards is pretty small because on this scale the ISS is moving quite "slow"

To show how everything is connected at the End, I amde a quick drawing, showcasing all important connections:

All Connections needed to make the Board work

Downloads