Can Somebody Please Explain Interrupts to Me?

Hi all,

I’ve recently made a rover with and Electron and Arduino Mega. So basically the Electron transmits data to the Mega for how to drive and stuff like that. Although, there are a few background functions that are in the regular loop that I feel are slowing down the main program. There are two background features(a solar panel that is mounted on a servo that turns to the brightest side of the rover and an accelerometer that reads every loop). Can I somehow put those in an interrupt to take them out of the main loop but still function in the background? I don’t mean to keep playing the "I’m twelve card(I am :joy: ) " but I thought interrupts were a totally different thing meant for sensor breakout boards…

-Thanks, Jack

Hey Jack,

You can think of interrupts as an “alert” that you get instead of continuously checking.

Example, the controller will sleep and once a button is pressed, the controller receives and interrupt and wakes up from sleep, looks at the interrupt, do stuff and go back to sleep.

The non-interrupt way is that the controller will keep asking “is the button pressed” while juggling other tasks.

I hope that explanation gives you some idea of what interrupts are for. :slight_smile:

With regards to your user code, if you can share with us, we can see how it can be executed more efficiently.

1 Like

As @kennethlimcp said looking at your code might give us the chance to locate other points of improvement maybe avoiding interrupts for your use case.
I got the feeling the solar panel stuff could easily be done in loop() if you keep your loop() logic non-blocking.
Or you could use Software Timers for some stuff. These are somehow like interrupts but not as restrictive.
Although there are cases where you won’t get around interrupts (e.g. very fast or precisely timed responses).

One analogy for interrupts I usually use is a telephone ring or a door bell.
You don’t want to be permanently checking the phone or door to see if anybody needs your attention. You just get on with your normal routine, but once the phone rings or the door bell goes, you drop your stuff and attend to the “interrupt” ASAP, once that’s done you get on from where you left off (at least the controler does - real life sometimes works differently :sunglasses: … what was I doing last :confused: :see_no_evil:)

@ScruffR @kennethlimcp

Thanks both of you for your suggestions! Here is my code although it is a little long. If you see that I have a servo interrupt that’s for a hardware thing not related to this thread… Sorry it is a little long the solar panel thing is about half way through but I bolded it. Also, if you see any ways to possibly make the delays that might be bogging it up go away that would be greatly appreciated as well!

include <Servo.h>
include <Wire.h>
include <Adafruit_NeoPixel.h>
Servo solarmotor;

Servo clawmotor;
int fval = 0;
int pin = A5;// the fsr for rover 3
const int solarInterrupt = 33;

const int clawInterrupt = 43;
int leftDistance, rightDistance;
int forwardLeftDistance, forwardRightDistance;
const int dangerThresh = 10;

int count = 0;
int frontLightPin = A0;
int backLightPin = A1;
int frontLight = 0;
int backLight = 0;
int light = 0;
define PIN            22//for the neopixel
define NUMPIXELS      12

//Sonar 1 
int echoPin1 =7;
int initPin1 =8;
int distance1 = 0;

//Sonar 2
int echoPin2 = 5;
int initPin2 =6;
int distance2 = 0;

//Sonar 3
int echoPin3 = 4;
int initPin3 = 11;
int distance3 = 0;

//Sonar 4
int echoPin4 =31;
int initPin4 =30;
int distance4 =0;

const int awarenessPin = 35;

//m1
const int inA1 = 24;
const int inA2 = 26;
int speedPinA = 9;
//m2 
const int inB1 = 25;
const int inB2 = 27;
int speedPinB = 10;
int LED = 13;
int x = 0;
const int solenoidPin = 33;
const int xPin = 2;    // X output of the accelerometer
const int yPin = 3;   // Y output of the accelerometer

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB);
int delayval = 500; // delay for half a second

