creating function names and populating arrays in setup

Seasons greetings to everyone!

I’m trying to optimise the setup of a sero project and want to be able to define arrays at the top of the code and populate them in the setup based on the number of servos. currently I have

#define SERVERQTY 5  //actual number - 1 as address starts at 0

// these Variables will change:
uint8_t servonum = 0;
long randNum;
int servopos;

int servoTimers[] = {0,1,2,3,4,5}; //servo timers
int timersActive[] = {false,false,false,false,false,false}; //create an array to store whether servo timer(s) are active
int angles[] = {0,0,0,0,0,0};      //create an array to store the current servo angles
int previousAngles[] = {0,0,0,0,0,0};  //create an array to store the previous servo angles
typedef void (*function) () ;               //need to learn what this does
function timerFunctions[] = { servoDelay0, servoDelay1, servoDelay2, servoDelay3, servoDelay4, servoDelay5 };   //create an array of function names that the timers call when complete

void setup() {
//code here
}

The above works but I’d like to do is something like this whereby I use the SERVOQTY to loop through and automatically fill in the array values (less work when adding another servo)

#define SERVERQTY 5  //actual number - 1 as address starts at 0

// these Variables will change:
uint8_t servonum = 0;
long randNum;
int servopos;

int servoTimers[SERVERQTY]; //servo timers
int timersActive[SERVERQTY]; //create an array to store whether servo timer(s) are active
int angles[SERVERQTY];      //create an array to store the current servo angles
int previousAngles[SERVERQTY];  //create an array to store the previous servo angles
typedef void (*function) () ;
function timerFunctions[SERVERQTY] = { servoDelay0, servoDelay1, servoDelay2, servoDelay3, servoDelay4, servoDelay5 };

