lego_ball_and_beam_v2

The ball and beam system is also called ‘balancing a ball on a beam’.It is generally linked to real control problems such as horizontally stabilizing an airplane during landing and in turbulent airflow. There are two degrees of freedom in this system. One is the ball rolling up and down the beam, and the other is beam rotating through its central axis. The aim of the system is to control the position of the ball to a desired reference point, and reject disturbances such as a push from a finger. The control signal can be derived by feeding back the position information of the ball. The control power signal goes to the servo-motor，then the torque generated from the motor drives the beam to rotate to the desired angle. Thus, the ball can be located at the desired position.

It is important to point out that the open loop of the system is unstable and nonlinear. The problem of ‘instability’ can be overcome by closing the open loop with a feedback controller. The nonlinear property is not significant when the beam only deflects a small angle from the horizontal position. In this case, it is possible to linearize the system. However, the non-linearities become significant when the angle of the beam from the horizontal is larger than 30 degrees, or smaller than -30 degrees. In this case, a simple linear approximation is not accurate. Thus a more advanced control technique such as nonlinear control should work better.

In order to theoretically model the ball and beam system, the assumptions are listed in the following:

- The ball rolls on the beam without slip
- The gearbox embedded in the motor exhibit no backlash effect
- The base of the system is static with respect to the ground
- The beam is able to rotate between -30 degrees to 30 degrees relative to the horizontal

The whole structure is made up of pieces of lego mindstorm kit ; There is a lego servo-motor that tilt the beam by using a wire, and the beam is hinged on the other side as shown the picture below.

Ball's position is detected by a Infrared distance sensor for NXT (DIST-Nx-v3)that is fixed on the beam.

According to physics laws, mathematical equations are derived to model a system. Therefore, a detailed derivation of those equations is presented. The following equation can be derived from analysis of the force balance on the ball employing Newton’s law.

m*g*sin(α) - Fr = m*x'' + b*x'

where **m** is the mass of the ball, **g** is acceleration of gravity, **x** is the vertical
distance between the center of ball and center of the shaft, **b1** is the friction constant while the ball rolls on the channel of the beam, **α** is the beam’s tilt angle from the horizontal position, **Fr** represents the externally applied force.

Based on the small angle theorem, this relation can be approximated by in the form:

m*g*α - Fr = m*x'' + b*x'

The angle of the beam **α** is linked to the angle of the motor **θ** according the following equation:

d*θ = α*L

where **d** is the radius of the pulley and **L** is the length of the beam;

The torque balance of the ball is expressed as:

Fr*R = Jball*(x''/R)

where **x** is the linear acceleration of the ball, **Jball** is the moment of inertia of the ball, given by:

Jball = 2/5 m*R^2

Finally, the following result can be derived (neglecting the friction constant **b1**):

(m*g*d*θ)/L = (m + Jball/(R^2))*x''

The open loop of the system is unstable so it can be overcome by closing the open loop with a feedback controller.

The error between set point and current position of the ball must be handled before being sent to the system, and this will be the task of the PID control:

The control signal is thus a sum of three terms: the P-term(which is proportional to the error), the I-term(which is proportional to the integral of the error), and the D-term(which is proportional to the derivative of the error). The controller parameters are proportional gain Kp, integral gain Ki, and derivative gain Kd. The integral, proportional and derivative part can be interpreted as control actions based on the past, the present and the future. Two controllers must be developed to control this system: an angular position controller for the motor controlling beam angle and a controller for the ball position and velocity on the beam. For this project, a stock controller available through the NXC programing language was used to control the motor position. This controller uses Proportional-Integral-Derivative (PID) control to set a motor position with an appropriate rise time and minimal overshoot of the set value. This controller can be accessed in two ways. One way allows the PID gains to be set manually. The second way (used in the following controller code) allows the user to control the maximum motor velocity and acceleration effectively dampening the system.

To control ball position and velocity it will be used a PD control because theoretically there isn't a steady state error and then Ki will be useless.

For PID control of the NXT motor on Port A:

code c> OnFwdRegPID(byte outputs,

char pwr, byte regmode, byte p, byte i, byte d )

