Lustigt fel på Arduino-krets (Video och kod included)

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Mr Andersson
Inlägg: 1394
Blev medlem: 29 januari 2011, 21:06:30
Ort: Lapplandet

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av Mr Andersson »

Det finns ingen if-tilldelning. Antingen har ni läst fel eller så är koden ändrad i efterhand.
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av Icecap »

Kod: Markera allt

if (s1angle <= s1minAngle || s1angle >= s1maxAngle)
  { // Checks where the 1st servomotor's angle is to drive it the opposite direction
  s1speed = -s1speed;
  }
Denna kod har ett allvarligt problem. Nu har jag inte räknat igenom det aktuella fallet men GENERELLT ger den en allvarlig risk.
Om s1angles1 är 1 över s1minAngle kommer den att subtraherar. Men ingenstans kollas det om värdet s1Angle faktisk har blivit lägre än s1minAngle och i så fall justera det.
Samma gäller såklart med additionsdelen.

Sättet ger alltså problem med out-of-bound och kan ge instabil funktion. Jag har lärt detta den hårda vägen.

Ihop med:

Kod: Markera allt

if (s1angle >= 80)
  {
  digitalWrite(s1LedClosed, LOW);
  digitalWrite(s1LedOpen, HIGH);
  }
if (s1angle <= 10)
  {
  digitalWrite(s1LedOpen, LOW);
  digitalWrite(s1LedClosed, HIGH);
  }
  
kan det ge effekter som inte är genomräknade.

Desutom kan rampningsdelen för addition och subtraktion sammankopplas enkelt. Man väljer bara att det ska adderas ett värde (Direction) och ska den räkna upp gör man:
Direction = s1speed;
Ska den räkna ner blir det:
Direction = -s1speed;

Därmed blir båda delar identiska och kan packas ihop till en enda rutin (för varje RC-servo) som enklare kan underhållas och debuggas.
Användarvisningsbild
teljemo
Inlägg: 1622
Blev medlem: 5 februari 2011, 12:08:13
Ort: Getinge
Kontakt:

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av teljemo »

Först och främst: Hej,
Jag har varit allmänt frånvarande i dagarna. Det känns så dumt när man ställt en fråga och får bra svar men man är inte här och ser det.
Ber om ursäkt. Det har varit hektiska dagar!..

Och så till ämnet :D
Icecap
Menar du att det räcker med att ändra till "==" i dessa jämförelser

Kod: Markera allt

