Program does not run certain lines of code

Hey.

This is my third post of my school project, here is the second, which also links to the first.

Here's a Imgur video link of the first parts of the program where it moves "0" (the chassi). The video isn't recent, but I hope it gives you a good picture of how the whole station will work and look.

The program controls 5 servos from a main method named "Main()". Different sections (c == 1, c ==2, ...) are called depending on what "c" is equal to and different "millis() delays". In these sections, other methods are being run that control different parts of my station. For an example, it has a robot arm, a hammer, a holder etc. that together build a very basic Lego car.

moveObject() controls the robot that moves the different parts of the car. c will only increase when this part is finished.

(setGripper() is a part of "moveObject" and controls the grip of the robot)

setHolder() controls the frame that holds the car down in its station and alligns the falling lego parts to their spots.

swingHammer() controls the hammer.

As you can see, c is incremented after every method is called ("c++;") which enables "Main()" to continue to the next section after the required time has passed (hasElapsed(time in milliseconds)).

Inside these methods are also several "commandServo()" methods, which give new "orders" to the servos. It simply gives a certain servo a new target angle and velocity (rotationspeed) that then the contents of "loop()" takes care of (it calculates new steps every 50 ms for all servos with "orders" until they've reached their target).

Now to the problem itself. The sequence in "Main()" goes splendid up until c == 6, which is when the hammer pulls itself up for the first time. After this, it completely skips all code between c == 7 and c == 16, where it only runs "setHolder(0);" before the whole station freezes. It's supposed to run the code inside c == 8 to c == 16 but it just doesn't. I've sat here for hours trying to figure out what's wrong. I've rewritten a few parts of the program but it didn't help, but one thing I've learned is that the problem has to do with "swingHammer()". As mentioned before, it only starts going wrong when the hammer first pulls itself up, which is just a basic "commandServo()". It used to be more complicated (as you can see by the old commented code in "loop()") and making it more basic didn't solve the problem.

If I've been vague or anything, please let me know.

Grateful for all the help I can get!

If I've been vague or anything, please let me know

Can't see your code.
Can't see your debug prints.

First half:

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

#define MIN_PULSE_WIDTH 650
#define MAX_PULSE_WIDTH 2350
#define DEFAULT_PULSE_WIDTH 1500
#define FREQUENCY 50


unsigned long currentMillis;
unsigned long previousMillis = 0;
unsigned long hammerMillis = 0;
unsigned long waitMillis = 0;
const int interval = 50;    // The time between steps of servos

int currentAngle[16];   // This stores the properties of a maximum of 16 servos
int velocity[16];       // (what my servo shield supports).
int targetAngle[16];
bool updateServo[16];

int lastTime;           // Time of hasElapsed start.
int lastTime2;          // Time of hasElapsed2 start.
int timeNow;

int c = 1;              // Which part of the main sequence to run.
int m = 1;              // Which part of moveObject to run.
int piece;              // The part that moveObject moves (chassi = 0, block 1 = 1, windshield = 2, last block = 3 & assembled car = 4).
int carsBuilt = 0;

bool hammerHasStruck = false;

// Servo outputs:
int rotationServo = 0;
int pitchServo = 4;
int gripperServo = 7;
int hammerServo = 8;
int holderServo = 12;

// Bools that control what methods to run:
bool runMain = true;
bool runMoveObject = false;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);

  pwm.begin();
  pwm.setPWMFreq(FREQUENCY);
  digitalWrite(LED_BUILTIN, HIGH);
  digitalWrite(LED_BUILTIN, LOW);

  for (int s = 0; s < 16; s++) updateServo[s] = false;
  setServo(0, 90);   // All servos used in the project must know where to start.
  setServo(4, 115);
  setServo(7, 90);
  setServo(8, 90);
  setServo(12, 50);
  delay(500);
}

