CNC Arduino Due

Hola, Estoy tratando de hacer un código cnc para arduino due, espero y pueda aportar información y me puedan aportar para terminar mi proyecto

primeramente ocupa saber el tiempo del scan para poder calcular la aceleración y desaceleración

void loop() 
{
 Timer = micros();

 Timer_Scan = micros() - Timer;
}

con esta parte ya tenia el tiempo del scan, mas sin embargo si el tiempo del scan era variable tenia que hacer calculo para cada scan, por lo que decidí tener un tiempo fijo de scan

void loop() 
{
 Timer = micros();

 esperar:
 Timer_Scan = micros() - Timer;
 if (Timer_Scan < 10)goto esperar;
}

Ya de esta forma tengo un tiempo de scan fijo o muy cercano uno del otro 10 u 11 useg, ahora ocupo leer la informacion que viene del puerto serial

void loop() 
{
 Timer = micros();
  Leer_Datos_Serial();

 esperar:
 Timer_Scan = micros() - Timer;
 if (Timer_Scan < 10)goto esperar;
}

void Leer_Datos_Serial()
{
  if (Serial.available() > 0)
  {
    char inChar = SerialUSB.read();
    inBuffer[Serial_cont++] = inChar;
    if (inChar == '\n')
    {
          inBuffer[Serial_cont++] = 0;
          copy(inBuffer, outBuffer, Serial_cont);
          Dato_Serial = true;
          Tam_Dato = Serial_cont;
          Serial_cont = 0;  
    }
  }
}

De esta forma si hay datos serie presentes leo un byte por scan para poder hacer otras actividades sin tener que ciclarme leyendo todo el puerto, cuando termine de leer el puerto, copio a outBuffer el dato recibido, activo una bandera (Dato_Serial) y habilito el puerto serie para leer otro dato si estuviera presente o en el momento de estar procesando el dato recibido, hora ocupo procesar el recibido, el dato no lo puedo procesar en un scan ya que dependiendo el tamaño puede llegar hasta 900 useg, por lo cual lo tengo que dividir en partes

void loop() 
{
 Timer = micros();
  Leer_Datos_Serial();
  if (Dato_Serial)
  {
     Procesar_Dato();
     Dato_Serial=0;
   }

 esperar:
 Timer_Scan = micros() - Timer;
 if (Timer_Scan < 10)goto esperar;
}

En la función Procesar_Dato realizo lo mismo qeu los programas normales arduino pero lo divido en pasos, en el primer scan leo si el dato recibido es un comando G, un comando M o es algún otro dato, en ese caso termino el proceso, en el segundo scan, si es comando M leo el valor de M y termino el proceso, si es G leo el valor de G, en el tercer scan pregunto si tiene valor X y leo el valor, en el cuarto leo Y y así sucesivamente hasta terminar. con esto no le quito tiempo al procesamiento y puedo hacer varias cosas al mismo tiempo.

Ya después de haber procesado el dato y ver que era un comando de movimiento activo una bandera, Mover, y entro a rutina de aceleración.

void loop() 
{
 Timer = micros();
  Leer_Datos_Serial();
  if (Dato_Serial)
  {
     Procesar_Dato();
     Dato_Serial=0;
   }
   if (Move)
  {
    Acceleracion();
    if (Permiso_Mover)
    {
      Mov_Linear();
      Permiso_Mover = 0;
    }
  }

 esperar:
 Timer_Scan = micros() - Timer;
 if (Timer_Scan < 10)goto esperar;
}

En la rutina de Aceleración se calcula de acuerdo a la velocidad cada cuando se debe de mover un pulso del motor

La programación me esta quedando de la siguiente manera

