John Bradnam
Published © GPL3+

Magnetic Levitation with ATtiny1614

A simple magnetic levitation toy built using a ATtiny1614 microprocessor

IntermediateFull instructions provided12 hours741
Magnetic Levitation with ATtiny1614

Things used in this project

Hardware components

Microchip ATtiny1614 Microprocessor
×1
AO4406 N-Channel MOSFET
SOIC-8 variant
×1
1117-5 5V Regulator
SOT223-T package
×1
Tactile Switch, Top Actuated
Tactile Switch, Top Actuated
8mm shafts
×2
Other components
1 x 1K 0805 resistor, 1 x 10K 0805 resistor, 2 x 39K 0805 resistors, 2 x 0.1uF 0805 capacitors, 1 x 47uF/10V 3528 Tantalum capacitor, 1 x 1N4148 SOD323 diode, 1 x 1N4007 SOD123 SMA diode
×1
D25mm*H20mm Holding Electric Magnet Lifting 5KG/50N Solenoid
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

STL Files

Files for 3D printing

Schematics

PCB

Schematic

Eagle files

Schematic & PCB in Eagle format

Code

Levitator_V1.ino

Arduino
//=========================================================|
//     Ekobots Innovation Ltda - www.ekobots.com.br        |
//        Juan Sirgado y Antico - www.jsya.com.br          |
//---------------------------------------------------------|
//      Program Magnetic Levitator PID - 2016/10/06        |
//               All rights reserved 2016                  |
//=========================================================|

/*
 * 230109 - jbrad2089@gmail.com
 *    - Updated to run on ATtiny1614
 */

/*-----------------------------------------------------------------------------
  ATTiny1614 Pins mapped to Ardunio Pins

             +--------+
         VCC + 1   14 + GND
 (SS)  0 PA4 + 2   13 + PA3 10 (SCK)
       1 PA5 + 3   12 + PA2 9  (MISO)
 (DAC) 2 PA6 + 4   11 + PA1 8  (MOSI)
       3 PA7 + 5   10 + PA0 11 (UPDI)
 (RXD) 4 PB3 + 6    9 + PB0 7  (SCL)
 (TXD) 5 PB2 + 7    8 + PB1 6  (SDA)
             +--------+

  PA0 to PA7 can be analog or digital
  PWM on D0, D1, D6, D7, D10

  BOARD: ATtiny1614/1604/814/804/414/404/214/204
  Chip: ATtiny1614
  Clock Speed: 20MHz
  Programmer: jtag2updi (megaTinyCore)
-----------------------------------------------------------------------------*/

//Comment out for simple on/off of solenoid
//#define USE_PID

//Pins
#define SOLENOID 0 //(PA4)
#define SWITCHES 1 //(PA5)
#define OH49E 2    //(PA6)

enum SWITCH {NONE, SUB, ADD};

int anaVal = 0;   // Analogic Valie
int digVal = 0;   // Digital Value
unsigned long timVal = 0; // Time Value

#define LOOP_DELAY 10 // Delay Value
#define LEVITATION_DEFAULT 262
#define PID_UPDATE_DELAY 500

//---------------------------------------------------------|
// PID Values
#define MIN_PID_VALUE 0
#define MAX_PID_VALUE 255

float setpoint = 0;
float measured_value = 0;
float output = 0;
float integral = 0;
float derivative = 0;
float error = 0;
float previous_error = 0;
float dt = 0.1;
float Kp = 1.0;              //How fast the system responds (too high cause overshoot)
float Ki = 0.1;              //How fast the steady state error is removed
float Kd = 0.01;             //How far into the future to predict the rate of change

//---------------------------------------------------------
// Setup hardware
void setup()
{
  // Digital Pins Work Mode Setup;
  pinMode(SOLENOID, OUTPUT);
  pinMode(SWITCHES, INPUT);
  pinMode(OH49E, INPUT);
  
  Serial.begin(57600);
  Serial.println("Levitator by JSyA");
  Serial.println("Starting...");
  
  timVal = millis() + PID_UPDATE_DELAY;
  setpoint = LEVITATION_DEFAULT;
}

void loopX()
{
  digitalWrite(SOLENOID, (readSwitches(false) == ADD) ? HIGH : LOW);
  delayMicroseconds(LOOP_DELAY);
}

//---------------------------------------------------------
// Main loop
void loop() // PID
{
  // Hall Sensor Read (Magnetic Field Intensity);
  anaVal = analogRead(OH49E);
  
  #ifdef USE_PID
    // PID calculations
    measured_value = anaVal;
    error = setpoint - measured_value;
    integral = integral + error * dt;
    derivative = (error - previous_error) / dt;
    output = (-Kp * error) + (-Ki * integral) + (-Kd * derivative);
    previous_error = error;
    Serial.println("A=" + String(measured_value) + ", E=" + String(error) + ", P=" + String(-Kp * error) + ", I=" + String(-Ki * integral) + ", D=" + String(-Kd * derivative) + ", O=" + String(digVal));
    
    // Final value setup
    digVal += max(min(output, MAX_PID_VALUE), MIN_PID_VALUE);
    
    // Increase/Decrease the value for Electromagnet;
    // With Base on Sensor Value and the Levitation Point;
    analogWrite(SOLENOID, digVal);
  #else
    digVal = (anaVal < setpoint) ? LOW : HIGH;
    digitalWrite(SOLENOID, digVal);
  #endif

  // Show log values for debug;
  if(millis() > timVal)
  {
     value_log();
     timVal = millis() + PID_UPDATE_DELAY;
  }
  
  // Increase The Value Of Levitation Point;
  if (readSwitches(false) == ADD) 
  {
    setpoint++;
    value_log();
    delay(250);
  }
  if (readSwitches(false) == SUB) 
  {
    setpoint--;
    value_log();
    delay(250);
  }
  // Time between electromagnet state changes;
  delayMicroseconds(LOOP_DELAY);
}

//---------------------------------------------------------------------
//Read current switches state
// - wait - True to wait for button released if pressed
// - Returns NONE, ADD or SUB
SWITCH readSwitches(bool wait)
{
  SWITCH sw = NONE;
  int value = analogRead(SWITCHES);
  if (value < 1000)
  {
    delay(10);    //debounce
    if (value == analogRead(SWITCHES))
    {
      sw = (value < 100) ? ADD : SUB;
      if (wait)
      {
        //wait for release
        while (analogRead(SWITCHES) < 1000)
        {
          delay(50);
        }
      }
    }
  }
  return sw;
}

//---------------------------------------------------------
// Write values to serial port
// Analogic/Digital/Levitation;
void value_log()
{
   // Show the Hall Sensor Value;
   Serial.print("anaVal=[");
   Serial.print(anaVal); 
   Serial.print("]-");
   // Show the Electromagnet state On=1/Off=0;
   Serial.print("digVal=[");
   Serial.print(digVal);
   Serial.print("]-");
   // Show the Levitation Point Value;
   Serial.print("setpoint=[");
   Serial.print(setpoint);
   Serial.println("];");
}

//=========================================================|

Credits

John Bradnam

John Bradnam

146 projects • 179 followers
Thanks to jsirgado.

Comments