Go Down

Topic: [SOLVED] How to multitask with servos? (Read 1 time) previous topic - next topic

neiklot

Quote
but how it's working ? I mean I can drive any servo from any pin on the arduino with only using digitalWrite function instead of the actual PWM signal from the known pins of the PWM?
The servo library works on all pins, not just the ~PWM pins. It's got nothing to do with PWM as we know it. It even works on the analog input pins, Ax, which are digital pins anyway.




wolfrose

The point I was making was that it's not the duty cycle that positions the servo, it's the absolute length of the pulse. If you halve the cycle, and keep the pulse the same length, that doubles the duty cycle but does not change the position. (Not like a DC motor and PWM, where the speed depends on the duty cycle, not the absolute high time.)

That and a few other values are #define'd in servo.h. I changed it to 10000 once, it worked fine.
You're totally right ! I tried 10 and 30ms, all worked fine. What matters is the length of the HIGH pulse.

So the numbers in the Servo library are the programmer preferences for the angles of the servo

I adjusted mine to
800 min
1652 mid
2450 max

which give me exact 180 degrees



Quote
You can't determine it's position (if by that you mean "find out where it is"), unless you have a 4-wire servo like some of adafruit's, which bring the actual position out on that extra wire.
Yep, that's what I thought about, I really can't determine the position of the servo.

The one way I thought about is to put the servo at a determined position at the start of the program; say 90 degrees, then save that position and move from there ..


Yeah problem solved .. now I just have to work on developing the functions, then I would like to post them here and receive the members opinions. I want to know what people think about my coding, is it good, nice, there're things to improve, modify ... etc.

Robin2

So the numbers in the Servo library are the programmer preferences for the angles of the servo
I'm not sure what you had in mind when you wrote that but it does not seem to me to be entirely correct.

I would describe the numbers in the library as those which the programmer considered would be suitable for the full range of motion for a wide range of servos.

As I said earlier (and as you have discovered) the exact limits that you should use in your program will vary between different types of servos and have to determined by trial and error.

if you happen to have a servo that needs values beyond the limits in the library you will need to modify the limits in the library. However if you have a servo whose limits are within a narrower range than the library there is no need to modify the library.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

wolfrose

I'm not sure what you had in mind when you wrote that but it does not seem to me to be entirely correct.
Yep, sorry I said it's preferences but it's according to the device specs. I know that but I meant that after doing the adjustments and the measurements .. etc.

Of course anything is electronics is done according to the specs!

Quote
I would describe the numbers in the library as those which the programmer considered would be suitable for the full range of motion for a wide range of servos.
That's what I was working on most the time, is to find the full range of 180 degrees exactly.


Quote
As I said earlier (and as you have discovered) the exact limits that you should use in your program will vary between different types of servos and have to determined by trial and error.
Quote
if you happen to have a servo that needs values beyond the limits in the library you will need to modify the limits in the library. However if you have a servo whose limits are within a narrower range than the library there is no need to modify the library.
Absolutely!


I also developed this function to send a pulse within microsecond range at any delay time!

How's it?

Code: [Select]
void servo_write(uint8_t pin, uint32_t tick_every, uint16_t pos){
  servo_cr = millis(); 
  if(servo_cr - servo_st >= tick_every){

  if(!servo_state){digitalWrite(pin,HIGH);
  servo_state = 1;servo_st = micros();}
   
  if(servo_state){servo_cr = micros();
    if(servo_cr - servo_st >= pos){digitalWrite(pin,LOW);
    servo_state = 0;}}
  }
}

Robin2

I also developed this function to send a pulse within microsecond range at any delay time!

How's it?
You tell us - what happens when you try it?

And please use the AutoFormat tool to lay out your code for easier reading. Don't put multiple statements on one line. Always put a } on a line of its own.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

wolfrose

You tell us - what happens when you try it?

And please use the AutoFormat tool to lay out your code for easier reading. Don't put multiple statements on one line. Always put a } on a line of its own.

OK, thanks for the tip, sorry for confusing you with my previous code post.

....... well I did it!

It's a function for multitasking process that tick the servo every determined time.

I can improve it to calculate the input delay time, and adjust that with the number of tick for the determined position that is set at the initialization of the program.

