M-Link Sensor mit Arduino

skytor

User
Hallo Thomas ..

nich das du denkst hier liest keiner mehr mit ;-) .... wir warten gespannt auf den Download Link und das Eagle Layout zum nachbauen :D

Gruss aus Lübeck
 
Hallo Thomas ..

nich das du denkst hier liest keiner mehr mit ;-) .... wir warten gespannt auf den Download Link und das Eagle Layout zum nachbauen :D

Gruss aus Lübeck

Hallo,

warte leider immer noch auf die Antwort von Multiplex. Außerdem hatte ich jetzt noch ein kleines Problem:
In letzter Zeit habe ich die Library nur mit mit einem 8Mhz Prozessor genutzt und noch ein paar kleine Anpassungen vorgenommen damit alles mit dem kritischeren Timing bei dieser Frequenz funktioniert. Als ich sie nun wieder auf dem Ardunio Uno mit 16Mhz benutzen wollte ging nichts mehr - ich musste die Timingparameter der NewSoftSerial etwas anpassen. Jetzt weiß ich nicht ob mein Uno eine "Macke" hat, oder die Änderungen im Coding das Timing beeinflusst haben. Muss jetzt mal mit anderen Boards Tests fahren. Ist doch etwas kritisch mit de Sofware Library.

Bezüglich Hardware: Eagle Layout wird es von mir nicht geben - ich arbeite zur Zeit mit Lochraster + Breakout Boards für die Sensoren - reicht für meine Zwecke - in die Fertigung von SMD Platinen möchte ich nicht einsteigen. Für meine Zwecke reicht das - meine Modelle sind groß genug :)

Aber vielleicht hat ja jemand Lust die Schaltung professionell aufzubauen - dann freue ich mich. Der G-Sensor ist von der Beschaltung trivial - aber ich veröffentliche die Schaltung gerne hier.

Der von mir verwendete Sensor (Freescale MMA7341L) ist leider nicht sehr genau (die verschiedenen Achsen haben recht große Differenzen) - und die +/- 11g sind auch nicht sehr üppig. Im Twinstar habe ich locker 6g erreicht....

Bin am überlegen, auf einen Sensor mit digitaler Aufbereitung und SPI/I2C Bus umzusteigen (z.B. Analog Devices ADXL345).



Gruß
Thomas
 
Update

Update

Hallo zusammen,

mittlerweile liegt eine Antwort von Multiplex vor, dass sie keine Bedenken haben, das ich meine MSB Library zu veröffentliche. Sie baten mich nur einen Hinweis auf den Schutz des MSB-Logos einzufügen und die Empfehlung, dass sich Entwickler, die ihre Hard-/Software öffentlich anbieten, bei Multiplex formlos registrieren damit sie immer die aktuelle Spezifikation zugesendet bekommen können.

Ich habe mittlerweile eine rudimentäre Dokumentation fertig. Zunächst stelle ich mir noch eine "Testphase" vor. Wer interessiert ist, kann die Library ab sofort bei mir anfordern - PN genügt.

Noch eine Ergänzung: Ich habe die Library unter die GNU GPL gestellt, weil ich im ersten Schritt nicht möchte, dass auf ihrer Basis "closed Source" Software entwickelt wird. Falls jemand Bedarf daran hat, die Library für ein komerzielles closed-soruce Projekt zu verwenden, finden wir sicher einen Weg ;)

Gruß

Thomas
 
Hallo Thomas,

coole Sache, vielen Dank! Das erleichtert diverse Entwicklungen ungemein ;)

Ich habe da auch noch diverse Dinge vor, was momentan aber noch magels Zeit auf Eis liegt...

Gruß, Alex
 

Tempo

User
Eigenentwicklung: MSB Anzeige am Sender

Eigenentwicklung: MSB Anzeige am Sender

Hallo Freunde,

