Buscar en este blog

miércoles, 23 de mayo de 2007

DIFFERENTIAL DRIVE (Implulso Diferencial)


La figura anterior muestra el diseño básico de un robot para el cálculo de la Odometría basada en el impulso diferencial, de tal manera que el robot puede realizar una estimación muerta (dead reckoning) a través de ecuaciones geométricas simples. Los encoders son colocados sobre los motores de las llantas del robot para calcular las revoluciones.

El robot podrá calcular su posición actual una vez conocida su posición inicial.

Las ecuaciones para la calcular la Odometría son las siguientes:

cm = πDn/nCe (1.2)

Donde:
cm = factor de conversión que transforma los pulsos del encoder en un desplazamiento lineal de la rueda.
D n = diámetro nominal de la rueda (en mm)
C e = resolución del encoder (en pulsos por revolución)
n = proporción de reducción de la marcha del motor debido a la localización del encoder sobre el eje del motor o junto a la rueda (si el encoder se encuentra junto a la rueda tomar n = 1).

Se puede estimar la distancia recorrida (incrementalmente) por las llantas izquierda (ΔUL,i) y derecha (ΔUR,i) de la siguiente forma:

ΔUR/L,i = cm N L/R, I (1.3)

Donde:
N L/R: incremento de los pulsos en la llanta izquierda o derecha.

También es posible calcular el desplazamiento a través de la distancia incremental recorrida linealmente por el robot tomando como referencia el centro del eje de las llantas (punto C en la figura anterior) como sigue:

ΔUi = (ΔUR +ΔUL )/2 (1.4)

Posteriormente, es posible calcular la orientación del robot:

Δθi = (ΔUR - ΔUL)/b (1.5)

Donde:
b= (wheelbase)es la distancia entre 2 puntos de contacto(las ruedas)

Una vez mas es posible calcular el incremento en la orientación θi de robot con la ecuación:

θi = θi-1 + Δθi

y las coordenadas del punto c de la siguiente manera:

xi = x i-1 + ΔU cosθ (1.7a)
yi = y i-1 + ΔUsinθ (1.7b)

Donde: (xi, yi) son las coordenadas del punto C en el instante i.

martes, 22 de mayo de 2007

ODOMETRÍA

Referencia: “Where am I?” Sensors and Methods for Mobile Robot Positioning

La Odometría es el método de navegación mas usado en el posicionamiento de robots móviles.
La Odometría es la estimación del movimiento de un vehículo tomando como base la rotación de sus ruedas. Las mediciones se calculan incrementalmente, lo que involucra la existencia inevitable de un error. Este error incrementa proporcionalmente con la distancia recorrida por el vehículo.

ERRORES DE ODOMETRÍA SISTEMÁTICOS Y NO SISTEMÁTICOS

Errores Sistemáticos:
Utilizar ruedas con diámetro diferente
El diámetro real de las ruedas difiere del diámetro nominal
Mala alineación de las ruedas
La base de la rueda real difiere de la nominal
Resolución finita del encoger
Frecuencia de muestreo finita

Errores no sistemáticos
Viajar a través de superficies irregulares
Viajar y encontrar objetos inesperados en la superficie
Derrape de las ruedas atribuible a:
Pisos resbaladizos
Sobre-aceleración
Patinar/derrapar
Fuerzas externas (interacción con cuerpos externos)
Fuerzas internas (rodamiento de ruedecillas)
Perder el contacto de las ruedas con el piso

Los errores sistemáticos son realmente importantes, ya que se acumulan constantemente, entonces, es importante detectar si un error es sistemático o no, para así lograr reducir el error de odometría que se acumula. Por ejemplo, en muchas superficies interiores lisas, el error sistemático contribuye mucho más a aumentar el error de odometría que los errores no sistemáticos.

DEAD RECKONING

Es un procedimiento matemático simple para estimar una posición actual de un dispositivo basada en una posición determinada previamente, y avanzando a esa posición sobre la base de una velocidad conocida, tiempo transcurrido, y dirección.
http://en.wikipedia.org/wiki/Dead_reckoning
mas...Where am I? Sensors and Methods for Mobile Robot Positioning

La implementación mas simple de Dead Reckoning es en la mayoría de las veces la Odometría, esto implica que el desplazamiento de un vehículo a lo largo de una trayectoria de viaje es obtenido directamente de un odómetro.

Un odómetro, (del griego ὁδός, camino y -metro, medir. Que mide el camino).
Un odómetro es un dispositivo que indica la distancia recorrida en un viaje por
automóvil u otro vehículo.

Comúnmente la instrumentación odométrica incluye encoders ópticos directamente acoplados a la armadura del motor o a los ángulos de las ruedas, sin embargo la elección del tipo de encoder depende de la complejidad de la aplicación.

