Skip to content

Bubble Machine Prototype

What’s this?

This is prototype’s prototype of “Bubble machine(仮)”, Fab Acadmey 2021 machine building project at Fablab Kannai, for experimenting minimal electronics and software implementation.


Materials


v0.1 - Stepper & servo motors

Composition and behavior

bm_prototype_composition

  • Motor Driver and Stepper motor operate fan table on X-axis rail frame
  • When a rotary fan table comes to the racket position, racket is tilted up to 90 degree
  • (Rotary fan is running continuously and when racket with soap faces toward the front, soap bubble is blew production only)
  • Application program is embedded in Arduino Uno

Electronics

Power supply

  • 12V-1.0A AC Adapter for powering stepper motor
  • 5V (from Arduino Uno, up to 200mA) for servo motor

    • There are no information about current in datasheet, some website tells about current for SG90: Ref.Proto Supplies

      SG90 Measure value
      Voltage 4.8-6VDC (5V Typical)
      Current (idle) 10mA (typical)
      Current (typical during movement) 100-250mA
      Current (stall) 360mA (measured)
      Stall Torque 1.7 kg-cm (measured)
      Speed 0.12s / 60 degree (varies with VDC)
  • 5V(from ARduino Uno) for data control circuit

Pin map v0.2

Arduino A4988 Stepper motor Servo motor
2 7)STEP
3 8)DIR
9 PWM
5V 10)VDD VCC
GND 9)GND Ground
16)VMOT - to 12V AC Adapter
15)GND - to 12V AC adapter ground
14)2B black
13)2A brown
12)1A yellow
11)1B orange

Ref.

Motor Driver (A4988) setup


Source Code v0.1

bubble_machine_sample01.ino

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <Servo.h>

// Define pin connections & motor's steps per revolution
const int dirPin = 2;
const int stepPin = 3;
const int servoPin = 9;

const int stepsPerRevolution = 200;

Servo myservo; 

int pos = 0;

void setup()
{
  // Declare pins as Outputs
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);

  myservo.attach(servoPin);
}
void loop()
{
  // Set motor direction clockwise
  digitalWrite(dirPin, HIGH);

  // Spin stepper motor
  for(int x = 0; x < stepsPerRevolution*4; x++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(1000);
  }

  // Rotate servo motor
  for (pos = 0; pos <= 90; pos += 1) {
    myservo.write(pos);              
    delay(10);
  }
  delay(2000);

  for (pos = 90; pos >= 0; pos -= 1) {
    myservo.write(pos); 
    delay(10);
  }

  // Set motor direction counterclockwise
  digitalWrite(dirPin, LOW);

  // Spin motor quickly
  for(int x = 0; x < stepsPerRevolution*4; x++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(1000);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(1000);
  }
  delay(1000);
}

Outcome - as of 2021.03.27


v0.2 - Add switch

Composition and behavior

bm_prototype_composition

Added minimal function to start / stop stepper and servo motors by minimal materials (tactile switch and LEDs).

Why?
To control the position of fan table and angle of racket whenever start/stop machine, ideally. Without start / stop function, I need to calibrate the position of that moving parts by hand every time.

Electronics

Power supply

  • Used internal pullup of Arduino digital pin.
  • LED power is from Arduino data control pin.

Pin map v0.2

Arduino A4988 Stepper motor Servo motor Others Memo
2 7)STEP
3 8)DIR
9 PWM
5V 10)VDD VCC
GND 9)GND Ground
16)VMOT - to 12V AC Adapter
15)GND - to 12V AC adapter ground
14)2B black
13)2A brown
12)1A yellow
11)1B orange
7(INPUT_PULLUP) Tactile switch New!
12 LED(red) - on New!
13 LED(clear-red) - off New!

Source Code v0.2

bubble_machine_sample02.ino

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <Servo.h>

// Define pin connections & motor's steps per revolution

const int dirPin = 2;
const int stepPin = 3;
const int swPin = 7;
const int servoPin = 9;
const int ledRed = 12; // sw_on = true;
const int ledWhite = 13; // sw_on = false; with Uno #13 LED

const int stepsPerRevolution = 200;

Servo myservo; 

int sw = 1;
int pos = 0;
boolean sw_on = false; 

void lightLED(){
  if (sw_on){
    digitalWrite(ledWhite, LOW);
    digitalWrite(ledRed, HIGH);
  } else {
    digitalWrite(ledWhite, HIGH);
    digitalWrite(ledRed, LOW);
  }
}

