User Tools

Site Tools


Writing /var/lib/dokuwiki/data/meta/teaching/ie0117/proyectos/2014/i/proyecto_1/base_omnidireccional.meta failed
teaching:ie0117:proyectos:2014:i:proyecto_1:base_omnidireccional

Base Omnidireccional

Integrantes

Ronald Caravaca Mora (A91329) Fabián Mora Cordero (B24398)

Descripción

En este proyecto de desarrollo se elaborará una base omnidireccional, basado en el proyecto de Andrey Jiménez Oses, que consistió en la elaboración de un carro omnidireccional, realizado en el segundo semestre del 2013 para el curso Programación en plataformas Abiertas(IE0117). Esta base se podrá mover en cualquier dirección, debido a las llantas omnidireccionales que posee. Se podrá controlar inalámbricamente con un Joystick via bluetooth.

Objetivo general

Crear una base omnidireccional controlada por bluetooth.

Objetivos específicos

Estudiar el estado actual. Terminar desarrollo de hardware y software para el control de los 4 motores. Concluir el desarrollo de software que corre en el raspberry pi, para coordinar las velocidades de los 4 motores. Permitir el control remoto usando bluetooth y joystick.

Justificación

Las bases omnidireccionales tienen una cantidad de usos muy grande, ya que se pueden usar en muchos ámbitos, algunos ejemplos son, en la industria militar, para saber si existe una bomba o no, en un lugar de difícil acceso, en el sector industrial, para transportar objetos de un lugar a otro, y para seguridad hogareña, ya que se pueden usar para vigilar el perímetro de una casa. Esto hace que el estudio de estos tipos de robots sea de gran interés para la industria.

La UCR al ser un ente académico le interesa este punto, pero no se detiene en él. Entonces la pregunta es que otros usos tiene, aparte de los usos comerciales, por ejemplo una red de estos robots, pueden ser utilizados para tener una idea visual de algún tipo de algoritmo, que de otra manera podría ser muy complicada de comprender, como reconocimiento de patrones, entonces tenemos que estas bases proveen también una herramienta de estudio para muchas investigaciones.

Metodología

Se estudiará el estado actual de la base omnidireccional con la ayuda de Andrey Jiménez, quien comenzó el proyecto el semestre anterior. Se analizará el estado actual, del control de los 4 motores y los problemas que tuvo Andrey Jimenez para obtener el funcionamiento deseado. Sé estudiaŕa el desarrollo actual del software en raspberry pi, y se modificará si es necesario, para la coordinación de las velocidades en los motores. Se analizará el funcionamiento del bluetooth de un joystick, en una computadora, para luego agregarle el soporte al raspberry pi.

STM32F4DISCOVERY

El STM32 es una familia de circuitos integrados basados en microcontroladores de 32 bits con núcleos RISC ARM Cortex-M4F, Cortex-M3 y Cortex-M0 de STMicroelectronics y el procesador ARM IP de ARM Holdings. Los diseños de núcleo ARM tienen numerosas opciones configurables, y ST elige la configuración individual de uso para cada diseño. ST concede sus propios periféricos al núcleo antes de convertir el diseño en una pastilla de silicio.

El STM32 serie F4 es el primer grupo de microcontroladores STM32 basado en el núcleo ARM Cortex-M4F. El F4 es también la primera serie STM32 en tener DSP y las instrucciones de coma flotante. La F4 es pin a pin compatible con el F2 de la serie STM32 y añade una mayor velocidad de reloj, 64K CCM RAM estática, full duplex I ² S, mejorado en tiempo real, y ADCs más rápido.

Instalacion

Necesitamos añadir la arquitectura i386

dpkg --add-architecture i386

haga un apt-get update

Descargue el último tarball de instalación de Herramientas de GNU para procesadores embebidos ARM y descomprimir:

cd ~/local/src
wget https://launchpad.net/gcc-arm-embedded/4.7/4.7-2013-q1-update/+download/gcc-arm-none-eabi-4_7-2013q1-20130313-linux.tar.bz2
tar -xjf gcc-arm-none-eabi-4_7-2013q1-20130313-linux.tar.bz2

Hacer que los ejecutables de herramientas a disposición de los usuarios, agregue el directorio bin a la PATH variable:

echo 'export PATH=$PATH:/home/****user****/local/src/gcc-arm-none-eabi-4_7-2013q1/bin/' >> /home/****user****/.bashrc

