4 IR sensors

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

Hi,

I use ATmega32A.
I want to interface 4 Modulated IR proximity sensors.

3 in front (left center and right) one at rear (center).

right now I read them in my main loop and decide the action after that.

But this approach has a problem as when bot is in motion and it sees something on right it tries to turn left for .5 secs. But if in that .5 sec there is another obstacle it ignores that and bangs in that.

If only there were ISR to handle it but there are only 3 external interrupt pins on m32 and 2 used for wheel encoder.

Can you suggest something here?

Thanks,
K

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

You need to write your main loop in such a way that it can register events while others are processed. Maybe a simple finite state machine?

I don't think external interrupts are required. You'd run into the same problem there too (how to process multiple events simultaneously).

/Jakob Selbing

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

Thanks,
I googled and discovered a lot about simple finite state machine, but the thing I didn't find is how I can implement one, or code examples, all I found is a lot of theory.

Can you suggest where to start, along those lines.

Thanks,
K

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

Quote:
Can you suggest where to start, along those lines.
I agree with jaksel, interrupts are not the solution. If you post some code, perhaps someone can suggest a direction.
swift1984m wrote:
If only there were ISR to handle it but there are only 3 external interrupt pins on m32 and 2 used for wheel encoder.
However, for what it's worth, although the 32A has only 3 external interrupts, you can squeeze 2 more out of it. Take a look at the Input Capture feature of TIMER1, and at the Analog Comparator. both can generate an interrupt. Input capture is easiest to use in this respect as it is a simple edge triggered unit. The analog comparator would require external components: 2 resistors to create a voltage divider that places some voltage between GND and VCC on one of the Analog Comparator inputs. Then you use the other input to detect edge transitions from your sensor.

Cheers,
JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

I have not yet ventured in the world of ADC's yet. (I am just a electronic hobbyist (By profession I am a Software application developer))

I will keep that piece of knowledge to put it in use soon.

Thank you so much JJ

I attach my code that worked on my ATmega8 (Now I use Atmega32A)

Regards,
K

Attachment(s): 

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

I usually code my state machines with a switch-case statement. The variable to switch on is an enum representing the different states. Transitions to other states is made by assigning the state variable in the various case-labels. Very simple yet powerful.

/Jakob Selbing

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

jaksel wrote:
I usually code my state machines with a switch-case statement. The variable to switch on is an enum representing the different states. Transitions to other states is made by assigning the state variable in the various case-labels. Very simple yet powerful.

Oh o.k., looks like I already have a FSM, if you see my code (Attached in previous post), in main loop I read state of all the sensors and then using rows of if conditions(instead of using a switch) to transit to an action.

But I still have the problem when a case is executing and another or same sensor see something else, and I want it to stop executing the current case and jump to another appropriate one.

So I will use Switch statement there and probably an enum or just a nibble to read in all sensors.

Any other suggestions there to improve on?

Thanks
K

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

swift1984m wrote:
I have not yet ventured in the world of ADC's yet.
Analog Comparator, not Analog-to-Digital Converter. The former can generate an external interrupt, the latter cannot.

