ShockBox

by spooderflash in Circuits > Electronics

248 Views, 0 Favorites, 0 Comments

ShockBox

EindProduct.jpg

DISCLAIMER: Ik raad het niet aan om dit na te maken aangezien er wordt gewerkt met elektrische schokken. De vliegenmepper heeft geen doorbrandbeveiliging en kan dus bij langdurige blootstelling aan de huid brandwonden veroorzaken. Dit is puur educatief bedoeld!

Voor dit project heb ik een apparaat gemaakt wat de gebruiker een schok geeft als herinnering om eens in de zoveel tijd op te staan van je werkplek. Aangezien het zitten wordt gezien als het nieuwe roken, besloot ik hier een product voor te maken om dit tegen te gaan.

De grote strap gaat om het linker of rechter bovenbeen waarbij het kleine doosje met de pijl naar de gebruiker wijst en de tekst voor deze persoon normaal leesbaar is. Hierin zit de gyroscope/accelerometer. Van de twee polsarmbandjes gaat er één om de linkerpols en de ander om de rechterpols. Wanneer de Arduino UNO aan wordt gezet gaat er een timer lopen die bijhoudt hoe lang de gyroscope/accelerometer tussen bepaalde waardes blijft. Wanneer iemand voor een x tijd binnen deze waardes blijft wordt er een signaal gestuurd naar de relais die ervoor zorgt dat het schokcircuit de schok uitdeelt op de plek waar de polsarmbandjes zijn bevestigd. Wanneer er een schok gegeven is wordt de timer weer gereset. Wanneer iemand gaat staan, na of voordat de schok heeft plaatsgevonden, meet de gyroscope/accelerometer een bepaalde waardeverandering waardoor er na het verstrijken van de timer dit keer niet een schok wordt gegeven. Wanneer iemand gaat zitten is er pas weer de mogelijkheid om te kunnen worden geschokt.

Tijdens mijn onderzoek ben ik erachter gekomen dat je eigenlijk heel eenvoudig bestaande circuits kan aanpassen zodat de arduino daar wat mee kan doen. Het circuit van de elektrische vliegenmepper hoeft niet enorm te worden aangepast. Het enige waar de arduino uiteindelijk voor zorgt is dat het geven van de schok geautomatiseerd wordt. De relais heeft de knop vervangen. Door goed te kijken naar wat een bepaald soort circuit precies doet kan je achterhalen waar je de componenten tussen wilt zetten. Op deze manier hoef je zelf niet alles vanaf scratch in elkaar te zetten en zijn de bestaande (eenvoudige) circuits voor mij nu veel minder intimiderend geworden om naar te kijken. Je weet immers dat je opzoek bent naar gedeelte wat de componenten kunnen overnemen, niet naar het compleet nabouwen van het bestaande circuit.

Supplies

Elektronische componenten

  1. Arduino UNO
  2. MPU-6500 Accelerometer - Gyroscope 6DOF Module 3.3V-5V
  3. 5V relais 1-channel hoog-actief
  4. 2x AA Batterijdoosje met Losse Draden en Schakelaar (Hiermee kan je eenvoudig het schokmechanisme uitzetten)
  5. 2x AA batterijen
  6. 9V Batterijdoosje met DC Jack en Schakelaar (Voeding voor de Arduino UNO)
  7. Procell Intense 9V Batterij
  8. Een elektrische vliegenmepper
  9. DuPont Jumper draad Male-Female 100cm 10 draden
  10. DuPont Jumper draad Male-Female 20cm 10 draden
  11. Optioneel wanneer je niet zelf een dupont y splitter wilt maken/kopen: Breadboard
  12. Optioneel wanneer je niet je eigen kabeltjes gaat maken: male en female DuPont krimpstekkers en meerdere DuPont 1P behuizingen.