Code: [Select]
void servo_tick(uint8_t pin, uint32_t tick_every, uint16_t pos){
if(!servo_state && !tick_lock){
digitalWrite(pin,HIGH);
servo_state = 1;
servo_st = micros();
}

if(servo_state && !tick_lock){
servo_cr = micros();
if(servo_cr - servo_st >= pos){
digitalWrite(pin,LOW);
tick_lock = 1;
}
}

if(tick_lock){     
servo_tick_cr = millis(); 
if(servo_tick_cr - servo_tick_st >= tick_every){
tick_lock = 0;
servo_state = 0;
servo_tick_st = millis();
}
}
}

wolfrose

I have another problem related to the hardware, I connected a servo to the same circuit powered with the same 5V from the arduino. The program hangs all the way, I tried to add different capacitors but it helped a little bit of the system just for the first run, after that it hangs! What to do now?

The system contains RFID module, a buzzer and a servo.

But adding the servo hangs the system!

Robin2

I have another problem related to the hardware, I connected a servo to the same circuit powered with the same 5V from the arduino.
That description is not entirely clear. It sounds as if you are powering the servo from the Arduino 5v pin. If so, that is a bad idea. The 5v pin cannot provide enough current for a motor. Give the servo a separate power supply with the GND connected to the Arduino GND.

If I have misunderstood then please post a simple diagram showing how everything is connected.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

wolfrose

I modified the setup later, added two 1000uF and another 5V/2A power adapter for the servo.

The arduino and the rfid are powered from the USB.

This is the circuit:



This is the code:
Code: [Select]
/****************************** LIBRARIES ******************************/
#include <SPI.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <RFID.h>

/****************************** DEFINITIONS ******************************/
// pins definitions
#define SS_PIN          10
#define RST_PIN         9
#define IR_1            A0
#define BUZZER          7
#define SERVO1          3
#define ACCEPT_LED      4
#define DENIED_LED      5

// setup definitions
#define CARDS           1
#define RFID_ARR_SIZE   CARDS*5

// servo definitions
#define SERVO1 3
#define SERVO2 4

// lcd status defines
#define START_MSG       0
#define CHECK_MSG       1
#define REGISTER_MSG    2
#define ACCEPTED_MSG    3
#define DENIED_MSG      4
#define ALREADY_MSG     5
#define FINISH_MSG      6

/****************************** VARIABLES ******************************/
// sys variables:
byte sys_state;
uint32_t sys_st;
uint32_t sys_cr;
uint16_t sys_pr = 500;

 
// lcd variables:
byte lcd_state;
uint32_t lcd_st;
uint32_t lcd_cr;
uint16_t lcd_pr;

// rfid variables:
byte crd_buf[RFID_ARR_SIZE],card_no;
byte register_lock,check_lock,print_lock;

/****************************** FUNCTIONES ******************************/
// system functions
void perphiral_reset(void);

// servo functions
void servo_freq(uint8_t pin, uint16_t pwm);

// rfid functions
void register_accepted_card(void);
void record_new_cards(void);
void check_card(void);
void print_registered_cards(void);

// lcd functions
void lcd_start(void);
void lcd_msg_mgt(void);

// objects
RFID rfid(SS_PIN, RST_PIN);
LiquidCrystal_I2C lcd(0x27,16,2);
Servo myservo;

//////////////////////////////////////////////////////////////////////
void setup(){
  Serial.begin(9600);
  SPI.begin();
  rfid.init();
  lcd_start();
  pinMode(BUZZER,OUTPUT);
  pinMode(ACCEPT_LED,OUTPUT);
  pinMode(DENIED_LED,OUTPUT);
  pinMode(SERVO1,OUTPUT);
  ////////////////////////////
  pinMode(SERVO1,OUTPUT);
  myservo.attach(SERVO1);
}

void loop(){
    register_accepted_card(); // apply only once
    check_card();
    lcd_msg_mgt();
    perphiral_reset();
    servo_gate();
}


void servo_gate(void){
  if(servo_gate_state){
    myservo.write(90);
  }
  else{
    myservo.write(0);
  }
}


void perphiral_reset(void){
  if(sys_state){ 
    sys_cr = millis();
    if(sys_cr - sys_st >= sys_pr){ 
      digitalWrite(ACCEPT_LED,LOW);
      digitalWrite(DENIED_LED,LOW);
      digitalWrite(BUZZER,LOW);
      sys_st = millis();
    }
  }
}

void lcd_start(void){
  lcd.init();
  lcd.backlight();
  lcd_state = START_MSG;
  lcd_st = millis();
}