Recordemos que para recargar el archivo .bashrc tenemos 2 opciones:

  • Cierre seción y logueese de nuevo
  • Recargue el directorio del archivo .bashrc
. .bashrc

Openocd

Instale openocd

sudo apt-get install openocd

Libopencm3

Primero debemos tener instalado python-yaml , si no esta instalado hacemos

sudo apt-get install python-yaml

Luego creamos la librería

cd ~/local/src/
git clone https://github.com/libopencm3/libopencm3-examples
cd libopencm3-examples
git submodule init
git submodule update
cd libopencm3
make

Hardware

Se utilizan 4 reudas macanum que por su configuración permiten el dereccionamienta omnidireccional. Se utilizan puentes H para el control de los motores DC, en este caso son dos puentes H, uno para cada par de motores. El STM32F4 se utiliza para la generación de la señal PWM que va los motores para el control de la velocidad.

Señal PWM

La señal PWM (Modulación por ancho de pulso) se usa para el control de la velocidad de los motores DC. Esto consiste en generar una señal de pulsos con diferentes anchos, al variar el ancho del pulso se varia la tensio eléctrica promedio que llega a los motores DC y con esto la valocidad de giro de los motores.

Código para el control de las velocidad de los motores

En general el código se puede ver como se siguiente diagrama de bloques:

Se reciben los datos de las valocidades para cada motor por medio de un puerto serie por usb, se guardan los valores en variables tipo float que la fucion gen_pwm toma y activa los timers que controlan los puentes H. El TIM1 y el TIM8 son timers del STM32 que se pueden usar para generar señales PWM.

Acontinuación el condigo fuente:

#include <libopencm3/stm32/f4/rcc.h>
#include <libopencm3/stm32/f4/gpio.h>
#include <libopencm3/stm32/f4/timer.h>
#include <libopencm3/stm32/f4/nvic.h>
#include <libopencm3-plus/newlib/syscall.h>
#include "carro.h"
#include <libopencm3-plus/cdcacm_one_serial/cdcacm.h>
#include <stdio.h>
#include <libopencm3-plus/utils/misc.h>
#include <libopencm3-plus/stm32f4discovery/leds.h>
#include <limits.h>
#include <stdbool.h>
#include "motor.h"
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <time.h>

//pwm-related timer configuration
#define SYSFREQ     168000000 //168MHz
#define PWMFREQ        32000  //32000
#define PWMFREQ_F       ((float )(PWMFREQ)) //32000.0f
#define PRESCALE        1                                       //freq_CK_CNT=freq_CK_PSC/(PSC[15:0]+1)
#define PWM_PERIOD_ARR  SYSFREQ/( PWMFREQ*(PRESCALE+1) )
#define INIT_DUTY 0.5f
#define PI 3.1416f
#define TICK_PERIOD 1.0f/PWMFREQ_F
#define MYUINT_MAX 536870912
#define t ticks/TICK_PERIOD
#define CUR_FREQ 1.0f/(period/TICK_PERIOD)

int hall_a;
uint ticks;
uint period;
uint temp_period;
float est_angle=0;
float duty_a=0.0f;
float duty_b=0.0f;
float duty_c=0.0f;
float duty_d=0.0f;
float ref_freqA=1;
float ref_freqB=1;
float ref_freqC=1;
float ref_freqD=1;

float cur_angle=0;
float final_ref_freq=40;
float error, p_error;
float i_error=0;
float cmd_angle;
float pi_control;
int close_loop=false;
int first_closed=false;
int motor_off;

void leds_init(void) {
  rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN);
  //gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO12);
  //gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO13);
  gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO14);
  gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO15);
}


