Week 11 - CNC team project

Task #11

The task for the eleventh week is to design, build and program a CNC (Computer Numerical Control) machine. For this project, we will work in a group.

ZenBot

Our team Griffin decided to build a Sisyphus inpired table with a magnetic ball printing a pattern in sand. We used SCARA as our main machanism and utilized Raspberry Pi 5, Arduino Nano and Nema17 stepper motors for control. The team website in Czech is accessible via Team Griffin link. My part in this project was to develop the control application.

Control Application

The Nema17 stepper motor 1 and 2 are connected to A4988 driver and the driver recieves steps and direction orders from Arduino Nano. Arduino is then connected via USB cable with Raspberry Pi 5, which sends control sequences to Arduino over serial communication. Raspberry Pi also hosts a server, which we can connect to over Wi-fi and operate the whole ZenBot including adding new patterns, choosing one and running the "printing" process.

📟 Arduino
The code for Arduino Nano is rather simple. It uses the AccelStepper library to work with the drivers and stepper motor. After startup, it sends setup successful message and waits for control sequences from the serial line. It expects four main controls: "HOME goS1:{int} goS2:{int}", "START", "STOP" and "dS1:{int} dS2:{int}". S1 and S2 are steps for the motors 1 and 2, it is the number of step the motors need to move. After successfully moving the motors by the given number of steps, Arduino sends answer message that it stepped and expects another command.

Include the AccelStepper Library
#include <AccelStepper.h>

#define BAUD_RATE 115200

#define DIR_PIN1 2
#define STEP_PIN1 3

#define DIR_PIN2 4
#define STEP_PIN2 5

#define SPEED 6000
#define ACCEL 12000

// Define motor interface type
#define motorInterfaceType 1

// Creates an instance 1
AccelStepper myStepper1(motorInterfaceType, STEP_PIN1, DIR_PIN1);

// Creates an instance 2
AccelStepper myStepper2(motorInterfaceType, STEP_PIN2, DIR_PIN2);

bool sent_stepped = true;
bool stopped = false;
bool homing = false;
String line = "";
int dS1, dS2;
int goS1, goS2;

void setup() {
    // set the maximum speed, acceleration and position
    myStepper1.setMaxSpeed(SPEED);
    myStepper1.setAcceleration(ACCEL);
    myStepper1.setCurrentPosition(0);

    myStepper2.setMaxSpeed(SPEED);
    myStepper2.setAcceleration(ACCEL);
    myStepper2.setCurrentPosition(0);

    Serial.begin(BAUD_RATE);
    Serial.println("SETUP COMPLETE");
}

void loop() {
    if (Serial.available()) {
        line = Serial.readStringUntil('\n');  // Read until newline

        if (line == "STOP") {
            myStepper1.moveTo(myStepper1.currentPosition());
            myStepper2.moveTo(myStepper2.currentPosition());
            stopped = true;
            Serial.println("STOPPED");
        }

        // Parse the values
    else if (sscanf(line.c_str(), "dS1:%d dS2:%d", &dS1, &dS2) == 2 and !stopped) {
            myStepper1.move(dS1);
            myStepper2.move(dS2);
            sent_stepped = false;
    }

        else if (line == "START") {
            stopped = false;
            Serial.println("READY");
        }

        // set home position
        else if (sscanf(line.c_str(), "HOME goS1:%d goS2:%d", &goS1, &goS2) == 2) {
            myStepper1.move(goS1);
            myStepper2.move(goS2);
            homing = true;
            stopped = false;
        }
    }

    if (myStepper1.distanceToGo() == 0 and myStepper2.distanceToGo() == 0 and (!sent_stepped or homing)) {
        if (homing) {
            myStepper1.setCurrentPosition(0);
            myStepper2.setCurrentPosition(0);
            Serial.println("HOMED");
            homing = false;
        }
        else {
            Serial.println("STEPPED");
            sent_stepped = true;
        }

    }

    myStepper1.run();
    myStepper2.run();
}

💻 Raspberry Pi 5
The application in Raspberry Pi is far more complex. It is full stack application with frontend in React and backend in Python and is run in Docker to support different PC architectures. The backend side communicates with Arduino over serial line, manages patterns, computes trajectory of the magnet ball, and supports transfer of all control and pattern visualization to the frontend part.

The frontend part offers GUI to control the ZenBot, its deployed as webapp and you can connect to it via local network. It also support adding new custom patterns generate over Sandify page with setting for SCARA g-code.

No image
No image
No image

Due to the program complexity the source code is accessible at ZenBot.

⏳ Demo