Final Project

Final Project

പൂമ്പാറ്റ: The Butterfly-Infinity Plotter

പൂമ്പാറ്റ:The Butterfly- Infinity Plotter is a compact and efficient XY plotter designed using three omni-wheels, stepper motors, an ESP32 microcontroller, and a Bluetooth module. The design aims to provide a precise, versatile, and cost-effective plotting solution for various applications.

The " പൂമ്പാറ്റ:The Butterfly- Infinity Plotter" is an innovative project that combines the precision of CNC technology with the creativity of artistry. This plotter is designed to draw intricate designs and images directly onto expansive canvases, such as walls and floors. With its CNC capabilities, it offers a high level of precision, allowing for the creation of detailed and captivating artworks on a larger scale. Whether transforming a blank wall into a vibrant mural or enhancing the aesthetics of a floor space, the Plotter opens up new possibilities for large-scale artistic expression. It's a fusion of technology and artistry, making it a unique and versatile tool for creative endeavors.

The Idea

Onam, the ten-day harvest festival of Kerala, is a dazzling display of culture, tradition, and joyous celebration. It's more than just a harvest festival; it's a homecoming, a renewal of spirit, and a time for families and communities to come together.

Onam is a vibrant and culturally rich festival celebrated predominantly in the Indian state of Kerala. It is an annual harvest festival that typically falls in the month of Chingam, the first month of the Malayalam calendar, which corresponds to August-September in the Gregorian calendar. Onam is celebrated

Pookalam: A Floral Welcome

Pookalam is a central part of Onam festivities. It's a floral design or rangoli made using a variety of colorful flowers and laid on the floor, particularly at the entrance of homes. These floral carpets are symbolic of prosperity and joy, and are believed to welcome King Mahabali, a mythical king who is said to visit Kerala during Onam.

The Making of a Pookalam

Traditionally, only locally available flowers were used to create pookalam. The preparation starts days before the main Onam day. Here's a glimpse into the process:

Each year, our office takes part in the tradition of drawing a pookalam for Onam. However, creating these intricate floral designs on the floor is a challenging and time-consuming process. It takes around 5-6 hours to draw the pattern.

This inspired the creation of "പൂമ്പാറ്റ: The Butterfly - Infinity Plotter," a cutting-edge tool designed to simplify and enhance this tradition.

"പൂമ്പാറ്റ: The Butterfly - Infinity Plotter" is a compact and efficient XY plotter, engineered with three omni-wheels, stepper motors, an ESP32 microcontroller, and a Bluetooth module. This innovative device merges the precision of CNC technology with the boundless creativity of artistic expression. The plotter's design ensures precise, versatile, and cost-effective plotting for a variety of applications.

This project embodies the fusion of technology and artistry, allowing for the creation of detailed and captivating designs directly onto expansive canvases such as walls and floors. The CNC capabilities of the plotter provide high precision, enabling the drawing of intricate and beautiful artworks on a larger scale. Whether transforming a blank wall into a vibrant mural or enhancing the aesthetics of a floor space, the "പൂമ്പാറ്റ: The Butterfly - Infinity Plotter" opens up new possibilities for large-scale artistic expression.

I have drawn a basic concept sketch in week 1

Project Management

For managing the final project, i have set a detailed project management plan

The project schedule outlines the steps from design and assembly to testing and final presentation.

Key Objectives of my project were outlined first

  1. Streamline the process of drawing pookalams.
  1. Achieve high precision and versatility in plotting designs.
  1. Ensure cost-effectiveness and ease of use.
  1. Enable large-scale artistic expression on floors.

Then I divided the project into various phases

Project Phases

1. Design Phase

  • Main Body Design : Design the main body of the plotter.
  • Motor Bracket Design : Design brackets to hold the motors.
  • Wheel Coupling : Mill and prepare wheel couplings.
  • Pen Holder Design : Design the holder for the plotting pen.
  • PCB Design: Design the PCB in KiCAD

2. Manufacturing Phase

  • Main Body Manufacturing : Manufacture the main body components using Zund and Laser Cutting Machine
  • 3D Printing : Print the designed components using 3D printers.
  • Milling : PCB Milling

3. Assembly Phase

  • Assembly of Wheels : Assemble the omni-wheels.
  • Assembly of Main Body : Assemble the main body components.

4. Electronics Phase

  • Electronics Design Micro Controller Board : Design the microcontroller board.
  • Electronics Design Main Board : Design the main electronics board.
  • Electronics Production : Produce the designed electronic components.
  • Soldering : Solder the electronic components.