void tim8_init(void){
        /* Enable TIM1 clock. and Port E clock (for outputs) */
        rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_TIM8EN);
        rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPEEN);

        //Set TIM8 channel (and complementary) output to alternate function push-pull'.
        //f4 TIM8=> GIO6: CH1, GPIO7: CH2
        //f4 TIM8=> GIO5: CH1N, GPIO0: CH2N
        gpio_mode_setup(GPIOB, GPIO_MODE_AF,GPIO_PUPD_NONE,GPIO1);
        gpio_set_af(GPIOB, GPIO_AF3, GPIO1);
	     gpio_mode_setup(GPIOC, GPIO_MODE_AF,GPIO_PUPD_NONE,GPIO8);
        gpio_set_af(GPIOC, GPIO_AF3, GPIO8);
	
        /* Enable TIM1 commutation interrupt. */
      //nvic_enable_irq(NVIC_TIM1_TRG_COM_TIM11_IRQ);        //f4

      /* Reset TIM1 peripheral. */
      timer_reset(TIM8);

      /* Timer global mode:
       * - No divider
       * - Alignment edge
       * - Direction up
       */
      timer_set_mode(TIM8, TIM_CR1_CKD_CK_INT, //For dead time and filter sampling, not important for now.
                     TIM_CR1_CMS_CENTER_3,        //TIM_CR1_CMS_EDGE
                                              //TIM_CR1_CMS_CENTER_1
                                              //TIM_CR1_CMS_CENTER_2
                                              //TIM_CR1_CMS_CENTER_3 la frequencia del pwm se divide a la mitad.
                       TIM_CR1_DIR_UP);

      timer_set_prescaler(TIM8, PRESCALE); //1 = disabled (max speed)
      timer_set_repetition_counter(TIM8, 0); //disabled
      timer_enable_preload(TIM8);
      timer_continuous_mode(TIM8);

      /* Period (32kHz). */
      timer_set_period(TIM8, PWM_PERIOD_ARR); //ARR (value compared against main counter to reload counter aka: period of counter)

      /* Configure break and deadtime. */
      //timer_set_deadtime(TIM1, deadtime_percentage*pwm_period_ARR);
      timer_set_enabled_off_state_in_idle_mode(TIM8);
      timer_set_enabled_off_state_in_run_mode(TIM8);
      timer_disable_break(TIM8);
      timer_set_break_polarity_high(TIM8);
      timer_disable_break_automatic_output(TIM8);
      timer_set_break_lock(TIM8, TIM_BDTR_LOCK_OFF);

      /* Disable outputs. */
      timer_disable_oc_output(TIM8, TIM_OC1);
      timer_disable_oc_output(TIM8, TIM_OC1N);
            
      /* -- OC1 and OC1N configuration -- */
      /* Configure global mode of line 1. */
      timer_enable_oc_preload(TIM8, TIM_OC1);
      timer_set_oc_mode(TIM8, TIM_OC1, TIM_OCM_PWM1);
      /* Configure OC1. */
      timer_set_oc_polarity_high(TIM8, TIM_OC1);
      timer_set_oc_idle_state_unset(TIM8, TIM_OC1); //When idle (braked) put 0 on output
      /* Configure OC1N. */
      timer_set_oc_polarity_high(TIM8, TIM_OC1N);
      timer_set_oc_idle_state_unset(TIM8, TIM_OC1N);
      /* Set the capture compare value for OC1. */
      timer_set_oc_value(TIM8, TIM_OC1, INIT_DUTY*PWM_PERIOD_ARR);//initial_duty_cycle*pwm_period_ARR);

    
      /* Reenable outputs. */
      timer_enable_oc_output(TIM8, TIM_OC1);
      timer_enable_oc_output(TIM8, TIM_OC1N);

      /* ---- */

      /* ARR reload enable. */
      timer_enable_preload(TIM8);

      /*
       * Enable preload of complementary channel configurations and
       * update on COM event.
       */
      //timer_enable_preload_complementry_enable_bits(TIM1);
      timer_disable_preload_complementry_enable_bits(TIM8);

      /* Enable outputs in the break subsystem. */
      timer_enable_break_main_output(TIM8);

      /* Generate update event to reload all registers before starting*/
      timer_generate_event(TIM8, TIM_EGR_UG);

      /* Counter enable. */
      timer_enable_counter(TIM8);

      /* Enable commutation interrupt. */
      //timer_enable_irq(TIM1, TIM_DIER_COMIE);

      /*********/
      /*Capture compare interrupt*/

       //enable capture compare interrupt
	timer_enable_update_event(TIM8);

	/* Enable commutation interrupt. */
	//timer_enable_irq(TIM1, TIM_DIER_CC1IE);	//Capture/compare 1 interrupt enable
	/* Enable commutation interrupt. */
	//timer_enable_irq(TIM1, TIM_DIER_CC1IE);
	timer_enable_irq(TIM8, TIM_DIER_UIE);
	nvic_enable_irq(NVIC_TIM8_UP_TIM13_IRQ);
  }
	

