2 Arduinos communicating through digital pins & interrupts

I am trying to make a device that runs a stepper motor at the same time as collecting force data. I cannot find a way to do this with only one Arduino. Collecting data with the same Arduino causes the stepper to stutter. I now have 2 Arduinos, one for data collection, the other for motor control.
I have abstracted the problem to make the motor side drive 2 LED's. One to signify the motor going forward and the other for backward. There are 2 command pins that are tied to interrupts on the motor side, the motor side then sends back a signal to say if the motor is busy or not, which is tied to an interrupt on the data side.
Here is the code for PusherControlSide.ino

//PINS
const int Motor_Busy_Pin = 4;
const int Comms_Pin_A = 5;
const int Comms_Pin_B = 6;
//must add in buttons eventually

//Variables 
float val = 0;
//float calibration_factor = -234550; //-7050 worked for my 440lb max scale setup

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);      // Change to better buad rate later
  pinMode(Motor_Busy_Pin, INPUT);
  pinMode(Comms_Pin_A, OUTPUT);
  pinMode(Comms_Pin_B, OUTPUT);
  digitalWrite(Comms_Pin_A,LOW);
  digitalWrite(Comms_Pin_B,LOW);              
  attachInterrupt(digitalPinToInterrupt(Motor_Busy_Pin), wait4Motor_ISR, CHANGE);
  //when the Motor_Busy_Pin goes from low to high this interrupt will trigger
}//void setup()

/*
 * The Motor side will follow this truth table
 *    | A | B | Y 
 *    | 0 | 0 | None
 *    | 0 | 1 | Forward
 *    | 1 | 0 | Backward
 *    | 1 | 1 | Trial
 */

void loop() {
  //test loop for demo
  Serial.println("start Loop");
  delay(5000);
  Serial.println("Forward");
//  delay(5000);
  digitalWrite(Comms_Pin_A,LOW);
  digitalWrite(Comms_Pin_B,HIGH); 
  Serial.println("Backward");
//  delay(5000);
  digitalWrite(Comms_Pin_A,HIGH);
  digitalWrite(Comms_Pin_B,LOW);
  Serial.println("Trial");
//  delay(5000);
  digitalWrite(Comms_Pin_A,HIGH);
  digitalWrite(Comms_Pin_B,HIGH);
  
}//void loop()


/*
 * Checks to see which signal is being sent to the 
 * motor and hangs or collects data accordingly
 * it also clears the signal back to 00
 * 
 */
void wait4Motor_ISR(){
   if(digitalRead(Motor_Busy_Pin) == LOW){
    digitalWrite(Comms_Pin_A,LOW);
    digitalWrite(Comms_Pin_B,LOW);
    delay(5000);
   }else{
   
    if(digitalRead(Comms_Pin_A) == HIGH && digitalRead(Comms_Pin_B) == HIGH){
//      while(digitalRead(Motor_Busy_Pin) == HIGH){Serial.print(scale.get_units(), 3);}
    
      int cycleCount = 0;
      while(digitalRead(Motor_Busy_Pin) == HIGH){cycleCount++;}
//      Serial.println(cycleCount);
    }else{
      int cycleCount = 0;
      while(digitalRead(Motor_Busy_Pin) == HIGH){cycleCount++;}
//      Serial.println(cycleCount);
    }//else if 
   }//else if Motor_Busy_Pin
}//void wait4Motor_ISR()

Here is the code for PusherMotorSide.ino

//Library includes
//#include <Stepper.h>  // for stepper motor

// more stepper stuff
//const int stepsPerRevolution = 200;
//Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

// PINS
const int Motor_Busy_Pin = 4;
const int Comms_Pin_A = 3;
const int Comms_Pin_B = 2;
//For LED DEMO
const int ForwardLED_PIN = 11;
const int BackwardLED_PIN = 12;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);      // Change to better buad rate later
  pinMode(Motor_Busy_Pin, OUTPUT);
  digitalWrite(Motor_Busy_Pin,LOW);
  pinMode(Comms_Pin_A, INPUT);
  pinMode(Comms_Pin_B, INPUT);  
  attachInterrupt(digitalPinToInterrupt(Comms_Pin_A), inputRecieved_ISR, CHANGE);
  attachInterrupt(digitalPinToInterrupt(Comms_Pin_B), inputRecieved_ISR, CHANGE);

  //For LED Demo
  pinMode(ForwardLED_PIN, OUTPUT);
  pinMode(BackwardLED_PIN, OUTPUT);
  digitalWrite(ForwardLED_PIN, LOW);  
  digitalWrite(BackwardLED_PIN, LOW);
}//void setup()

void loop() {
  // put your main code here, to run repeatedly:
}//void loop()