</code>

For Velocity and Acceleration control of the NXT motor on Port A:

PosRegEnable(OUT_A); PosRegSetMax(byte output, byte max_speed, byte max_acceleration ) PosRegSetAngle (OUT_A, angle);

The angular position of the motor is accessed via a built in encoder using the following command:

curAngleInDegrees = MotorRotationCount(OUT_A);

To control the ball on the beam it is required the use of a sensor that is able to recognize the current position of the ball so “High Precision Medium Range Infrared distance sensor for NXT (DIST-Nx-Medium-v3)” was chosen from Mindsensors.com

Documentation and examples for using this sensor can be found on their website.

SetSensorLowspeed(S1); DISTNxSendCommand(S1, DIST_CMD_ENERGIZED, DIST_ADDR); DR = DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR); //Read Sensor Value

The current position of the ball will be compared with the set point in order to give the error that will be managed by the PD controller. In order to understand the accuracy of the sensor, two tests were performed:

1) the ball is stack on the central position of the beam:

where Error is the difference between the set point (the central position) and the current position of the ball (now it is stuck).

2) the ball goes from the central position to one side of the beam:

Finally it is possible to understand that the sensor accuracy is very good.

The PD controller needs an error between the current position of the ball (given by the sensor) and the set point. Before the control loop started, the sensor detects the central position of the ball in order to save the set point of the close loop; This was done by taking the average of many readings (ReadNum = 30) to calculate it.

float Error; float set_point; int ReadNum = 30; int i; ... for (i = 0; i < ReadNum; i++) //cycle for calibration { set_point += DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR); Wait(100); TextOut(10, LCD_LINE3, "Calibrating..."); } set_point = set_point/ReadNum; Error = DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR) - set_point; // give the Error = current position - set point

To improve the quality of sensor data, a very simple filter has been implemented. Before sending the signal to the controller, the sensor reads 3 times the current position of the ball provided an average reading.

int FiltNum = 3; int j; ... Error = 0; for (j = 0; j < FiltNum; j++) { Error += DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR)- set_point; } Error = Error/FiltNum; // current error

In order to understand what happens on the field, the sensor data was written on two files and was plotted on Matlab:

byte fileHandle1; short fileSize1; short bytesWritten1; byte fileHandle2; short fileSize2; short bytesWritten2; int t0; int time; ... DeleteFile("Tempo.txt"); DeleteFile("Data.txt"); CreateFile("Tempo.txt", 10000, fileHandle1); CreateFile("Data.txt", 10000, fileHandle2); t0 = CurrentTick(); X = Error ; // current error X //write on file time and error time = CurrentTick()-t0; string tmp1 = NumToStr(time); WriteLnString(fileHandle1,tmp1, bytesWritten1); string tmp2 = NumToStr(X); WriteLnString(fileHandle2,tmp2, bytesWritten2);

The error found as the difference between the set point and the current position of the ball is processed by the PD controller in order to send a command to the motor. The Kp and Kd gains were chosen by trial, error and observation. Before Kp were chosen in order to give stability to the system, and after Kd were chosen in order to reduce oscillations: use Kp to decrease the rise time and Kd to reduce overshoot and settling time.

float X float DerX floar X_old; float dT = 0.1; float angle; ... //PD control DerX = (X - X_old)/dT; // derivative error integral = integral + 1/2 *(X + X_old)*dT; // integral error (useless) angle = (Kp*X) + (Kd*DerX) + (Ki*integral); // command for motor after PD regulation PosRegSetAngle (OUT_A, -angle); // command for the motor X_old = X; //save current error

