#11
 5,111     Sørnorge     0
Husk at arduino ikke har usb. Det er kun et innebygget seriell til usb adapter. Du er begrenset av seriellporten.

Jeg satt en arduino til å lese data fra en gps, og sende rådataene til terminal på pc. Overhode ingenting avansert. Med de vanlige arduinoene ble det så mye å tenke på for arduinoene at det ble fullstendig kaos i dataene som kom til pc'n (buffer overflow både på gps-les og terminal-skriv). På en Due, som har den raskeste cpuen av arduinoene, klarte den stort sett å henge med. Det jeg endte med å gjøre var å kode om gps-modulen for å redusere rådataene til det minimum jeg trengte, og videre lage kode på arduinoen som behandlet rådataene videre slik at det som ble sendt videre til pc var kun det minimum av data jeg trengte, altså i stor grad ferdig prosessert. Hele kluet for å få det til var å minimere antall bytes som trengtes å overføres.
Etter den erfaringen har jeg holdt meg til to modeller: Due fordi den er raskest (og har mest minne), og Micro fordi den er minst i fysiske mål.

Det er fort gjort å lage for mye overhead slik at selv de enkleste data resulterer i overføringsproblemer om man ikke er oppmerksom på at det er en flaskehals her. Forskjellen kan være så liten som at om du leser sensor og skriver til terminal for hver sensor, så får du problemer, mens hvis du leser alle 12 sensorer, pakker det sammen til en melding og skriver til terminal, så har du god margin.

Alt er bare ment som et tips om at, hvis du ikke er oppmerksom på det, kan oppleve at datainnsamlingen din kan se ganske merkelig ut.

  (trådstarter)
   #12
 3,535     0
En viktig grunn til at jeg valgte Leonardo-utgaven var at den har USB. Ikke bare til kommunikasjon; prosessoren kan også drives på 5V fra USB, og trenger ikke selvstendig strømforsyning (så lenge ikke shields krever mer strøm enn det USBen leverer). https://www.arduino.cc/en/Products/Compare påstår at en rekke Arduionoer har USB - ifølge denne tabellen også Due og Micro - men det kan jo være reviderte modeller, nyere enn de du har brukt. (En annen sak er at Leonardo til 9 dollar/stk er en brøkdel av prisen på en Due, rundt 35-40 dollar/stk.)

Data fra en GPS er litt annerledes enn data fra et termometer Smile. Kjørte du da på 9600 bps? I så fall blir jeg ikke det minste forbauset. Jeg har aldri jobbet med GPS, og vet ikke hvordan rådataene ser ut der, men tror gjerne det kan utgjøre mer enn 8-900 bytes/sek!

Du skriver at data bør pakkes til større meldinger. Samtidig virker det som du kjører ren serieport på fysisk lag. Der sendes hver byte uavhengig og asynkront, med start/stop-bit(s) for hver byte. Går linja på full speed sparer du ingen overhead om bytene er levert som en en blokk eller enkeltvis. (Det gjelder også 9600 bps over USB: Det sendes en USB-melding hvert millisekund, og siden det bare kommer én byte fra UARTen ca. hvert ms får du full USB-meldingsoverhead på hver eneste byte - men i USBen har du ingen flaskehals).

Jeg har en ørliten mistanke: De fleste UARTer (om det nå er fysisk hardware eller software-emulering) har bare en byte eller to bufferplass. Skriver du data byte-for-byte raskere enn UARTen får sendt ut på 9600 bps, og du ikke har handshake med UARTen til å holde deg igjen, da overskriver du usendte data i buffer. Gir du UART-driveren en blokk på 100 bytes, vil den "låne" blokka som buffer, og får sendt den i ro og fred mens du er ute og samler inn nye data, uten å skrive noe i denne bufferen. For å unngå ødelagte data kunne du skrevet byte-for-byte, med handshaking med UARTen. Da kunne du ikke gått ut og samlet nye data i mellomtiden; det kan du om du låner bort en buffer (men du burde absolutt sjekke at UARTen er ferdig med bufferen du lånte ut før du fyller inn neste batch med data i den!).