La exactitud de las mediciones odométricas para el dead reckoning es en gran medida una función directa del diseño de la cinemática del vehículo.

La energía cinética es la energía que posee un cuerpo de masa m por encontrarse en movimiento. Es un error común creer que por "movimiento" se habla de movimiento lineal v. Existe también el movimiento angular ω, y no puede ser ignorado. Desde un punto de vista formal, la energía cinética es el trabajo necesario para acelerar una partícula desde una velocidad (angular y lineal) nula hasta una velocidad (angular y lineal) dada. Las unidades del SI para la energía son julios o joules.
http://es.wikipedia.org/wiki/Energ%C3%ADa_cin%C3%A9tica

ESCALA GEOMÉTRICA (Geometric Scaling)



Nombres comunes: Scale, Zoom, Shrink, Píxel Replication, Píxel Interpolation, Subsampling.

Puede ser usada para agrandar o reducir el tamaño de una imagen (o parte de una imagen). La reducción de una imagen es conocida generalmente como subsampling, y puede lograrse de dos maneras: una a través del remplazamiento (de los valores de un grupo de pixeles por un valor seleccionado arbitrariamente dentro de los valores de ese grupo) y la otra por interpolación (promediando los valores de intensidad de un grupo de pixeles para obtener el valor de intensidad de un píxel en la imagen reducida).

Este proceso no solo reduce el tamaño de los datos, sino también los efectos del ruido como sal y pimienta o el ruido gausiano.

Implementación en OpenCV

Resize
Resizes image
void cvResize( const CvArr* src, CvArr* dst, int interpolation=CV_INTER_LINEAR );
src
Source image.
dst
Destination image.
interpolation
Interpolation method:
· CV_INTER_NN - nearest-neigbor interpolation,
· CV_INTER_LINEAR - bilinear interpolation (used by default)
· CV_INTER_AREA - resampling using pixel area relation. It is preferred method for image decimation that gives moire-free results. In case of zooming it is similar to CV_INTER_NN method.
· CV_INTER_CUBIC - bicubic interpolation.
The function cvResize resizes image src so that it fits exactly to dst. If ROI is set, the function consideres the ROI as supported as usual.


CÓDIGO PARA REDUCIR EL TAMAÑO DE UNA IMAGEN

#include"highgui.h"
#include"cxcore.h"
#include"cv.h"
#include"cvaux.h"
#include"math.h"
#include"iostream.h"

void main(){
IplImage* img1 = cvLoadImage("../cam1.bmp", 1);
IplImage* img2 = cvLoadImage("../leg1.bmp", 1);

cvNamedWindow("Imagen Original (1)", 1);
cvShowImage("Imagen Original (1)", img1);

cvNamedWindow("Imagen Original (2)", 1);
cvShowImage("Imagen Original (2)", img2);

cvResize(img1, img2, CV_INTER_LINEAR);

cvNamedWindow("Imagen modificada", 1);
cvShowImage("Imagen modificada", img2);

cvWaitKey(0);
cvDestroyWindow("Imagen Original (1)");
cvDestroyWindow("Imagen Original (2)");
cvDestroyWindow("Imagen modificada");
}


En el código anterior se utilizaron dos imágenes de tamaños diferentes (cam1.bmp de 256x256 y leg1.bmp de 700x500) que son las siguientes:



cam1



leg1

lunes, 21 de mayo de 2007

NAVEGACIÓN ROBÓTICA CON FISCHERTECHNIK -Teclado de Dirección- (26-Marzo-07)

El siguiente programa hace funcionar el robot utilizando el teclado de dirección para especificar la dirección en la que ha de moverse:

#include "Windows.h"
#include "iostream.h"
#include "conio.h"
#include "stdio.h"
#include "umFish40VC.H"

void main() {

char Ende;
char c;

cout << "Corriendo" << endl;
int iHandle = rbOpenInterfaceUSB(ftROBO_first_USB, 0);

if (iHandle == rbFehler) {
cout << "No se ha podido conectar con la interfaz" << endl;
cin.get(Ende);
return;
}

c=getch();

do{ if(c == 75){ //derecha
rbSetMotor(iHandle,1,0);
rbSetMotor(iHandle,2,1);
Sleep(100);
}

if(c == 77){//izquierda
rbSetMotor(iHandle,2,0);
rbSetMotor(iHandle,1,1);
Sleep(100);
}

if(c == 72){//adelante
rbSetMotor(iHandle,1,1);
rbSetMotor(iHandle,2,1);
Sleep(100);
}

if(c == 80){//atras
rbSetMotor(iHandle,1,2);
rbSetMotor(iHandle,2,2);
Sleep(100);
}

if(c == 15){//parar
rbSetMotor(iHandle,1,0);
rbSetMotor(iHandle,2,0);
}

c=getch();

}while(c!=27);

rbCloseInterface(iHandle);
cout << endl << "Prueba terminada" << endl;
cin.get(Ende);

}