void setup()
{
  pinMode(swPin, INPUT_PULLUP);  

  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);

  myservo.attach(servoPin);
  Serial.begin(115200);
}
void loop()
{
  sw = digitalRead(swPin);
  if ((sw == 0 ) && (sw_on == false)){
    sw_on = true;
  } else if ((sw == 0 ) && (sw_on )){
    sw_on = false;
  }
  Serial.println(sw_on);

  lightLED();

  if (sw_on) {

    // Set motor direction clockwise
    digitalWrite(dirPin, HIGH);

    // Spin stepper motor
    for(int x = 0; x < stepsPerRevolution*4; x++) {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(1000);
      digitalWrite(stepPin, LOW);
      delayMicroseconds(1000);
    }

    // Rotate servo motor
    for (pos = 0; pos <= 90; pos += 1) {
      myservo.write(pos);              
      delay(10);
    }
    delay(500);

    for (pos = 90; pos >= 0; pos -= 1) {
      myservo.write(pos); 
      delay(10);
    }

    // Set motor direction counterclockwise
    digitalWrite(dirPin, LOW);

    // Spin motor quickly
    for(int x = 0; x < stepsPerRevolution*4; x++) {
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(1000);
      digitalWrite(stepPin, LOW);
      delayMicroseconds(1000);
    }
    delay(500);
  }

  // wait for checking "sw_on" flag
  delay(1000);
}

Outcome - as of 2021.03.29


v0.3 - Use Stepper library and implement “homing” logic

For coding easily, it looks good to use Stepper library in Arduino standard library.

It’s important to homing (return to initial position when switch off) for calibrating machine smoothly.

Homing (return to initial Position)

As per Arduino forum - Stepper Motor Basics,

Position Feedback

Stepper motors do not have the ability to tell the Arduino what position they are at, nor do they have the ability (like a servo) to go to a particular position. All they can do is move N steps from where they are now.

If it is essential to have position feedback a rotary encoder can be attached to the motor shaft - but that is beyond the scope of this essay.

Initial Position

When it starts up the Arduino has no means of knowing where the stepper motor is positioned - for example somebody might have moved it manually when the power was off.

The usual way to establish a datum for counting steps is with a limit switch. At startup the Arduino will move the motor until it triggers the switch. The Arduino will then regard that step position as step zero for the purpose of future position keeping.

Note

It’s necessary to keep how many steps forward it has taken. When “stop” switch is toggled, reverse the count and motor comes to zero position.

RPM

RPM (Round per minute) is calculated by:

60 x (steps per second / steps per revolution)

Ref. Sciencing - Calcuating RPMs for Stepper Motors

In case of KH42KM2-802 on prototype machine,

  • steps per second : measured at v0.2 example as 800 steps / 1.75 seconds ≒ 457
  • steps per revolution : 200

60 x (457 / 200) ≒ 137

Warning

This value totally is not right. Actual source code works by smoothly 500 RPM It may be because v0.2 works by 1 millisecond delay for each digitalWrite() and need to add the other overhead.


Source code v0.3

bubble_machine_sample03.ino

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <Servo.h>
#include <Stepper.h>

// Define pin connections & motor's steps per revolution

const int dirPin = 2;
const int stepPin = 3;
const int swPin = 7;
const int servoPin = 9;
const int ledRed = 12; // sw_on = ture;
const int ledWhite = 13; // sw_on = false; with Uno #13 LED

Servo myservo; 

// change this to the number of steps on your motor
#define STEPS 200
// const int stepsPerRevolution = 800;

Stepper stepper(STEPS, dirPin, stepPin);

int sw = 1; // switch value (default:1 = off)
int sv_pos = 0; // currrent servo position
int step_pos = 0; // current steps position
int x = 0; // x steps per loop

boolean sw_on = false; // current switch status
boolean dir_up = true; // current direction

const int steps_begin = 0;
const int steps_end = 3200;

void lightLED(){
  if (sw_on){
    digitalWrite(ledWhite, LOW);
    digitalWrite(ledRed, HIGH);
  } else {
    digitalWrite(ledWhite, HIGH);
    digitalWrite(ledRed, LOW);
  }
}

void setup(){
  pinMode(swPin, INPUT_PULLUP);  
  pinMode(dirPin, OUTPUT);  

  myservo.attach(servoPin);

  // set the speed of the motor to 500 RPMs
  stepper.setSpeed(500);
  x = STEPS/100;

  Serial.begin(115200);
}

