Nån arduino-guru som kan hjälpa? (räkna ner mellan två events)

Permalänk

Nån arduino-guru som kan hjälpa? (räkna ner mellan två events)

Helt novis på arduino, men är säker på att mitt problem kan lösas med just arduino.
Jag har en maskin där en axel kan befinna sig i två lägen, 1 och 2.
1-läget är viloläge, och 2-läget är yttersta läget innan den återgår till läge 1.

En fotocell säger åt maskinen när den ska köra från läge 1 till 2 och sen automatiskt gå tillbaka till läge 1 igen. Detta utförs inom ca 30 sekunder.

Problemet är att maskinen ibland inte lyckas gå hela vägen från läge 1 till 2 och tillbaka, utan helt sonika fastnar några centimeter efter att den startat mot läge 2. (Beror antagligen på motorn, gammal kolborst-motor, helt oberäknelig)

Så, vad jag vill uppnå är att en knapp släpps upp när axeln lämnar läge 1, börjar räkna sekunder, och om knappen inte trycks in igen inom drygt 30 sekunder så skall signal skickas till relä eller siren eller liknande.

Jag är ganska säker på att arduino kan fixa knappen, nerräkningen och signalen till relät, men frågan är hur tusan knåpar jag ihop detta?

Jag började titta på circuits.io och tänkte att man kunde väl svänga ihop något, men icke...

Någon som har en idé var man kan börja titta? Kanske t.o.m färdig kodsnutt och schema för detta?

Visa signatur

-<<Grogga med filmjölk>>-

Permalänk
Medlem

Det absolut bästa sättet om maskinen ska gå mellan två fasta punker är att sätta ett gränsläge där den ska stanna, som säger till datorn nu är det dags att stanna

Visa signatur

.:Cpu:. AMD Ryzen 9 5950x 3.4GHz:. .:Motherbord:. Asus ROG strix X570-I .:Ram:. 32 GB .:SSD M.2 1TB .:Gpu:.ASUS GeForce RTX 2070 SUPER 8GB ROG STRIX GAMING OC 2560 x 1440 (144Hz), .:OS:. Windows 10 Pro 64-bit .:Chassi:. BitFenix Prodigy M .:Skräm:. Main Acer 24" Predator XB241YU Second Viewsonic VX2268wm 120Hz

Permalänk

@DwarF: Mja, inte så enkelt... Maskinen i sig har inget arduino-frågan att göra.
Rent konkret handlar det om följande scenario, beskrivet i otroligt avancerat högnivåspråk
"On releasebutton start counter
if counter greater than 30
then
alarm
else
nothing
"

Visa signatur

-<<Grogga med filmjölk>>-

Permalänk
Medlem

Precis som föregående talare är inne på hade jag använt någon form av limitswitch. Om målet endast är att förflytta något längs hela längden d.v.s från A till B och inte stanna halvvägs där i mellan så borde en limitswitch vara en idé.

Använde själv 2 limitswitchar i mitt senaste arduino projekt (solartracker).

Jag använde 2 vanliga tryck knappar som slår i ett skruvhuvud när de når sitt mål och därmed vänder motorn riktning. För att lösa detta kodmässigt tillsammans med en stegmotor så använder jag mig av små steg och loopar koden flera gånger.

