Mechanical Design, Machine Design

make machine in group


Intro.

Hey! welcome to machine week. This week me and my fablab group will work together to make working machine. We dont have Individual assignment but Individual job to do here according to our skill set.

Week Task:

group assignment
- design a machine that includes mechanism+actuation+automation
- build the mechanical parts and operate it manually
- document the group project and your individual contribution


Firmware,Interface and comminucation

Machines are not just mechanical parts of something. It is combination of electronic, software and everthing that make it work

In group project I am looking after Software part like firmware, Interface and comminucation protocol.

we plan to build CNC sketching Car we named it कलाCar (कला mean Art). Since most of CNC machines like 3D printer, lasercutter ,vinyl cutter etc are limiter to it bed sizes. This also make them huge in overall size. So we plan to make CNC bot to be free from bed size so it can draw on any size canvas. Sketching Car is fun but real motive is came after knowing it vash application even in farming. But lets not to complicated things now


Structure and electronics:

KalaCar is two wheel sketching robot. Two wheel are drive using nema 17 stepper motors. Wheel parts designing and developing was done by Anand Tale

It draw with a marker on reponse at Z axis. It work on servo motor and design for Z axis mechanism was Done by pavan kuchar

It work using Arduino mega. For driving different output devices like stepper motors and servo We have used RAMPS sheild for Mega. We added battery pack to make our project completely wireless it communicate through bluetooth This Job was Detail by Vijay Karale .

Since everyone of us was new in this kind of work so it not that they only done all that jobs all alone each one of us helping and sharing his expertise.

Mohit ahuja took responsility to combining all part and supporting people on troubleshooting.

Fab X student Pradeep Kumar was young member of group supported everyone in work and provided all help needed

we have two week to complete this project so first week spent on structure and on all assembly so remaining one week was my responsility to perpare firmware and interface

Blender Script and Python

Blender is OpenSource 3D modeling and animation Software. Mostly like many other Softwares Blender can be Control and Program via text and that called Script. Blender Script is in Python Language so possibility of experimenting is huge

We agreed to use blender for our interface part. Blender is well developed application hence perfect for our use.

So this is not the first code I started with but code I made after some failed experiments. Some maybe not true you can say many that I missed to document each thing because I was too much busy with writing and solving logic on code.

Since whatever I have done to come this much far have worth it

So first let me share some chanllenges and useful finding before moving on codes

After some long study and experiment I observe that when normal script or python code runs through blender It freeze the whole interface until background script get his job done else if code is loop in nature it keep running and UI stay freeze and In that case you need to terminate whole blender Program

I have use timing event which trigger function having a code to move timeframe one step ahead on every interval of time until it complete the total number of frames.

There is 3d object in viewport that can animated manually or by attaching it with path with respect to timeline.

On each frame object move or change it positions because it been animated. So what script does is that it take each updated location value and send it through bluetooth serial communication to the car and car response accordingly to the value it received

This stay continue until it reached to it last frame

* Here is Final Blender Script

                    
import bpy
import serial
import time
import os
import math
                         

from bpy.props import EnumProperty
from bpy.types import Operator, Panel
from bpy.utils import register_class, unregister_class

ser = serial.Serial('COM22', 9600)
time.sleep(2) # wait for the serial connection to initialize
con="happy"
#--------------------------------------------------------------------------------------------------
class ModalTimerOperator(bpy.types.Operator):
    """Operator which runs its self from a timer"""
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"

    _timer = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            global con
            
            if bpy.context.scene.frame_current < bpy.context.scene.frame_end :
                
                bpy.context.scene.frame_set(bpy.context.scene.frame_current + 1)
                
                xt,yt,zt = bpy.context.object.matrix_world.to_translation()
                xr,yr,zr = bpy.context.object.matrix_world.to_euler()
                
                step = bpy.context.object.constraints["Follow Path"].offset_factor * 300
                
                
                while con != b'start\r\n':
                    ser.write(str(123.321).encode())
                    con = ser.readline()                
                con='0'
                print("started")

                time.sleep(0.1)
                ser.write(str(step).encode())
                con = ser.readline()
                while con != b'dones\r\n':
                    con = ser.readline()                
                con='0'
                print(step)
                
                time.sleep(0.1)
                ser.write(str(math.degrees(zr)).encode())
                
                con = ser.readline()
                while con != b'doner\r\n':
                    con = ser.readline()                
                con='0'
                print(math.degrees(zr))
                
                time.sleep(0.1)
                ser.write(str(zt).encode())
                
                con = ser.readline()
                while con != b'donez\r\n':
                    con = ser.readline()                
                con='0'
                print(zt)
                print("Data Send \n")
                
                
                
                con = ser.readline()
                while con != b'done\r\n':
                    con = ser.readline()                
                con='0'
                print("Data excuted \n")
                
            else:
                # change theme color, silly!
                color = context.preferences.themes[0].view_3d.space.gradients.high_gradient
                color.s = 1.0
                color.h += 0.01  


        return {'PASS_THROUGH'}

    def execute(self, context):
        wm = context.window_manager
        self._timer = wm.event_timer_add(0.1, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        wm = context.window_manager
        wm.event_timer_remove(self._timer)

#-------------------------------------------------------------------------------------------------- 
class TEST_PT_panel(Panel):
    bl_idname = 'TEST_PT_panel'
    bl_label = 'Test'
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Test'
 
    def draw(self, context):
        layout = self.layout
        layout.operator('test.test_op', text='Reset completely').action = 'HM'
        layout.operator('test.test_op', text='start streaming').action = 'RF'
        layout.operator('test.test_op', text='Disconnect serial').action = 'DC'
 
#--------------------------------------------------------------------------------------------------
class TEST_OT_test_op(Operator):
    bl_idname = 'test.test_op'
    bl_label = 'Test'
    bl_description = 'Test'
    bl_options = {'REGISTER', 'UNDO'}
 
    action: EnumProperty(
        items=[
            ('HM', 'Home', 'Home'),
            ('RF', 'Refresh', 'Refresh'),
            ('DC', 'Disconnect', 'Disconnect')
        ]
    )
 
    def execute(self, context):
        if self.action == 'HM':
            self.reset_scene(context=context)
        elif self.action == 'RF':
            self.start_trans(context=context)
        elif self.action == 'DC':
            self.disconnect_port(context=context)
        return {'FINISHED'}
 
    @staticmethod
    def reset_scene(context):
        print("1")
        # Define the serial port and baud rate.
        
        bpy.ops.object.select_all(action='SELECT')
        bpy.ops.object.delete(use_global=False, confirm=False)
        bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0))

 
    @staticmethod
    def start_trans(context):
        print("sending...")
        bpy.ops.wm.modal_timer_operator()
        
 
    @staticmethod
    def disconnect_port(context):
        print("Port Disconnecting")
        ser.close()
 
 
 
 