5. Integration and Testing Phase

  • Testing with CNC Shield : Test the assembly with a CNC shield.
  • Software Checking and Interfacing : Ensure the software is correctly interfaced with the hardware.
  • Testing Using Board : Conduct thorough testing using the electronics board.
  • Total System Integration : Integrate all components and ensure system compatibility.

6. Documentation and Presentation Phase

  • Documentation : Document the design, assembly, and testing processes.
  • Final Presentation : Prepare and present the completed project.

Schedule Breakdown

Date Activity Status Remarks
18 May 2024 Main Body Design Completed Scheduled to Zund
20 May 2024 Motor Bracket Design Completed Scheduled to 3D printing
21 May 2024 Wheel Coupling Completed Done By Milling
22 May 2024 Assembly of Wheels Completed
23 May 2024 Assembly of Main Body Completed
24 May 2024 Testing with CNC Shield Pending
27 May 2024 Electronics Design Micro Controller Board Pending
27 May 2024 Electronics Design Main Board Pending
28 May 2024 Pen Holder Design Pending 3D Printing
29 May 2024 Electronics Production Pending
30 May 2024 Soldering Pending
31 May 2024 Soldering Pending
1 June 2024 Software Checking, Interfacing Pending
2 June 2024 Testing Using Board Pending
3-5 June 2024 Total System Integration Pending
5-7 June 2024 Documentation Pending
10 June 2024 Final Presentation Pending

Milestones set for the project

  1. Design Completion: All design-related activities completed by 28 May 2024.
  1. Manufacturing Completion: All manufacturing tasks completed by 23 May 2024.
  1. Assembly Completion: All assembly tasks completed by 23 May 2024.
  1. Electronics Completion: All electronics design and production completed by 31 May 2024.
  1. Testing Completion: All testing activities completed by 5 June 2024.
  1. Final Presentation: Final presentation prepared and delivered by 10 June 2024.

I have made KANBAN Board to visualize the progress

Design

First, i have to draw a concept sketch

this design was done in Fusion 360, on the second week as a part of the cad design this was just the concept inspired by an actual vehicle

System Integration

  1. Hardware Integration:
    • Chassis and Motors:
      The plotter is built on a circular chassis made from Acrylic Sheet. Three NEMA 17 stepper motors are mounted using custom brackets. Each motor drives an omni-wheel, allowing for precise movement in any direction.
    • Microcontroller and Driver Boards:
      An ESP 32 is used to control the plotter, interfacing with three motor Driver boards (one for each stepper motor). The driver boards manage the current supplied to the motors, ensuring smooth and precise motion.
    • Power Supply:
      The system is powered by a 12V power supply. Voltage regulation is handled by the driver boards and the Arduino’s onboard regulator to ensure the components receive the appropriate voltage and current.
  1. Software Integration:
    • G-Code Interpreter:
      The plotter features an onboard interpreter that recognizes G-code commands generated by software like Inkscape. This allows for easy conversion of designs into plotting instructions.
    • Bluetooth Communication:
      AnESP 32 module allows the plotter to receive commands wirelessly from a PC or a mobile device. This provides flexibility in controlling the plotter remotely.
    • Control Software:
      This software is used to send G-code files to the plotter, enabling it to execute complex drawing tasks.
  1. Mechanical Design:
    • Omni-Wheels and Motion:
      The three omni-wheels are crucial for the plotter’s movement, providing traction only in the direction of rotation. This unique design allows for smooth and precise movement in any direction on the plotting surface.

    Omni wheels only have traction in the direction of rotation.

    If three omni-wheels are arranged as shown in image then vertical upward motion is possible if

    • wheel W1 does not rotate,
    • wheel W2 rotates counter-clockwise, and
    • wheel W3 rotates in a clock-wise direction.

    Horizontal motion to the right is possible if

    • wheel W1 rotates counter-clockwise and
    • wheels W2 and W3 both rotate in a clock-wise direction

    The direction of travel may be changed by reversing the wheel rotations.

    “Bresenham’s Line Drawing Algorithm. which only requires horizontal and vertical motion, is used to draw curves, circles, and diagonal lines.

    The required wheel speeds for horizontal and vertical motion are summarized below:

    • for horizontal motion, wheel W1 must rotate twice as fast as wheels W2 and W3.
    • for vertical motion, since wheels W2 and W3 are angled, the image must be scaled sqrt(3) vertically if a square is to look like a square when plotted.

    • Pen Mechanism:
      An SG90 servo motor is used to control the pen mechanism, lifting and lowering the pen as needed to draw on the surface.