void loop()
{
 Timer = micros();               // Leo el tiempo actual en useg

  Leer_Entradas();                //Leo las entradas digitales del arduino
  
  Leer_Datos_Serial();          //Leo entradas por medio del dato serie

  if (Dato_Serial)                  //Si e recibido un dato lo proceso  
  {
     Procesar_Dato();            // Proceso dato recibido
     Dato_Serial=0;               // Desactivo bandera de dato recibido
   }

   if (Move)                          // Si esta activa la bandera de movimiento, ejecuto rutina de Acc
  {
    Acceleracion();                // Ejecuto rutina de Acc
    if (Permiso_Mover)           // Si es hora de mover un pulso del motor lo muevo
    {
      Mov_Linear();                // Muevo un solo pulso del motor
      Permiso_Mover = 0;       // Desactivo bandera de movimiento de pulsos
    }
  }
  
  Escribir_Salidas();              // Si hay una salida presente ya sea activación o desactivación de pulsos 
                                          // la escribo 

  Escribir_Datos_Serial();      //Escribo un byte por escan si hay datos presentes en el buffer de salida
                                          //el unico incomveniente es que utilizo una velocidad de 115200 
                                          //(8.6 useg/bit)  por 10 bit de encio tarda 86 useg
                                          // No se si alguine me pudiera decir como escribir directo al buffer de salida
                                          // y no esperar hasta qeu el dato se haya enviado

 esperar:                             // Espero para qeu se cumplan los 10 useg del scan 
 Timer_Scan = micros() - Timer;
 if (Timer_Scan < 10)goto esperar;
}

otro apartado importante es que la escritura de las salidas digitales tienen que ser lo mas rápido posible por lo cual estoy utilizando la siguiente función

void Fast_digitalWrite1( uint32_t ulPin, bool ulVal )
{
  if ( ulVal ) g_APinDescription[ulPin].pPort->PIO_SODR  = g_APinDescription[ulPin].ulPin;
  else         g_APinDescription[ulPin].pPort->PIO_CODR  = g_APinDescription[ulPin].ulPin;
}

No se si alguien tenga una función parecida para la lectura de los pines de entrada

Voy a trabajar en la tarde le sigo compartiendo mi proyecto...

LeopoldoGuerra:
No se si alguien tenga una función parecida para la lectura de los pines de entrada

Página 624 de la hoja de datos de Sam3x:

31.5.8 Inputs
The level on each I/O line can be read through PIO_PDSR (Pin Data Status Register). This register indicates the level of the I/O lines regardless of their configuration, whether uniquely as an input or driven by the PIO controller or driven by a peripheral.
Reading the I/O line levels requires the clock of the PIO controller to be enabled, otherwise PIO_PDSR reads the levels present on the I/O line at the time the clock was disabled

un ejemplo ici (respuesta 3)
https://forum.arduino.cc/index.php?topic=499177.0

Gracias "ard_newbie", lo voy a aplicar para mi función de lectura.

Ya puse mi estructura principal del programa, ahora voy a poner una de las funciones principales que es la de Acceleracion(), esta función en si se divide en dos partes la primera es el calculo de la aceleración y la segunda es la aceleración, a continuación voy a poner las variables y constante que se ocupan y luego a explicar estas dos funciones

#define   Vel_Max                       2500.0         // Velocidad máxima en pulsos por segundos
#define   Acc                              2.5              // Tiempo de Aceleración en segundos
#define   Dacc                            2.5              // Tiempo de Desaceleración en segundos
#define   Inc_Scan_Vel_Max        0.025          //  = Vel_Max*Tiempo Scan en seg (2500*0.00001)
#define   Inc_Scan_Acc               0.0000001   //  =Inc_Scan_Vel_Max*Tiempo_Scan(seg)/Acc =0.025*0.00001/2.5
#define   Inc_Scan_Dacc             0.0000001   //  =Inc_Scan_Vel_Max*Tiempo_Scan(seg)/Dacc =0.025*0.00001/2.5
#define Timer_Acc                      0.001          //Acc/Vel_Max 
#define Timer_Dacc                    0.001          //Dacc/Vel_Max


