Multiple inputs and multiple outputs servo problem

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,

         I have an issue in my avr code. Basically , I have two different IR sensors that give an input when ever the emitter is blocked. I am using that input to run two different servomotors. i.e - IR sensor 1-> servomotor 1 and IR sensor 2 -> servomotor 2. 

        My issue in code is I can only run the same servomotor after completing the sensing and output of the other pair. I wanted both to be independent in such a way that say, when I block the IR module 1 ,  servomotor 1 has to run. But now it waits for the 2nd pair to complete and then starts as cycle. 

 

Please suggest me what kind of modification I have to make in code.

 

PS: I am a biologist by profession. Have to make this for a research purpose . 

 

My code is down here...

 

 

#include <avr/io.h>
#ifndef F_CPU

#define F_CPU 1000000UL 
#endif
#include <util/delay.h>

 
int main(void)

{
    
  DDRA&=~_BV(3);//set port A pin 3 as input (Infra red sensor as input)
  PORTA|=_BV(3);//Enable pull up
  DDRA= _BV(2);// set Port A pin 2 as input( Another Infra red sensor as input)
  PORTA|= _BV(2);// Enable pull up

  TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);             //NON Inverted PWM
  TCCR1B|=(1<<WGM13)|(1<<WGM12)|(0<<CS11)|(1<<CS10);    //PRESCALER=1 MODE 14(FAST PWM)

  ICR1=19999;    //fPWM=50Hz (Period = 20ms Standard).
  
  for(;;)  // infinite loop 

  {

     if (bit_is_clear(PINA, 3))// if infra red is not sensed
          
               
       {  
           
          PORTD&=~_BV(4);
        
        
      //PORTD&=~_BV(4);//Servomotor output is 0;

         loop_until_bit_is_set(PINA, 3);// 
            

             DDRD|=(1<<PD4);  //connected to first servomotor
             
      
            OCR1B=400;    //45 degree rotation
          _delay_ms(150);

                        
         OCR1B=1050;      // 90 degree rotaiton
           _delay_ms(150); 
 
         OCR1B=1950;    //135 degree rotation
               _delay_ms(150);
        
                     OCR1B=2400;   //180 degree rotaiton 
            _delay_ms(150);
        
           
           _delay_ms(500);
          
        }    

     
     if (bit_is_clear(PINA, 2))// if second infra red sensor is not detected 
          
               
       {  
           
          PORTD&=~_BV(4);
        
        
      //PORTD&=~_BV(4);//Servomotor output is 0;

         loop_until_bit_is_set(PINA, 3);// 
            

             DDRD|=(1<<PD5);  // connected to second servomotor
             
      
            OCR1A=400;    //45 degree 
          _delay_ms(150);

                        
         OCR1A=1050;      // 90 degree rotaiton
           _delay_ms(150); 
 
         OCR1A=1950;    //135 degree rotation
               _delay_ms(150);
        
                     OCR1A=2400;   //180 degree rotaiton 
            _delay_ms(150);
        
           
           _delay_ms(500);

       }

  }

 

}

    

......Thanks in advance

Cheers

Indran

This topic has a solution.

indran

Last Edited: Thu. Nov 6, 2014 - 01:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your fundamental problem is the waiting.
You have discovered the reason embedded programs usually do not

wait for a task to complete before starting another independent task.

for(;;;) {
    // stuff depending on current time and motor1 state
    // stuff depending on current time and motor2 state
}

Note that the motor states include the times at which they arrived in those states.

If you have another timer available, a 10 ms "heartbeat" should not be too hard to arrange.

The time will only need to be eight bits, so you will not need to deal with atomicity issues.

 

I think you have other problems as well.

At least one derives from getting magic numbers wrong.

A magic number is an apparently arbitrary number that is used more than once.

The 150's seem to be consistent, but I think that you might have gotten a pin number wrong.
 

Also, DDRA4 is sometimes cleared and set again in short order.

In cases where PINA3 changes at just the right time, DDRA4 will stay cleared.

International Theophysical Year seems to have been forgotten..
Anyone remember the song Jukebox Band?

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Welcome to the Forum.

 

I don't read C, so just a comment or on possible approaches to the problem.

 

If you turn on and off the servo based on the IR sensor only, and the durations are not timed, then one might consider this type of approach to running two "simultaneous" processes:

 

Use interrupts to make this task "easy".

 

Pseudo Code:

Headers

Ports and Pins setup

Init variables

Setup a timer in CTC mode to generate an interrupt every 10 mSec, (100 times a second).

 

Init Servo startup locations

Turn on interrupts

 

