Programacion de sensor optico y motores

Hola, saludos soy nueva en esta plataforma.

Estoy realizando un escáner 3D para un proyecto por medio de un sensor óptico de referencia Sharp GP2Y0A41SK0F y 2 motores paso a paso NEMA 17, sin embargo al momento de correr el programa los valores que me arroja en el monitor serie NO SON CORRECTOS ya que los verifico en el programa Meshlab que sirve para formar la nube de puntos del objeto a escanear y no me forma la imagen que necesito.

Adjunto el código por si alguien me puede ayudar con algún error que vea, de antemano muchas gracias me seria de muchísima ayuda

int scan_amount = 40;                   //Amaunt of scans for each point. The result is the mean. This would increase the delay for each scan.
int z_axis_height = 1200; //in cm         //Maximum height of the scaned file
int step_delay = 3000; //in us          //Delay for each step for the stepper motor in microseconds
float z_layer_height = 0.5; //in mm     //Layer height. The amount of mm for each layer. 
int lead_screw_rotations_per_cm = 8;    //How many rotations needs the lead screw to make in order to make 1cm. 
int steps_per_rotation_for_motor = 50; //Steps that the motor needs for a full rotation. 
int distance_to_center = 9;             //In cm. Distance from sensor to the turntable center in cm

//I/O
//Turntable driver pins
int dir_r = 7;
int step_r = 8;
int enable_r = 9;
//Z-axis driver pins
int dir_z = 5;
int step_z = 3;
int enable_z = 6;

int scan_changed = 0;       //Scan process was changed
float distancia = 0;         //Measured distance
float angle = 0;            //Rotation angle for each loop (0º-360º)
float x = 0;                //X, Y and Z coordinate
float y = 0;
float z = 0;
int z_loop = 0;             //variable used for the z-axis motor rotation
int r_loop = 0;             //variable used for the turntable motor rotation
float measured_analog = 0;  //Analog read from the distance sensor
float analog = 0;           //Analog MEAN 
float RADIANS = 0.0;        //Angle in radians. We calculate this value later in Setup loop
int steps_z_height = 0;     //Variable used for the amount of steps in z-axis


void setup() {
  Serial.begin(9600);
  pinMode(A3, INPUT);  
  pinMode(dir_z, OUTPUT);
  pinMode(step_z, OUTPUT);
  pinMode(enable_z, OUTPUT);
  pinMode(dir_r, OUTPUT);
  pinMode(step_r, OUTPUT);
  pinMode(enable_r, OUTPUT);
  digitalWrite(enable_z,HIGH);//disable the z_azis driver
  digitalWrite(enable_r,HIGH);//disable the z_azis driver

  //Calculate variables
  RADIANS = (3.141592 / 180.0) * (360/steps_per_rotation_for_motor);
  steps_z_height = (z_layer_height * steps_per_rotation_for_motor * lead_screw_rotations_per_cm)/10;
}

