Teensy 3.5 Takes "Turns" in executing 2 simple functions

Status
Not open for further replies.

laptophead

Well-known member
I am making a robot that has wheels and "legs" . The legs are able to change angles based on an RC input and a pot feedback.
For that see functions in the code
FrontLegMotionFun();
BackLegMotionFun();

I am obtaining PWM RC functions based on IRQ and that seems smooth.
The problem is that when I move both legs, the CPU seems to pause one for half a sec and take care of the other one, and vice versa.
One leg at the time responds nicely, but I need to move them both smoothly in the same time. I thought the super duper Teensy can handle it seamlessly.

Please help,
thanks
 

Attachments

  • Andros04_Installed.ino
    12.4 KB · Views: 79
The super duper Teensy does what you say, and can not compensate for the buggy output of this thing between your ears.
 
Last edited:
Pls make a short as possible program which reproduces the problem, post it, and we will try to help..
 
Teensy certainly can do things, but looking through the code not clear on how and when it will by driving the servo's at the same time. This will also be complicated by the way Servo's take time to reach the final point. As per Frank's second post suggest cutting down your code to just the init, loop and the two movement functions. Idea would be to get a program that would just cycle the leg motion continuously with as few as possible other bells and whistles in it. The process of doing that will probably find the problem, if not then what you have should be short enough to post directly here (please use the code tags).

Posted code is far easier to work with rather than a github link and increases the chances of somebody running eyes across it closely enough to pick up the problem.
 
use millis() in your code to do a step-by-step action that may appear smooth, or use l293d's and put them triggers on the same PORT and have fun with PORT MANIPULATION :)
 
I agree with most of the other statements, given, but to maybe kickstart you toward solving this, some of the steps I would do include:

a) Try to get an idea where in the code things are hanging up... I would probably use a logic analyzer where I would use unused IO pins, and maybe set it high at start of a function like FrontLegMotionFun and set it low at the end and measure the time, likewise with the BackLeg... Are these functions taking a long time to complete? Without Logic Analyzer I used to use LEDS to see it visibly. You can use pin 13 for one and I used to rig others with external resistor/LED....

Or I print stuff to USB port: like:
Code:
uint32_t last_cycle_time = 0;  // defined outside of function, setup could init to millis();
....
uint32_t cycle_start = millis(); 
FrontLegMotionFun();
uint32_t after_front = millis();
BackLegMotionFun();
uint32_4 after_back = millis();
Serial.printf("DT cycle: %d, front: %d, back: %d\n", cycle_start-last_cycle_time, after_front-cycle_start, after_back-after_start);
last_cycle_time = after_back;
Warning: Typed on fly so probably issues. If you don't use printf, can do with several Serial.print statements.

I would assume these delta times are small, but if not, then might need to look closer into those functions. if delta time per cycle is large may need again to figure out which function time is being used.

Maybe your code is generating/processing a ton of interrupts. So maybe add interrupt counter in each of your interrupt functions and maybe print those out when you print out the delta times.

Again the idea is to instrument the code so you can get a general idea of where the processor is using up time.

Good Luck
 
OK, I isolated the code just for these functions and it still take turns,

I hope is comprehensible, please help.


I am making a robot that has wheels and "legs" . The legs are able to change angles based on an RC input and a pot feedback.
For that see functions in the code
FrontLegMotionFun();
BackLegMotionFun();

I am obtaining PWM RC functions based on IRQ and that seems smooth.
The problem is that when I move both legs, the CPU seems to pause one for half a sec and take care of the other one, and vice versa.
One leg at the time responds nicely, but I need to move them both smoothly in the same time. I thought the super duper Teensy can handle it seamlessly.

Please help,
thanks
 

Attachments

  • Teensy_LegStudy_RC_input.ino
    3.6 KB · Views: 69
Inline version of the code