Do

               'Process Servo #1

               If  sensor #1 is on

                              Turn on Servo 1

               else

                              turn off Servo 1

               end if

              

               'Process Servo #2

               If  sensor #2 is on

                              Turn on Servo 2

               else

                              turn off Servo 2

               end if

 

               'Process anything else

               (Read a push button switch, flash an LED, etc)

               (Display IR status and servo status on LCD...)

Loop

 

Subroutine or Function, (whatever)            Turn On Servo 1

Function              Turn Off Servo 1

Function              Turn On Servo 2

Function              Turn Off Servo 2

 

Interrupt Routine:

Read IR sensor #1 and set a flag/bit/byte/variable On/Off for its state

Read IR sensor #2 and set a flag/bit/byte/variable On/Off for its state

return

 

 

In this case the status of the IR sensors is being continuously, (well, actually once every 10 mSec), updated.

In your Main Loop you take action based upon the status of the IR Sensors, but you don't actually even have to read them in the Main Loop, it is done in the background.

The decision to turn on and off the servos is based upon the status of the servo, and only takes a few instructions, (uSec's), so the Main Loop will actually process very quickly.

In this case the apparent servo update rate will depend upon the ISR rate, (10 mSec in this example).  The IR status can't change faster than that, (unless you change the ISR rate).

 

The Main loop is pretty simple. 

The key actions are done in the subroutines.

 

I see some timed delays for a given servo degrees rotation in your code.

 

If you want the IR sensor to trigger a servo turn for a given time period, to get a given rotation, then in the Interrupt routine if the IR sensor changes state, instead of setting a simple flag, initialize a countdown timer in mSec for the delay desired.

In the Main Loop, if the countdown timer is > 0 turn the Servo on.

(You can re-turn it on each pass through the loop, it doesn't matter!)

Decrement the counter by 10 mSec.

If the countdown timer = 0 then turn off the servo.  (And turn it off each pass, again it doesn't matter if you keep turning it off)

 

Note, also, that timing a servo's activity sometimes works fine, sometimes it doesn't.  (For cheap, open loop servos, without internal absolute position sensing)

The actual position might vary, based upon the load against the servo, the servo's operating voltage, (does the servo's voltage drop when both servos are running simultaneously), and the operating temperature, (the stickiness of the lubrication on the servos gears as a function of ambient temperature), etc.)

For true precision positioning, one generally wants exact position feedback on the servo's position.  This could be an optical encoder disk, a mechanical micro switch, a rotational or linear potentiometer, etc.

For some applications a simple timed rotation might be fine, or there might be feedback for a sensor further down the process, (Servo opens or closes X amount of mSec, operating a valve, while the control loop is controlled by a flow meter distal to the valve, etc.)

 

Good luck with your project!

 

JC

Last Edited: Thu. Nov 6, 2014 - 05:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

In the first place, take stock of your HW resolution.  Servo pulses happen every 20ms, so you'll never get e.g. a 150ms delay between movements.  It will be 140 or 160.

 

Given that, and given that the 20ms servo period is already ticking off, why not use it for your timing?

 

Here is a shell, no doubt with an inadvertent bug or two.  The point is, (possibly) check the sensor and (possibly) update the servos every servo tick, based on some state variables and some counters.

 

u8 servo1_cnt = 0;
u8 servo2_cnt = 0;
u8 servo1_state = 0;
u8 servo2_state = 0;

for (;;) // forever
{
    if (new_servo_period) // look at timer PWM overflow flag
    {
        clear_overflow_flag  // by writing a 1 to it
        if (sensor1 && (servo1_state == 0))
        {
            servo1_cnt = 8  // 160ms
            servo1_state = 1
            OCR1A = FIRST_POSITION
        }
        else if ((servo1_state == 1) && (--servo1_cnt == 0))
        {
            servo1_state = 2
            servo1_cnt = 8
            OCR1A = SECOND_POSITION
        }
        ....and so on for servo1, then same for servo2....
    }       
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you so much for the detailed explanation . 

indran

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 Thank you so much for the detailed explanation  and the shell code you provided. I am trying to make changes in my codes using your information. 

 

Cheers,

Indran

                                                                     

indran

Last Edited: Fri. Nov 7, 2014 - 05:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

  Thank you for pointing out the 150 ms issue. and also thank you so much shell code. I am trying to make changes in my code and see the impact.  Since  I am a biologist by profession, taking some time than others in debugging the stuff. 

thanks a lot..

 

Cheers

Indran

indran

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for pointing out my problems in the code. I am trying to modify my code and see the changes accordingly. 

Thank you for the wonderful help and support.

 

Regards,

Indran

indran