void loop() {

   if(z < z_axis_height)
  {     
    for(int loop_cont = 0 ; loop_cont < steps_per_rotation_for_motor; loop_cont++)
    {
      //getDistance();
      digitalWrite(enable_r,LOW);   //enable the turntable driver
      digitalWrite(dir_r,LOW);      //turntable spin to right
      digitalWrite(step_r,HIGH);   //make a step
      delay(5);
      delayMicroseconds(step_delay);
      digitalWrite(step_r,LOW);
      delay(5);
      delayMicroseconds(step_delay);
      angle = angle + RADIANS;      
      
    }
    angle = 0;  //Reset the angle value for next rotation
    
    /*My threaded rod needs 8 full rotations for 1cm. A full rotation is 200 steps in my case.
    We need 1600 for 1cm. So, we need 80 for 0.5mm. The amount is calulated automaically.
    Just change the variables at the beginning if you want*/
    while(z_loop < steps_z_height) 
    {      
    digitalWrite(enable_z,LOW);     //enable the z_azis driver
    digitalWrite(dir_z,LOW);        //z_azis spin to right
    digitalWrite(step_z,HIGH);      //z_azis make a step
    delayMicroseconds(step_delay);
    digitalWrite(step_z,LOW);
    delayMicroseconds(step_delay);
    z_loop = z_loop+1;              //Increase the loop by 1
    }
    z = z + z_layer_height;         //Increase the made z-height by 1 unit
    z_loop = 0;                     //Reset the z-axis rotation variable

//}//end of if z_height  



}

double getDistance();

  for (int aa=0; aa < scan_amount; aa++)
  {
    measured_analog= analogRead(A3);
    delay(2);
    analog = analog + measured_analog;    
  }
  distancia = analog/scan_amount;       
  analog=0;
  measured_analog = 0; 
  distancia = map(distancia,0.0,1023.0,0.0,3.3);
  distancia = -5.40274*pow(distancia,3)+28.4823*pow(distancia,2)-49.7115*distancia+31.3444; 
  distancia = distance_to_center - distancia;  
  
  y =  (sin(angle) * distancia);  
  x =  (cos(angle) * distancia);
  Serial.print(y); Serial.print(","); 
  Serial.print(x); Serial.print(","); 
  Serial.println(z); Serial.print("");
 // Serial.println(distancia); 
 Serial.println(angle);
//  Serial.println(" cm  "); 
  delay(500);  

}
//Function that maps the value in a float format
float map(float fval, float val_in_min, float val_in_max, float val_out_min, float val_out_max)
{
  return (fval - val_in_min) * (val_out_max - val_out_min) / (val_in_max - val_in_min) + val_out_min;
}

map() no funciona con números de tipo float--> Solo con int. necesitas escribir tu propia función de map()

