Skip to content

Week 10: Mechanical Design and Machine Design

My main role on the project was to focus on the electronics and coding for the machine.

Link to Group Assignment

Dismantled 3D Printer Base

For the foundation of the machine we dismantled an existing 3D printer that was used for a previous Kamakura Fab Academy machine group project - Juicy Messenger.



We started by exploring how the original machine worked by moving the parts manually while it was off. The machine was originally a 3D printer where the bed moved on the y direction on lead screws and another set of lead screws moved the head in the z direction and a belt moved the head in the x direction.

We decided that to work for our project we needed to change it so that what was the z axis became the y axis and x remain the same.

After pulling everything apart we were able to reassemble the original machine to our new configuration and move it by hand in the x and y direction. The x direction uses a belt around a cogged pulley attached to a stepper motor and the y uses two lead screws each attached to a stepper motor.

We had some alignment/wonkyness issues with the lead screws, but we were able to resolve this by making sure everything was tight and straight (definitely a two person job).

Controlling the Stepper Motors - Arduino Uno

The dismantled and reconfigured 3d Printer originally used two stepper motors for the z axis, now the y axis and one for the x axis, still x axis.

To control these stepper motors I decided to use an Arduino Uno with a CNC Shield.

Stepper Motors used were Quimat Motor 17HD48002H-22B. These were changed from the original steppers used for the 3D printer.

CNC Shield Setup

Components:
- CNC Shield (HiLetGo V3)
- 2x Stepper Drivers
- 6x Micro Steppers

The two y stepper motors were wired together and then connected to y on the CNC Shield.

The x stepper motor was wired to the x on the CNC Shield.

The CNC Shield was then connected to separate power form the Arduino, to allow for the right amount of power to be fed to the steppers and to protect the Arduino from power fluctuations created by the stepper motors. Through testing of this particular setup I found that I needed at least 15V with at least 2Ah to power the setup and move all the motors.

Note: For the CNC Shield max power input is 36V and 3Ah.

Arduino Uno Setup

To control the steppers through the CNC Shield I used Grbl. This was loaded onto the Arduino by doing the following: - Download grbl from Github https://github.com/gnea/grbl
- Download a zip file of the code grbl-master.zip - Load the zip file as a library in the Arduino IDE

- Open the grblUpload Example Code and upload it onto the Arduino

grblUpload Code

/***********************************************************************
This sketch compiles and uploads Grbl to your 328p-based Arduino! 

To use:
- First make sure you have imported Grbl source code into your Arduino
  IDE. There are details on our Github website on how to do this.

- Select your Arduino Board and Serial Port in the Tools drop-down menu.
  NOTE: Grbl only officially supports 328p-based Arduinos, like the Uno.
  Using other boards will likely not work!

- Then just click 'Upload'. That's it!

For advanced users:
  If you'd like to see what else Grbl can do, there are some additional
  options for customization and features you can enable or disable. 
  Navigate your file system to where the Arduino IDE has stored the Grbl 
  source code files, open the 'config.h' file in your favorite text 
  editor. Inside are dozens of feature descriptions and #defines. Simply
  comment or uncomment the #defines or alter their assigned values, save
  your changes, and then click 'Upload' here. 

Copyright (c) 2015 Sungeun K. Jeon
Released under the MIT-license. See license.txt for details.
***********************************************************************/

#include <grbl.h>

// Do not alter this file!

I was able to test functionality using universal G-code Sender.

Battery Power for Stepper Motors

One key requirement for the machine was to be able to run it at the beach away from mains power. As such I needed a battery.

I could have gone an bought a battery, however I decided that we could use what we had available in the Lab, an 18V 3Ah battery from a drill.

This battery had clearly labelled positive and negative terminals. Copper PCB material from the SRM-20, was a perfect fit in the terminals.

I used the SRM-20 to cut out two rectangular pieces of board, I then soldered a female terminal on each board to plug positive and negative wires from the CNC Shield into.



Controlling the Arduino and Servo - Raspberry Pi 4

To allow for the machine to be remotely controlled I decided to use a Raspberry Pi 4.

First test was to install and use Universal G-code Sender on the Pi to control the stepper motors. This worked.

Next step was to be able to send a looped code that produces a random pattern.

CNC Code

I can use Python to send G-code to the Arduino from the Pi over Serial. You just need to make sure that you have the correct name for the port the Arduino is on when connected via USB to the Pi.

I utilised ChatGPT to help us with writing the code, this was both to save time, but also to test ChatGPT's capabilities in coding.

First I asked it to create code for drawing a circle

# Made by ChatGPT April 2023 
import serial
import time
import math

ser = serial.Serial('/dev/ttyACM0', 115200, timeout=1) # Replace ttyACM0 with the appropriate port for your Arduino Uno

def send_gcode(gcode):
    ser.write(str.encode(gcode + '\n'))
    grbl_out = ser.readline().decode('utf-8').strip()
    print('sent: ' + gcode)
    print('received: ' + grbl_out)

send_gcode('$X') # send the kill alarm command to reset the Arduino Uno

send_gcode('G21') # set units to millimeters

send_gcode('G90') # set absolute positioning mode

send_gcode('G0 X0 Y0 Z5 F1000') # move to the starting position

radius = 15 # 30mm diameter circle has a 15mm radius
angle_step = 10 # step size in degrees

send_gcode('G1 X{} Y{} F1000'.format(radius, 0)) # move to starting point on circle

for angle in range(0, 360, angle_step):
    x = radius * math.cos(math.radians(angle))
    y = radius * math.sin(math.radians(angle))
    send_gcode('G1 X{} Y{} F1000'.format(x, y)) # move to next point on circle

send_gcode('G1 X{} Y{} F1000'.format(radius, 0)) # return to starting point on circle

ser.close() # close the serial connection

When then asked for a wave like pattern. ChatGPT came up with using a sine wave.

# Made by ChatGPT April 2023 
import serial
import time
import math

ser = serial.Serial('/dev/ttyACM0', 115200, timeout=1) # Replace ttyACM0 with the appropriate port for your Arduino Uno

def send_gcode(gcode):
    ser.write(str.encode(gcode + '\n'))
    grbl_out = ser.readline().decode('utf-8').strip()
    print('sent: ' + gcode)
    print('received: ' + grbl_out)

send_gcode('$X') # send the kill alarm command to reset the Arduino Uno

send_gcode('G21') # set units to millimeters

send_gcode('G90') # set absolute positioning mode

width = 100 # set the width of the rectangular area to draw in
height = 100 # set the height of the rectangular area to draw in

# set the starting position of the machine
start_x = width / 2
start_y = height / 2

# set the amplitude and period of the sine wave
amplitude = 10
period = 20

# set the step size for the curve
step_size = 0.5

# set the movement speed of the machine
speed = 1000

# set the color of the line
#line_color = (255, 255, 255)
x = 1
# loop to draw a continuous line
while True:
    # move the machine in a sine wave
    for b in range(0, width):
        #y = round(start_y + amplitude * math.sin(math.pi * x / period))
        x = x
       # limit y to a maximum of 100 using an if statement
        if y > height:
            y = height

        if x > width
            end for

        send_gcode('G1 X{} Y{} F{}'.format(x, y, speed))
        x = x + 0.5


    # wait for the machine to finish moving
    time.sleep(0.1)

The sine wave code was then modified to change the x to two loops so that the machine would move the x axis back and forth.

# Made by ChatGPT, modified by Claire Chaikin-Bryan April 2023 
import serial
import time
import math

ser = serial.Serial('/dev/ttyACM0', 115200, timeout=1) # Replace ttyACM0 with the appropriate port for your Arduino Uno

def send_gcode(gcode):
    ser.write(str.encode(gcode + '\n'))
    grbl_out = ser.readline().decode('utf-8').strip()
    print('sent: ' + gcode)
    print('received: ' + grbl_out)

send_gcode('$X') # send the kill alarm command to reset the Arduino Uno

send_gcode('G21') # set units to millimeters

# send_gcode('G90') # set absolute positioning mode

width = 100 # set the width of the rectangular area to draw in
height = 100 # set the height of the rectangular area to draw in

# set the starting position of the machine
start_x = width / 2
start_y = height / 2

# set the amplitude and period of the sine wave
amplitude = 10
period = 20

# set the step size for the curve
step_size = 0.5

# set the movement speed of the machine
speed = 2000

# set the color of the line
#line_color = (255, 255, 255)
loop = 'A'
x = 0
# loop to draw a continuous line
while True:
# Loop A
    if loop == 'A':
        while x <= 100:
            print('Loop A:', x)
            x += 10
            y = round(start_y + amplitude * math.sin(math.pi * x / period))
            if y > height:
                y = height
            send_gcode('G1 X{} Y{} F{}'.format(x, y, speed))
            time.sleep(1)
        # switch to Loop B when x reaches 100
        loop = 'B'

    # Loop B
    elif loop == 'B':
        while x >= 0:
            print('Loop B:', x)
            x -= 10
            y = round(start_y + amplitude * math.sin(math.pi * x / period))
            if y > height:
                y = height
            send_gcode('G1 X{} Y{} F{}'.format(x, y, speed))
            time.sleep(1)
        # switch to Loop A when x reaches 0
        loop = 'A'    

    # wait for the machine to finish moving
    time.sleep(0.1)

I finally asked ChapGPT to change the modified sine wave code to make the line random and limit x and y to +-100 (I could then easily change this parameter).

# Made by ChatGPT, modified by Claire Chaikin-Bryan April 2023  
import serial
import time
import random

ser = serial.Serial('/dev/ttyACM0', 115200, timeout=1) # Replace ttyACM0 with the appropriate port for your Arduino Uno