def register():
    register_class(TEST_OT_test_op)
    register_class(TEST_PT_panel)
    bpy.utils.register_class(ModalTimerOperator)
 
 
def unregister():
    unregister_class(TEST_OT_test_op)
    unregister_class(TEST_PT_panel)
    bpy.utils.unregister_class(ModalTimerOperator)
 
 
if __name__ == '__main__':
    register()
    
    


                    
                

*Here is code for arduino mega

                    
#include <Servo.h> // Header for Servo operation
Servo myservo; // Define Object
//=========================================================================================================
//Motor Pins
int smDirectionPin1 = 55; //pin number for stepper motor 1 direction
int smStepPin1 = 54; //pin number for motor 1 steps
int smDirectionPin2 = 61; //pin number for stepper motor 2 direction
int smStepPin2 = 60; //pin number for motor 2 steps
int smEnable1 = 38; //stepper driver enable pin
int smEnable2 = 56; //stepper driver enable pin
//---------------------------------------------------------------------------------------------------------
float rotationcoeff = 2.5; // number of rotation of wheel to rotate car to 360 angle
float MotorStepPerRev = 800; //number of step to rotate wheel to 360 angle
long num1, num2, num3, num4 = 0; // variable needed
String r1_data, r2_data, r3_data; // receive data storing variable
//----------------------------------------------------------------------------------------------------------
void wheels(int stp, int spd, int wd1, int wd2)
{
  digitalWrite(smDirectionPin1, wd1);
  digitalWrite(smDirectionPin2, wd2);
  int x = 0;
  for ( x = stp; x > 0; x--)
  {
    digitalWrite(smStepPin1, HIGH);
    digitalWrite(smStepPin2, HIGH);
    delayMicroseconds(spd);
    digitalWrite(smStepPin1, LOW);
    digitalWrite(smStepPin2, LOW);
    delayMicroseconds(spd);
  }
}

void stp(float x)
{
  num2 = long(x);
  while (num1 < num2) {
    wheels(1, 1000, 1, 1);
    num1++;
  }
  while (num1 > num2) {
    wheels(1, 1000, 0, 0);
    num1--;
  }
  num1 = long(x);
}

void rev(float y)
{
  num4 = long(y);
  if (num3 < num4) {
    wheels(int(((MotorStepPerRev * rotationcoeff) / 360)*y), 1000, 1, 0);
    //num3++;
  }
  else if (num3 > num4) {
    wheels(int(((MotorStepPerRev * rotationcoeff) / 360)*y), 1000, 0, 1);
    //num3--;
  }
  num3 = long(y);
}

void zaxis(int z) {
  if ( z < 0)
  {
    myservo.write(0);
  }
  else if (z > 180)
  {
    myservo.write(180);
  }
  else
  {
    myservo.write(z);
  }
}