void Main()
{
  if (c == 1 && hasElapsed(500))
  {
    setHolder(0);
    commandServo(0, 90, 2);
    commandServo(4, 115, 4);
    setGripper(2);
    //c++;            // No moveObject() is being called when c = 1, meaning that "c++" is needed.
  }
  else if (c == 2 && hasElapsed(1000))
  {
    moveObject(0);
  }
  else if (c == 3 && hasElapsed(1000))
  {
    setHolder(3);
  }
  else if (c == 4 && hasElapsed(10))
  {
    moveObject(1);
  }
  else if (c == 5 && hasElapsed(2500))
  {
    swingHammer(true);
  }
  else if (c == 6 && hasElapsed(750))
  {
    swingHammer(false);
  }
  else if (c == 7 && hasElapsed(1000))
  {
    setHolder(2);
  }
  else if (c == 8 && hasElapsed(2000))
  {
    moveObject(2);
  }
  else if (c == 9 && hasElapsed(1500))
  {
    setHolder(1);
  }
  else if (c == 10 && hasElapsed(1000))
  {
    setHolder(2);
  }
  else if (c == 11 && hasElapsed(2500))
  {
    swingHammer(true);
  }
  else if (c == 12 && hasElapsed(750))
  {
    swingHammer(false);
  }
  else if (c == 13 && hasElapsed(1000))
  {
    moveObject(3);
  }
  else if (c == 14 && hasElapsed(2500))
  {
    swingHammer(true);
  }
  else if (c == 15 && hasElapsed(750))
  {
    swingHammer(false);
  }
  else if (c == 16 && hasElapsed(1000))
  {
    setHolder(0);
  }
  else if (c == 17 && hasElapsed(3000))
  {
    moveObject(4);
  }
  else if (c == 18 && hasElapsed(3000))
  {
    if (carsBuilt != 3)
    {
      lastTime = timeNow;
      lastTime2 = timeNow;
      c = 1;
      carsBuilt++;
    }
    else
    {
      runMain = false;
      runMoveObject = false;
    }
  }
}

void moveObject(int p) // 0 for chassi, 1 for the first block, 2 for the windshield and 3 for the last block.
{
  runMoveObject = true;
  runMain = false;
  piece = p;

  if (m > 11) m = 1;  // Resets m so that this sequence (moveObject) can run again when called.

  int horizAngle1; // The "pickup angle" to rotate towards horizontally.
  int horizAngle2; // The "place angle" to rotate towards horizontally.

  int vertiAngle1; // The "pickup angle" to rotate towards vertically.
  int vertiAngle2; // The "place angle" to rotate towards vertically.


  if (piece == 0)  // Pick up and place chassi.
  {
    horizAngle1 = 0;
    horizAngle2 = 90;

    vertiAngle1 = 50;
    vertiAngle2 = 50;
  }
  else if (piece == 1) // Pick up and place first block.
  {
    horizAngle1 = 32;
    horizAngle2 = 82;

    vertiAngle1 = 50;
    vertiAngle2 = 45;
  }
  else if (piece == 2) // Pick up and place windshield.
  {
    horizAngle1 = 32;
    horizAngle2 = 100;

    vertiAngle1 = 50;
    vertiAngle2 = 55;
  }
  else if (piece == 3) // Pick up and place second block.
  {
    horizAngle1 = 32;
    horizAngle2 = 82;

    vertiAngle1 = 50;
    vertiAngle2 = 55;
  }
  else if (piece == 4) // Pick up and place assembled car.
  {
    horizAngle1 = 82;
    horizAngle2 = 170;

    vertiAngle1 = 45;
    vertiAngle2 = 90;
  }

  if (m == 1 && hasElapsed2(1000))
  {
    commandServo(0, 90, 2);
    setGripper(2);
    m++;
  }
  else if (m == 2 && hasElapsed2(1000))
  {
    commandServo(0, horizAngle1, 2);
    m++;
  }
  else if (m == 3 && hasElapsed2(2000))
  {
    setGripper(0);
    m++;
  }
  else if (m == 4 && hasElapsed2(1000))
  {
    commandServo(4, vertiAngle1, 4);
    m++;
  }
  else if (m == 5 && hasElapsed2(1500))
  {
    setGripper(1);
    m++;
  }
  else if (m == 6 && hasElapsed2(1500))
  {
    commandServo(4, 120, 4);
    m++;
  }
  else if (m == 7 && hasElapsed2(1500))
  {
    commandServo(0, horizAngle2, 2);
    m++;
  }
  else if (m == 8 && hasElapsed2(2000))
  {
    commandServo(4, vertiAngle2, 4);
    m++;
  }
  else if (m == 9 && hasElapsed2(1500))
  {
    setGripper(0);
    m++;
  }
  else if (m == 10 && hasElapsed2(1000))
  {
    commandServo(4, 115, 4);
    commandServo(0, 90, 2);
    setGripper(2);
    m++;
  }
  else if (m == 11 && hasElapsed2(1000))
  {
    runMain = true;       // The main sequence can now continue.
    m++;
    runMoveObject = false;  // Stops this method from running
    c++;
  }
}

