control.cpp

       1  #include <control.h>
          extern "C" {
          #include "extApi.h"
          }
          
          
          
          
       9  int Control::control(  int clientID ) {
           //LLAMADA DESDE EJECUTAR (  CONTROL PRINCIPAL )
          
           return 0;
          }
          
      15  int Control::interrupt_1(  int clientID ){
           //LLAMADA DESDE BOTON DE INTERRUPCION 1
          
           return 0;
          }
          
      21  int Control::interrupt_2(  int clientID ){
           //LLAMADA DESDE BOTON DE INTERRUPCION 2
          
           return 0;
          }
          
      27  int Control::interrupt_3(  int clientID ){
           //LLAMADA DESDE BOTON DE INTERRUPCION 3
          
           return 0;
          }
          
      33  int Control::interrupt_4(  int clientID ){
           //LLAMADA DESDE BOTON DE INTERRUPCION 4
          
           return 0;
          }
          
          
          

control.h

       1  //Definición de Clase Plantilla de Código de Control (  puede ser cualquiera con tal de que implemente I_control )
          #ifndef CONTROL_H
          #define CONTROL_H
          #include <i_control.h>
          
          //La clase implementa la "interfaz" (  clase abstracta ) i_control
       7  class Control: public I_Control
          {
           public:
      10   int control(  int clientID );
      11   int interrupt_1(  int clientID );
      12   int interrupt_2(  int clientID );
      13   int interrupt_3(  int clientID );
      14   int interrupt_4(  int clientID );
          };
          
          #endif // CONTROL_H

