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

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
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 »

Det finns väl inget alls som hindrar att man skriver ett program
för Arduino som gör denna uppgift utan att trassla till det.
Att återkommande också hävda att just AVR är gammal förlegad hårdvara tillför inte debatten något.
Skulle en 8 MHz AVR processor ha några som helst relevanta begränsningar i detta fall?
Likaså skulle en egensnickrad PIC variant på något som helst sätt göra ett bättre jobb i att
köra dessa båda servon fram och tillbaks? Isåfall vad?

Eftersom nu arduino är något som favoriseras av just nybörjare så blir
naturligtvis kod och exempel som man hittar av varierande kvalité. Men det betyder ju inte
per automatik att arduinon som sådan inte går att göra bra grejer på heller.

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 »

Alltså - en Arduino klarar detta jobb elegant! En "våldsammare" och/eller nyare μC hade inte gjort jobbet bättre.

Min motvilja mot Arduino är delvist den äldre (originaltypen) hårdvara och deras avvikelse från C++ standarden. Att det finns "värre modeller" är en klen tröst tycker jag.

Hela systemet med de hjälpfunktioner som finns inbjuder till dålig programmeringspraxis och att det i mångt och mycket är den blinda som leder den döva i de funktioner som utvecklas är ingen hjälp.

Det finns inget glovärdigt i att styra en portpinne vid att kalla den <Port_A_Bit_3> kontra <IO_Pin_9>, det är sak samma. Men de delayms{} och liknande funktioner ger en ingång till programmeringen som är ganska enligt de "goda" gamla BASIC-dagar.
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 »

Min första kod fungerade inte,
då jag inte tänkt på vissa situationer

Här är en fungerande variant.

För att det skulle vara enkelt att duplicera koden och utan att det blir rörigt
har jag gjort servo "controllern" som en klass
den klassen hanterar ett servo, en "button" och två LED:s
vilka pinnar som används defineras i beginfunktionen.

om man vill kan man skapa en extra tab i Arduino IDE
(för att slippa ha ButtonControlledServo klassen i main filen)

denna döper man lämpligtvis till ButtonControlledServo.h
sedan flyttar man koden
fr.o.m. #include <Servo.h>
t.o.m. }; // end of ButtonControlledServo class

till denna nya tab.
avkommentera
//#include "ButtonControlledServo.h"

har provkört koden i UnoArduSim och det fungerar där,
har en Arduino Nano men orkar inte koppla upp det för att testa
vill inte programmera om den just nu heller.

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)
  check, 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!
*/

#include <Servo.h>

//#define USE_SERVO_SPEED // uncomment this if you want your original behaivour i.e. move servo in small increments (experimental)

class ButtonControlledServo
{
public:
    Servo servo;
    char angle;
    char minAngle;
    char maxAngle;
    byte servoSpeed;
    byte buttonPin;
    char countUpDown;
    byte buttonPushedOld;
    byte servoNr;
    byte servoAtStartLedPin;
    byte servoAtEndLedPin;
    
    ButtonControlledServo() {
      angle = 0;
      minAngle = 0;
      maxAngle = 0;
      servoSpeed = 1;
      buttonPin = 0;
      countUpDown = 0;
      buttonPushedOld = 0;
      servoNr = 0;
      servoAtStartLedPin = 0;
      servoAtEndLedPin = 0;
    }
    
    void begin (byte _servoNr, int _buttonPin, int servoPin, int _servoAtStartLedPin, int _servoAtEndLedPin, char servoMinAngle, char servoMaxAngle, byte _servoSpeed) {
        servoNr = _servoNr;
        angle = servoMinAngle;
        servoSpeed = _servoSpeed;
        minAngle = servoMinAngle;
        maxAngle = servoMaxAngle;
        buttonPin = _buttonPin;
        servoAtStartLedPin = _servoAtStartLedPin;
        servoAtEndLedPin = _servoAtEndLedPin;
                
        servo.attach(servoPin); // Attaches servo on pin
        pinMode(servoAtStartLedPin, OUTPUT);
        pinMode(servoAtEndLedPin, OUTPUT);
        pinMode(buttonPin, INPUT); // not really necessary
        
        servo.write(servoMinAngle); // Set the initial position for servo (homeing, when mounted it should be open)
    }
    
