17. Machine design

What I’ve done this week

  • Designed a machine and fabricated it
  • Demonstrate it as a part of the group

Weekly Assignment Requirement

Individual assignments
- design, build, and connect wired or wireless node(s) with network or bus addresses

Group assignment
- Design a machine that includes mechanism + actuation + automation - Build the mechanical parts and operate it manually - Document the group project

Description of Assignment Work

The outline

for the machine design week, all the students in Fable Kamakura formed a group and Tatsuro Homma who was student from FabLab Kannai joined to our team. we had conversations several times online and decided to create a kind of machine orchestra working on online conference service. Each students would created a machine which could play sounds automatically and also had the function to get signal from the internet to actuate each machine simultaneously. Homma-san suggested to use the system of MQTT because it seemed easy to send signals to many machines at a time. So we tried to take in MQTT for our Orchestra under the leadership of him. Please check the Group Assignment page for knowing more about the system in detail.

Group Assignment

I created the presentation video for our group. It was edited by Adobe After Effects and Adobe Premiere Pro. Please check it as well.

Group page Week17

I put my design file at “Links to Files and Code” section on my page instead of group page.

Design sketch



I designed the machine hitting glasses working as a kind of percussion. In the middle, there was a turning table to revolve the glasses which had different scales each by including variety of amount of water inside. It worked by stepper motor to change the angle of revolving table precisely. And hitting part was manipulated by DC motor with drum brushes made of nylon (probably) on its shaft. These two motors would be controlled by ESP32 worked with MQTT via the internet. Basically it would worked by itself but I was thinking to attach buttons to control it manually.



By putting materials on the cutting mat, I arranged the structure of the device.



and simply tested to make sound. I found using rotation of the motor for hitting glasses was difficult. so I changed the mechanism from using it to using the bending of bamboo stick.

Making the model

I created 3D model by Fusion360 at first. then, I laser cut and 3D printed each parts and assembled them.

gear part



used add-in called SPUR GEAR for designing gears. If the each gear using the same value of module, they can mesh together with each other. And you can change the size of the gear from the value of number of teeth.



I tried to create three of them as the same size.



And laser cut them. The shape of middle hole was cut for fitting to the shafts (servo and so on) motor to prevent racing them.



One of them was directly attached to the turntable. I made it slightly thicker because it could make space for the other gears to revolve easily.

turntable part



I was thinking to use 6 glasses for this device so I placed them to keep equal distance from each other.



The turntable had a lot of small halls to attach the glass holders on it by screw.



Under the turn table, I attached spacers to prepare the space for the gears.



I put metal balls into the hole inside the ring spacers to help revolving the table smoothly by reducing friction.

glass holder part



To hold the glasses I printed glass holder parts by 3D printer.



Firstly I made its inside height 5cm but the edge of it touched to the glass and disturbed to make sounds.



To solve the issue, I cut 1cm of its height and the glass sounded properly. So I modified the 3D model as this.

hitting stick tower part



Using cam mechanism to control the stick. the cam was originally made of MDF but I changed to acrylic plate because MDF got stuck by friction sometimes.



The structure inside the tower. I used the DC motor kit and stuck it to the wall by bamboo pins (see the picture above).



And also created a ball type mallet to hit the glasses to create better sounds.

assembling



Assembled like this (still printing a mallet this time though). I decided to test with 3 glasses at first. And I prepared button place but I didn’t use it actually.

Programming


// Include the Arduino Stepper Library
#include <Stepper.h>

// Number of steps per output rotation
const int stepsPerRevolution = 36;

// Create Instance of Stepper library
Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11); //for arduino
//Stepper myStepper(stepsPerRevolution, 36, 39, 34, 35); //do not use(error pinset for barduino)
//Stepper myStepper(stepsPerRevolution, 12, 14, 27, 26); //for barduino
#define button1 6; //for arduino
//#define button1 23 //for barduino
#define button2 7; //for arduino
//#define button2 22 //for barduino


void setup()
{
  // set the speed (rpm):
  myStepper.setSpeed(100);
  // initialize the serial port:
  Serial.begin(115200);
  pinMode(button1,INPUT);
  pinMode(button2,INPUT);
}

void loop() 
{

  if((digitalRead(button1) == LOW) && (digitalRead(button2) != LOW)){
  // step one revolution in one direction:
  Serial.println("clockwise");
  myStepper.step(stepsPerRevolution);
  }

  if((digitalRead(button1) != LOW) && (digitalRead(button2) == LOW)){
  Serial.println("counterclockwise");
  myStepper.step(-stepsPerRevolution);
  }

  if((digitalRead(button1) == LOW) && (digitalRead(button2) == LOW)){
  Serial.println("around the world");
  myStepper.step(200);
  }
}

I tested a servo motor with motor driver module using L298N. If I press a button, it turns 60 degree. If I press double button at the same time, it goes around.