Code:
#define FrontPotPIN A0 //Potentiometer Analog pin. The pot  Must receive 3.3v not 5
#define BackPotPIN A1
#define Aux5PIN 25 //Top left adjustment- used for BackLeg movement. RED wire
#define Aux6PIN 24 // Top right adjustment - used forFront Leg
volatile uint16_t BackLegVal;
uint16_t BackLeg_start;
volatile uint16_t FrontLegVal;
uint16_t FrontLeg_start;


// Legs Motors Section



#define FrontPotPIN A0 //Potentiometer Analog pin. The pot  Must receive 3.3v not 5 --Yellow long wire  
#define BackPotPIN A1
const int FrontLegUpPin = 23; // (MotorA)Pin for FrontMotor going UP-// it means that 0 is max speed and 255 no current
const int FrontLegDnPin= 22;  //  Pin for FrontMotor Down
const int BackLegUpPin = 21; // (MotorB)Pin for right motor Forward move PWM
const int BackLegDnPin= 20;  // Pin for right motor BACK move PWM

void setup() {
  Serial.begin(9600);

  //Legs Section
    pinMode(FrontPotPIN, INPUT);
    pinMode(BackPotPIN, INPUT);
    pinMode(FrontLegUpPin,OUTPUT);
    pinMode(BackLegUpPin,OUTPUT);
    pinMode(FrontLegDnPin,OUTPUT);
    pinMode(BackLegDnPin,OUTPUT);
 attachInterrupt(Aux5PIN, BackLegRC_Read_Fun, CHANGE); //Top lef adjustment
  attachInterrupt(Aux6PIN, FrontLegRC_Read_Fun, CHANGE);
}

void loop() {
  /*
analogWrite (FrontLegUpPin, 256);  
analogWrite (FrontLegDnPin, 200); 
 delay (2000);
analogWrite (FrontLegDnPin, 256);
 analogWrite (FrontLegUpPin, 200);
 delay (2000);
  */
FrontLegMotionFun();
BackLegMotionFun();
       
}

void FrontLegMotionFun ()

{ 
  int FrontLegPotVal=(analogRead(FrontPotPIN)-220);  //first we read the pot position and we ad a number to adjust the "Center point"
  int GapFront = (FrontLegPotVal- (FrontLegVal- 1100)); // we are using "-1100" so we're left with a clean value from 0 to 700
 ///*
  Serial.print("FrontLegPotVal");
    Serial.print(FrontLegPotVal);
   Serial.print("\t"); 
  Serial.print("FrontLegRC Input");
   Serial.print(FrontLegVal);
  Serial.print("\t"); 
   Serial.print("GapFront=");
  Serial.println(GapFront);
 //*/
if (GapFront <= -30)
    {
        digitalWrite (FrontLegUpPin, 1);
        digitalWrite (FrontLegDnPin, 0); // pin22 white wire
    }
    else if (GapFront >= 30 && FrontLegVal>0)
    {
        digitalWrite (FrontLegUpPin, 0);
        digitalWrite (FrontLegDnPin, 1);
    }
    else   // do nothing
    {
        digitalWrite (FrontLegUpPin, 1);
        digitalWrite (FrontLegDnPin, 1);
    }
    
}   

void BackLegMotionFun ()

{ 
  int BackLegPotVal=(analogRead(BackPotPIN)-100);  //first we read the pot position and we ad a number to adjust the "Center point"
  int GapBack = (BackLegPotVal- (BackLegVal-1100));  // we are using "-1100" so we're left with a clean value from 0 to 700
/*  
    Serial.print("BackLegPotVal=");
    Serial.print(BackLegPotVal);
   Serial.print("\t"); 
  Serial.print("BackLegRC Input=");
   Serial.print(BackLegVal);
  Serial.print("\t"); 
   Serial.print("GapBack=");
  Serial.println(GapBack);
*/ 
if (GapBack <=-30 )
    {
        digitalWrite (BackLegUpPin, 1);
        digitalWrite (BackLegDnPin, 0); // pin22 white wire
    }
    else if (GapBack >= 30 && BackLegPotVal>60)
    {
        digitalWrite (BackLegUpPin, 0);
        digitalWrite (BackLegDnPin, 1);
    }
    else   // do nothing
    {
        digitalWrite (BackLegUpPin, 1);
        digitalWrite (BackLegDnPin, 1);
    }
    
}   


