Skip to content

11. Mechanical Design, Machine Design

(WIP)

Mechanical Design

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

Machine Design

Group assignment:

  • actuate and automate your machine
  • document the group project and your individual contribution

Have you answered these questions?

  • Documented the machine building process to the group page
  • Documented your individual contribution to this project on your own website
  • Linked to the group page from your individual page as well as from group page to your individual pages
  • Shown how your team planned and executed the project (Group page)
  • Described problems and how the team solved them (Group page)
  • Listed future development opportunities for this project (Group page)
  • Included your design files (Group page)
  • Optionally included an aprox. 1 min video (1920x1080 HTML5 MP4) + slide (1920x1080 PNG) (Group page)

What I’ve done this week

Group assignment:

Individual assignment:

  • Design the machine by Fusion360
  • Program by Arduino

Overview

This week we created the following machine.

This is a toy for children visiting the lab

Here is how it works

Design the machine by Fusion360

First, I created a machine the base moves in the x-axis direction with a stepper motor

This mechanism is also be used for my final project, a trash separator part.

A stepper motor moves the base to the left and right in the x-axis direction.





First, the following mechanisms were created and tested using cardboard

Test Code

#include <AccelStepper.h>

#define motorInterfaceType 1
const int dirPin = 22;
const int stepPin = 23;

AccelStepper myStepper(motorInterfaceType, stepPin, dirPin);

