Skip to content

Machine Building Project

This is the documentation page of Machine Building activity by Ahmad Tijjani Ishaq and Muhammad Jidda.

As for our individual Contribution it can be found here Jidda and Ahmed

Slide

Image 1

Presentaion Video

Group Assignment Overview

This is the group assignment of the week.

  - Design a machine that includes mechanism+actuation+automation+application;     
  - Build the mechanical parts and operate it manually;                         
  - Document the group project and your individual contribution;

  - Actuate and automate your machine;
  - Document the group project and your individual contribution

MACHINE

Machines are mechanical devices designed to perform specific tasks by converting energy from one form to another. They are integral to human civilization and play a crucial role in various aspects of our daily lives, from simple tools to complex industrial equipment.

For our activity, We decided to make a pen plotter using CoreXY systems architecture.

Overview

CoreXY is a kinematic arrangement commonly used in the design of Computer Numerical Control (CNC) machines. It offers a mechanism for precise control of movement along two axes (X and Y) using a system of belts and pulleys. CoreXY provides advantages such as reduced moving mass, increased work speed, and improved work quality compared to other motion systems.

Image 1

Image 2

Building Mechanical part

The mechanical frame or body has to be in place before any automation can take place, hence we follow the following steps to make our mechanism.

Obtaining Components

Having had the design concept in mind, we started by obtaining the materials required by following the tempalte laid in the following reference to coreXY.

Some parts are purchased while others were made locally in the lab as some of them are 3D printed parts while some are acrylic materials.

The following parts were purchased. Credit to Koji Yamada/ Hajime Ito For documenting as shown below.

(1) Frame

SN Item Details Qty Remarks
1 2020Aluminum Extrusion(Y) ex.400mm 2P
2 2020Aluminum Extrusion(X) ex.300mm 2P 3mm Acrylic spacer will be added
3 2020Aluminum Extrusion(X) ex.300mm 1P
4 Delta Socket 4P
5 Socket Head Screws M5x8mm 8P
6 T-Slot M5 8P
7 Non-stretch fishing line

(2) Y-axis Pulley *2 units required for both sides.

SN Item Details Qty Remarks
8 Socket Head Screws M5x30mm 1P Inner wheels
9 V-slot Wheel 1P Inner wheels
10 Spring Washer M5 1P Inner wheels
11 Washer M5 1P Inner wheels
12 Nut M5 1P Inner wheels
13 Socket Head Screws M5x30mm 1P Outer wheels
14 V-Slot Wheel 1P Outer wheels
15 Spring Washer M5 1P Outer wheels
16 Acrylic Spacer 5mm 1P Outer wheels
17 Washer M5 1P Outer wheels
18 Nut M5 1P Outer wheels
19 Socket Head Screws M5x8mm 2P
20 T-Slot M5 2P

(3) Y-axis Carriage *2 units required for both sides.

SN Item Details Qty Remarks
21 Socket Head Screws M5x40mm 1P Inner wheels
22 V-Slot Wheel 1P Inner wheels
23 Spring Washer M5 1P Inner wheels
24 V-Slot Wheel 1P Inner wheels
25 Spring Washer M5 1P Inner wheels
26 Nut M5 1P Inner wheels
27 Socket Head Screws M5x30mm 1P Outer wheels
28 V-Slot Wheel 1P Outer wheels
29 Nut M5 1P Outer wheels
30 Socket Head Screws M5x8mm 2P
31 T-Slot M5 2P

(4) Y-axis Motor *2 units required for both sides.

SN Item Details Qty Remarks
32 Stepper Motor NEMA17 17HS4401 1.5A 42x42x38mm 1P Motor
33 Socket Head Screws M3x8mm 4P Motor
34 Socket Head Screws M5x30mm 1P Pulley
35 Bearing D16xd5xH5 2P Pulley
36 Spring Washer M5 1P Pulley
37 Washer M5 1P Pulley
38 Spring Washer M5 1P Pulley
39 Nut M5 1P Pulley
40 Socket Head Screws M5x8mm 2P
41 T-Slot M5 2P