void setup() {
//code here
for(servonum = 0; servonum <= SERVERQTY; servonum++){
  servoTimers[servonum] = servonum;
  timersActive[servonum] = false;
  angles[servonum] = 90;
  previousAngles[servonum] = 0;
  
}

The code compiles but appears to crash in the setup. Before I go any further, is what I’m trying to do an acceptable way of creating the arrays (as you can tell, I’m new to all of this).
I wanted to also use the same method for automatically defining the timerFunction array but that does not compile.
Cheers,
Philip

This line

for(servonum = 0; servonum <= SERVERQTY; servonum++){

should be

for(servonum = 0; servonum < SERVERQTY; servonum++){

Array indexes start at 0 so your code is trying to initialise 6 servos when you only have an array for 5

…R

Doh! thanks for that. I've actually got six servos so that means that when I create the arrays I'm only creating them with 5 elements, not six.

so I guess

int servoTimers[SERVERQTY + 1];

should do the trick.

or better still, do as you suggested and increase the SERVERQTY by 1

Thanks for your help. :-)

If you have SERVERQTY servos then the array declaration should be

int servoTimers[SERVERQTY];

This will give you an array large enough to hold SERVERQTY items of data numbered from 0 to SERVERQTY - 1. Note that the array index starts at zero

Then, when you use the array in a for loop you should use

for (int x = 0; x < SERVERQTY; x++)

This will give values of x from 0 to SERVERQTY - 1 which matches the numbering of the array levels.

great, thanks @Robin2 & @UKHeliBob, got that part working a treat with the following code

#define SERVERQTY 6  //actual number of servos
uint8_t servonum = 0;

int servoTimers[SERVERQTY];     //servo timers
int timersActive[SERVERQTY];     //create an array to store whether servo timer(s) are active
int angles[SERVERQTY];              //create an array to store the current servo angles
int previousAngles[SERVERQTY];  //create an array to store the previous servo angles
//create functions array for each of the simpletimer done calls
typedef void (*function) () ;
function timerFunctions[] = { servoDelay0, servoDelay1, servoDelay2, servoDelay3, servoDelay4, servoDelay5 };

void setup(){
  for (servonum = 0; servonum < SERVERQTY; servonum++){
    angles[servonum] = 90;
    previousAngles[servonum] = 90;
    servoTimers[servonum] = servonum;
    timersActive[servonum] = false;
  }
}

Now, I’m wondering whether I can do the same with the timerfunctions array but when I try

function timerFunctions[SERVERQTY];

and add this to the setup

timerFunctions[servonum] = "servoDelay" + servonum;

I get this error
Arduino: 1.8.7 (Mac OS X), Board: “Arduino Nano, ATmega328P (Old Bootloader)”

/Users/philip/Documents/Arduino/beehive2/beehive2.ino: In function ‘void setup()’:
beehive2:65:30: error: cannot convert ‘const char*’ to ‘function {aka void ()()}’ in assignment
timerFunctions[servonum] = “servoDelay” + servonum;
^
exit status 1
cannot convert 'const char
’ to ‘function {aka void (*)()}’ in assignment

I’ve tried searching for an answer but unfortunately what I’ve read goes over my head!

I'm not sure what you are trying to do with this

timerFunctions[servonum] = "servoDelay" + servonum;

but I suspect it is the sort of thing that will work with an interpreted language and not with a compiled language.

...R

i was trying to put this

function timerFunctions[] = { servoDelay0, servoDelay1, servoDelay2, servoDelay3, servoDelay4, servoDelay5 };

into the setup as part of the config loop along with populating all the other arrays

void setup(){
  for (servonum = 0; servonum < SERVERQTY; servonum++){
    angles[servonum] = 90;
    previousAngles[servonum] = 90;
    servoTimers[servonum] = servonum;
    timersActive[servonum] = false;
    timerFunctions[servonum] = "servoDelay" + servonum;
  }
}

but i think your diagnosis is correct.

I’m going to try and simplify the code so as each servo simpletimer calls the same function at the end of the random duration and instead of testing an array flag to see if the timer is still running, i’m going to try and use

if (!timer.isEnabled(servoTimers[servonum])){
}

instead. This will negate the requirement to set up a functions array as well as the timersActive array.
[EDIT] Done and working like a charm! Thanks for all your help, much appreciated. [/EDIT]

philipbutler: I'm going to try and simplify the code so as each servo simpletimer calls the same function at the end of the random duration and instead of testing an array flag to see if the timer is still running, i'm going to try and use

if (!timer.isEnabled(servoTimers[servonum])){
}

Since servoTimers[servonum] is initialized to servonum, why not get rid of the servoTimers array and just use:

if (!timer.isEnabled(servonum)){
}

Why not make use of the C++ language and introduce a Servo class?

class MyServo
{
private:
	int currentAngle;
	int previousAngle;
	bool isTimerActive;
public:
	void begin()
	{
		currentAngle = 90;
		previousAngle = 90;
		isTimerActive = false;
	}
};

and in your setup function:

#define SERVERQTY 6  //actual number of servos

MyServo servos[SERVERQTY];     //servo timers
void setup(){
  for (int i = 0; i < SERVERQTY; i++){
    servos[i].begin();
  }
}

johnwasser: Since servoTimers[servonum] is initialized to servonum, why not get rid of the servoTimers array and just use:

if (!timer.isEnabled(servonum)){
}

Hi, thanks for the suggestion, I tried it and it appears to work apart from servo 0

I forgot to mention that to get the revised code to work I had to modify the servoTimers[servonum] array setup to be

servoTimers[servonum] = servonum +1;

as for some reason the simpletimer function did not like 0 as a timer name

here is the code in context. If you’re wondering, I’m using the arduino to animate 16 bees on a beehive!

void loop(){
  if (trigger == 1){
    Serial.println ("**** Oh No! the bees are awake and not happy! ***");
    digitalWrite(LED_BUILTIN, HIGH);
    if (timer.isEnabled(buzzTimer)) {
      Serial.println("BUZZ RE-START");
      timer.restartTimer(buzzTimer);
    } else {
      Serial.println("BUZZ START");
      buzzTimer = timer.setTimeout(buzzDurationMs, buzzDelay);
    }       
    trigger = 0;
  }
  if (timer.isEnabled(buzzTimer)) {
    for (servonum = 0; servonum < SERVERQTY; servonum++){
      
      if (!timer.isEnabled(servoTimers[servonum])){
          previousAngles[servonum] = angles[servonum];
          angles[servonum] = doServo(servonum);
          // calculate degrees of rotation
          int rotation = abs(previousAngles[servonum] - angles[servonum]);
          // use the amount of rotation value to vary the time delay
          servoTimers[servonum] = timer.setTimeout((10*rotation), servoTimerFin);
      }
    }
    servonum = 0;   //reset servo num back to zero
    //tmrpcm.play("beehive.wav");  
  }
  timer.run();
}

int doServo (uint8_t n) {

  int angle = random(30,140);
  int servopos = map(angle, 0, 180, SERVOMIN, SERVOMAX);
  servo.setPWM(n, 0, servopos);
  return angle;
}
void buzzDelay() {
  Serial.println ("****   PHEW!  They've gone back to sleep     ****");
  digitalWrite(LED_BUILTIN, LOW);
  for (servonum = 0; servonum < SERVERQTY; servonum++){
    int servopos = map(90, 0, 180, SERVOMIN, SERVOMAX);
    servo.setPWM(servonum, 0, servopos);
  }  
}
void servoTimerFin() {
  // nothing to do here
}

I think that this is sort of what you were aiming at with your original attempt. I got it to compile without errors or warnings. A cleaner solution would be to encapsulate each servo in a “TimedServo” object class with a ‘.begin()’ method to initialize the member variables.

#include <Servo.h>
#include <SimpleTimer.h>  // https://github.com/schinken/SimpleTimer

const byte ServoCount = 6;

Servo Servos[ServoCount];
const byte ServoPins[ServoCount] = {2, 3, 4, 5, 6, 7};
SimpleTimer ServoTimers[ServoCount]; // One SimpleTimer per servo
bool ServoTimersActive[ServoCount] ; // Globals default to 0 (false)
int ServoAngles[ServoCount];
int ServoPreviousAngles[ServoCount];

// Create an array of pointers to the callback functions for the timers
void servoDelay0(void);  // It is not clear why the Arduino IDE automatic
void servoDelay1(void);  // generation of function prototypes is not
void servoDelay2(void);  // working for these functions.  We put in these
void servoDelay3(void);  // prototypes to work around this problem.
void servoDelay4(void);
void servoDelay5(void);
typedef void (*fp) (void);  // 'fp' is a pointer to a function that takes no arguments and returns 'void'
fp ServoTimeoutFunctions[ServoCount] =
{servoDelay0, servoDelay1, servoDelay2, servoDelay3, servoDelay4, servoDelay5 };

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

  // Initialize all of the servos
  for (int i = 0; i < ServoCount; i++)
  {
    Servos[i].attach(ServoPins[i]);
    // ServoTimersActive[i] = false;  // Not necessary.  Globals default to 0 (false)
    ServoTimers[i].setInterval(1000, ServoTimeoutFunctions[i]);
  }
}

void servoDelay0()
{
  servoDelay(0);
}
void servoDelay1()
{
  servoDelay(1);
}
void servoDelay2()
{
  servoDelay(2);
}
void servoDelay3()
{
  servoDelay(3);
}
void servoDelay4()
{
  servoDelay(4);
}
void servoDelay5()
{
  servoDelay(5);
}

// This is the function called when each timer completes
void servoDelay(byte servoNumber)
{
  Serial.print(servoNumber);
}

void loop() {}