    void update() {
        // the following makes sure that countUpDown is only activated once (it creates a button toggle functionality)
        
        if (digitalRead(buttonPin) == LOW) { // Checks if button is pushed down
            if (buttonPushedOld == LOW)
            {
                buttonPushedOld = HIGH;
                if (angle == minAngle && countUpDown == 0) // countUpDown == 0 makes sure that the prev execution is completed
                {
                    countUpDown = 1;
                    
                    #ifndef USE_SERVO_SPEED
                    servo.write(maxAngle); // Moving the servo to the end
                    #endif
                    
                    Serial.print("Movin servo "); Serial.print(servoNr); Serial.println(" to the end"); //  Print text in serial monitor
                    delay(100); // button debounce
                }
                else if (angle == maxAngle && countUpDown == 0) // countUpDown == 0 makes sure that the prev execution is completed
                {
                    countUpDown = -1;
                    
                    #ifndef USE_SERVO_SPEED
                    servo.write(minAngle); // Moving the 1st servo to the beginning
                    #endif        
            
                    Serial.print("Movin servo "); Serial.print(servoNr); Serial.println(" to the end"); //  Print text in serial monitor
                    delay(100); // button debounce
                }
            }
        }
        else // if button 1 is not pressed
        {
            if (buttonPushedOld == HIGH) 
            {
                buttonPushedOld = LOW; // only set if the button was pressed before
            }
        }
      
        // the following is just a software timer (if not using USE_SERVO_SPEED)
        // that give the servo enough time to move to the destination
        if (countUpDown != 0) { // if servo is moving
      
            angle = angle + servoSpeed * countUpDown ;  // upcount or downcount the "timer" value
        
            // fix overflow/underflow
            if (angle < minAngle)
                angle = minAngle;
            else if (angle > maxAngle)
                angle = maxAngle;
              
        #ifdef USE_SERVO_SPEED
            servo.write(angle); // Moving the servo to current angle
        #endif
        
            if (angle == minAngle) { // if at either end stop counter
                digitalWrite(servoAtEndLedPin, LOW);
                digitalWrite(servoAtStartLedPin, HIGH);
                countUpDown = 0;
            }
            else if (angle == maxAngle) {
                digitalWrite(servoAtEndLedPin, HIGH);
                digitalWrite(servoAtStartLedPin, LOW);
                countUpDown = 0;
            }
                
            // using s1speed as a factor to this delay
            delay(servoSpeed); // Creates a delay to wait for servo to get in place before looping on
        }
    }
}; // end of ButtonControlledServo class

//#include "ButtonControlledServo.h"

// 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 s1LedOpenPin 8
#define s1LedClosedPin 9
#define s2LedOpenPin 10
#define s2LedClosedPin 11

// Defines variables for servo 1
#define s1speed 10    // Speed for servo 1 movement
#define s1minAngle 7  // Angle of servo 1 arm when vent is closed
#define s1maxAngle 87 // Angle of servo 1 arm when vent is open

// Defines variables for servo 2
#define s2speed 10    // Speed for servo 2 movement
#define s2minAngle 7  // Angle of servo 2 arm when vent is closed
#define s2maxAngle 87 // Angle of servo 2 arm when vent is open

ButtonControlledServo bcs1;
ButtonControlledServo bcs2;

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

  bcs1.begin(1, b1Pin, s1Pin, s1LedClosedPin, s1LedOpenPin, s1minAngle, s1maxAngle, s1speed);
  bcs2.begin(2, b2Pin, s2Pin, s2LedClosedPin, s2LedOpenPin, s2minAngle, s2maxAngle, s2speed);
  
  Serial.println("*Teljemo's servo controller initiated*"); // Print text in serial monitor

  // Print for serial monitor
  Serial.println("Starting angles are: "); // Print text in serial monitor
  Serial.print(s1minAngle); // Prints angle of servo 1
  Serial.println(" degrees for servo 1"); // Print text in serial monitor
  Serial.print(s2minAngle); // 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

