Balanza electromagnética

Hola,de nuevo por acá con mis problemas.
Como ya he comentado antes, soy docente y siempre ando tratando de hacer cosas novedosas en el aula para que los chicos se entusiasmen, esta vez he preparado una serie de experiencias con magnetismo, entre esas pruebas esta una balanza electromagnética, algo bien simple


Como puede verse, esta basada en un electroiman al que se le varía la tensión, en este caso de 0 a 28.5 v cuando la tensión es suficiente puede vencer la fuerza de la masa que se coloca en el platillo.
Hice una serie de pesadas para ver que tipo de función seguía

Hace una función cuadrática Y= Ax^2+Bx+C tal como se ve en la figura.
Bien quiero hacer una balanza digital usando arduino, hice el siguiente código (que no anda)

//balanza electromagnética
const int analogInPin = A5;  // Analog input pin that the potentiometer is attached to
const int buttonPin = 2;     // the number of the pushbutton pin
int buttonState = 0;
float sensorValue = 0.000;        // value read from the pot
float outputValue = 0.000;        // value output to the PWM (analog out)
int contadorPalanca = 0;
void setup() {
   // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
  pinMode(buttonPin, INPUT);     
}

void loop(){
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  if (buttonState == LOW && contadorPalanca == 0) {     
    // read the analog in value:
  sensorValue = analogRead(analogInPin/1024)*2.550/1000;// V           
  //map it to the range of the analog out:0
  outputValue = map(sensorValue, 0,2.55 , 0, 28.5);
float gramos = ((0.03200* (pow(outputValue,2))+(-0.05899*(outputValue))+(-0.71320)))*1.35582;// función Ax^2+Bx+C

  Serial.print("gr = " );                       
  //Serial.println(outputValue);    
  Serial.println(gramos);
  contadorPalanca = 1;
  } 
 else 
{
  if(buttonState == HIGH) 
  contadorPalanca = 0;
}
}

El problema esta en la conversión del valor que recibo en la entrada analógica, como no le puedo poner los 28.5 v que me da la fuente, hice un divisor de tensión que entrega en A5 de 0 a 2.55V
He probado que largue por serial SensorValue, que me debería dar entre esos valores de 0 a 2.55, ni cerca
Tampoco el comando map me va bien
Favor ayuda.
Si a alguno le interesa el trabajo con los imanes esta acá Diez pruebas con magnetismo – Espacio de Cesar
Saludos

sensorValue = analogRead(analogInPin/1024)*2.550/1000;// V

Esto debería ser:

sensorValue = analogRead**(analogInPin)/1024***2.550/1000;// V

analogPin/1024=0 => te devuelve el valor de 0 :stuck_out_tongue:

que interesante !!! muy buena idea!!

prueba lo que comenta ondo, en principio ese problema esta clarisimo, si despues sigue sin funcionar avisa y seguimos mirando.

por cierto, mides el voltaje cuando se produce la atracción de la varilla por el iman? lo digo porque no seria mejor darle un voltaje alto para que el iman y la varilla esten pegadas, y despues disminuir el voltaje progresivamente hasta que se despegue la varilla. si pones un pulsador o barrera optica puedes hacer que el arduino detecte cuando se ha producido el desacoplo y te de los resultados.
aunque mirando el codigo igual ya haces esto con el buttonPin 2,no?

Apenas llegue a casa pruebo, estoy en el trabajo, muchas gracias OndO.
Sergegsx, se puede hacer al revés darle mas tensión y ver cuando despega, lo que he notado es que una vez que se pega uno puede bajar bastante mas la tensión de la que necesitó para pegarlo, al estar mas cerca la barra del electroiman la atracción es mayor.
Ya comentaré los resultados

Muy interesante CesarCarlos. Seguire tu blog

Gracias flico.
Parece que no, hay alguna otra cosa mal
He puesto tal como me indicas

 sensorValue = analogRead(analogInPin)/1024*2.55/1000;// V 
Serial.println(sensorValue);

me da 0.00
sin embargo si hago

 sensorValue = analogRead(analogInPin);// V 
Serial.println(sensorValue);

ahi si me da valores coherentes y se modifican cuando aumento la tensión, hay algo mal en la sintaxis esa