Features of the Machine

  • Compact Design:
    The plotter has a small footprint, making it suitable for use in limited spaces.
  • Large Drawing Area:
    Despite its compact size, the plotter can handle large drawings due to its Bluetooth design, which eliminates the need for physical connections that restrict movement.
  • High Resolution:
    The plotter achieves a horizontal resolution of 8.78 steps per mm, ensuring precise and detailed drawings.
  • Bluetooth Operation:
    The wireless design allows for remote control and operation, increasing convenience and flexibility.
  • Simple Construction:
    The design minimizes metalwork and only requires basic tools for assembly, making it accessible for hobbyists and DIY enthusiasts.

Design Parameters

  • Plotting Area: The effective plotting area is determined by the movement range of the omni-wheels and the length of the pen mechanism. The design should accommodate various paper sizes typically used for plotting.
  • Stepper Motor Specifications: The NEMA 17 stepper motors are chosen for their balance of torque and precision. The current and voltage settings are adjusted using the Big Easy Driver boards to match the motor specifications.
  • Servo Motor Range: The SG90 servo motor's range of motion is calibrated to ensure the pen can be lifted and lowered accurately without causing smudges or missed lines.
  • Power Supply Requirements: The 12V power supply should provide sufficient current to power all three stepper motors and the servo motor simultaneously, with consideration for peak power demands during operation.

I have re modified the design which i had drawn in week 2

Then i started converting the concept Sketch to Fusion , Started Drawing the baase frame

Then i have to draw the sketch for mounts

Later, I have exported the NEMA 17 and

Add side features

Draw the pen lift Mechanism using servo

Electronics Design

The plotter is driven by three NEMA 17 stepper motors, each controlled by a DRV8825 motor driver. The system is powered by a 12V supply, with the control logic managed by an ESP32 microcontroller. The following sections detail the components and their interconnections within the schematic.

Components and Connections

  1. Microcontroller (ESP32)
    The ESP32 microcontroller serves as the brain of the plotter. It interfaces with the motor drivers and controls the stepper motors' movements. The ESP32 is powered by a 3.3V supply and uses various GPIO pins for motor control signals (STEP, DIR, and ENABLE) for each motor driver.
  1. Power Supply
    The power supply section includes a 12V input that is regulated down to 5V and 3.3V using voltage regulators. The 12V supply powers the DRV8825 motor drivers, while the 3.3V supply powers the ESP32 and other logic components. Decoupling capacitors are placed near power supply pins to filter out noise and ensure stable operation.
  1. Motor Drivers (DRV8825)
    Three DRV8825 stepper motor drivers control the NEMA 17 motors.
  1. Connectors and Headers
    Multiple connectors and headers are used for interfacing with external components, including power inputs, motor connections, and additional peripherals. Headers are also provided for programming and debugging purposes.
  1. LEDs and Indicators
    LEDs with current-limiting resistors are included in the design to indicate the status of various signals and power lines. These LEDs help in troubleshooting and ensure that the system is functioning correctly.
  1. Capacitors and Resistors
    Decoupling capacitors are strategically placed near power supply pins to reduce noise. Pull-up and pull-down resistors are used where necessary to maintain stable logic levels on the control signals.

For motor W1, configure the DRV8825 for 8x micro-stepping by setting M0 and M1 to HIGH and M2 to LOW. For motors W2 and W3, set the DRV8825 to 16x micro-stepping by connecting M0, M1, and M2 to HIGH. The DRV8825 can accept an input voltage in the range of 8-45 volts, so use an 8-volt power supply for day-to-day use to minimize heat dissipation, and consider a LiPo battery for self-contained operation, as the current drain can approach 2A. Adjust each motor current to 600mA (0.6 amps) using the “current limit” potentiometers on the DRV8825 modules. To do this, turn off power to the driver, measure the VREF voltage with a multimeter, and adjust the potentiometer until VREF is 0.3V. Turn the power back on and verify the setting.

Then i moved on to tracing the paths

I generated the drill files and plot files from Kicad and used https://gerber2png.fablabkerala.in/ for generating png outputs for production.

BoM

After the design, I prepared the Bill of Materials and ordered the Omni wheels from Robu.in rest of the components were blocked in inventory.

Manufacturing

Body

In week15 i was used to cut my project main body in Zund . Refer the documentation of week15 for more details.

Motor Mounts

The motor mount is designed for NEMA 17 it can be directly mount on the body using M4 Bolts

Added to Prusa MK3+

Then i sourced the NEMA17 from FAB inventory and connected in motor Mounts

Top & Side Covers

I have used Laser cutting Machine in my FABLAB to cut logo and , side & top panels

Since i was already familier with CNC Week refer my documentation