demo.cpp

       1  //Clase Ejemplo de Código Usuario. Ver Documentación de Remote Api para entender funciones.
          #include <demo.h>
          #include <sstream>
          #include <math.h>
          extern "C" {
          #include "extApi.h"
          }
          
          using namespace std;
          
      11  int Demo::control(  int clientID ) {
           cout << "Demo: Inicio de Control\n";
           int leftMotorHandle;
           int rightMotorHandle;
           int leftMotorHandle0;
           int rightMotorHandle0;
          
           //genera un handle para los motores de khepera y khepera#0 y de los objetos robot en sí.
           simxGetObjectHandle(  clientID,  "K3_rightWheelMotor#",  &rightMotorHandle,  simx_opmode_oneshot_wait );
           simxGetObjectHandle(  clientID,  "K3_leftWheelMotor#",  &leftMotorHandle,  simx_opmode_oneshot_wait );
           simxGetObjectHandle(  clientID,  "K3_rightWheelMotor#0",  &rightMotorHandle0,  simx_opmode_oneshot_wait );
           simxGetObjectHandle(  clientID,  "K3_leftWheelMotor#0",  &leftMotorHandle0,  simx_opmode_oneshot_wait );
          
          
          
           while (  simxGetConnectionId(  clientID )!=-1 )
           {
           //mover khepera
           simxSetJointTargetVelocity(  clientID,  leftMotorHandle,  2*pi,  simx_opmode_oneshot );
           simxSetJointTargetVelocity(  clientID,  rightMotorHandle,  2*pi,  simx_opmode_oneshot );
          
           //mover khepera#0
           simxSetJointTargetVelocity(  clientID,  leftMotorHandle0,  pi,  simx_opmode_oneshot );
           simxSetJointTargetVelocity(  clientID,  rightMotorHandle0,  pi,  simx_opmode_oneshot );
          
           }
           cout << "Demo: Control abortado\n";
           return 0;
          
          }
          //adelante
      42  int Demo::interrupt_1(  int clientID ){
           int leftMotorHandle;
           int rightMotorHandle;
           float velocidad = this->velocidad;
          
           cout << "Demo: Adelante v: " << velocidad << "\n";
          
           simxGetObjectHandle(  clientID,  rightmotor.c_str(   ),  &rightMotorHandle,  simx_opmode_oneshot_wait );
           simxGetObjectHandle(  clientID,  leftmotor.c_str(   ),  &leftMotorHandle,  simx_opmode_oneshot_wait );
          
          
           while (  simxGetConnectionId(  clientID )!=-1 ) {
           simxSetJointTargetVelocity(  clientID,  leftMotorHandle,  velocidad,  simx_opmode_oneshot );
           simxSetJointTargetVelocity(  clientID,  rightMotorHandle,  velocidad,  simx_opmode_oneshot );
           }
           return 0;
          }
          //marcha atrás
      60  int Demo::interrupt_2(  int clientID ){
           int leftMotorHandle;
           int rightMotorHandle;
           float velocidad = this->velocidad;
          
           cout << "Demo: Marcha atrás v: " << velocidad << "\n";
          
           simxGetObjectHandle(  clientID,  rightmotor.c_str(   ),  &rightMotorHandle,  simx_opmode_oneshot_wait );
           simxGetObjectHandle(  clientID,  leftmotor.c_str(   ),  &leftMotorHandle,  simx_opmode_oneshot_wait );
          
          
           while (  simxGetConnectionId(  clientID )!=-1 ) {
           simxSetJointTargetVelocity(  clientID,  leftMotorHandle,  -velocidad,  simx_opmode_oneshot );
           simxSetJointTargetVelocity(  clientID,  rightMotorHandle,  -velocidad,  simx_opmode_oneshot );
           }
           return 0;
          }
          //giro izquierda
      78  int Demo::interrupt_3(  int clientID ){
           int leftMotorHandle;
           int rightMotorHandle;
           float angulos[3]={0,  0,  0};
           float alfa =0;
           float anterior=0;
           float angulo=0;
           float velocidad = this->velocidad;
          
          
          
           simxGetObjectHandle(  clientID,  rightmotor.c_str(   ),  &rightMotorHandle,  simx_opmode_oneshot_wait );
           simxGetObjectHandle(  clientID,  leftmotor.c_str(   ),  &leftMotorHandle,  simx_opmode_oneshot_wait );
          
          
           //para girar 90º,   obtiene la orientación (  angulos de euler con respecto a los ejes absolutos ).
           simxGetObjectOrientation(  clientID,  leftMotorHandle,  -1,  angulos,  simx_opmode_oneshot_wait );
           //alfa es el angulo beta inicial.
           alfa=angulos[1];
           //anterior es necesario para calcular el incremento de angulo (  debido al sistema angular de vrep: 0->90->0->-90->0 )
           anterior=alfa;
           //angulo es el angulo actual en coordenadas radiales.
           angulo=alfa;
           while (  simxGetConnectionId(  clientID )!=-1 ) {
           //calculo angulo nuevo con la diferencia del dado por vrep y el anterior dado por vrep (  incremento ).
           simxGetObjectOrientation(  clientID,  leftMotorHandle,  -1,  angulos,  simx_opmode_oneshot );
           angulo= angulo+fabs(  angulos[1]-anterior );
           //si el angulo actual está mas allá de 90º del inicial,   giro completo. Si no,   sigue girando.
           if (   angulo<alfa+pi/2  ) {
           simxSetJointTargetVelocity(  clientID,  leftMotorHandle,  0,  simx_opmode_oneshot );
           simxSetJointTargetVelocity(  clientID,  rightMotorHandle,  velocidad,  simx_opmode_oneshot );
          
           } else {
           simxSetJointTargetVelocity(  clientID,  leftMotorHandle,  velocidad,  simx_opmode_oneshot );
           simxSetJointTargetVelocity(  clientID,  rightMotorHandle,  velocidad,  simx_opmode_oneshot );
           }
           anterior=angulos[1];
           }
           return 0;
          }
          //giro derecha (  ídem giro izquierda ).
     119  int Demo::interrupt_4(  int clientID ){
           int leftMotorHandle;
           int rightMotorHandle;
           float angulos[3]={0,  0,  0};
           float alfa =0;
           float anterior=0;
           float angulo=0;
           float velocidad = this->velocidad;
          
           cout << "Demo: Giro Der. v: " << velocidad << "\n";
          
           simxGetObjectHandle(  clientID,  rightmotor.c_str(   ),  &rightMotorHandle,  simx_opmode_oneshot_wait );
           simxGetObjectHandle(  clientID,  leftmotor.c_str(   ),  &leftMotorHandle,  simx_opmode_oneshot_wait );
          
           //para girar a la
           simxGetObjectOrientation(  clientID,  rightMotorHandle,  -1,  angulos,  simx_opmode_oneshot_wait );
           alfa=angulos[1];
           anterior=alfa;
           angulo=alfa;
           while (  simxGetConnectionId(  clientID )!=-1 ) {
           simxGetObjectOrientation(  clientID,  leftMotorHandle,  -1,  angulos,  simx_opmode_oneshot );
           angulo= angulo-fabs(  angulos[1]-anterior );
           if (  angulo>alfa-pi/2 ) {
           simxSetJointTargetVelocity(  clientID,  leftMotorHandle,  velocidad,  simx_opmode_oneshot );
           simxSetJointTargetVelocity(  clientID,  rightMotorHandle,  0,  simx_opmode_oneshot );
          
           } else {
           simxSetJointTargetVelocity(  clientID,  leftMotorHandle,  velocidad,  simx_opmode_oneshot );
           simxSetJointTargetVelocity(  clientID,  rightMotorHandle,  velocidad,  simx_opmode_oneshot );
           }
           anterior=angulos[1];
           }
           return 0;
          }
          //adjunta el índice del robot al label de vrep,   para identificar que robot "interrumpir".
          //permitir robots con nombre personalizado es posible,   pero resulta mas trabajoso de lo que reporta al usuario,   por tanto no se incluye en la demo.
     155  void Demo::setRobot(  int indice_robot ) {
          
           if (  indice_robot>0 ) {
           std::ostringstream sstr;
           sstr << "K3_leftWheelMotor#" << indice_robot -1;
           leftmotor = sstr.str(   );
           sstr.str(  "" );
           sstr.clear(   );
           sstr << "K3_rightWheelMotor#" << indice_robot -1;
           rightmotor = sstr.str(   );
           } else {
           leftmotor = "K3_leftWheelMotor#";
           rightmotor = "K3_rightWheelMotor#";
           }
          
          }
          //establece la velocidad (  multiplo de pi ) con el argumento dado.
     172  void Demo::setVelocidad(  int multiplicador ) {
           velocidad=multiplicador*pi;
          }
          
          
          
          
          
          

