Autocutter: The Automated Cutting Board
A NEMA 17 moves the knife, a servo clamps the food, an ultrasonic sensor decides when to stop cutting.
Devices & Components
1
Grove - Servo
1
Arduino Uno Rev3
1
Nema 17 stepper motor
1
HCSR04
1
TB6600 motor driver
Hardware & Tools
1
driving belt
1
bench power supply
1
aluminium extrusion
Software & Tools
Arduino IDE
1
Blender Software
Project description
Code
cpp
1/* 2 * Automated Cutting Board 3 * 4 * Sequence: 5 * 1. Close clamp until HC-SR04 detects it's gripping the workpiece 6 * 2. Store clamp position as cut boundary 7 * 3. Home the knife carriage to one end 8 * 4. Move carriage to opposite end at full speed 9 * 5. Slam knife down, lift back up 10 * 6. Step carriage back toward clamp, repeat cut 11 * 7. Stop 2cm before clamp position 12 * 8. Home knife servo, unclamp 13 * 14 * Hardware: 15 * - Arduino Uno 16 * - NEMA 17 + TB6600 driver (carriage linear drive) 17 * - DM996 servo (knife, 35 kg·cm) 18 * - SG90-class servo (clamp, 15 kg·cm) 19 * - HC-SR04 ultrasonic sensor (workpiece detection) 20 */ 21 22#include <AccelStepper.h> 23#include <Servo.h> 24 25// ---------------- PIN ASSIGNMENTS ---------------- 26#define STEP_PIN 3 27#define DIR_PIN 4 28#define ENABLE_PIN 5 29 30#define KNIFE_SERVO 9 31#define CLAMP_SERVO 10 32 33#define TRIG_PIN 7 34#define ECHO_PIN 8 35 36#define START_BUTTON 2 37 38// ---------------- MOTION PARAMETERS -------------- 39// Stepper (carriage) 40const int STEPS_PER_MM = 80; 41const long CARRIAGE_LENGTH = 200; 42const float MAX_SPEED = 4000; 43const float HOMING_SPEED = 1500; 44const float ACCELERATION = 3000; 45 46// Knife servo 47const int KNIFE_UP_ANGLE = 10; 48const int KNIFE_DOWN_ANGLE = 140; 49const int KNIFE_SLAM_DELAY = 250; 50const int KNIFE_LIFT_DELAY = 300; 51 52// Clamp servo 53const int CLAMP_OPEN_ANGLE = 0; 54const int CLAMP_MAX_ANGLE = 180; 55const int CLAMP_STEP_DEGREES = 2; 56const int CLAMP_STEP_DELAY = 60; 57 58// Cutting 59const int CUT_INCREMENT_MM = 4; 60const int SAFETY_OFFSET_MM = 20; 61 62// HC-SR04 63const float CLAMP_GRIP_THRESHOLD_CM = 1.0; 64const int SENSOR_SAMPLES = 5; 65 66// ---------------- GLOBALS ----------------------- 67AccelStepper carriage(AccelStepper::DRIVER, STEP_PIN, DIR_PIN); 68Servo knife; 69Servo clamp; 70 71float clampDetectedDistanceCm = 0; 72 73// ---------------- SETUP ------------------------- 74void setup() { 75 Serial.begin(115200); 76 77 pinMode(ENABLE_PIN, OUTPUT); 78 digitalWrite(ENABLE_PIN, LOW); 79 80 pinMode(TRIG_PIN, OUTPUT); 81 pinMode(ECHO_PIN, INPUT); 82 pinMode(START_BUTTON, INPUT_PULLUP); 83 84 carriage.setMaxSpeed(MAX_SPEED); 85 carriage.setAcceleration(ACCELERATION); 86 87 knife.attach(KNIFE_SERVO); 88 clamp.attach(CLAMP_SERVO); 89 90 knife.write(KNIFE_UP_ANGLE); 91 clamp.write(CLAMP_OPEN_ANGLE); 92 93 Serial.println(F("Ready. Press button to start cut cycle.")); 94} 95 96// ---------------- LOOP -------------------------- 97void loop() { 98 if (digitalRead(START_BUTTON) == LOW) { 99 delay(50); // debounce 100 if (digitalRead(START_BUTTON) == LOW) { 101 runCutCycle(); 102 while (digitalRead(START_BUTTON) == LOW) { /* wait for release */ } 103 } 104 } 105} 106 107// ---------------- HIGH-LEVEL SEQUENCE ------------ 108void runCutCycle() { 109 Serial.println(F("--- Starting cut cycle ---")); 110 111 // 1. Close clamp until HC-SR04 confirms contact 112 if (!closeClampUntilGrip()) { 113 Serial.println(F("ERROR: No workpiece detected. Aborting.")); 114 clamp.write(CLAMP_OPEN_ANGLE); 115 return; 116 } 117 118 // 2. Home the carriage (knife starts at far end from clamp) 119 homeCarriage(); 120 121 // 3. Move to opposite end at full speed 122 long farEndSteps = (long)CARRIAGE_LENGTH * STEPS_PER_MM; 123 Serial.println(F("Fast traverse to start of cut.")); 124 carriage.moveTo(farEndSteps); 125 while (carriage.distanceToGo() != 0) carriage.run(); 126 127 // 4. First slam 128 slamKnife(); 129 130 // 5. Incremental cutting toward the clamp 131 // Stop SAFETY_OFFSET_MM before the clamp's detected position. 132 long stopPositionSteps = (long)SAFETY_OFFSET_MM * STEPS_PER_MM; 133 long currentTarget = farEndSteps; 134 135 while (currentTarget > stopPositionSteps) { 136 currentTarget -= (long)CUT_INCREMENT_MM * STEPS_PER_MM; 137 if (currentTarget < stopPositionSteps) currentTarget = stopPositionSteps; 138 139 Serial.print(F("Moving to step: ")); 140 Serial.println(currentTarget); 141 142 carriage.moveTo(currentTarget); 143 while (carriage.distanceToGo() != 0) carriage.run(); 144 145 slamKnife(); 146 } 147 148 // 6. Home the knife and unclamp 149 knife.write(KNIFE_UP_ANGLE); 150 delay(KNIFE_LIFT_DELAY); 151 152 Serial.println(F("Unclamping.")); 153 clamp.write(CLAMP_OPEN_ANGLE); 154 delay(500); 155 156 // Return carriage to home for next cycle 157 homeCarriage(); 158 159 Serial.println(F("--- Cycle complete ---")); 160} 161 162// ---------------- CLAMP ------------------------- 163// Close clamp incrementally; watch the HC-SR04 for a distance drop that 164// indicates the clamp has contacted and is now pushing the workpiece. 165bool closeClampUntilGrip() { 166 Serial.println(F("Closing clamp...")); 167 168 float baselineCm = readDistanceCm(); 169 if (baselineCm <= 0) { 170 Serial.println(F("Sensor read failed.")); 171 return false; 172 } 173 Serial.print(F("Baseline distance: ")); 174 Serial.print(baselineCm); 175 Serial.println(F(" cm")); 176 177 for (int angle = CLAMP_OPEN_ANGLE; angle <= CLAMP_MAX_ANGLE; angle += CLAMP_STEP_DEGREES) { 178 clamp.write(angle); 179 delay(CLAMP_STEP_DELAY); 180 181 float d = readDistanceCm(); 182 if (d <= 0) continue; 183 184 // When the clamp contacts the workpiece and starts pushing it, 185 // the measured distance drops below baseline by more than the threshold. 186 if ((baselineCm - d) >= CLAMP_GRIP_THRESHOLD_CM) { 187 clampDetectedDistanceCm = d; 188 Serial.print(F("Workpiece gripped at angle ")); 189 Serial.print(angle); 190 Serial.print(F(", distance ")); 191 Serial.print(d); 192 Serial.println(F(" cm")); 193 return true; 194 } 195 } 196 197 return false; 198} 199 200// ---------------- KNIFE ------------------------- 201void slamKnife() { 202 knife.write(KNIFE_DOWN_ANGLE); 203 delay(KNIFE_SLAM_DELAY); 204 knife.write(KNIFE_UP_ANGLE); 205 delay(KNIFE_LIFT_DELAY); 206} 207 208// ---------------- CARRIAGE HOMING --------------- 209// No limit switch — home by driving hard toward the motor end and 210// resetting position to zero. TB6600 will skip steps against the end-stop 211// rather than damage anything at these speeds/torques. 212void homeCarriage() { 213 Serial.println(F("Homing carriage.")); 214 carriage.setMaxSpeed(HOMING_SPEED); 215 carriage.moveTo(-100000L); 216 unsigned long t0 = millis(); 217 while (millis() - t0 < 4000) { 218 carriage.run(); 219 } 220 carriage.setCurrentPosition(0); 221 carriage.setMaxSpeed(MAX_SPEED); 222 Serial.println(F("Carriage homed.")); 223} 224 225// ---------------- HC-SR04 ----------------------- 226float readDistanceCm() { 227 228 float samples[SENSOR_SAMPLES]; 229 int valid = 0; 230 231 for (int i = 0; i < SENSOR_SAMPLES; i++) { 232 digitalWrite(TRIG_PIN, LOW); 233 delayMicroseconds(2); 234 digitalWrite(TRIG_PIN, HIGH); 235 delayMicroseconds(10); 236 digitalWrite(TRIG_PIN, LOW); 237 238 long duration = pulseIn(ECHO_PIN, HIGH, 30000UL); 239 if (duration > 0) { 240 samples[valid++] = duration * 0.0343f / 2.0f; 241 } 242 delay(10); 243 } 244 245 if (valid == 0) return -1; 246 247 // Simple bubble sort for median (N is small) 248 for (int i = 0; i < valid - 1; i++) { 249 for (int j = 0; j < valid - i - 1; j++) { 250 if (samples[j] > samples[j + 1]) { 251 float tmp = samples[j]; 252 samples[j] = samples[j + 1]; 253 samples[j + 1] = tmp; 254 } 255 } 256 } 257 258 return samples[valid / 2]; 259}
Comments
Only logged in users can leave comments