Вы находитесь на странице: 1из 36

ANALISIS PARA CONTROL PID

Arduino Signal Analysis with Processing


adrianAugust 20, 2016Arduino, OmniTopic, Programming, Robotics

En muchas ocasiones es necesario de disponer de un osciloscopio para medir y analizar las seales que se ejecutan en
nuestros programas con Arduino.
Con razn a un experimento; introducir un ejemplo de cmo podemos llevar a cabo estos anlisis para poderlos ver
grficamente a travs de Processing.
Este ejemplo dispone de un sensor ptico que detecta los flancos de un encoder pegado a una rueda encoder pegado
a un motor.

En mi caso tengo un sensor OPTEK; en cualquiera de sus series OPB; que se pueden encontrar facilmente desguazando
un ratn con scroll o impresora viejas. Una vez conseguido, lo tendremos que disponer en un eje giratoria. Para hacer
pruebas se puede buscar una manera de medir el paso de luz o no alternativamente.
Cuando ya lo tengamos conectado, el montaje sobre la placa se realiza como aparece en la siguiente imagen.
Aho
ra deberemos hacer un programa para leer los estados. Primero voy a proporcionar un cdigo en el que se leen los
estados en bajo o en alto. Pero seguidamente lo haremos con interrupciones, que es una manera mejor de elaborar este
control.

Lectura de estado del sensor


1 const int Pin = 2;
2

4 void setup() {

Serial.begin(9600);
5
pinMode(Pin, INPUT_PULLUP);
6
}
7

8
void loop() {
9
bool value = digitalRead(Pin);
1
0

11 Serial.write( 0xff );

1 Serial.write( (value >> 8) & 0xff );


2
Serial.write( value & 0xff );
1
3 }

1
4

Como se puede observar, hay unos Serial.write un poco raros. Estas funciones sern las encargadas de imprimir a
travs del puerto serie a nuestro ordenador los valores actualizados de nuestra rueda y Processing los recopilar para
desarrollar una grfica temporal en el que se podr ver la evolucin de los estados en todo momento.
Copiamos el siguiente cdigo en Processing.
1 import processing.serial.*;

Serial port; // Create object from Serial class


3

int val; // Data received from the serial port


4
int[] values;
5
float zoom;
6

7
void setup()
8 {

size(1280, 480);
9

// Open the port that the board is connected to and use the same speed (9600 bps)
1
0
port = new Serial(this, Serial.list()[0], 9600);

11 values = new int[width];

1 zoom = 1.0f;
2
smooth();
1
3 }

1
4
int getY(int val) {
1
5 return (int)(height - val / 3.0f * (height - 1))-height/3;

1 }
6

1
7
1 int getValue() {
8
int value = -1;
1
9 while (port.available() >= 3) {

if (port.read() == 0xff) {
2
0
value = (port.read() << 8) | (port.read());

2
}
1
}
2
2
return value;

2 }
3

2
4 void pushValue(int value) {

2 for (int i=0; i<width-1; i++)


5
values[i] = values[i+1];
2
6 values[width-1] = value;
2 }
7

2
8 void drawLines() {

2 stroke(255);
9

3
0 int displayWidth = (int) (width / zoom);

3
1
int k = values.length - displayWidth;
3
2

3 int x0 = 0;
3
int y0 = getY(values[k]);
3
4 for (int i=1; i<displayWidth; i++) {

3 k++;
5
3 int x1 = (int) (i * (width-1) / (displayWidth-1));
6
int y1 = getY(values[k]);
3
7 line(x0, y0, x1, y1);

x0 = x1;
3
8
y0 = y1;

3
}
9
}
4
0

4
void drawGrid() {
1
stroke(255, 0, 0);
4
2 line(0, height/2, width, height/2);

4 }
3