If I understand you and your code correctly, what you're hoping to do is steer your robot away from an obstacle for a minimum period of time to ensure it has a good chance of getting clear of that obstacle, but you want it to continue to monitor the sensors during that time in order to permit it to change course again quickly. Your code has those sections commented out (I assume because you settled for the instantaneous approach), but I see that you were using _delay_ms(). That is a blocking function, and the reason you can't monitor your sensors during and avoidance manoeuver. Instead, set a flag to indicate the observed obstacle type, and store the current time. Then in another section of main, examine those flags, and compare the current time to the stored time of the last observed obstacle. If the difference is less than your desired threshold, continue the avoidance manoeuver. Once the threshold has expired, clear the flags and resume normal motion. Basicially, separate detection from action (which you've done), and don't use blocking delays. You'll also need an interrupt-driven time function:

#include 

volatile uint32_t timer0_milliseconds = 0;

ISR(TIM0_OVF_vect) {
  timer0_milliseconds++;
}

void configure_millisecond_timing(void) {
  // configure millisecond ISR
  // F_CPU == 8000000, prescaler = 64, resolution = 125: 8000000/64/125 = 1000
  TCCR0 = _BV(WGM01) | _BV(CS01) | _BV(CS00);  // CTC mode, prescaler = 8
  OCR0 = 124;
  TIMSK |= _BV(TOIE0);
}


uint32_t milliseconds(void) {
  uint32_t timer0_milliseconds_local;
  ATOMIC_BLOCK(ATOMIC_RESTORE_STATE) {
    timer0_milliseconds_local = timer0_milliseconds;
  }
  return timer0_milliseconds_local;
}

This is not a general purpose solution (you could write a timing system that adapts to changes in F_CPU, and doesn't completely take over the timer), but should get you started.

Then for your main code, separate detection from action, and use non-blocking time functions:

#define REVERSE_DELAY 500
#define NEW_COURSE_DELAY 2000

  static uint32_t obstacle_last_seen at;

  while(1) {
  
    // detection
    if (bit_is_set(IR_PIN, IR_BIT_LEFT)) {
      left=ON;
      obstacle_last_seen_at = millis();
    }
    else {
      left=OFF;
    }
    if (bit_is_set(IR_PIN, IR_BIT_CENTER)) {
      center=ON;
      obstacle_last_seen_at = millis();
    }
    else {
      center=OFF;
    }
    if (bit_is_set(IR_PIN, IR_BIT_RIGHT)) {
      right=ON;
      obstacle_last_seen_at = millis();
    }
    else {
      right=OFF;
    }
    if (bit_is_set(IR_PIN, IR_BIT_REAR)) {
      rear=ON;
      obstacle_last_seen_at = millis();
    }
    else {
      rear=OFF;
    }
    
    // action      
    if ((millis() - obstacle_last_seen_at) < REVERSE_DELAY) {
      steer_robot(GO_REVERSE);
    }
    else if ((millis() - obstacle_last_seen_at) < NEW_COURSE_DELAY) {

      if (left==ON && center==ON && right==ON)
        steer_robot(GO_HARD_RIGHT);
      else if (left==OFF && center==ON && right==OFF)
        steer_robot(GO_HARD_LEFT);
      else if (left==ON && center==OFF && right==OFF)
        steer_robot(GO_RIGHT);
      else if (left==OFF && center==OFF && right==ON)
        steer_robot(GO_LEFT);
      else if (left==ON && center==ON && right==OFF)
        steer_robot(GO_HARD_RIGHT);
      else if (left==OFF && center==ON && right==ON)
        steer_robot(GO_HARD_LEFT);
        
    }
    else
      steer_robot(GO_FORWARD);

  }

}

Just as an example. I'v made no attempt to maintain the specific manoeuvers from your original code.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

I have a tutorial using the classic stop-light problem. It is at http://www.proaxis.com/~wagnerj

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

You Guys are great, Thanks for your guidance. Do keep me posted if you find anything interesting on this in future, I will update with my final approach and results.
I couldn't try anything today (was in office), but will do it soon.

Thanks,
K

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

I just finished reading the Stop light problem that Jim suggested. This gave me a good idea about FSM and how to implement them in MCUs.
http://www.proaxis.com/~wagnerj

Googled and bumped into this article that gave me a good idea about how to go about designing the state machine for my particular purpose of robot obstacle avoidance.
http://www.mcgurrin.com/robots/?p=54

Now I am very enthusiastic to implement it.

Great end of the day...well its 3 am already. :(

Thanks,
K

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

JJ the idea of using the timer became bit complicated for me to complete it yet.

And another thing I am stuck with defining the states in which my obstacle avoiding bot can transition ... What are thumb rules to capture all states while making a stare diagram?

My internet is out I am using mobile phone.to send this ... I will post my state diagram that I made till now once internet is back ..

Thanks
K

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

swift1984m wrote:
JJ the idea of using the timer became bit complicated for me to complete it yet.
The code posted should work pretty much as is. I just looked at it again, and I did forget this:
#include 

I also omitted enabling global interrupts

sei();

You should put that somewhere near the beginning of main(), along with a call to configure_millisecond_timing(). Then you can find out what time it is in milliseconds since reset by calling millis();. Simple as that. If you're wondering how it works, drop me a PM with a specific question. We can carry it back to the forum when appropriate.

Quote:
And another thing I am stuck with defining the states in which my obstacle avoiding bot can transition ... What are thumb rules to capture all states while making a stare diagram?
You've pretty much already described the states. Review Jim's tutorial. You already seem to have identified that the detection of obstacles represents a separate FSM than that of the manoeuvers to avoid them. I'd stick with that approach. It is what will permit you to easily code a system that can continue monitoring for new obstacles even while mid-execution of a manoeuver that was triggered by an earlier obstacle.

Think of obstacle detection as an FSM that can transition from any of its states to any other of its states. Those states represent the identification of each type of obstacle to which you want to respond. The events that trigger a change of state are changes in input from your 4 IR sensors.

Now think of the avoidance manoeuvering as another FSM that has number of groups of linked states. Each group of linked states could be, say, a timed sequence of specific steering commands (as you have already demonstrated). The specific commands are those selected (by you) as most suitable for avoiding a certain type of obstacle. Whether or not a group can be prematurely interrupted by another, and what happens if it is, is also up to you. How a group of linked states naturally terminates will also depend on your design criteria.

The connection between the two FSM is that the state machine that directs the manoeuvers is triggered by events external to it, and those events are the states in the detection FSM.

Jim has a section in his tutorial about multiple state machines. He warns of pitfalls around multiple interrupts. That shouldn't be a problem for you here, interrupts are not necessary for a simple system like this. Although the timing code I proposed uses a timer interrupt, that is not directly related to either FSM. It is a global resource for telling time, nothing more.

In truth, you can code this as a single FSM without much trouble (the detection FSM is really just a mapping of your IR sensor data), but separating out the tasks simplifies each FSM a bit, and may help you see the big picture a bit better.

Good luck.
JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Thanks JJ,
I think I completed the code as per your suggestions, but unfortunately I cannot run my bot at this hour (3:45 am) and wake up my wife. I will try it tomorrow morning and update how it works.

The entire code is available in svn repo at https://code.google.com/p/avoibot/

I attache a copy for your perusal. I hope I understood it right. Do let me know your views.

Difficult part is to identify the states.

Thanks a lot for your time.
K

Attachment(s): 

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

swift1984m wrote:
I attache a copy for your perusal. I hope I understood it right. Do let me know your views.
Looks like you thought I made a typo in timer0_init(void). The correct value for OCR0 is 124, not 125. The timer resolution is zero-based, so for a resolution of 125, set TOP (in this case, OCR0) to 125 - 1, which is 124. Setting it to 125 sets a timer resolution of 126. This won't threaten the safety of the universe, but it will make your timing functions a bit slow, by 0.8% (126 / 125 = 1.008).
	static uint32_t obstacle_last_seen_at=0;

Variables declared static are automatically initialized to zero. This is required by the C standard.

Of the sixteen possible sensor input combinations, you only handle 9 of them. You have ommited all of the states that include REAR with one or more other sensors. What will happen if LEFT, CENTER, and REAR are high? You have no explicit states to handle these, but since you assign 'obstacle_last_seen_at' based on any combination of sensor input, the action constrained by REVERSE_DELAY will still run, even without an explicit state for that input. Also, since you have no 'default:' clause in your switch statement, the reverse action will continue until limited by NEW_COURSE_DELAY. Meaning, for these unhandled states the robot will go into reverse for the full interval of NEW_COURSE_DELAY. This of course will change dynamically as new sensor input comes in.

In fact, even when the robot sees an obstacle to the REAR, it will first respond by going backwards for REVERSE_DELAY. I don't think this is what you intended.

This is a good start, but you need to go back to the FSM diagram. Start by identifiying all possible input conditions. Since you have 4 sensors, each with 2 states, that's 16 input conditions. Once you've done that, you can devise a response for each of these conditions. Some, but not all, of those responses will have some commonalities. For example, you may want to go into reverse a bit when you see something to the right or left, before you steer in the opposite direction of the obstacle. This will not be the case if you see something to the rear.

More complex behaviour can be constructed by including the current motion of the robot in your FSM. This is where it gets harry, and where a second, independent FSM can be helpful.

This kind of complexity will be important when answering the question of what to do if all the sensors show an obstacle, i.e. your robot is surrounded... how do you get out of that?

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Hi JJ,
I am not understanding why is it going reverse always, I modified the code as following. I do not define few states in combination with rear because i thought that is a rare occurrence. Will implement those when I get these done :)

int main(void)
{
	/* input/output initializations */
	io_init();

	/* pwm setup for motor */
	pwm_init();

	/* timer0 setup for time tracking */
	timer0_init();
	
	/* other inits */
	init();
	
	/* initialize LCD display, cursor off */
	lcd_init(LCD_DISP_ON);
	lcd_clrscr();   /* clear display home cursor */

	/* Booting animation */
	booting();
	
	/* variable initializations */
	static uint32_t obstacle_last_seen_at;
	uint8_t left,right,center,rear;
	/* Main loop */		
	while(1){
		
		// detection
		if (bit_is_set(IR_PIN, IR_BIT_LEFT)) {
			left=ON;
			obstacle_last_seen_at = milliseconds();
		}
		else {
			left=OFF;
		}
		if (bit_is_set(IR_PIN, IR_BIT_CENTER)) {
			center=ON;
			obstacle_last_seen_at = milliseconds();
		}
		else {
			center=OFF;
		}
		if (bit_is_set(IR_PIN, IR_BIT_RIGHT)) {
			right=ON;
			obstacle_last_seen_at = milliseconds();
		}
		else {
			right=OFF;
		}
		if (bit_is_set(IR_PIN, IR_BIT_REAR)) {
			rear=ON;
			obstacle_last_seen_at = milliseconds();
		}
		else {
			rear=OFF;
		}
		
		// action
		if (rear==ON) steer_robot(M_FORWARD);
		if ((milliseconds() - obstacle_last_seen_at) < REVERSE_DELAY) {
			steer_robot(GO_REVERSE);
		}
		else if ((milliseconds() - obstacle_last_seen_at) < NEW_COURSE_DELAY) {

			if (left==ON && center==ON && right==ON)
			steer_robot(GO_HARD_RIGHT);
			else if (left==OFF && center==ON && right==OFF)
			steer_robot(GO_HARD_LEFT);
			else if (left==ON && center==OFF && right==OFF)
			steer_robot(GO_RIGHT);
			else if (left==OFF && center==OFF && right==ON)
			steer_robot(GO_LEFT);
			else if (left==ON && center==ON && right==OFF)
			steer_robot(GO_HARD_RIGHT);
			else if (left==OFF && center==ON && right==ON)
			steer_robot(GO_HARD_LEFT);
			
		}
		else steer_robot(GO_FORWARD);

	}			

	return 0;
}

I attache Pictures of my bot that would help you understand the problem in detail.

I didn't get the hang of state diagram still.

Thanks,
K

Attachment(s): 

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

It looks like you've reverted to your previous code, mostly. I think you were on the right tack before, you just need to handle all the states, even if you don't know what to do with them yet. Just make sure you have a 'case' or a 'default' clause to handle them all.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

joeymorin wrote:
It looks like you've reverted to your previous code, mostly. I think you were on the right tack before, you just need to handle all the states, even if you don't know what to do with them yet. Just make sure you have a 'case' or a 'default' clause to handle them all.

JJ

No I didn't change it to my previous code, If you look closely it is same code that you shared earlier.

With my previous code bot moves and avoid some obstacles but it gets stuck and moves forward and back rather vibrates in front of obstacles because I was not reversing the bot a bit on seeing obstacle. If I need to reverse I had to use delay function, but Now I want to do it with out delay function.

Now with the latest changes using the obstacle_last_seen_at logic it only moves backward (I see it is obvious from the code, see below).
How can I correct it what is that I am not doing right as per your suggestion.

        /* Main loop */
        while(1){
                // detection

                sensor=sensor_read();


                if (sensor==1 || sensor==2 || sensor == 4 || sensor == 8) obstacle_last_seen_at = milliseconds();  //always updates with new millis #1



                // action
                if ((milliseconds() - obstacle_last_seen_at) < REVERSE_DELAY) {
                        steer_robot(GO_REVERSE);
                }  // this sets executed immediately after the #1, and diff in millis will be always less than 500, bot will go reverse always.



                else if((milliseconds() - obstacle_last_seen_at) < NEW_COURSE_DELAY) {

                        switch(sensor){

Full listing of code can be viewed at https://code.google.com/p/avoibot/source/browse/PWM_Motor32/trunk/PWM_Motor32/PWM_Motor32.c

I am stuck with this, and I had big plans like implementing PID and all :(

I appreciate your help.
Regards,
K

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

swift1984m wrote:
Now with the latest changes using the obstacle_last_seen_at logic it only moves backward (I see it is obvious from the code, see below).
How can I correct it what is that I am not doing right as per your suggestion.
Does it always move backwards? When SHOULD it move backwards? When should it move forward?

I think you need to take a break from the C coding, and think about how the robot should behave. Then try to make a simple state diagram. Then implement the state diagram.

Note that the current solution is not exactly ideal for state machine implementation. Further you have some parts not quite correct, e.g.

if (sensor==1 || sensor==2 || sensor == 4 || sensor == 8)

is pretty dangerous, and

case S_LEFT_CENTER_RIGHT:
 steer_robot(GO_HARD_RIGHT);

looks strange to me.

/Jakob Selbing

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

jaksel wrote:
swift1984m wrote:

I think you need to take a break from the C coding, and think about how the robot should behave. Then try to make a simple state diagram. Then implement the state diagram.

I think you are right, I might be out of my mind already.

I am sleeping 3 am from past one week. I need a break from C.

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

swift1984m wrote:
If you look closely it is same code that you shared earlier.
That was just an example. As I mentioned, I made no effort to maintain the specific manoeuvers shown in your original code.
jaksel wrote:
I think you need to take a break from the C coding, and think about how the robot should behave. Then try to make a simple state diagram. Then implement the state diagram.
I agree. You really need to go back to pen and paper and get the FSM straight in your head. Trying to code without a clear idea of what you're trying to accomplish is literally like stabbing in the dark.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]