void FrontLegRC_Read_Fun() { // reverse drive 
    if (digitalRead(Aux6PIN) == HIGH) {FrontLeg_start = micros();}
        else { FrontLegVal = (uint16_t) (micros() - FrontLeg_start);}
}
void BackLegRC_Read_Fun() { // 
    if (digitalRead(Aux5PIN) == HIGH) {BackLeg_start = micros();}
        else { BackLegVal = (uint16_t) (micros() - BackLeg_start);}
}
 
Looking at the sequence, is your interupt process triggering for the wrong legs? So leg moves until target position, then the other leg gets sent to new target? Or does each leg do a complete in/out cycle before the other leg starts?
 
Gremlin,
Each leg moves for about 500ms to a new position, then stops, and the CPU goes to the other leg and does the same.
Then the CPU comes back to the first leg and moves it further, then goes back... etc. till each leg goes to the target and they stop where they should.

For the previous posts, port manipulation is beyond my skill and it might affect other functions. Maybe I should crank up the CPU speed?
Is there a disadvantage to that?
Or use different pins for digitalWrite so 2 different cores inside the CPU handle each task and they dont step on each other? I dont know the internal architecture. Beyond my skill level. I did not play much with ARM , but I thought it is good at multi tasking.

Worst comes to worst I will get a separate CPU for each leg...
 
Again hard to know where things are hanging up. So again I would instrument the code to see where time is being spent. Maybe first try would be something like:
Code:
#define FrontPotPIN A0 //Potentiometer Analog pin. The pot  Must receive 3.3v not 5
#define BackPotPIN A1
#define Aux5PIN 25 //Top left adjustment- used for BackLeg movement. RED wire
#define Aux6PIN 24 // Top right adjustment - used forFront Leg
volatile uint16_t BackLegVal;
uint16_t BackLeg_start;
volatile uint16_t FrontLegVal;
uint16_t FrontLeg_start;


// Legs Motors Section



#define FrontPotPIN A0 //Potentiometer Analog pin. The pot  Must receive 3.3v not 5 --Yellow long wire  
#define BackPotPIN A1
const int FrontLegUpPin = 23; // (MotorA)Pin for FrontMotor going UP-// it means that 0 is max speed and 255 no current
const int FrontLegDnPin = 22; //  Pin for FrontMotor Down
const int BackLegUpPin = 21; // (MotorB)Pin for right motor Forward move PWM
const int BackLegDnPin = 20; // Pin for right motor BACK move PWM
uint32_t FrontLegIntCnt = 0;  // Count of interrupts
uint32_t BackLegIntCnt = 0;  // Count of interrupts on Back leg
void setup() {
  while (!Serial && (millis() < 4000)) ;  // wait for serial port to be there
  Serial.begin(9600);
  delay(250);
  Serial.println("/n/n********** Program Start *********\n");  // print seomething at start
  //Legs Section
  pinMode(FrontPotPIN, INPUT);
  pinMode(BackPotPIN, INPUT);
  pinMode(FrontLegUpPin, OUTPUT);
  pinMode(BackLegUpPin, OUTPUT);
  pinMode(FrontLegDnPin, OUTPUT);
  pinMode(BackLegDnPin, OUTPUT);
  attachInterrupt(Aux5PIN, BackLegRC_Read_Fun, CHANGE); //Top lef adjustment
  attachInterrupt(Aux6PIN, FrontLegRC_Read_Fun, CHANGE);
}