void setup() {
	// put your setup code here, to run once:
	Serial.begin(9600);
	Wire.begin(8); // for i2c 
	Wire.onReceive(receiveEvent);
	pixels.begin(); 
	pinMode(initPin1, OUTPUT);// for the ultrasounds
	pinMode(echoPin1, INPUT);
	pinMode(initPin2, OUTPUT);
	pinMode(echoPin2, INPUT);
	pinMode(initPin3, OUTPUT);
	pinMode(echoPin3, INPUT);
	pinMode(initPin4, OUTPUT);
	pinMode(echoPin4, INPUT);

	pinMode(inA1,OUTPUT);
	pinMode(inA2,OUTPUT);
	pinMode(speedPinA,OUTPUT);
	pinMode(inB1,OUTPUT);
	pinMode(inB2,OUTPUT);
	pinMode(speedPinB,OUTPUT);

	pinMode(xPin, INPUT);
	pinMode(yPin, INPUT);
	pinMode(solenoidPin, OUTPUT);
	digitalWrite(solenoidPin, LOW);
	pinMode(awarenessPin, OUTPUT);

	solarmotor.attach(32);

	clawmotor.attach(42);
	pinMode(solarInterrupt, OUTPUT);

	pinMode(clawInterrupt, OUTPUT);

	digitalWrite(clawInterrupt, LOW);
}

void receiveEvent(int bytes) {
	x = Wire.read();  
	Serial.print(x);// read one character from the I2C
}