void setup() {
  myservo.attach(6);
  pinMode(smDirectionPin1, OUTPUT);
  pinMode(smStepPin1, OUTPUT);
  pinMode(smDirectionPin2, OUTPUT);
  pinMode(smStepPin2, OUTPUT);
  pinMode(smEnable1, OUTPUT);
  pinMode(smEnable2, OUTPUT);
  digitalWrite(smEnable1, LOW);
  digitalWrite(smEnable2, LOW);
  digitalWrite(smDirectionPin1, HIGH);
  digitalWrite(smDirectionPin2, HIGH);
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0)
  {
    r1_data = Serial.readString();
    if ( r1_data.toFloat() == 123.321)
    {
      Serial.println("start");
      while (!Serial.available());
      r1_data = Serial.readString();
      Serial.println("dones");
      while (!Serial.available());
      r2_data = Serial.readString();
      Serial.println("doner");
      while (!Serial.available());
      r3_data = Serial.readString();
      Serial.println("donez");
      zaxis(r3_data.toInt());
      stp(r1_data.toFloat());
      rev(r2_data.toFloat());
      Serial.println("done");
    }
  }
}
                    
                

Here is video for final test run

Focus on car

This clip is 10x to 6x faster respectively since whole was slow very slow. and you see I wanted to write R but there is issue in angle it turn but It wrote R as you see.

To confirm issue and to see where exact error is in blender script or firmware I tested firmware code independently

*Here is test code

                    
#include <Servo.h> // Header for Servo operation
Servo myservo; // Define Object
//=========================================================================================================
//Motor Pins
int smDirectionPin1 = 55; //pin number for stepper motor 1 direction
int smStepPin1 = 54; //pin number for motor 1 steps
int smDirectionPin2 = 61; //pin number for stepper motor 2 direction
int smStepPin2 = 60; //pin number for motor 2 steps
int smEnable1 = 38; //stepper driver enable pin
int smEnable2 = 56; //stepper driver enable pin
//---------------------------------------------------------------------------------------------------------
float rotationcoeff = 2.8; // number of rotation of wheel to rotate car to 360 angle
int MotorStepPerRev = 799; //number of step to rotate wheel to 360 angle
long num1, num2, num3, num4 = 0; // variable needed
String r1_data, r2_data, r3_data; // receive data storing variable
//----------------------------------------------------------------------------------------------------------
void wheels(int stp, int spd, int wd1, int wd2)
{
  digitalWrite(smDirectionPin1, wd1);
  digitalWrite(smDirectionPin2, wd2);
  int x = 0;
  for ( x = stp; x > 0; x--)
  {
    digitalWrite(smStepPin1, HIGH);
    digitalWrite(smStepPin2, HIGH);
    delayMicroseconds(spd);
    digitalWrite(smStepPin1, LOW);
    digitalWrite(smStepPin2, LOW);
    delayMicroseconds(spd);
  }
}

void stp(float x)
{
  num2 = long(x);
  while (num1 < num2) {
    wheels(1, 1000, 1, 1);
    num1++;
  }
  while (num1 > num2) {
    wheels(1, 1000, 0, 0);
    num1--;
  }
  num1 = long(x);
}

void rev(float y)
{
  num4 = long(y);
  while (num3 < num4) {
    wheels(int((MotorStepPerRev * rotationcoeff) / 360), 1000, 1, 0);
    num3++;
  }
  while (num3 > num4) {
    wheels(int((MotorStepPerRev * rotationcoeff) / 360), 1000, 0, 1);
    num3--;
  }
  num3 = long(y);
}

void zaxis(int z) {
  if ( z < 0)
  {
    myservo.write(0);
  }
  else if (z > 180)
  {
    myservo.write(180);
  }
  else
  {
    myservo.write(z);
  }
}

void setup() {
  myservo.attach(6);
  pinMode(smDirectionPin1, OUTPUT);
  pinMode(smStepPin1, OUTPUT);
  pinMode(smDirectionPin2, OUTPUT);
  pinMode(smStepPin2, OUTPUT);
  pinMode(smEnable1, OUTPUT);
  pinMode(smEnable2, OUTPUT);
  digitalWrite(smEnable1, LOW);
  digitalWrite(smEnable2, LOW);
  digitalWrite(smDirectionPin1, HIGH);
  digitalWrite(smDirectionPin2, HIGH);
  Serial.begin(9600);
}

void loop() {
  zaxis(0);
  stp(1000);
  rev(90);
  stp(2000);
  rev(180);
  stp(3000);
  rev(270);
  stp(4000);
  rev(360);
  delay(10000);
}
                    
                

Here the result

This code is independently running mean I pre code it to draw square. But as you can see there is shift in angle each time it turn else covering distance all are equal. This conclude there is some error in written code that needed fixing. since two make sure error is not due to wheel slip I done one more test

Here I pause one wheel and kept rotating another one to see How perfect it draw circle. This I have done just to test movement perfection

Click To visit group machine week page and to Known more about our project


Learning Outcomes:

For this week I am done. As you see there are issue with code It is not perfect So I will work with it personally in future and continue this project in a different form. To park group project here I needed to stop. Apart from writing firmware and interface most of my time and energy consume in troubleshooting design because I have expertise in Electronic and computing. Supporting other in completing their task and with that working on my own task was chanllenging but I cant ignore this things in my group because goal was to complete project not just to do my job only. So with all that struggle I managed this much documentation and I learn blender script from this process and I am happy about it.


Download files:

blenderscript.py
firmware.ino