- BallandBeamv2.nxc
#include "dist-nx-lib.nxc" // Range Finder Device Address #define DIST_ADDR 0x02\ // 0.5 1.5 #define Kp 0.92 // non superare 1.1 (0.9) -92 #define Kd 0.40 // 0.40 #define Ki 0 byte fileHandle1; short fileSize1; short bytesWritten1; byte fileHandle2; short fileSize2; short bytesWritten2; float set_point=0; float X; long curAngleInDegrees; float Error; float X_old=0; float DerX; float integral=0; float angle; float dT = 0.1; int t0; int time; int ReadNum = 30; // number of mesures for sensor calibration int FiltNum = 3; // number of mesures read by the sesor during regolation int i; int j; task main() { DeleteFile("Tempo.txt"); DeleteFile("Data.txt"); CreateFile("Tempo.txt", 10000, fileHandle1); CreateFile("Data.txt", 10000, fileHandle2); SetSensorLowspeed(S1); // empower the port 1 for sensor PosRegEnable(OUT_A); // empower the port A for motor DISTNxSendCommand(S1, DIST_CMD_ENERGIZED, DIST_ADDR); // energize the sensor for (i = 0; i < ReadNum; i++) //cycle for calibration { set_point += DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR); Wait(100); TextOut(10, LCD_LINE3, "Calibrating..."); } set_point = set_point/ReadNum; // give the set point Error = DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR)- set_point; // give the error DR_old = current position - set point t0 = CurrentTick(); while (1) { //cycle for regulation Error = 0; for (j = 0; j < FiltNum; j++) { Error += DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR)- set_point; } Error = Error/FiltNum; // current error X = Error ; // current error X //write on file time and error time = CurrentTick()-t0; string tmp1 = NumToStr(time); WriteLnString(fileHandle1,tmp1, bytesWritten1); string tmp2 = NumToStr(X); WriteLnString(fileHandle2,tmp2, bytesWritten2); // write on nxt display curAngleInDegrees = MotorRotationCount(OUT_A); // give the current angle of the motor in degrees (encoder) ClearScreen(); /*NumOut(0, LCD_LINE1, DR, false);*/ /*NumOut(0, LCD_LINE2, DR, false); */ NumOut(0, LCD_LINE4,Kp*X, false); /*NumOut(0, LCD_LINE6, dT, false);*/ NumOut(0, LCD_LINE7, Kd*DerX, false); NumOut(0, LCD_LINE8, curAngleInDegrees, false); //PD control DerX = (X - X_old)/dT; // derivative error integral = integral + 1/2 *(X + X_old)*dT; // integral error (useless) angle = (Kp*X) + (Kd*DerX) + (Ki*integral); // command for motor after PD regulation PosRegSetAngle (OUT_A, -angle); // command for the motor X_old = X; //save current error } DISTNxSendCommand(S1, DIST_CMD_DEENERGIZED, DIST_ADDR); // deenegize the sensor }

The picture above shows how does PD control work. The PD control is enough stable and the ball reach the central position in a few seconds but there is a problem when the ball is close to steady state (central position in the beam). This might be due to reasons of structural type (stiffness of the structure or the presence of backlash in the internal gear box) or to problems related to the type of control.

First of all it was increasing the structural stiffness with a new support:

The vibrations of the building are greatly reduced but the problem is still present.

A state space model of a typical plant is given by:

xdot = A*x + B*u

y = C*x + D*u

where A is the state matrix, B is the input matrix, C is the output matrix, D is the direct transmission matrix, x is the plant states, y is the output of the plant, and u is the vector of input signals.

The LQR stands for Linear Quadratic Regulator, which seeks a gain matrix that minimizes some performance index J:

J = ∫ [x'(t)*Q*x(t) + u'(t)R*u(t)]dt

where Q is the state weighting matrix, and R is the control weighting matrix. The optimal gain matrix is calculated by following Equation:

K = R^-1*B'*P

where P is determined by solving the algebraic Riccati Equation, show in following:

A'*P + P*A - P*B*R^-1*B'*P + Q=0

It is important to note that 'a unique, positive definite solution P, which minimizes the performance index J', can be determined by last equation, given that the system is controllable.

It is very important to find a mathematical model very close to real system for implementing a good LQR. The system can be divided into two subsystems in order to find transfer function from input (power to the motor) to output (ball position).

In some cases, plants or systems are so complicated or unknown that dynamics cannot be derived using simple physical laws. Therefore, it is necessary to use other methods to identify mathematical models of those systems. Inputs and outputs of the system have been measured through experiments. With this data, a system identification technique can be used to estimate both structures and parameters of the system.