void loop() {
  /*
    analogWrite (FrontLegUpPin, 256);
    analogWrite (FrontLegDnPin, 200);
    delay (2000);
    analogWrite (FrontLegDnPin, 256);
    analogWrite (FrontLegUpPin, 200);
    delay (2000);
  */
  uint32_t loop_start = millis();
  FrontLegMotionFun();
  uint32_t after_front = millis();
  BackLegMotionFun();
  uint32_t after_back = millis();
  Serial.printf("DT front: %d back: %d INTS: %d %d\n", after_front - loop_start, after_back - after_front,
                FrontLegIntCnt, BackLegIntCnt);


}

void FrontLegMotionFun ()

{
  int FrontLegPotVal = (analogRead(FrontPotPIN) - 220); //first we read the pot position and we ad a number to adjust the "Center point"
  int GapFront = (FrontLegPotVal - (FrontLegVal - 1100)); // we are using "-1100" so we're left with a clean value from 0 to 700
  /*
  Serial.print("FrontLegPotVal");
  Serial.print(FrontLegPotVal);
  Serial.print("\t");
  Serial.print("FrontLegRC Input");
  Serial.print(FrontLegVal);
  Serial.print("\t");
  Serial.print("GapFront=");
  Serial.println(GapFront);
  */
  if (GapFront <= -30)
  {
    digitalWrite (FrontLegUpPin, 1);
    digitalWrite (FrontLegDnPin, 0); // pin22 white wire
  }
  else if (GapFront >= 30 && FrontLegVal > 0)
  {
    digitalWrite (FrontLegUpPin, 0);
    digitalWrite (FrontLegDnPin, 1);
  }
  else   // do nothing
  {
    digitalWrite (FrontLegUpPin, 1);
    digitalWrite (FrontLegDnPin, 1);
  }

}

void BackLegMotionFun ()

{
  int BackLegPotVal = (analogRead(BackPotPIN) - 100); //first we read the pot position and we ad a number to adjust the "Center point"
  int GapBack = (BackLegPotVal - (BackLegVal - 1100)); // we are using "-1100" so we're left with a clean value from 0 to 700
  /*
      Serial.print("BackLegPotVal=");
      Serial.print(BackLegPotVal);
     Serial.print("\t");
    Serial.print("BackLegRC Input=");
     Serial.print(BackLegVal);
    Serial.print("\t");
     Serial.print("GapBack=");
    Serial.println(GapBack);
  */
  if (GapBack <= -30 )
  {
    digitalWrite (BackLegUpPin, 1);
    digitalWrite (BackLegDnPin, 0); // pin22 white wire
  }
  else if (GapBack >= 30 && BackLegPotVal > 60)
  {
    digitalWrite (BackLegUpPin, 0);
    digitalWrite (BackLegDnPin, 1);
  }
  else   // do nothing
  {
    digitalWrite (BackLegUpPin, 1);
    digitalWrite (BackLegDnPin, 1);
  }

}


void FrontLegRC_Read_Fun() { // reverse drive
  FrontLegIntCnt++;
  if (digitalRead(Aux6PIN) == HIGH) {
    FrontLeg_start = micros();
  }
  else {
    FrontLegVal = (uint16_t) (micros() - FrontLeg_start);
  }
}
void BackLegRC_Read_Fun() { //
  BackLegIntCnt++;
  if (digitalRead(Aux5PIN) == HIGH) {
    BackLeg_start = micros();
  }
  else {
    BackLegVal = (uint16_t) (micros() - BackLeg_start);
  }
}

In here I make sure the serial port is setup and print something out in Setup. Why? maybe the program crashes and restarts... Not likely but.... Then I added counters to your two interrupts that increment and then instrumented main loop to print out how many millis are spent in front leg and back leg function, it also prints out the interrupt counts.... I suspect that you should get a ton of debug messages with real small numbers for delta time, but if not, we know it is hanging up in these functions.

If this does print really small delta times, I would then maybe remove printing the delta times, and instead print maybe FrontLegVal and BackLegVal and verify they look correct.