Behuizing & Straps

  1. Kartonnen doosje van 24cm x 17cm x 10cm (LxBxH)
  2. Kado/kaft papier om je behuizing een mooie look te geven ;). Zelf heb ik de glimmende zijde van kaftpapier gebruikt.
  3. SOLITY® Klittenband Zelfklevend met 2 Gratis Alcoholdoekjes - Velcro - 2x5 Meter - Extra Sterk - Wit
  4. Piepschuim o.i.d (iets waarmee je een relatief zachte bodem kan maken voor in het doosje waar je je componenten op gaat plaatsen)
  5. Plastic Zelfklevend Afstandsbusje M3 - M3.5 - 8.4mm Verhoging
  6. Tiewraps, 30cm
  7. Good Ol' Fashioned Ducttape
  8. Isolatietape


Gereedschap

  1. Soldeerbout met soldeertin
  2. Schaar (voor papier / karton)
  3. Een sterke kniptang o.i.d (je moet gaan knippen in het metalen gaas van de elektrische vliegenmepper)
  4. Optioneel wanneer je geen breadboard wilt gebruiken: Krimptang
  5. Optioneel wanneer je geen breadboard wilt gebruiken: Kabelknipper
  6. Optioneel wanneer je geen breadboard wilt gebruiken: Kabelstripper

Elektrische Vliegenmepper Demonteren

DemontageVliegenmepper.jpg
VliegenmepperCircuit.jpg
F8JGKUULHM00O1I.jpg
dajklsh.png

De eerste stap was het uit elkaar halen van de elektrische vliegenmepper. Het metalen gaas heb ik bewaard om daar later de polsarmbandjes van te maken. Toen het circuit eenmaal open en bloot lag heb ik rustig gekeken naar welke rol de arduino nu kan overnemen voor mij. Hier werd snel duidelijk dat deze alleen de rol van de knop kon overnemen.

Echter had ik per ongeluk de kabels van de eerste vliegenmepper kapot getrokken waardoor ik niet meer wist welke kabel waar zat bevestigd op de PCB. Ik heb dan ook een nieuwe elektrische vliegenmepper gekocht, degene die bij de supplies staat. De foto's waarbij je de achterkant kan zien van een PCB toont het circuit aan van de nieuwe vliegenmepper.

Het is nu een goed moment om duidelijk te maken dat zowel de gele als groene draad, onderaan de foto rechtsonderin, uiteindelijk verbinding moeten maken met degene die geschokt moet worden. Dit moet namelijk later in het proces gemaakt worden m.b.v de polsarmbandjes. Als dit niet het geval zou zijn dan krijgt de gebruiker niet de schok.

De Code

// Wat doet de code hieronder.


//Met de timerclass kan je instanties van timers maken met een specifieke duur, ze resetten, controleren of ze zijn verlopen en de resterende tijd of verstreken tijd opvragen wanneer je dat nodig hebt.
//De code om de gyroscope/accelerometer uit te lezen is afkomstig van https://howtomechatronics.com/tutorials/arduino/arduino-and-mpu6050-accelerometer-and-gyroscope-tutorial/
//Het is vrij ingewikkelde code gebasseerd op bepaalde datasheets van de componenten en ik kan met 100% zekerheid zeggen dat ik heb aangenomen wat hier staat, werkt. Er is tevens ook rekening gehouden met het calibreren van de gyroscope/accelerometer.
//Superkudos naar Dejan, you legend.

class Timer
{
  private:
    unsigned long startTime; //Slaat de starttijd van de timer op.
    unsigned long durationTimer; //Slaat de duur van de timer op.


  public:
    Timer(unsigned long duration) //Dit is de constructor van de Timer-klasse. Het neemt een unsigned long "duration" als parameter en initialiseert durationTimer met de opgegeven waarde. Vervolgens roept het de functie reset() aan om de startTime in te stellen op de huidige tijd met behulp van de millis() functie.
    {
      this->durationTimer = duration;
      this->reset();
    }


    void reset() //Deze functie reset de timer door de startTime variabele bij te werken met de huidige tijd met behulp van de millis() functie.
    {
      this->startTime = millis();
    }


    bool isExpired() //Deze functie controleert of de timer is verlopen. Het berekent het verschil tussen de huidige tijd (millis()) en startTime en vergelijkt dit met durationTimer. Als het verschil groter is dan of gelijk is aan durationTimer, returned het true, wat aangeeft dat de timer is verlopen. Anders returned het false.
    {
      return (millis() - this->startTime >= this->durationTimer);
    }


    unsigned long getRemainingTime() //Deze functie berekent en geeft de resterende tijd in milliseconden tot de timer verloopt. Als de timer al is verlopen (gecontroleerd met isExpired()), returned het 0. Anders berekent het het verschil tussen durationTimer en de verstreken tijd (millis() - startTime) om de resterende tijd te bepalen.
    {
      if (this->isExpired())
      {
        return 0;
      }
     
      else
      {
        return (this->durationTimer - (millis() - this->startTime));
      }
    }


    unsigned long getElapsedTime() //Deze functie berekent en geeft de verstreken tijd in seconden sinds het starten van de timer. Het berekent het verschil tussen de huidige tijd (millis()) en startTime en deelt dit door 1000 om het in seconden om te zetten.
    {
      return ((millis() - this->startTime) / 1000);
    }
};


Timer timer(5000); // Maakt een timer aan met een duratie van 5000 milliseconden (5 seconden). Na deze tijd krijgt de gebruiker een schok, ALS de accelerometer nog steeds onder een bepaalde waarde meet.


Timer AccelTimer(10000); // Maakt een timer aan met een duratie van 10000 milliseconden (10 seconden) welke wordt gebruikt om de tijdslimiet te bepalen van hoe lang de accelerometer niet moet bewegen om te worden gezien als "gebruiker zit"


/*
   Arduino and MPU6050 Accelerometer and Gyroscope Sensor Tutorial
   by Dejan, https://howtomechatronics.com
*/

#include <Wire.h>
const int MPU = 0x68; // MPU6050 I2C address
float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
float accAngleX, accAngleY, gyroAngleX, gyroAngleY, gyroAngleZ;
float roll, pitch, yaw;
float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY, GyroErrorZ;
float elapsedTime, currentTime, previousTime;
int c = 0;


unsigned long previousMillis = 0;
unsigned long interval = 1000;
unsigned long duration = 5000;


void setup()
{
  Serial.begin(19200);
  Wire.begin();                      // Initialize comunication
  Wire.beginTransmission(MPU);       // Start communication with MPU6050 // MPU=0x68
  Wire.write(0x6B);                  // Talk to the register 6B
  Wire.write(0x00);                  // Make reset - place a 0 into the 6B register
  Wire.endTransmission(true);        // end the transmission
 
  pinMode(10, OUTPUT);


  /*
  // Configure Accelerometer Sensitivity - Full Scale Range (default +/- 2g)
  Wire.beginTransmission(MPU);
  Wire.write(0x1C);                   // Talk to the ACCEL_CONFIG register (1C hex)
  Wire.write(0x10);                   // Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true);
  // Configure Gyro Sensitivity - Full Scale Range (default +/- 250deg/s)
  Wire.beginTransmission(MPU);
  Wire.write(0x1B);                   // Talk to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                   // Set the register bits as 00010000 (1000deg/s full scale)
  Wire.endTransmission(true);
  delay(20);
  */


  // Call this function if you need to get the IMU error values for your module
  calculate_IMU_error();
  delay(20);
}