separa las operaciones que quieres hacer con paréntesis, te aseguras que el compilador va a hacer lo que quieres.

está bien el esperimento, pero (si he entendido bién) veo que estas comparando una función cuadrática con una lineal, esta claro que cuando esté pegado al ser la distancia menor cuanto mayor sea la tension que aplicas mayor será la fuerza.

yo pondría un muelle, la fuerza es proporcional a la distancia, sin embargo una masa no.

quizás me equivoque a estas horas ya no soy persona, y hace mucho que di el tema este y quizás no sea este el objetivo que buscas.

un saludo

He intentado eso Don Gato, de separar con parentesis, pero hay algo que no cierra.
Lo de la función cuadratica esta en el código

float gramos = ((0.03200* (pow(outputValue,2))+(-0.05899*(outputValue))+(-0.71320)))*1.35582;// función Ax^2+Bx+C

Ya veré de crear otra variable y ahí poner las operaciones

C y las operaciones con decimales... siempre es un coñazo. Para que un resultado sea de coma flotante, todos los operandos deben ser coma flotante, así que me imagino que tendrás que hacer un cast al analogRead()

((float)analogRead(analogInPin))/1024*2.55/1000;

si el cast explícito este no te va (a veces el compilador se queja o no le da la gana de hacerlo), prueba a hacerlo implícito así:

float gramos;

gramos=analogRead(); // Forzamos a que el compilador exprese el numero como float.
gramos = gramos *2.55/1024/1000;

A mi esto me solía ir bastante bien cuando tenía estos problemas :stuck_out_tongue:

Hola,
abundando en lo que comenta OndO, cuando escribes "1024" 0 "1000" en esa línea estás pasando unos enteros, prueba poniendo "1024.0" y "1000.0". Ten en cuenta que analogRead()

Returns
int (0 to 1023)

Prueba así:

sensorValue = (float)analogRead(analogInPin)/1024.0*2.55/1000.0 ;

puedes poner algunos numeros experimentales que hayas sacado. es decir valor en el pin analogico y valor que has calculado a mano?

sensorValue = analogRead(analogInPin)/1024*2.55/1000;
si analogRead lee 1000 según tu formula da 2.49x10^-3

se supone que estas haciendo esa formula para convertir el valor leido en el voltaje debido al divisor de tensión,no? yo lo haria asi
sensorValue = analogRead(analogInPin);
float supplyvoltage = map(sensorValue, ... )

porque haces el outputvalue ??

luego con el supplyvoltage calculas el peso

float gramos = ((0.03200* (pow(outputValue,2))+(-0.05899*(outputValue))+(-0.71320)))*1.35582;// función Ax^2+Bx+C

Esta tarde hago las pruebas que me indicaron y comento.
Para Sergegsx los valores experimentales están en la gráfica del primer posteo, la columna X son los voltios de la fuente y la Y son los gramos (hice la prueba agregando monedas previamente pesadas con una balanza de laboratorio)

Un pregunta. Porqué utilizas una tensión tan enrevesada. No sería más sencillo utilizar una tensión de... no se, de 10 Voltios o a caso 20 Voltios. De este modo, se pueden realizar unos cálculos con mayor escalabilidad (creo que, es cuestión de modificar tu palanca para lograr esto).

Considero que, una vez tengas una tensión de 10V, por ej., sin duda te resultará más sencillo tu aproximación (tanto matemática como en programación), al resultado que buscas.

Saludos.

velon:
Porqué utilizas una tensión tan enrevesada.

Que narices es una tensión enrevesada? lo mismo da 10 que 2,55 que 63,592 * PI, sólo es un numero. Al microcontrolador le da igual multiplicar por uno que por otro (a no ser que elijas potencias de dos, que para eso hay "trucos"). 10V no puede ponerlos en el ADC (se carga el Arduino).

Hola, ya estoy pesando, no es lo que esperaba ya que la reproductibilidad es bastante baja, el error es de +/- 0.1 gr pero bue algo es algo.
El código quedó asi con algunas modificaciones bien rústicas propias de quien no sabe programar.
Al comando map() no lo pude hacer funcionar.