if (s1angle == s1minAngle || s1angle == s1maxAngle) { // Checks where the 1st servomotor's angle is to drive it the opposite direction
      s1speed = -s1speed;
Eller att man ska ha en extra rad kod som gör en kontroll upptill för att se att servon har roterat till korrekt vinkel?

Jag har ändrat till "==" på båda angle jämförelserna samt led delen så att det nu endast ska hända nåt om man är lika med variabeln och inte lika eller under/över.

Dock vet jag inte riktigt hur en sån här servo skickar sin position. Jag läser kanske av den fel, för när jag exempelvis trycker på knappen när den står i 7 grade så ska den gå till 87 grader.
Om jag sätter ett finger i vägen och stoppar servon så säger ändå monitorn att den gått till 87 grader. Alltså är det inte en verklig position utan en förväntad position i programmet??

Senaste revisionen (Bara == som är ändrat i stort sätt)

Kod: Markera allt

/*
  Program made by Emanuel Teljemo in 2020.

  The purpose of the program is to control 2 servo motors that are installed in a ventilation system.
  The servos turn airvalves on and off to focus the air flow from the chosen path.

  TO DO LIST:
  Shut down servos after 5 sec as a saftey measure against overheating
  Add a function to control a relay based on both servos angle state
  Add saftey control function to check servo position after movement
  Shorten code (combine variables)
  Remake button code so it only reads 1 signal and doesnt keeps running servos if button is hold


  WARNING!
  When this code was made I was experimenting so USE AT OWN RISK!


*/
// Setting up servo's
#include <Servo.h>  // Includes a servo file that is already installed with Arduino IDE
Servo s1, s2;  // Creates servo object's

// Defines pins on the arduino board
#define s1Pin 3  // Signal from servo 1
#define s2Pin 5  // Signal from servo 2
#define b1Pin 2 // Signal from pushbutton1
#define b2Pin 4 // Signal from pushbutton2

#define s1LedOpen 8
#define s1LedClosed 9
#define s2LedOpen 10
#define s2LedClosed 11

// Defines variables for servo 1
int s1angle = 7;  // Initial angle for servo 1
int s1speed = 10; // Speed for servo 1 movement
const int s1minAngle = 7;  // Angle of servo 1 arm when vent is closed
const int s1maxAngle = 87; // Angle of servo 1 arm when vent is open

// Defines variables for servo 2
int s2angle = 7;  // Initial angle for servo 2
int s2speed = 10; // Speed for servo 2 movement
const int s2minAngle = 7;  // Angle of servo 2 arm when vent is closed
const int s2maxAngle = 87; // Angle of servo 2 arm when vent is open

// Creates variables for buttons
int b1Pushed = 0;  // Button variable set to 0 before setup
int b2Pushed = 0;  // Button variable set to 0 before setup


// Setup
void setup() {
  // Connections
  Serial.begin(9600); // Serial need to match buad rate. See buad rate in serial monitor

  //Attaching/activating servos
  s1.attach(s1Pin); // Attaches servo 1 on pin 3
  s2.attach(s2Pin); // Attaches servo 2 on pin 5

  // Pinout for LED's
  pinMode(s1LedOpen, OUTPUT);
  pinMode(s1LedClosed, OUTPUT);
  pinMode(s2LedOpen, OUTPUT);
  pinMode(s2LedClosed, OUTPUT);

  Serial.println("*Teljemo's servo controller initiated*"); // Print text in serial monitor

  // Initial movement
  s1.write(s1angle); // Set the initial position for servo 1 (homeing, when mounted it should be open)
  s2.write(s2angle); // Set the initial position for servo 2 (homeing, when mounted it should be open)

  // Print for serial monitor
  Serial.println("Starting angles are: "); // Print text in serial monitor
  Serial.print(s1angle); // Prints angle of servo 1
  Serial.println(" degrees for servo 1"); // Print text in serial monitor
  Serial.print(s2angle); // Prints angle of servo 2
  Serial.println(" degrees for servo 2"); // Print text in serial monitor
  Serial.println("***********************************"); // Print text in serial monitor
}
// End of setup

// Loop
void loop() {
  // Button 1
  if (digitalRead(b1Pin) == LOW) { // Checks if button 1 is pushed down
    b1Pushed = 1; //  Set value to 1 if above is true
  }
  if (b1Pushed) { // Asks if button 1 is pushed
    s1angle = s1angle + s1speed;  // Changes the value of the 1st angle variable

    if (s1angle == s1minAngle || s1angle == s1maxAngle) { // Checks where the 1st servomotor's angle is to drive it the opposite direction
      s1speed = -s1speed;
      b1Pushed = 0; // Tells the program that the 1st button is no longer pushed
    }
    s1.write(s1angle); // Moving the 1st servo to the defined value of s1angle

    Serial.print("Moved servo 1: "); //  Print text in serial monitor
    Serial.print(s1angle);   // Prints angle of servo 1
    Serial.println(" degrees"); //  Print text in serial monitor

    delay(1); // Creates a delay to wait for servo 1 to get in place before looping on
  }

  // Button 2
  if (digitalRead(b2Pin) == LOW) { // Checks if button 2 is pushed down
    b2Pushed = 1; //  Set value to 1 if above is true
  }
  if (b2Pushed) { // Asks if button 2 is true
    s2angle = s2angle + s2speed;  // Changes the value of the angle variable

    if (s2angle == s2minAngle || s2angle == s2maxAngle) { // Checks where the 2nd servomotor's angle is to drive it the opposite direction
      s2speed = -s2speed;
      b2Pushed = 0; // Tells the program that the 2nd button os no longer pushed
    }
    s2.write(s2angle); // Moving the 2nd servo to the defined value of angle

    Serial.print("Moved servo 2: "); // Print text in serial monitor
    Serial.print(s2angle);   // Prints angle of servo 2
    Serial.println(" degrees"); // Print text in serial monitor

    delay(1); // Creates a delay to wait for servo 2 to get in place before looping on
  }

  // LED check
  //Servo 1 LED's
  if (s1angle == 87) {
    digitalWrite(s1LedClosed, LOW);
    digitalWrite(s1LedOpen, HIGH);
  }
  if (s1angle == 7) {
    digitalWrite(s1LedOpen, LOW);
    digitalWrite(s1LedClosed, HIGH);
  }

// Servo 2 LED's
  if (s2angle == 87) {
    digitalWrite(s2LedClosed, LOW);
    digitalWrite(s2LedOpen, HIGH);
  }
  if (s2angle == 7) {
    digitalWrite(s2LedOpen, LOW);
    digitalWrite(s2LedClosed, HIGH);
  }

  //End of loop
}
//  End of program
Jag kan passa på att fråga ang knapp problemet.
Vad är den bästa metoden att implementera i min kod för att inte servorna ska gå konstanta om jag håller in en knapp?
Googlade och hittade andra sätt folk har skrivit just för knappar. Inte alltid "digitalRead" så som ja gjort. Kanske är det fel metod?
Zkronk
Inlägg: 1423
Blev medlem: 23 augusti 2005, 16:44:36
Ort: Uppsala

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av Zkronk »

Du behöver hålla reda på föregående tillstånd på knapparna för att kunna få det beteendet.
Jag tror något i stilen nedan skulle kunna fungera, dock helt otestat..
Hur hanterar du kontaktavstudsning på knapparna? Gör du det i hårdvara eller ska du implementera det i mjukvaran?

Kod: Markera allt

int b1State = HIGH;                                                                 
int b1PrevState = HIGH;                                                             
                                                                                    
void loop() {
    b1State = digitalRead(b1Pin);                                                   
                                                                                    
    if ((b1State != b1PrevState) && (b1State == LOW)) {                                                                               
        s1angle = s1angle + s1speed;  // Changes the value of the 1st angle variable
                                                                                    
        if (s1angle == s1minAngle || s1angle == s1maxAngle) { // Checks where the 1st servomotor's angle is to drive it the opposite direction
          s1speed = -s1speed;
        }                                                                           
        s1.write(s1angle); // Moving the 1st servo to the defined value of s1angle
                                                                                    
        Serial.print("Moved servo 1: "); //  Print text in serial monitor           
        Serial.print(s1angle);   // Prints angle of servo 1                         
        Serial.println(" degrees"); //  Print text in serial monitor                
                                                                                    
        delay(1); // Creates a delay to wait for servo 1 to get in place before looping on
    }                                                                               
                                                                                    
    b1PrevState = b1State;
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av Icecap »

Det finns inget feed-back från servon! Det fungerar vid att den inkommande pulsbredd jämförs med en intern pulsbredd från det interna positionspotentiometer.
Skillnaden driver motorn via en H-brygga.

Så VARJE PULS SOM KOMMER får den närmre positionen den ska vila i.

Om du inte behöver att den byter plats i en viss takt är det bara att skicka ett antal öppna- eller stängda pulser direkt, då kommer servon att köra snabbt.

Och det var även orsaken till att jag skrev tidigare att den rent faktisk ska ha ett antal "slutpulser" när den är i mål, kanske 10 st.
Användarvisningsbild
teljemo
Inlägg: 1622
Blev medlem: 5 februari 2011, 12:08:13
Ort: Getinge
Kontakt:

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av teljemo »

[b skrev:Zkronk[/b] post_id=1583708 time=1609960737 user_id=1387]
Du behöver hålla reda på föregående tillstånd på knapparna för att kunna få det beteendet.
Hur hanterar du kontaktavstudsning på knapparna? Gör du det i hårdvara eller ska du implementera det i mjukvaran?
Tack!
Förändringen till state löser så att servon bara gör en rörelse även om jag håller in knappen.
Dock är rörelsen endast en "puls" på 10 grader eftersom "s1angle = s1angle + s1speed"
(s1speed är satt som 10)
Hur får jag den nu att "pulsa" till max respektive min vinkel är nådd?

Ang kontaktavstudsning har jag satt resistorer på ena sidan av varje knapp. Det var nåt jag läste om i en artikel när jag satte ihop kretsen.
Kan det vara det du menar?
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av Icecap »

Resistorerna är till för att ge tydliga signalnivåer och har inte med avstudsningen att göra.

Avstudsning görs enklast vid att avläsa knapp-porten t.ex. var 10ms.
Man kollar då om den förra avläsningen är lik den nuvarande avläsning, om så är fallet OCH en/fler knapp(ar) är aktiverat är det en legal knapptryckning.

Din loop som räknar upp4ner positionen ska ju först nolla staten (om knappen är släppt) när den har räknat klart.
Användarvisningsbild
manicken
Inlägg: 91
Blev medlem: 10 februari 2006, 14:20:59
Ort: DEGEBERGA

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av manicken »

Det är aldrig bra att använda

Kod: Markera allt

if (s1angle == s1minAngle || s1angle == s1maxAngle)
om den räknar ojämt eller om "check värdet" inte är jämt delbart med s1speed kan man missa värdet och hela if skippas

du borde först få ett servo att fungera som det ska:

i denna kod så borde inte kontaktavstudsning behövas
då det tar tillräckligt med tid för servot att nå slutet ändå.

Kod: Markera allt

s1speed = -s1speed;
eller t.ex.
b1Pushed = !b1Pushed;
kan ibland misstolkas av kompilatorn och inte få det resultat man förväntar sig

det idiotsäkra är:

Kod: Markera allt

s1speed = s1speed*(-1);
eller t.ex.
if (b1Pushed) b1Pushed = 0;
else b1Pushed = 1;
och sen ändra tillbaka till

Kod: Markera allt

if (s1angle <= s1minAngle || s1angle >= s1maxAngle) 
tror att delayt i slutet borde iallafall vara (tänk på att det är millisekunder)

Kod: Markera allt

delay(10);

Kod: Markera allt

// Button 1
  if (digitalRead(b1Pin) == LOW) { // Checks if button 1 is pushed down
    b1Pushed = 1; //  Set value to 1 if above is true
  }
  if (b1Pushed) { // Asks if button 1 is pushed
    s1angle = s1angle + s1speed;  // Changes the value of the 1st angle variable

    if (s1angle <= s1minAngle || s1angle >= s1maxAngle) { // Checks where the 1st servomotor's angle is to drive it the opposite direction
      s1speed = -s1speed;
      b1Pushed = 0; // Tells the program that the 1st button is no longer pushed
    }
    s1.write(s1angle); // Moving the 1st servo to the defined value of s1angle

    Serial.print("Moved servo 1: "); //  Print text in serial monitor
    Serial.print(s1angle);   // Prints angle of servo 1
    Serial.println(" degrees"); //  Print text in serial monitor

    delay(10); // Creates a delay to wait for servo 1 to get in place before looping on
  }
Tänk även på att många skrivningar till Serie porten kan göra att "buffer" blir full och då blir det extra delay i koden.

Taget direkt ifrån källkoden:

Kod: Markera allt

// If the output buffer is full, there's nothing for it other than to 
// wait for the interrupt handler to empty it a bit
det du skulle också kunna göra är att bara skriva till servot i ändlägena:

Kod: Markera allt

int s1countUpDown = 0; // set to -1 when counting down, set to 1 when counting up;
// Button 1
  if (digitalRead(b1Pin) == LOW) { // Checks if button 1 is pushed down
    s1Moving = 1; //  Set value to 1 if above is true
  }
  if (s1Moving ) { // Asks if servo1 need to move
    
    s1angle = s1angle + s1speed * s1countUpDown ;  // Changes the value of the 1st angle variable

    // following checks makes it idiotproof
    if (s1angle < s1minAngle)
    	s1angle = s1minAngle;
    else if (s1angle > s1maxAngle)
    	s1angle = s1maxAngle;
    	
    if (s1angle == s1minAngle)
    {
      s1countUpDown = 1;
      s1.write(s1maxAngle); // Moving the 1st servo to the end
      Serial.print("Movin servo 1 to the max"); //  Print text in serial monitor
      s1Moving = 0;
    }
    else if (s1angle == s1maxAngle)
    {
      s1countUpDown = -1;
      s1.write(s1minAngle); // Moving the 1st servo to the beginning
      Serial.print("Movin servo 1 to the max"); //  Print text in serial monitor
      s1Moving = 0;
    }
    // using s1speed as a factor to this delay
    delay(s1speed); // Creates a delay to wait for servo 1 to get in place before looping on
  }
Användarvisningsbild
mankan
EF Sponsor
Inlägg: 905
Blev medlem: 18 juli 2015, 11:23:22
Ort: Linköping

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av mankan »

En kompilator misstolkar inte saker ibland. Däremot måste man ha koll på datatyperna man använder för att få väntat resultat vid användning av konstruktionerna ovan.
Användarvisningsbild
teljemo
Inlägg: 1622
Blev medlem: 5 februari 2011, 12:08:13
Ort: Getinge
Kontakt:

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av teljemo »

manicken

Jag provade dina exempel men blev väldigt ryckigt. Servon stannade ibland utan att ha gått i ändläge..
Jag måste missat nåt!!
Vill du göra ett komplett "idiotsäkert" exempel så rätt kod hamnar på rätt plats?
Användarvisningsbild
manicken
Inlägg: 91
Blev medlem: 10 februari 2006, 14:20:59
Ort: DEGEBERGA

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av manicken »

Jag glömde att skriva att
Int s1countUpDown=0; är en global variabel

Edit.
Den ska initieras med 1 istället för noll annars fungerar det inte
Användarvisningsbild
Lennart Aspenryd
Tidigare Lasp
Inlägg: 12607
Blev medlem: 1 juli 2011, 19:09:09
Ort: Helsingborg

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av Lennart Aspenryd »

Tack alla. Detta blev väl ett bra exempel på vad Sef kan vara. Jag skall leta upp ett par servon och några Buttons under helgen och köra det hela.
Så mer kommentarer och synpunkter är välkomna.
Att Arduino kan vara en bra plattform, beror ju bl.a. på att så många har den. Och vill dela med sig .
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4689
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av Swech »

Lite tips för att skriva den här typen av program.
Tittar man på det hela så har vi två servo som skall köras till växlande 0° eller 90°när motsvarande knapp trycks in.

Delen i programmet som kör ett servo bör endast fokusera på att köra servot. Vad som startar en körning eller hur detta sker
bör man helt dölja för servot.

Servodelen har 4 states.
1. Stopp i läge 0°, väntar på startsignal
2. Kör mot läge 90°
3. Stopp i läge 90°, väntar på startsignal
4. Kör mot läge 0°

Värden på läge 0° och läge 90°har egentligen inget med själva staten att göra; man kan skriva
1. Stopp i läge x°, väntar på startsignal
2. Kör mot läge y°
3. Stopp i läge y°, väntar på startsignal
4. Kör mot läge x°

Oavsett har vi 4 states
Servorutinen skall alltså ha en state variabel och en motsvarande select case tillståndsmaskin.

Därefter har vi en helt annan del som endast hanterar knapptryckning.
Den delen skall BARA detektera knapptryckning och när detta har gjorts skall en flagga sättas att det är dags att ändra state.
Servodelen läser flaggan och agerar därefter.
Knappdelen skall INTE pilla på servostaten.

När vi har dessa båda delar anropas de med två uppsättningar variabler. Så får vi två knappflaggor och kan styra två servo.

Vad är då fördelen med detta?
Jo Varje del är separerad och behöver inte veta vad de andra gör.
Om man t.ex vill ändra att servo 1 startar servo två
så tar man bort knapprutin för nr 2 och ersätter denna istället med en rutin som endast kollar när servo 1 talar om att den kommit till
ändläget. då triggar den servo nr 2.
inget i servorutinerna behöver då ändras utan det funkar direkt.....

Swech
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av Icecap »

Arduino är enbart "bra" för att det är ett försimplat system.

Försimplingen gör att många gör program som ditt, det går att göra det hela mycket smidigare och välfungerande, fortfarande i Arduino-språket.

Teknisk sett är Arduino en simpel och dåligt åldrat μC (i original) med en del begränsningar.

Jag kunne sno ihop detta i en valfri PIC på 4 timmar. De första 30 min ville vara att definiera projektet, hur det ska fungera och därefter välja hårdvaran.

Sedan en timmes tid för programmering och resten på att kolla igenom alla lägen och hitta buggar.
Användarvisningsbild
Lennart Aspenryd
Tidigare Lasp
Inlägg: 12607
Blev medlem: 1 juli 2011, 19:09:09
Ort: Helsingborg

Re: Lustigt fel på Arduino-krets (Video och kod included)

Inlägg av Lennart Aspenryd »

Nu kom det ett par intressanta och tänkvärda synpunkter.
Att definiera vad som skall uträttas (röra, ändra Servolägen) och med vilka medel (knapptryckningar) Är grundläggande.
Att rita upp, i block eller på annat grafiskt sätt är sällan fel.
Att sedan välja utförandeprodukt (microproc) eller en färdig enhet som Arduino är vilket som.
Och jag håller med, att skriva program är inte det svår, det är att kunna förutse alla olika lägen och infall som kan hända.
Kanske är det den största bristen med Arduino , att går så fort att ta till sig.
Men jag lyssnar på fler kloka ord här.
Skriv svar