float   Inc_Scan;               // Incremento por scan a velocidad deseada
long   Dist_Acc;                // Distancia a mover en la Acc
long   Dist_Dacc;              // Distancia a mover en la Dacc
long   Dist_Mover;            // Distancia maxima a mover en el movimiento actual
long   Cont_Dist_Mover;    // Va contando la distancia cada vez que aumenta un pulso
float   Dist_D_Acc;            // relacion entre distancia a mover y suma de la dos distancias de Acc y Dacc
float   Vel;                        // Velocidad deseada
float   Dist_M;                  // variable para saber si ya toca mover un pulso
bool   Mover;                    //bandera que hay un movimiento activo
bool   Permiso_Mover;       // bandera que hay permiso de mover un pulso

void Cal_Acceleracion(void)
{

Dist_Acc = (Vel/ 2.0) * Vel * Timer_Acc;                     //calculo la distancia recorrida en la Acc
Dist_Dacc = (Vel/ 2.0) * Vel * Timer_Dacc;                 //calculo la distancia recorrida en la Dacc
Dist_D_Acc = float(Dist_Mover) / float(Dist_Acc + Dist_Dacc);   // Calculo que relación tiene la distancia a mover con respecto a la suma de Distancia Acc y Dacc

  if (Dist_D_Acc < 1.0)                   // Pregunto si la distancia de la Acc y Dacc es mayor a distancia Max
  {                                                // Esto solo funciona si la Acc y Dacc son iguales
    Dist_Acc = Dist_Acc * Dist_D_Acc;
    Dist_Dacc = Dist_Dacc * Dist_D_Acc;
  }

Inc_Scan = (Vel * 0.00001);
Move = 1;
}

void Acceleracion(void)
{
  if (Dist_Mover <= Cont_Dist_Mover)
  {
    Move = 0;
  }
  else if ((Dist_Mover - Cont_Dist_Mover) <=  Dist_Dacc)
  {
    Inc_Dist -= Inc_Dacc;
  }
  else if (Cont_Dist_Mover <= Dist_Acc)
  {
    Inc_Dist += Inc_Acc;
  }
  else
  {
    Inc_Dist = Inc_Scan;
  }

  Dist_M += Inc_Dist;
  if (Dist_M >= 1.0)
  {
    Cont_Dist_Mover++;
    Permiso_Mover = 1;
    Dist_M -= 1.0;
  }
}

Este es el código que estoy utilizando para la rampa de Aceleración y Desaceleración, el único inconveniente es que si yo me muevo de G01X0Y0 a G01X10Y0 y luego a G01X20Y0, Desacérelo a cero y vuelvo a acelerar a la velocidad, siendo que debería ser un movimiento continuo, mas adelante explico como soluciono ese detalle.

Moderador
Por favor edita tu primer post usando etiquetas de código.

Normas del foro

Buen día, aquí pongo mi primer programa trabajando bajo esta estructura, este programa solo reconoce código G00 y G01,

config.h

#ifndef _CONFIG_H_
#define _CONFIG_H_


#define   BUFFER_SIZE    100  // Tamaño buffer serial

#define MICRO_STEP     8
#define ROD_CONF_X     (200/8)

#define PULSOS_MM_X   ( ROD_CONF_X * MICRO_STEP )

#define   Vel_Max                2500.0     // Velocidad máxima en pulsos por segundos
#define   Acc                    2.5        // Tiempo de Aceleración en segundos
#define   Dacc                   2.5        // Tiempo de Desaceleración en segundos
#define   Inc_Scan_Vel_Max       0.025      //  = Vel_Max*Tiempo Scan en seg (2500*0.00001)
#define   Inc_Scan_Acc           0.0000001  //  =Inc_Scan_Vel_Max*Tiempo_Scan(seg)/Acc =0.025*0.00001/2.5
#define   Inc_Scan_Dacc          0.0000001  //  =Inc_Scan_Vel_Max*Tiempo_Scan(seg)/Dacc =0.025*0.00001/2.5
#define   Timer_Acc              0.001      //Acc/Vel_Max
#define   Timer_Dacc             0.001      //Dacc/Vel_Max