Just for curiosity, I just assembled and checked the final look

Then I have pasted the logo of my project carefully

Pen Lift

I have already designed the penlift mechanism using sevo motor

I have 3D printed the parts for the pen lift mechanism

Electronics Production

So once i have completed the electronics design, i have scheduled the electronics production for the next day. So I have already become familiar with CNC milling of the PCB boards (refer to my documentation from Week 4 but I am super excited to produce the double-sided PCB .

Trace Path

Drill Paths

First, i traced the path of top layer

after tracing the top layer and drill holes i take out the pcb for next side milling

Paste the double side tape for bottom layer tracing

Placed the PCB properly on bottomside

then traced and cut the outer line

Finally i got my double Side PCB

Soldering

For soldering, i have sourced the components from Fab Inventory

After 4 hrs………

Testing the Board

Once i completed the soldering , ineed to test the PCB for its functionality ,

I screwed in two wires at the terminal and connected it to DC Power Supply.

Parameter values set on DC Power Supply
            Voltage: 12V
            Current: 0.6A 
          

Current Limiting Potentiometer

Before running the motor, we must limit the maximum current flowing through the stepper coils so that it does not exceed the motor’s rated current. This is done by tightenening or loosening the screw which actually is a current-limiting potentiometer. Here, I have set its voltage at around 0.6V.

Refer Last Minute Engineers to know about the two methods in which the adjustment can be done.

i have given the program for testing

// defines pins
          #define stepPin 10 
          #define dirPin 0 
          #define faultPin 8
          #define enablePin 9 
           
          void setup() {
            // Sets the pins as Outputs
            pinMode(stepPin,OUTPUT); 
            pinMode(dirPin,OUTPUT);
            pinMode(faultPin,OUTPUT); 
            pinMode(enablePin,OUTPUT);
          }
          void loop() {
            digitalWrite(dirPin,HIGH); // Enables the motor to move in a particular direction
            digitalWrite(enablePin,LOW); // DRV8825 driver is enabled when the pin is LOW
             digitalWrite(faultPin,HIGH); // If FAULT pin is LOW, chip is disabled
            // Makes 200 pulses for making one full cycle rotation
            for(int x = 0; x < 800; x++) {
              digitalWrite(stepPin,HIGH); 
              delayMicroseconds(700);    // by changing this time delay between the steps we can change the rotation speed
              digitalWrite(stepPin,LOW); 
              delayMicroseconds(700); 
            }
            delay(1000); // One second delay
            
            digitalWrite(dirPin,LOW); //Changes the rotations direction
            // Makes 400 pulses for making two full cycle rotation
            for(int x = 0; x < 1600; x++) {
              digitalWrite(stepPin,HIGH);
              delayMicroseconds(500);
              digitalWrite(stepPin,LOW);
              delayMicroseconds(500);
            }
            delay(1000);
          }

Testing video

I have also checked the penlift mechanism by servo example code in Arduiuo IDE

#include <Servo.h>
          
          Servo myservo;  // create servo object to control a servo
          // twelve servo objects can be created on most boards
          
          int pos = 0;    // variable to store the servo position
          
          void setup() {
            myservo.attach(32);  
          }
          
          void loop() {
            for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
              // in steps of 1 degree
              myservo.write(pos);              // tell servo to go to position in variable 'pos'
              delay(15);                       // waits 15 ms for the servo to reach the position
            }
            for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
              myservo.write(pos);              // tell servo to go to position in variable 'pos'
              delay(15);                       // waits 15 ms for the servo to reach the position
            }
          }

Testing Video

It was smoothly functioned

Assembly

So far, I have only assembled the body and omni-wheels after manufacturing, so by the time I got to the final assembly, I was quite experienced. For the final assembly, I used drill drivers and screwdrivers.You can see the partialassembled images above

Here is the detailed video

final assembled picture

Now its time to programming the board

Programming

For omni wheel mechanism I have referenced the internet for the movement mechanism- Read full article here

Abstract of the mechanism is given below

Horizontal motion

For horizontal motion to the right:

  • whee1 W1 must rotate counter clock-wise (CCW)
  • wheels W2 and W3 both rotate clock-wise (CW).
  • Wheel W1 must rotate twice as fast as wheels W2 and W3.

A wheel speed ratio of exactly 2 is possible using 16x and 8x micro-stepping.

A NEMA 17 motor with a 58mm diameter wheel (W1) and 8x micro-stepping equates to a horizontal resolution of 0.114mm per step or 8.78 steps per mm.

Vertical motion