void lcd_msg_mgt(void){
  lcd_cr = millis();
  if(lcd_cr - lcd_st >= lcd_pr){
    switch(lcd_state){
     
      case START_MSG:
        lcd.clear();
        lcd.print("RFID SYSTEM");
        lcd.setCursor(0, 1);
        lcd.print("Hi ..");
        lcd_state = REGISTER_MSG;
        lcd_pr = 1000;
      break;

      case REGISTER_MSG:
        lcd.clear();
        lcd.print("REGISTER your");     
        lcd.setCursor(0, 1);
        lcd.print("RFID CARD no: ");
        lcd.print(card_no+1);
        register_lock = 0;
        lcd_pr = 300;
      break;
     
      case CHECK_MSG:
        lcd.clear();
        lcd.print("ENTER your");     
        lcd.setCursor(0, 1);
        lcd.print("RFID CARD:");
        check_lock = 1;
        sys_state = 0;
        lcd_pr = 500; 
      break;
             
      case ACCEPTED_MSG:
        lcd.clear();
        lcd.print("CARD ACCEPTED");
        lcd_state = CHECK_MSG;
        lcd_pr = 1000;
      break; 
     
      case DENIED_MSG:
        lcd.clear();
        lcd.print("CARD DENIED");
        lcd_state = CHECK_MSG;
        lcd_pr = 1000;
      break;   

      case ALREADY_MSG:
        lcd.clear();
        lcd.print("CARD ALREADY");
        lcd.setCursor(0, 1);
        lcd.print("REGISTERED");
        lcd_state = REGISTER_MSG;
        register_lock = 0;
        lcd_pr = 1000;
      break; 
       
      case FINISH_MSG:
        lcd.clear();
        lcd.print("FINISHED");
        lcd.setCursor(0, 1);
        lcd.print("REGISTERATION");
        check_lock  = 1;
        lcd_state = CHECK_MSG;
        lcd_pr = 1500;
      break;       
    }
    lcd_st = millis();
  }
}

void register_accepted_card(void){
  if (!register_lock) {
    if (rfid.isCard()) {
      if(rfid.readCardSerial()){
        if(card_no>0){
          for(byte i = 0; i<card_no; i++){
            if(!memcmp((crd_buf+(i*5)),rfid.serNum,5)){
               
              lcd_state = ALREADY_MSG;
              register_lock = 1;
            }
          }
        }
       
        if(!register_lock){
         
          for(byte i=0;i<5;i++){
            crd_buf[(card_no*5)+i] = rfid.serNum[i];
         }

          // This is just to print the card number and its code         
          Serial.print("card#"); Serial.println(card_no+1);
          for(byte i=card_no*5;i<(card_no*5)+5;i++){
            Serial.print(crd_buf[i],HEX);Serial.print(", ");}
          Serial.println();Serial.println("//////////////////////////");
         
          card_no++;
          if(card_no >= CARDS){
              lcd_state = FINISH_MSG;
          }
         
          else{
              lcd_state = REGISTER_MSG;
          }
          register_lock = 1;         
        }
      }
    }
    rfid.halt();
  }
}


void check_card(void){
  bool accessGranted = false;  // A flag to store the state - start off denied. 
  if (check_lock){
    if (rfid.isCard()){
      if (rfid.readCardSerial()){
        for(byte i=0;i<card_no;i++){
          if(!memcmp(crd_buf+(i*5),rfid.serNum,5)){
            accessGranted = true;
          }
        }

        if(accessGranted){
          Serial.println("card accepted");
          digitalWrite(ACCEPT_LED,HIGH);
          digitalWrite(DENIED_LED,LOW);
          digitalWrite(BUZZER,LOW);
          check_lock = 0;
          sys_state = 1;
          lcd_state = ACCEPTED_MSG;
          sys_st = millis();
        }
        else{
          Serial.println("card denied");
          digitalWrite(ACCEPT_LED,LOW);
          digitalWrite(DENIED_LED,HIGH);
          digitalWrite(BUZZER,HIGH);
          check_lock = 0;
          sys_state = 1;
          lcd_state = DENIED_MSG;
          sys_st = millis();
        }
      }
      rfid.halt();
    }
  }
}

Robin2

#24
Apr 09, 2019, 05:46 pm Last Edit: Apr 11, 2019, 02:41 pm by Robin2
I modified the setup later, added two 1000uF and another 5V/2A power adapter for the servo.
You do not appear to have not told us the results when you tried that arrangement.

...R

Two or three hours spent thinking and reading documentation solves most programming problems.

wolfrose

Ops .. sorry !