//------------Definicion de pines-----------//
#define Pul_X_Pin  2//A0
#define Dir_X_Pin  5//A1
#define E_X_Pin    8//38

#define Pul_Y_Pin  3//A6
#define Dir_Y_Pin  6//A7
#define E_Y_Pin    8//A2

#define Pul_Z_Pin  4//46
#define Dir_Z_Pin  7//48
#define E_Z_Pin    8//A8

#endif

Por cuestión de tamaño lo tengo que dividir en varias partes

#include <Arduino.h>
#include "config.h"


//-------------Variables--------//
char inBuffer[BUFFER_SIZE]; // buffer para la entrada serial
char outBuffer[BUFFER_SIZE]; // buffer para la entrada serial

int  Serial_cont = 0;         // contador de byte de entrada serial
int  Tam_Dato = 0;            // Tamaño de dato recibido en byte
int  Gcode = 0;               // Codigo G en proceso
int  Mcode = 0;               // Codigo M en proceso
bool Move = 0;                // Movimiento en proceso
int  Salida;                  // saber si se a activado un pulso de salida
bool Dato_Serial;             // Bandera Dato serie recibido

long Timer;                   // Tiempo actual al empesar el scan
long Timer_Scan;              // Tiempo del scan

float  Inc_Scan;          // Incremento por scan a velocidad deseada
long   Dist_Acc;          // Distancia a mover en la Acc
long   Dist_Dacc;         // Distancia a mover en la Dacc
long   Dist_Mover;        // Distancia maxima a mover en el movimiento actual
long   Cont_Dist_Mover;   // Va contando la distancia cada vez que aumenta un pulso
float  Dist_D_Acc;        // relacion entre distancia a mover y suma de la dos distancias de Acc y Dacc
float  Vel= Vel_Max;      // Velocidad deseada
float  Dist_M;            // variable para saber si ya toca mover un pulso
bool   Mover;             //bandera que hay un movimiento activo
bool   Permiso_Mover;     // bandera que hay permiso de mover un pulso
float   Vel_Act;          // Velocidad actual
double  Inc_Dist;         // contador para dar permiso mover un pulso

long     x_counter, y_counter, z_counter, max_delta;
long     Delta_x, Delta_y, Delta_z;
bool     Dir_x, Dir_y, Dir_z;

bool     led13;
//------------------------------//

//----------Structuras----------//
typedef struct LongPoint
{
  long x;
  long y;
  long z;
} t_longPoint;

t_longPoint Ant;
t_longPoint New;
//------------------------------//

void setup() {
  SerialUSB.begin(115200);
  while (!SerialUSB);
  SerialUSB.println("start");
  pinMode ( Pul_X_Pin, OUTPUT );
  pinMode ( Dir_X_Pin, OUTPUT );
  pinMode ( E_X_Pin, OUTPUT );

  pinMode ( Pul_Y_Pin, OUTPUT );
  pinMode ( Dir_Y_Pin, OUTPUT );
  pinMode ( E_Y_Pin, OUTPUT );

  pinMode ( Pul_Z_Pin, OUTPUT );
  pinMode ( Dir_Z_Pin, OUTPUT );
  pinMode ( E_Z_Pin, OUTPUT );

  pinMode ( 13, OUTPUT );
  Fast_digitalWrite1(13, 0);

}

void loop() {
  Timer = micros();

  //Leer_entradas();
  Leer_datos_serie();

  if (Dato_Serial && Move == 0)
  {
    Procesar_Dato(outBuffer, Tam_Dato);
    Dato_Serial = 0;
    SerialUSB.println("ok");
  }
  if (Move)
  {
    Acceleracion();
    if (Permiso_Mover)
    {
      Mov_Linear();
      Permiso_Mover = 0;
    }
  }

  Escribir_salidas();
  //Escribir_datos_serie();


esperar:
  Timer_Scan = micros() - Timer;
  if (Timer_Scan < 10)goto esperar;
}