Hvordan koder du GPS-data? Gir GPS-enheten det som ASCII-siffer er en triviell halvering av datavolumet å kode det som BCD. Lager du ditt eget pakkeformat har du da 6 nibble-verdier for bruk til framing på laveste nivå (felt-separator for variabel bredde felt) eller tagging av helt enkle data ("verdi 1" til "verdi 6") hvis verdiene kommer hulter til bulter eller ofte mangler. For ikke-desimale dataverdier fungerer selvsagt ikke BCD, men det er vanlig å spandere en av de seks ubrukte verdiene til desimalkomma for reelle tall. (Har du alltid f.eks. tre siffer etter punktum kan du bare hoppe over kommaet sette det inn på mottakssiden.)

Hvis du på bunnivå, der du har mange verdier, klarer deg med 4 bits/siffer pluss 4 bits/felt, er mye spart. Jeg antar det er på høyere lag du vil redusere protokoll-overhead. Lager du en melding med header og sjekksum for hver byte kan jeg forstå at du tjener på å pakke sammen i større enheter, men det krever noe mer en terminalemulator på PCen! Hva slags format og protokoll bruker du? Neppe full TCP/IP med vindusmekanismer og retransmisjon - da ville du ikke hatt problemer med tapte data! Har noen implementert Kermit for Arduino? (Kermit ville ikke være det verste alternativet!)

Jeg har ikke begynt å kode på Arduinoen enda, men å sette opp en liten løkke for å se hvor mye data jeg klarer å mose gjennom USBen er en helt utmerket hello-world-øving som ikke krever mer, fysisk sett, enn en USB-kabel fra PCen til Leonardoen. Jeg begynner vel der, og vil rapportere hvor høy effektiv hastighet jeg klarer å tvinge gjennom. Når linja går på full speed setter jeg opp en dummy-CPU-load som jeg fyller resten av tiden med, for å se hvor mye ledig CPU-kapasitet jeg har med linja på full guffe, så jeg får sett hvor stor andel av CPUen som går til kommunikasjon, ved ulike hastigheter og teknikker.

Jeg kommer tilbake når jeg har fått kjørt noe i praksis.
   #13
 5,111     Sørnorge     0
At de har usb tilkobling betyr ikke at de har native usb. Som sagt har de seriell-usb adapter innebygget. (Det var arduino-klonene som begynte med dette. Originalen har ganske nylig kopiert kopiene på dette området.)
Og det er også utfordringen om du skal koble til nettverk eller lagring - kommunikasjonen går på seriell grensesnitt. Alternativt kan du bruke I2C, men det er jo ikke akkurat raskt det heller.

Kanskje Yún er bedre på dette. Jeg har ikke sett på den.
  (trådstarter)
   #14
 3,535     0
Aller første test:

Loop ASCIItab-eksempelet, med millis()-kall foran og bak. 4140 tegn sendt ut på 74 ms, stabilt fra gjennomløp til gjenomløp. Det gir effektivt 448 kbps throughput.

Andre test:

For hver loop, kjøre, med millis() foran og bak;

for (int chno = 0; chno < 4096; chno++) { Serial.write(46); }

Surprise! 81-82 ms - lavere effektiv hastighet (404 kbps) uten arbeidet med formattering - men langt flere Serial.write()-kall.

Tredje test:

For hver loop, kjøre, med millis() foran og bak;

for (int chno = 0; chno < 32; chno++) { Serial.write(<128 byte konstant tegnstreng>); }

Litt ustabilt - 16-19 ms, 2048 kbps ned til 1725 kbps. Serial.print() er noe raskere, 15-17 ms pr iterasjon, men det regner jeg som ubetydelig.

Ifølge dokumentasjonen er Serial.write() og Serial.print() ikke-blokkerende, slik at loop() får tilbake kontrollen før all output er fysisk utført. Men det er tydeligvis full flytkontroll internt i biblioteket - jeg har ikke sett en eneste tapt eller korrumpert byte, selv om jeg pøser på med 4096 bytes i en tett loop. For å være på den helt sikre siden la jeg inn en Serial.flush() etter hvert .write()-kall, men det hadde ingen målbar effekt på effektiv overføringshastighet. Så les "non-blocking" som "non-blocking, provided that there is room in in the buffer for all data supplied".