In order to understand the transfer function from input power and angular speed of the motor, a plot of the step response of the motor (-30% of max power) is shown in the picture; Observing the response, it is possible to assume a I order for the motor system and finally calculate the characteristic parameters:

In this second subsystem it is possible the use of dynamic equations as was shown in the previous section which are summarized in this picture :

Finally the transfer function of this two subsystem are used to build a good mathematical model of the ball and beam system; Matlab gives the possibility to compare the model with real system in order to understand its goodness;

In order to understand the power and efficacy of LQR control, I'm going to compare it with a PD control in order to show advantages.

The Ball and Beam is a MIMO system because a motor position regulator is required for ball position control. Therefore, for PD simulation, I used a specific function called PosRegSetAngle in order to use an internal microcontroller (PID) of servomotor; In this way I can make a PD control of the ball position by introducing a second system identification on the system motor+internalcontroller:

By using Simulink, it is possible to compare actual system with a simulated system that is build from the dynamic equations writing before.

In order to obtain all system parameters, a Matlab code was running before simulation :

clc; close all; clear all; tos= 0.24; os= 8/30; R =0.020; %radius of the ball (m) m = 0.0026; %mass of the ball (kg) psi = sqrt((log(os)*log(os))/((log(os)*log(os))+(pi*pi))); %damping ratio (rad/s) sn = 1/(tos*sqrt(1-psi*psi)/pi); %natural frequency g = 9.8; %gravitational accelaration L = 0.645; %lenght of the beam (m) d = 0.015; % motor radius Jball = (2/5)*(m*(R^2)); %moment of inertia of the ball N = (m * g * d / L)/(m + (Jball/(R^2)));

ATTENTION : before running the following code, place the beam in horizontal position and the ball close to the IR sensor ( 5 cm from it) in order to simulate a disturbance rejection (for more details see the video and observe the initial position of the beam and of the ball)

- PDControl.nxc
#include "dist-nx-lib.nxc" // Range Finder Device Address #define DIST_ADDR 0x02\ // 0.5 1.5 #define P 96 #define I 75 #define D 39 byte fileHandle1; short fileSize1; short bytesWritten1; byte fileHandle2; short fileSize2; short bytesWritten2; byte fileHandle3; short fileSize3; short bytesWritten3; byte fileHandle4; short fileSize4; short bytesWritten4; byte fileHandle5; short fileSize5; short bytesWritten5; float set_point=0.0; float Kp = 450; //from simulation float Kd = 450; float Ki = 0; float X; float curAngleInDegrees; float curAngleInDegreesOld=0.0; float CurPos; float vel; float thetam = 0.0; float X_old=0; float DerX; float integral=0; long angle; float r = 0.0; float dT = 0.1; float t0; float time = 0.0; float time_old; int ReadNum = 30; // number of mesures for sensor calibration int FiltNum = 3; // number of mesures read by the sesor during regolation int i; int j; task main() { DeleteFile("Tempo.txt"); DeleteFile("Data.txt"); DeleteFile("LinVel.txt"); DeleteFile("Theta.txt"); DeleteFile("AngVel.txt"); CreateFile("Tempo.txt", 1000, fileHandle1); CreateFile("Data.txt", 1000, fileHandle2); CreateFile("LinVel.txt", 1000, fileHandle3); CreateFile("Theta.txt", 1000, fileHandle4); CreateFile("AngVel.txt", 1000, fileHandle5); SetMotorRegulationTime (10); PosRegEnable(OUT_A,P,I,D); PosRegSetMax (OUT_A, 0, 0); SetSensorLowspeed(S1); // empower the port 1 for sensor DISTNxSendCommand(S1, DIST_CMD_ENERGIZED, DIST_ADDR); // energize the sensor for (i = 0; i < ReadNum; i++) //cycle for calibration { set_point = set_point + DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR); Wait(100); TextOut(10, LCD_LINE3, "Calibrating..."); } ClearScreen(); set_point = ((set_point/ReadNum)*0.001) + 0.2; // give the set point float dato = 0.0; long theta = 0; float AngVel = 0.0; float LinVel = 0.0; float xapCur = 0.0; float xaCur = 0.0 ; float u = 0.0; char Pwr; float time_old = 0.0; float thetaOld = 0.0; float CurPosOld = DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR)*0.001 - set_point; float CurPos = 0.0; float xapOld = 0.0; t0 = CurrentTick(); while (1) { //cycle for regulation for (j = 0; j < FiltNum; j++) { CurPos = CurPos + DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR)*0.001 - set_point; } CurPos = CurPos/FiltNum; // current error X = CurPos ; //write on file time and error time = (CurrentTick()-t0) * 0.001; theta = MotorRotationCount(OUT_A); thetam = theta * 0.0175 ; AngVel = (thetam - thetaOld)/(time - time_old); LinVel = (CurPos - CurPosOld)/(time - time_old); u = -1 * (Kp*CurPos + Kd*LinVel); ClearScreen(); NumOut(0, LCD_LINE1, u, false); NumOut(0, LCD_LINE2, CurPos, false); NumOut(0, LCD_LINE3, AngVel, false); PosRegSetAngle(OUT_A,u); Pwr = MotorActualSpeed (OUT_A); string tmp1 = NumToStr(time); WriteLnString(fileHandle1,tmp1, bytesWritten1); string tmp2 = NumToStr(X); WriteLnString(fileHandle2,tmp2, bytesWritten2); string tmp3 = NumToStr(Pwr); WriteLnString(fileHandle3,tmp3, bytesWritten3); string tmp4 = NumToStr(theta); WriteLnString(fileHandle4,tmp4, bytesWritten4); string tmp5 = NumToStr(Pwr); WriteLnString(fileHandle5,tmp5, bytesWritten5); time_old = time; thetaOld = thetam; CurPosOld = CurPos; xapOld = xapCur; CurPos = 0.0; } DISTNxSendCommand(S1, DIST_CMD_DEENERGIZED, DIST_ADDR); // deenegize the sensor }