void tim1_init(void)
{
      /* Enable TIM1 clock. and Port E clock (for outputs) */
      rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_TIM1EN);
      rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPEEN);

      //Set TIM1 channel (and complementary) output to alternate function push-pull'.
      //f4 TIM1=> GIO9: CH1, GPIO11: CH2, GPIO13: CH3
      //f4 TIM1=> GIO8: CH1N, GPIO10: CH2N, GPIO12: CH3N
      gpio_mode_setup(GPIOE, GPIO_MODE_AF,GPIO_PUPD_NONE,GPIO9 | GPIO11| GPIO13);//e9 e13 | GPIO11
      gpio_set_af(GPIOE, GPIO_AF1, GPIO9 | GPIO11 | GPIO13);
      gpio_mode_setup(GPIOE, GPIO_MODE_AF,GPIO_PUPD_NONE,GPIO8 | GPIO10| GPIO12);//e12 e8 | GPIO10
      gpio_set_af(GPIOE, GPIO_AF1, GPIO8 | GPIO10| GPIO12);

      /* Enable TIM1 commutation interrupt. */
      //nvic_enable_irq(NVIC_TIM1_TRG_COM_TIM11_IRQ);        //f4

      /* Reset TIM1 peripheral. */
      timer_reset(TIM1);

      /* Timer global mode:
       * - No divider
       * - Alignment edge
       * - Direction up
       */
      timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, //For dead time and filter sampling, not important for now.
                     TIM_CR1_CMS_CENTER_3,        //TIM_CR1_CMS_EDGE
                                              //TIM_CR1_CMS_CENTER_1
                                              //TIM_CR1_CMS_CENTER_2
                                              //TIM_CR1_CMS_CENTER_3 la frequencia del pwm se divide a la mitad.
                       TIM_CR1_DIR_UP);

      timer_set_prescaler(TIM1, PRESCALE); //1 = disabled (max speed)
      timer_set_repetition_counter(TIM1, 0); //disabled
      timer_enable_preload(TIM1);
      timer_continuous_mode(TIM1);

      /* Period (32kHz). */
      timer_set_period(TIM1, PWM_PERIOD_ARR); //ARR (value compared against main counter to reload counter aka: period of counter)

      /* Configure break and deadtime. */
      //timer_set_deadtime(TIM1, deadtime_percentage*pwm_period_ARR);
      timer_set_enabled_off_state_in_idle_mode(TIM1);
      timer_set_enabled_off_state_in_run_mode(TIM1);
      timer_disable_break(TIM1);
      timer_set_break_polarity_high(TIM1);
      timer_disable_break_automatic_output(TIM1);
      timer_set_break_lock(TIM1, TIM_BDTR_LOCK_OFF);

      /* Disable outputs. */
      timer_disable_oc_output(TIM1, TIM_OC1);
      timer_disable_oc_output(TIM1, TIM_OC1N);
      timer_disable_oc_output(TIM1, TIM_OC2);
      timer_disable_oc_output(TIM1, TIM_OC2N);
      timer_disable_oc_output(TIM1, TIM_OC3);
      timer_disable_oc_output(TIM1, TIM_OC3N);

      /* -- OC1 and OC1N configuration -- */
      /* Configure global mode of line 1. */
      timer_enable_oc_preload(TIM1, TIM_OC1);
      timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1);
      /* Configure OC1. */
      timer_set_oc_polarity_high(TIM1, TIM_OC1);
      timer_set_oc_idle_state_unset(TIM1, TIM_OC1); //When idle (braked) put 0 on output
      /* Configure OC1N. */
      timer_set_oc_polarity_high(TIM1, TIM_OC1N);
      timer_set_oc_idle_state_unset(TIM1, TIM_OC1N);
      /* Set the capture compare value for OC1. */
      timer_set_oc_value(TIM1, TIM_OC1, INIT_DUTY*PWM_PERIOD_ARR);//initial_duty_cycle*pwm_period_ARR);

      /* -- OC2 and OC2N configuration -- */
      /* Configure global mode of line 2. */
      timer_enable_oc_preload(TIM1, TIM_OC2);
      timer_set_oc_mode(TIM1, TIM_OC2, TIM_OCM_PWM1);
      /* Configure OC2. */
      timer_set_oc_polarity_high(TIM1, TIM_OC2);
      timer_set_oc_idle_state_unset(TIM1, TIM_OC2);
      /* Configure OC2N. */
      timer_set_oc_polarity_high(TIM1, TIM_OC2N);
      timer_set_oc_idle_state_unset(TIM1, TIM_OC2N);
      /* Set the capture compare value for OC2. */
      timer_set_oc_value(TIM1, TIM_OC2, INIT_DUTY*PWM_PERIOD_ARR);//initial_duty_cycle*pwm_period_ARR);

      /* -- OC3 and OC3N configuration -- */
      /* Configure global mode of line 3. */
      timer_enable_oc_preload(TIM1, TIM_OC3);
      timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1);
      /* Configure OC3. */
      timer_set_oc_polarity_high(TIM1, TIM_OC3);
      timer_set_oc_idle_state_unset(TIM1, TIM_OC3);
      /* Configure OC3N. */
      timer_set_oc_polarity_high(TIM1, TIM_OC3N);
      timer_set_oc_idle_state_unset(TIM1, TIM_OC3N);
      /* Set the capture compare value for OC3. */
      timer_set_oc_value(TIM1, TIM_OC3, INIT_DUTY*PWM_PERIOD_ARR);//initial_duty_cycle*pwm_period_ARR);//100);

      /* Reenable outputs. */
      timer_enable_oc_output(TIM1, TIM_OC1);
      timer_enable_oc_output(TIM1, TIM_OC1N);
      timer_enable_oc_output(TIM1, TIM_OC2);
      timer_enable_oc_output(TIM1, TIM_OC2N);
      timer_enable_oc_output(TIM1, TIM_OC3);
      timer_enable_oc_output(TIM1, TIM_OC3N);

      /* ---- */

      /* ARR reload enable. */
      timer_enable_preload(TIM1);

      /*
       * Enable preload of complementary channel configurations and
       * update on COM event.
       */
      //timer_enable_preload_complementry_enable_bits(TIM1);
      timer_disable_preload_complementry_enable_bits(TIM1);

      /* Enable outputs in the break subsystem. */
      timer_enable_break_main_output(TIM1);

      /* Generate update event to reload all registers before starting*/
      timer_generate_event(TIM1, TIM_EGR_UG);

      /* Counter enable. */
      timer_enable_counter(TIM1);

      /* Enable commutation interrupt. */
      //timer_enable_irq(TIM1, TIM_DIER_COMIE);

      /*********/
      /*Capture compare interrupt*/

      //enable capture compare interrupt
      timer_enable_update_event(TIM1);

      /* Enable commutation interrupt. */
      //timer_enable_irq(TIM1, TIM_DIER_CC1IE);        //Capture/compare 1 interrupt enable
      /* Enable commutation interrupt. */
      //timer_enable_irq(TIM1, TIM_DIER_CC1IE);
      timer_enable_irq(TIM1, TIM_DIER_UIE);
      nvic_enable_irq(NVIC_TIM1_UP_TIM10_IRQ);
}