viernes, 18 de mayo de 2007

PROCESAMIENTO DE IMAGENES - TEMPLATE MATCHING

Template Matching es una técnica dentro del procesamiento de imagenes que nos sirve para encontrar partes pequeñas de una imagen (template), dentro de una imagen completa. http://en.wikipedia.org/wiki/Template_matching
Es una medida de qué tan bien un template en niveles de gris g(x,y) se ajusta a una imagen f(x,y) dada. Se puede usar una función de distancia o una NCC (normalized cross-correlation). http://rkb.home.cern.ch/rkb/AN16pp/


Es una técnica de reconocimiento de patrones que consiste en buscar en una imagen I, una imagen mas pequeña denominada patron o template (T).

Dada una imagen A de tamaño (WxH), y P una imagen mas pequeña denominada patron de tamaño (wxh), el resultado es una imagen M de tamaño (W-w+1)x(H-h+1), en donde cada uno de sus pixeles indica la verosimilitud o probabilidad de que el rectangulo [x,y], [x+w-1, y+h-1] de A contenga el patron P.





El siguiente código ilustra el uso de la función cvMatchTemplate() de Open CV


MatchTemplate
Compares template against overlapped image regions
void cvMatchTemplate( const CvArr* I, const CvArr* T,CvArr* result, int method );
I
Image where the search is running. It should be single-chanel, 8-bit or 32-bit floating-point.
T
Searched template; must be not greater than the source image and the same data type as the image.
R
Image of comparison results; single-channel 32-bit floating-point. If I is W×H and T is w×h then R
must be W-w+1×H-h+1.
method
Specifies the way the template must be compared with image regions (see below).


The function cvMatchTemplate [p 202] is similiar to cvCalcBackProjectPatch [p 199] . It slids through I,
compares w×h patches against T using the specified method and stores the comparison results to result.
Here are the formular for the different comparison methods one may use (the summation is done over
template and/or the image patch: x’=0..w-1, y’=0..h-1):

method=CV_TM_SQDIFF:
R(x,y)=sum x’,y’ [T(x’,y’)-I(x+x’,y+y’)] 2

method=CV_TM_SQDIFF_NORMED:
R(x,y)=sum x’,y’ [T(x’,y’)-I(x+x’,y+y’)] 2 /sqrt[sum x’,y’ T(x’,y’) 2 ·sum x’,y’ I(x+x’,y+y’) 2 ]

method=CV_TM_CCORR:
R(x,y)=sum x’,y’ [T(x’,y’)·I(x+x’,y+y’)]


method=CV_TM_CCORR_NORMED:
R(x,y)=sum x’,y’ [T(x’,y’)·I(x+x’,y+y’)]/sqrt[sum x’,y’ T(x’,y’) 2 ·sum x’,y’ I(x+x’,y+y’) 2 ]

method=CV_TM_CCOEFF:
R(x,y)=sum x’,y’ [T’(x’,y’)·I’(x+x’,y+y’)],
where T’(x’,y’)=T(x’,y’) - 1/(w·h)·sum x",y" T(x",y") (mean template brightness=>0)
I’(x+x’,y+y’)=I(x+x’,y+y’) - 1/(w·h)·sum x",y" I(x+x",y+y") (mean patch brightness=>0)

method=CV_TM_CCOEFF_NORMED:
R(x,y)=sum x’,y’ [T’(x’,y’)·I’(x+x’,y+y’)]/sqrt[sum x’,y’ T’(x’,y’) 2 ·sum x’,y’ I’(x+x’,y+y’) 2 ]

After the function finishes comparison, the best matches can be found as global minimums
(CV_TM_SQDIFF*) or maximums (CV_TM_CCORR* and CV_TM_CCOEFF*) using cvMinMaxLoc


#include "cv.h"
#include "highgui.h "
#include "stdio.h"