Det spiller ingen rolle hvilken hastighet jeg setter på porten, verken på Arduino-siden eller på PC-siden. USB-driver for begge sider er levert med Arduino-softwaren, så for alt jeg vet kan de kjøre sin egen protokoll med out-of-band flytkontroll. (Det vi kjører av tilsvarende ting på jobben krever at hastigheten settes likt på testkortet og PCen; data sendes ikke hurtigere enn avtalt gjennom bps-settingen.)

Konklusjon: Med effektiv overføringshastighet på 2 Mbps, forutsatt at data er formattert og pakket sammen, er ikke linjehastigheten noen flaskehals for meg. Langt der ifra - den er flere størrelsesordner over hva jeg trenger!

Hvis ikke 2 Mbps holder for GPS-rapporteringen din, da blir jeg forbauset - men i så fall blir jeg ikke forbauset over at du må bruke en modell med såpass kraftig CPU og så mye RAM for å handtere datavolumet. Men jeg mistenker at du kan bruke USB-kretsene i CPUen, selv om du sier du må ha et eksternt USB-adapter. Microen har jo akkurat samme prosessor (type, klokkefrekvens), flash og RAM som Leonardo; det er ingen grunn til at den ikke skal kjøre USB på samme måte. Due-CPUens on-chip USB er spec'et opp til 480 Mbps, og en såpass solid CPU burde klare å mate den med mer enn 2 Mbps også!

Antagelig kunne jeg fin-tune Leonardo (og Micro) til enda høyere hastighet ved å gå ned i biblioteket og skreddersy funksjoner for f.eks. å levere 1kbyte blokker direkte til USB-driveren, men så lenge jeg ikke har behovet, bruker jeg ikke tid på det.





  (trådstarter)
   #15
 3,535     0
Går du fra beskrivelsen av Due til Atmels beskrivelse av SAM3X8E er det helt udiskutabelt at det er ARM M3-brikka som inneholder USB-kontrolleren. Hvis du har en Due med en annen prosessor er det rart at den kalles for Due!

I beskrivelsen på https://www.arduino.cc/en/Main/ArduinoBoardDue er det ganske eksplisitt forklart (ganske langt ned på siden) at den ene av de to USB-kontaktene er koblet til "Native USB", som også er tydelig forklart at er USB-logikken på ARM-brikka.

Det anbefales at man bruker "USB Programming port" for å flashe Arduinoen. I så fall må du jo ha en egen USB for den jobben (eller flytte kabelen rundt), men du kan også bruke "Native port", ifølge dokumentasjonen.

Nå har ihvertfall jeg kjørt 2 Mbsp dataoverføring fra en Arduiono Leonardo til en PC, uten feil, uten eksplisitt flytkontroll, og uten at jeg har sett noe som helst spor av noen serielinjer eller UART. Jeg bruker Serial-biblioteket uten omsvøp, og ser Arduionen som COM4 på PC-siden, uten noen ekstern USB-kontroller og uten annen forbindelse mellom PC og Leonardo (Arduionen drives også på USB-strøm.)

Så kort sagt: Mine behov er godt dekket. Det kan likevel hende at det ikke dekker dine behov.
  (trådstarter)
   #16
 3,535     0
Liten korreksjon:

Jeg skrev et stykke høyere oppe at ATmega32U4-brikken i Leonardo (og Micro) har USB 2.0 på 480 Mbps - det er ikke korrekt. Riktignok er det USB 2.0, men kun Full- og Low-speed (12 og 1,5 Mbps), ikke HighSpeed (480 Mbps). Se http://www.atmel.com/devices/atmega32u4.aspx. 12 Mbps er mer enn nok for mitt bruk uansett!

For uinnvidde: USB 1.x, 2.x og 3.x har ikke mye mer til felles enn navnet og pluggen (og selv pluggen kan jo være ulik med USB 3.x). Selv om brukeren ikke ser det, er det internt stor forskjell på å kjøre USB 1.x Full-speed og USB 2.x Full-speed (og enda større forskjell med 3.x Full-speed!). Det er en fordel å kjøre USB 2.x framfor 1.x, selv om hastigheten er den samme; det gjør f.eks. hub'ens oppgave enklere og kan f.eks. gi lavere forsinkelse.
   #17
 5,111     Sørnorge     0