void system_init(void) {
  rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_168MHZ]);
  leds_init();
  cdcacm_init();
  printled(4, LRED);
  tim1_init();
  tim8_init();
}


void gen_pwm(void) {
  //calc_attenuation();

 // static float pi_times;

//pi_controller();
duty_a=ref_freqA/10.0f;
duty_b=ref_freqB/10.0f;
duty_c=ref_freqC/10.0f;
duty_d=ref_freqD/10.0f;

if (duty_a < 0.0f)
  {
    timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1);
    timer_disable_oc_output(TIM1,TIM_OC1);
    timer_enable_oc_output (TIM1, TIM_OC1N);
    duty_a=-duty_a;
  }
else
  {
    timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1);
    timer_enable_oc_output(TIM1, TIM_OC1 );
    timer_disable_oc_output (TIM1, TIM_OC1N);
  }
//////////////////////////////////////////////////////////////
if (duty_b < 0.0f)
  {
    timer_set_oc_mode(TIM1, TIM_OC2, TIM_OCM_PWM1);
    timer_disable_oc_output(TIM1, TIM_OC2 );
    timer_enable_oc_output (TIM1, TIM_OC2N);
    duty_b=-duty_b;
  }
else
  {
    timer_set_oc_mode(TIM1, TIM_OC2, TIM_OCM_PWM1);
    timer_enable_oc_output(TIM1, TIM_OC2 );
    timer_disable_oc_output (TIM1, TIM_OC2N);
  }