int main() {


IplImage* im = cvLoadImage( "../cam1.jpg", -1); //-1 indica que cargue la imagen en sus colores y caracteristicas originales

if( im == 0 ) {
std::cerr << "Error al cargar la imagen: " <<>
return 1;
}

IplImage* imG = cvCreateImage(cvSize(im->width, im->height), 8, 1);//direcciona un espacio en memoria con las dimensiones de ancho y alto de im, con 8 bits y 1 canal

cvCvtColor(im, imG, CV_BGR2GRAY);//img cambia su espacio de color al espacio de color de im, (BGR2GRAY)


//coordenadas iniciales del rectángulo
int xVal = 150;
int yVal = 50;
int neighLength = 25;
CvRect rect = cvRect(xVal,yVal,neighLength,neighLength);//traza una area rectangular

CvMat* tplate = cvCreateMat(neighLength, neighLength, CV_8UC1);//cvCreateMat crea una matriz(renglones, columnas, tipo de elemento)CV_8UC1(8 bits unsigned, 1 canal)

cvGetSubRect(imG, tplate, rect );//obtiene de img el area definida por rect y la asigna a tplate

//se especifica el tamaño necesario para realizar la función matching
int resultW = imG->width - tplate->width + 1;
int resultH = imG->height - tplate->height +1;

//direcciona el espacio para cada imagen
IplImage* result0 = cvCreateImage(cvSize(resultW, resultH), IPL_DEPTH_32F, 1);
IplImage* result1 = cvCreateImage(cvSize(resultW, resultH), IPL_DEPTH_32F, 1);
IplImage* result2 = cvCreateImage(cvSize(resultW, resultH), IPL_DEPTH_32F, 1);
IplImage* result3 = cvCreateImage(cvSize(resultW, resultH), IPL_DEPTH_32F, 1);
IplImage* result4 = cvCreateImage(cvSize(resultW, resultH), IPL_DEPTH_32F, 1);
IplImage* result5 = cvCreateImage(cvSize(resultW, resultH), IPL_DEPTH_32F, 1);

//se aplican cada una de las técnicas de matching
cvMatchTemplate(imG, tplate, result0, CV_TM_SQDIFF);
cvMatchTemplate(imG, tplate, result1, CV_TM_SQDIFF_NORMED);
cvMatchTemplate(imG, tplate, result2, CV_TM_CCORR);
cvMatchTemplate(imG, tplate, result3, CV_TM_CCORR_NORMED);
cvMatchTemplate(imG, tplate, result4, CV_TM_CCOEFF);
cvMatchTemplate(imG, tplate, result5, CV_TM_CCOEFF_NORMED);

//se muestra el resultado del matching
cvNamedWindow("SQDIFF", 0 );
cvNamedWindow("SQDIFF_NORMED",0);
cvNamedWindow("CCORR",0);
cvNamedWindow("CCORR_NORMED",0);
cvNamedWindow("CCOEFF",0);
cvNamedWindow("CCOEEFF_NORMED",0);

cvShowImage("SQDIFF", result0);
cvShowImage("SQDIFF_NORMED", result1);
cvShowImage("CCORR", result2);
cvShowImage("CCORR_NORMED", result3);
cvShowImage("CCOEFF", result4);
cvShowImage("CCOEEFF_NORMED", result5);

//marca el área en la imagen original de donde se obtuvo el template
cvRectangle(imG, cvPoint(xVal,yVal), cvPoint(xVal+neighLength,yVal+neighLength),
CV_RGB(255,0,255),2 , 8, 0);

//muestra la imagen y el template
cvNamedWindow("Image",0);
cvNamedWindow("Template",0);
cvShowImage("Image", imG);
cvShowImage("Template", tplate);

cvWaitKey(0);

cvReleaseImage(&imG);
cvReleaseMat(&tplate);
cvReleaseImage(&result0);
cvReleaseImage(&result1);
cvReleaseImage(&result2);
cvReleaseImage(&result3);
cvReleaseImage(&result4);
cvReleaseImage(&result5);

cvDestroyAllWindows();

return 0;

}


SIMULANDO EL FUNCIONAMIENTO DE UNA CÁMARA FOTOGRÁFICA CON OPENCV (18-Mayo-07)

En este apartado se presenta el código fuente de un programa que permite enfocar la imagen observada en la computadora para posteriormente almacenarla en el disco duro. El programa permite guardar 10 imagenes.

#include "stdio.h"
#include "conio.h"
#include "cv.h"
#include "highgui.h"
#include "cxcore.h"
#include "cvaux.h"

int main(){

char* nomImages[] = {".\img_1.jpg", ".\img_2.jpg", ".\img_3.jpg", ".\img_4.jpg", ".\img_5.jpg", ".\img_6.jpg", ".\img_7.jpg", ".\img_8.jpg", ".\img_9.jpg", ".\img_10.jpg"};

CvCapture* capture = cvCaptureFromCAM(-1);
if(!capture){
printf("Error: Capture = NULL\n");
getchar();
return -1;
}

cvNamedWindow("cvSaveImage", 1);

for(int i=0; i<10;>

while(1){

IplImage* frame = cvQueryFrame(capture);

if(!frame) {
printf("Error: Frame = NULL\n");
getchar();
return -1;
}

cvShowImage("cvSaveImage", frame);

if((cvWaitKey(10) & 255)==27) break;

}

IplImage* frame = cvQueryFrame(capture);

if(!frame) {
printf("Error: Frame = NULL\n");
getchar();
return -1;
}

cvShowImage("cvSaveImage", frame);

cvSaveImage(nomImages[i], frame);

printf("imagen %d",i);

cvWaitKey(0);

}

cvReleaseCapture(&capture);
cvDestroyWindow("cvSaveImage");
return(0);

}