hier ein Bild der Eigenentwicklung meiner Anzeige im Einsatz.
Die großen Ziffern sind sehr schnell und leicht auch im Augenwinkel zu erfassen, ohne das Modell aus den Augen zu lassen.
Dazu halte ich lediglich meinen Handsender entsprechend zwischen Auge und Modell ;)
Das negativ LCD hat einen angenehm großen Kontrast im Sonnenschein unter großem Blickwinkel.


kleines BildTempoMat1_FernsteuerungundXperience.jpg

Viele Grüße

Tempo
 
Neues von neuer Seite (mir) :P

Neues von neuer Seite (mir) :P

Hallo alle zusammen,
bin auf diesen Thread gestoßen und wollte auch mal meinen Senf dazu geben:
First of all: danke! Dank dieses Threads und einigen anderen Websites habe ich erfolgreich meinen Arduino auf den Sensorbus aufgeschaltet.

Also: Wozu der ganze Spaß: mir sind die MPX sensoren zu teuer und mit Arduino kann man das ganze auchnoch selber individuell konfigurieren.

Wozu das erneute Aufwärmen des Threads? Es hat sich viel getan was Arduinos etc. angeht, va. bzgl. der Programmieroberfläche und libraries.

Falls Fragen zu dem Thema auftreten oder ihr persönliche Hilfe braucht, gern ne PN oder Mail an mich (simon123_1Äweb*de) [das Ä durch ein @ und den Stren duch einen Punkt ersetzen]

Also, zu meinem Projekt:
Ich brauche: ein Vario, einen Höhenmesser und einen Spannungsmonitor für meinen Antriebslipo.
Hardware:
- Arduinoboard (am besten mit nativem iic, >2 digital pins oder alternativ RX/TX pins vom regulären UART Serial, >1 anolog pin und einem 16bit Timer, damit die, für die Sensoren nötigen libraries problemlos laufen.) Ich empfehle konkret einen Arduino nano (für die Einsteiger unter uns) oder pro mini für die Fortgeschrittenen (3.3V evtl für diese Anwendung die Bessere Wahl). Von ATTiny rate ich ab!!!!
- Kleinere Elektrische Bauteile: Wiederstände im niedrigen kOhm bereich für einen Spannungsteiler (falls Spannungsmessung am Antriebsakku gewünscht); NPN Transistor, 10kOhm und Diode für den "halb-duplex - RX-TX wandler"
Klingt alles kompliziert, ist aber ganz einfach:

Zunächst muss uns eines klar sein: Der Empfänger verwendet für die Sensorschnittstelle einen standart UART-Bus, wie ihn auch der Arduino nativ unterstützt (RX/TX). Als Datenrate(Baudrate) verlangt und nutzt der Empfänger 38,4kBit/s alias 38400Baud. Im Gegensatz zum Arduino, der mit seperaten RX und TX Kabeln arbeitet, fallen beim MPX-Sensorbus beide Leitungen zur RX/TX Leitung zusammen (halb duplex). Wir können aber nicht einfach am Arduino beide Leitungen zusammen klemmen und an den Empfänger anschließen. Der TX-Pin am Arduino steht im Idle (nichts wird gesendet) dauerhaft auf logic 1 was bedeutet, er liegt immer bei 3,3 bzw 5 V. Der RX pin kann dementsprechend keine Daten empfangen.
mit folgender Schaltung von http://nerdralph.blogspot.de/2014/01/avr-half-duplex-software-uart.html lässt sich das Problem überwinden:
TX/RX ---+--|>|-----+----- Tx
| $ R1
+--------(/^\)--- Rx
NPN E C
(Besseres Bild auf seiner Website, hier nur falls diese mal offline geht)
(Allen code auf der Website können wir für dieses Projekt ignorieren, va. wenn wir Anfänger sind ;)

TX/RX geht zum Senosor Signal des Empfängers und RX und TX zum Arduino (Nicht vergessen Arduino GND und Empfänger - zu verbinden, sonst entseht kein Stromkreis)