void loop()
{
  // === Read acceleromter data === //
  Wire.beginTransmission(MPU);
  Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
 
  //For a range of +-2g, we need to divide the raw values by 16384, according to the datasheet
  AccX = (Wire.read() << 8 | Wire.read()) / 16384.0; // X-axis value //Voor dit project heb je alleen deze waarde nodig, maar je kan natuurlijk ook de andere waardes gebruiken.
  AccY = (Wire.read() << 8 | Wire.read()) / 16384.0; // Y-axis value
  AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0; // Z-axis value
 
  // Calculating Roll and Pitch from the accelerometer data
  accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58; // AccErrorX ~(0.58) See the calculate_IMU_error()custom function for more details
  accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58; // AccErrorY ~(-1.58)
 
  // === Read gyroscope data === //
  previousTime = currentTime;        // Previous time is stored before the actual time read
  currentTime = millis();            // Current time actual time read
  elapsedTime = (currentTime - previousTime) / 1000; // Divide by 1000 to get seconds
  Wire.beginTransmission(MPU);
  Wire.write(0x43); // Gyro data first register address 0x43
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Read 4 registers total, each axis value is stored in 2 registers
  GyroX = (Wire.read() << 8 | Wire.read()) / 131.0; // For a 250deg/s range we have to divide first the raw value by 131.0, according to the datasheet
  GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;
  GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;
 
  // Correct the outputs with the calculated error values
  GyroX = GyroX + 0.56; // GyroErrorX ~(-0.56)
  GyroY = GyroY - 2; // GyroErrorY ~(2)
  GyroZ = GyroZ + 0.79; // GyroErrorZ ~ (-0.8)
 
  // Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees
  gyroAngleX = gyroAngleX + GyroX * elapsedTime; // deg/s * s = deg
  gyroAngleY = gyroAngleY + GyroY * elapsedTime;
  yaw =  yaw + GyroZ * elapsedTime;
 
  // Complementary filter - combine acceleromter and gyro angle values
  roll = 0.96 * gyroAngleX + 0.04 * accAngleX;
  pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;
 
  //////////
  // Print the values on the serial monitor
  Serial.print(AccX);
  Serial.print(", ");
  Serial.print(AccY);
  Serial.print(", ");
  Serial.println(AccZ);
 
  if (timer.isExpired() && !AccelMovedInPastTenSeconds())
  {
    Shock();
    timer.reset();
  }  
 
  delay(100);
}


void Shock() //Stuurt het signaal naar pin 10, waar de relais op is aangesloten, welke vervolgens de gebruiker dmv het schokcircuit een schok geeft.
{
  digitalWrite(10, HIGH);

///==WARNING==///
  delay(100); //Deze waarde duidt aan voor hoe lang de schok duurt in milliseconden!
///==WARNING==///

  digitalWrite(10, LOW);
}


//Heeft de accelerometer waardes buiten een bepaalde range gemeten?
bool AccelMovedInPastTenSeconds()
{
  if (abs(AccX) >= 0.5)
  {   
    AccelTimer.reset();    
    return true;
  }

  return false;
}


void calculate_IMU_error()
{
  // We can call this funtion in the setup section to calculate the accelerometer and gyro data error. From here we will get the error values used in the above equations printed on the Serial Monitor.
  // Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values
  // Read accelerometer values 200 times
  while (c < 200)
  {
    Wire.beginTransmission(MPU);
    Wire.write(0x3B);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    AccX = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    AccY = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0 ;


    // Sum all readings
    AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
    AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
    c++;
  }


  //Divide the sum by 200 to get the error value
  AccErrorX = AccErrorX / 200;
  AccErrorY = AccErrorY / 200;
  c = 0;


  // Read gyro values 200 times
  while (c < 200)
  {
    Wire.beginTransmission(MPU);
    Wire.write(0x43);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    GyroX = Wire.read() << 8 | Wire.read();
    GyroY = Wire.read() << 8 | Wire.read();
    GyroZ = Wire.read() << 8 | Wire.read();
    // Sum all readings
    GyroErrorX = GyroErrorX + (GyroX / 131.0);
    GyroErrorY = GyroErrorY + (GyroY / 131.0);
    GyroErrorZ = GyroErrorZ + (GyroZ / 131.0);
    c++;
  }


  //Divide the sum by 200 to get the error value
  GyroErrorX = GyroErrorX / 200;
  GyroErrorY = GyroErrorY / 200;
  GyroErrorZ = GyroErrorZ / 200;
 
  // Print the error values on the Serial Monitor
  Serial.print("AccErrorX: ");
  Serial.println(AccErrorX);
  Serial.print("AccErrorY: ");
  Serial.println(AccErrorY);
  Serial.print("GyroErrorX: ");
  Serial.println(GyroErrorX);
  Serial.print("GyroErrorY: ");
  Serial.println(GyroErrorY);
  Serial.print("GyroErrorZ: ");
  Serial.println(GyroErrorZ);
}


Prototyping

drawing.png
pcbnew.jpg
Testingjpg.jpg
Testing2.jpg