def send_gcode(gcode):
    ser.write(str.encode(gcode + '\n'))
    grbl_out = ser.readline().decode('utf-8').strip()
    print('sent: ' + gcode)
    print('received: ' + grbl_out)

send_gcode('$X') # send the kill alarm command to reset the Arduino Uno

send_gcode('G21') # set units to millimeters

# set the starting position of the machine
start_x = 0
start_y = 0

# set the movement speed of the machine
speed = 2000

# loop to draw a continuous line
while True:
    x = random.randint(-100, 100)
    y = random.randint(-100, 100)

    send_gcode('G1 X{} Y{} F{}'.format(x, y, speed))

    # wait for the machine to finish moving
    time.sleep(0.1)

Our machine was a little jerky something with its movements, but I found that by rounding the code to multiples of ten it worked better. I think this could be due to damage in our stepper motors, maybe due to power overloads

Servo Code

To be able to control and switch the two drawing bits I needed to have code for the servo.

ChatGPT came up with the following.

# Made by ChatGPT April 2023 
import RPi.GPIO as GPIO
import time

# Set up GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)

# Set up PWM
pwm = GPIO.PWM(18, 50) # pin 18, frequency 50Hz
pwm.start(0) # start with duty cycle of 0

# Define a function to set the angle of the servo
def set_angle(angle):
    duty = angle / 18 + 2 # calculate duty cycle from angle
    GPIO.output(18, True) # turn on the servo
    pwm.ChangeDutyCycle(duty) # set duty cycle
    time.sleep(1) # wait for servo to move
    GPIO.output(18, False) # turn off the servo
    pwm.ChangeDutyCycle(0) # set duty cycle to 0

# Move servo to 0 degrees
set_angle(0)

# Move servo to 90 degrees
set_angle(90)

# Move servo to 180 degrees
set_angle(180)

# Clean up GPIO
pwm.stop()
GPIO.cleanup()

I then tested this code to know which angle to set for the middle and the left/right bit (pineapple and stick).

Note: I had initial issues with controlling the servo with the code provided by ChatGPT (servo greatly oer spinning), I tested another servo and found that is worked fine, so I concluded that I had a broken servo and used the new one moving forward.

Final Code for Random Movement and Servo

# Made by ChatGPT, modified by Claire Chaikin-Bryan April 2023 

import serial
import time
import random
import RPi.GPIO as GPIO
import time

# Set up GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.OUT)

# Set up PWM
pwm = GPIO.PWM(18, 50) # pin 18, frequency 50Hz
pwm.start(0) # start with duty cycle of 0

# Define a function to set the angle of the servo
def set_angle(angle):
    duty = angle / 18 + 2 # calculate duty cycle from angle
    GPIO.output(18, True) # turn on the servo
    pwm.ChangeDutyCycle(duty) # set duty cycle
    time.sleep(1) # wait for servo to move
    GPIO.output(18, False) # turn off the servo
    pwm.ChangeDutyCycle(0) # set duty cycle to 0


ser = serial.Serial('/dev/ttyACM0', 115200, timeout=1) # Replace ttyACM0 with the appropriate port for your Arduino Uno

def send_gcode(gcode):
    ser.write(str.encode(gcode + '\n'))
    grbl_out = ser.readline().decode('utf-8').strip()
    print('sent: ' + gcode)
    print('received: ' + grbl_out)

send_gcode('$X') # send the kill alarm command to reset the Arduino Uno

send_gcode('G21') # set units to millimeters

# set the starting position of the machine
start_x = 0
start_y = 0

# set the movement speed of the machine
speed = 3000

#create counter for servo
a = 0

set_angle(90)

while True:
    for a in range (0, 5):
        # Move servo to 0 degrees
        set_angle(0)

        # loop to draw a continuous line
        x = random.randint(-50, 50)
        x = round(x / 10) * 10
        y = random.randint(-100, 80)
        y = round(x / 10) * 10

        send_gcode('G1 X{} Y{} F{}'.format(x, y, speed))

        # wait for the machine to finish moving
        time.sleep(3)
        a = a + 1
    for a in range (5, 10):
        # Move servo to 0 degrees
        set_angle(120)

    # loop to draw a continuous line
        x = random.randint(-50, 50)
        x = round(x / 10) * 10
        y = random.randint(-100, 80)
        y = round(x / 10) * 10

        send_gcode('G1 X{} Y{} F{}'.format(x, y, speed))

        # wait for the machine to finish moving
        time.sleep(3)
        a = a - 1

# Clean up GPIO
pwm.stop()
GPIO.cleanup()

Battery Power to Raspberry Pi 4

I used a potable battery pack used to charge a laptop to provide power to the Pi, which then provides power to the Arduino via USB.

Final Electronics Setup

Electronics in the cart to be pulled behind the main machine.

Final Machine in the Sand


Files

grbl-master.zip
grblUpload.ino
cncpi.py