void loop() {
	// put your main code here, to run repeatedly:
	// for the motor drive
	count = count + 1;
	fval = analogRead(pin);
	distance1 = getDistance(initPin1, echoPin1);
	//printDistance(1, distance1);
	delay(150);
	/*
if(distance1 > 20){
	digitalWrite(awarenessPin, HIGH);
}
else{
digitalWrite(awarenessPin, LOW); 
}
*/
	distance2 = getDistance(initPin2, echoPin2);
	//printDistance(2, distance2);
	delay(150);

	distance3 = getDistance(initPin3, echoPin3);
	// printDistance(3, distance3);
	delay(150);

	distance4 = getDistance(initPin4, echoPin4);
	//printDistance(4, distance4);

	delay(500);

	rightDistance = distance1;
	leftDistance = distance2;
	forwardRightDistance = distance3;
	forwardLeftDistance = distance4;
	// for the accelerometer now
	int pulseX, pulseY;
	// variables to contain the resulting accelerations
	int accelerationX, accelerationY;

	// read pulse from x- and y-axes:
	pulseX = pulseIn(xPin, HIGH);
	pulseY = pulseIn(yPin, HIGH);

	// convert the pulse width into acceleration
	// accelerationX and accelerationY are in milli-g's:
	// earth's gravity is 1000 milli-g's, or 1g.
	accelerationX = ((pulseX / 10) - 500) * 8;
	accelerationY = ((pulseY / 10) - 500) * 8;
	if(accelerationX <= -80 && accelerationX >= -450){
		digitalWrite(awarenessPin, HIGH);
	}
	else{
		digitalWrite(awarenessPin, LOW);
	}
	// for the communication between electron and arduino mega
	if (x == '0') {
		digitalWrite(LED, HIGH);
		delay(200);
		digitalWrite(LED, LOW);
		delay(200);
		Serial.print("Hello");
		forward();
		if (forwardRightDistance < 7 && forwardLeftDistance < 7){
			delay(2000);
			compareDistance();
		}
		else{
			forward();
		}
		if(accelerationX >= -40 && accelerationX <= -300){
			digitalWrite(inA1, LOW);
			digitalWrite(inA2, HIGH);
			digitalWrite(inB1, LOW);
			digitalWrite(inB2, HIGH);
			analogWrite(speedPinA, 125);
			analogWrite(speedPinB, 125);
		}
		else{
			digitalWrite(inA1, LOW);
			digitalWrite(inA2, HIGH);
			digitalWrite(inB1, LOW);
			digitalWrite(inB2, HIGH);
			analogWrite(speedPinA, 255);
			analogWrite(speedPinB, 255);
		}
	}
	if (x == '1') {
		digitalWrite(LED, HIGH);
		delay(200);
		digitalWrite(LED, LOW);
		delay(200);
		Serial.print("hi");
		backWard();
	}
	if (x == '2') {
		digitalWrite(LED, HIGH);
		delay(200);
		digitalWrite(LED, LOW);
		delay(200);
		Serial.print("today");
		sTop();
	}
	//If value received is 3 blink LED for 400 ms
	if (x == '3') {
		digitalWrite(LED, HIGH);
		delay(400);
		digitalWrite(LED, LOW);
		delay(400);
		turnLeft();
		delay(1000);
		sTop();
		delay(6000);
		if(leftDistance < 6){
			sTop();
			delay(100);
			if(rightDistance > 6){
				turnRight();
				delay(500);
				sTop();
				int distanceFwd = leftDistance + rightDistance;
				if (distanceFwd > dangerThresh) //if path is clear
				{
					forward(); //move forward
				}
				else{
					delay(4000);
				}
			}

		}

	}
	if (x == '4') {
		digitalWrite(LED, HIGH);
		delay(200);
		digitalWrite(LED, LOW);
		delay(200);
		turnRight();
		delay(1000);
		sTop();
		delay(6000);

		if(rightDistance < 6){
			sTop();
			delay(100);
			if(leftDistance > 6){
				turnLeft();
				delay(500);
				sTop();
				delay(300);
				int distanceFwd =  leftDistance &&  rightDistance;
				if (distanceFwd > dangerThresh) //if path is clear
				{
					forward(); //move forward
				}
				else{
					delay(4000);
				}

			}

		}
	}
	if (x == '5') {
		digitalWrite(LED, HIGH);
		delay(200);
		digitalWrite(LED, LOW);
		delay(200);
		turnRight();
		delay(500);
		sTop();
		delay(6000);

		if(rightDistance < 6){
			sTop();
			delay(100);
			if(leftDistance > 6){
				turnLeft();
				delay(500);
				sTop();
				delay(300);
				int distanceFwd = forwardLeftDistance + forwardRightDistance;
				if (distanceFwd > dangerThresh) //if path is clear
				{
					forward(); //move forward
				}
				else{
					delay(4000);
				}

			}

		}
	}

	if (x == '6') {
		digitalWrite(LED, HIGH);
		delay(400);
		digitalWrite(LED, LOW);
		delay(400);
		turnLeft();
		delay(500);
		sTop();
		delay(6000);
		if(leftDistance < 6){
			sTop();
			delay(100);
			if(rightDistance > 6){
				turnRight();
				delay(500);
				sTop();
				
				if (forwardRightDistance > 6 && forwardLeftDistance > 6) //if path is clear
				{
					forward(); //move forward
				}
				else{
					delay(4000);
				}
			}

		}
	}

	if(x == '7'){
		
		if (forwardRightDistance > 6 && forwardLeftDistance > 6 || forwardRightDistance <= 0 || forwardLeftDistance <= 0){
			forward();

			if(accelerationX <= -40 && accelerationX >= -450){
				digitalWrite(inA1, LOW);
				digitalWrite(inA2, HIGH);
				digitalWrite(inB1, LOW);
				digitalWrite(inB2, HIGH);
				analogWrite(speedPinA, 125);
				analogWrite(speedPinB, 125);
				digitalWrite(awarenessPin, HIGH);
			}
			else{
				digitalWrite(inA1, LOW);
				digitalWrite(inA2, HIGH);
				digitalWrite(inB1, LOW);
				digitalWrite(inB2, HIGH);
				analogWrite(speedPinA, 255);
				analogWrite(speedPinB, 255);
				digitalWrite(awarenessPin, LOW);
			}
		}
		//if(forwardRightDistance <= 0){
		// forward();
		// }
		//if(forwardLeftDistance <= 0){
		//  forward();
		//}
		else{
			sTop();
			delay(1000);
			backWard();
			delay(1500);
			compareDistance();
		}

		if(x == '8'){
			int tick = 0;
			tick = tick + 1;
			clawmotor.write(90);
			while(tick == 10000){
				clawmotor.write(180);
			}
		}
		/*  
if(forwardRightDistance < 7 && forwardLeftDistance > 7){// if right side is greater that the left
sTop();
delay(600);
if(leftDistance > 15){
	turnLeft();
}
if(rightDistance > 15){
	turnRight();
}
if(rightDistance > 15 && leftDistance > 15){
	compareDistance();
}
}

if(forwardRightDistance > 7 && forwardLeftDistance < 7){
sTop();
delay(600);
if(leftDistance > 15){
	turnLeft();
}
if(rightDistance > 15){
	turnRight();
}
}
else{
	compareDistance();
	}
*/ 

	}

	**frontLight = analogRead(frontLightPin);**
	>  backLight = analogRead(backLightPin);**
	>  //Serial.print("back");**
	>  //Serial.print(backLight);**
	> // Serial.print("front");**
	>  //Serial.print(frontLight);**

	> if(frontLight > backLight ){**
		> delay(100);**
		> digitalWrite(solarInterrupt, HIGH);**
		> delay(200);**
		> solarmotor.write(30);**

		> digitalWrite(solarInterrupt, LOW);**
		> }**
	> if(frontLight < backLight ){**
		> delay(100);**
		> digitalWrite(solarInterrupt, HIGH);**
		> delay(200);**
		> solarmotor.write(80);**
		> digitalWrite(solarInterrupt, LOW);**


	}

	/*
if(frontLight > backLight && frontLight > 1000){
delay(100);
solarmotor.write(80);
}
if(frontLight < backLight && backLight > 1000){
delay(100);
solarmotor.write(0);
}
*/
	Serial.print(fval);
	delay(100);
	Serial.print(",");
	if(fval < 80){
		clawmotor.write(180);
		delay(500);
	}
	if(fval > 81){
		clawmotor.write(90);
		delay(500);
	}


	if (forwardRightDistance > 6 && forwardLeftDistance > 6 || forwardRightDistance <= 0 || forwardLeftDistance <= 0){
		pixels.setPixelColor(1, pixels.Color(0, 255, 0));
		pixels.setPixelColor(2, pixels.Color(0, 255, 0));
		pixels.setPixelColor(3, pixels.Color(0, 255, 0));
		pixels.setPixelColor(4, pixels.Color(0, 255, 0));
		pixels.setPixelColor(5, pixels.Color(0, 255, 0));
		pixels.setPixelColor(6, pixels.Color(0, 255, 0));
		pixels.setPixelColor(7, pixels.Color(0, 255, 0));
		pixels.setPixelColor(8, pixels.Color(0, 255, 0));
		pixels.setPixelColor(9, pixels.Color(0, 255, 0));
		pixels.setPixelColor(10, pixels.Color(0, 255, 0));
		pixels.setPixelColor(11, pixels.Color(0, 255, 0));
		pixels.setPixelColor(12, pixels.Color(0, 255, 0));

	}
	else{ 
		

		pixels.setPixelColor(1, pixels.Color(255, 0, 0));
		pixels.setPixelColor(2, pixels.Color(255, 0, 0));
		pixels.setPixelColor(3, pixels.Color(255, 0, 0));
		pixels.setPixelColor(4, pixels.Color(255, 0, 0));
		pixels.setPixelColor(5, pixels.Color(255, 0, 0));
		pixels.setPixelColor(6, pixels.Color(255, 0, 0));
		pixels.setPixelColor(7, pixels.Color(255, 0, 0));
		pixels.setPixelColor(8, pixels.Color(255, 0, 0));
		pixels.setPixelColor(9, pixels.Color(255, 0, 0));
		pixels.setPixelColor(10, pixels.Color(255, 0, 0));
		pixels.setPixelColor(11, pixels.Color(255, 0, 0));
		pixels.setPixelColor(12, pixels.Color(255, 0, 0));

	}


	// pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
	// pixels.setPixelColor(i, pixels.Color(0,150,0)); // Moderately bright green color.

	pixels.show(); // This sends the updated pixel color to the hardware.

}//WHERE VOID LOOP ENDS!!!`````````````````````````````````````````````````````

