MohammadReza Sharifi
Published © MIT

Smart Anti-Kickback System for Electric Drills

Real-Time Safety Architecture Using Arduino Nano 33 BLE Sense

AdvancedFull instructions provided3 hours3
Smart Anti-Kickback System for Electric Drills

Things used in this project

Hardware components

Nano 33 BLE Sense
Arduino Nano 33 BLE Sense
×1
Gravity: Digital 5A Relay Module
DFRobot Gravity: Digital 5A Relay Module
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Circuit Diagram

Code

MainApp

Arduino
#include <Arduino_LSM9DS1.h>

// ======================= PIN CONFIG =======================
#define CUTOFF_PIN   9
#define LED_STATUS   13

// ======================= TIMING ===========================
#define SAMPLE_RATE_HZ     500.0f
#define DT                 (1.0f / SAMPLE_RATE_HZ)

// ======================= FILTER ===========================
#define LPF_CUTOFF_HZ      120.0f
float lpf_alpha;

// ======================= THRESHOLDS =======================
#define ALPHA_CRIT         7500.0f   // deg/s^2  ( )
#define SPEED_DROP_RATIO   0.45f
#define MIN_ROT_SPEED      20.0f     // deg/s  (     )

// ======================= STATES ===========================
bool systemArmed   = false;
bool cutoffLatched = false;

// ======================= IMU VARS =========================
float gyroBiasZ = 0.0f;

float omegaZ_raw  = 0.0f;
float omegaZ_filt = 0.0f;
float omegaZ_prev = 0.0f;
float alphaZ      = 0.0f;

// ======================= TIMERS ===========================
unsigned long armTime = 0;

// ======================= FUNCTIONS ========================
float lowPass(float prev, float input) {
  return prev + lpf_alpha * (input - prev);
}

void triggerCutoff() {
  cutoffLatched = true;
  digitalWrite(CUTOFF_PIN, HIGH);
  digitalWrite(LED_STATUS, HIGH);
  Serial.println("!!! ANTI-KICKBACK ACTIVATED !!!");
}

void calibrateGyro() {
  const int N = 600;
  float sum = 0;

  Serial.println("Calibrating gyro bias... Keep drill still");

  for (int i = 0; i < N; i++) {
    float gx, gy, gz;
    if (IMU.gyroscopeAvailable()) {
      IMU.readGyroscope(gx, gy, gz);
      sum += gz;
    }
    delay(2);
  }

  gyroBiasZ = sum / N;
  Serial.print("Gyro Z bias = ");
  Serial.println(gyroBiasZ);
}

// ======================= SETUP ============================
void setup() {
  pinMode(CUTOFF_PIN, OUTPUT);
  pinMode(LED_STATUS, OUTPUT);

  digitalWrite(CUTOFF_PIN, LOW);
  digitalWrite(LED_STATUS, LOW);

  Serial.begin(115200);
  while (!Serial);

  if (!IMU.begin()) {
    while (1) {
      Serial.println("IMU INIT FAILED");
      delay(1000);
    }
  }

  // LPF coefficient
  float rc = 1.0f / (2.0f * PI * LPF_CUTOFF_HZ);
  lpf_alpha = DT / (DT + rc);

  calibrateGyro();

  armTime = millis();
  Serial.println("System warming up...");
}

// ======================= LOOP =============================
void loop() {

  // ===== LATCH MODE =====
  if (cutoffLatched) {
    delay(10);
    return;
  }

  // ===== ARMING PHASE =====
  if (!systemArmed) {
    if (millis() - armTime > 2500) {   // 2.5s warm-up
      systemArmed = true;
      Serial.println("System ARMED");
    }
  }

  float gx, gy, gz;

  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(gx, gy, gz);

    // ===== AXIS MAPPING =====
    // : Z = Z
    omegaZ_raw = gz - gyroBiasZ;

    // ===== FILTER =====
    omegaZ_filt = lowPass(omegaZ_filt, omegaZ_raw);

    // ===== DERIVATIVE =====
    alphaZ = (omegaZ_filt - omegaZ_prev) / DT;

    // ===== LOGIC CONDITIONS =====
    bool highAngularAccel = abs(alphaZ) > ALPHA_CRIT;
    bool suddenSpeedDrop  = abs(omegaZ_filt) < SPEED_DROP_RATIO * abs(omegaZ_prev);
    bool realMotion       = abs(omegaZ_prev) > MIN_ROT_SPEED;
    bool systemReady      = systemArmed;

    // ===== FINAL DECISION =====
    if (systemReady && realMotion && highAngularAccel && suddenSpeedDrop) {
      triggerCutoff();
    }

    omegaZ_prev = omegaZ_filt;
  }

  delayMicroseconds(200); // ~500Hz
}

Credits

MohammadReza Sharifi
15 projects • 9 followers
I'm an Electrical Engineer and Maker.

Comments