void inputRecieved_ISR(){
  if(digitalRead(Comms_Pin_A) == LOW && digitalRead(Comms_Pin_B) == HIGH){
      digitalWrite(Motor_Busy_Pin,HIGH);
//      myStepper.setSpeed(800);
//      myStepper.step(-50);
      //For LED Demo
      digitalWrite(ForwardLED_PIN, HIGH); 
//      for(int i = 0; i < 100000; i++){}
      delay(2000);
      digitalWrite(ForwardLED_PIN, LOW);

      digitalWrite(Motor_Busy_Pin,LOW);
  }//if(digitalRead(Comms_Pin_A) == LOW && digitalRead(Comms_Pin_B) == HIGH)
    
   if(digitalRead(Comms_Pin_A) == HIGH && digitalRead(Comms_Pin_B) == LOW){
      digitalWrite(Motor_Busy_Pin,HIGH);
//      myStepper.setSpeed(800);
//      myStepper.step(50);
      //for LED Demo
      digitalWrite(BackwardLED_PIN, HIGH); 
//      for(int i = 0; i < 100000; i++){}
      delay(2000);
      digitalWrite(BackwardLED_PIN, LOW);
      
      digitalWrite(Motor_Busy_Pin,LOW);
    }//if(digitalRead(Comms_Pin_A) == HIGH && digitalRead(Comms_Pin_B) == LOW)
    
    if(digitalRead(Comms_Pin_A) == HIGH && digitalRead(Comms_Pin_B) == HIGH){
      digitalWrite(Motor_Busy_Pin,HIGH);
//      myStepper.setSpeed(800);
//      int steplen = 18;
//      for(int i = 0; i < 6; i++){
//        for(int j = 0; j < 188; j++){
//          myStepper.step(steplen);
//          //get data                       original code makes stuttering
//        }//for(int j = 0; j < 188; j++)
//        steplen *= -1;
//      }//for(int i = 0; i < 6; i++)

      //for LED Demo
      for(int i = 0; i < 6; i++){
        if(i%2){
          digitalWrite(ForwardLED_PIN, HIGH);
          delay(2000); 
//          for(int i = 0; i < 100000; i++){}
          digitalWrite(ForwardLED_PIN, LOW);
        }else{
          digitalWrite(BackwardLED_PIN, HIGH); 
//          for(int i = 0; i < 100000; i++){}
          delay(2000);
          digitalWrite(BackwardLED_PIN, LOW);
        }//else if i%2
      }//for(int i = 0; i < 6; i++)
      digitalWrite(Motor_Busy_Pin,LOW);
    }//if(digitalRead(Comms_Pin_A) == HIGH && digitalRead(Comms_Pin_B)
}//void inputRecieved_ISR()

here is a picture of my config

Currently, the device only flashes the forward LED once every 4 seconds. A far cry from the Demo routine detailed in PusherControllSide.ino. What am I missing here? Are the routines going too fast? I appreciate your feedback...

Did you analyze this, before moving to a different solution of multiple processors? Where are the delays that cause this happening? Perhaps they are caused by the way you coded it, and it can be fixed.

Using two Arduinos may not be the worst idea, but accomplishing the total functionality shouldn't need interrupts at all.

It only makes doing quite a bit harder, really.

That's two curve balls you throwing yourself.

Having seen what ppl do with one microprocessor and standard well-known programming techniques, I'm with @anon57585045 that you should be able to get away with just one.

a7

Perhaps you can point me in the right direction.
This device is going to use a stepper motor to drive a push prod against a stalk of Corn. In the push prod lies a scale that we will read "continuously" to analyse the anchorage of the stalk.

The research team has another device that accomplishes this same goal but is much bulkier and more of a pain to walk around the corn field. It uses an analog scale and drives the same stepper motor the same way.

You can see this commented out in the code
3 trials (for ( i < 6))
188 repitions of 18 step "strides"
At the end of each stride is a measurement. Making for a sample rate of 376 samples per period and a graph that sort of looks like a bell curve repeated over 3 periods.

This new digital scale is lighter and much easier to use in the field. But the function for reading the data is based on Serial.print() which interrupts the MCU long enough to create the stutter. This is supported by the fact that we can remove the data collection and the stepper runs flawlessly.

The end goal is to have this device send the data to an iPad over Bluetooth. Most of the Bluetooth devices I have experience with are connected to the MCU through some sort of Serial connection, so I don't see a way around this issue. I'm open to any ideas.

So I decided that the best thing I could come up with is to have the data collected and dealt with by one MCU. It can be interrupted by the Serial connection to its hearts content, it just needs to gather as many data points as before. This outputs to 2 digital pins that follow the truth table. When those values change, this interrupts the motor side MCU and it follows the truth table to execute the correct routine for the stepper. While that happens, the motor side sets a status pin to high that causes an interrupt on the control side, which causes the control side to wait for the motor to become free again or collects data while the routine is taking place.

This isolates the stepper routines from the data collection and nice smooth stepper motion while also capturing our signal... In theory.

Thank you for your feedback so far and I hope to hear more from you.

Im a noob in this, however I noticed you have delays of 2sec, these will pause everything.

Try to code it with millis() and see if this improves the situation.

It might look something like this:

unsigned long currentMillis = millis(); // goes in loop()
unsigned long previousMillis = 0; 
unsigned long delayMillis = 2000;

for(int i = 0; i < 6; i++){
        if(i%2){

          previousMillis = millis();
          digitalWrite(ForwardLED_PIN, HIGH);

          if( currentMillis - previousMillis >= 2000) // used to be delay(2000);
          { 
//          for(int i = 0; i < 100000; i++){}
          digitalWrite(ForwardLED_PIN, LOW);
          previousMillis = currentMillis;
          }

        } else .....

I think many of us reacted to your idea without even looking at your code. This

void wait4Motor_ISR(){
   if(digitalRead(Motor_Busy_Pin) == LOW){
    digitalWrite(Comms_Pin_A,LOW);
    digitalWrite(Comms_Pin_B,LOW);
    delay(5000);
...

shows that you don't yet quite know enough to venture into the trouble you are asking for - delay() does not work in an interrupt service routine.

And this

also seems like an odd thing to note. Serial comms operate on interrupts already, quietly and without you going to any trouble at all. Perhaps a review of basic serial communication wuold be in order, here are two links worth some time:

Serial Input Basics - updated

Serial Input Basics Tutorial from Robin2 - Example Modification

I suggest that in addition (instead of, really) your textual description, you prepare traditional flowcharts for the necessary functions - as far as I could tell, you are bouncing between one side being busy while the other rolls its thunmbs, then vice versa.

I remain certain that this is entirley possible with one processor. When the fog has lifted, I will try to parse your "word salad" and see if I remain right. :expressionless:

a7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.