Go Down

Topic: How to have servo and linear actuator working on the same code (Read 253 times) previous topic - next topic

Erwan987

Hi, we are currently working on a flap mechanism for a university project. We are trying to control a servo (for rotation) and a linear actuator (to extend a part of the flap). They are connected to a slave Arduino that receives the rotation angles and extension/retraction command from a Master. The code for servo and linear actuator work on their own, but when they are combined together on the same code it doesn't and keeps crashing the Arduino after performing one extension. Can someone help us see where we made a mistake ? Thanks a lot :)

Code: [Select]

#include <Wire.h>
#include <Servo.h>
# define SLAVE_ADDRESS 0x60
byte x = 0x00;

Servo myservo;
Servo linearactuator;  // create servo object to control a servo
// twelve servo objects can be created on most boards

int posact = 0;    // variable to store the servo position
    // variable to specify which command to follow (41= Extension, 42= Retraction)

void setup() {
  Wire.begin(SLAVE_ADDRESS);                // join i2c bus with address #8
 
  Serial.begin(9600);  // start serial for output
  myservo.attach(3);
  linearactuator.attach(9);
  String value = "";
}

void loop() {
  delay(100);
 
  Wire.onReceive(receiveEvent); // register event
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
  int pos = Wire.read();    // receive byte as an integer
  if (pos <=40) {
    myservo.write(pos);
     Serial.println(pos); // print the integer
  }

//EXTENSION
  if (pos == 41){ //41 is an arbitrary input used for extension
    for (posact = 0; posact <= 150; posact += 1) { // goes from 0 degrees to 180 degrees in steps of 1 degree
      linearactuator.write(posact);              // tell LA to go to position in variable 'pos'
      Serial.println(pos);
      delay(20);                       // waits 20ms for the servo to reach the position
     
      }
      Serial.println(pos);
    //exit(0);
  }
  // RETRACTION
  if (pos == 42){ //42 is an arbitrary input used for retraction
    for (posact = 150; posact >= 0; posact -= 1) { // goes from 0 degrees to 180 degrees in steps of 1 degree
      linearactuator.write(posact);              // tell LA to go to position in variable 'pos'
      Serial.println(pos);
      delay(20);                       // waits 20ms for the servo to reach the position
     
      }
      //exit(0);
      Serial.println(pos);
  }
 
}
 



Robin2

AFAIK the line Wire.onReceive(receiveEvent); should be in setup() rather than in loop()

I have no idea whether that change would solve the problem.

Have you tried commenting out parts of the combined code to see where the problem lies?

If none of those ideas helps then post the two separate working programs.

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

wvmarle

The receiveEvent() function is an ISR, so using delay() in that function is a Very Bad Idea and can very well be the cause of your device hanging: the Servo library also uses interrupts for its timing.

Every time this receiveEvent() is called, you read just one byte, even if there are more in the I2C buffer. If you send commands faster than they can be handled, especially with the delay, the buffer might start to fill up. This may also cause problems. Do these movements in loop(), based on a flag set by the receiveEvent() function. Do it smartly (no delay() but millis() timing)  and you can move both at the same time.

Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

ardly

What exactly happens when the Arduino "crashes"?

Does you change the wiring between running the working code for the servo and theworking code for the actuator?
How is everything connected/powered?
"Facts do not cease to exist because they are ignored" - Aldous Huxley

Erwan987

Hi, thank you for your answers, we've now managed to get the actuator to extend. However, it makes a weird noise when fully extended, as if it was trying to extend even more. We also made it retract but only if the command is typed fast enough after the extension  :smiley-confuse: . The servo is working properly. We now need to have the L.A successfully extend and retract every time. What do you think is wrong with the coding ? Thank you.

Code: [Select]

#include <Wire.h>
#include <Servo.h>
# define SLAVE_ADDRESS 0x60
byte x = 0x00;

Servo myservo;
Servo linact;  // create servo object to control a servo
// twelve servo objects can be created on most boards
unsigned long previousMillis=0 ;
const long interval = 1000;

int posact = 0;    // variable to store the servo position
    // variable to specify which command to follow (41= Extension, 42= Retraction)

void setup() {
  Wire.begin(SLAVE_ADDRESS);                // join i2c bus with address #8
  Wire.onReceive(receiveEvent);
  Serial.begin(9600);  // start serial for output
  myservo.attach(3);
  linact.attach(9);
  String value = "";
}

void loop() {
 
 
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {

 
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
 
   

  int pos = Wire.read();    // receive byte as an integer
  if (pos <=40) {
    myservo.write(pos);
   
 
     Serial.println(pos); // print the integer
    }


  if (pos > 40) {

   //EXTENSION

  if (pos == 41){
    for (posact = 0; posact <= 180; posact += 1) { // goes from 0 degrees to 180 degrees in steps of 1 degree
      linact.write(posact);              // tell servo to go to position in variable 'posact'
     
      }
      Serial.println(pos);
    }
   
   
  // RETRACTION

  if (pos==42) {
    for (posact = 180; posact >= 0; posact -= 1) { // goes from 0 degrees to 180 degrees in steps of 1 degree
      linact.write(posact);              // tell servo to go to position in variable 'posact'
     
      }

      Serial.println(pos);
    }

   }

  }

 }




 






GoForSmoke

Don't put Serial in an ISR. Smartest move for the ISR is just grab the time and data for your sketch to act on. The ISR should be as short as possible, the sketch should not be blocked from catching the data and doing the work part.

You may need to pick up on some new coding habits to really get into MCU automation and learn to break tasks down to pieces rather than lump things together. Just why takes a little time to sink in but the ability to run many things together smoothly should do for an excuse till then.

1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

wvmarle

Quote
int pos = Wire.read();    // receive byte as an integer
Why is that an int, not a byte? The value from Wire.read can only be 0-255.

And indeed do all that work in loop() or functions called from it, not in the ISR (receiveEvent() for you). That won't end well. Serial uses interrupts, the Servo library probably as well. As long as you're in an ISR interrupts are switched off so that's asking for trouble.
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

GoForSmoke

The main reason I see why the ISR is so big is because the interrupt is used to get around the delay.

Erwan, the main lesson we try to get people to learn here is how to get rid of delays and reap the cycles saved.

By that approach you would have one task reading the sensor and another task positioning the servo. Neither would be inside the logic of the other, both of course would be in void loop() that should run > 10KHz.

BTW, 1-wire isn't real fast, how many times a second could you read that sensor?
1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

Go Up