Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Un sistema de autonivelado diferente
#1
Sistema de autonivelado diferente parecido a un mechero de coche.
Echadle un vistazo, es curioso: http://igg.me/at/bltouch/x/12322242.
Citar
#2
gracias parece interesante, aver si no es muy complicado
saludos
Citar
#3
Ese sistema tiene buena pinta, pero requiere llevar un electroimán que hay que alimentar, y puede pesar como un servo, con los mismos problemas de inercia.

Yo tengo un sistema estrictamente mecánico que no requiere servo ni electroimán. A ver si mañana lo puedo grabar funcionando y lo cuelgo en alguna parte.
Citar
#4
lo prometido es deuda, y ya he grabado cómo funciona mi autolevel:

resim
Citar
#5
Muy interesante, sacamantecas. Podrías poner información sobre como funciona y como has hecho el sistema de autonivelado? Gracias
Citar
#6
En el gráfico de abajo hay una radiografía del artilugio: a izquierda en posición de reposo, y a la derecha en posición de medición:


.jpg   bolaa.jpg (Tamaño: 11.24 KB / Descargas: 741)

La cosa gris claro que hay a la derecha es una rueda de presión con un muelle (no se ve en el dibujo) que suele estar escondida en los viejos ratones de bola:


.png   radiografia.PNG (Tamaño: 42.61 KB / Descargas: 745)

Si te interesa el despiece, lo tienes en https://www.youmagine.com/designs/endsto...-autolevel

El artilugio es una pieza de artesanía fina, casi de joyería. Hay que hacerlo varias veces para que llegue a funcionar bien, mejorando los sistemas de pegado (loctite+bicarbonato), ajuste y colocación de alambres (son trozos de clip)... pero el resultado final es fabuloso.

El cacharro está ajustado a la décima de milímetro a mi impresora, que es única, pero al menos la idea queda ahí.

Suerte con ello
Citar
#7
Ok. Entendido perfectamente. Me pondré a adaptar las piezas para mi impresora. Me podrías indicar como has codificado el inicio de impresión para que el carro se mueva al final del eje x y comience a hacer la calibración?
Citar
#8
Muy ingenioso ese sistema sin duda Sacamanetas.

Los movimientos los introduces S118 con GCODES antes del G28 y G29 imagino.
Citar
#9
Imagino que sí, que será con GCODES. Por favor sacamantecas, podrías indicar cual es el código GCODE?. También podrías indicar como tengo que indicar a marlin (o es también GCODE) que tome la nivelación en los distintos puntos de la cama?.
Y por último, otra pregunta: cuándo marlin recibe la nivelación de la cama en los distintos puntos de muestreo, que hace, toma la media de los puntos o se hace un plano con estos puntos y conforma su propia horizontal, que en caso de que la cama esté perfectamente nivelada, coincidirá con la cama, y si no, pues no coincide y toda las capas de la pieza a imprimir te las hace paralela al plano imaginario detectado por los puntos de muestreo? No se si me he explicado bien.
Gracias.
Citar
#10
Gestionar el sistema mio es parecido al sistema del SLED (trineo) que incorpora Marlin al menos desde la versión de agosto.
En donde están programados G29, G31 y G32 he hecho algunos cambios (marcados con MAKA_SONDA_Z):