Ist alles verkabelt (ein "solderless breadboard" bietet sich an) kann der erste Test gestartet werden:
Ich verwende einen Arduino mit integrierter USB-Schnittstelle (z.b. UNO oder Nano). Achtung: das native UART wird hier bereits durch den USB Anschluss belegt und kann nicht benutz werden für die Kommunikation mit dem Empfänger!
Stattdessen verwende ich die SoftwareSerial library:

Code:
#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RXpin:Pin 10, TXpin: Pin 11

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(250000);//Serial ist die Verbindung zum PC
  Serial.println("hey");//Im Seriellen Monitor der Arduino IDE sollte hey zu lesen sein. (Bautrate am PC auf das maximum der IDE: 250000)
  mySerial.setTimeout(5);
  mySerial.begin(38400);//mySerial ist die Verbindung zum Empfänger
}

void loop() {
  
  byte b[5];
  long l[5];
  long t=micros();
  while(mySerial.available()>0){mySerial.read();}//wir wollen vor beginn des Tests einen leeren Buffer, wir dumpen seinen Inhalt  
  while(mySerial.available()<1){t=micros();};//wir warten bis vom Empfänger was ankommt. 
  long begintime=micros();//wir speichern die Zeit in Mikro Sekunden (nicht millisekunden)
  b[0]= mySerial.read();//wir lesen das erste byte, das vom Master ankommt und speichern es
  l[0]=t;//wir speichern die Zeit, wann das byte angekommen ist
  t=micros();
  
  for(int i=1;i<5;i++){//das selbe wie oben, blos 4 mal hintereinander (schleife)
    while(mySerial.available()<1){t=micros();};
    l[i]=t;
    b[i]= mySerial.read();
    t=micros();
  }
  long endtime=micros();//wir speichen die Zeit, wenn das letzte byte angekommen ist.
  for(int i=0;i<5;i++){
    Serial.print(b[i],HEX);//wir lassen uns eine Zeile mit den bytes (hexadezimal darstellung) ausgeben, die empfangen wurden
    Serial.print("      ");
  }
  Serial.println();
  Serial.print(0);
  Serial.print("      ");
  for(int i=1;i<5;i++){
    Serial.print(l[i]-l[i-1]);//wir lassen uns eine Zeile mit den zeiten ausgeben, die vergangen sind, bevor das jeweilege byte empfangen wurde
    Serial.print("  ");
  }
  Serial.println();
  Serial.print(l[4]-l[0]);Serial.print("  ");Serial.println(endtime-begintime);//wir lassen uns 2 mal die dauer ausgeben
  delay(2000);//nach 2 Sekunden kommt die nächste Messung
}

Die erste Zeile sind die Anfragen des Masters. Die Adressen, die er anfragt solten von 2 bis f (15) rotieren.
Die zweite Zeile, wieviel zeit jeweils zwischen der vorherigen und dieser Anfrage verstrichen ist. Eigendlich müsste diese Zeit immer ungefär 6ms (=6000micro Sekunden) betragen, bein meinen Tests ergaben sich aber meist Zeiten von etwa 5ms.

Sind weitere Erläuterungen des restlichen Projekts gewünscht?
Hier ist der Code für das Vario (profisorsch)! Wenn Interesse am Projekt besteht (PN bitte) werde ich das ganze gerne noch erläutern.
Für einen Programmierer eine Katastrophe, aber er ist nur zum testen und wird noch optimiert:

Code:
#include <SoftwareSerial.h>
#include <Wire.h>
#include <MS5611.h>

int variobuffer=0;
int variocnt=0;
MS5611 ms5611;
boolean dataavail=false;
int vario=0;
int alt=10;
int voltage=0;
int alert=0;
float prfAlt=0;
float TOALT;
long t;
float lastValue=0;

SoftwareSerial mySerial(10, 11); // RX, TX