In het begin was het vooral kijken waar ik alle elektrische componenten tussen zou moeten zetten. De relais zou fungeren als knop en de arduino zou nu degene zijn die aanstuurt of er een schok gegeven zou mogen worden. De gyroscope/accelerometer meet alleen bepaalde waardes, de arduino moest ze interpreteren. Nu de code paraat stond kon ik gaan kijken naar hoe ik dit zou samenvoegen met het circuit.


Elektronisch schema van prototype in de bijlage als .svg

Downloads

Elektronisch Circuit Bouwen

FinalCircuitInstr.png

Nu duidelijk was dat het circuit van het prototype succesvol werkt kon ik overgaan naar het versimpelen hiervan. Aangezien ik geen breadboard heb gebruikt in het eindproduct moest ik dupont kabels gaan splitten en samenvoegen omdat meerdere componenten aangesloten moesten worden op de 5V van de arduino. Zie stap 5 voor hoe ik dat heb gedaan.

Elektronisch schema van het eindproduct staat in de bijlage als .svg


Behuizing, Straps En Aangepaste Dupont Kabels Maken

doosjeinside.jpg
legss.jpg
legsinside.jpg
legstrapjpg.jpg
wriststrap.jpg
bigstrap.jpg
armstrap.jpg

Omdat de gyroscope/accelerometer moest meten of iemand zou zitten of niet heb ik ervoor gekozen dat deze op het bovenbeen zou moeten gaan zitten. Om dit goed voor elkaar te krijgen heb ik een klein doosje gemaakt van karton waarin de MPU-6500 geplaatst werd. Deze heb ik vastgeplakt aan de bodem met de plastic afstandbusjes. Om het doosje zelf zit een tiewrap wat de klittenband strap op zijn plaats moest houden.

Voor de polsarmbandjes deed ik precies hetzelfde. Alleen moest ik nu eerst een stuk uit het metalen gaas van de elektrische vliegenmepper gaan knippen wat de schok zou doorgeven aan de gebruiker. Bij deze stap was het belangrijk dat er twee armbandjes zouden worden gemaakt omdat de schok alleen gegeven kan worden wanneer beide schokdraadjes verbonden zouden zijn met iets wat goed elektriciteit geleid.

De polsarmbandjes zijn zo gemaakt dat je ze nog moet vastklikken aan de kabels die uit de relais komen. Op deze manier kan je later altijd nog andere variaties maken van waarmee je de schok kan overbrengen naar de gebruiker. In de video bij de volgende stap zie je ook dat ik test of de kabels onder stroom komen te staan door ze allebei tegen het metalen gaas van de armband de houden.

Voor het zelf maken van dupont Y-adapter heb ik de tutorial van deze website gebruikt.


Voor de bodem van het doosje heb ik een soort van piepschuim gebruikt waar je moederborden, videokaarten etc op kan neerleggen om deze zo veilig mogelijk te beschermen. Hierop heb ik weer stukken klittenband geplakt waarmee ik de verschillende componenten heb bevestigd. De arduino zelf is bevestigd op het piepschuim met 4 van de plastic afstandbusjes. Hetzelfde geldt voor de gyroscope/accelerometer, deze is bevestigd in zijn doosje met 2 plastic afstandbusjes.

Eindproduct in Actie

Instructable ShockBox

Conclusie

Tijdens dit project heb ik geleerd wat een arduino is, wat je ermee kan en hoe je ze zelf kan implementeren in je eigen projecten. Ook begrijp ik nu hoe elektrische vliegenmeppers werken, hoe je ze kan demonteren en kan repurposen voor de wat minder ethisch verantwoorde projecten ;). Tevens heb ik geleerd hoe ik moet solderen en hoe ik eigen klittenband straps kan maken. Bij het testen was het vooral vaak jezelf onder stroom zetten om te kijken of de duratie van de schok niet soms te lang was. 2 seconden is achteraf gezien echt heel lang, die deed aardig pijn.

For science! Am I right?


In ieder geval, nu wordt er gewerkt met een schokduratie van 0.1 seconden, dit was een stuk beter te managen. Anders zou dit project onder "martelmethodes" vallen...

Nogmaals, ik raad het echt niet aan om zomaar dit project te gaan maken aangezien je jezelf redelijk eenvoudig wat pijn kan opleveren. Dus once again, for educational purposes only!