Finally we start simulation and real experiments with NXT and we can see how system react to a disturbance on ball position ( x0 = -0.2 m):

Before applying the LQR system is necessary to convert the transfer function, previously identified, into the state space configuration. A possible state space representation can be :

Xdot = A*X + B*u Y = C*X + D*u

where X is the state vector which consisting of :

x1 = x = ball position

x2 = xdot = ball linear velocity

x3 = theta = angular position of the motor

x4 = thatadot = angular velocity of the motor

u is the input command (% duty cycle) and the matrices are:

A = [ 0 1 0 0 0 0 N 0 0 0 0 1 0 0 0 -1/tau ]

B = [ 0 0 0 -k/tau ]

C = [ 1 0 0 0 0 0 1 0 ]

D = [ 0 0 ]

where :

N = (m*g*d/L)/(m + (Jball/ (r^2)))

tau = time constant of the motor

k = steady state constant of the motor

In order to solve the Riccati equation and find the vector of gains K, it is helpful the use of Matlab code:

clc; close all; clear all; % Iordine.m % this code find the K gains for Simulink model using "lqr" command % Antonio Tota tau= 0.34-0.120; k = 0.1750; R =0.020; %radius of the ball (m) m = 0.0026; %mass of the ball (kg) g = 9.8; %gravitational accelaration L =0.645; %0.390; %lenght of the beam (m) d = 0.015; % motor radius Jball = (2/5)*(m*(R^2)); %moment of inertia of the ball N = (m * g * d / L)/(m + (Jball/(R^2))); A = [0 1 0 0; 0 0 N 0; 0 0 0 1; 0 0 0 -1/tau]; B = [0; 0; 0; k/tau]; C = [1 0 0 0;0 0 1 0]; D = [0;0]; Cm = eye(4); Dm = [0;0;0;0]; Control = ctrb(A,B); Observe = obsv(A,C); controllability = rank(Control); Observability = rank(Observe); Tc = 0.054; %10 ms ts = ss(A,B,C,D); sysd = c2d(ts,Tc); Control1 = ctrb(sysd.a,sysd.b); Observe1 = obsv(sysd.a,sysd.c); controllability1 = rank(Control1) Observability1 = rank(Observe1) poles = eig(A) tsi = 5; %s desired settling time x1max = 0.01; %m max overshoot desired x2max = 0.3; %m/s x3max = 6.6904; %rad max motor angle desired(10° of the beam is good for linearization!!) x4max = 15; %rad/s (max angular speed of motor) umax = 50; %%dc max desired input ro = 100; %according Bryson's Rule, this is the tradeoff between control and energy (input) effort %according Bryson's Rule : Q = [1/(tsi*(x1max^2)) 0 0 0 ; 0 1/(tsi*(x2max^2)) 0 0 ; 0 0 1/(tsi*(x3max^2)) 0 ; 0 0 0 1/(tsi*(x4max^2)) ]; RR = ro/(umax^2) ; K = lqr(A,B,Q,RR) KK=dlqr(sysd.a,sysd.b,Q,RR) sim ('lqrfinalidI.mdl')

