Programa de exemplo do Robô TON-BOT no modo seguidor de parede.

Dependencies:   IOTON-API QEI USBDevice mbed-ton ton-bot

Fork of ton-bot_seguidor_linha by IOTON Technology

controlador.cpp

Committer:
krebyy
Date:
2017-07-05
Revision:
4:f3c97c053b9f

File content as of revision 4:f3c97c053b9f:

/**
******************************************************************************
* @file    controlador.cpp
* @author  Kleber Lima da Silva (kleber@ioton.cc)
* @version V0.0.1
* @date    05-Julho-2017
* @brief   Biblioteca para controle de velocidade usando os encoders.
******************************************************************************
* @attention
*
* COPYRIGHT(c) 2017 IOTON Technology
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************
*/

#include "controlador.h"


/******************************************************************************/
/** @addtogroup Biblioteca do controlador de velocidade (perfil retangular)
* @{
*/

/* Variáveis Externas --------------------------------------------------------*/
int32_t distancia_mm = 0;
int32_t distancia_deg = 0;


/* Variáveis Privadas --------------------------------------------------------*/
int8_t tipo_movimento = 0;
int32_t setpoint_dist = 0;
int32_t setpoint_speed_esquerda_cnt = 0, setpoint_speed_direita_cnt = 0;
int32_t encoder_esquerda_delta = 0, encoder_direita_delta = 0;
int32_t encoder_esquerda_anterior_cnt = 0, encoder_direita_anterior_cnt = 0;
int32_t pid_esquerda_out = 0, pid_direita_out = 0;
int32_t erro_esquerda_anterior = 0, erro_direita_anterior = 0;
bool bUsarSensores = false;
float frontal_esquerdo = 0, lateral_esquerdo = 0, lateral_direito = 0, frontal_direito = 0;


/*******************************************************************************
*Função principal do controle de velocidade -----------------------------------
*/
void controleVelocidade(void)
{
  getSensoresParede(&frontal_esquerdo, &lateral_esquerdo, &lateral_direito, &frontal_direito);
  updateEncoders(); // Atualiza as distâncias e velocidades
  controladorPID(); // Controlador de velocidade
}


/* Função para selecionar os parâmetros do movimento ---------------------------
* raio [mm]: 0 para movimento translacional ou raio para a curva
* dist_ou_angulo [mm ou deg]: distância(translational ou angular) do movimento
* speed [mm/s]: velocidade do movimento
*/
void setMovimento(int32_t raio, int32_t dist_ou_angulo, int32_t speed)
{
  if (raio == 0)
  {
    tipo_movimento = TRANSLACIONAL;

    /* Usado para o controle de velocidade */
    setpoint_speed_esquerda_cnt = SPEED_TO_COUNTS(speed);
    setpoint_speed_direita_cnt = setpoint_speed_esquerda_cnt;
  }
  else
  {
    tipo_movimento = ROTACIONAL;

    /* Calcula as velocidade a partir do raio */
    float speedX_mm_s = (float)speed;
    float speedW_rad_s = speedX_mm_s / (float)raio;

    int32_t speedX_cnt = SPEED_TO_COUNTS(abs(speed));
    int32_t speedW_cnt = RAD_S_TO_COUNTS(speedW_rad_s);

    if (raio < RODA_RODA)
    {
      speedX_cnt -= (abs(speedW_cnt) / 2);
      speedW_cnt /= 2;
    }

    /* Usado para o controle de velocidade */
    setpoint_speed_esquerda_cnt = speedX_cnt - speedW_cnt;
    setpoint_speed_direita_cnt = speedX_cnt + speedW_cnt;
  }

  /* Usado para indicar o fim do movimento */
  setpoint_dist = dist_ou_angulo;
}


/* Atualiza a leitura dos encoders ---------------------------------------------
*/
void updateEncoders(void)
{
  int32_t encoder_esquerda_cnt, encoder_direita_cnt;

  /* Atualiza a contagem dos encoders */
  encoder_esquerda_cnt = getEncoderEsquerda();
  encoder_direita_cnt = getEncoderDireita();

  /* Atualiza a alteração dos encoders (speed) */
  encoder_esquerda_delta = encoder_esquerda_cnt - encoder_esquerda_anterior_cnt;
  encoder_direita_delta = encoder_direita_cnt - encoder_direita_anterior_cnt;

  /* Guarda os valores anteriores */
  encoder_esquerda_anterior_cnt = encoder_esquerda_cnt;
  encoder_direita_anterior_cnt = encoder_direita_cnt;

  /* Calcula a distância (mm) e o ângulo (deg) */
  distancia_mm = COUNTS_TO_MM((encoder_direita_cnt + encoder_esquerda_cnt) / 2);
  distancia_deg = COUNTS_TO_DEG((encoder_direita_cnt - encoder_esquerda_cnt) / 2);
}