4
4
4 void keyReleased() {
5
switch (key) {
4
6 case '+':

zoom *= 2.0f;
4
7
println(zoom);

4
if ( (int) (width / zoom) <= 1 )
8
zoom /= 2.0f;
4
9
break;

5 case '-':
0
zoom /= 2.0f;
5
1 if (zoom < 1.0f)

5 zoom *= 2.0f;
2
break;
5
3 }
5 }
4

5
5 void draw()

5 {
6
background(0);
5
7 drawGrid();

val = getValue();
5
8
if (val != -1) {

5
pushValue(val);
9
}
6
0 drawLines();

6 }
1

6
2
6
3

6
4

6
5

6
6

6
7

6
8

6
9

7
0

7
1
7
2

7
3

7
4

7
5

7
6

7
7

7
8

7
9

8
0
8
1

8
2

8
3

8
4

8
5

8
6

8
7
Lectura incremental del sensor
1 const int Pin = 2;

int wheel = 0;
2

bool lastValue;
3

4
void setup() {
5
Serial.begin(9600);
6
pinMode(Pin, INPUT_PULLUP);
7
lastValue = digitalRead(Pin);
8
}

1
0 void loop() {

bool value = digitalRead(Pin);


11
if(value != lastValue){
1
2
1 wheel++;
3
lastValue = value;
1
4 }

Serial.write( 0xff );
1
5
Serial.write( (wheel >> 8) & 0xff );

1
Serial.write( wheel & 0xff );
6
}
1
7

1
8

1
9

2
0

Este cdigo lo nico que hace es leer continuamente el valor leido de nuestro sensor y en el momento de cambio de
estado sumar uno a la variable wheel que es la encargada de contar en qu parte del giro se encuentra sta.
Copiamos el siguiente cdigo en Processing en el que solo cambiaremos la escala para poder visualizar un rango
amplio de valores.
1 import processing.serial.*;

Serial port; // Create object from Serial class


3

int val; // Data received from the serial port


4
int[] values;
5
float zoom;
6

7
void setup()
8
{
9
size(1280, 480);

1
0 // Open the port that the board is connected to and use the same speed (9600 bps)

port = new Serial(this, Serial.list()[0], 9600);


11
1 values = new int[width];
2
zoom = 1.0f;
1
3 smooth();

}
1
4

1
5 int getY(int val) {

return (int)(height - val / 40.0f * (height - 1));


1
6
}

1
7

int getValue() {
1
8
int value = -1;

1 while (port.available() >= 3) {


9
if (port.read() == 0xff) {
2
0
2 value = (port.read() << 8) | (port.read());
1
}
2
2 }

return value;
2
3
}

2
4

void pushValue(int value) {


2
5
for (int i=0; i<width-1; i++)

2
values[i] = values[i+1];
6
values[width-1] = value;
2
7 }

2
8
void drawLines() {
2
9
3 stroke(255);
0

3
1 int displayWidth = (int) (width / zoom);

3
2
int k = values.length - displayWidth;
3
3

3 int x0 = 0;
4
int y0 = getY(values[k]);
3
5 for (int i=1; i<displayWidth; i++) {

3 k++;
6
int x1 = (int) (i * (width-1) / (displayWidth-1));

3
7 int y1 = getY(values[k]);

line(x0, y0, x1, y1);


3
8
3 x0 = x1;
9
y0 = y1;
4
0 }

}
4
1

4
2 void drawGrid() {

stroke(255, 0, 0);
4
3
line(0, height/2, width, height/2);

4
}
4

4
5
void keyReleased() {

4 switch (key) {
6
case '+':
4
7
4 zoom *= 2.0f;
8
println(zoom);
4
9 if ( (int) (width / zoom) <= 1 )

zoom /= 2.0f;
5
0
break;

5
case '-':
1
zoom /= 2.0f;
5
2
if (zoom < 1.0f)

5 zoom *= 2.0f;
3
break;
5
4 }

5 }
5