void Leer_entradas()
{
}

void Leer_datos_serie()
{
  if (SerialUSB.available() > 0)
  {
    char inChar = SerialUSB.read();
    inBuffer[Serial_cont++] = inChar;
    if (inChar == '\n')
    {
      inBuffer[Serial_cont++] = 0;
      copy(inBuffer, outBuffer, Serial_cont);
      Dato_Serial = true;
      Tam_Dato = Serial_cont;
      Serial_cont = 0;
    }
  }
}

void Escribir_salidas()
{
  if (Salida==1) Salida=2; //Espero un ciclo para poner a cero los pines de pulsos
  else if (Salida==2)
  {
    Fast_digitalWrite1(Pul_X_Pin, 0);
    Fast_digitalWrite1(Pul_Y_Pin, 0);
    Fast_digitalWrite1(Pul_Z_Pin, 0);
    Salida=0;
  }
}
void Escribir_datos_serie()
{
}

void copy(char* src, char* dst, int len)
{
  for (int i = 0; i < len; i++) {
    *dst++ = *src++;
  }
}

Segunda parte

void Procesar_Dato(char Dato[], int size)
{
  if (Buscar_Caracter('G', Dato, size))
  {
    if ( Buscar_Caracter('F', Dato, size) )
    {
      Vel_Act = Buscar_Valor('F', Dato, size);
      Vel = Vel_Act;
    }
    if ( Buscar_Caracter('X', Dato, size)) New.x = PULSOS_MM_X * Buscar_Valor('X', Dato, size);
    if ( Buscar_Caracter('Y', Dato, size)) New.y = PULSOS_MM_X * Buscar_Valor('Y', Dato, size);
    if ( Buscar_Caracter('Z', Dato, size)) New.z = PULSOS_MM_X * Buscar_Valor('Z', Dato, size);

    Gcode = Buscar_Valor('G', Dato, size);
    switch (Gcode)
    {
      case 0:
        Vel = Vel_Max;
      case 1:
        Cal_Mov_Linear();
        Move = 1;
        Vel = Vel_Act;
        break;
    }
  }

  if (Buscar_Caracter('M', Dato, size))
  {
    Mcode = Buscar_Valor('M', Dato, size);
    switch (Mcode)
    {
      // Encender Motor
      case 3:
        break;

      // Apagar Motor
      case 5:
        break;
    }
  }
}

double Buscar_Valor(char Caracter, char Dato[], int size)
{
  char temp[10] = "";
  for (byte i = 0; i < size; i++)
  {
    if (Dato[i] == Caracter)
    {
      i++;
      int k = 0;
      while (i < size && k < 10)
      {
        if (Dato[i] == 0 || Dato[i] == ' ')
          break;
        temp[k] = Dato[i];
        i++;
        k++;
      }
      return strtod(temp, NULL);
    }
  }
  return 0;
}

bool Buscar_Caracter(char Caracter, char Dato[], int size)
{
  for (byte i = 0; i < size; i++)
  {
    if (Dato[i] == Caracter)
      return true;
  }
  return false;
}



