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 ("!");
}

Step 3: Demonstration of Work and Experiment With Different Balls and Settings of the PID Controller.

Thanks for watching.

galkin.vadim.prog@gmail.com