Jeg forsto heller ikke stort med at kortene hadde problemer med å ta unna gps-dataene. Derfor konkluderte jeg som jeg gjorde, uten å utforske det videre. Etter dine tester tyder det på at flaskehalsen hos meg var noe annet, men jeg har ingen forslag til hva, ettersom reduksjon av dataene som skulle overføres løste problemet. Mulig de sliter hvis man skal lese fra en serieport og skrive til en annen samtidig?

O_K
   #18
 431     0
I fare for å gå altfor mye off topic her så kan jeg si at jeg har hatt tillsvarende problem med arduino og GPS enhet. Hvis jeg ikke får GPS modulen til å sende reduserte datamengder så klarer jeg ikke motta hele NMEA strengen. Det virket som bruddstykker falt ut. Det er en del tråder om utfordringen på div forum.

http://forum.arduino.cc/index.php?topic=277741.0

Jeg løste mitt problem ved å øke bufferen til SoftSerial som beskrevet her:
http://www.hobbytronics.co.uk/arduino-serial-buffer-size

Jeg er litt usikker på hvorfor dette behovet oppstod, men jeg gjorde en del prosessering av dataene, og det er mulig at prosessoren (arduino nano) ikke klarte å holde følge. Jeg lurte litt på å prøve å sette opp noe med inerrupt, men kom aldri så langt før jeg flyttet og måtte bruke tiden min på bygging istedenfor. Snart kommer jeg vel så langt at det skal inn litt elektronikk i huset, og da blir vel gamle kunste tatt opp igjen.
  (trådstarter)
   #19
 3,535     0
Det er vel ikke off-topic - selv om GPS er litt fjernt fra husbygging er mange problemer, som de vi her diskuterer, like relevant for å kommunisere med alarmer og styring og diverse annet.

Jeg er rimelig sikker på at problemet du er borti skyldes mangel på flytkontroll. Da er det Feil Svar å bare øke bufferstørrelse/hastighet for å skjule symptomene. Hvis en GPS-enhet regelmessig sender ut linjer på 80-100 tegn til Arduinoer med 64 tegns buffer, da er GPSen med 99,9% sikkerhet forberedt på å ta imot et signal "Stopp! Vent litt!". Hvis bare Arduinoen sender det...

Hvis du bare har to linjer (RX og TX) mellom Arduino og GPS, må Arduino sende Stopp!-signalet som et tegn, XOFF (0x13). GPSen må, før hvert tegn den sender ut, sjekke om det har kommet inn en XOFF. I så fall går den i en tomgangsløkke, uten å sende mer. Arduinoen sender XOFF når buffer er nesten full. (Ikke helt! Det tar tid å stoppe sending.) GPSen i tomgangsløkka leser om det kommer flere tegn, først når Arduinoen sender en XON (0x11), når den har fått ryddet mer bufferplass, hopper GPSen ut av løkka og fortsetter sending.

Det er noen ulemper med XON/XOFF: Vil du sende vilkårlige binære data, kan det hende at 0x11 og 0x13 forekommer som dataverdier, og de kan stoppe overføringen utilsiktet (man kjører alltid XON/XOFF i begge retninger); det fungerer bare med tekst-data. Dernest: Hvis også GPSens mottaks-buffer er full, og GPSen har bedt Arduino ikke sende mer, hvordan skal den da kunne sende XOFF for å stoppe GPS-dataene? Ting kan låse seg fullstendig! (Det finnes måter å unngå låse-situasjoner, men da må man kjøre stram disiplin!)

Et alternativ er å spandere to ekstra pinner/linjer, en hver veg. Arduino kan sette linja høy, som et Stopp!-signal. GPS sjekker linja før sending av neste tegn; først når den er lav igjen sendes neste tegn. Dette kan gjøres i programvare, akkurat som med XON/XOFF, men finnes det en UART-krets i sender og mottaker, tar disse gjerne styring over linja så du slipper å skrive kode for å teste den. En RS-232-kontakt har egne pinne-par (DTS/DSR, eller RTS/CTS). Slik "hardware flytkontroll" kan brukes med vilkårlige binære data, du risikerer ingen vranglås, det krever mindre programkode, og som regel kan motparten reagere vesentlig raskere.