I then would probably print out the state of the up down pins and the state of pot values. I like to try to print all of these values on one line, such that it is easy to see when things change. Example for the State of 4 output pins, maybe at start of the line with one character...

Again I don't know if these will find where it is hanging up or not, but hopefully gives you an idea on steps to take to try to localize down to what is going on.

Good luck
 
Kurt, I so much appreciate your help

But this seems very elaborate. I will live with it for right now.
If it becomes critical, I will pursue it later.

Thanks


Again hard to know where things are hanging up. So again I would instrument the code to see where time is being spent. Maybe first try would be something like:
Code:
#define FrontPotPIN A0 //Potentiometer Analog pin. The pot  Must receive 3.3v not 5
#define BackPotPIN A1
#define Aux5PIN 25 //Top left adjustment- used for BackLeg movement. RED wire
#define Aux6PIN 24 // Top right adjustment - used forFront Leg
volatile uint16_t BackLegVal;
uint16_t BackLeg_start;
volatile uint16_t FrontLegVal;
uint16_t FrontLeg_start;


// Legs Motors Section



#define FrontPotPIN A0 //Potentiometer Analog pin. The pot  Must receive 3.3v not 5 --Yellow long wire  
#define BackPotPIN A1
const int FrontLegUpPin = 23; // (MotorA)Pin for FrontMotor going UP-// it means that 0 is max speed and 255 no current
const int FrontLegDnPin = 22; //  Pin for FrontMotor Down
const int BackLegUpPin = 21; // (MotorB)Pin for right motor Forward move PWM
const int BackLegDnPin = 20; // Pin for right motor BACK move PWM
uint32_t FrontLegIntCnt = 0;  // Count of interrupts
uint32_t BackLegIntCnt = 0;  // Count of interrupts on Back leg
void setup() {
  while (!Serial && (millis() < 4000)) ;  // wait for serial port to be there
  Serial.begin(9600);
  delay(250);
  Serial.println("/n/n********** Program Start *********\n");  // print seomething at start
  //Legs Section
  pinMode(FrontPotPIN, INPUT);
  pinMode(BackPotPIN, INPUT);
  pinMode(FrontLegUpPin, OUTPUT);
  pinMode(BackLegUpPin, OUTPUT);
  pinMode(FrontLegDnPin, OUTPUT);
  pinMode(BackLegDnPin, OUTPUT);
  attachInterrupt(Aux5PIN, BackLegRC_Read_Fun, CHANGE); //Top lef adjustment
  attachInterrupt(Aux6PIN, FrontLegRC_Read_Fun, CHANGE);
}

void loop() {
  /*
    analogWrite (FrontLegUpPin, 256);
    analogWrite (FrontLegDnPin, 200);
    delay (2000);
    analogWrite (FrontLegDnPin, 256);
    analogWrite (FrontLegUpPin, 200);
    delay (2000);
  */
  uint32_t loop_start = millis();
  FrontLegMotionFun();
  uint32_t after_front = millis();
  BackLegMotionFun();
  uint32_t after_back = millis();
  Serial.printf("DT front: %d back: %d INTS: %d %d\n", after_front - loop_start, after_back - after_front,
                FrontLegIntCnt, BackLegIntCnt);


}

void FrontLegMotionFun ()

{
  int FrontLegPotVal = (analogRead(FrontPotPIN) - 220); //first we read the pot position and we ad a number to adjust the "Center point"
  int GapFront = (FrontLegPotVal - (FrontLegVal - 1100)); // we are using "-1100" so we're left with a clean value from 0 to 700
  /*
  Serial.print("FrontLegPotVal");
  Serial.print(FrontLegPotVal);
  Serial.print("\t");
  Serial.print("FrontLegRC Input");
  Serial.print(FrontLegVal);
  Serial.print("\t");
  Serial.print("GapFront=");
  Serial.println(GapFront);
  */
  if (GapFront <= -30)
  {
    digitalWrite (FrontLegUpPin, 1);
    digitalWrite (FrontLegDnPin, 0); // pin22 white wire
  }
  else if (GapFront >= 30 && FrontLegVal > 0)
  {
    digitalWrite (FrontLegUpPin, 0);
    digitalWrite (FrontLegDnPin, 1);
  }
  else   // do nothing
  {
    digitalWrite (FrontLegUpPin, 1);
    digitalWrite (FrontLegDnPin, 1);
  }

}