//balanza electromagnética
const int analogInPin = A5;  // Analog input pin that the potentiometer is attached to
const int buttonPin = 2;     // the number of the pushbutton pin
int buttonState = 0.00;
float voltios=0.00;
float gramos=0.00;
float sensorValue = 0.000;        // value read from the pot
float outputValue = 0.000;        // value output to the PWM (analog out)
int contadorPalanca = 0;
void setup() {
   // initialize serial communications at 9600 bps:
  Serial.begin(9600); 
  pinMode(buttonPin, INPUT);     
}

void loop(){
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  if (buttonState == LOW && contadorPalanca == 0) {     
  sensorValue = (float)analogRead(analogInPin)/526.00*2.55;// V
  outputValue = sensorValue*11.15015+0.14;
gramos = (0.03200* (pow(outputValue,2.00)))+(-(0.05899*(outputValue)))+(-(0.71320));// función Ax^2+Bx+C

  Serial.print("gr = " );                       
  //Serial.println(outputValue);
    //Serial.println(outputValue);
  Serial.println(gramos);
  contadorPalanca = 1;
  } 
 else 
{
  if(buttonState == HIGH) 
  contadorPalanca = 0;
}
}

Para el amigo que preguntó por las tensiones "raras", es u prototipo se usó lo que hay, un carretel de hilo de coser para el electroiman y la fuente del laboratorio que va de 0 a 28.5V, y tal cual dice OndO, al micro no le importan los números raros, el procesa.
Sergegsx tenías razón había algo mal en esa división por 1000.
Muchas gracias por la ayuda, creo que no hay Karma en este foro no?
Un abrazo

quizas puedas añadir un convertirdor An a dig mas preciso y así mejorar tus resultados. dependiendo de lo que quieras pesar 0.1 tampoco es tanto error y si puedes disminuirlo como te comento pues mejor.
suerte

Creo que mas bien es un problema mecánico, si bien la barra es de hierro dulce, también sospecho que puede quedar algo imantada y la segunda lectura por tanto sea menor a la anterior, de todos modos como ejercicio didáctico va bien.
Gracias de nuevo

CesarCarlos:
Creo que mas bien es un problema mecánico, si bien la barra es de hierro dulce, también sospecho que puede quedar algo imantada y la segunda lectura por tanto sea menor a la anterior, de todos modos como ejercicio didáctico va bien.

Es probable que sea un problema mecánico, pero quizás logras mejorarlo haciendo un buen porrón de muestras y haciendo una media. Parece una chorrada, pero te permite hacer auténticas birguerías (por eso tiene hasta un nombre chulo en inglés "oversampling"). Yo he logrado medir temperaturas a 1ºC de precisión a base de un simple 1N4148 (diodo vulgar y corriente). Otro asunto es que busques una forma de menguar los efectos, o de "reiniciar" los estados por defecto.

EDIT: una opción que se me ocurre es que cambies la varilla ferromagnética por un imán, que debería darte un flujo magnético más estable, y por ende, más repetitividad.

OndO, eso esta muy interesante, soy bastante nulo en programación, lo mio es bastante intuitivo, te comento que el termómetro con el 1N4148 fue lo primero que hice cuando recibí la placa arduino La placa ARDUINO – Espacio de Cesar yo había usado esa sonda, pero de una manera muy precaria hacía tiempo y con arduino logré calibrarla para que me de la lectura directa, anda muy bien, es mas me hice una estufa de cultivos usando como sensor el diodito.
Lo del imán en lugar de la barra, tendría que estudiarlo, no deberían ponerse en contacto físico ambas partes para que luego se despeguen con la sola fuerza del plato...
Comentame un poco los comandos que se usan en el oversampling, gracias OndO por los aportes, siempre que entro a este foro me encuentro con gente que habla mi mismo idioma, aunque soy muy crudo en programación y aca s las saben todas :slight_smile: :slight_smile:
Editado: Creo que no es posible el tomar muchas veces la lectura, el sistema que uso es ir levantando la tensión manualmente, apenas el electroiman tiene la fuerza suficiente para vencer la masa despega el swich y el programa lee, si sigo levantando la tensión no pasa nada, para eso esta la variable
que traba el sckech

int contadorPalanca = 0;

Ayudaría usar un electroiman en forma de herradura????

Teoricamente con la forma de herradura se obtiene un mejor arreglo de las lineas de campo, como en las gruas industriales.