It's the same result ! Even with adding the two caps and the separate power supply for the servo.

Robin2

It's the same result !
Are you referring to what you described in Reply #21? (It makes life much easier if you mention the Reply number)

What exactly do you mean by
Quote
But adding the servo hangs the system!
Do you mean that the program works perfectly when it includes the code for the servo but the servo is not actually connected?
But it fails to work when the servo is connected to the system?

If so that suggests a power or wiring problem or a faulty servo.

Does the servo work with a simple servo-sweep program?

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

wolfrose

Are you referring to what you described in Reply #21? (It makes life much easier if you mention the Reply number)
Sorry for the unclear comments. No, actually to Reply #23, which is after the modifications of adding the separate power supply for the servo and the 2 capacitors for the power rails.

Quote
What exactly do you mean by Do you mean that the program works perfectly when it includes the code for the servo but the servo is not actually connected?
But it fails to work when the servo is connected to the system?
I mean, that the RFID works by reading and showing data on LCD when the servo is not connected and hangs when the servo is connected.

I think that happened because there were problems either with the code or the circuit.


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


But with all that :)

The project now works perfectly !!

This is the final code:

Code: [Select]
/****************************** LIBRARIES ******************************/
#include <SPI.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <RFID.h>

/****************************** DEFINITIONS ******************************/
// pins definitions
#define SS_PIN          10
#define RST_PIN         9
#define IR_1            A0
#define BUZZER          7
#define SERVO1          3
#define ACCEPT_LED      4
#define DENIED_LED      5

// setup definitions
#define CARDS           1
#define RFID_ARR_SIZE   CARDS*5

// servo definitions
#define DEG_0   800
#define DEG_90  1500
#define DEG_180 2300

#define SERVO1 3
#define SERVO2 4

// lcd status defines
#define START_MSG       0
#define CHECK_MSG       1
#define REGISTER_MSG    2
#define ACCEPTED_MSG    3
#define DENIED_MSG      4
#define ALREADY_MSG     5
#define FINISH_MSG      6

/****************************** VARIABLES ******************************/
// sys variables:
byte sys_state;
uint32_t sys_st;
uint32_t sys_cr;
uint16_t sys_pr = 500;

// servo variables:
uint32_t servo_st, servo_cr;
bool servo_state,servo_delay,servo_gate_state;
 
// lcd variables:
byte lcd_state;
uint32_t lcd_st;
uint32_t lcd_cr;
uint16_t lcd_pr;

// rfid variables:
byte crd_buf[RFID_ARR_SIZE],card_no;
byte register_lock,check_lock,print_lock;

/****************************** FUNCTIONES ******************************/
// system functions
void perphiral_reset(void);

// servo functions
void servo_freq(uint8_t pin, uint16_t pwm);

// rfid functions
void register_accepted_card(void);
void record_new_cards(void);
void check_card(void);
void print_registered_cards(void);

// lcd functions
void lcd_start(void);
void lcd_msg_mgt(void);

// objects
RFID rfid(SS_PIN, RST_PIN);
LiquidCrystal_I2C lcd(0x27,16,2);
Servo myservo;

//////////////////////////////////////////////////////////////////////
void setup(){
  Serial.begin(9600);
  SPI.begin();
  rfid.init();
  lcd_start();
  pinMode(BUZZER,OUTPUT);
  pinMode(ACCEPT_LED,OUTPUT);
  pinMode(DENIED_LED,OUTPUT);
  pinMode(SERVO1,OUTPUT);
  ////////////////////////////
  myservo.attach(SERVO1);
  myservo.write(25);
  servo_st = millis();
}

void loop(){
    register_accepted_card(); // apply only once
    check_card();
    lcd_msg_mgt();
    perphiral_reset();
    servo_gate();
}

void servo_gate(void){
  if(servo_gate_state){
    myservo.write(95);
   
  }
}

void perphiral_reset(void){
  if(sys_state){ 
    sys_cr = millis();
    if(sys_cr - sys_st >= sys_pr){ 
      digitalWrite(ACCEPT_LED,LOW);
      digitalWrite(DENIED_LED,LOW);
      digitalWrite(BUZZER,LOW);
      sys_st = millis();
    }
  }
}

void lcd_start(void){
  lcd.init();
  lcd.backlight();
  lcd_state = START_MSG;
  lcd_st = millis();
}