void setup(){
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

void loop(){
  myStepper.setMaxSpeed(1000);
  myStepper.setAcceleration(50);
  myStepper.setSpeed(200);
  myStepper.moveTo(2000);
  myStepper.runToPosition();
}

Explanation of Codes

Library for using stepper

#include <AccelStepper.h>

Define pins to which DRV8825’s STEP & DIR pins are connected.

const int dirPin = 22;
const int stepPin = 23;

Set motorInterfaceType to 1. (1 means an external stepper driver with Step and Direction pins)

#define motorInterfaceType 1

Create an instance for each stepper motor

AccelStepper myStepper(motorInterfaceType, stepPin, dirPin);

Configures stepper pins to behave as an output

void setup(){
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
}

Sets the maximum permitted speed. The run() function will accelerate up to the speed set by this function. Caution: the maximum speed achievable depends on your processor and clock speed. The default maxSpeed is 1.0 steps per second.

myStepper.setMaxSpeed(1000);

Sets the acceleration/deceleration rate.

Parameters [in] acceleration The desired acceleration in steps per second per second. Must be > 0.0. This is an expensive call since it requires a square root to be calculated. Dont call more ofthen than needed

myStepper.setAcceleration(50);

Sets the desired constant speed

myStepper.setSpeed(200);

Set the target position. The run() function will try to move the motor (at most one step per call) from the current position to the target position set by the most recent call to this function. Caution: moveTo() also recalculates the speed for the next step. If you are trying to use constant speed movements, you should call setSpeed() after calling moveTo().

myStepper.moveTo(2000);

Moves the motor (with acceleration/deceleration) to the target position and blocks until it is at position. Dont use this in event loops, since it blocks.

myStepper.runToPosition();

BOM

This machine need the following materials.

Sorting machine part

Parts Required Number Use
shaft φ8 mm x 800 mm 2 The two shafts serve as guides for moving the platform in parallel.
Stepper Motor Nema17 2 To control the bear’s marionette / To move the base
Servo Motor SG90 3 To rotate the panel that will be the target (boy, flower, pig)
timing belt 1 Belt to transfer the power of the stepper motor to the base
timing pulley 1 Pulleys to operate the belt
Linear Bushings LM-8UU 2 Linear bushings to allow the base to move smoothly over the shaft
Half Screw with Hexagon Hole 1 Shaft for rotating pulley
stepper_case.stl [.stl] 1 Case to put into stepper motors
roller_case.stl [.stl] 1 Case to put into pulley
base.stl [.stl] 1 moving base to attach bear marionette

Electric circuit

The electric circuit was built as follows

The following article is a reference for the stepper motor circuit

Drv8825 Stepper Motor Driver Esp32 Tutorial

Explanation of the motor driver (DRV8825)

Here for information on adjusting the current in advance preparation.

Atsufumi Suzuki week10 groupwork

These are the control pins which are used to control the where EN, SLP and RST control the power states and DIR and STEP control the input.

SLP and RST are shorted because they are not used in this project.

M0, M1, and M2 are pins for use when using microstep, but are not used this time

VMOT, GND: This is the stepper motor power supply pins. Connect 8.2-45V external power supply with VMOT and common ground.

The DRV8825 motor driver module also features a FAULT pin. This is used for over current protection. The pin goes in a LOW state disabling the driver due to over current protection. What happens is that the FAULT pin which is shorted with the SLP pin when goes in a LOW state that means that the driver is disabled.

Created shafts (φ8 mm x 800 mm)

Create linear bushing and thread it through the shaft

Linear bush and Timing belt can be attached to the back of the base.

Attached the base.

Attached the stepper motor and the rotary shaft screw

Created the case for the stepper motor and the rotary shaft screw



3d printed and assembled the following




Program by Arduino

The code is almost the same as the webserver programs for week08 and week10, with some changes in function names and stepping motor parameters.

Referenced

esp32 useful wi-fi functions arduino

AccelStepper Class Reference

#include <WiFi.h>
#include <WebServer.h>
#include <ESP32Servo.h>
#include <AccelStepper.h>

// WiFi
#define SSID "ENV_WIFI"
#define PASS "ENV_PASS"

// Servo
Servo myservo;
Servo myservo2;
Servo myservo3;

int minUs = 500;
int maxUs = 2400;

// Stepper
#define motorInterfaceType 1
const int dirPin = 22;
const int stepPin = 23;

const int dirPin2 = 16;
const int stepPin2 = 17;

AccelStepper myStepper(motorInterfaceType, stepPin, dirPin);

AccelStepper myStepper2(motorInterfaceType, stepPin2, dirPin2);


// Web server
WebServer server(80);

void setup(){

  Serial.begin(115200);

  myservo.setPeriodHertz(50);
  myservo.attach(4, minUs, maxUs);

  myservo2.setPeriodHertz(50);
  myservo2.attach(19, minUs, maxUs);

  myservo3.setPeriodHertz(50);
  myservo3.attach(21, minUs, maxUs);

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

  pinMode(stepPin2, OUTPUT);
  pinMode(dirPin2, OUTPUT);

  connectWiFi();
  server.on("/", handleRoot);
  server.on("/boy", boy);
  server.on("/flower", flower);
  server.on("/pig", pig);
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  server.handleClient();
}

void connectWiFi(){
  WiFi.begin(SSID, PASS);
  Serial.println();
  while(WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("WiFi connected");
  Serial.println(WiFi.localIP());
}

void handleRoot(){
  server.send(200, "text/plain", "OK");
}

void boy(){

  Serial.println("boy");
  myStepper.setMaxSpeed(1000);
  myStepper.setAcceleration(50);
  myStepper.setSpeed(200);
  myStepper.moveTo(1100);
  myStepper.runToPosition();

  myStepper2.setMaxSpeed(1000);
  myStepper2.setAcceleration(50);
  myStepper2.setSpeed(200);
  myStepper2.moveTo(200);
  myStepper2.runToPosition();

  delay(1000);

  myservo.write(180);

  myStepper2.setMaxSpeed(1000);
  myStepper2.setAcceleration(50);
  myStepper2.setSpeed(200);
  myStepper2.moveTo(0);
  myStepper2.runToPosition();

  myStepper.setMaxSpeed(1000);
  myStepper.setAcceleration(50);
  myStepper.setSpeed(200);
  myStepper.moveTo(0);
  myStepper.runToPosition();

  myservo.write(0);

  server.send(200, "text/plain", "boy");

}

void flower(){

  Serial.println("flower");
  myStepper.setMaxSpeed(1000);
  myStepper.setAcceleration(50);
  myStepper.setSpeed(200);
  myStepper.moveTo(2000);
  myStepper.runToPosition();

  myStepper2.setMaxSpeed(1000);
  myStepper2.setAcceleration(50);
  myStepper2.setSpeed(200);
  myStepper2.moveTo(200);
  myStepper2.runToPosition();

  delay(1000);
  myservo2.write(0);

  myStepper2.setMaxSpeed(1000);
  myStepper2.setAcceleration(50);
  myStepper2.setSpeed(200);
  myStepper2.moveTo(0);
  myStepper2.runToPosition();

  myStepper.setMaxSpeed(1000);
  myStepper.setAcceleration(50);
  myStepper.setSpeed(200);
  myStepper.moveTo(0);
  myStepper.runToPosition();

  myservo2.write(180);

  server.send(200, "text/plain", "flower");

}

void pig(){

  Serial.println("pig");
  myStepper.setMaxSpeed(1000);
  myStepper.setAcceleration(50);
  myStepper.setSpeed(200);
  myStepper.moveTo(3000);
  myStepper.runToPosition();

  myStepper2.setMaxSpeed(1000);
  myStepper2.setAcceleration(50);
  myStepper2.setSpeed(200);
  myStepper2.moveTo(200);
  myStepper2.runToPosition();

  delay(1000);

  myservo3.write(180);

  myStepper2.setMaxSpeed(1000);
  myStepper2.setAcceleration(50);
  myStepper2.setSpeed(200);
  myStepper2.moveTo(0);
  myStepper2.runToPosition();

  myStepper.setMaxSpeed(1000);
  myStepper.setAcceleration(50);
  myStepper.setSpeed(200);
  myStepper.moveTo(0);
  myStepper.runToPosition();

  myservo3.write(0);

  server.send(200, "text/plain", "pig");
}

Explanation of Codes

Library for using wifi

#include <WiFi.h>

Library for use as a web server

#include <WebServer.h>

Library for using servo

#include <ESP32Servo.h>

Library for using stepper

#include <AccelStepper.h>

Define SSID and password

#define SSID "ENV_WIFI"
#define PASS "ENV_PASS"

Create an instance for each servo motor

Servo myservo;
Servo myservo2;
Servo myservo3;

Published values for SG90 servos

int minUs = 500;
int maxUs = 2400;

Define pins to which DRV8825’s STEP & DIR pins are connected.

const int dirPin = 22;
const int stepPin = 23;

const int dirPin2 = 16;
const int stepPin2 = 17;

Set motorInterfaceType to 1. (1 means an external stepper driver with Step and Direction pins)

#define motorInterfaceType 1

Create an instance for each stepper motor

AccelStepper myStepper(motorInterfaceType, stepPin, dirPin);

AccelStepper myStepper2(motorInterfaceType, stepPin2, dirPin2);

Create an instance of the web server to process the web server with the name server. The port number is set to the common port 80

WebServer server(80);

The data transfer rate for serial communication was specified at 115200 bps(baud)

Serial.begin(115200);

Use 50hz servo

servo.attach(pin, min, max)

  • pin: the number of the pin that the servo is attached to

  • min (optional): the pulse width, in microseconds, corresponding to the minimum (0-degree) angle on the servo (defaults to 544)

  • max (optional): the pulse width, in microseconds, corresponding to the maximum (180-degree) angle on the servo (defaults to 2400)

attach() documentation

  myservo.setPeriodHertz(50);
  myservo.attach(4, minUs, maxUs);

  myservo2.setPeriodHertz(50);
  myservo2.attach(19, minUs, maxUs);

  myservo3.setPeriodHertz(50);
  myservo3.attach(21, minUs, maxUs);

Configures stepper pins to behave as an output

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

  pinMode(stepPin2, OUTPUT);
  pinMode(dirPin2, OUTPUT);

Connect WiFi

 connectWiFi();

When starting the web server, define a function for each address.

server.on("/", handleRoot);
server.on("/boy", boy);
server.on("/flower", flower);
server.on("/pig", pig);
server.begin();
Serial.println("HTTP server started");

In void loop(), only “WebServer.handleClient()” is called, and the processing is described in the each function

void loop() {
  server.handleClient();
}

Configure Wifi Connect settings

void connectWiFi(){
  WiFi.begin(SSID, PASS);
  Serial.println();
  while(WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("WiFi connected");
  Serial.println(WiFi.localIP());
}

WiFi.begin() to connect to a network

WiFi.begin(SSID, PASS);

Connecting to a Wi-Fi network can take a while, so we usually add a while loop that keeps checking if the connection was already established by using WiFi.status(). When the connection is successfully established, it returns WL_CONNECTED

while(WiFi.status() != WL_CONNECTED){
  delay(500);
  Serial.print(".");
}
void handleRoot(){
  server.send(200, "text/plain", "OK");
}

Return value to client

HTTP 200 OK is the response code returned if the request is successful

server.send(200, "text/plain", "OK");

The main part is writen in the following three functions.

The contents of the following functions are almost the same, the only difference is that they control the moving position of the stepper motors and the different servo motors.

// Flow for boy panel
void boy(){}

// Flow for flower panel
void flower(){}

// Flow for pig panel
void pig(){}

Here is an example of boy() code

void boy(){

  Serial.println("boy");

  // Move the base
  myStepper.setMaxSpeed(1000);
  myStepper.setAcceleration(50);
  myStepper.setSpeed(200);
  myStepper.moveTo(1100);
  myStepper.runToPosition();

  // The bear marionette gears move.
  myStepper2.setMaxSpeed(1000);
  myStepper2.setAcceleration(50);
  myStepper2.setSpeed(200);
  myStepper2.moveTo(200);
  myStepper2.runToPosition();

  delay(1000);


  // The target panel is flipped over.
  myservo.write(180);


  // The bear marionette gears return to the previous position..
  myStepper2.setMaxSpeed(1000);
  myStepper2.setAcceleration(50);
  myStepper2.setSpeed(200);
  myStepper2.moveTo(0);
  myStepper2.runToPosition();


  // Base returns to original position
  myStepper.setMaxSpeed(1000);
  myStepper.setAcceleration(50);
  myStepper.setSpeed(200);
  myStepper.moveTo(0);
  myStepper.runToPosition();


  // The target panel is flipped over. 
  myservo.write(0);

  server.send(200, "text/plain", "boy");

}

Sets the maximum permitted speed. The run() function will accelerate up to the speed set by this function. Caution: the maximum speed achievable depends on your processor and clock speed. The default maxSpeed is 1.0 steps per second.

myStepper.setMaxSpeed(1000);

Sets the acceleration/deceleration rate.

Parameters [in] acceleration The desired acceleration in steps per second per second. Must be > 0.0. This is an expensive call since it requires a square root to be calculated. Dont call more ofthen than needed

myStepper.setAcceleration(50);

Sets the desired constant speed

myStepper.setSpeed(200);

Set the target position. The run() function will try to move the motor (at most one step per call) from the current position to the target position set by the most recent call to this function. Caution: moveTo() also recalculates the speed for the next step. If you are trying to use constant speed movements, you should call setSpeed() after calling moveTo().

myStepper.moveTo(1100);

Moves the motor (with acceleration/deceleration) to the target position and blocks until it is at position. Dont use this in event loops, since it blocks.

myStepper.runToPosition();

Image recognition part

Created the following parts to hold the Raspberry Pi camera in place.

Parts Quantity
Raspberry Pi 4 1
Camera module 1
Tact Switch 1
10kΩ Resistor 1

Electric circuit

The Electric circuit was built as follows

Created with reference to the following article

I used teachable machine for machine learning

Teachable Machine

teachable machine allows you to have machine learning on your app and use models in python or javaScript

Select Get Started => Image Project

In this case, select the standard image model (224px x 224px, color image) to output in sensorflowlite format.

The following screen appear

Add the images to have recognized to each class.

This time, recognized the following three images

The picture was created by Kurumi Shiowaki-san

Imported each images.

Export in tensorflow lite format

Program by python

import time
import tensorflow as tf
import numpy as np
import cv2
import RPi.GPIO as GPIO
import requests as req
from imutils.video.pivideostream import PiVideoStream

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(10, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

interpreter = tf.lite.Interpreter(model_path="model_unquant.tflite")
interpreter.allocate_tensors()

input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

target_height = input_details[0]["shape"][1]
target_width = input_details[0]["shape"][2]

f = open("labels.txt", "r")
lines = f.readlines()
f.close()
classes = {}
for line in lines:
    pair = line.strip().split(maxsplit=1)
    classes[int(pair[0])] = pair[1].strip()

def detect(frame):

    resized = cv2.resize(frame, (target_width, target_height))
    input_data = np.expand_dims(resized, axis=0)
    input_data = (np.float32(input_data) - 127.5) / 127.5
    interpreter.set_tensor(input_details[0]["index"], input_data)

    interpreter.invoke()
    detection = interpreter.get_tensor(output_details[0]["index"])
    return detection

def draw_detection(frame, detection):
    for i, s in enumerate(detection[0]):
        tag = f"{classes[i]}: {s*100:.2f}%"
        cv2.putText(frame, tag, (10, 20 + 20 * i),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
    return frame

def main():
    camera = PiVideoStream(resolution=(512, 400)).start()
    time.sleep(2)

    while True:
        frame = camera.read()
        detection = detect(frame)
        value = classes[detection.tolist()[0].index(
            max(detection.tolist()[0]))]
        drawn = draw_detection(frame, detection)
        cv2.imshow("frame", drawn)
        if GPIO.input(10) == GPIO.HIGH:
            request = 'ESP32_IP_Address' + '/' + value
            response = req.get(request)
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break

    camera.stop()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

Explanation of Codes

First imported the following library modules

import time
import tensorflow as tf
import numpy as np
import cv2
import RPi.GPIO as GPIO
import requests as req
from imutils.video.pivideostream import PiVideoStream

Module for handling time.

import time

Import tensorflow

library for use in machine learning

import tensorflow as tf

Library for fast numerical calculation

Import numpy as np

Import OpenCV

Library for processing images and videos

import cv2

Library for controlling RaspberryPi with Python

import RPi.GPIO as GPIO

Python HTTP communication library.

import requests as req

Library for both PiCamera modules and USB cameras

from imutils.video.pivideostream import PiVideoStream

Use GPIO.setwarnings(False) to disable warnings.

GPIO.setwarnings(False)

This is for GPIO pin numbering setup

GPIO.setmode(GPIO.BOARD)

Set pin 10 to be an input pin and set initial value to be pulled low

GPIO.setup(10, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

Load a TFLite model

interpreter = tf.lite.Interpreter(model_path="model_unquant.tflite")

Memory allocation. This is required immediately after model loading.

interpreter.allocate_tensors()

Get the properties of the input and output layers of the training model.

input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

Obtaining the tensor data configuration of the input layer

target_height = input_details[0]["shape"][1]
target_width = input_details[0]["shape"][2]

The variable f contains data for reading and writing files. This is called a file object.

Assign the contents of labels.txt as read-only data to variable f.

f = open("labels.txt", "r")

readlines() reads the entire contents of the file, line by line, into a list

lines = f.readlines()

When a machine learning model is exported from teachable machine, labels.tet is exported at the same time.

The content of labels.txt is as follow

0 boy
1 flower
2 pig

As a rule, when you are finished using a file object, you must call the close() method to close (close) it.

If you leave the file without calling close(), it will be recognized that the file is still in use. This will inhibit other programs from attempting to use the same file.

f.close()

Assign dictionary to the variable class

classes = {}

Each of the three is added to classes as {key: value} in labels.txt

0 boy
1 flower
2 pig
for line in lines:
    pair = line.strip().split(maxsplit=1)
    classes[int(pair[0])] = pair[1].strip()

It goes as follows

classes = {
  0: boy
  1: flower
  2: pig
}

Explain inside the main function.

def main():
    camera = PiVideoStream(resolution=(512, 400)).start()
    time.sleep(2)

    while True:
        frame = camera.read()
        detection = detect(frame)
        value = classes[detection.tolist()[0].index(
            max(detection.tolist()[0]))]
        drawn = draw_detection(frame, detection)
        cv2.imshow("frame", drawn)
        if GPIO.input(10) == GPIO.HIGH:
            request = 'ESP32_IP_Address' + '/' + value
            response = req.get(request)
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break

    camera.stop()
    cv2.destroyAllWindows()

Open camera stream

PiVideoStream is a module for PiCamera

camera = PiVideoStream(resolution=(512, 400)).start()
time.sleep(2)

Inside while True: process is looped

while True:
    frame = camera.read()
    detection = detect(frame)
    value = classes[detection.tolist()[0].index(
        max(detection.tolist()[0]))]
    drawn = draw_detection(frame, detection)
    cv2.imshow("frame", drawn)
    if GPIO.input(10) == GPIO.HIGH:
        request = 'ESP32_IP_Address' + '/' + value
        response = req.get(request)
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

camera.stop()
cv2.destroyAllWindows()

read() is used to retrieve a single photo from the frame.

frame = camera.read()
detection = detect(frame)

The contents of detect() are as follows

def detect(frame):

    resized = cv2.resize(frame, (target_width, target_height))
    input_data = np.expand_dims(resized, axis=0)
    input_data = (np.float32(input_data) - 127.5) / 127.5
    interpreter.set_tensor(input_details[0]["index"], input_data)

    interpreter.invoke()
    detection = interpreter.get_tensor(output_details[0]["index"])
    return detection

this will resize the image to have target_width (width) and target_height (height):

resized = cv2.resize(frame, (target_width, target_height))

np.expand_dims() adds a new dimension of size 1

input_data = np.expand_dims(resized, axis=0)

Each RGB 0 ~ 255 pixel value should fall in the range of -1 to 1

input_data = (np.float32(input_data) - 127.5) / 127.5

Set pointer to tensor data in index

interpreter.set_tensor(input_details[0]["index"], input_data)

Predicts classification results

interpreter.invoke()

Inference results are stored in the index of output_details

detection = interpreter.get_tensor(output_details[0]["index"])

Returns the value of detection

return detection

Pick the highest value in classes.

value = classes[detection.tolist()[0].index(
        max(detection.tolist()[0]))]
classes = {
  0: boy
  1: flower
  2: pig
}

For example If boy 90% , flower 5% ,pig 5% Boy is selected.

drawn = draw_detection(frame, detection)

The contents of detect() are as follows

def draw_detection(frame, detection):
  for i, s in enumerate(detection[0]):
      tag = f"{classes[i]}: {s*100:.2f}%"
      cv2.putText(frame, tag, (10, 20 + 20 * i),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
  return frame

Retrieve index numbers and scores one by one

  for i, s in enumerate(detection[0]):

Use the percentages in 100 such as boy: 90%

tag = f"{classes[i]}: {s*100:.2f}%"

cv2.putText(img, text, org, fontFace, fontScale, color, thickness)

img: OpenCV image

text: text

org: The coordinates of the lower left corner of the text in (x, y)

fontFace: Font. Only a few types can be specified, such as cv2.FONT_HERSHEY_SIMPLEX

color: Text color. (blue, green, red)

thickness: Line thickness. Optional, default value is 1

cv2.putText(frame, tag, (10, 20 + 20 * i),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)

Returns the value of frame

return frame

Display the image on the window

The first argument is a string window name. The second argument is the image to be displayed. Multiple windows can be displayed as needed, but each window must have a different name.

cv2.imshow("frame", drawn)

When the button is pressed, HTTP GET request is sent by adding /value (boy or flower or pig) to the ESP32 listening as webserver

if GPIO.input(10) == GPIO.HIGH:
    request = 'ESP32_IP_Address' + '/' + value
    response = req.get(request)

Exit while loop if q key is pressed

if cv2.waitKey(1) & 0xFF == ord("q"):
    break

Only when the module is executed directly, the code to be executed is written in if block

if __name__ == "__main__":
    main()

What I learned

  • Although the machine we created this time had a simple structure, it was interesting to see how the rotation of the stepping motors and servo motors could be used to perform different operations!

Appendix


Last update: May 2, 2022