/*
DETECCIÓN Y SEGUIMIENTO DE VISITANTES CON ROBOT MÓVIL Alfredo Morales Pinzón
Asesor: Fernando De la Rosa Universidad de los Andes
Archivo:servidorSeguidor.cpp
En este archivo se encuentra en código fuente de la aplicación desarrollada para la detección y el seguimiento de visitantes con robot móvil.
Este código ha sido generado a partir de códigos base de MobileRobots. En especifico se usaron los ejemplos: actsColorFollowingExample y serverDemo (ArNetworking).
*/
//Librerias
#include "Aria.h"
#include "ArNetworking.h"
//Clase "Seguir" que hace la rutina de detección y seguimiento del visitante.
//Es importante anotar que el método fire de la clase es el que se invocará
//por cada ciclo de ejecución del robot. class Seguir : public ArAction
{
public:
// The state of the Seguir action enum State {
NO_TARGET, // There is no target in view TARGET, // This is a target in view };
// Constructor
Seguir(ArACTS_1_2 *acts, ArVCC4 *camera, ArKeyHandler *keyHandler);
// Destructor ~Seguir(void);
// Activa la rutina de detección y seguimiento void activar();
//Desactiva la rutina de detección y seguimiento void desactivar();
// Cambia parámetros de movimiento para avanzar void avanzar();
// Cambia parámetros de movimiento para frenar (Disminuir velocidad)
41
void frenar();
// Cambia parámetros de movimiento para parar void parar();
// Cambia parámetros de movimiento para girar a la derecha void girarDerecha();
// Cambia parámetros de movimiento para girar a la izquierda void girarIzquierda();
// The action
ArActionDesired *fire(ArActionDesired currentDesired);
// Set the ACTS channel that we want to get blob info from bool setChannel(int channel);
// Return the current state of this action State getState(void) { return myState; }
// Height and width of pixels from frame-grabber enum {
WIDTH = 160, HEIGHT = 120 };
protected:
// Action que se desea ejecute el robot ArActionDesired myDesired;
// Se encargada de hacer la conexión con ACTS ArACTS_1_2 *myActs;
// Se encarga de hacer la conexión con la cámara para su control ArVCC4 *myCamera;
// Ultimo tiempo en que se vio el objeto de detección ArTime myLastSeen;
// Estado de la clase State myState;
//Canal de obtención de datos de ACTS int myChannel;
// Máximo tiempo de espera para obtener una detección int myMaxTime;
// Handler de teclado
ArKeyHandler *myKeyHandler;
// Funtores de los métodos de movimiento. Se usan para estableces // funciones de callback. ArFunctorC<Seguir> activarCB; ArFunctorC<Seguir> desactivarCB; ArFunctorC<Seguir> avanzarCB; ArFunctorC<Seguir> frenarCB; ArFunctorC<Seguir> pararCB; ArFunctorC<Seguir> girarDerechaCB; ArFunctorC<Seguir> girarIzquierdaCB;
// Estado de la rutina de seguimiento (Activada/Desactivada) bool seguirActivado;
// Estado del movimiento dado por el usuario mediante el teclado bool mover;
42
int deltaAngulo;
// Cantidad de movimiento incremental dada por el usuario al mover el robot
int deltaVelocidad;
// Numero de incrementos en velocidad (Positivos o Negativos) int adelante;
// Numero de incrementos en rotación (Positivos o Negativos) int izquierda;
};
// Constructor: Initialize the Seguir action
Seguir::Seguir(ArACTS_1_2 *acts, ArVCC4 *camera, ArKeyHandler *keyHandler) :
myKeyHandler(keyHandler), ArAction("Seguir", "Seguir the largest blob."),activarCB(this, &Seguir::activar)
,desactivarCB(this, &Seguir::desactivar), avanzarCB(this, &Seguir::avanzar), pararCB(this, &Seguir::parar)
,girarDerechaCB(this, &Seguir::girarDerecha),girarIzquierdaCB(this, &Seguir::girarIzquierda), frenarCB(this, &Seguir::frenar)
{ //Inicialización de atributos myActs = acts; myCamera = camera; myChannel = 0; myState = NO_TARGET; setChannel(1); myLastSeen.setToNow(); myMaxTime = 1000; seguirActivado = false; mover = false; adelante = 0; izquierda = 0; deltaVelocidad = 15; deltaAngulo = 12;
//Se añaden las funciones de CallBack al handler del teclado myKeyHandler->addKeyHandler('a', &activarCB); myKeyHandler->addKeyHandler('d', &desactivarCB); myKeyHandler->addKeyHandler(ArKeyHandler::UP, &avanzarCB); myKeyHandler->addKeyHandler(ArKeyHandler::DOWN, &frenarCB); myKeyHandler->addKeyHandler(ArKeyHandler::SPACE, ¶rCB); myKeyHandler->addKeyHandler(ArKeyHandler::RIGHT, &girarDerechaCB); myKeyHandler->addKeyHandler(ArKeyHandler::LEFT, &girarIzquierdaCB); } // Destructor Seguir::~Seguir(void) {
//Cerramos la conexión con ACTS if(myActs->isConnected()) { myActs->requestQuit(); myActs->closePort(); printf("Se desconecto\n"); }
43
}
// Método llamado al oprimir la tecla "a", para activar la rutina // de seguimiento void Seguir::activar(void) { printf("activar\n"); seguirActivado = true; }
// Método llamado al oprimir la tecla "d", para desactivar la rutina // de seguimiento void Seguir::desactivar(void) { printf("desactivar\n"); seguirActivado = false; }
// Método llamado al oprimir la tecla "UP". Aumenta el parámetro de // velocidad del robot
void Seguir::avanzar(void) { if(!seguirActivado) { printf("Hacia arriba\n"); adelante += deltaVelocidad; mover = true; } }
// Método llamado al oprimir la tecla "DOWN". Disminuye el parámetro de // velocidad del robot
void Seguir::frenar(void) { if(!seguirActivado) { printf("Frenando\n"); adelante -= deltaVelocidad; mover = true; } }
// Método llamado al oprimir la tecla "SPACE". Pone en ceros los parámetros de
// movimiento del robot void Seguir::parar(void) { if(!seguirActivado) { printf("Parar\n"); mover = false; adelante = 0; izquierda = 0; } }
44
// Método llamado al oprimir la tecla "RIGHT". Disminuye el parámetro de
// Angulo de dirección del robot void Seguir::girarDerecha(void) { if(!seguirActivado) { printf("Girar Derecha\n"); mover = true; izquierda -= 1 ; } }
// Método llamado al oprimir la tecla "LEFT". Aumenta el parámetro de // Angulo de dirección del robot
void Seguir::girarIzquierda(void) { if(!seguirActivado) { printf("Girar Izquierda\n"); mover = true; izquierda += 1 ; } }
// Acción de seguir que se ejecuta en la rutina del robot ArActionDesired *Seguir::fire(ArActionDesired currentDesired) { // Reset myDesired.reset(); if(!seguirActivado) { if(mover) { myDesired.setVel(adelante); myDesired.setDeltaHeading(izquierda*deltaAngulo); izquierda = 0; } else { myDesired.setVel(0); myDesired.setDeltaHeading(0); } return &myDesired; }
// Se anula el movimiento del robot por parte del usuario adelante = 0;
izquierda = 0;
ArACTSBlob blob;
ArACTSBlob largestBlob;
45
int numberOfBlobs; int blobArea = 10;
double xRel, yRel;
numberOfBlobs = myActs->getNumBlobs(myChannel);
// If there are blobs to be seen, set the time to now if(numberOfBlobs != 0)
{
for(int i = 0; i < numberOfBlobs; i++) { myActs->getBlob(myChannel, i + 1, &blob); if(blob.getArea() > blobArea) { flag = true; blobArea = blob.getArea(); largestBlob = blob; } } myLastSeen.setToNow(); }
// If we have not seen a blob in a while... if (myLastSeen.mSecSince() > myMaxTime) {
if(myState != NO_TARGET) ArLog::log(ArLog::Normal, "Target Lost");
myState = NO_TARGET; }
else {
// If we see a blob and haven't seen one before..
if(myState != TARGET) ArLog::log(ArLog::Normal, "Target Aquired");
myState = TARGET; }
if(TARGET && flag == true) {
// Determine where the largest blob's center of gravity // is relative to the center of the camera
xRel = (double)(largestBlob.getXCG() - WIDTH/2.0) / (double)WIDTH;
yRel = (double)(largestBlob.getYCG() - HEIGHT/2.0) / (double)HEIGHT;
// Tilt the camera toward the blob if(!(ArMath::fabs(yRel) < .20)) { if (-yRel > 0) myCamera->tiltRel(1); else myCamera->tiltRel(-1); }
46
// Set the heading and velocity for the robot if (ArMath::fabs(xRel) < .10) { myDesired.setDeltaHeading(0); } else { if (ArMath::fabs(-xRel * 10) <= 10) myDesired.setDeltaHeading(-xRel * 10); else if (-xRel > 0) myDesired.setDeltaHeading(10); else myDesired.setDeltaHeading(-10); } myDesired.setVel(300); return &myDesired; } else { myDesired.setVel(0); myDesired.setDeltaHeading(0); return &myDesired; } }
// Set the channel that the blob info will be obtained from bool Seguir::setChannel(int channel)
{
if (channel >= 1 && channel <= ArACTS_1_2::NUM_CHANNELS) { myChannel = channel; return true; } else return false; }
int main(int argc, char **argv) {
// Inicializamos ARIA Aria::init();
//ArLog::init(ArLog::StdErr, ArLog::Verbose); ArRobot robot;
printf("Antes de crear la camara"); // The camera (Cannon VC-C4)
ArVCC4 vcc4 (&robot);
// ACTS, for tracking blobs of color ArACTS_1_2 acts;
// our base server object ArServerBase server;
// Parser de verificación de parametros ArArgumentParser parser(&argc, argv);
47
ArSimpleConnector simpleConnector(&parser); ArServerSimpleOpener simpleOpener(&parser);
// set up a gyro, if installed ArAnalogGyro gyro(&robot);
// load the default arguments parser.loadDefaultArguments();
ArClientSwitchManager clientSwitchManager(&server, &parser);
if (!Aria::parseArgs() || !parser.checkHelpAndWarnUnparsed()) {
Aria::logOptions(); Aria::exit(1); }
// Se añade un key handler para el manejo de acciones por medio del teclado
ArKeyHandler keyHandler;
Aria::setKeyHandler(&keyHandler);
// Acciones limiter y limiter far para evitar que el robot choque ArActionLimiterForwards limiter("speed limiter near", 800, 1000, 600);
ArActionLimiterForwards limiterFar("speed limiter far", 800, 1200, 600);
ArActionLimiterBackwards backwardsLimiter; ArActionConstantVelocity stop("stop", 0);
ArActionConstantVelocity backup("backup", -200);
// Creacion de la clase que sigue al visitante Seguir seguir(&acts, &vcc4, &keyHandler);
// Set up where we'll look for files such as user/password char fileDir[1024];
ArUtil::addDirectories(fileDir, sizeof(fileDir), Aria::getDirectory(),
"ArNetworking/examples");
// first open the server up
if (!simpleOpener.open(&server, fileDir, 240)) {
if (simpleOpener.wasUserFileBad())
printf("Bad user/password/permissions file\n"); else
printf("Could not open server port\n"); exit(1);
}
// Range devices:
ArSonarDevice sonarDev;
48 ArIRs irs; robot.addRangeDevice(&irs); ArBumpers bumpers; robot.addRangeDevice(&bumpers); ArSick sick(361, 180); robot.addRangeDevice(&sick);
// Se añaden servicios al servidor
ArServerInfoRobot serverInfoRobot(&server, &robot); ArServerInfoSensor serverInfoSensor(&server, &robot); ArServerInfoDrawings drawings(&server);
drawings.addRobotsRangeDevices(&robot);
ArLaserReflectorDevice reflector(&sick, &robot); drawings.addRangeDevice(&reflector);
// Modos de control de movimiento del robot ArServerModeStop modeStop(&server, &robot); ArServerModeDrive modeDrive(&server, &robot);
ArServerModeRatioDrive modeRatioDrive(&server, &robot); ArServerModeWander modeWander(&server, &robot);
modeDrive.addAsDefaultMode(); modeDrive.activate();
// set up the simple commands
ArServerHandlerCommands commands(&server);
ArServerSimpleComUC uCCommands(&commands, &robot); // send commands directly to microcontroller
ArServerSimpleComMovementLogging loggingCommands(&commands, &robot);
// control debug logging
ArServerSimpleComGyro gyroCommands(&commands, &robot, &gyro); // configure gyro
ArServerSimpleComLogRobotConfig configCommands(&commands, &robot);
// control more debug logging
ArServerSimpleServerCommands serverCommands(&commands, &server); // control ArNetworking debug logging
modeDrive.addControlCommands(&commands); // configure the drive modes (e.g. enable/disable safe drive)
// Reenviar el video al cliente que lo requiera
ArHybridForwarderVideo videoForwarder(&server, "localhost", 7070);
// Control de cámara pan/tilt/zoom ArPTZ *camera = NULL;
ArServerHandlerCamera *handlerCamera = NULL; ArCameraCollection *cameraCollection = NULL;
49
if (videoForwarder.isForwardingVideo()) {
bool invertedCamera = false;
camera = new ArVCC4(&robot, invertedCamera, ArVCC4::COMM_UNKNOWN, true, true);
camera->init();
cameraCollection = new ArCameraCollection();
cameraCollection->addCamera("Cam1", "VCC4", "Camera", "VCC4");
handlerCamera = new ArServerHandlerCamera("Cam1", &server,
&robot, camera,
cameraCollection); }
// Conección con el robot
if (!simpleConnector.connectRobot(&robot)) {
printf("Could not connect to robot... exiting\n"); Aria::shutdown();
return 1; exit(1); }
// Abrir la conección con ACTS acts.openPort(&robot);
// Inicializa la cámara vcc4.init();
// Prevenir que el robot vaya muy rápido robot.setAbsoluteMaxTransVel(400);
// Habilitar la recepción de comandos robot.comInt(ArCommands::ENABLE, 1);
// Apagar los sonidos de amigobot robot.comInt(ArCommands::SOUNDTOG, 0);
// Se añadern las acciones con su respectivo nivel de importancia robot.addAction(&limiter, 100); robot.addAction(&limiterFar, 99); robot.addAction(&backwardsLimiter, 98); robot.addAction(&seguir, 77); robot.addAction(&backup, 50); robot.addAction(&stop, 30);
//Habilitar los motores robot.enableMotors();
// log whatever we wanted to before the runAsync simpleOpener.checkAndLog();
50
server.runAsync();
printf("Server is now running...\n");
// Se añade un key handler que maneje la salida oprimir escape //if ((keyHandler = Aria::getKeyHandler()) == NULL)
if (Aria::getKeyHandler() == NULL) {
keyHandler = new ArKeyHandler; Aria::setKeyHandler(&keyHandler); robot.lock();
robot.attachKeyHandler(&keyHandler); robot.unlock();
printf("To exit, press escape.\n"); }
robot.lock();
robot.attachKeyHandler(&keyHandler); robot.unlock();
printf("To exit, press escape.\n"); clientSwitchManager.runAsync();
//Corremos el robot asincronamente robot.runAsync(true);
//Esperamos escape para salir robot.waitForRunExit();