void lcd_msg_mgt(void){
  lcd_cr = millis();
  if(lcd_cr - lcd_st >= lcd_pr){
    switch(lcd_state){
     
      case START_MSG:
        lcd.clear();
        lcd.print("RFID SYSTEM");
        lcd.setCursor(0, 1);
        lcd.print("Hi ..");
        lcd_state = REGISTER_MSG;
        lcd_pr = 1000;
      break;

      case REGISTER_MSG:
        lcd.clear();
        lcd.print("REGISTER your");     
        lcd.setCursor(0, 1);
        lcd.print("RFID CARD no: ");
        lcd.print(card_no+1);
        register_lock = 0;
        lcd_pr = 300;
      break;
     
      case CHECK_MSG:
        lcd.clear();
        lcd.print("ENTER your");     
        lcd.setCursor(0, 1);
        lcd.print("RFID CARD:");
        check_lock = 1;
        sys_state = 0;
        lcd_pr = 500; 
      break;
             
      case ACCEPTED_MSG:
        lcd.clear();
        lcd.print("CARD ACCEPTED");
        lcd_state = CHECK_MSG;
        lcd_pr = 1000;
      break; 
     
      case DENIED_MSG:
        lcd.clear();
        lcd.print("CARD DENIED");
        lcd_state = CHECK_MSG;
        lcd_pr = 1000;
      break;   

      case ALREADY_MSG:
        lcd.clear();
        lcd.print("CARD ALREADY");
        lcd.setCursor(0, 1);
        lcd.print("REGISTERED");
        lcd_state = REGISTER_MSG;
        register_lock = 0;
        lcd_pr = 1000;
      break; 
       
      case FINISH_MSG:
        lcd.clear();
        lcd.print("FINISHED");
        lcd.setCursor(0, 1);
        lcd.print("REGISTERATION");
        lcd_state = CHECK_MSG;
        lcd_pr = 1500;
      break;       
    }
    lcd_st = millis();
  }
}

void register_accepted_card(void){
  if (!register_lock) {
    if (rfid.isCard()) {
      if(rfid.readCardSerial()){
        if(card_no>0){
          for(byte i = 0; i<card_no; i++){
            if(!memcmp((crd_buf+(i*5)),rfid.serNum,5)){
             
              Serial.println("already card is");
              for(byte p = i*5; p<(i*5)+5; p++){
                Serial.print(crd_buf[p],HEX);Serial.print(", ");}
                Serial.println();
               
              lcd_state = ALREADY_MSG;
              register_lock = 1;
            }
          }
        }
       
        if(!register_lock){
         
          for(byte i=0;i<5;i++){
            crd_buf[(card_no*5)+i] = rfid.serNum[i];}

          Serial.print("loop#"); Serial.println(card_no);
          Serial.print("start index ");Serial.println(card_no*5);
          Serial.print("end index ");Serial.println((card_no*5)+5);
          Serial.println();

         
          Serial.print("card#"); Serial.println(card_no+1);
          for(byte i=card_no*5;i<(card_no*5)+5;i++){
            Serial.print(crd_buf[i],HEX);Serial.print(", ");}
          Serial.println();Serial.println("//////////////////////////");
         
          card_no++;
          if(card_no >= CARDS){lcd_state = FINISH_MSG;}
          else{lcd_state = REGISTER_MSG;}
          register_lock = 1;         
        }
      }
    }
    rfid.halt();
  }
}

void check_card(void){
  bool accessGranted = false;  // A flag to store the state - start off denied. 
  if (check_lock){
    if (rfid.isCard()){
      if (rfid.readCardSerial()){
        for(byte i=0;i<card_no;i++){
          if(!memcmp(crd_buf+(i*5),rfid.serNum,5)){
            accessGranted = true;
          }
        }

        if(accessGranted){
          Serial.println("card accepted");
          digitalWrite(ACCEPT_LED,HIGH);
          digitalWrite(DENIED_LED,LOW);
          digitalWrite(BUZZER,LOW);
          check_lock = 0;
          sys_state = 1;
          lcd_state = ACCEPTED_MSG;
          servo_gate_state = 1;                   // SERVO Activation
          sys_st = millis();
        }
        else{
          Serial.println("card denied");
          digitalWrite(ACCEPT_LED,LOW);
          digitalWrite(DENIED_LED,HIGH);
          digitalWrite(BUZZER,HIGH);
          check_lock = 0;
          sys_state = 1;
          lcd_state = DENIED_MSG;
          servo_gate_state = 0;                   // SERVO Deactivation
          sys_st = millis();
        }
      }
      rfid.halt();
    }
  }
}

Go Up