GPS og Arduino må selvsagt være enige om typen flytkontroll - XON/XOFF, DTS/DSR eller RTS/CTS (så lenge du ikke skal ut på en RS232-kontakt er det ikke stor forskjell mellom de to hardware-alternativene); det må aktiviseres likt på begge sider, begge sider må støtte samme måte.

Det jeg kalte "tomgangsløkke" behøver ikke være så veldig tomt... På en Arduino kan det godt være den ordinære loop(), som i toppen av funksjonen gjør en

. while (<unsent data> && digitalRead(flowControlPin) == LOW) {
. <send another byte>
. }
. <do any other work>

Rett nok: Hvis flowControlPin blir LOW et mikrosekund etter at du leste den, tar det en runde med <do any other work> før du får sendt av gårde neste tegn, men det er vel sjelden vi skriver loop()-kode som tar mer enn en håndfull ms pr runde. (Er det mange tunge steg, kan jo while-løkka over gjentas mellom hvert steg, om det blir kritisk.)

Du kan begynne å styre med avbruddsrutiner etc, men da må du holde tunga i rett munn, som man sier. Særlig hvis loop() og avbruddsrutine deler data - som regel deler de noe - skal du vite hvordan du setter det opp. Har loop() nettopp startet en sammensatt operasjon (f.eks. sette inn et element i ei liste), og så kommer avbruddsrutina og mekker på samme liste, da kan du risikere både at elementer forsvinner og løkker i det som skulle vært ei lineær liste. Det er ikke trivielt å kode slike ting korrekt!

loop()-modellen er tiltrekkende enkel; den unngår de fleste problemer med bare én aktivitet på gang samtidig, én "prosess" (du kan se på en avbruddsrutine som en parallell prosess), med full kontroll på rekkefølgen ting gjøres i. Du må bare legge deg til en kodingsstil der du gjør unna en loop så kjapt at det ikke blir for lenge å vente for noen av aktivitetene. Det kan kreve noen triks hvis det er stor konkurranse om ressursene. (Og du må lære deg varsomhet med delay()!) Som hovedregel vil jeg si at med mindre du har utdannelse i programmering på universitetsnivå er programmering av avbruddsrutiner å bevege seg ut på tynn is. Som regel finnes det langt tryggere måter å løse oppgaven!
   #20
 5,111     Sørnorge     0
GPS'n sender kontinuerlig. Den tar ingen input, ei heller stoppsignal. For min gps var det ikke dokumentert hvor lang streng den sender, ei heller hvordan den endres. Produsenten svarte ikke på henvendelser, og den gang jeg dillet med dette så ingen forumbrukere ut til å kjenne til den. Håper jeg postet i minst ett forum hvordan jeg til slutt løste det, for jeg har glemt det selv. I.o.m at det sendes konstant er ikke avbrudd en brukbar løsning.

Til din kode slipper du imidlertid dette. Du trenger bare en kode som leser av spenning fra hver sensor, og sender til et lagringsmedie - som jeg vil anbefale at er en pc. PC'n må ta imot datastrømmen, legge til tidsstempel og skrive til fil. Jeg ville brukt CSV, ikke database til lagringen. Det vil antagelig være naturlig at arduino sender en byte pr sensor (avlesningen på inngangen er antagelig en byte), og en sjekksumbyte, slik at total meldingslengde er 13byte for 12 sensorer. PC'n bør ta seg av å konvertere byte til tall fortløpende før lagring.
Hvis du f.eks bare vil ha en avlesning pr minutt, bør pc'n ta seg av den filtreringen. Det blir mer nøyaktig enn å la arduino sove. PC'n vil bør da også ta sjekksumsjekk, og er det feil på den meldingen som skal lagres m.t.p riktig tidspunkt, får den bare lagre neste melding i steden.