void setup() {
  analogReference(EXTERNAL);
  mySerial.begin(38400);
  mySerial.setTimeout(5);
  while(!ms5611.begin())
  {
    delay(500);
  }
  ms5611.setOversampling(MS5611_ULTRA_HIGH_RES);
  prfAlt=ms5611.getAltitude(ms5611.readPressure());
  t = micros();
  TOALT=ms5611.getAltitude(ms5611.readPressure());
}

void loop() {
  if(mySerial.available()>0){
    int red=mySerial.read();
    if(red==0x5A){
      TOALT=prfAlt;
    }else if(red==0x03){
      delayMicroseconds(1500);
      if(mySerial.available()>0){
        while(mySerial.available()>0){mySerial.read();}
      }else{
        if(dataavail){
          if(variocnt==5){
            vario+=variobuffer;
            vario=vario/variocnt;
            mySerial.write(0x33);
            mySerial.write(lowByte(vario*2+alert));
            mySerial.write(highByte(vario*2+alert));
            vario=0;
            variobuffer=0;
            variocnt=0;
          }else{
            vario+=variobuffer;
            variocnt++;
          }
        }else{
          mySerial.write(0x33);
          mySerial.write(lowByte(0x8000));
          mySerial.write(highByte(0x8000));
        }
      }
    }else if(red==0x04){
      delayMicroseconds(1500);
      if(mySerial.available()>0){
        while(mySerial.available()>0){mySerial.read();}
      }else{
        if(dataavail){
          mySerial.write(0x48);
          mySerial.write(lowByte(alt*2+alert));
          mySerial.write(highByte(alt*2+alert));
        }else{
          mySerial.write(0x48);
          mySerial.write(lowByte(0x8000));
          mySerial.write(highByte(0x8000));
        }
      }
    }else if(red==0x05){
      delayMicroseconds(1500);
      if(mySerial.available()>0){
        while(mySerial.available()>0){mySerial.read();}
      }else{
        if(dataavail){
          mySerial.write(0x51);
          mySerial.write(lowByte(voltage*2+alert));
          mySerial.write(highByte(voltage*2+alert));
          dataavail=false;
        }else{
          mySerial.write(0x51);
          mySerial.write(lowByte(0x8000));
          mySerial.write(highByte(0x8000));
        }
        updatedata();
      }
    }
  }
}

void updatedata(){
  voltage=(int)(0.5F+(analogRead(A0)/1024.0F)*66.0F);
  long realPressure = ms5611.readPressure();
  float absoluteAltitude = ms5611.getAltitude(realPressure);
  float vspeed=(1000000*(absoluteAltitude-prfAlt)/(micros()-t));// avg in m/s
  t=micros();
  prfAlt=absoluteAltitude;
  alt=(prfAlt-TOALT)+0.5F;//
  if((vspeed<0&&lastValue<0&&vspeed<lastValue*0.3F)||(vspeed>0&&lastValue>0&&vspeed>lastValue*0.3F)){
    passVario(vspeed);
  }else{
    passVario((vspeed+lastValue)/2.0F);
  }
  lastValue=vspeed;
  dataavail=true;
}

void passVario(float value){
  if(value>0){
    variobuffer=0.5F+value*10;
  }else{    
    variobuffer=value*10-0.5F;
  }
}
 

kalle123

User
Hallo simon 123,

Du kennst aber schon folgendes Projekt:

https://github.com/openXsensor/openXsensor

Das kann alles Beschriebene, auch MSB, und hat einen fertigen sehr gut funktionierenden Vario-Algorithmus.

Viele Grüße
Jörn

Verwende ich schon länger ... ;)

Vario (mit MS5611 und BMP xxx), Strom (ACS 712 und 758), Spannung, Drehzahl und GPS (U-Blox).

Mit MPX RX und HFMG-3 Modul auf Taranis .... Unterstützt aber auch FRSKY, HOTT, JETI!

Gruß KH
 
Kannte ich nicht, aber ich mache das hautsächlich zum persönlichen Vergnügen und deshalb will ich das alles selber schreiben, konzipieren und zusammenbasteln.
Von daher bleib ich bei meiner Lösung;) Danke trotzdem!