double mapf(double x, double in_min, double in_max, double out_min, double out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

distancia = mapf(distancia,0,1023,0.0,3.3);

Muchas gracias por tu aporte, ya modifique eso en la programación aunque al momento de pasar los datos de los ejes (X,Y,Z) al programa Meshlab aun no me realiza de forma correcta la nube de puntos del objeto que estoy escaneando.

No soy muy buena programando pero creo que puede ser por esta ecuación del código

distancia = -5.40274pow(distancia,3)+28.4823pow(distancia,2)-49.7115*distancia+31.3444;

"arruinaste" el código en la primera publicación ...

debe mantener un name diferente para la función map () solo para asegurarse de que no se llame a la función incorporada

de donde viene la formula ?

el código lo estoy tomando de este tutorial, según eso la formula viene de la hoja de datos del sensor aunque yo la verdad la revise y esa formula no la veo.

Aparentemente todo en el código me funciona y eme arroja valores en el monitor serie pero al momento de pasar esos valores a Meshlab no me realiza la nube de puntos como debería

http://electronoobs.com/eng_arduino_tut30.php

imprime y, x, z, angle (en ese orden)

  Serial.print(y); Serial.print(",");
  Serial.print(x); Serial.print(",");
  Serial.println(z); Serial.print("");
  // Serial.println(distancia);
  Serial.println(angle);

en el tutorial el archivo que genera es x, y, z

Me va arrojando esos valores

parece que el ángulo es siempre 0, entonces sinus es 0, entonces y es 0

Si correcto, ese es el problema que el ángulo no debería ser 0 y no se como solucionarlo no soy muy experta programando

cambiar la impresión para que sea

  Serial.print(y); Serial.print("\t");
  Serial.print(x); Serial.print("\t");
  Serial.println(z); Serial.print("\t");
  Serial.print(angle);Serial.print("\t");
  Serial.println(distancia);

Me muestra estos valores en el monitor, Y y Angulo me sigue arrojando 0

publica tu código completo

codigo_escaner.ino (5,3 KB)

eso es porque

    angle = 0;  //Reset the angle value for next rotation

prueba con este código

/*ELECTRONOOBS 3D scanner using IR sensor SHARP GP2Y0A51SK0F;
  Datasheet GP2Y0A51SK0F: https://www.pololu.com/file/0J845/GP2Y0A41SK0F.pdf.pdf
  Tutorial: http://www.electronoobs.com/eng_arduino_tut30.php
  YouTube Channel: https://www.youtube.com/channel/UCjiVhIvGmRZixSzupD0sS9Q
  SUBSCRIBE!

  Schematic: http://www.electronoobs.com/eng_arduino_tut30_sch1.php
*/

#include <SPI.h>

//Editable variables
int scan_amount = 40;                   //Amaunt of scans for each point. The result is the mean. This would increase the delay for each scan.
int z_axis_height = 1200; //in cm         //Maximum height of the scaned file
int step_delay = 3000; //in us          //Delay for each step for the stepper motor in microseconds
float z_layer_height = 0.1; //in mm     //Layer height. The amount of mm for each layer.
int lead_screw_rotations_per_cm = 8;    //How many rotations needs the lead screw to make in order to make 1cm.
int steps_per_rotation_for_motor = 50; //Steps that the motor needs for a full rotation.
int distance_to_center = 9;             //In cm. Distance from sensor to the turntable center in cm

//I/O
//Turntable driver pins
int dir_r = 7;
int step_r = 8;
int enable_r = 9;
//Z-axis driver pins
int dir_z = 5;
int step_z = 3;
int enable_z = 6;

int scan_changed = 0;       //Scan process was changed
float distancia = 0;         //Measured distance
float angle = 0;            //Rotation angle for each loop (0º-360º)
float x = 0;                //X, Y and Z coordinate
float y = 0;
float z = 0;
int z_loop = 0;             //variable used for the z-axis motor rotation
int r_loop = 0;             //variable used for the turntable motor rotation
float measured_analog = 0;  //Analog read from the distance sensor
float analog = 0;           //Analog MEAN
float RADIANS = 0.0;        //Angle in radians. We calculate this value later in Setup loop
int steps_z_height = 0;     //Variable used for the amount of steps in z-axis

// Function that maps the value in a float format
double mapf(double x, double in_min, double in_max, double out_min, double out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

void setup() {
  Serial.begin(9600);
  pinMode(A3, INPUT);
  pinMode(dir_z, OUTPUT);
  pinMode(step_z, OUTPUT);
  pinMode(enable_z, OUTPUT);
  pinMode(dir_r, OUTPUT);
  pinMode(step_r, OUTPUT);
  pinMode(enable_r, OUTPUT);
  digitalWrite(enable_z, HIGH); //disable the z_azis driver
  digitalWrite(enable_r, HIGH); //disable the z_azis driver

  //Calculate variables
  RADIANS = (3.141592 / 180.0) * (360.0 / steps_per_rotation_for_motor);
  steps_z_height = (z_layer_height * steps_per_rotation_for_motor * lead_screw_rotations_per_cm) / 10.0;
}

void loop() {

  if (z < z_axis_height)
  {
    angle = 0;  //Reset the angle value
    analog = 0; //reset the andlog read total value
    measured_analog = 0; //reset the andlog read value

    for (int loop_cont = 0 ; loop_cont < steps_per_rotation_for_motor; loop_cont++)
    {

      digitalWrite(enable_r, LOW);  //enable the turntable driver
      digitalWrite(dir_r, LOW);     //turntable spin to right
      digitalWrite(step_r, HIGH);  //make a step
      delay(5);
      delayMicroseconds(step_delay);
      digitalWrite(step_r, LOW);
      delay(5);
      delayMicroseconds(step_delay);
      angle = angle + RADIANS;      //Increase the angle by one more unit
    }

    /*My threaded rod needs 8 full rotations for 1cm. A full rotation is 200 steps in my case.
      We need 1600 for 1cm. So, we need 80 for 0.5mm. The amount is calulated automaically.
      Just change the variables at the beginning if you want*/
    while (z_loop < steps_z_height)
    {
      digitalWrite(enable_z, LOW);    //enable the z_azis driver
      digitalWrite(dir_z, LOW);       //z_azis spin to right
      digitalWrite(step_z, HIGH);     //z_azis make a step
      delayMicroseconds(step_delay);
      digitalWrite(step_z, LOW);
      delayMicroseconds(step_delay);
      z_loop = z_loop + 1;            //Increase the loop by 1
    }
    z = z + z_layer_height;         //Increase the made z-height by 1 unit
    z_loop = 0;                     //Reset the z-axis rotation variable

    //}//end of if z_height

    //We finished the scan, we stop the drivers
    //else
    //{
    //  digitalWrite(enable_z,HIGH);
    //  digitalWrite(enable_r,HIGH);
    //}

  }//End ov void loop

  double getDistance();

  for (int aa = 0; aa < scan_amount; aa++)
  {
    measured_analog = analogRead(A3);
    delay(2);
    analog = analog + measured_analog;
  }
  distancia = analog / scan_amount;      //Get the mean. Divide the scan by the amount of scans.

  distancia = mapf(distancia, 0.0, 1023.0, 0.0, 3.3); //Convert analog pin reading to voltage
  distancia = -5.40274 * pow(distancia, 3) + 28.4823 * pow(distancia, 2) - 49.7115 * distancia + 31.3444; //From datasheet
  distancia = distance_to_center - distancia;  //the distance d = distance from sensor to center - measured distance

  y =  (sin(angle) * distancia);
  x =  (cos(angle) * distancia);

  Serial.print(y); Serial.print("\t");
  Serial.print(x); Serial.print("\t");
  Serial.print(z); Serial.print("\t");
  Serial.print(angle); Serial.print("\t");
  Serial.println(distancia);
  delay(500);
}

pero tienes algo realmente extraño con double getDistance();...
No estoy seguro de por qué eliminó la definición de la función

con el código que me acabas de enviar, Y me sigue arrojando en 0 y ángulo siempre me da el mismo valor (6.28)

-->

??

Como te dije al principio, la verdad no soy muy buena programando entiendo que esa función es como para hallar la distancia del sensor al objeto

Un problema esta acá

double getDistance() ;

debe ser

double getDistance() {

Y tambien debes sacar el comentario que tienes en el for inicial del loop
Te dejo todo aca, aunque

int scan_amount       = 40;                   //Amaunt of scans for each point. The result is the mean. This would increase the delay for each scan.
int z_axis_height     = 1200; //in cm         //Maximum height of the scaned file
int step_delay        = 3000; //in us          //Delay for each step for the stepper motor in microseconds
float z_layer_height  = 0.5; //in mm     //Layer height. The amount of mm for each layer.
int lead_screw_rotations_per_cm = 8;    //How many rotations needs the lead screw to make in order to make 1cm.
int steps_per_rotation_for_motor = 50; //Steps that the motor needs for a full rotation.
int distance_to_center = 9;             //In cm. Distance from sensor to the turntable center in cm

//I/O
//Turntable driver pins
int dir_r       = 7;
int step_r      = 8;
int enable_r    = 9;
//Z-axis driver pins
int dir_z       = 5;
int step_z      = 3;
int enable_z    = 6;

int scan_changed = 0;       //Scan process was changed

float angle       = 0;            //Rotation angle for each loop (0º-360º)
float x           = 0;                //X, Y and Z coordinate
float y           = 0;
float z           = 0;
int z_loop        = 0;             //variable used for the z-axis motor rotation
int r_loop        = 0;             //variable used for the turntable motor rotation
int measured_analog = 0;  //Analog read from the distance sensor
long analog       = 0;           //Analog MEAN
float distancia   = 0;         //Measured distance
float RADIANS     = 0.0;        //Angle in radians. We calculate this value later in Setup loop
int steps_z_height = 0;     //Variable used for the amount of steps in z-axis


void setup() {
  Serial.begin(9600);
  pinMode(A3, INPUT);
  pinMode(dir_z, OUTPUT);
  pinMode(step_z, OUTPUT);
  pinMode(enable_z, OUTPUT);
  pinMode(dir_r, OUTPUT);
  pinMode(step_r, OUTPUT);
  pinMode(enable_r, OUTPUT);
  digitalWrite(enable_z, HIGH); //disable the z_azis driver
  digitalWrite(enable_r, HIGH); //disable the z_azis driver

  //Calculate variables
  RADIANS = (3.141592 / 180.0) * (360 / steps_per_rotation_for_motor);
  steps_z_height = (z_layer_height * steps_per_rotation_for_motor * lead_screw_rotations_per_cm) / 10;
}

void loop() {

  if (z < z_axis_height) {
      for (int loop_cont = 0 ; loop_cont < steps_per_rotation_for_motor; loop_cont++)   {
        getDistance();
        digitalWrite(enable_r, LOW);  //enable the turntable driver
        digitalWrite(dir_r, LOW);     //turntable spin to right
        digitalWrite(step_r, HIGH);  //make a step
        delay(5);
        delayMicroseconds(step_delay);
        digitalWrite(step_r, LOW);
        delay(5);
        delayMicroseconds(step_delay);
        angle += RADIANS;
      }
      angle = 0;  //Reset the angle value for next rotation
  
      /*My threaded rod needs 8 full rotations for 1cm. A full rotation is 200 steps in my case.
        We need 1600 for 1cm. So, we need 80 for 0.5mm. The amount is calulated automaically.
        Just change the variables at the beginning if you want*/
      while (z_loop < steps_z_height)  {
        digitalWrite(enable_z, LOW);    //enable the z_azis driver
        digitalWrite(dir_z, LOW);       //z_azis spin to right
        digitalWrite(step_z, HIGH);     //z_azis make a step
        delayMicroseconds(step_delay);
        digitalWrite(step_z, LOW);
        delayMicroseconds(step_delay);
        z_loop = z_loop + 1;            //Increase the loop by 1
      }
      z = z + z_layer_height;         //Increase the made z-height by 1 unit
      z_loop = 0;                     //Reset the z-axis rotation variable
  
      //}//end of if z_height
  }
}

double getDistance() {
  for (int aa = 0; aa < scan_amount; aa++)   {
       analog += analogRead(A3);
       delay(2);
  }
  distancia = analog / scan_amount;
  analog = 0;
  distancia = mapf(distancia, 0.0, 1023.0, 0.0, 3.3);
  distancia = -5.40274 * pow(distancia, 3) + 28.4823 * pow(distancia, 2) - 49.7115 * distancia + 31.3444;
  distancia = distance_to_center - distancia;

  y =  (sin(angle) * distancia);
  x =  (cos(angle) * distancia);
  Serial.print(y); 
  Serial.print(",");
  Serial.print(x); 
  Serial.print(",");
  Serial.println(z); 
  Serial.print("");
  // Serial.println(distancia);
  Serial.println(angle);
  //  Serial.println(" cm  ");
  delay(500);
}

//Function that maps the value in a float format
float mapf(float fval, float val_in_min, float val_in_max, float val_out_min, float val_out_max) {
  return (fval - val_in_min) * (val_out_max - val_out_min) / (val_in_max - val_in_min) + val_out_min;
}

14:54:55.770 -> 1.96,-1.08,29.50
14:54:55.770 -> 2.08
14:54:56.387 -> 1.74,-1.26,29.50
14:54:56.387 -> 2.20
14:54:56.972 -> 1.54,-1.43,29.50
14:54:57.007 -> 2.32
14:54:57.589 -> 1.44,-1.71,29.50
14:54:57.589 -> 2.44
14:54:58.204 -> 1.45,-2.24,29.50
14:54:58.204 -> 2.57
14:54:58.818 -> 1.04,-2.13,29.50
14:54:58.818 -> 2.69

Supongo que debo de cambiar en la función map( ) de numero tipo float a tipo double como me lo indicaste desde el principio.

Acabo de correr el último código que me enviaste y el primer motor donde esta este condicional me gira como las manecillas d un reloj mas no hace una rotación completa

Hola @natlia9930
¿Podría explicarme el motivo de estos 2 retrasos seguidos?

      delay(5);
      delayMicroseconds(step_delay);
     ........................................
      delay(5);
      delayMicroseconds(step_delay);

RV mineirin