#include <Arduino.h>
#include <analogWrite.h>

void setup() {
  Serial.begin(115200);
  pinMode(13,OUTPUT);
  pinMode(23,INPUT);
  pinMode(22,INPUT);
}

void loop(){
  int i;
  for(i=255;i>=0;i--/2){
    Serial.println(i); 
    analogWrite(13,i);
    delay(10);  
  }
  for(i=0;i<=255;i++/2){
    Serial.println(i); 
    analogWrite(13,i);
    delay(10);  
  }
}

I also tried to control a DC motor by PWM using MOSFET. I just tried to control as repeating speed up and down and added indicating LED by it.


#include <Arduino.h>
#include <Stepper.h>
#include <analogWrite.h>

// Number of steps per output rotation
const int stepsPerRevolution = 1000;
Stepper myStepper(stepsPerRevolution, 12, 14, 27, 26);


void setup()
{
  myStepper.setSpeed(50);
  // initialize the serial port:
  pinMode(13,OUTPUT);
  Serial.begin(115200);
}

void loop() 
{
  Serial.println("clockwise");
  myStepper.step(stepsPerRevolution*3);
  delay(1000);

  int i;
  for(i=255;i>=0;i--/2){
    Serial.println(i); 
    analogWrite(13,i);
    delay(10);  
  }
  for(i=0;i<=255;i++/2){
    Serial.println(i); 
    analogWrite(13,i);
    delay(10);  
  }

Then, I used both motor at the same time.

Next, I tried them with the assembled device.


Hitting test with DC motor. It seemed to work well.


Rotating test with servo motor. It didn’t work smoothly even if it hadn’t loaded glasses yet. I decided to recreate gears to increase the power for revolving.

improved version

I made change in the gear system which I mentioned in the previous section.



The gear for servo got smaller and the one for table got bigger. then it generated more power to revolve by the mechanism of gear train. The inside of the gear for table was cut out to reduce its weight.



And spacer was also changed as smaller to make space for the bigger gear for the table. (Left : old one, Right : new one)

Final outcome

Finally, I completed the device as the following video.


#include <Arduino.h>
#include <analogWrite.h>
#include <Stepper.h>
const int stepsPerRevolution = 180;
Stepper myStepper(stepsPerRevolution, 12, 14, 27, 26);

const int ledPin = 13;
#define DCMotor 25 
#define button1 16 //for barduino
#define button2 17 //for barduino

void setup() {
  Serial.begin(115200);
  myStepper.setSpeed(30); //low speed
  pinMode(ledPin,OUTPUT);
  pinMode(DCMotor,OUTPUT);
  pinMode(button1,INPUT);
  pinMode(button2,INPUT);
}

void loop(){
    Serial.print("1");
    analogWrite(DCMotor,250); //70,72補助ありで回転開始、73自力スタート
    delay(2000);  
    analogWrite(DCMotor,0);
    delay(110);
    Serial.print("2");
    myStepper.step(stepsPerRevolution);
    analogWrite(DCMotor,250); //70,72補助ありで回転開始、73自力スタート
    delay(1200);  
    analogWrite(DCMotor,0);
    delay(110);
    Serial.print("1");
    myStepper.step(-stepsPerRevolution);
    analogWrite(DCMotor,250); //70,72補助ありで回転開始、73自力スタート
    delay(2000);  
    analogWrite(DCMotor,0);
    delay(110);
    Serial.print("3'");
    myStepper.step(-stepsPerRevolution);
    analogWrite(DCMotor,250); //70,72補助ありで回転開始、73自力スタート
    delay(2000);  
    analogWrite(DCMotor,0);
    delay(110);
    Serial.print("1'");
    myStepper.step(stepsPerRevolution);
}



And the code below (you can also download from file section) was used for group presentation video.
This program is hitting only one glass because I couldn’t adjusted the servo motor well for the orchestra at that time. so I just prepared simple version program.

the actual motion of the device is written at “void mqttCallback” section. and the extra section is for mainly networking by MQTT. Please check the Group Assignment page if you want to know more about it.

/*
This is a sample template program for ESP32 connecting to 
AWS IoT over MQTT to make distributed machine device for group 
project of Machine design and mechanial design in   
FabAcademy 2020 (students at Fablab Kamakura and Kannai).

As this code contains certification information, PLEASE 
DO NOT UPLOAD THIS SOURCE CODE to ANY SHARABLE PLACE 
DIRECTLY(including FabAcademy page). If you need to upload
this to sharable place, PLEASE MAKE SURE YOU DELETE
VALUES OF rootCA, certificate and privateKey CHARACTORS. 

For preparation, please find PubSubClient.h in youf local 
library and chhange #define MQTT_MAX_PACKET_SIZE 128 to 512. 

For using this, please update as follows. 
1) Set your ssid and password
2) Configure your topic (or for your use to publish/receive message) 
3) Specify your topic name to subscribe in connectAWSIoT()
4) Write your logic on receiving message in mqttCallback()
5) Write your logic for publishing message in mqttLoop() 
*/

#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <Arduino.h>
#include <analogWrite.h>


// pin assignment for LED blink
const int ledPin = 13;
//#define ledPin 13
#define DCMotor 25 //for barduino
//#define button1 32 //for barduino
//#define button2 33 //for barduino

// 1) set your ssid and password ----------
char *ssid = "your_wifi_ssid";
char *password = "your_wifi_password";
// 1) end ---------------------------------

// AWS_IOT endpoint setting (fixed)
const char *endpoint = "a2toz7cb5zl4er-ats.iot.ap-northeast-1.amazonaws.com";
const int port = 8883;
//char deviceId[4]; // random device ID in 4 digit hexadecimal (max: ffff) 
byte mac_addr[6];
char deviceId[20];

// 2) configure your topic (or for your use to connect to other people) ----- 
// Topic name needs to be format in "fa2020jp/topic[*]"
// Topic for publishing (if you do not need to publish, you do not need pubTopic. 
//char *pubTopic0 = "fa2020jp/topic0";
//char *pubTopic1 = "fa2020jp/topic1";

// Topic for subscribing
char *subTopic0 = "fa2020jp/topic0";
char *subTopic4 = "fa2020jp/topic4";
// 2) end -----------------------------------------------------------

const char* rootCA = "-----BEGIN CERTIFICATE-----\n" \
*** //need to put own rootCA downloaded from AWS (reference: https://recipe.kc-cloud.jp/archives/9612)
"-----END CERTIFICATE-----\n";
const char* certificate = "-----BEGIN CERTIFICATE-----\n" \
*** //need to put own certificate generated by AWS
"-----END CERTIFICATE-----\n";
const char* privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" \
*** //need to put own privateKey generated by AWS
"-----END RSA PRIVATE KEY-----\n";

WiFiClientSecure httpsClient;
PubSubClient mqttClient(httpsClient);

long randomNumber;

//for stepper motor
#include <Stepper.h>
const int stepsPerRevolution = 1000;
Stepper myStepper(stepsPerRevolution, 12, 14, 27, 26);

void setup() {
    //for stepper motor
    myStepper.setSpeed(30); //middle speed
    Serial.begin(115200);

    pinMode(ledPin, OUTPUT);
    pinMode(DCMotor,OUTPUT);

    // Start WiFi connection
    Serial.println("Connecting to ");
    Serial.print(ssid);
    WiFi.begin(ssid, password);

    // wait until WiFi connected
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("\nWifi Connected.");

    // Configure certification and MQTT Client
    httpsClient.setCACert(rootCA);
    httpsClient.setCertificate(certificate);
    httpsClient.setPrivateKey(privateKey);
    mqttClient.setServer(endpoint, port);
    mqttClient.setCallback(mqttCallback);

    // initialize the random number generator with a fairly random input
    // randomSeed(analogRead(0));

    // Set device Id from Mac Address
    WiFi.macAddress(mac_addr);
    sprintf(deviceId, "%02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);

    connectAWSIoT();
}

void connectAWSIoT() {
    while (!mqttClient.connected()) {
        // generate device ID in 4 digit hexadecimal (max: ffff)
        // generate random decimal max 65536 and convert it to hexadecimal format
        // if device ID is dupulicated with the other device, re-generate device ID.
        // randomNumber = random(65536);
        // ltoa(randomNumber, deviceId, 16);

        if (mqttClient.connect(deviceId)) {
            Serial.print("mqtt Connected - deviceId: ");
            Serial.println(deviceId);
            // QoS 0 is sending message only 1 time (the fastest)
            // QoS 1 is returning puback to publisher after send message successfully
            // QoS 2 is sending message only 1 time with validation (the slowest)
            // AWS IoT only allows QoS 0 or 1. 
            int qos = 0;

            // 3) Specify your topic name to subscribe ----------- 
            mqttClient.subscribe(subTopic0, qos);
            // 3) end --------------------------------------------
            Serial.println("Subscribed.");
        } else {
            Serial.print("mqttClient.connect() Failed - deviceId:");
            Serial.println(randomNumber);
            Serial.print("Error state=");
            Serial.println(mqttClient.state());
            // Wait every 5 seconds until connect to MQTT broker
            delay(5000);
        }
    }
}

long messageSentAt = 0;
int dummyValue = 0;
int dummyValue1 = 0;
char pubMessage0[256];
char pubMessage1[256];


void mqttCallback (char* topic, byte* payload, unsigned int length) {
    DynamicJsonDocument doc(256);

    // Write serial monitor
    Serial.print("Received. topic=");
    Serial.println(topic);

    // deserialize
    DeserializationError error = deserializeJson(doc, payload);
    if (error) {
        Serial.print("deserializeJson() failed with code ");
        Serial.println(error.c_str());
        return;
    }

    // 4) Write your logic on received message -----------------
    // blink LED
    if(doc["seq"].as<int>()){
//    digitalWrite(ledPin, HIGH);
//    //stepper motor
//    Serial.println("clockwise");
//    myStepper.step(stepsPerRevolution);
//    }
    analogWrite(DCMotor,250); //70,72補助ありで回転開始、73自力スタート
    delay(950);  
    analogWrite(DCMotor,0);
    delay(80);
    }
//    int i;
//    for(i=255;i>=0;i--/2){
//      analogWrite(DCMotor,i);
//      delay(10);
//      }
//    for(i=0;i<=255;i++/2){
//      Serial.println(i); 
//      analogWrite(DCMotor,i);
//      delay(10);
//     }

    // dump Json in readable format
    serializeJsonPretty(doc, Serial);
    Serial.println();
    // parse Json (retrieve int value from for each track)
//    Serial.print("track1: ");
//    Serial.println(doc["t1"].as<int>());
//    Serial.print("track2: ");
//    Serial.println(doc["t2"].as<int>());
//    Serial.print("track3: ");
//    Serial.println(doc["t3"].as<int>());
//    Serial.print("track4: ");
//    Serial.println(doc["t4"].as<int>());
//    Serial.print("track5: ");
//    Serial.println(doc["t5"].as<int>());


    // wait for blink LED
    delay(200);
    digitalWrite(ledPin, LOW);
    // 4) end -------------------------------------------------
}

void mqttLoop() {
    if (!mqttClient.connected()) {
        connectAWSIoT();
    }
    mqttClient.loop();

//    // 5) ----- Write your logic for publishing message from here ----- 
//    // (If you are not pubishing anything, you can delete following code)
//
//    // In this case, send message every 5 seconds.
//    long now = millis();
//    if (now - messageSentAt > 3000) {
//        messageSentAt = now;
//
//        // increment dummyValue
//        dummyValue1 = dummyValue++;
//
//        // It looks good to declare JsonDocument in local scope 
//        DynamicJsonDocument doc0(256);
//        DynamicJsonDocument doc1(256);
//
//        // edit data for topic1
//        doc0["t1"]=dummyValue1;  // track1 for topic0
//        doc0["t2"]=dummyValue++; // track2 for topci0
//        doc0["t3"]=0; // track2 for topci0
//        doc0["t4"]=1; // track2 for topci0
//        doc0["t5"]=2; // track5 for topci0
//
//        // edt data for topic2
//        doc1["t1"]=dummyValue1;  // track1 for topic1: same note (at the same time) with doc1(topic1)
//        doc1["t2"]=dummyValue++; // track2 for topic1
//        doc1["t3"]=11; // off     // track3 for topic1
//        doc1["t4"]=12; // on      // track4 for topic1
//        doc1["t5"]=13; // track5 for topci1
//
//        // serialize Json object to message in byte charactors
//        serializeJson(doc0, pubMessage0);
//        serializeJson(doc1, pubMessage1);
//
//        Serial.print("Publishing message to topic0 ");
//        Serial.println(pubTopic0);
//        Serial.println(pubMessage0);
//        Serial.print("Publishing message to topic1 ");
//        Serial.println(pubTopic1);
//        Serial.println(pubMessage1);
//
//        // Publish message to topic
//        mqttClient.publish(pubTopic0, pubMessage0);
//        mqttClient.publish(pubTopic1, pubMessage1);
//        Serial.println("Published.");
//    }
//    // 5) end---------------------------------------------------
}

void loop() {
  mqttLoop();
//  if((digitalRead(button1) == LOW) && (digitalRead(button2) != LOW)){
//  // step one revolution in one direction:
//  Serial.println("clockwise");
//  myStepper.step(stepsPerRevolution);
//  }
//
//  if((digitalRead(button1) != LOW) && (digitalRead(button2) == LOW)){
//  Serial.println("counterclockwise");
//  myStepper.step(-stepsPerRevolution);
//  }
//
//  if((digitalRead(button1) == LOW) && (digitalRead(button2) == LOW)){
//  Serial.println("around the world");
//  myStepper.step(200);
//  }

}

Description of Important Weekly Learning Outcome

Unfortunately, the team members couldn’t meet in the lab because of covid-19. But, doing project online have been done well this time. I think it was nice experience to do project remotely. And to create the device from the idea to the finished work was also good. I could learn about gears and its mechanism in the assignment work.

design file (.f3d file)
mtm_oka_mqtt_aws_final (.ino file)


Appendix

Control Stepper Motor with L298N Motor Driver & Arduino

Using DC motor with MOSFET (Japanese source)