Introduction: Magic Ball ( PID Control, Arduino Due )
Breadboard to demonstrate PID control on the Arduino Due.
Supplies
1. Arduino Due x1
2. Touchscreen 5 wires x1
3. Power supply unit 5 V. x1
4. Servomotors x2
5. Plywood 6 and 8 mm.
Layout created in Autodesk Fusion 360 and CorelDraw 2021.
Step 1: Making the Platform
We cut out the details with a laser cutter.
Then we put the parts together and glue them with wood glue.
Step 2: Download the Program to the Arduino Due.
#include <Servo.h>
#include <PID_v1.h>
// Specify links and initial settings
double Kp = 4, Ki = 1, Kd = 2;
// Define the variables we will connect to
double Setpoint_X, Input_X, Output_X;
double Setpoint_Y, Input_Y, Output_Y;
PID myPID_X(&Input_X, &Output_X, &Setpoint_X, Kp, Ki, Kd, DIRECT);
PID myPID_Y(&Input_Y, &Output_Y, &Setpoint_Y, Kp, Ki, Kd, DIRECT);
int Target_x, Target_y;
int Delta_x, Delta_y;
const int servo1 = 8; // servo motor X
const int servo2 = 9; // servo motor Y
Servo myservo1; // create a Servo object to control servo motor X
Servo myservo2; // create a Servo object to control servo motor Y
// NEC touch screen
const byte PS = 0; // PS touchscreen output
const byte UL = 3; // UL touchscreen output
const byte UR = 4; // UR touchscreen output
const byte LL = 5; // LL touchscreen output
const byte LR = 6; // LR touchscreen output
int TouchScreenVal_x; // variable for storing data from analog pin X
int TouchScreenVal_y; // variable for storing data from analog pin Y
int TouchScreenVal_xm; // variable to store data for servo motor X
int TouchScreenVal_ym; // variable to store data for servo motor Y
int TouchScreenVal_x0; // variable to store the starting point X0
int TouchScreenVal_y0; // variable to store the starting point Y0
int servoVal_xm; // variable for storing data from servo motor X
int servoVal_ym; // variable for storing data from servo motor Y
int servoVal_x0; // variable for storing data X0
int servoVal_y0; // variable for storing data Y0
void setup () {
// Setting up the touchscreen
pinMode (PS, INPUT);
pinMode (UR, OUTPUT);
pinMode (UL, OUTPUT);
pinMode (LL, OUTPUT);
pinMode (LR, OUTPUT);
digitalWrite (UL, LOW); // UL
digitalWrite (UR, LOW); // UR
digitalWrite (LL, LOW); // LL
digitalWrite (LR, LOW); // LR
// Initialize the serial communication protocol
Serial.begin (9600);
// ADC
analogReadResolution (12);
// Servo
myservo1.attach (servo1); // connect servo motor X
myservo2.attach (servo2); // connect servo motor Y
// enable PID
myPID_X.SetMode (AUTOMATIC);
myPID_Y.SetMode (AUTOMATIC);
TouchScreenVal_x0 = 0;
TouchScreenVal_y0 = 0;
servoVal_x0 = 107;
servoVal_y0 = 104;
Target_x = 512;
Target_y = 360;
}
void loop () {
digitalWrite (UR, HIGH); // UR
digitalWrite (LL, LOW); // LR
// read the X value from the touchscreen along the horizontal axis (values between 1000 and 3000)
digitalWrite (UL, LOW); // UL
digitalWrite (LR, HIGH); // LL
delayMicroseconds (200);
// delay (1);
TouchScreenVal_x = analogRead (PS);
TouchScreenVal_xm = TouchScreenVal_x0;
if (TouchScreenVal_x> 100) TouchScreenVal_xm = TouchScreenVal_x0 + map (TouchScreenVal_x, 1330, 2570, 0, 1023); // scale the resulting value for use with a servo motor (range: 100 to 110)
// read the Y value from the touchscreen along the vertical axis (value from 1000 to 3000)
digitalWrite (UL, HIGH); // UL digitalWrite (LR, LOW); // LL
delayMicroseconds (200);
// delay (1);
TouchScreenVal_y = analogRead (PS);
TouchScreenVal_ym = TouchScreenVal_y0;
if (TouchScreenVal_y> 100) TouchScreenVal_ym = TouchScreenVal_y0 + map (TouchScreenVal_y, 1330, 2680, 0, 767); // scale the resulting value for use with a servo motor (range: 100 to 110)
Setpoint_X = Target_x;
Input_X = TouchScreenVal_xm;
myPID_X.Compute ();
servoVal_xm = servoVal_x0 + map (Output_X, 0, 255, +4, -4); // scale the resulting value for use with the servo motor (result in the range 99 to 109)
myservo1.write (servoVal_xm); // display the rotor of the second servo motor in accordance with the obtained scale level
Delta_x = Target_x - TouchScreenVal_xm;
Setpoint_Y = Target_y;
Input_Y = TouchScreenVal_ym;
myPID_Y.Compute ();
servoVal_ym = servoVal_y0 + map (Output_Y, 0, 255, -4, +4); // scale the resulting value for use with the servo motor (result in the range 99 to 109)
myservo2.write (servoVal_ym); // display the rotor of the second servo motor in accordance with the obtained scale level
Delta_y = Target_y - TouchScreenVal_ym;
//OutputPID ();
}
// display PID values
void OutputPID () {
Serial.print ("SX ="); Serial.print (Setpoint_X);
//Serial.print ("TX ="); Serial.print(TouchScreenVal_x);
Serial.print ("MX ="); Serial.print (TouchScreenVal_xm);
Serial.print ("DX ="); Serial.print (Delta_x);
Serial.print ("OX ="); Serial.print (Output_X);
Serial.print ("SMX ="); Serial.print (servoVal_xm);
Serial.print ("---");
Serial.print ("SY ="); Serial.print (Setpoint_Y);
//Serial.print ("TY ="); Serial.print(TouchScreenVal_y);
Serial.print ("MY ="); Serial.print (TouchScreenVal_ym);
Serial.print ("DY ="); Serial.print (Delta_y);
Serial.print ("OY ="); Serial.print (Output_Y);
Serial.print ("SMY ="); Serial.print (servoVal_ym);
Serial.println ("!");
}






