Código del MBot - marcos-allen/Reto_TE2003B_mBot_Mega GitHub Wiki

Código en C del Atmega 2560

Programación de FreeRTOS en la tarjeta MegaPi con dos tareas, una interrupción y sin código arduino.


/******************************************************************************
 RETO
*******************************************************************************/
#include <Arduino_FreeRTOS.h>
#include "queue.h"
#include "semphr.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "src/MeSingleLineFollower.h"
#include "src/MeCollisionSensor.h"
#include "src/MeBarrierSensor.h"
#include "src/MeNewRGBLed.h"
#include <MeMegaPi.h>
#include <math.h>

//declaraciones de la tasa de comunicación serial
#define F_CPU 16000000
#define USART_BAUDRATE 57600
#define UBRR_VALUE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

//variables constantes para calcular las velocidades de las llantas
#define distancia_ruedas_cm 13.5  //l (en cm) distancia de ruedas
#define Vn 20               //velocidad normal, derecho(cm/s)

int interrupcion = 0; //variable para el manejo de la interrupción
char RX_Byte;
unsigned char mybuffer[50];
double Vl, Vr; //velocidades en cada rueda izqueirda Vl, derecha Vr

///Codigo de los motores utilizados en los ejemplos///
MeBarrierSensor barrier_62(62);
MeMegaPiDCMotor motor_1(1); //1A
MeMegaPiDCMotor motor_9(9); //1B
MeMegaPiDCMotor motor_2(2); //2A
MeMegaPiDCMotor motor_10(10); //2B
double angle_rad = PI/180.0;
double angle_deg = 180.0/PI;

///funcion que calcula la velocidad de las ruedas en cm/s
void calcularVelocidades(double Kp, double angulo_en_grados, double* Vl, double* Vr) {

    //angulo a radianes
    double angulo_rad = angulo_en_grados * M_PI / 180.0; //M_PI = PI (constante)
    
    //velocidad angular
    double omega = Kp * angulo_rad;
    
    //velocidad para las ruedad
    *Vl = Vn + (omega * distancia_ruedas_cm / 2.0); //direcciones corregidas
    *Vr = Vn - (omega * distancia_ruedas_cm/ 2.0); //direcciones corregidas
    //*Vl = Vn - (omega * distancia_ruedas_cm / 2.0); //formula original
    //*Vr = Vn + (omega * distancia_ruedas_cm / 2.0); //formula original
}
//funcion que transforma la velodicad en cm/s a porcentaje de pwm
double transformarVelocidades(double velocidad_cm_s) {
    const double velocidad_maxima_cm_s = 22.2425;  //velocidad
    const double pwm_base = 60.0;                 //porcentaje de PWM que da esa velocidad

    //regla de 3 
    double pwm = (velocidad_cm_s * pwm_base) / velocidad_maxima_cm_s;

    // Limitar entre 0 y 100
    if (pwm > 100.0) pwm = 100.0;
    if (pwm < 0.0) pwm = 0.0;

    return pwm;
}
//funcion que transforma velocidad en pwm a un entero de entre 0 y 255
int transformarPWM(double velocidad_pwm) {
    const double velocidad_maxima_pwm = 100;  //velocidad
    const int numero_base = 255;                 //entero que da ese pwm

    //regla de 3 
    int entero = (velocidad_pwm * numero_base) / velocidad_maxima_pwm ;

    if (entero > 255) entero = 255;
    if (entero < 0) entero = 0;

    return entero;
}
///Codigo de los motores utilizados en los ejemplos///
void motor_foward_left_run(int16_t speed)
{
   motor_10.run(-speed);
}

void motor_foward_right_run(int16_t speed)
{
  motor_1.run(speed);
}

void motor_back_left_run(int16_t speed)
{
  motor_2.run(-speed);
}

void motor_back_right_run(int16_t speed)
{
  motor_9.run(speed);
}

void move_control(int16_t vx, int16_t vy, int16_t vw)
{
  int16_t foward_left_speed;
  int16_t foward_right_speed;
  int16_t back_left_speed;
  int16_t back_right_speed;

  foward_left_speed = vy + vx + vw;
  foward_right_speed = vy - vx - vw;
  back_left_speed = vy - vx + vw;
  back_right_speed = vy + vx - vw;

  motor_foward_left_run(foward_left_speed);
  motor_foward_right_run(foward_right_speed);
  motor_back_left_run(back_left_speed);
  motor_back_right_run(back_right_speed);
}