(und mein Vario-Algorithmus schafft übrigens inzwischen auch ne 0er Auflösung von +-5cm pro sekunde;)

Neuer Code:
Code:
#include <Wire.h>
#include <MS5611.h>

//minimum update delays in ms (0=each cycle)
const int updateATemp=1000;
const int updateAlt=1000;
const int updateVario=300;
const int updateVoltage=100;
const int voltagearraylength=60;

MS5611 ms5611;

boolean iicavail; //false: 0x8000 /2 und alert=false!;

long lastATempMeasurement;
//boolean aTempavail;
int ambientTemprature; // 0,1 °C

long lastAltMeasurement;
float takeoffAlt;
//boolean altavail;
int alt; //Meter

long lastVarioMeasurement;
long varioTime;
float varioPreviousAlt;
float varioLastValue;
//boolean varioavail;
int vario; // 0,1 Meter/sekunde

long lastVoltageMeasurement;
long lastvalert;
int valert;
float voltvalues[voltagearraylength];
int voltindex=0;
//boolean voltageavail;
boolean voltagealert;
int voltage;

void setup() {
  pinMode(LED_BUILTIN,OUTPUT);
  digitalWrite(LED_BUILTIN,HIGH);
  
  iicavail=true;
  //aTempavail=false;
  //altavail=false;
  //varioavail=false;
  //voltageavail=false;

  varioLastValue=0.0F;
  lastATempMeasurement=-updateATemp;
  lastAltMeasurement=-updateAlt;
  lastVarioMeasurement=-updateVario;
  lastVoltageMeasurement=-updateVoltage;

  ambientTemprature=0x8000/2;
  vario=0x8000/2;
  alt=0x8000/2;
  
  pinMode(3,INPUT_PULLUP);
  analogReference(EXTERNAL);
  
  Serial.begin(38400);
  Serial.setTimeout(5);
  
  if(digitalRead(3)==LOW){
    iicavail=false;
    //aTempavail=true;
    //altavail=true;
    //varioavail=true;
    digitalWrite(LED_BUILTIN,LOW);
    delay(300);
    digitalWrite(LED_BUILTIN,HIGH);
    delay(300);
    digitalWrite(LED_BUILTIN,LOW);
    delay(300);
    digitalWrite(LED_BUILTIN,HIGH);
    delay(300);
    digitalWrite(LED_BUILTIN,LOW);
    delay(300);
    digitalWrite(LED_BUILTIN,HIGH);
    delay(300);
  }else{
    while(!ms5611.begin())
    {
      delay(500);
    }
    ms5611.setOversampling(MS5611_ULTRA_HIGH_RES);
    varioPreviousAlt=ms5611.getAltitude(ms5611.readPressure());
    varioTime = micros();
    takeoffAlt=(
      ms5611.getAltitude(ms5611.readPressure()) +
      ms5611.getAltitude(ms5611.readPressure()) +
      ms5611.getAltitude(ms5611.readPressure())
      )/3.0F;
  }
  digitalWrite(LED_BUILTIN,LOW);
}

void loop() {
  if(Serial.available()>0){
    int red=Serial.read();
    delayMicroseconds(1500);
    if(Serial.available()>0){
      while(Serial.available()>0){Serial.read();}
    }else{
      switch (red) {
        case 0x02:
          //if(aTempavail){
            Serial.write(0x26);
            Serial.write(lowByte(ambientTemprature*2));
            Serial.write(highByte(ambientTemprature*2));
            //aTempavail=false;
          //}
          break;
        case 0x03:
          //if(varioavail){
            Serial.write(0x33);
            Serial.write(lowByte(vario*2));
            Serial.write(highByte(vario*2));
            //varioavail=false;
          //}
          break;
        case 0x04:
          //if(altavail){
            Serial.write(0x48);
            Serial.write(lowByte(alt*2));
            Serial.write(highByte(alt*2));
            //altavail=false;
          //}
          break;    
        case 0x05:
          //if(voltageavail){
            Serial.write(0x51);
            Serial.write(lowByte(voltage*2+voltagealert));
            Serial.write(highByte(voltage*2+voltagealert));
            //voltageavail=false;
            
          //}
          break;      
      }
    }
  }
  updateData();
}