5
6 void draw()
5 {
7
background(0);
5
8 drawGrid();

val = getValue();
5
9
if (val != -1) {

6
pushValue(val);
0
}
6
1
drawLines();

6 }
2

6
3

6
4

6
5
6
6

6
7

6
8

6
9

7
0

7
1

7
2

7
3

7
4
7
5

7
6

7
7

7
8

7
9

8
0

8
1

8
2

8
3
8
4

8
5

8
6

8
7

Ahora podremos visualizar el siguiente resultado mientras hacemos girar la rueda. El nmero de ranuras son 20, y como
estamos elaborando un control de cambio de estados a lectura con ranura y sin ranura, multiplicando por 2 tendremos
el giro de una vuelta completa de la rueda. Por ello la escala de la grfica est limitada a 40. En el momento que
superemos 40 ranuras llegar a arriba del todo.
De todas maneras, hemos comentado que hay un mtodo mejor para recopilar la informacin de la seal para este
caso; y es con interrupciones.
Las interrupciones son unos pines especiales capaces de detectar un evento ocurrido en la seal para ejecutar una
accin. Por ejemplo, cada vez que cambia el estado de un sensor, se puede ejecutar la funcin sumar una unidad a
un contador, como hacemos en el cdigo anterior.
La mayor ventaja de este procedimiento es que la interrupcin asociada al pin recoge ese evento e interrumpe la
ejecucin natural del cdigo para actualizar ese estado y prioriza la funcin que se ha declarado dentro de la misma.
Existen 4 eventos dentro de una interrupcin.
o LOW > Dispara la funcin siempre y cuando el Pin est en bajo.
o CHANGE > Dispara la funcin cuando el estado cambia. De bajo a alto o de alto a bajo indiferentemente.
o RISING > Dispara la funcin cuando el estado cambia de bajo a alto.
o FALLING > Dispara la funcin cuando el estado cambia de alto a bajo.

o HIGH (SOLO PARA ARDUINO DUE) >Dispara la funcin siempre y cuando el Pin est en alto.
Hay que tener en cuenta que cada placa tiene un nmero de interrupciones definidos.Y no es casualidad haber escogido
el Pin 2 para este ejercicio, ya que la placa Arduino UNO, tiene solo dos interrupciones en el PIN 2 y en el PIN 3.
El caso que nuestro cdigo en Arduino quedar de esta nueva forma y ejecutar lo mismo, pero mejor.

1 const byte IntPin = 2;

volatile int wheel = 0;


2

void setup()
4
{
5
6 Serial.begin(9600);

attachInterrupt(digitalPinToInterrupt(IntPin), counterwheel, CHANGE);


7

}
8

9
void loop() {
1
0

11 Serial.write( 0xff );

1 Serial.write( (wheel >> 8) & 0xff );


2
Serial.write( wheel & 0xff );
1
3 }

1
4
void counterwheel(){
1
5 wheel++;

1
6 }

1
7

1
8

1
9

Seguidamente expondr otro ejemplo que se puede realizar para establecer el contador a cero cuando demos una
vuelta completa; y de esta manera podamos visualizarlo en la grfica en sucesivos giros.

1 const byte IntPin = 2;

volatile int wheel = 0;


2

void setup(){
4
Serial.begin(9600);
5 attachInterrupt(digitalPinToInterrupt(IntPin), counterwheel, CHANGE);

}
6

void loop() {
8

9
Serial.write( 0xff );
1
0 Serial.write( (wheel >> 8) & 0xff );

11 Serial.write( wheel & 0xff );

1 if (wheel >= 40){


2
wheel =0;
1
3 }

1 }
4

1
5
1 void counterwheel(){
6
wheel++;
1
7 }

1
8

1
9

2
0

2
1
Como se puede ver en la siguiente grfica, cada subida es una vuelta completa a la rueda.

En la siguiente entrada aprovecharemos este cdigo para


realizar un control con PID.

Вам также может понравиться