int getDistance (int initPin, int echoPin){

	digitalWrite(initPin, HIGH);
	delayMicroseconds(10); 
	digitalWrite(initPin, LOW); 
	unsigned long pulseTime = pulseIn(echoPin, HIGH); 
	int distance = pulseTime/58;
	return distance;

}


///*
void printDistance(int id, int dist){
	///*
	Serial.print(id);
	
	for (int i = 0; i <= dist; i++) { 
		Serial.print("-");
	}
	
	Serial.print(dist, DEC);
	Serial.println(" cm");
	
}
//*/
// for the motors
void backWard(){
	digitalWrite(inA1, HIGH);
	digitalWrite(inA2, LOW);
	digitalWrite(inB1, HIGH);
	digitalWrite(inB2, LOW);
	analogWrite(speedPinA, 255);
	analogWrite(speedPinB, 255);
}

void forward(){
	digitalWrite(inA1, LOW);
	digitalWrite(inA2, HIGH);
	digitalWrite(inB1, LOW);
	digitalWrite(inB2, HIGH);
	analogWrite(speedPinA, 255);
	analogWrite(speedPinB, 255);
	// if the rover is driving down a slope

}

void sTop(){
	digitalWrite(inA1, LOW);
	digitalWrite(inA2, LOW);
	digitalWrite(inB1, LOW);
	digitalWrite(inB2, LOW);
	analogWrite(speedPinB, 0);
	analogWrite(speedPinA, 0);
}

