Tanto per comincare sembra che la batteria stabilizzi un bel pò i valori.
per ora uso 50000 valori per trovare la media, poi lavoro su 1 valore, pensavo di provare la media di 10 o 20 valori.
Comunque dal sito l'atmega impiega circa 100uS per un'analogread, abbassabili a 50 con perdita di precisione (settando il prescaler).
ora sto cercando di limitare l'errore, per ora eliminando i valori che differiscono meno di 1,5 dalla media ottengo un'ottima lettura a gyro fermo (vel. angolare == 0), però non vede per rotazioni molto lente.
il codice attuale, si può notare che ho anche cercato di moltiplicare il tempo per la velocità angolare (come fisica insegna), ma forse anche per il tempo dovrei usare una media (però deve essere calcolata nel loop, altrimenti sarà irreale, dunque i primi valori avranno privi di questo controllo). ma bando alle chiacchere:
piccola cosa divertente: settate l'errore a 0.5, e divertitevi ad avvicinare un dito al gyro senza toccarlo: vedrete i valori errati salire di botto.
già che ci sono vi posto pure la controparte java che legge l'angolo assoluto e disegna un simpatico orizzonte artificiale, necessita un'immagine esterna di supporto di nome "giro.png"
Se volete fare a gara tra il mio codice e il gyro senza modifiche, è semplice: collegate il gyro alla ricevente, sia il bianco-rosso-nero che il giallo.
poi inserite nel bianco che va al servo un cavo che finirà in un pin digitale dell'arduino. settate il canale sul giallo fichè non si accende la luce fissa (AVC mode) a questo punto basta un pulsein() per ottenere un valore, che diviso per 4000, nel mio caso, dà l'angolo in radianti necessario alla funzione calcola() (l'ultima in basso, in pratica orizon=-numero/40000; diventa orizon=-numero/4000;)
ATTENZIONE: alimentare l'arduino e la ricevente con lo stesso Voltaggio
la banda del buco ringrazia per la gentile attenzione
per ora uso 50000 valori per trovare la media, poi lavoro su 1 valore, pensavo di provare la media di 10 o 20 valori.
Comunque dal sito l'atmega impiega circa 100uS per un'analogread, abbassabili a 50 con perdita di precisione (settando il prescaler).
ora sto cercando di limitare l'errore, per ora eliminando i valori che differiscono meno di 1,5 dalla media ottengo un'ottima lettura a gyro fermo (vel. angolare == 0), però non vede per rotazioni molto lente.
il codice attuale, si può notare che ho anche cercato di moltiplicare il tempo per la velocità angolare (come fisica insegna), ma forse anche per il tempo dovrei usare una media (però deve essere calcolata nel loop, altrimenti sarà irreale, dunque i primi valori avranno privi di questo controllo). ma bando alle chiacchere:
codice:
void setup() { analogReference(EXTERNAL); Serial.begin(57600); Serial.println("Pronto!"); calibrazione(); } int sensorPin = 0; //pin analogico da cui leggere il dato int sensorValue; long valueReaded=0; float media; long CALIBRATIONDELAY = 50000; unsigned long time; void calibrazione(){ long sommaMedia=0; long i; for (i=0;i<CALIBRATIONDELAY;i++){ sensorValue = analogRead(sensorPin); valueReaded++; sommaMedia += sensorValue; //Serial.print("Ultima lettura:"); // Serial.println(sensorValue); } media = (float)sommaMedia/(float)valueReaded; //digitalWrite(13, LOW); valueReaded=0; Serial.print("Mid:"); Serial.println(media, 10); Serial.print("Last value:"); Serial.println(sensorValue, 10); time = micros(); } float tempDiff, diff=0; long mediaControllo=0; long error=0; unsigned long oldTime; void loop() { sensorValue = analogRead(sensorPin); valueReaded++; tempDiff= ((float)sensorValue)-media; if ( abs(tempDiff)<1.5 ){ tempDiff=0; //Serial.println("Zero"); }else{ // Serial.print("Angular rotation:"); // Serial.println(tempDiff); //Serial.print("Error read: "); //Serial.println(sensorValue); error++; } oldTime=time; time = micros(); diff+= tempDiff;//*(time-oldTime); mediaControllo += sensorValue; if (valueReaded % 1000==0){ // Serial.print("Absolute angle: "); Serial.println(diff, 10); Serial.print("Last read: "); Serial.println(sensorValue); Serial.print("Last timediff: "); Serial.println((time-oldTime)); Serial.print("Errors on 1000 read: "); Serial.println(error); error=0; Serial.print("mid: "); Serial.println(media, 10); if (valueReaded >= CALIBRATIONDELAY){ float tempMedia = (float)mediaControllo/(float)(valueReaded); Serial.print("mid on last "); Serial.print(valueReaded); Serial.print(" read: "); Serial.println(tempMedia, 10); mediaControllo=0; valueReaded=0; //if (abs(media-tempMedia)<0.2 || abs(tempMedia-media)<0.2) //media = tempMedia; } } }
già che ci sono vi posto pure la controparte java che legge l'angolo assoluto e disegna un simpatico orizzonte artificiale, necessita un'immagine esterna di supporto di nome "giro.png"
Se volete fare a gara tra il mio codice e il gyro senza modifiche, è semplice: collegate il gyro alla ricevente, sia il bianco-rosso-nero che il giallo.
poi inserite nel bianco che va al servo un cavo che finirà in un pin digitale dell'arduino. settate il canale sul giallo fichè non si accende la luce fissa (AVC mode) a questo punto basta un pulsein() per ottenere un valore, che diviso per 4000, nel mio caso, dà l'angolo in radianti necessario alla funzione calcola() (l'ultima in basso, in pratica orizon=-numero/40000; diventa orizon=-numero/4000;)
ATTENZIONE: alimentare l'arduino e la ricevente con lo stesso Voltaggio
codice:
import gnu.io.CommPort; import gnu.io.CommPortIdentifier; import gnu.io.SerialPort; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Enumeration; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextField; public class test_stringa extends JFrame{ /** * */ private static final long serialVersionUID = 1L; double orizon =0; Image image; //contains the image to modify Graphics2D g2d; //used to modify the image JTextField orizonText; public static void main ( String[] args ) { boolean portFound = false; String defaultPort; // determine the name of the serial port on several operating systems String osname = System.getProperty("os.name","").toLowerCase(); if ( osname.startsWith("windows") ) { // windows defaultPort = "COM1"; } else if (osname.startsWith("linux")) { // linux defaultPort = "/dev/ttyUSB0"; } else if ( osname.startsWith("mac") ) { // mac defaultPort = "????"; } else { System.out.println("Sorry, your operating system is not supported"); return; } if (args.length > 0) { defaultPort = args[0]; } System.out.println("Set default port to "+defaultPort); Enumeration<?> portList = CommPortIdentifier.getPortIdentifiers(); CommPortIdentifier portId; while (portList.hasMoreElements()) { portId = (CommPortIdentifier) portList.nextElement(); if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { System.out.println("Serial found port: "+defaultPort); if (portId.getName().equals(defaultPort)) { System.out.println("Found port: "+defaultPort); portFound = true; } } } if (!portFound) { System.out.println("port " + defaultPort + " not found."); System.exit(0); } try{ (new test_stringa()).connect(defaultPort); } catch ( Exception e ) { // TODO Auto-generated catch block e.printStackTrace(); } } void connect ( String portName ) throws Exception { orizonText =new JTextField("orizzonte"); image = Toolkit.getDefaultToolkit().getImage("./giro.png"); BufferedImage bim = new BufferedImage(100,100,BufferedImage.TYPE_INT_ARGB); g2d = (Graphics2D)(bim.createGraphics()); ImageIcon orizzonteIMG = new ImageIcon(bim); JLabel gyro = new JLabel("Gyroscope Only",orizzonteIMG,JLabel.CENTER); add(gyro); //add(orizonText); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(200,200); setVisible(true); System.out.println("do you see frame?"); CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); if ( portIdentifier.isCurrentlyOwned() ) { System.out.println("Error: Port is currently in use"); } else { CommPort commPort = portIdentifier.open(this.getClass().getName(),2000); if ( commPort instanceof SerialPort ) { SerialPort serialPort = (SerialPort) commPort; serialPort.setSerialPortParams(57600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE); InputStream in = serialPort.getInputStream(); //OutputStream out = serialPort.getOutputStream(); leggi(in); } else { System.out.println("Error: Only serial ports are handled by this example."); } } } private double MEDIA = 0; private double diff = 0; private void leggi(InputStream in) { boolean finito=false; double input = 0; long readCount = 0; int calibrateCount = 0; int delay = 200; while (!finito){ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in)); try { while(bufferedReader.ready()){ String inputstring = bufferedReader.readLine(); input = 0; if(!inputstring.isEmpty()){ try{ input = Double.parseDouble(inputstring); System.out.println("Input: "+input); calcola(input); }catch (Exception e){ System.out.println("Input: "+inputstring); } } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private void calcola(double numero) { //numero-=1370; orizon=-numero/40000; g2d.rotate(orizon,50,50); g2d.drawImage(image,0,0,100,100,null); repaint(); g2d.rotate(-orizon,50,50); } }
Commenta