(5) X-axis Carriage

SN Item Details Qty Remarks
42 Socket Head Screws M5x30mm 4P
43 V-Slot Wheel 4P
44 Nut M5 1P
45 Socket Head Screws M3x15mm 2P Non-stretch fishing line holder
46 Washer M3 2P ditto.
47 Nut M3 2P ditto.

(6) Limit Switch *2 units required for both X and Y axes.

SN Item Details Qty Remarks
48 Limit Switch 1P
49 Screw M2x12mm 2P
50 Nut M2 2P
51 Socket Head Screws M5x8mm 1P
52 T-Slot M5 1P

locally made materials

Some 3D printings were made as well as laser cutting.

Image 3

Image 4

Image 5

SN Item Image Purpose Data QTY
53 Capstan Motor alt text For stepper motor STL 2P
54 Capstan Pulley alt text For stepper motor STL 2P
55 Stud 4pcs alt text For rolling pulley smoothly STL 5P
56 X-axis Carriage alt text For mounting X-carriage STL 2P
57 X-axis Carriage alt text For holding strings STL 1P
58 Y-axis Pulley alt text For mounting pulleys on Y-axis STL 2P
59 Y-axis Carriage alt text For mounting Y-carriage STL 2P
60 Y-axis Motor alt text For mounting stepper motor STL 2P

Assembly of parts

Parts obtained were assembled according to CoreXY systems architecture..

Image 6

Image 7

Image 8

Image 9

Image 10

Image 11

Image 12

Image 13

Image 14

The frame is set and movements are tested. The coreXY mechanism is now set for use as base of our pen plotter.

Automation

To complete our machine building, we did the following.

  • Build the pen holder.
  • mill the electronic circuits board.
  • Program the system.

Building the pen holder

Pen Holder

The pen holder is primarilly our payload but we hope to add more payload to the coreXY device. We got the stl and laser cut part of the pen holder sytem from Nntuan Thigivers pen plotter files and the stl file can be accessed here

The penholder uses a servo motor to move the plotter hesd up and down. In addition to pen holder we mounted the limit switch at their respective possitions.

Image 15

Image 16

Milling The electronics board

The boards were milled, two similar for driving stepper and another one for driving the servo motor in the penholder.

Image 17

Image 18

Image 19

indepth on how to mill the board can be found in our electronics production page.

we got the PNG files for stepper motor board design from coreXY reference page. and that of servo from the servo reference

Bill of material for milling the stepper board is as follows:

Part Count Info
Xiao RP2040 1
H-Bridge TB67H451FNG 2
0.1uF 1206 2
1uF 1206 2
10uF 1206 2
0.25R 1206 2
120R 1206 2
1x7 SMD Vertical Pinsocket 2
S4B-XH-SM4-TB or 1x4 SMD Pinheader 1
1x2 SMD Pinheader 1

Bill of material for milling the servo board is as follows:

Part Count Info
Xiao RP2040 1
1k smd res 1
10k smd res 1
1x7 SMD Vertical Pinsocket 2
S4B-XH-SM4-TB or 1x4 SMD Pinheader 1
1x3 SMD Pinheader 1
Light emitting diode smd 1
schottky diode smd CDBM1100-G 1
Mosfet 1
1x2 header for 12v power 1

Additional Parts Needed before programming are: - USB 3.0 for multiple USB ports - USB type C cable for connection to PC

Programming the system.

The last step for our machine is the coding aspect. To proceed with this we did the following.

Image 20

Image 21

Image 22

Web Interface Implementation

We want the plotter to work with a canvas so that anything that is drawn on the canvas can be plotter by the machine. other features add is the ability to draw shapes like circle, square and star easily by clicking on the shape.

Sketch

Image 23

Result We have deploy the modular-thing project locally and made some modification of the interface Image 24