Second half:

void setServo(int s, int angle)         // s is which servo it moves (0 to 15).
{
  pwm.setPWM(s, 0, pulseWidth(angle));
  currentAngle[s] = angle;              // The servo's current angle is updated.
}

void commandServo(int s, int angle, int v)
{
  targetAngle[s] = angle;
  velocity[s] = v;
  updateServo[s] = true;
}

void setGripper(int mode)
{
  if (mode == 0)
  {
    commandServo(gripperServo, 50, 3);    // Makes the tool close its grip.
  }
  else if (mode == 1)
  {
    commandServo(gripperServo, 105, 3);   // Makes the tool open its grip.
  }
  else if (mode == 2)
  {
    commandServo(gripperServo, 90, 3);    // Makes the tool go to its default mode (semi-closed).
  }
}

void swingHammer(bool strike)
{
  if (strike)
  {
    commandServo(hammerServo, 45, 50); // Swings the hammer down.
    //hammerHasStruck = true;
    //runMain = false;
    //hammerMillis = millis();  // Saves the time of strike to make it go up after 500 ms (look in the beginning of loop()).
  }
  else if (!strike)
  {
    commandServo(hammerServo, 90, 3); // Pulls the hammer up.
  }
  c++;
}

void setHolder(int mode)
{
  int angle;
  if (mode == 0) angle = 50;
  else if (mode == 1) angle = 90;
  else if (mode == 2) angle = 102;
  else if (mode == 3) angle = 105;
  commandServo(holderServo, angle, 2);

  c++;
}

bool hasElapsed(int period)
{
  if (timeNow >= lastTime + period)
  {
    lastTime = timeNow;
    return true;
  }
  else
  {
    return false;
  }
}

bool hasElapsed2(int period)
{
  if (timeNow >= lastTime2 + period)
  {
    lastTime = timeNow;
    lastTime2 = timeNow;
    return true;
  }
  else
  {
    return false;
  }
}

void loop()
{
  currentMillis = millis();
  timeNow = millis();
  
  if      (runMain)       Main();            // Runs Main().
  else if (runMoveObject) moveObject(piece); // Runs moveObject until it's finished, which is when runMoveObject = false.
  
  /*
    if (hammerHasStruck && (currentMillis - hammerMillis >= 500))
    {
    commandServo(hammerServo, 90, 3); // Automatically pulls the hammer up 500 ms after it has struck.
    hammerHasStruck = false;
    runMain = true;
    lastTime = timeNow;
    lastTime2 = timeNow;
    c++;
    }
  */





  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;

    for (int s = 0; s < 16; s++)
    {
      if (updateServo[s] == true) // Checks to see if servo number s needs to be updated.
      {
        int newAngle;         // The next incremented angle to rotate to (not target).
        int rotation;         // Which way (up or down) the servo should rotate.

        if (targetAngle[s] > currentAngle[s]) rotation = 1;    // Sets the rotation direction depending
        else rotation = -1;                                    // on whether the target angle is over or below current.

        if (currentAngle[s] != targetAngle[s])              // Keep going as long as it hasn't reached its target.
        {
          newAngle = currentAngle[s] + rotation * (velocity[s]); // Assigns the position of the next step.

          if ((rotation == 1 && newAngle > targetAngle[s])         // If the next step exceeds target, rotate to target instead.
              || (rotation == -1 && newAngle < targetAngle[s]))
            newAngle = targetAngle[s];

          pwm.setPWM(s, 0, pulseWidth(newAngle));           // Rotate servo to the new angle(the next step.)
          currentAngle[s] = newAngle;                       // Update the current angle of rotated servo.
          if (currentAngle[s] == targetAngle[s])
          {
            updateServo[s] = false;    // Stop updating and rotating this servo if it has reached its target.
            break;
          }
        }
      }
    }
  }
}

