Motors stop working after first "for" loop

Hello everyone,

I’m doing a sequence of motors running with different delays. The thing is, after I set the PWM of the motors for the first time, the second time is not working for me. Any ideas what it is happening? I’m using this controller

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

Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

#define USMIN  150
#define USMAX  600 
#define SERVO_FREQ  50 


void setup() {
  Serial.begin(9600);
  pwm.begin();
  pwm.setOscillatorFrequency(27000000);
  pwm.setPWMFreq(SERVO_FREQ);
  delay(10);
 
}

void loop() {
  for(uint16_t i=0;i<SERVO_NUM;i++){
    pwm.setPWM(i, 0, USMIN);
    delay(servoDelay[i]);
    Serial.println(i);
  }
  delay(500);
  for(uint16_t i=0;i<SERVO_NUM;i++){
    pwm.setPWM(i, 0, USMAX);
    delay(servoDelay[i]);
    Serial.println(i);
  }
  delay(500);
}

This is the sequence (it is repetitive, but in the future it won’t, I’m just testing):

#define SERVO_NUM  120
const int servoDelay[SERVO_NUM] = {
  200, 500, 100, 50, 50, 50, 300, 10, 500, 10,
  200, 500, 100, 50, 50, 50, 300, 10, 500, 10,
  200, 500, 100, 50, 50, 50, 300, 10, 500, 10,
  200, 500, 100, 50, 50, 50, 300, 10, 500, 10,
  200, 500, 100, 50, 50, 50, 300, 10, 500, 10,
  200, 500, 100, 50, 50, 50, 300, 10, 500, 10,
  200, 500, 100, 50, 50, 50, 300, 10, 500, 10,
  200, 500, 100, 50, 50, 50, 300, 10, 500, 10,
  200, 500, 100, 50, 50, 50, 300, 10, 500, 10,
  200, 500, 100, 50, 50, 50, 300, 10, 500, 10,
  200, 500, 100, 50, 50, 50, 300, 10, 500, 10,
  200, 500, 100, 50, 50, 50, 300, 10, 500, 10,
};

Please provide a detailed description of what you mean by "is not working for me".

Hi pert, thanks for responding.

What I meant is that the examples that provides the Adafruit PWM Servo Driver works perfectly. It can move the motors every complete loop. But I made this code myself that seems to be OK in my opinion, but the servos only rotate in the first “for”, not even the first loop.

Do you think it could be something I2C related?

This is the examples that works for me:

/*************************************************** 
  This is an example for our Adafruit 16-channel PWM & Servo driver
  Servo test - this will drive 8 servos, one after the other on the
  first 8 pins of the PCA9685

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/815
  
  These drivers use I2C to communicate, 2 pins are required to  
  interface.

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

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

// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
// you can also call it with a different address and I2C interface
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40, Wire);

// Depending on your servo make, the pulse width min and max may vary, you 
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
#define SERVOMIN  150 // This is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  600 // This is the 'maximum' pulse length count (out of 4096)
#define USMIN  600 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150
#define USMAX  2400 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates

// our servo # counter
uint8_t servonum = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("8 channel Servo test!");

  pwm.begin();
  // In theory the internal oscillator is 25MHz but it really isn't
  // that precise. You can 'calibrate' by tweaking this number till
  // you get the frequency you're expecting!
  pwm.setOscillatorFrequency(27000000);  // The int.osc. is closer to 27MHz  
  pwm.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updates

  delay(10);
}

// You can use this function if you'd like to set the pulse length in seconds
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. It's not precise!
void setServoPulse(uint8_t n, double pulse) {
  double pulselength;
  
  pulselength = 1000000;   // 1,000,000 us per second
  pulselength /= SERVO_FREQ;   // Analog servos run at ~60 Hz updates
  Serial.print(pulselength); Serial.println(" us per period"); 
  pulselength /= 4096;  // 12 bits of resolution
  Serial.print(pulselength); Serial.println(" us per bit"); 
  pulse *= 1000000;  // convert input seconds to us
  pulse /= pulselength;
  Serial.println(pulse);
  pwm.setPWM(n, 0, pulse);
}

void loop() {
  // Drive each servo one at a time using setPWM()
  Serial.println(servonum);
  for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
    pwm.setPWM(servonum, 0, pulselen);
  }

  delay(500);
  for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
    pwm.setPWM(servonum, 0, pulselen);
  }

  delay(500);

  // Drive each servo one at a time using writeMicroseconds(), it's not precise due to calculation rounding!
  // The writeMicroseconds() function is used to mimic the Arduino Servo library writeMicroseconds() behavior. 
  for (uint16_t microsec = USMIN; microsec < USMAX; microsec++) {
    pwm.writeMicroseconds(servonum, microsec);
  }

  delay(500);
  for (uint16_t microsec = USMAX; microsec > USMIN; microsec--) {
    pwm.writeMicroseconds(servonum, microsec);
  }

  delay(500);

  servonum++;
  if (servonum > 7) servonum = 0; // Testing the first 8 servo channels
}

What I see of a difference, is that the servos are changing every loop. So I’m going to try that. But it seems weird to me that it doesn’t work after the first “for”.

To be clear, are you talking about DC motors or servos. You use the words interchangeably but they are very different things. I think you probably mean servos but please confirm, including the type of servo and how they are powered.

Please describe in detail what the servos actually do when you use your code. In physical terms not in terms of for loops. What actually happens.

E.g. you have 120 servos on a load of linked PCA9685 boards. All 120 servos move at their various times to the position set by USMIN? Then nothing else happens? Or does it?

Steve

Hi Steve, thanks for responding. Yes they’re indeed servos, sorry for not making that clear. And yes, I have 120 Servos. Also I found the solution. Turns out that it was a logic problem, not physical. Well kind of physical too. These drivers only drive up to 16 motors, but I was trying to move them all with one driver :fearful:

Obviously, the PCA9685 chip will collapse if I tell him to set a PWM signal to a motor that doesn’t exist for it. So I changed the code to this one, just in case someone is just silly as me.

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

Adafruit_PWMServoDriver pwm[8] = {
  Adafruit_PWMServoDriver(0x40), 
  Adafruit_PWMServoDriver(0x41), 
  Adafruit_PWMServoDriver(0x42), 
  Adafruit_PWMServoDriver(0x43), 
  Adafruit_PWMServoDriver(0x44), 
  Adafruit_PWMServoDriver(0x45), 
  Adafruit_PWMServoDriver(0x46), 
  Adafruit_PWMServoDriver(0x47)
};

#define USMIN  150
#define USMAX  600
#define SERVO_FREQ  50


void setup() {
  Serial.begin(9600);
  for (int j = 0; j < 8 ; j++) {
    pwm[j].begin();
    pwm[j].setOscillatorFrequency(27000000);
    pwm[j].setPWMFreq(SERVO_FREQ);
    delay(10);
  }
  Serial.println("POSITION");
  delay(10);
  for (int i = 0; i < SERVO_NUM; i++) {
    pwm[int(i/16)].setPWM(i - int((i)/16)*16, 0, USMIN);
    Serial.println(i);
  }
  delay(2000);
}

void loop() {
  Serial.println("START");
  for (int i = 0; i < SERVO_NUM; i++) {
    pwm[int(i/16)].setPWM(i - int(i/16)*16, 0, USMAX);
    Serial.println(i);
    delay(servoDelay[i]);
  }
  Serial.println("END");
  while (true);
}

Sorry for this trouble and thank you guys for answering my concerns.