demo.h

       1  //Definicion Clase Ejemplo de Código Usuario.
          #ifndef DEMO_H
          #define DEMO_H
          #include <i_control.h>
          
          //La clase implementa la "interfaz" (  clase abstracta ) i_control
       7  class Demo: public I_Control
          {
           public:
      10   int control(  int clientID );
      11   int interrupt_1(  int clientID );
      12   int interrupt_2(  int clientID );
      13   int interrupt_3(  int clientID );
      14   int interrupt_4(  int clientID );
           //establece el nombre del robot a controlar con las interrupciones demo.
      16   void setRobot (  int indice_robot );
           //establece la velocidad de los motores en las interrupciones demo.
      18   void setVelocidad (  int multiplicador );
           private:
      20   std::string leftmotor = "K3_leftWheelMotor#";
      21   std::string rightmotor = "K3_rightWheelMotor#";
           const float pi=3.141592;
           float velocidad = pi;
          };
          
          #endif // DEMO_H

i_control.h

       1  //"Interfaz" (  clase abstracta ) que debe implementar la clase de código cliente
          //Ver clase ejemplo en Demo.
          #ifndef I_CONTROL_H
          #define I_CONTROL_H
          
          
          
          
       9  class I_Control
          {
           public:
      12   virtual int control(  int clientID ) = 0; //Método virtual puro,   debe sobrecargarse con el contenido de Control.
      13   virtual int interrupt_1(  int clientID ) = 0; //Métodos virtuales puros,   debe sobrecargarse con el contenido de interrupciones.
      14   virtual int interrupt_2(  int clientID ) = 0; //(  normalmente adelante,  atras,  izq y der,   respectivamente ).
      15   virtual int interrupt_3(  int clientID ) = 0;
      16   virtual int interrupt_4(  int clientID ) = 0;
          };
          
          #endif

kheperasimgui.cpp

       1  #include "kheperasimgui.h"
          #include "ui_kheperasimgui.h"
          #include <thread>
          #include <QMessageBox>
          #include <QTimer>
          #include <QInputDialog>
          #include <iostream>
          #include <i_control.h>
          #include "control.cpp"
          #include "demo.cpp"
          #include <QTextStream>
          #include <QScrollBar>
          #include <QUrl>
          #include <QDesktopServices>
          extern "C" {
          #include "extApi.h"
          }
          
          using namespace std;
          //Constructor del objeto GUI
      21  KheperaSimGUI::KheperaSimGUI(  QWidget *parent ) :
           QMainWindow(  parent ),  
           ui(  new Ui::KheperaSimGUI )
          {
           ui->setupUi(  this );
           log = freopen (  "log",  "w",  stdout );
          
           //Define un temporizador que ejecutar refrescar_datos(   ) cada 150ms
           QTimer *timer = new QTimer(  this );
           connect(  timer,   SIGNAL(  timeout(   ) ),   this,   SLOT(  refrescar_datos(   ) ) );
           //inicia el temporizador
           timer->start(  150 );
          
          }
          //Destructor del objeto GUI
      36  KheperaSimGUI::~KheperaSimGUI(   )
          {
           delete ui;
          }
          
          
          //Abre una conexión con V-REP (  puerto por defecto 19997 ),   Inicia la simulacion y cierra la conexión.
      43  void KheperaSimGUI::iniciar_sim(  string ip ){
           //Comprueba que no haya una conexión ya abierta antes de conectar.
           if (  simxGetConnectionId(  clientIDsim )==-1 ){
           clientIDsim=simxStart(  (  simxChar* ) ip.c_str(   ),  19997,  true,  true,  2000,  5 );
           }
          
           //Comprueba que se haya realizado la conexión con éxito. Si no,   muestra error.
           if (  clientIDsim!=-1 )
           {
           simxStartSimulation(  clientIDsim,  simx_opmode_oneshot_wait );
           simxFinish(  clientIDsim );
           ui->pausar->setEnabled(  true );
           cout << "Gui: Simulación iniciada\n";
          
           } else {
           cout << "Error: Imposible iniciar simulación remotamente. (  Pulsar Play en V-REP y volver a intentar )\n";
           QMessageBox error;
           error.setText(  "Error: Imposible iniciar simulación remotamente. (  Pulsar Play en V-REP y volver a intentar )" );
           error.exec(   );
           }
          }
          //Abre una conexión con la escena V-REP,   en la IP y puerto dado.
      65  int KheperaSimGUI::conectar(  string ip,  int puerto ){
          
           clientIDexe=simxStart(  (  simxChar* ) ip.c_str(   ),  puerto,  true,  true,  2000,  5 );
           //Comprueba la conexión,   si ha fallado,   muestra error.
           if (  simxGetConnectionId(  clientIDexe )==-1 ) {
           cout << "Error: Imposible conectar con el servidor. Asegúrese de que el puerto es correcto (  " << ui->puertotexto->text(   ).toInt(   ) <<" )\n";
           cout << "Debe ejecutar un proceso servidor en el Host Simulador,   normalmente con una llamada a\n";
           cout << "simExtRemoteApiStart(  puerto ) en un Child Script de Lua.\n";
           cout << "Ver código de control demo y escena demo2khepera.ttt\n";
           QMessageBox error;
           error.setText(  "Error: Imposible conectar con el servidor" );
           error.exec(   );
           }
           return clientIDexe;
          }
          
          //crea y lanza un thread (  hilo ) con el metodo pedido,   para permitir funcionamiento concurrente.
          
      83  void KheperaSimGUI::codigo_en_hilo(  ptrfunc ptrfuncion )
          {
           if (  ui->demoset->isChecked(   ) ){
           std::thread hilo(  ptrfuncion,  &demo,  clientIDexe );
           //el hilo continua ejecutándose hasta que retorna la función hilo (  el hilo padre se "desprende" del hijo )
           hilo.detach(   );
           } else {
           std::thread hilo(  ptrfuncion,  &control,  clientIDexe );
           hilo.detach(   );
           }
          }
          
          //refresca los datos de posición y velocidad de la gui. La invoca el timer creado en el constructor de la GUI.
      96  void KheperaSimGUI::refrescar_datos(   )
          { //Comprueba que haya una conexión. Si la hay,   obtiene los datos. (  Ver Doc. Remote API para entender funciones )
           if (  simxGetConnectionId(  clientIDexe )!=-1 ) {
           int robotHandle;
           //indica de que robot se representarán los datos,   segun el combobox de selección.
           string robot = ui->comboBox_2->currentText(   ).toUtf8(   ).constData(   );
           simxGetObjectHandle(  clientIDexe,  robot.c_str(   ),  &robotHandle,  simx_opmode_oneshot_wait );
           simxGetObjectPosition(  clientIDexe,  robotHandle,  -1,  position,  simx_opmode_oneshot );
           simxGetObjectVelocity(  clientIDexe,  robotHandle,  velocidad,  NULL,  simx_opmode_oneshot );
           } else {
           //Si no hay conexión,   pone a 0 los valores.
           for (  int i = 0; i<3; i++ ){
           position[i]=0;
           velocidad[i]=0;
           }
           }
           //actualiza los "LCD" de la GUI
           ui->xlcd->display(  position[0] );
           ui->ylcd->display(  position[1] );
           ui->zlcd->display(  position[2] );
           ui->vxlcd->display(  velocidad[0] );
           ui->vylcd->display(  velocidad[1] );
           ui->vzlcd->display(  velocidad[2] );
           //Muestra el contenido del archivo log en el textEdit. Solo si "mostrar output" está selecc.
           if (  ui->actionMostrar_Output->isChecked(   ) ) {
           fclose(  log );
           log = fopen(  "log",  "r" );
           QTextStream stream(  log );
           QString str = stream.readAll(   );
           ui->textEdit->setText(  str );
           QScrollBar *sb = ui->textEdit->verticalScrollBar(   );
           sb->setValue(  sb->maximum(   ) );
           fclose(  log );
           //redirecciona stdout al archivo log. ver página man de freopen.
           log = freopen (  "log",  "a",  stdout );
           }
          
          
          }
          
          //código de evento: pulsar botón ejecutar.
     137  void KheperaSimGUI::on_ejecutar_clicked(   )
          { //define la IP y puerto desde los textbox.
           ip = ui->iptexto->text(   ).toUtf8(   ).constData(   );
           puerto = ui->puertotexto->text(   ).toInt(   );
           //si está marcada la opción de Inicio remoto,   inicia la sim. remotamente.
           if(  ui->inicioremotoset->isChecked(   ) ){
           iniciar_sim(  ip );
           }
           //cierra cualquier conexión de control/interrupcion que haya.
           simxFinish(  clientIDexe );
           //conecta y ejecuta el código de control (  Demo ó Control ) en un hilo independiente.
           if (  conectar(  ip,  puerto ) != -1 ) {
           ptrfunc ptrfuncion = &I_Control::control;
           codigo_en_hilo(  ptrfuncion );
           cout << "Gui: Control ejecutado\n";
           }
          
          
          }
          //código de evento: pulsar botón iniciar simulación.
     157  void KheperaSimGUI::on_sim_clicked(   )
          {
           ip = ui->iptexto->text(   ).toUtf8(   ).constData(   );
           puerto = ui->puertotexto->text(   ).toInt(   );
           iniciar_sim(  ip );
          
          }
          //código de evento: pulsar botón parar simulación.
     165  void KheperaSimGUI::on_parar_clicked(   )
          {
           //abre una conexión en el puerto por defecto,   para la simulación y cierra la conexión.
           clientIDsim=simxStart(  (  simxChar* ) ip.c_str(   ),  19997,  true,  true,  2000,  5 );
           simxStopSimulation(  clientIDsim,  simx_opmode_oneshot_wait );
           simxFinish(  clientIDsim );
           cout << "Gui: Simulación parada\n";
           ui->pausar->setText(  "Pausar Sim." );
           ui->pausar->setEnabled(  false );
          
          }
          //código de evento: pulsar boton pausar/reanudar sim.
     177  void KheperaSimGUI::on_pausar_clicked(   )
          { //obtiene el estado actual del botón: Pausar/Reanudar.
           string texto = ui->pausar->text(   ).toUtf8(   ).constData(   );
           //abre una conexión en el puerto por defecto.
           clientIDsim=simxStart(  (  simxChar* ) ip.c_str(   ),  19997,  true,  true,  2000,  5 );
           //si tiene que pausar,   pausa,   y se pone en estado reanudar. Ídem al contrario.
           if (  !texto.compare(  "Pausar Sim." ) ) {
           simxPauseSimulation(  clientIDsim,  simx_opmode_oneshot_wait );
           cout << "Gui: Simulación pausada\n";
           ui->pausar->setText(  "Reanud Sim." );
           } else {
           simxStartSimulation(  clientIDsim,  simx_opmode_oneshot_wait );
           cout << "Gui: Simulación reanudada\n";
           ui->pausar->setText(  "Pausar Sim." );
           }
           //cierra la conexión en puerto por defecto.
           simxFinish(  clientIDsim );
          
          
          }
          //código de evento: pulsar botón de interrupt X.
     198  void KheperaSimGUI::on_interrupt1_clicked(   )
          { //cierra cualquier conexión de control/interrupcion que exista,  conecta
           //y ejecuta el código de interrupción (  Demo ó Control ) en un hilo independiente.
           simxFinish(  clientIDexe );
           if (  conectar(  ip,  puerto ) != -1 ) {
           //crea un puntero a metodo miembro con el metodo seleccionado.
           ptrfunc ptrfuncion = &I_Control::interrupt_1;
           //ejecuta el metodo seleccionado en un hilo.
           codigo_en_hilo(  ptrfuncion );
           }
          }
          
     210  void KheperaSimGUI::on_interrupt2_clicked(   )
          {
           simxFinish(  clientIDexe );
           if (  conectar(  ip,  puerto ) != -1 ) {
           ptrfunc ptrfuncion = &I_Control::interrupt_2;
           codigo_en_hilo(  ptrfuncion );
           }
          
          }
          
     220  void KheperaSimGUI::on_interrupt3_clicked(   )
          {
           simxFinish(  clientIDexe );
           if (  conectar(  ip,  puerto ) != -1 ) {
           ptrfunc ptrfuncion = &I_Control::interrupt_3;
           codigo_en_hilo(  ptrfuncion );
           }
          }
     228  void KheperaSimGUI::on_interrupt4_clicked(   )
          {
           simxFinish(  clientIDexe );
           if (  conectar(  ip,  puerto ) != -1 ) {
           ptrfunc ptrfuncion = &I_Control::interrupt_4;
           codigo_en_hilo(  ptrfuncion );
           }
          }
          //código de evento: selección de nombre de robot para mostrar sus datos.
     237  void KheperaSimGUI::on_comboBox_2_activated(  QString robottexto )
          { //Si se selecciona Personalizado,   abre un dialogo para introducir un nuevo nombre.
          
           if (  !robottexto.compare(  "Personalizado..." ) ){
           QString nombrerobot = QInputDialog::getText(  this,  tr(  "Nombre Nuevo" ),  tr(  "Nombre robot:" ) );
           //Comprueba que no se canceló el dialogo,   añade la nueva opción a la lista y la selecciona.
           if (  nombrerobot!=NULL ) {
           ui->comboBox_2->insertItem(  0,  nombrerobot );
           ui->comboBox_2->setCurrentIndex(  0 );
           }
           } else if (  !robottexto.compare(  "Añadir" ) ){
           std::ostringstream sstr;
           sstr << "K3_robot#" << ui->comboBox_2->count(   ) -3;
           QString str = QString::fromStdString(  sstr.str(   ) );
           ui->comboBox_2->insertItem(  ui->comboBox_2->count(   )-2,  str );
           ui->comboBox_2->setCurrentIndex(  ui->comboBox_2->count(   )-3 );
           }
          }
          //cambia los nombres de los botones de interrupcion al modo Control.
     256  void KheperaSimGUI::on_controlset_clicked(   )
          {
           ui->interrupt1->setText(  "Interrupt 1" );
           ui->interrupt2->setText(  "Interrupt 2" );
           ui->interrupt3->setText(  "Interrupt 3" );
           ui->interrupt4->setText(  "Interrupt 4" );
           ui->comboBox_3->setEnabled(  false );
           ui->label_13->setEnabled(  false );
           ui->comboBox->setEnabled(  false );
          }
          //revierte los botones de interrupcion al modo demo.
     267  void KheperaSimGUI::on_demoset_clicked(   )
          {
           ui->interrupt1->setText(  "Adelante" );
           ui->interrupt2->setText(  "Atrás" );
           ui->interrupt3->setText(  "Izquierda" );
           ui->interrupt4->setText(  "Derecha" );
           ui->comboBox_3->setEnabled(  true );
           ui->label_13->setEnabled(  true );
           ui->comboBox->setEnabled(  true );
          }
          //permite cambiar el robot al que se envian las interrupciones. Solo modo demo.(  En modo control el usuario puede elegir con su código cualquier robot/acción )
     278  void KheperaSimGUI::on_comboBox_3_activated(  const QString a )
          { string texto = a.toUtf8(   ).constData(   );
           if (  !texto.compare(  "Añadir" ) ){
           std::ostringstream sstr;
           sstr << "K3_robot#" << ui->comboBox_3->count(   ) -2;
           QString str = QString::fromStdString(  sstr.str(   ) );
           ui->comboBox_3->insertItem(  ui->comboBox_3->count(   )-1,  str );
           ui->comboBox_3->setCurrentIndex(  ui->comboBox_3->count(   )-2 );
           }
           demo.setRobot(  ui->comboBox_3->currentIndex(   ) );
          }
          
          //permite cambiar la velocidad de los motores en las interrupciones. Solo modo Demo. Advierte que el robot se desestabiliza para altas velocidades.
     291  void KheperaSimGUI::on_comboBox_activated(  int index )
          { //comprueba velocidad > 2x y que no se ha especificado que no se muestre la advertencia.
           if (  index>1 && !nomostrarwarning ){
           QMessageBox warning;
           QCheckBox nomostrar;
           nomostrar.setText(  "No volver a mostrar" );
           warning.setText(  "Para V > 2x,   el control no asegura la estabilidad del robot" );
           warning.setCheckBox(  &nomostrar );
           warning.exec(   );
           if (  warning.checkBox(   )->isChecked(   ) ){
           nomostrarwarning = true;
           }
           }
           demo.setVelocidad(  index+1 );
          }
          //codigo de cierre por menú
     307  void KheperaSimGUI::on_actionSalir_triggered(   )
          {
           fclose(  log );
           exit(  0 );
          }
          //muestra el output (  hace la ventana mas grande ) o lo oculta (  ventana mas pequeña )
     313  void KheperaSimGUI::on_actionMostrar_Output_toggled(  bool arg1 )
          {
           if (  arg1 ) {
           setFixedSize(  450,  410 );
           } else {
           setFixedSize(  450,  275 );
           }
          }
          //código de cierre por pulsar X en ventana.
     322  void KheperaSimGUI::closeEvent(  QCloseEvent *bar ) {
          
           fclose(  log );
          
          }
          
     328  void KheperaSimGUI::on_actionAyuda_triggered(   )
          {
           QDesktopServices::openUrl(  QUrl(  "http://xpeiro.github.io/compu3/" ) );
          }

kheperasimgui.h

          //Definición de la clase de la Interfaz Gráfica.
          #ifndef KHEPERASIMGUI_H
          #define KHEPERASIMGUI_H
          #include <QMainWindow>
          #include <demo.h>
          #include <control.h>
          #include <i_control.h>
          #include <stdio.h>
          
          
          namespace Ui {
      12  class KheperaSimGUI;
          }
          
      15  class KheperaSimGUI : public QMainWindow
          {
           Q_OBJECT
          
          public:
          
      21   explicit KheperaSimGUI(  QWidget *parent = 0 );
      22   ~KheperaSimGUI(   );
      23   typedef int (  I_Control::* ptrfunc ) (  int );
          
      25  private slots:
           //inicia la simulación remotamente (  IP:parámetro. Puerto: 19997,   predeterminado de V-REP )
           void iniciar_sim(  std::string ip );
           //abre una conexión remota nueva en la ip y puerto dada
      29   int conectar(  std::string ip,  int puerto );
           //ejecuta la función hilo como un thread y lo desvincula del padre-> detach(   ).
      31   void codigo_en_hilo(  KheperaSimGUI::ptrfunc ptrfuncion );
           //muestra los datos de posicion y velocidad en la GUI.
      33   void refrescar_datos(   );
           //Slots/Métodos que se cargan en los eventos definidos por sus nombres.
      35   void on_ejecutar_clicked(   );
          
      37   void on_sim_clicked(   );
          
      39   void on_parar_clicked(   );
          
      41   void on_pausar_clicked(   );
          
      43   void on_interrupt1_clicked(   );
          
      45   void on_interrupt2_clicked(   );
          
      47   void on_interrupt3_clicked(   );
          
      49   void on_interrupt4_clicked(   );
          
      51   void on_controlset_clicked(   );
          
      53   void on_demoset_clicked(   );
          
      55   void on_comboBox_2_activated(  QString robottexto );
          
      57   void on_comboBox_3_activated(  const QString a );
          
      59   void on_comboBox_activated(  int index );
          
      61   void on_actionSalir_triggered(   );
          
      63   void on_actionMostrar_Output_toggled(  bool arg1 );
          
      65   void closeEvent(  QCloseEvent *bar );
          
      67   void on_actionAyuda_triggered(   );
          
          private:
          
           Ui::KheperaSimGUI *ui;
           //Handle/identificador usado para conexiones de señales de manejo de simulación (  Iniciar,   Parar,   Pausar/Reanudar )
           //Usa siempre el puerto 19997,   inicializado por defecto en V-REP
           int clientIDsim=-1;
           //Handle/identificador usado para conexiones de señales de control/interrupcion.
           //Usa el puerto definido por el usuario (  debe abrirse manualmente con un Script Lua. Ver modelo Khepera incluido ).
           int clientIDexe=-1;
           //IP del Host Simulador. Localhost por defecto.
           std::string ip="127.0.0.1";
           //Puerto de escucha. Debe configurarse en un Script Lua. Ver modelo Khepera incluido.
           int puerto=20001;
           // buffer de coordenadas de posición.
           float position[3];
           // buffer de módulos de velocidad (  lineal ).
           float velocidad[3];
           //toggle de la advertencia de velocidad excesiva.
           bool nomostrarwarning =false;
          
           FILE * log;
          
           Demo demo;
          
           Control control;
          
          
          
          };
          
          #endif // KHEPERASIMGUI_H

main.cpp

       1  #include "kheperasimgui.h"
          #include <QApplication>
          
       4  int main(  int argc,   char *argv[] )
          { //Instancia la GUI
           QApplication a(  argc,   argv );
           KheperaSimGUI w;
           //muestra la GUI
           w.show(   );
           //Fija el tamaño de la ventana.
           w.setFixedSize(  450,  275 );
          
           return a.exec(   );
          }