For upward vertical motion:

  • wheel W1 does not rotate.
  • wheel W2 must rotate CCW
  • wheel W3 must rotate CW
  • wheels W2 and W3 must both rotate 1/sqrt(3)=0.5774 times for 1 unit of travel.

A wheel speed of 0.5774 is NOT possible using stepping motors ... a simple solution is to multiply all vertical dimensions by sqrt(3).

So based on this, my instructer Saheen helped me to reach to the full programme

We have used Platform.io for smoother compiling

#include <config.h>
          #include <ESP32Servo.h>
          #include <AccelStepper.h>
          #include <MultiStepper.h>
          #include <string.h>
          #include "BluetoothSerial.h"
          
          #define DEBUG
          
          // DEFINE GRBL SERIAL PORT
          BluetoothSerial SerialBT;
          
          // DEFINE STEPPER PINS
          AccelStepper stepper1(AccelStepper::DRIVER, MOTOR_1_STEP_PIN, MOTOR_1_DIRECTION_PIN);
          AccelStepper stepper2(AccelStepper::DRIVER, MOTOR_2_STEP_PIN, MOTOR_2_DIRECTION_PIN);
          AccelStepper stepper3(AccelStepper::DRIVER, MOTOR_3_STEP_PIN, MOTOR_3_DIRECTION_PIN);
          MultiStepper steppers;
          
          // initializing servo
          Servo penServo;
          
          #define MOTOR_1_MAX_SPEED 3000
          #define MOTOR_2_MAX_SPEED 3000
          #define MOTOR_3_MAX_SPEED 3000
          
          #define MOTOR_1_MAX_ACCELERATION 1000
          #define MOTOR_2_MAX_ACCELERATION 1000
          #define MOTOR_3_MAX_ACCELERATION 1000
          
          #define LINE_BUFFER_LENGTH 1024
          
          #define STEPPERS_DISABLED 1
          #define STEPPERS_ENABLED 0
          
          struct point
          {
            float x;
            float y;
            float z;
            int speed;
          };
          
          struct point actuatorPos;
          
          float StepInc = 1;
          int StepDelay = 0;
          int LineDelay = 50;
          
          // float StepsPerMillimeterX = 0.86;
          // float StepsPerMillimeterY = 0.5;
          
          float StepsPerMillimeterX = 86.0;
          float StepsPerMillimeterY = 50.0;
          
          float Xmin = 0;
          float Ymin = 0;
          
          float Xpos = Xmin;
          float Ypos = Ymin;
          
          
          
          boolean verbose = false;
          long positions[2];
          
          
          
          float xPosition = 0.0;
          float yPosition = 0.0;
          
          void mov(long x, long y)
          {
            // Convert desired position changes to scaled velocities
            float Vx = x * SCALING_FACTOR;
            float Vy = y * SCALING_FACTOR;
            // float Vz = z * SCALING_FACTOR;
          
            // Initialize velocities
            float v1 = 0;
            float v2 = 0;
            float v3 = 0;
          
            // Calculate wheel velocities for X direction (forward/backward)
            if (Vx != 0)
            {
              v2 = Vx / WHEEL_RADIUS;
              v3 = -Vx / WHEEL_RADIUS;
            }
          
            // Calculate wheel velocities for Y direction (sideways)
            if (Vy != 0)
            {
              v1 = 2 * Vy / WHEEL_RADIUS;
              v2 = Vy / WHEEL_RADIUS;
              v3 = Vy / WHEEL_RADIUS;
            }
          
            // Convert velocities to steps (using a time interval of 1 second for simplicity)
            positions[0] = v1 * STEPS_PER_REV / (2 * PI);
            positions[1] = v2 * STEPS_PER_REV / (2 * PI);
            positions[2] = v3 * STEPS_PER_REV / (2 * PI);
          
            steppers.moveTo(positions);
          
           
            steppers.runSpeedToPosition();
          
            stepper1.setCurrentPosition(0);
            stepper2.setCurrentPosition(0);
            stepper3.setCurrentPosition(0);
          }
          
          // void drawLine(float x1, float y1)
          // {
          //   float dx = x1 - xPosition;
          //   float dy = y1 - yPosition;
          
          // #ifdef DEBUG
          
          //   // Debugging output for target positions
          //   Serial.print("Target X: ");
          //   Serial.println(x1);
          //   Serial.print("Target Y: ");
          //   Serial.println(y1);
          
          //   // Debugging output for relative movements
          //   Serial.print("Move X by: ");
          //   Serial.println(dx);
          //   Serial.print("Move Y by: ");
          //   Serial.println(dy);
          // #endif
          
          //   // Update current positions based on movement
          //   xPosition = x1;
          //   yPosition = y1;
          
          // #ifdef DEBUG
          
          //   // Debugging output for new positions
          //   Serial.print("xPosition: ");
          //   Serial.println(xPosition);
          //   Serial.print("yPosition: ");
          //   Serial.println(yPosition);
          // #endif
          
          //   mov(dx, dy); // Call the actual move function with relative distances
          // }
          
          void drawLine(float x1, float y1) {
          
            if (verbose)
            {
              Serial.print("fx1, fy1: ");
              Serial.print(x1);
              Serial.print(",");
              Serial.print(y1);
              Serial.println("");
            }  
          
            
          
            if (verbose)
            {
              Serial.print("Xpos, Ypos: ");
              Serial.print(Xpos);
              Serial.print(",");
              Serial.print(Ypos);
              Serial.println("");
            }
          
            if (verbose)
            {
              Serial.print("x1, y1: ");
              Serial.print(x1);
              Serial.print(",");
              Serial.print(y1);
              Serial.println("");
            }
          
            //  Convert coordinates to steps
            x1 = (int)(x1*StepsPerMillimeterX);
            y1 = (int)(y1*StepsPerMillimeterY);
            float x0 = Xpos;
            float y0 = Ypos;
          
            //  Let's find out the change for the coordinates
            long dx = abs(x1-x0);
            long dy = abs(y1-y0);
            int sx = x0<x1 ? StepInc : -StepInc;
            int sy = y0<y1 ? StepInc : -StepInc;
          
            long i;
            long over = 0;
          
            if (dx > dy) {
              for (i=0; i<dx; ++i) {
                // myStepperX.step(sx);
                mov(sx, 0);
                over+=dy;
                if (over>=dx) {
                  over-=dx;
                  // myStepperY.step(sy);
                  mov(0, sy);
                }
                delay(StepDelay);
              }
            }
            else {
              for (i=0; i<dy; ++i) {
                // myStepperY.step(sy);
                mov(0, sy);
                over+=dx;
                if (over>=dy) {
                  over-=dy;
                  // myStepperX.step(sx);
                  mov(sx, 0);
                }
                delay(StepDelay);
              }    
            }
          
            if (verbose)
            {
              Serial.print("dx, dy:");
              Serial.print(dx);
              Serial.print(",");
              Serial.print(dy);
              Serial.println("");
            }
          
            if (verbose)
            {
              Serial.print("Going to (");
              Serial.print(x0);
              Serial.print(",");
              Serial.print(y0);
              Serial.println(")");
            }
          
            
            delay(LineDelay);
            
            Xpos = x1;
            Ypos = y1;
          }
          
          void processIncomingLine(char *line, int charNB)
          {
            int currentIndex = 0;
            char buffer[64];
            struct point newPos;
          
            newPos.x = 0.0;
            newPos.y = 0.0;
            newPos.z = 0.0;
            newPos.speed = 0;
          
            int G_command = 0;
          
            char *indexX;
            char *indexY;
            char *indexZ;
            char *indexSpeed;
          
            while (currentIndex < charNB)
            {
              switch (line[currentIndex++])
              {
              case 'G':
                buffer[0] = line[currentIndex++];
                buffer[1] = line[currentIndex++];
                buffer[2] = '\0';
                G_command = atoi(buffer);
                switch (atoi(buffer))
                {
                case 00:
                  // Serial.println(atoi(buffer));
                case 01:
                  // Serial.println("G01");
                  Serial.println('Function :: ');
                  indexX = strchr(line + currentIndex++, 'X');
                  indexY = strchr(line + currentIndex++, 'Y');
                  indexZ = strchr(line + currentIndex++, 'Z');
                  indexSpeed = strchr(line + currentIndex++, 'F');
          
                  if (indexSpeed > 0)
                  {
                    newPos.speed = atof(indexSpeed + 1);
                  }
          
                  if (G_command == 1)
                  {
                    Serial.print("Speed :: ");
                    Serial.println(newPos.speed);
                    stepper1.setMaxSpeed(newPos.speed);
                    stepper2.setMaxSpeed(newPos.speed);
                    stepper3.setMaxSpeed((newPos.speed) / 2);
                  }
                  else if (G_command == 0)
                  {
          
                    stepper1.setMaxSpeed(MOTOR_1_MAX_SPEED);
                    stepper2.setMaxSpeed(MOTOR_2_MAX_SPEED);
                    stepper3.setMaxSpeed(MOTOR_3_MAX_SPEED);
                  }
          
                  if (indexY <= 0 && indexZ <= 0)
                  { // If Y and Z are missing
                    newPos.y = actuatorPos.y;
                    newPos.z = actuatorPos.z;
                    newPos.x = atof(indexX + 1);
                  }
                  else if (indexX <= 0 && indexZ <= 0)
                  { // If X and Z are missing
                    newPos.x = actuatorPos.x;
                    newPos.z = actuatorPos.z;
                    newPos.y = atof(indexY + 1);
                  }
                  else if (indexX <= 0 && indexY <= 0)
                  { // If X and Y are missing
                    newPos.x = actuatorPos.x;
                    newPos.y = actuatorPos.y;
                    newPos.z = atof(indexZ + 1);
                  }
                  else if (indexZ <= 0)
                  { // If Z is missing
                    newPos.x = atof(indexX + 1);
                    newPos.y = atof(indexY + 1);
                    newPos.z = actuatorPos.z;
                  }
                  else if (indexY <= 0)
                  { // If Y is missing
                    newPos.x = atof(indexX + 1);
                    newPos.z = atof(indexZ + 1);
                    newPos.y = actuatorPos.y;
                  }
                  else if (indexX <= 0)
                  { // If X is missing
                    newPos.y = atof(indexY + 1);
                    newPos.z = atof(indexZ + 1);
                    newPos.x = actuatorPos.x;
                  }
                  else
                  { // All coordinates are present
                    newPos.x = atof(indexX + 1);
                    newPos.y = atof(indexY + 1);
                    newPos.z = atof(indexZ + 1);
                  }
          
                  drawLine(newPos.x, newPos.y);
                  actuatorPos.x = newPos.x;
                  actuatorPos.y = newPos.y;
                  actuatorPos.z = newPos.z;
                  break;
          
                case 28:
                  Ypos = 0.0;
                  Xpos = 0.0;
                  xPosition = 0.0;
                  yPosition = 0.0;
                  SerialBT.println("Home Position Set X = 0.0 Y = 0.0");
                  // home();
                  break;
                default:
                  SerialBT.println("Unknown command");
                  break;
                }
                break;
              case 'M':
                buffer[0] = line[currentIndex++];
                buffer[1] = line[currentIndex++];
                buffer[2] = '\0';
                switch (atoi(buffer))
                {
                case 03:
                {
                  char *indexS = strchr(line + currentIndex++, 'S');
                  int servoAngle = atoi(indexS + 1);
                  if (servoAngle <= 180 && servoAngle >= 0)
                  {
                    penServo.write(servoAngle);
                    delay(15);
          #ifdef DEBUG
                    Serial.println(servoAngle);
          #endif
                  }
                }
                break;
          
                default:
                  SerialBT.print("Command not recognized : M");
                  SerialBT.println(buffer);
                  break;
                }
                break;
              default:
                SerialBT.print("Unknown command : ");
                SerialBT.println(buffer);
                break;
              }
            }
          }
          
          void processCommands()
          {
          
            delay(200);
            char line[LINE_BUFFER_LENGTH];
            char c;
            int lineIndex;
            bool lineIsComment, lineSemiColon;
          
            lineIndex = 0;
            lineSemiColon = false;
            lineIsComment = false;
          
            while (1)
            {
              while (SerialBT.available() > 0)
              {
                c = SerialBT.read();
                if ((c == '\n') || (c == '\r'))
                {
                  if (lineIndex > 0)
                  {
                    line[lineIndex] = '\0';
                    if (verbose)
                    {
                      SerialBT.print("Received : ");
                      SerialBT.println(line);
                    }
                    if (strcmp(line, "G28") == 0)
                    {
                      // home();
                      Xpos = 0.0;
                      Ypos = 0.0;
                      xPosition = 0.0;
                      yPosition = 0.0;
                      SerialBT.println("Home Position Set X = 0.0 Y = 0.0");
                    }
                    else
                    {
                      processIncomingLine(line, lineIndex);
                    }
                    lineIndex = 0;
                  }
                  else
                  {
                  }
                  lineIsComment = false;
                  lineSemiColon = false;
                  SerialBT.println("OK");
                }
                else
                {
                  if ((lineIsComment) || (lineSemiColon))
                  {
                    if (c == ')')
                      lineIsComment = false;
                  }
                  else
                  {
                    if (c <= ' ')
                    {
                    }
                    else if (c == '/')
                    {
                    }
                    else if (c == '(')
                    {
                      lineIsComment = true;
                    }
                    else if (c == ';')
                    {
                      lineSemiColon = true;
                    }
                    else if (lineIndex >= LINE_BUFFER_LENGTH - 1)
                    {
                      Serial.println("ERROR - lineBuffer overflow");
                      lineIsComment = false;
                      lineSemiColon = false;
                    }
                    else if (c >= 'a' && c <= 'z')
                    {
                      line[lineIndex++] = c - 'a' + 'A';
                    }
                    else
                    {
                      line[lineIndex++] = c;
                    }
                  }
                }
              }
            }
          }
          
          void setup()
          {
            Serial.begin(115200);
            SerialBT.begin(MACHINE_NAME);
          
            pinMode(STEPPERS_DISABLE_PIN, OUTPUT);
            pinMode(STATUS_LED_PIN, OUTPUT);
          
            penServo.attach(SERVO_PIN);
            delay(15); // wait for 15 ms
          
            penServo.write(50);
            delay(15); // wait for 15 ms
          
          
            // Configure each stepper
            stepper1.setMaxSpeed(MOTOR_1_MAX_SPEED);
            stepper1.setAcceleration(MOTOR_1_MAX_ACCELERATION);
            stepper1.setCurrentPosition(0);
            stepper2.setMaxSpeed(MOTOR_2_MAX_SPEED);
            stepper2.setAcceleration(MOTOR_2_MAX_ACCELERATION);
            stepper2.setCurrentPosition(0);
            stepper3.setMaxSpeed(MOTOR_3_MAX_SPEED);
            stepper3.setAcceleration(MOTOR_3_MAX_ACCELERATION);
            stepper3.setCurrentPosition(0);
            steppers.addStepper(stepper1);
            steppers.addStepper(stepper2);
            steppers.addStepper(stepper3);
          
            Serial.println(" Poombata is Ready pair with bluetooth");
            // Serial.print("X range is from ");
            // Serial.print(Xmin);
            // Serial.print(" to ");
            // Serial.print(Xmax);
            // Serial.println(" mm.");
            // Serial.print("Y range is from ");
            // Serial.print(Ymin);
            // Serial.print(" to ");
            // Serial.print(Ymax);
            // Serial.println(" mm.");
            // Serial.print("Z range is from ");
            // Serial.print(Zmin);
            // Serial.print(" to ");
            // Serial.print(Zmax);
            // Serial.println(" mm.");
          
            digitalWrite(STEPPERS_DISABLE_PIN, STEPPERS_ENABLED);
          }
          
          void loop()
          {
          
            processCommands();
          }