int pulseWidth(int angle)
{
  int pulse_wide, analog_value;
  pulse_wide   = map(angle, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
  analog_value = int(float(pulse_wide) / 1000000 * FREQUENCY * 4096);
  return analog_value;
}

//void wait(int period)
//{
//  digitalWrite(LED_BUILTIN, HIGH);
//  int time_now = millis();
//  while (millis() < time_now + period) loop();
//  digitalWrite(LED_BUILTIN, LOW);
//
//}

/*

    for (int a = 0; a < 11; a++)  // Test loop: Makes the servo go from 1 % to 100%, 10% at a time.
    {
    int b;
    if (a == 0) a = 1;

    setServo(0, 0);           // Set servo number 0 to 0 degrees ASAP.
    delay(500);
    moveServo(0, 180, a * 10);     // Move servo number 0 to 180 degrees at speed a.
    delay(2000);
    }
*/



/*
  void moveServo(int s, int targetAngle, int velocity)
  {
  int newAngle;         // The next incremented angle to rotate to (not target). Should this be double/float?
  int rotation;         // Which way (up or down) the servo should rotate.

  if (velocity >= 100) setServo(s, targetAngle);        // Makes sure that only 100% is allowed.
  else
  {
    if (targetAngle[s > currentAngle[s]) rotation = 1;    // Sets the rotation direction depending
    else rotation = -1;                                     // on whether the target angle is over or below.

    while (acurrentAngle[s] != targetAngle)              // Keep going as long as it hasn't reached its target.
    {
      newAngle = currentAngle[s] + rotation * (velocity / 10);   // Assigns the position of the next step.

      if ((rotation == 1 && newAngle > targetAngle)         // If the next step exceeds target, rotate to target instead.
          || (rotation == -1 && newAngle < targetAngle))
        newAngle = targetAngle;

      pwm.setPWM(s, 0, pulseWidth(newAngle));           // Rotate servo to the new angle(the next step.
      delay(20);                                            // The most important delay of the whole sketch.
      currentAngle[s] = newAngle;                       // Update the current angle of rotated servo.
      if (currentAngle[s] == targetAngle) break;        // If it has reached its target, stop rotating.
    }
  }
  }
*/






//  commandServo(0, 170, 1);
//  commandServo(4, 20, 2);
//
//  wait(2000);
//
//  commandServo(0, 20, 3);
//  wait(2000);




//  commandServo(4, 170, 4);
//
//  wait(2000);
//
//  commandServo(0, 170, 5);
//  commandServo(4, 20, 6);
//  wait(2000);
//
//  commandServo(0, 170, 1);
//  wait(2000);
//  commandServo(0, 20, 1);

If your code is too long for a single Reply then please add the .ino as an attachment. It is too easy to make mistakes when trying to join two parts together.

...R

Hi,
From what I can see of your code, you need to add some Serial.print debugging to check your variables at critical parts of your code.
At the moment you have no way of knowing how you code is running.

I can see that this project needs a screen/display to be connected so the progress of the process can be observed.

Tom.... :slight_smile:

Can any friendly Administrator move this to Programming? :slight_smile:

EDIT: No need! The problem is fixed!!!

Since I stored the current time (timeNow) in milliseconds in an integer, it could only count to roughly 32,7 s, since integers can only store numbers up to 32 767. The problem was fixed by changing it to "long" instead. What a relief!!! :smiley:

Eophex:
Since I stored the current time (timeNow) in milliseconds in an integer, it could only count to roughly 32,7 s, since integers can only store numbers up to 32 767. The problem was fixed by changing it to "long" instead. What a relief!!! :smiley:

All variables associated with millis() should be unsigned long

...R