void updateData(){
  long mill=millis();
  if((mill-lastVoltageMeasurement)>updateVoltage){
    float v=(analogRead(A0)/1024.0F)*66.0F;
    voltage=(int)(0.5F+v);
    lastVoltageMeasurement=mill;/*
    voltvalues[voltindex]=v;
    voltindex++;
    if(voltindex>=voltagearraylength){voltindex=0;}
    //Voltageavail=true;
    if(v<3.45F){
      valert=500; 
    }else if(v<3.65F){
      valert=4*1000;  
    }else if(v<3.8F){
      boolean b=true;
      for(int i=0;i<voltagearraylength;i++){
        if(voltvalues[i]>(v-0.7)&&voltvalues[i]<(v+0.7)){b=false;}
      }
      if(b){
        valert=7*1000;
      }else{
        valert=0;
      }
    }else{
      valert=0;
    }
    if(voltagealert){
      if((millis()-lastvalert)>valert){
        voltagealert=false;
        lastvalert=millis();
      }
    }else{
      if((millis()-lastvalert)>300){
        voltagealert=true;
        lastvalert=millis();
      }
    }*/
  }
  if(iicavail){
    if((mill-lastATempMeasurement)>updateATemp){
      ambientTemprature=10.0F*ms5611.readTemperature();
      //aTempavail=true;
      lastATempMeasurement=mill;
    }
    boolean updateAltduringVario=false;
    if((mill-lastAltMeasurement)>updateAlt){
      //alt=(ms5611.getAltitude(ms5611.readPressure())-takeoffAlt)+0.5F;
      //Altavail=true;
      updateAltduringVario=true;
    }
    if((mill-lastVarioMeasurement)>updateVario){
      float absoluteAltitude = ms5611.getAltitude(ms5611.readPressure());
      absoluteAltitude += ms5611.getAltitude(ms5611.readPressure());
      absoluteAltitude += ms5611.getAltitude(ms5611.readPressure());
      absoluteAltitude += ms5611.getAltitude(ms5611.readPressure());
      absoluteAltitude += ms5611.getAltitude(ms5611.readPressure());
      absoluteAltitude += ms5611.getAltitude(ms5611.readPressure());
      absoluteAltitude += ms5611.getAltitude(ms5611.readPressure());
      absoluteAltitude += ms5611.getAltitude(ms5611.readPressure());
      absoluteAltitude += ms5611.getAltitude(ms5611.readPressure());
      absoluteAltitude += ms5611.getAltitude(ms5611.readPressure());
      absoluteAltitude = absoluteAltitude/10.0F;
      passVario(1000*(absoluteAltitude-varioPreviousAlt)/(mill-varioTime));
      varioPreviousAlt=absoluteAltitude;
      varioTime=mill;
      if(updateAltduringVario){
        alt=varioPreviousAlt-takeoffAlt+0.5F;
        
      lastAltMeasurement=mill;
      }
      lastVarioMeasurement=mill;
      //Serial.println(vario);
      //Varioavail=true;
    }
  }
}

void passVario(float value){
  int vspeed;
  if(value>0){
    vspeed=0.5F+value*10;
  }else{    
    vspeed=value*10-0.5F;
  }
  if(((vspeed<0&&varioLastValue<0&&vspeed<varioLastValue*0.3F)||(vspeed>0&&varioLastValue>0&&vspeed>varioLastValue*0.3F))&&(vspeed>3||vspeed<-3)){
    vario=vspeed;
  }else{
    vario=(vspeed+varioLastValue)/2.0F;
  }
  varioLastValue=vspeed
  
  
  
  
  ;
}
 
Ansicht hell / dunkel umschalten
Oben Unten