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
#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)
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 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!
Links to Files and Code¶
-
base.stl [.stl]
-
roller_case.stl [.stl]
-
stepper_case.stl [.stl]
-
camera_part_1.stl [.stl]
-
camera_part_2.stl [.stl]
-
camera_part_3.stl [.stl]
-
camera_part_4.stl [.stl]
-
Sorter.ino [.ino]
-
Stepper_test.ino [.ino]
-
image_recognition.py [.py]
-
labels.txt[.txt]
-
model_unquant.tflite[.tflite]