Hi all,
I am trying to PID control two electromagnets.
I would like to set the position between them and make them move to a specific location.
Before getting into PID I would first like to explain my test system:
- Two electromagnets
- One mounted static, one mounted on a sliding drawer-bearing
- The magnets are driven by an L298N board
- The position of the moving magnet is tracked by a linear encoder from an HP printer
- The position from the linear encoder is read by an Arduino Micro
- The magnets are controlled by an Arduino Mega that reads the position from the Micro using i2c : Master Reader/Slave Sender
Pictures of the setup:
(click for full size)
Now I have some very crude code to control the position.
The important part is this:
if(intPosition < 50){
//If the distance is less than XX (=X.Xmm) the magnets should repell
repell();
}
if(intPosition > 60){
//If the distance is more than XX (=X.Xmm) the magnets should attract
attract();
}
The complete code is this
// includes
#include <Wire.h>
//SETUP PIN CONTROL ON L298N ================================
int pinPWM_M1 = 2;
int pinDIR_M1A = 3;
int pinDIR_M1B = 4;
int pinPWM_M2 = 5;
int pinDIR_M2A = 6;
int pinDIR_M2B = 7;
// VARIABLES TO GET CURRENT POSITION FROM ENCODER ==========
int intPosition; // the current position reported by the encoder
byte a,b; // bytes to hold the data coming over i2c, two bytes needed for bigger and negative values: https://thewanderingengineer.com/2015/05/06/sending-16-bit-and-32-bit-numbers-with-arduino-i2c/
void setup() {
//These pin control polarity and pwm for the magnets via the L298N board
pinMode(pinPWM_M1,OUTPUT);
pinMode(pinDIR_M1A,OUTPUT);
pinMode(pinDIR_M1B,OUTPUT);
pinMode(pinPWM_M2,OUTPUT);
pinMode(pinDIR_M2A,OUTPUT);
pinMode(pinDIR_M2B,OUTPUT);
//Turn on magnets
//With these values the magnets attract
//Magnet 1
analogWrite(pinPWM_M1,255);
digitalWrite(pinDIR_M1A, LOW);
digitalWrite(pinDIR_M1B, HIGH);
//Magnet 2
analogWrite(pinPWM_M2,255);
digitalWrite(pinDIR_M2A, HIGH);
digitalWrite(pinDIR_M2B, LOW);
//SERIAL setup, for debugging
Serial.begin(9600);
//I2C WIRE
Wire.begin(); // join i2c bus (address optional for master)
} //end setup
void attract(){
//Only one magnet must reverse polarity
//Magnet 1
digitalWrite(pinDIR_M1A, LOW);
digitalWrite(pinDIR_M1B, HIGH);
}
void repell(){
digitalWrite(pinDIR_M1A, HIGH);
digitalWrite(pinDIR_M1B, LOW);
}
void loop() {
//get the current position from the connected Arduino Micro over i2c
Wire.requestFrom(1, 2); // requests 2 bytes from slave device #1
a = Wire.read();
b = Wire.read();
//Two bytes combined to give position
intPosition = a;
intPosition = (intPosition << 8) | b;
Serial.println(intPosition);
if(intPosition < 50){
//If the distance is less than XX (=X.Xmm) the magnets should repell
repell();
}
if(intPosition > 60){
//If the distance is more than XX (=X.Xmm) the magnets should attract
attract();
}
} //end loop
The result is this (video), I call it:
"Hammer Time !"
So my test system works, somewhat.
Now my question would be how to implement PID control to control the position decently.
Thanks for reading !