void Cal_Mov_Linear(void)
{

  if ((New.x - Ant.x) >= 0)
  {
    Delta_x = New.x - Ant.x;
    Dir_x = 1;
    Fast_digitalWrite1(Dir_X_Pin, 1);
  }
  else
  {
    Delta_x = Ant.x - New.x;
    Dir_x = 0;
    Fast_digitalWrite1(Dir_X_Pin, 0);
  }

  if ((New.y - Ant.y) >= 0)
  {
    Delta_y = New.y - Ant.y;
    Dir_y = 1;
    Fast_digitalWrite1(Dir_Y_Pin, 1);
  }
  else
  {
    Delta_y = Ant.y - New.y;
    Dir_y = 0;
    Fast_digitalWrite1(Dir_Y_Pin, 0);
  }

  if ((New.z - Ant.z) >= 0)
  {
    Delta_z = New.z - Ant.z;
    Dir_z = 1;
    Fast_digitalWrite1(Dir_Z_Pin, 1);
  }
  else
  {
    Delta_z = Ant.z - New.z;
    Dir_z = 0;
    Fast_digitalWrite1(Dir_Z_Pin, 0);
  }



  max_delta = max(Delta_x, Delta_y);
  max_delta = max(Delta_z, max_delta);

  x_counter = -max_delta / 2;
  y_counter = x_counter;//-max_delta / 2;
  z_counter = x_counter;//-max_delta / 2;

  Cal_Acceleracion();
}

void Cal_Acceleracion(void)
{
  Dist_Mover=max_delta;
  Cont_Dist_Mover=0;


  Dist_Acc = (Vel/ 2.0) * Vel * Timer_Acc;                     //calculo la distancia recorrida en la Acc
  Dist_Dacc = (Vel/ 2.0) * Vel * Timer_Dacc;                 //calculo la distancia recorrida en la Dacc
  Dist_D_Acc = float(Dist_Mover) / float(Dist_Acc + Dist_Dacc);   // Calculo que relación tiene la distancia a mover con respecto a la suma de Distancia Acc y Dacc

  if (Dist_D_Acc < 1.0)                   // Pregunto si la distancia de la Acc y Dacc es mayor a distancia Max
  {                                                // Esto solo funciona si la Acc y Dacc son iguales
    Dist_Acc = Dist_Acc * Dist_D_Acc;
    Dist_Dacc = Dist_Dacc * Dist_D_Acc;
  }

  Inc_Scan = (Vel * 0.00001);
}

void Mov_Linear(void)
{

  x_counter += Delta_x;
  if (x_counter > 0)
  {
    x_counter -= max_delta;
    Fast_digitalWrite1(Pul_X_Pin, 1);
    if (Dir_x)
      Ant.x++;
    else
      Ant.x--;
  }



  y_counter += Delta_y;
  if (y_counter > 0)
  {
    y_counter -= max_delta;
    Fast_digitalWrite1(Pul_Y_Pin, 1);
    if (Dir_y)
      Ant.y++;
    else
      Ant.y--;
  }


  z_counter += Delta_z;
  if (z_counter > 0)
  {
    z_counter -= max_delta;
    Fast_digitalWrite1(Pul_Z_Pin, 1);
    if (Dir_z)
      Ant.z++;
    else
      Ant.z--;
  }
  Salida=1;
}


void Fast_digitalWrite1( uint32_t ulPin, bool ulVal )
{
  if ( ulVal )
    g_APinDescription[ulPin].pPort->PIO_SODR  = g_APinDescription[ulPin].ulPin;
  else
    g_APinDescription[ulPin].pPort->PIO_CODR  = g_APinDescription[ulPin].ulPin;
}


void Acceleracion(void)
{
  if (Dist_Mover <= Cont_Dist_Mover)
  {
    Move = 0;
  }
  else if ((Dist_Mover - Cont_Dist_Mover) <=  Dist_Dacc)
  {
    Inc_Dist -= Inc_Scan_Dacc;
  }
  else if (Cont_Dist_Mover <= Dist_Acc)
  {
    Inc_Dist += Inc_Scan_Acc;
  }
  else
  {
    Inc_Dist = Inc_Scan;
  }

  Dist_M += Inc_Dist;
  if (Dist_M >= 1.0)
  {
    Cont_Dist_Mover++;
    Permiso_Mover = 1;
    Dist_M -= 1.0;
  }
}

Aun no e hecho librerías todo lo tengo bajo el mismo programa, ya que no se repite muchas veces y la memoria del Arduino Due estaba pensando hacer Macros en vez de Funciones para cuestión de velocidad de procesamiento