//////////////////////////////////////////////////////////////
if (duty_c < 0.0f)
  {
    timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1);
    timer_disable_oc_output(TIM1, TIM_OC3 );
    timer_enable_oc_output (TIM1, TIM_OC3N);
    duty_b=-duty_b;
  }
else
  {
    timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1);
    timer_enable_oc_output(TIM1, TIM_OC3 );
    timer_disable_oc_output (TIM1, TIM_OC3N);
  }
  //////////////////////////////////////////////////////////////
 if (duty_d < 0.0f)
    {
    timer_set_oc_mode(TIM8, TIM_OC1, TIM_OCM_PWM1);
    timer_disable_oc_output(TIM8, TIM_OC1 );
    timer_enable_oc_output (TIM8, TIM_OC1N);
    duty_b=-duty_b;
  }
else
  {
    timer_set_oc_mode(TIM8, TIM_OC1, TIM_OCM_PWM1);
    timer_enable_oc_output(TIM8, TIM_OC1 );
    timer_disable_oc_output (TIM8, TIM_OC1N);
  }
 

/* Set the capture compare value for OC1. */
timer_set_oc_value(TIM1, TIM_OC1, duty_a*PWM_PERIOD_ARR);
/* Set the capture compare value for OC1. */
timer_set_oc_value(TIM1, TIM_OC2, duty_b*PWM_PERIOD_ARR);
//tim_force_update_event(TIM8);
}

void tim1_up_tim10_isr(void) {
// Clear the update interrupt flag
timer_clear_flag(TIM1,  TIM_SR_UIF);
gen_pwm();
}

void tim8_up_tim13_isr(void) {
// Clear the update interrupt flag
timer_clear_flag(TIM8,  TIM_SR_UIF);
gen_pwm();
}


bool receive_a_string(char* cmd_s){
  char c=0;
  int i=0;
	
if (poll(stdin) > 0){
  while (c!='\r'){
    c=getc(stdin);
    cmd_s[i]=c;
    i++;
    putc(c, stdout); //no necesito q me devuelva lo q escribo?
  }
  
  cmd_s[i]='\0';
  return true;
}
else
  return false;
}


void clean_stdin(void){
  while ( poll(stdin)>0){
    printf("Cleaning stdin\n");
    getc(stdin);
  }
}

void stdin_init(void){
  setvbuf(stdin,NULL,_IONBF,0);  // Sets stdin  in unbuffered mode (normal for usart com)
  setvbuf(stdout,NULL,_IONBF,0); // Sets stdout in unbuffered mode (normal for usart com)
  clean_stdin();
} 


int main(void){
  system_init();
  stdin_init();

char cmd_s[50]="";
char cmdA[15]=""; //A  Motor
char cmdB[15]=""; //B Motor
char cmdC[15]=""; //C  Motor
char cmdD[15]=""; //D Motor

float valueA;//A Motor speed
float valueB;//B Motor speed
float valueC;//C Motor speed
float valueD;//D Motor speed

while (1){
 
 if (receive_a_string(cmd_s)){
   //printf("%s", cmd_s);
   sscanf(cmd_s, "%s %f %s %f %s %f %s %f", cmdA, &valueA, cmdB, &valueB, cmdC, &valueC, cmdD, &valueD);
    if( (strcmp(cmdA, "a") == 0) && (strcmp(cmdB, "b")  == 0) && (strcmp(cmdC, "c")  == 0) && (strcmp(cmdD, "d")  == 0) ){ 
				//set ref freq
				ref_freqA=valueA;
				ref_freqB=valueB;
				ref_freqC=valueC;
				ref_freqD=valueD;
				//printf("test\n");
				printf("\n%f %f %f %f\n", valueA, valueB, valueC, valueD);
          printf("%s %s %s %s\n", cmdA, cmdB, cmdC, cmdD);
      }
    }
  }
}

Minicom

Se utilizó Minicom para probar el software del microcontrolador:

Minicom es un programa de comunicación serial para acceder a una red o dispositivo de seguridad a través de su puerto de consola.

Instalación
apt-get install minicom

Añadir su usuario al grupo “dialout”.

adduser your_user dialout

Una vez flasheado el STM32 con el software se crea el puerto serial por usb, para saber cual es ese puerto hacemos:

dmesg | grep tty

Vermos algo asi como:

crw-rw---- 1 root dialout 4, 64 2007-02-26 22:55 ttyACM0

Ahora corremos el minicom.