if (bp1 == 1) { Serial.println("The tracker has reached endpoint 1"); myStepper.step(-10240); delay(10); } else if (bp2 == 1) { Serial.println("The tracker has reached endpoint 2"); myStepper.step(10240); delay(10); } else if (avl > avr) { myStepper.step(-15); //Kan behöva vara positivt } else if (avl < avr) { myStepper.step(15); //kan behöva byta riktning }

bp1 och bp2 har tidigare lästs in med digitalRead, om knappen är aktiverad så blir resultat av digitalRead 1. När detta inträffar så körs det som står inom if delen.

Permalänk

Asch, det är jag som inte förklarar tillräckligt vettigt.
Maskinen jag pratar om har ingenting med programmering/arduino att göra.
Maskinen har ett återkommande intermittent problem som jag vill övervaka med en extern enhet, i det här fallet en arduino uno med en tryckknapp.

Så rent krasst har arduino inget med själva styrningen av maskinen att göra.

Tänk så här; jag har en arduino uno med ett 9-volts batteri och tryckknapp inkopplat. (Basic för att fungera antar jag)
Knappen hålls hela tiden intryckt, det är defaultläget.
Men, när knappen släpps upp börjar arduion räkna sekunder, och om knappen inte tryckts in igen inom en given period, te.x. 30 sekunder så träder ett event in, t.ex. att ett relä slår till ett alarm, eller en led blinkar....

Det är så enkelt jag kan förklara...

Visa signatur

-<<Grogga med filmjölk>>-

Permalänk
Testpilot

För att räkna tid mellan två tidpunkter kan du använda funktionen millis, den ger antalet millisekunder som gått sen programmet startade. Du kan alltså först lagra millis i en variabel från när du vill räkna och sen kan du jämföra millis igen mot ditt sparade värde, är skillnaden mer än 30000 millisekunder har det gått för lång tid.

limit = 30000; //30 sekunder starttime = millis(); if(millis() - starttime > limit){ //det har gått 30 sekunder }

Sen får du ju utöka med exempelvis DigitalRead för att läsa in knappen och diverse loopar som väntar på knappen osv. Säg till om du behöver hjälp med den biten med så kan jag säkert slänga ihop nått

Notera även som det står på referens-sidan att millis slår runt (blir 0 igen) efter ca 50 dagar så ska du övervaka din maskin längre än så måste du koda så programmet kan hantera det.

Visa signatur

Kolla gärna in min RGB-LED-ljusstake i galleriet
[Gigabyte GA-Z97MX-Gaming 5][Intel Core i5 4690K][Corsair XMS3 16GB][Asus GeForce RTX 2060 Super Dual Evo OC]

Permalänk
Hedersmedlem

Ett alternativ kan vara att använda inbyggda timers. Vet inte riktigt vilken precision det ger och det kräver lite extra arbete men man undviker problemet med millis

Permalänk
Datavetare

Vet inte om du löst problemet, men i princip behöver du någon form av timer som sätts till 30 sekunder när knappen släpps.

Sedan händer en av två saker

  • knappen trycks in igen, då ska timern stoppas

  • timern löser ut

I båda dessa fall ska något hända.

Man vill inte använda delay() eller liknade då det låser upp huvudloopen, utan man vill ha en asynkron timer som gör vad som behöver göras varje varv i loop()

Nedan borde kunna lösa ditt problem. OBS har inte testat koden på Arduino, bara Googlat att det är OK att använda uint64_t och i fallet nedan används bara 64-bitars heltal när timern sätts (lär vara rätt långsamt att hantera 64-bitars tal på AVR...).

#define SECONDS * (1000ULL) #define MINUTES * (60ULL SECONDS) #define HOURS * (60ULL MINUTES) #define DAYS * (24ULL HOURS) typedef uint64_t duration_t; typedef unsigned long msec_t; static bool inRange(msec_t n, msec_t begin, msec_t end) { bool nAfterBegin = (long) (begin - n) < 0; bool nBeforeOrAtEnd = (long) (end - n) >= 0; return nAfterBegin && nBeforeOrAtEnd; } class OneShotTimer { bool isActive; msec_t lastMillis; msec_t absMillis; msec_t overflowCnt; public: OneShotTimer() : isActive(false) { } void durationSet(duration_t d) { this->lastMillis = millis(); duration_t expirationMsec = d + this->lastMillis; this->absMillis = (msec_t) expirationMsec; this->overflowCnt = (msec_t) (expirationMsec >> 32); this->isActive = true; } void cancel() { this->isActive = false; } bool expired () { bool isExpired = false; if (this->isActive) { msec_t now = millis(); if (inRange (this->absMillis, this->lastMillis, now)) { if (this->overflowCnt == 0) { isExpired = true; cancel(); } else { this->overflowCnt--; } } this->lastMillis = now; } return isExpired; } }; OneShotTimer resetTmr; void setup() { // setup target } void loop() { if (isButtonReleased()) { resetTmr.durationSet(30 SECONDS); } else if (isButtonPressed()) { resetTmr.cancel(); } if (resetTmr.expired()) { // do whatever required when the timer expires } }

Antagandet i ovan är experied() anrops oftare än var 25:e dag (annars blir det overflow i tidsdelta). Det ska inte vara något problem i praktiken då det vettigaste är att anropa expired() varje varv man gör i loop().

Edit: går att sätta längre tider. T.ex.
setDuration(5 HOURS + 10 MINUTES);

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer