Projekt "Houpačka" byl koncipován jako vzdělávací aktivita, jejímž cílem bylo zábavnou formou seznámit účastníky s principy fungování Arduino platformy, programováním a základy senzoriky. Žáci si prostřednictvím tohoto projektu osvojili dovednosti v oblasti měření vzdálenosti pomocí ultrazvukových senzorů, zpracování dat a tvorby jednoduchých aplikací. Současně projekt podporoval rozvoj kreativního myšlení a řešení problémů.
Cílem zařízení se dvěma ultrazvukovými senzory bylo následující: pokud se pohnulo s černou kostkou proti ultrazvukovému senzoru nebo naopak, tak servomotor nadzvedl nebo snížil dřevěnou rovinu a poslal vozíček na stejnou vzdálenost jakou představovala vzdálenost mezi ultrazvukovým senzorem a černou kostičkou.
Program pro arduino:
#include <Servo.h>
#define Umax 66 // degrees
#define Umin -66
#define Umax_rad 1.151 // radians
#define Umin_rad -1.151
#define T 0.09
const int echoPin2= 4;
const int trigPin2= 3;
const int echoPin1= 6;
const int trigPin1= 7;
Servo servo;
double setpoint, setpoint_prec; // In METRI : 30cm --> 0.3m
double y, y_prec;
double error;
double P, I, D, U;
double I_prec=0, U_prec=0, D_prec=0;
boolean Saturation = false;
double Kp = 8.6; //
double Ki = 1.1; // 0.1
double Kd = 6.3; //
float measure_1 (void);
float measure_2 (void);
void move_servo(int);
void setup() {
Serial.begin(9600);
pinMode(trigPin2, OUTPUT);
pinMode(echoPin2, INPUT);
pinMode(trigPin1, OUTPUT);
pinMode(echoPin1, INPUT);
servo.attach(9);
delay(1000);
move_servo(90);
delay(2000);
setpoint_prec = measure_2(); // blocco
delay(1000);
y_prec = measure_1(); // carrello
delay(1000);
}
void loop() {
setpoint = measure_2(); // cube // meters
setpoint = 0.53*setpoint + 0.47*setpoint_prec; // digital filter
delay(3);
y = measure_1(); // cart // meters ( alfa*y : if alfa increase, y less filteres --> so the signal is dirty but fast )
y = 0.53*y + 0.47*y_prec; // digital filter
delay (3);
error = round( 100*(y - setpoint) )*0.01;
// PID control
P = Kp*error;
if ( ! Saturation ) I = I_prec + T*Ki*error;
D = (Kd/T)*(y - y_prec);
D = 0.56*D + 0.44*D_prec; // filter D ( alfa*D : if alfa increase, D less filteres --> so the signal is dirty but fast )
U = P + I + round(100*D)*0.01 ; // U in radians
// saturate control action
if ( U < Umin_rad) {
U=Umin_rad;
Saturation = true;
}
else if ( U > Umax_rad) {
U=Umax_rad;
Saturation = true;
}
else Saturation = false;
U=round(U*180/M_PI); // Transform U in degrees: -63 < U° < 63
U=map(U, Umin, Umax, 24, 156);
if (U < 83 || U > 95 || abs(error) > 0.02 ) move_servo( round(U) ); // it is used to stop the servo when the setpoint is reached
delay (24);
//Serial.print(setpoint*100);
//Serial.print(" ");
//Serial.print(y*100);
//Serial.print(" ");
//Serial.print(U);
//Serial.println();
I_prec = I;
y_prec = y;
D_prec = D;
setpoint_prec = setpoint;
}
float measure_1 (void) {
long elapsed_time=0;
float distance=0;
digitalWrite(trigPin1, LOW);
delayMicroseconds(10);
digitalWrite(trigPin1, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin1, LOW);
elapsed_time = pulseIn(echoPin1, HIGH);
distance = (float)elapsed_time/58.2;
delay(30);
if (distance > 42) distance=43;
else if (distance < 0) distance=0;
return 0.01*(distance-1.5+0.5); // meters
}
float measure_2 (void) {
long elapsed_time=0;
float distance=0;
digitalWrite(trigPin2, LOW);
delayMicroseconds(10);
digitalWrite(trigPin2, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin2, LOW);
elapsed_time = pulseIn(echoPin2, HIGH);
distance = (float)elapsed_time/58.2;
delay(30);
if (distance > 42) distance=43;
else if (distance < 0) distance=0;
return 0.01*(distance+2); // meters +2cm to get the center of the cube
}
void move_servo(int u) {
servo.write(u-map(u, 30, 150, 14, 3));
}