[spoiler]
Código:
#ifdef ENABLE_AUTO_BED_LEVELING
    case 29: // G29 Detailed Z-Probe, probes the bed at 3 or more points.
        {
            #if Z_MIN_PIN == -1
            #error "You must have a Z_MIN endstop in order to enable Auto Bed Leveling feature!!! Z_MIN_PIN must point to a valid hardware pin."
            #endif

            // Prevent user from running a G29 without first homing in X and Y
            if (! (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) )
            {
                LCD_MESSAGEPGM(MSG_POSITION_UNKNOWN);
                SERIAL_ECHO_START;
                SERIAL_ECHOLNPGM(MSG_POSITION_UNKNOWN);
                break; // abort G29, since we don't know where we are
            }

#ifdef Z_PROBE_SLED
            dock_sled(false);
#elif defined(MAKA_SONDA_Z)
            maka_sonda(true);
#endif // Z_PROBE_SLED
            st_synchronize();
            // make sure the bed_level_rotation_matrix is identity or the planner will get it incorectly
            //vector_3 corrected_position = plan_get_position_mm();
            //corrected_position.debug("position before G29");
            plan_bed_level_matrix.set_to_identity();
            vector_3 uncorrected_position = plan_get_position();
            //uncorrected_position.debug("position durring G29");
            current_position[X_AXIS] = uncorrected_position.x;
            current_position[Y_AXIS] = uncorrected_position.y;
            current_position[Z_AXIS] = uncorrected_position.z;
            plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
            setup_for_endstop_move();

            feedrate = homing_feedrate[Z_AXIS];
            
#ifdef AUTO_BED_LEVELING_GRID
            // probe at the points of a lattice grid

            int xGridSpacing = (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION) / (AUTO_BED_LEVELING_GRID_POINTS-1);
            int yGridSpacing = (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION) / (AUTO_BED_LEVELING_GRID_POINTS-1);


            // solve the plane equation ax + by + d = z
            // A is the matrix with rows [x y 1] for all the probed points
            // B is the vector of the Z positions
            // the normal vector to the plane is formed by the coefficients of the plane equation in the standard form, which is Vx*x+Vy*y+Vz*z+d = 0
            // so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z

            // "A" matrix of the linear system of equations
            double eqnAMatrix[AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS*3];
            // "B" vector of Z points
            double eqnBVector[AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS];


            int probePointCounter = 0;
            bool zig = true;

            for (int yProbe=FRONT_PROBE_BED_POSITION; yProbe <= BACK_PROBE_BED_POSITION; yProbe += yGridSpacing)
            {
              int xProbe, xInc;
              if (zig)
              {
                xProbe = LEFT_PROBE_BED_POSITION;
                //xEnd = RIGHT_PROBE_BED_POSITION;
                xInc = xGridSpacing;
                zig = false;
              } else // zag
              {
                xProbe = RIGHT_PROBE_BED_POSITION;
                //xEnd = LEFT_PROBE_BED_POSITION;
                xInc = -xGridSpacing;
                zig = true;
              }

              for (int xCount=0; xCount < AUTO_BED_LEVELING_GRID_POINTS; xCount++)
              {
                float z_before;
                if (probePointCounter == 0)
                {
                  // raise before probing
                  z_before = Z_RAISE_BEFORE_PROBING;
                } else
                {
                  // raise extruder
                  z_before = current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS;
                }

                float measured_z = probe_pt(xProbe, yProbe, z_before);

                eqnBVector[probePointCounter] = measured_z;

                eqnAMatrix[probePointCounter + 0*AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS] = xProbe;
                eqnAMatrix[probePointCounter + 1*AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS] = yProbe;
                eqnAMatrix[probePointCounter + 2*AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS] = 1;
                probePointCounter++;
                xProbe += xInc;
              }
            }
            clean_up_after_endstop_move();

            // solve lsq problem
            double *plane_equation_coefficients = qr_solve(AUTO_BED_LEVELING_GRID_POINTS*AUTO_BED_LEVELING_GRID_POINTS, 3, eqnAMatrix, eqnBVector);

            SERIAL_PROTOCOLPGM("Eqn coefficients: a: ");
            SERIAL_PROTOCOL(plane_equation_coefficients[0]);
            SERIAL_PROTOCOLPGM(" b: ");
            SERIAL_PROTOCOL(plane_equation_coefficients[1]);
            SERIAL_PROTOCOLPGM(" d: ");
            SERIAL_PROTOCOLLN(plane_equation_coefficients[2]);

            #ifdef MAKA_SONDA_Z
                // poner ahora la sonda en su sitio, porque la bed_level_equation puede llegar a adulterar el cálculo de X hasta el punto de afectar a su manipulación
                maka_sonda(false);
                st_synchronize();
            #endif

            set_bed_level_equation_lsq(plane_equation_coefficients);

            free(plane_equation_coefficients);

#else // AUTO_BED_LEVELING_GRID not defined

            // Probe at 3 arbitrary points

            // probe 1
            float z_at_pt_2, z_at_pt_3, z_at_pt_1 = probe_pt(ABL_PROBE_PT_1_X, ABL_PROBE_PT_1_Y, Z_RAISE_BEFORE_PROBING);

            // probe 2
            float z_at_pt_2 = probe_pt(ABL_PROBE_PT_2_X, ABL_PROBE_PT_2_Y, current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS);

            // probe 3
            float z_at_pt_3 = probe_pt(ABL_PROBE_PT_3_X, ABL_PROBE_PT_3_Y, current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS);

            clean_up_after_endstop_move();

            #ifdef MAKA_SONDA_Z
                // poner ahora la sonda en su sitio, porque la bed_level_equation puede llegar a adulterar el cálculo de X hasta el punto de afectar a su manipulación
                maka_sonda(false);
                st_synchronize();
            #endif
            
            set_bed_level_equation_3pts(z_at_pt_1, z_at_pt_2, z_at_pt_3);


#endif // AUTO_BED_LEVELING_GRID
            st_synchronize();

            // The following code correct the Z height difference from z-probe position and hotend tip position.
            // The Z height on homing is measured by Z-Probe, but the probe is quite far from the hotend.
            // When the bed is uneven, this height must be corrected.
            real_z = float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS];  //get the real Z (since the auto bed leveling is already correcting the plane)
            x_tmp = current_position[X_AXIS] + X_PROBE_OFFSET_FROM_EXTRUDER;
            y_tmp = current_position[Y_AXIS] + Y_PROBE_OFFSET_FROM_EXTRUDER;
            z_tmp = current_position[Z_AXIS];

            apply_rotation_xyz(plan_bed_level_matrix, x_tmp, y_tmp, z_tmp);         //Apply the correction sending the probe offset
            current_position[Z_AXIS] = z_tmp - real_z + current_position[Z_AXIS];   //The difference is added to current position and sent to planner.
            plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