//#define USE_SERVO_SPEED // uncomment this if you want your original behaivour i.e. move servo in small increments (without bugs)

// Loop
void loop() {
    bcs1.update();
    bcs2.update();
  //End of loop
}
//  End of program

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 »

Grymt bra input från alla!
Körde precis den senaste koden ifrån manicken och den fungerar fint.

Då har jag egentligen 2 punkter som dyker upp...
Låt oss säga att nåt kärvar för en servomotor. Den ska vrida en platta i ett rör och det skulle kunna komma in främmande föremål som lägger sig ivägen.
I nuläget står motorn och morrar om den bara är lite fel mot vinkeln den ska vara och jag är orolig att om den hamnar i ett sånt läge och står så under en längre tid kan den kanske överhettas och ta skada?
Alltså borde jag ha ännu en funktion som stänger av spänningen till servomotorerna när de inte kör.

Knapptryckning:
Spänning till servo PÅ
Kör servo
Servo körd:
Delay på 3 sek
Spänning till servo AV
Inväntar knapptryckning:


För detta behöver jag addera lite hårdvara känns det som. Ett varsitt litet relä till varje servo..

Den andra punkten är att jag vill ansluta ett större relä också för att styra utsugsfläkten baserat på hur ventilerna står.
Om båda är är stängda så ska fläkten stanna och när man öppnar en ventil så ska fläkten starta.
Här tänker jag en aning på säkerheten som nämnts lite innan. Ser ni några större risker i att använda ett 230v relä i den här applikationen?
Då tänker jag risk för bugg eller Arduino haveri som skulle kunna leda till brand pga starkström.
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 »

Som skrivit tidigare kommer servon bara att köra så länge pulserna kommer fram!
När de stoppar kan det ta 70ms eller så innan motorn stannar men annars...
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 »

Som skrivit tidigare kommer servon bara att köra så länge pulserna kommer fram!
När de stoppar kan det ta 70ms eller så innan motorn stannar men annars...
Kollade på källkoden för Servo.h
om jag förstår det rätt så måste man göra detach för att stänga av pulserna.

vilket man i princip kan göra varje gång servot når sitt ändläge, och när man ska köra så gör man en attach.

Kod: Markera allt

class ButtonControlledServo
{
public:
    Servo servo;
    char angle;
    char minAngle;
    char maxAngle;
    byte servoSpeed;
    byte buttonPin;
    char countUpDown;
    byte buttonPushedOld;
    byte servoNr;
    byte servoAtStartLedPin;
    byte servoAtEndLedPin;
    
    ButtonControlledServo() {
      angle = 0;
      minAngle = 0;
      maxAngle = 0;
      servoSpeed = 1;
      buttonPin = 0;
      countUpDown = 0;
      buttonPushedOld = 0;
      servoNr = 0;
      servoAtStartLedPin = 0;
      servoAtEndLedPin = 0;
    }
    
    void begin (byte _servoNr, int _buttonPin, int servoPin, int _servoAtStartLedPin, int _servoAtEndLedPin, char servoMinAngle, char servoMaxAngle, byte _servoSpeed) {
        servoNr = _servoNr;
        angle = servoMinAngle;
        servoSpeed = _servoSpeed;
        minAngle = servoMinAngle;
        maxAngle = servoMaxAngle;
        buttonPin = _buttonPin;
        servoAtStartLedPin = _servoAtStartLedPin;
        servoAtEndLedPin = _servoAtEndLedPin;
                
        
        pinMode(servoAtStartLedPin, OUTPUT);
        pinMode(servoAtEndLedPin, OUTPUT);
        // LED initial values
        digitalWrite(servoAtEndLedPin, LOW);
        digitalWrite(servoAtStartLedPin, HIGH);
        pinMode(buttonPin, INPUT); // not really necessary

        servo.attach(servoPin); // Attaches servo on pin
        servo.write(servoMinAngle); // Set the initial position for servo (homeing, when mounted it should be open)
        // following "simulates" a run, so that the servo is given enought time to goto the initial position
        // and so that the servo signal can then be turn off
        angle = servoMaxAngle;
        countUpDown = -1;
    }
    