/* Controlador PID de velocidade dos motores -----------------------------------
*/
void controladorPID(void)
{
  int32_t erro_esquerda = 0, erro_direita = 0;

  /* Alinhamento através dos sensores */
  if (bUsarSensores == true)
  {
    int32_t sensor_feedback = (int32_t)getErroSensores() / K_SENSORES;

    erro_esquerda += sensor_feedback;
    erro_direita -= sensor_feedback;
  }

  /* Erro de velocidade */
  erro_esquerda += (setpoint_speed_esquerda_cnt - encoder_esquerda_delta);
  erro_direita += (setpoint_speed_direita_cnt - encoder_direita_delta);

  /* PD - motor da esquerda */
  pid_esquerda_out += (KP * erro_esquerda) +
  (KD * (erro_esquerda - erro_esquerda_anterior));

  /* PD - motor da direita */
  pid_direita_out += (KP * erro_direita) +
  (KD * (erro_direita - erro_direita_anterior));

  /* Guarda os valores anteriores */
  erro_esquerda_anterior = erro_esquerda;
  erro_direita_anterior = erro_direita;

  setMotores(pid_esquerda_out / 1000.0f, pid_direita_out / 1000.0f);
}


/* Indica o fim do movimento ---------------------------------------------------
*/
bool isFinalMovimento(void)
{
  if (tipo_movimento == TRANSLACIONAL && distancia_mm >= setpoint_dist)
  {
    return true;
  }
  else if (tipo_movimento == ROTACIONAL && abs(distancia_deg) >= setpoint_dist)
  {
    return true;
  }
  else if ((tipo_movimento == TRANSLACIONAL) && (frontal_esquerdo > CENTRO_FRONTAL && frontal_direito > CENTRO_FRONTAL))
  {
    return true;
  }

  return false;
}


/* Reseta os encoders e as variáveis do controlador ----------------------------
*/
void resetControlador(void)
{
  resetEncoderEsquerda();
  resetEncoderDireita();

  encoder_esquerda_anterior_cnt = 0;
  encoder_direita_anterior_cnt = 0;

  distancia_mm = 0;
  distancia_deg = 0;

  pid_esquerda_out = 0; pid_direita_out = 0;
  erro_esquerda_anterior = 0; erro_direita_anterior = 0;
  setpoint_speed_esquerda_cnt = 0; setpoint_speed_direita_cnt = 0;
}


/* Movimenta o micromouse para frente uma distância em [mm] --------------------
* Se mm == 0: anda para frente até o próximo comando
*/
void frente(int32_t mm)
{
  if (mm != 0)
  {
    bUsarSensores = true;
    resetControlador();
    setMovimento(0, mm, SPEED_RETA);

    do
    {
      wait_ms(1);
    }
    while (isFinalMovimento() == false);
  }
  else
  {
    bUsarSensores = true;
    setMovimento(0, mm, SPEED_RETA);
    wait_ms(1);
  }
}


/* Realiza uma curva em torno do próprio eixo (graus < 0: para direita) --------
*/
void curvaPivot(int16_t graus)
{
  bUsarSensores = false;
  resetControlador();
  setMotores(0, 0);
  wait_ms(100);

  /* Seleciona o movimento de acordo com o sentido da curva */
  if (graus > 0) setMovimento(RODA_RODA / 2, graus, SPEED_CURVA);
  else setMovimento(RODA_RODA / 2, -graus, -SPEED_CURVA);

  do
  {
    wait_ms(1);
  }
  while (isFinalMovimento() == false);
}


/* Realiza uma curva em torno do próprio eixo e anda até a fronteira da célula
*       (graus < 0: para direita)
*/
void curva(int16_t graus)
{
  frente(CELULA / 2);
  curvaPivot(graus);
  frente(CELULA / 2);
}

/* Retorna o erro de alinhamento dos sensores ----------------------------------
*/
int16_t getErroSensores(void)
{
  float erro = 0;

  /* ------ ALINHAMENTO LATERAL ------ */
  if (frontal_esquerdo < FRONTAL_TH && frontal_direito < FRONTAL_TH)
  {
#if PID_TECNICA == 1
    if (lateral_esquerdo > CENTRO_LATERAL && lateral_direito < CENTRO_LATERAL)
    {
      erro = lateral_esquerdo - CENTRO_LATERAL;
    }
    else if (lateral_direito > CENTRO_LATERAL && lateral_esquerdo < CENTRO_LATERAL)
    {
      erro = CENTRO_LATERAL - lateral_direito;
    }
#elif PID_TECNICA == 2
    if (lateral_esquerdo > LATERAL_TH && lateral_direito > LATERAL_TH)
    {
      erro = lateral_esquerdo - lateral_direito;
    }
    else if (lateral_esquerdo > LATERAL_TH)
    {
      erro = 2 * (lateral_esquerdo - CENTRO_LATERAL);
    }
    else if (lateral_direito > LATERAL_TH)
    {
      erro = 2 * (CENTRO_LATERAL - lateral_direito);
    }
#endif
  }
  /* ------ ALINHAMENTO FRONTAL ------ */
  else if (frontal_esquerdo > ALINHAMENTO_FRONTAL && frontal_direito > ALINHAMENTO_FRONTAL)
  {
    erro = (frontal_direito - frontal_esquerdo);
  }

  return ((int16_t)(erro * 4095));//return erro;
}

/**
* @}
*/


/************************ (C) COPYRIGHT IOTON Technology **********************/
/***********************************END OF FILE********************************/