#ifdef Z_PROBE_SLED
            dock_sled(true, -SLED_DOCKING_OFFSET); // correct for over travel.
#endif // Z_PROBE_SLED

        }
        break;
#ifndef Z_PROBE_SLED && !defined(MAKA_SONDA_Z)
    case 30: // G30 Single Z Probe
        {
            engage_z_probe(); // Engage Z Servo endstop if available
            st_synchronize();
            // TODO: make sure the bed_level_rotation_matrix is identity or the planner will get set incorectly
            setup_for_endstop_move();

            feedrate = homing_feedrate[Z_AXIS];

            run_z_probe();
            SERIAL_PROTOCOLPGM(MSG_BED);
            SERIAL_PROTOCOLPGM(" X: ");
            SERIAL_PROTOCOL(current_position[X_AXIS]);
            SERIAL_PROTOCOLPGM(" Y: ");
            SERIAL_PROTOCOL(current_position[Y_AXIS]);
            SERIAL_PROTOCOLPGM(" Z: ");
            SERIAL_PROTOCOL(current_position[Z_AXIS]);
            SERIAL_PROTOCOLPGM("\n");

            clean_up_after_endstop_move();
            retract_z_probe(); // Retract Z Servo endstop if available
        }
        break;
#else
    case 31: // dock the sled
        #ifdef MAKA_SONDA_Z
            maka_sonda(false);
        #else
            dock_sled(true);
        #endif
        break;
    case 32: // undock the sled
        #ifdef MAKA_SONDA_Z
            maka_sonda(true);
        #else
            dock_sled(false);
        #endif
        break;
#endif // Z_PROBE_SLED && !defined(MAKA_SONDA_Z)
#endif // ENABLE_AUTO_BED_LEVELING
[/spoiler]

Ahora falta la rutina maka_sonda() que se encarga de meter y sacar la sonda:

[spoiler]
Código:
#ifdef MAKA_SONDA_Z
void maka_sonda(boolean sacar) {
    if (axis_known_position[X_AXIS]) {
        float xlento = homing_feedrate[X_AXIS]/90;
        if (sacar) { // ya se puede planificar el movimiento horizontal
            if ( current_position[Z_AXIS] < Z_RAISE_BEFORE_PROBING ) {
                plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]=Z_RAISE_BEFORE_PROBING, current_position[E_AXIS], max_feedrate[Z_AXIS], active_extruder);
                st_synchronize(); }

            plan_buffer_line(MAKA_SONDA_Z_SACA_COGER, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder);
            plan_buffer_line(MAKA_SONDA_Z_SACA_DESDE, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], xlento, active_extruder);
            plan_buffer_line(current_position[X_AXIS]=MAKA_SONDA_Z_SACA_HASTA, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder);
            plan_buffer_line(MAKA_SONDA_Z_SACA_SUELTA, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder);
            plan_buffer_line(current_position[X_AXIS] = MAKA_SONDA_Z_METE_DESDE, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], xlento, active_extruder);
            // ya no hace falta esperar un st_synchronize();
        } else {
            if (current_position[X_AXIS] > MAKA_SONDA_Z_METE_DESDE)
                plan_buffer_line(MAKA_SONDA_Z_METE_DESDE, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder);
            plan_buffer_line(MAKA_SONDA_Z_METE_DESDE, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], max_feedrate[X_AXIS], active_extruder);
            plan_buffer_line(current_position[X_AXIS] = MAKA_SONDA_Z_METE_HASTA, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], xlento, active_extruder);
            // no hace falta un st_synchronize();
        }
    } else {
        // avisar de que no es viable
       LCD_MESSAGEPGM(MSG_POSITION_UNKNOWN);
       SERIAL_ECHO_START;
       SERIAL_ECHOLNPGM(MSG_POSITION_UNKNOWN);
    }
}
#endif
[/spoiler]