sudo minicom -s

Se ve asi:

En serial port setup conectamos el puerto. Presionando F desactivamos el Hardware Flow Control y con A ponemos el nombre del puerto:

Luego hacemos ESC y exit, ahora podemos enviar los comandos que en el código fuente estan especificados.

Control por bluetooth

Instalar lo necesario para usar el control de PS3

Para instalar todo lo necesario para instalar el control de PS3 primero se ocupa descargar el codigo fuente de la aplicacion que esta en la direccion http://sourceforge.net/projects/qtsixa/files/QtSixA%201.5.1/QtSixA-1.5.1-src.tar.gz/download Como el codigo fuente ocupa otras dependecias para poder instalarse, se tienen que instalar

libbluetooth3
libdbus-1
libdbus-glib-1
libjack 
bluez
libbluetooth3
udev
bluez-hcidump
Python-DBus

Despues en la carpeta en que se descargó

tar -xvzf QtSixA-1.5.1-src.tar.gz
cd QtSixA-1.5.1
cd sixad

Antes de poder hacer el make, se ocupa hacer una modificacion al archivo shared.h, ahi se tiene que agregar la lineas con “+”

 #ifndef SHARED_H
 #define SHARED_H
 
+#include <unistd.h>
+
 struct dev_led {
     bool enabled;
     bool anim;

Ahora se puede proseguir con la instalacion.

make
sudo make install
cd ..
cd utils
gcc -o sixpair sixpair.c -lusb
Conectar el control de PS3

Primero se tiene que sincronizar la direccion bluetooth del control, con la de la computadora, para esto se conecta el control por usb al Pi, y se ejucuta el ejecutable ./sixpair . Despues se desconecta el control del usb, y en consola se ejecuta

sudo sixad -s
Obtener los datos del Joystick
#!/usr/bin/env python
import pygame
import math
import os
# Define some colors
BLACK    = (   0,   0,   0)
WHITE    = ( 255, 255, 255)

# This is a simple class that will help us print to the screen
# It has nothing to do with the joysticks, just outputing the
# information.
class TextPrint:
    def __init__(self):
        self.reset()
        self.font = pygame.font.Font(None, 20)
        
    def printd (self, screen, textString):
        textBitmap = self.font.render(textString, True, BLACK)
        screen.blit(textBitmap, [self.x, self.y])
        self.y += self.line_height
      
    def reset(self):
        self.x = 10
        self.y = 10
        self.line_height = 15
      
    def indent(self):
        self.x += 10
      
    def unindent(self):
        self.x -= 10  
          
pygame.init() 

#Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()

# Initialize the joysticks
pygame.joystick.init()    
# Get ready to print

textPrint = TextPrint()

# -------- Main Program Loop -----------
while done==False:
    # EVENT PROCESSING STEP
    for event in pygame.event.get(): # User did something
        if event.type == pygame.QUIT: # If user clicked close
            done=True # Flag that we are done so we exit this loop
            
    # Possible joystick actions: JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION
        if event.type == pygame.JOYBUTTONDOWN:
            print("Joystick button pressed.")
            
        if event.type == pygame.JOYBUTTONUP:        
            print("Joystick button released.") 
                    
    # Get count of joysticks
    joystick_count = pygame.joystick.get_count()
       
    # For each joystick:
    for i in range(joystick_count):
        joystick = pygame.joystick.Joystick(i)
        joystick.init()  
             
    #Usually axis run in pairs, up/down for one, and left/right for the other
      
        axes = joystick.get_numaxes()
        y=-joystick.get_axis(1);
        x=joystick.get_axis(0);
      
        velocidad= math.sqrt(x**2+y**2);
        direccion=math.atan2(y,x);
     
        v1=-(velocidad*math.sin(direccion+(math.pi/4)));
        v2=velocidad*math.cos(direccion+(math.pi/4));
        v3=velocidad*math.cos(direccion+(math.pi/4));
        v4=-(velocidad*math.sin(direccion+(math.pi/4)));
	var="echo -n -e "+"a "+v1+"b "+v2+"c "+v3+"d "+v4+"> /dev/ttyACM0"
	os.system(var)
        print var  
         
       # Limit to 20 frames per second
        clock.tick(20)    
pygame.quit ()
teaching/ie0117/proyectos/2014/i/proyecto_1/base_omnidireccional.txt · Last modified: 2022/09/20 00:08 (external edit)