Finally, the gains obtained with “lqr” command are used for the following Simulink model:

ATTENTION : before running the following code, place the beam in horizontal position and the ball close to the IR sensor ( 5 cm from it) in order to simulate a disturbance rejection (for more details see the video and observe the initial position of the beam and of the ball)

After simulation, It's time to test the real system by using NXC code: Required Library File: dist-nx-lib.nxc

- LQRControl.nxc
#include "dist-nx-lib.nxc" // Range Finder Device Address #define DIST_ADDR 0x02\ // 0.5 1.5 #define P 96 // useless #define I 75 // useless #define D 39 // useless byte fileHandle1; short fileSize1; short bytesWritten1; byte fileHandle2; short fileSize2; short bytesWritten2; byte fileHandle3; short fileSize3; short bytesWritten3; byte fileHandle4; short fileSize4; short bytesWritten4; byte fileHandle5; short fileSize5; short bytesWritten5; float set_point=0.0; float K1=459.1388; float K2=594.0909; float K3=5.3849; float K4=0.4687; float X; float curAngleInDegrees; float curAngleInDegreesOld=0.0; float CurPos; float vel; float thetam; float X_old=0; float DerX; float integral=0; long angle; float r = 0.0; float dT = 0.1; float t0; float time=0.0; float time_old; int ReadNum = 30; // number of mesures for sensor calibration int FiltNum = 3; // number of mesures read by the sesor during regolation int i; int j; task main() { DeleteFile("Tempo.txt"); DeleteFile("Data.txt"); DeleteFile("LinVel.txt"); DeleteFile("Theta.txt"); //DeleteFile("AngVel.txt"); CreateFile("Tempo.txt", 1000, fileHandle1); CreateFile("Data.txt", 1000, fileHandle2); CreateFile("LinVel.txt", 1000, fileHandle3); CreateFile("Theta.txt", 1000, fileHandle4); //CreateFile("AngVel.txt", 5000, fileHandle5); SetMotorRegulationTime (10); PosRegEnable(OUT_A,P,I,D); PosRegSetMax (OUT_A, 0, 0); SetSensorLowspeed(S1); // empower the port 1 for sensor DISTNxSendCommand(S1, DIST_CMD_ENERGIZED, DIST_ADDR); // energize the sensor for (i = 0; i < ReadNum; i++) //cycle for calibration { set_point = set_point + DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR); Wait(100); TextOut(10, LCD_LINE3, "Calibrating..."); } ClearScreen(); set_point = ((set_point/ReadNum)*0.001) + 0.2; // give the set point float dato = 0.0; long theta = 0; float AngVel = 0.0; float LinVel = 0.0; float xapCur = 0.0; float xaCur = 0.0 ; float u = 0.0; char Pwr; float time_old = 0.0; float thetaOld = 0.0; float CurPosOld = DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR)*0.001 - set_point; float CurPos = 0.0; float xapOld = 0.0; t0 = CurrentTick(); while (1) { //cycle for regulation for (j = 0; j < FiltNum; j++) { CurPos = CurPos + DISTNxReadValue(S1, DIST_REG_DIST_LSB, 2, DIST_ADDR)*0.001 - set_point; } CurPos = CurPos/FiltNum; // current error X = CurPos ; // current error X //write on file time and error time = (CurrentTick()-t0) * 0.001; theta = MotorRotationCount(OUT_A); thetam = theta * 0.0175 ; AngVel = (thetam - thetaOld)/(time - time_old); LinVel = (CurPos - CurPosOld)/(time - time_old); u = -1 * (K1*CurPos + K2*LinVel + K3*thetam + K4*AngVel); ClearScreen(); NumOut(0, LCD_LINE1, u, false); NumOut(0, LCD_LINE2, CurPos, false); NumOut(0, LCD_LINE3, thetam, false); PosRegSetAngle(OUT_A,u); Pwr = MotorActualSpeed (OUT_A); string tmp1 = NumToStr(time); WriteLnString(fileHandle1,tmp1, bytesWritten1); string tmp2 = NumToStr(X); WriteLnString(fileHandle2,tmp2, bytesWritten2); string tmp3 = NumToStr(u); WriteLnString(fileHandle3,tmp3, bytesWritten3); string tmp4 = NumToStr(thetam); WriteLnString(fileHandle4,tmp4, bytesWritten4); string tmp5 = NumToStr(Pwr); WriteLnString(fileHandle5,tmp5, bytesWritten5); time_old = time; thetaOld = thetam; CurPosOld = CurPos; xapOld = xapCur; CurPos = 0.0; //Wait(20); } DISTNxSendCommand(S1, DIST_CMD_DEENERGIZED, DIST_ADDR); // deenegize the sensor }