Code

    //https://fabacademy.org/2024/labs/kannai/Instruction/tips/machine_building/

    // Array of [x,y] positions of drawing design
    //Square
    var ptsSquare = [[50,0],[50,50],[0,50],[0,0]];

    //Star
    var ptsStar = [[20,10],[30,50],[40,10],[10,40],[50,40],[20,10]];

    //new code for circle

    var centerX = 0; // X-coordinate of the center of the circle
    var centerY = 0; // Y-coordinate of the center of the circle
    var radius = 30; // Radius of the circle
    var numPoints = 50; // Number of points to approximate the circle

    var ptsCircle = [];

    for (var i = 0; i < numPoints; i++) {
        var angle = (i / numPoints) * 2 * Math.PI;
        var x = centerX + radius * Math.cos(angle);
        var y = centerY + radius * Math.sin(angle);
        ptsCircle.push([x, y]);
    }

    // svg converter to point

      var pathData = "M 20,10 L 30,50 L 40,10 L 10,40 L 50,40 Z"; // Path data from the SVG path
      var pts = [];

      // Regular expression to match commands (M, L, etc.) and numbers
      var regex = /([MLHVCSQTAZmlhvcsqtaz])\s*(-?\d*\.?\d+)(?:\s*,\s*(-?\d*\.?\d+))?/g;

      var match;
      while (match = regex.exec(pathData)) {
        var command = match[1];
        var x = parseFloat(match[2]);
        var y = parseFloat(match[3]);

        switch (command) {
          case 'M': // Move to
          case 'L': // Line to
            pts.push([x, y]);
            break;
          // Handle other commands as needed (e.g., curve commands)
        }
      }

      console.log(pts);


    // UI in View tab
    var el = document.createElement("div");

    el.style = `
      padding: 10px; 
    `;

    el.innerHTML = `<center>
    <h2><font color="#5B9BAF">FabAcademy2024 - Machine Building</font></h2>
    <img src="https://fabacademy.org/2024/labs/kannai/images/logo2022-yoko-w_transp.png" alt="FabLab Kannai" width="200">
    <h3><font color="#5B9BAF">Pen Plotter Machine Interface</font></h3>

    <p></p>
        <hr>
        <table>
            <tbody>
                <tr>
                    <td></td>
                    <td><button id="yPlus"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-up-fill" viewBox="0 0 16 16">
                        <path d="m7.247 4.86-4.796 5.481c-.566.647-.106 1.659.753 1.659h9.592a1 1 0 0 0 .753-1.659l-4.796-5.48a1 1 0 0 0-1.506 0z"/>
                      </svg><br /> Y+ </button></td>
                    <td></td>
                    <td>&nbsp;&nbsp;&nbsp;&nbsp;</td><!-- space in 3rd column-->
                    <td><button  id="zUp"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-up-fill" viewBox="0 0 16 16">
                        <path d="m7.247 4.86-4.796 5.481c-.566.647-.106 1.659.753 1.659h9.592a1 1 0 0 0 .753-1.659l-4.796-5.48a1 1 0 0 0-1.506 0z"/>
                      </svg><br />Z+ </button></td>
                </tr>
                <tr>
                    <td><button id="xMinus"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-left-fill" viewBox="0 0 16 16">
                        <path d="m3.86 8.753 5.482 4.796c.646.566 1.658.106 1.658-.753V3.204a1 1 0 0 0-1.659-.753l-5.48 4.796a1 1 0 0 0 0 1.506z"/>
                      </svg> X- </button></td>
                    <td><button id="Home"  style="border: none; background: none; cursor: pointer;"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-house" viewBox="0 0 16 16">
                        <path d="M8.707 1.5a1 1 0 0 0-1.414 0L.646 8.146a.5.5 0 0 0 .708.708L2 8.207V13.5A1.5 1.5 0 0 0 3.5 15h9a1.5 1.5 0 0 0 1.5-1.5V8.207l.646.647a.5.5 0 0 0 .708-.708L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293zM13 7.207V13.5a.5.5 0 0 1-.5.5h-9a.5.5 0 0 1-.5-.5V7.207l5-5z"/>
                      </svg></button></td>
                    <td><button id="xPlus"> X+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-right-fill" viewBox="0 0 16 16">
                        <path d="m12.14 8.753-5.482 4.796c-.646.566-1.658.106-1.658-.753V3.204a1 1 0 0 1 1.659-.753l5.48 4.796a1 1 0 0 1 0 1.506z"/>
                      </svg> </button></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td><button id="yMinus">Y- <br /><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-down-fill" viewBox="0 0 16 16">
                        <path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z"/>
                      </svg></button></td>
                    <td></td>
                    <td></td>
                    <td><button id="zDown"> Z- <br /><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-caret-down-fill" viewBox="0 0 16 16">
                        <path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z"/>
                      </svg> </button></td>

                </tr>

            </tbody>
        </table>
        <hr>
        <p><b>Draw Shapes</b></p>
        <button style="border: none; background: none; cursor: pointer;" id="DrawCircle"><p></p><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-circle" viewBox="0 0 16 16">
            <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
          </svg></button>
          <button style="border: none; background: none; cursor: pointer;" id="DrawSquare"> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-square" viewBox="0 0 16 16">
            <path d="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/>
          </svg></button>

          <button style="border: none; background: none; cursor: pointer;" id="DrawStar"> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-star" viewBox="0 0 16 16">
            <path d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256 4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73 3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356-.83 4.73zm4.905-2.767-3.686 1.894.694-3.957a.56.56 0 0 0-.163-.505L1.71 6.745l4.052-.576a.53.53 0 0 0 .393-.288L8 2.223l1.847 3.658a.53.53 0 0 0 .393.288l4.052.575-2.906 2.77a.56.56 0 0 0-.163.506l.694 3.957-3.686-1.894a.5.5 0 0 0-.461 0z"/>
          </svg></button>
          <br/>
          <p></p>
        <canvas style="border: 1px solid black;" id="drawingCanvas" width="100" height="100"></canvas><br>
    <button id="convertBtn">Start Drawing</button>
    <button id="resetBtn">Reset</button>
    <pre id="pointsDisplay"></pre>
    `;

    //pen up initially
    zUp();

    //Synchronizer of two motors
    var machine = createSynchronizer([motorA, motorB]);

    //Definition of CoreXY Motion 
    async function goTo(x,y){
      console.log(`Moving to (${x}, ${y})`);
      await machine.absolute([1*(x+y),1*(x-y)]); 
    }

    // Set button ID and click_event
    el
      .querySelector("#xPlus")
      .addEventListener("click", () => {
        xPlus();
      })

    el
      .querySelector("#xMinus")
      .addEventListener("click", () => {
        xMinus();
      })

    el
      .querySelector("#yPlus")
      .addEventListener("click", () => {
        yPlus();
      })

    el
      .querySelector("#yMinus")
      .addEventListener("click", () => {
        yMinus();
      })

    el
      .querySelector("#zUp")
      .addEventListener("click", () => {
        zUp();
      })

    el
      .querySelector("#zDown")
      .addEventListener("click", () => {
        zDown();
      })


    el
      .querySelector("#Home")
      .addEventListener("click", () => {
        goToHome();
      })

    el
      .querySelector("#DrawCircle")
      .addEventListener("click", () => {
        delay(100);
        drawCircle();
      })

    el
      .querySelector("#DrawSquare")
      .addEventListener("click", () => {
        delay(100);
        drawSquare();
      })

    el
      .querySelector("#DrawStar")
      .addEventListener("click", () => {
        delay(100);
        drawStar();
      })

    // canvas
    const canvas = el.querySelector('#drawingCanvas');
      const ctx = canvas.getContext('2d');
      const convertBtn = el.querySelector('#convertBtn');
      const resetBtn = el.querySelector('#resetBtn');
      const pointsDisplay = el.querySelector('#pointsDisplay');
      let points = [];

      // Function to draw on canvas
      function draw(event) {
        var rect = canvas.getBoundingClientRect();
        var x = Math.round(event.clientX - rect.left);
        var y = Math.round(event.clientY - rect.top);

        points.push([x, y]);

        ctx.lineTo(x, y);
        ctx.stroke();
      }

      // Function to clear the canvas
      function resetCanvas() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        points = [];
        pointsDisplay.textContent = '';
      }

      // Function to convert drawing to points
      function convertToPoints() {
        // pointsDisplay.textContent = JSON.stringify(points);


        drawObj();
      }

      // Event listeners
      canvas.addEventListener('mousedown', (event) => {
        var rect = canvas.getBoundingClientRect();
        var x = Math.round(event.clientX - rect.left);
        var y = Math.round(event.clientY - rect.top);

        ctx.beginPath();
        ctx.moveTo(x, y);
        canvas.addEventListener('mousemove', draw);
      });

      canvas.addEventListener('mouseup', () => {
        canvas.removeEventListener('mousemove', draw);
      });

      convertBtn.addEventListener('click', convertToPoints);
      resetBtn.addEventListener('click', resetCanvas);

    render(el);

    // document.addEventListener('DOMContentLoaded', () => {

    // });

    // When you start running this javascript code, the machine runs from here

    //motor setting
    motorA.setCurrent(1);
    motorA.setStepsPerUnit(5);
    motorB.setCurrent(1);
    motorB.setStepsPerUnit(5);
    machine.setPosition([0, 0]);// set present position as (X0,Y0)
    //machine.setPosition(0, 0);// CHECK this syntax works or not

    //var isAtEndStopX = false;
    //console.log(isAtEndStopX);

    // Function definition
    async function goToHome(){
      while(await motorB.getLimitState()){ // Limit switch at X- as Normally-Open
        motorA.velocity(10);//move motorA CW
        motorB.velocity(10); //move motorB CW
      }
      while(await motorA.getLimitState()){ //  Limit switch at Y- as Normally-Open
        motorA.velocity(10); //positive value means CW
        motorB.velocity(-10);//negative value means CCW
      }
      motorA.velocity(0);
      motorB.velocity(0);
      machine.setPosition([0, 0]);
      await delay(1000);
      goTo(10,10 );
      machine.setPosition([0, 0]);
      await delay(1000);
    }//end of goToHome



    function xPlus() {
        zUp();
        machine.setPosition([0, 0]);
        for ( i = 0; i<10; i++){
        goTo(i,0 );     
        }  
    }

    function xMinus() {
        zUp();
        machine.setPosition([0, 0]);
        for ( i = 0; i<10; i++){
        goTo(-i,0 );
      }
    }

    function yPlus() {
        zUp();
        machine.setPosition([0, 0]);
        for ( i = 0; i<10; i++){
        goTo(0,i );
      }
    }

    function yMinus() {
        zUp();
        machine.setPosition([0, 0]);
        for ( i = 0; i<10; i++){
        goTo(0,-i );
      }
    }

    function zUp() {
      // Code for the function goes here
      console.log(servo.writeAngle(70));
    }

    function zDown() {
      console.log(servo.writeAngle(90));
    }

    // new code
    async function drawCircle(){
    // await goTo(ptsCircle[0][0], ptsCircle[0][1]);
      zDown();
      for (let i = 0; i < ptsCircle.length; i++){
        await goTo(ptsCircle[i][0], ptsCircle[i][1]);
        await delay(200);  
      }
      zUp();
    }

    async function drawSquare(){
      //await goTo(ptsSquare[0][0], ptsSquare[0][1]);
      zDown();
      for (let i = 0; i < ptsSquare.length; i++){
        await goTo(ptsSquare[i][0], ptsSquare[i][1]);
        await delay(200);  
      }
      zUp();
    }


    async function drawStar(){
      // await goTo(points[0][0], points[0][1]);
      zDown();
      for (let i = 0; i < ptsStar.length; i++){
        await goTo(ptsStar[i][0], ptsStar[i][1]);
        await delay(200);  
      }
      zUp();
    }

    async function drawObj(){
      await goTo(points[0][0], points[0][1]);
      zDown();
      for (let i = 0; i < points.length; i++){
        await goTo(points[i][0], points[i][1]);
        await delay(200);  
      }
      zUp();
    }

Last update: June 26, 2024