    void update() {
        // the following makes sure that countUpDown is only activated once (it creates a button toggle functionality)
        if (digitalRead(buttonPin) == LOW) { // Checks if button is pushed down (active LOW)
            if (buttonPushedOld == LOW)
            {
                buttonPushedOld = HIGH;
                if (angle == minAngle && countUpDown == 0) // countUpDown == 0 makes sure that the prev execution is completed
                {
                    countUpDown = 1;
                    servo.attach(servoPin); // activate the PWM module
                    #ifndef USE_SERVO_SPEED
                    servo.write(maxAngle); // Moving the servo to the end
                    #endif
                    
                    Serial.print("Movin servo "); Serial.print(servoNr); Serial.println(" to the end"); //  Print text in serial monitor
                    delay(100); // button debounce
                }
                else if (angle == maxAngle && countUpDown == 0) // countUpDown == 0 makes sure that the prev execution is completed
                {
                    countUpDown = -1;
                    servo.attach(servoPin); // activate the PWM module
                    #ifndef USE_SERVO_SPEED
                    servo.write(minAngle); // Moving the 1st servo to the beginning
                    #endif        
            
                    Serial.print("Movin servo "); Serial.print(servoNr); Serial.println(" to the end"); //  Print text in serial monitor
                    delay(100); // button debounce
                }
            }
        }
        else if (buttonPushedOld == HIGH)
            buttonPushedOld = LOW; // only set if the button was pressed before (this resets the button toggle function)
        
        // the following is just a software timer (if not using USE_SERVO_SPEED)
        // that give the servo enough time to move to the destination
        if (countUpDown != 0) { // if servo is moving
      
            angle = angle + servoSpeed * countUpDown ;  // upcount or downcount the "timer" value
        
            // fix overflow/underflow
            if (angle < minAngle)
                angle = minAngle;
            else if (angle > maxAngle)
                angle = maxAngle;
              
        #ifdef USE_SERVO_SPEED
            servo.write(angle); // Moving the servo to current angle
        #endif
        
            if (angle == minAngle) { // if at either end stop counter
                digitalWrite(servoAtEndLedPin, LOW);
                digitalWrite(servoAtStartLedPin, HIGH);
                servo.detach(); // deactivate PWM module
                countUpDown = 0;
            }
            else if (angle == maxAngle) {
                digitalWrite(servoAtEndLedPin, HIGH);
                digitalWrite(servoAtStartLedPin, LOW);
                servo.detach(); // deactivate PWM module
                countUpDown = 0;
            }
                
            // using s1speed as a factor to this delay
            delay(servoSpeed); // Creates a delay to wait for servo to get in place before looping on
        }
    }
};
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 behövs alltså inga extra relä för att stänga av servon.

för att detektera om ventilen är stängd är det nog lämpligast att använda en magnetisk givare
där man placerar en magnet på "flärpen"
https://www.electrokit.com/produkt/magn ... 5mm-x-5mm/

och sedan utanför röret(i plast) sätter man en hall-effekt givare
https://www.electrokit.com/produkt/alle ... sor-5mv-g/
som man läser av med den inbyggda ADC
(eller så kan man också använda en spänningskomparator)
https://www.electrokit.com/produkt/lm31 ... omparator/
för att känna av en egen given nivå av magnetfältet, som sedan aktiverar utgången hos komparatorn

det finns också digitala hall-effekt givare
men de växlar endast utgången när magnetfältet når en fast nivå
så det blir svårt att avgöra om ventilen är stängd eller inte med dessa
Skriv svar