Finally we start simulation and real experiments with NXT and we can see how system react to a disturbance on ball position ( x0 = -0.2 m):

x is equal to zero when the ball is in the center position of the beam, so if a disturbance is introduced the system react to it as shown in the picture below :

It was shown how singular controller works in presence of external disturbance, but which of them is the best one?

1)First of all, in PD control I use a second microcontroller (PosRegSetAngle) inside the servomotor which is not necessary in LQR control

2)The setting of PD gains required a lot of trials and experience

3)The PD control doesn’t consider an optimitation of energy in input used during regolation (that’s the big difference from LQR control)

Let's understand better what does it means:

The previous analysis was only on simulation scenario, but it is possible to reach the same conclusions on real scenario by using nxt lego; The previous simulink model were «ideal» in the sense that it doesn't consider some nonlinearities which are present on real system. Firstly, I use on NXT the same gains obtained from previous ideal simulation:

Of course there is a discrepancy between real and simulated behavior but what I stated previously is still visible. Overshoot and time settling is quite similar but there is a big difference in control effort as I discussed before in the simulation (about energy saving).

The difference from ideal simulation and actual reality could be due to several possible reasons:

1)System identification of motor system

2)Deadzones

3)Resolution and accuracy of sensors

4)Discrete system (and not continuos)

5)Friction between ball and beam

It could be possible to implement some of these nonlinearity in the simulink model in order to reach a simulation closer to reality:

By using this new Simulink model, we can observe the nonlinearities also in the simulation:

In my opinion the friction between ball an beam plays important role, especially at the beginning of the regulation where u is nonzero value but the ball is stuck, and this could be bring a sort of delay as picture shown.

Previous experiments show how the system react to an external disturbance; It is possible to implement a Track System Control which means that the system starts in Zero position (all states are equal to 0) and a command on the ball position will send to it. In this way, it is possible to implement also an integrator which will reduce the steady state error ( mainly due to the friction ).

Let we see how the system react to a step command of x = -0.2 m :

In this situation , without changing Q and R matrix, the control effort (time settling = 5 s ; overshoot = 1%; umax = 50%) is not accomplished. This is mainly due to the presence of the discrete integrator and the Gain Compensation M which ,at the same time, cancel the steady state error.

In order to build by yourself the Ball and Beam System, building instructions of the final project design are proposed in the following link:

lego_ball_and_beam_v2.txt · Last modified: 2016/11/09 15:44 by dwallace