void turnLeft(){
	digitalWrite(inA1, HIGH);
	digitalWrite(inA2, LOW);
	digitalWrite(inB1, LOW);
	digitalWrite(inB2, HIGH);
	analogWrite(speedPinA, 255);
	analogWrite(speedPinB, 255);
}

void turnRight(){
	digitalWrite(inA1, LOW);
	digitalWrite(inA2, HIGH);
	digitalWrite(inB1, HIGH);
	digitalWrite(inB2, LOW);
	analogWrite(speedPinA, 255);
	analogWrite(speedPinB, 255);
}

void compareDistance()
{
	if (leftDistance > rightDistance) //if left is less obstructed 
	{
		turnLeft();//turn left
		delay(2000); 
	}
	else if (rightDistance > leftDistance) //if right is less obstructed
	{
		turnRight();//turn right
		delay(1000);
	}
	else //if they are equally obstructed
	{
		backWard();
		delay(400);
		turnRight(); //turn 180 degrees
		delay(2000);
	}
}

Jack, you should wrap your code like this,

``` cpp
your code here
```

rather than in block quotes to make it look pretty :wink:.

Is there anything that you know of that teaches a beginner the proper or recommended ways of programming in C++ ?

Like when to use a Software Timer vs an Interrupt, and how to write efficient code that is not blocking ect...

You can learn alot by studying how all the different libraries are written but I would love a short course on how to code well and avoid the most common beginner mistakes.

This is too funny to put here because its true.

via Imgflip Meme Generator

@RWB @ScruffR @Ric @kennethlimcp

I mean I basically taught myself to code so I don’t really know much about how to wrap or how the code is blocked although it does seem interesting.

I think I’m probably going to rewrite the whole thing to make it work better that’s not blocking and stuff like that, now that I know my code has a lot of that in it :sweat_smile: .

All these delay() calls are blocking the controler from running anything else while just idling inside delay().
To keep the program responsive, don't use delays of any kind.