void loop(){

  // Checkn switch and toggle
  sw = digitalRead(swPin);

  // Toggle LED only when sw_on status is changed
  if ((sw == 0 ) && (sw_on == false)){
    sw_on = true;
    lightLED();
    Serial.println("Switch ON");
    delay(500);

  } else if ((sw == 0 ) && (sw_on )){
    sw_on = false;
    lightLED();
    Serial.println("Switch OFF");
    delay(1000);
  }

  // Switch ON
  if (sw_on) {

    // check steps, rotate servo and toggle direction
    // only on steps_bigin or steps_end position
    if (step_pos <= steps_begin) {
      Serial.print("step_pos: ");
      Serial.println(step_pos);
      step_pos = steps_begin;

      // Set motor direction clockwise
      // digitalWrite(dirPin, HIGH);
      dir_up = true;
      Serial.print("dir_up");

      delay(500);

    } else if (steps_end <= step_pos) {
      Serial.print("step_pos: ");
      Serial.println(step_pos);

      step_pos = steps_end;

      // Rotate servo motor up (Raise racket)
      for (sv_pos = 90; sv_pos >= 0; sv_pos -= 1) {
        myservo.write(sv_pos); 
        delay(10);
      }

      delay(2000);

      // Rotate servo motor down
      for (sv_pos = 0; sv_pos <= 90; sv_pos += 1) {
        myservo.write(sv_pos);              
        delay(10);
      }

      // Set motor direction counterclockwise
      // digitalWrite(dirPin, LOW);
      dir_up = false;
      Serial.println("dir_up: false");

      delay(500);
    }

    // step by STEPS(steps pre rev.)/100
    if (dir_up == true) {
      stepper.step(x);
      step_pos = step_pos + x;  
    } else {
      stepper.step(-x);
      step_pos = step_pos -x;             
    }

  // Switch OFF
  } else {
     Serial.print("step_pos: ");
     Serial.println(step_pos);
     Serial.print("dir_up: ");
     Serial.println(dir_up);

     // Homing stepper
     if (step_pos != 0) {
       stepper.step(-step_pos);
       step_pos = 0;
     }
     delay(1000);
  }
}

Outcome as of 2021.03.30


v0.4 Experiment limit switch (hit back motor direction)

Composition and behavior

For edge detection by limit switch, I experimented one limit switch to control stepper motor.


Pin map v0.4

Arduino A4988 Stepper motor Servo motor Others Memo
2 7)STEP
3 8)DIR
4 Limit Switch v0.4
9 PWM
5V 10)VDD VCC VCC for LED,Tact switch,Limit switch
GND 9)GND Ground GND for LED,Tact switch,Limit switch
16)VMOT - to 12V AC Adapter
15)GND - to 12V AC adapter ground
14)2B black
13)2A brown
12)1A yellow
11)1B orange
7(INPUT_PULLUP) Tactile switch v0;2
12 LED(red) - on v0.2
13 LED(clear-red) - off v0.2

Source code v0.4

bubble_machine_sample04.ino

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <Servo.h>
#include <Stepper.h>

const int dirPin = 2;
const int stepPin = 3;
const int Lswitch = 4;
const int swPin = 7;
const int servoPin = 9;
const int ledRed = 12; // sw_on = ture;
const int ledWhite = 13; // sw_on = false; with Uno #13 LED

Servo myservo; 

// change this to the number of steps on your motor
#define STEPS 200

Stepper stepper(STEPS, dirPin, stepPin);

int sw = 1; // switch value (default:1 = off)
int sv_pos = 0; // currrent servo position
int step_pos = 0; // current steps position
int x = 0; // x steps per loop

boolean sw_on = false; // current switch status
boolean dir_up = true; // current direction

boolean edge = false; 

const int steps_begin = 0;
const int steps_end = 4000;

void lightLED(){
  if (sw_on){
    digitalWrite(ledWhite, LOW);
    digitalWrite(ledRed, HIGH);
  } else {
    digitalWrite(ledWhite, HIGH);
    digitalWrite(ledRed, LOW);
  }
}

void go_home(){
  Serial.print("step_pos: ");
  Serial.println(step_pos);
  Serial.print("dir_up: ");
  Serial.println(dir_up);

  // Homing stepper
  if (step_pos != 0) {
    stepper.step(-step_pos);
    step_pos = 0;
  }
  delay(1000);
}

void setup(){
  pinMode(swPin, INPUT_PULLUP);  
  pinMode(dirPin, OUTPUT);  
  pinMode(Lswitch, INPUT_PULLUP); 

  myservo.attach(servoPin);

  // set the speed of the motor to 500 RPMs
  stepper.setSpeed(500);
  x = STEPS/100;

  Serial.begin(115200);
}