Y acabamos definiendo unas constantes al Configuration.ini para ajustar perfectamente los movimientos:

[spoiler]
Código:
    #define    MAKA_SONDA_Z
    #define    MAKA_SONDA_Z_SACA_COGER        X_MAX_POS
    #define    MAKA_SONDA_Z_SACA_DESDE        MAKA_SONDA_Z_SACA_COGER + 2.5
    #define    MAKA_SONDA_Z_SACA_HASTA        MAKA_SONDA_Z_SACA_DESDE - 11.5
    #define    MAKA_SONDA_Z_SACA_SUELTA    MAKA_SONDA_Z_SACA_HASTA + 1
    #define    MAKA_SONDA_Z_METE_DESDE        MAKA_SONDA_Z_SACA_COGER - 14
    #define    MAKA_SONDA_Z_METE_HASTA        MAKA_SONDA_Z_METE_DESDE + 11
[/spoiler]

Para el autolevel, Marlin calcula la ecuación del plano de la cama. Ese cálculo puede hacerlo con 3 puntos enumerados con ABL_PROBE_PT_?_? o bien con una matriz de AUTO_BED_LEVELING_GRID_POINTS puntos de lado. Una vez calculada la ecuación, la usa en cada movimiento para cambiar los ejes de referencia y fabricar la pieza perfectamente perpendicular al plano de la cama.

Este sistema presupone que la cama está razonablemente horizontal. Si la cama forma un ángulo de 90º es evidente que no funcionaría. Con un ángulo de 45º el borde de la boquilla iría rascando la capa anterior y tampoco sería viable. Con un ángulo de 2º seguramente no habría problemas en piezas pequeñas, pero en una pieza grande de 100mm de altura tendríamos una desviación en el eje X de 3,5mm que podría llegar a dar problemas

Se puede modificar Marlin para cuantificar ese "razonablemente horizontal" que comentaba, y que aborte cuando rebase un límite.
Citar
#11
A ver que os parece lo que voy a proponer, a ver si simplifica un poco el sistema. Resulta que teniendo la cama paralela al eje X (cosa relativamente sencilla de hacer), pienso que solo sería necesario tomar un punto, p.e. el centro de la cama. De esta manera no haría falta imprimir en planos "inclinados" y las impresiones serían más rápidas, pues en cada capa no tendríamos movimientos del eje z, solo x e y.
No se si esto supone un ahorro en el tema de la configuración de marlin, pero creo que para mi impresora voy a hacerlo así, si es que se puede. Qué pensáis?
Citar
#12
Imprimir en un plano inclinado no es más lento, porque los movimientos de Z en este caso son simultáneos a los de X e Y (no es como cuando el extrusor pasa de una zona de la pieza a otra, que hace un levantamiento con X e Y quietos).

Al hacer el autlevel con la impresora conectada al PC, te va diciendo el Z que encuentra en cada punto de test. Con esos datos es muy fácil nivelar la cama y trabajar en horizontal. Por eso es importante conservar la posibilidad de ejecutar un G29. Pero si ya sabes que la cama es horizontal, no necesitas incluir el G29 en la inicialización. Pero entonces necesitarás tener bien configurado otro endstop para ejecutar el G28.

Yo tengo un endstop de Z de emergencia para que en caso de fallo del principal, la máquina no siga bajando hasta auto-destruirse, pero no está calibrado (de hecho... ni tengo medios para calibrarlo)
Citar
#13
Creo que tienes razón. Muchas gracias.
Citar


Temas similares...
Tema Autor Respuestas Vistas Último mensaje
  DUDA Extrusor sistema bowden se mueve pero no va Inderlard 1 236 08-04-2019, 02:47 PM
Último mensaje: Simemart
  Sistema de 3 motores eje z lambite 5 2,235 14-12-2015, 03:25 PM
Último mensaje: lambite