//handle para la queue que almacena los angulos
QueueHandle_t myQueue;

//semaphore handle para manejar la interrupción PK0
SemaphoreHandle_t interruptSemaphore;

TaskHandle_t vTaskHandleUART; //Handle de la tarea que controla motores

//UART and pin configuration
void setup()
{
  xTaskCreate(vHandlerTaskUART,"MOTOR HANDLER TASK",100, NULL, 1, &vTaskHandleUART);
  xTaskCreate(vHandlerTaskSTOP,"PCINT16 HANDLER TASK",100,NULL,1,NULL);
  xTaskCreate(vREADTask,"READ DATA",100,NULL,2,NULL);
 
  //creación del semáforo binario
  interruptSemaphore = xSemaphoreCreateBinary();
  
  //si el semáforo es creado, inicializa interrupción PCINT16
  if(interruptSemaphore != NULL)
  {
    //se hace PK0 (pin 62) entrada
    DDRK &= ~(1 << PK0);
    //Resistencia pull up en PK0
    PORTK &= ~(1 << PK0);
    //se habilita interrupción por cambio de estado en PORTK
    PCICR |= (1 << PCIE2);
    //se habilita interrupción PCINT16
    PCMSK2 |= (1 << PCINT16);
    sei();
  }
  //creación de la queue
  myQueue = xQueueCreate(3, sizeof(char));

  //revisa si la queue ha sido creada
  if(myQueue != NULL) 
  {    
    //configuración UART
    UBRR0H = (uint8_t)(UBRR_VALUE >> 8);
    UBRR0L = (uint8_t)UBRR_VALUE;
    //UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01); // 8-bit data
    UCSR0C = 0x06;       // Set frame format: 8data, 1stop bit 
    UCSR0B |= (1 << RXEN0) | (1 << TXEN0) | (0 << RXCIE0);   // TX and RX enables and RX interrupt enabled      
    UCSR0A = 0x00; // Limpia banderas

    sprintf(mybuffer, "1\n");//Envia un "1" para iniciar la raspberry
    USART_Transmit_String((unsigned char *)mybuffer);
  }
}

//Tarea que se encarga de leer los caracteres de la cola y controla los motores
void vHandlerTaskUART(void * pvParameters)
{
  
   char data1, data2, data3;
  BaseType_t qStatus1, qStatus2, qStatus3;
  int entero_L, entero_R;
  double kp;

  while(1)
  {
    //revisa el tamaño de la cola, si es 3, avanza
    unsigned int itemsInQueue = uxQueueMessagesWaiting(myQueue);
    if (itemsInQueue == 3)
    {
      qStatus1 = xQueueReceive(myQueue, &data1, portMAX_DELAY);
        
      if(qStatus1 == pdPASS)
      {
        sprintf(mybuffer, "Dato 1 leido %c \n", data1);
        USART_Transmit_String((unsigned char *)mybuffer);
      }
      qStatus2 = xQueueReceive(myQueue, &data2, portMAX_DELAY);
      if (qStatus2 == pdPASS)
      {
        sprintf(mybuffer, "Dato 2 leido %c \n", data2);
        USART_Transmit_String((unsigned char *)mybuffer);
      }
        qStatus3 = xQueueReceive(myQueue, &data3, portMAX_DELAY);
        if (qStatus3 == pdPASS)
        {
          sprintf(mybuffer, "Dato 3 leido %c \n", data3);
          USART_Transmit_String((unsigned char *)mybuffer);
          
          //Almaceno los caracteres en una variable y lo convierte a entero
          char value[4];
          sprintf(value, "%c%c%c", data1, data2, data3);
          int grad = atoi(value);
          sprintf(mybuffer, "Entrando a la funcion, grados: %d \n", grad);
          USART_Transmit_String((unsigned char *)mybuffer);

          //Obtitiene el valor absoluto del angulo y dependiendo de este, el valor de kp cambia
          int grados = abs(grad);
          if (grados  >= 60)
          {
            kp = 1.8;
          }else if((grados < 60) && (grados >= 40))
          {
            kp = 1.6;
          }else if ((grados < 40) && (grados >= 20))
          {
            kp = 1.4;
          }else
          {
            kp = 0.1;
            }
          //velocidades en cm/s llamando a la función
          calcularVelocidades(kp,grad, &Vl, &Vr);
          
          //convertir cm/s a porcentaje de pwm
          double pwm_L = transformarVelocidades(Vl);
          double pwm_R = transformarVelocidades(Vr);
           
          //convertir pwm  a entero entre 0 y 255
          entero_L = transformarPWM(pwm_L);
          entero_R = transformarPWM(pwm_R);
      
          //muestra la velocidad
          sprintf(mybuffer,"velocidad rueda izquierda (Vl): %d \n", entero_L);
          USART_Transmit_String((unsigned char *)mybuffer);
          sprintf(mybuffer,"velocidad rueda derecha (VR): %d \n", entero_R);
          USART_Transmit_String((unsigned char *)mybuffer);
          
          sprintf(mybuffer, "Modificando PWM\n");
          USART_Transmit_String((unsigned char *)mybuffer);
          
          if (grad == 0)  //Si el angulo = 0, los motores se mantienen constantes
          {
            motor_1.run(100);
            motor_9.run(100);
            motor_2.run(-100);
            motor_10.run(-100);
          }
          else //Si engulo!=0, los motores se modifican
          {
            motor_1.run(entero_R);
            motor_9.run(100);
            motor_2.run(-100);
            motor_10.run(-entero_L);
            }
          
           sprintf(mybuffer, "1\n");
          USART_Transmit_String((unsigned char *)mybuffer);
          }
      }
    vTaskDelay(1);
  }
}