void BackLegMotionFun ()

{
  int BackLegPotVal = (analogRead(BackPotPIN) - 100); //first we read the pot position and we ad a number to adjust the "Center point"
  int GapBack = (BackLegPotVal - (BackLegVal - 1100)); // we are using "-1100" so we're left with a clean value from 0 to 700
  /*
      Serial.print("BackLegPotVal=");
      Serial.print(BackLegPotVal);
     Serial.print("\t");
    Serial.print("BackLegRC Input=");
     Serial.print(BackLegVal);
    Serial.print("\t");
     Serial.print("GapBack=");
    Serial.println(GapBack);
  */
  if (GapBack <= -30 )
  {
    digitalWrite (BackLegUpPin, 1);
    digitalWrite (BackLegDnPin, 0); // pin22 white wire
  }
  else if (GapBack >= 30 && BackLegPotVal > 60)
  {
    digitalWrite (BackLegUpPin, 0);
    digitalWrite (BackLegDnPin, 1);
  }
  else   // do nothing
  {
    digitalWrite (BackLegUpPin, 1);
    digitalWrite (BackLegDnPin, 1);
  }

}


void FrontLegRC_Read_Fun() { // reverse drive
  FrontLegIntCnt++;
  if (digitalRead(Aux6PIN) == HIGH) {
    FrontLeg_start = micros();
  }
  else {
    FrontLegVal = (uint16_t) (micros() - FrontLeg_start);
  }
}
void BackLegRC_Read_Fun() { //
  BackLegIntCnt++;
  if (digitalRead(Aux5PIN) == HIGH) {
    BackLeg_start = micros();
  }
  else {
    BackLegVal = (uint16_t) (micros() - BackLeg_start);
  }
}

In here I make sure the serial port is setup and print something out in Setup. Why? maybe the program crashes and restarts... Not likely but.... Then I added counters to your two interrupts that increment and then instrumented main loop to print out how many millis are spent in front leg and back leg function, it also prints out the interrupt counts.... I suspect that you should get a ton of debug messages with real small numbers for delta time, but if not, we know it is hanging up in these functions.

If this does print really small delta times, I would then maybe remove printing the delta times, and instead print maybe FrontLegVal and BackLegVal and verify they look correct.

I then would probably print out the state of the up down pins and the state of pot values. I like to try to print all of these values on one line, such that it is easy to see when things change. Example for the State of 4 output pins, maybe at start of the line with one character...

Again I don't know if these will find where it is hanging up or not, but hopefully gives you an idea on steps to take to try to localize down to what is going on.

Good luck
 
The type of debug prints may seem elaborate - but they are the only way to see what is actually happening under the covers.

KurtE likely gave a really good 'drop in' guide to start seeing your issue [as robotics is one of his many specialties]. Spending a short time learning the process with his guidance might payback later when new or other problems show up.

It might be that the simplest thing is wrong and it will quickly show up. Going to two Teensy's would be more elaborate and require even more interaction where the problem could only be harder to find without these 'debug' skills. I'm not sure how a T_3.5 wouldn't be up to the task that (from a glance) an UNO should be able to do.

Good luck.
 
I implemented your code

And discovered that the Teensy is doing fine. The problem was in the DC motor controllers. At "full speed" they have an interruption issue known to the manufacturer.

Thanks a lot.
 
Status
Not open for further replies.
Back
Top