@ScruffR

Ok, I take it unsigned longs would be better for delays then :wink: .

I noticed the lack of anything Particle in your code…

> //Sonar 4
> int echoPin4 =31;
> int initPin4 =30;
> int distance4 =0;

is that an Arduino Mega?

Try to learn the how to move a servo, change the neopixels and get the distances; each without using any delays.

1 Like

@BulldogLowell

Ok

In the motors where I used to say turnLeft(); followed by a delay for how long it should do that, I changed it to turnLeft(int duration); so now it says turnLeft(2000); would that still slow it down?

The problem is your hardware choice isn’t 1:1 compatible with any Particle device. Perhaps refactor your code for Photon, if you have one…

if you could, also re-post your code using code tags being careful to NOT include those leading angled braces, we can show you how to do some of this.

@BulldogLowell, I took the liberty to repost the code correctly.

@JackD12, the magic “word” here may be FSM (Finite State Machine). FSM’s are the most used methods to a) creating logically flowing code and b) avoiding blocking code.

What do you mean?

@JackD12, look at your earlier posting of your code. I removed the > injected by the quote command and reposted with the code post and prefixes.

1 Like

@peekay123

Thanks!

@BulldogLowell I removed a lot of the unnecessary delays and it definitely operates a lot smoother!

1 Like

You could look towards unblocking your code with a more functional approach. Take a look at this and how it is reading every 100mS and printing every 1000mS. This is using a method that polls millis() and executes on defined intervals:


// function definitions
void displayDistances(int interval);
int getDistance(EchoSensor sensor);
void readDistanceSensors(int interval);

//

struct EchoSensor{
  int echoPin;
  int initPin;
};

const EchoSensor echoSensor[4] = {
  { 7,  8}, //Sonar 0 
  { 5,  6},
  { 4, 11},
  {31, 30}
};

int distance[4];

void setup() 
{
  Serial.begin(9600);
  for(int i = 0; i < sizeof(echoSensor)/sizeof(echoSensor[0]); i++)
  {
    pinMode(echoSensor[i].echoPin, INPUT);
    pinMode(echoSensor[i].initPin, OUTPUT);
  }
}

void loop() 
{
  readDistanceSensors(100); // 100 mS interval
  displayDistances(1000); // 1000 mS interval
}

void displayDistances(int interval)
{
  static unsigned long lastMillis = 0;
  if(millis() - lastMillis > interval) 
  {
    for(int i = 0; i < sizeof(echoSensor)/sizeof(echoSensor[0]); i++)
    {
      Serial.print("\ndistance ");
      Serial.print(i);
      Serial.print(":\t");
      Serial.println(distance[i]);
    }
    lastMillis += interval;
  }
}

void readDistanceSensors(int interval)
{
  static unsigned long lastMillis = 0;
  if(millis() - lastMillis > interval)
  {
    for(int i = 0; i < sizeof(echoSensor)/sizeof(echoSensor[0]); i++)
    {
      distance[i] = getDistance(echoSensor[i]);
    }
    lastMillis += interval;
  }
}

int getDistance(struct EchoSensor sensor)
{
  digitalWrite(sensor.initPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(sensor.initPin, LOW); 
  unsigned long pulseTime = pulseIn(sensor.echoPin, HIGH); 
  return pulseTime/58;
}

note use of arrays and how compact loop() becomes.

Now... using echoSensors like this is also blocking because pulseIn() holds and waits for the response... there are other non-blocking methods where that not need to be that way.

The key is to do this sort of thing for the rest of your program...

(not tested but compiles for Arduino)

2 Likes

So if a beginner wants to learn how to properly code studying how to properly setup a FSM (Finite State Machine) would be a recommended?

@BulldogLowell

Wow I will definitely sub that in for my code!

Thanks for taking the time to write that out because I can gaurantee you I NEVER would have thought to do that :sweat_smile: !