It uses bluetooth communication with the board using webserial .

Testing of the code with Board

So once the program is sent to the board, we test the movements

Horzontal and vertical Movements

Circular Interpolation

Infinity Plotter Interface

The Infinity Plotter is a Frontend Application, developed using the Next.js framework. The application facilitates seamless communication with connected CNC (Computer Numerical Control) machines through the WebSerial API. This interface aims to offer a user-friendly experience for monitoring and controlling CNC operations directly from a web browser.

Our developer, Midhlaj helped me to build this.

Real-time Communication

Enables direct and efficient communication with CNC machines using the WebSerial API.

User-friendly Interface

Designed with a clean and intuitive interface to ensure ease of use for operators.

Cross-Platform Accessibility

Being a web application, it can be accessed from any device with a web browser, providing flexibility and convenience.

Next.js Framework

Utilizes the powerful features of Next.js, including server-side rendering and static site generation, to ensure optimal performance and SEO.

Technical Details

Framework

The frontend application is built using the Next.js framework. Next.js is a popular React framework that offers several benefits, including:

  • Server-Side Rendering (SSR): Improves performance by rendering pages on the server.
  • Static Site Generation (SSG): Allows pre-rendering of pages at build time, which enhances load times and SEO.
  • API Routes: Simplifies the creation of backend APIs within the same project.

WebSerial API

The WebSerial API is a modern browser API that provides direct access to serial ports. This is crucial for enabling real-time communication between the web application and CNC machines. Key capabilities include:

  • Port Access: Open and close connections to serial ports.
  • Data Transfer: Send and receive data to/from the CNC machine.
  • Event Handling: Handle serial port events to manage data streams and connection states.

Communication Workflow

  • Port Connection: The user selects the appropriate serial port connected to the CNC machine.
  • Data Exchange: The application sends commands to and receives responses from the CNC machine via the WebSerial API.
  • Real-time Monitoring: The interface updates in real-time based on the data received from the CNC machine, allowing users to monitor operations seamlessly.

FInal Result

So my work is almost complete, and tested various patterns by the G Code sender

Here is some videos

It is drawing infinite planes

me with my പൂമ്പാറ്റ……

Final Video

Downloads

Fab Academy by Basil Abraham is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International