//Handler Task, Tarea que detiene los motores al haber una interrupción en PK0
void vHandlerTaskSTOP(void *pvParameters)
{
  while(1)
  {
    //espera por siempre al semáforo
    if (xSemaphoreTakeFromISR(interruptSemaphore, pdTRUE) == pdPASS) 
    {
      if (interrupcion == 1)
      {
        sprintf(mybuffer, "-------------------0\n");
        USART_Transmit_String((unsigned char *)mybuffer);
        motor_1.run(0);
        motor_9.run(0);
        motor_2.run(0);
        motor_10.run(0);
        vTaskSuspend(vTaskHandleUART); //Suspende la tarea que controla los motores
      }else
      {
        sprintf(mybuffer, "1\n");
        USART_Transmit_String((unsigned char *)mybuffer);
        vTaskResume(vTaskHandleUART); //Reanuda la tarea que controla los motores
        }
    }
  //vTaskDelay(1);
  }
}

//Tarea que leee los datos del UART y los almacena en la cola
void vREADTask(void *pvParameters)
{  
    BaseType_t qStatus;
    while(1)
    {  
          //revisa si hay nuevo dato RX en UART
      if((UCSR0A & (1 << RXC0)) != 0)
      {
        //lee dato recibido
        RX_Byte = UDR0;
        sprintf(mybuffer, "Recibido: %c\n", RX_Byte);
        USART_Transmit_String((unsigned char *)mybuffer);
        
        //Envia dato a la cola
        qStatus = xQueueSendToBack(myQueue, &RX_Byte, portMAX_DELAY);
        if(qStatus == pdPASS)
        {
          sprintf(mybuffer, "Dato enviado a la queue: %c\n", RX_Byte);
          USART_Transmit_String((unsigned char *)mybuffer);
        }
        else
        {
          sprintf(mybuffer, "Dato no enviado a la queue\n");
          USART_Transmit_String((unsigned char *)mybuffer);
        }
      }
     vTaskDelay(1);
    }
}

//loop vacio
void loop()
{}

//PCINT2 ISR, da el semáforo desde ISR
ISR(PCINT2_vect)
{  
  sprintf(mybuffer, "ISR\n");
  USART_Transmit_String((unsigned char *)mybuffer);
  if (!(PINK & (1 << PK0))) 
  {
    interrupcion = 1;
    } else 
    {
    interrupcion = 0;
    }
    xSemaphoreGiveFromISR(interruptSemaphore, pdTRUE);
}

/////funciones de transmisión del UART///////
void USART_Transmit(unsigned char data)
{
    //wait for empty transmit buffer
    while(!(UCSR0A & (1 << UDRE0)));
  
    //put data into buffer, send data
    UDR0 = data;  
}

void USART_Transmit_String(unsigned char * pdata)
{
    unsigned char i;
    //calculate string length
    unsigned char len = strlen(pdata);

    //transmit byte for byte
    for(i=0; i < len; i++)
    {
        //wait for empty transmit buffer
        while(!(UCSR0A & (1 << UDRE0)));
        //put data into buffer, send data
        UDR0 = pdata[i];
    }
}
⚠️ **GitHub.com Fallback** ⚠️