void loop(){

  // Checkn switch and toggle
  sw = digitalRead(swPin);

  // Toggle LED only when sw_on status is changed
  if ((sw == 0 ) && (sw_on == false)){
    sw_on = true;
    lightLED();
    Serial.println("Switch ON");
    delay(500);

  } else if ((sw == 0 ) && (sw_on )){
    sw_on = false;
    lightLED();
    Serial.println("Switch OFF");
    delay(1000);
  }

  if( (digitalRead(Lswitch) == LOW) && (edge == false) ) {
    Serial.println("edge colision detected"); 
    edge = true; 
    go_home();
    delay(20);
  } 

  if( (digitalRead(Lswitch) == HIGH) && (edge == true) ) {
    edge = false;
    delay(20); 
  }


  // Switch ON
  if (sw_on) {

    // check steps, rotate servo and toggle direction
    // only on steps_bigin or steps_end position
    if (step_pos <= steps_begin) {
      Serial.print("step_pos: ");
      Serial.println(step_pos);
      step_pos = steps_begin;

      // Set motor direction clockwise
      // digitalWrite(dirPin, HIGH);
      dir_up = true;
      Serial.print("dir_up");

//      delay(500);
      delay(50);

    } else if (steps_end <= step_pos) {
      Serial.print("step_pos: ");
      Serial.println(step_pos);

      step_pos = steps_end;

      // Rotate servo motor up (Raise racket)
      for (sv_pos = 90; sv_pos >= 0; sv_pos -= 1) {
        myservo.write(sv_pos); 
        delay(10);
      }

      delay(2000);

      // Rotate servo motor down
      for (sv_pos = 0; sv_pos <= 90; sv_pos += 1) {
        myservo.write(sv_pos);              
        delay(10);
      }

      // Set motor direction counterclockwise
      // digitalWrite(dirPin, LOW);
      dir_up = false;
      Serial.println("dir_up: false");

      delay(500);
    }

    // step by STEPS(steps pre rev.)/100
    if (dir_up == true) {
      stepper.step(x);
      step_pos = step_pos + x;  
    } else {
      stepper.step(-x);
      step_pos = step_pos -x;             
    }

  // Switch OFF
  } else {
    go_home();
  }
  digitalWrite(Lswitch, HIGH); 
} 

Outcome as of 2021.03.31


v0.5 Toggle motor direction by two limit switches

Composition and behavior

  • On startup, to move the motor until it triggers the switch. The Arduino will then regard that step position as step zero for the purpose of future position keeping.
  • Two limit switches toggle the direction to move stepper motor

Pin map v0.5

Arduino A4988 Stepper motor Servo motor Others Memo
2 7)STEP
3 8)DIR
4 Limit Switch v0.4
5 Limit Switch v0.5
9 PWM
5V 10)VDD VCC VCC for LED,Tact switch,Limit switch
GND 9)GND Ground GND for LED,Tact switch,Limit switch
16)VMOT - to 12V AC Adapter
15)GND - to 12V AC adapter ground
14)2B black
13)2A brown
12)1A yellow
11)1B orange
7(INPUT_PULLUP) Tactile switch v0;2
12 LED(red) - on v0.2
13 LED(clear-red) - off v0.2

Source code v0.5

bubble_machine_sample05.ino


Outcome as of 2021.04.01


v0.6 Use limit switches for edge collision detection

3D printed attachment for limit switch

For attaching limit switches to rail frame, made an attachment that fits with 20x20 aluminum frame.

3D model on Autodesk A360


Composition and behavior

v0.6_composition

  • On power on, stepper automatically goes to edge “UP”, turns to edge “Down”, then go to home position. Software checks how many steps it takes from “UP” to “Down”, then sets positions(absolute step numbers). Below is from log message in Serial monitor output:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    23:53:40.346 -> edgeUp collision detected
    23:53:40.346 -> Detected step_end position (edgeUp) is: 1186
    23:53:42.796 -> edgeUp collision detected
    23:53:42.796 -> Detected steps_begin positon (edgeDown) is: -2876
    23:53:42.796 -> ---Adjusted steps positions---
    23:53:42.796 -> steps_begin: 0    // edge "Down" position 
    23:53:42.796 -> steps_home: 200   // home position
    23:53:42.796 -> steps_turn: 3862  // the place where servo rotates and table head turns
    23:53:42.796 -> steps_end: 4062   // edge "Up" position
    23:53:42.796 -> ------------------------------
    
  • If anything wrong and table head touch with limit switches, table head automatically goes to home position and stop stepping motor.

Source code v0.6

bubble_machine_sample06.ino


Outcome as of 2021.04.02


Files


Reference


Last update: April 12, 2021