Using an array in class constructor

Hello all,

I am working on my first Arduino project beyond simple LEDS etc. I am constructing a crawler robot. y idea is to proof the concept on a cheap pre-built platform before going to full scale.

I spent a week fighting with C++ and finally got basic movements down. My code was a godawful hardcoded mess that would be a nightmare to change things later. Then I found Miguel Grinberg’s excellent blog (http://blog.miguelgrinberg.com/post/building-an-arduino-robot-part-i-hardware-components) on the topic and decided to adapt his code.

I have subsequently been able to build device driver’s for all of my components and got them working swimmingly. Unfortunately I am now at a stand still.

I want to add two more ultrasonic sensors, left and right. I also am considering adding Sharp IR sensors.

In order to keep the code modular I thought I would initialize an array of distance sensors so that future additions or subtractions would just require changing the size of the array.

I’ve run into a problem though - it seems using a for loop in a class constructor is not possible.

My current code looks like this:

Robot()
            : leftMotor(LEFT_MOTOR_INIT), rightMotor(RIGHT_MOTOR_INIT),
              for(i, i <= SONAR_NUM, i++){distanceSensor[i](DISTANCE_SENSOR_INIT[i])};,
              for(i, i <= SONAR_NUM, i++){distanceAverage[i](TOO_CLOSE*10)};,
              remoteControl(REMOTE_CONTROL_INIT)

......

 private:
        Motor leftMotor;
        Motor rightMotor;
        for(i, i <= SONAR_NUM, i++)
        {
            MovingAverage<unsigned int, 3> distanceAverage[i]
        };
        RemoteControl remoteControl;
        enum state_t { stateStopped, stateMoving, stateTurning, stateRemote };
        state_t state;
        unsigned long endStateTime;
        for(i, i <= SONAR_NUM, i++)
        {
            DistanceSensor distanceSensor[i]
        };

SONAR_NUM is defined as the number of sensors and DISTANCE_SENSOR_INIT is a previously defined array of constants.

Can someone suggest a method that would work with this strategy?

Edit: it looks like the forum has ate my array notations… the “”\ should be “BRACKET i CLOSEBRACKET”
Edit2: OK, thanks for the heads up on the code tags. Now it looks right.

Try using [ code ] [ /code ] tags. They exist purely for the purpose of protecting things like brackets.

It's not wise to increase or decrease the size of an array of objects on an arduino. UNO only has 2K ram and MEGA 8K. On this type of systems, you go with a fixed max number of objects of each type and save their addresses in an array of object pointers of that object type. Unused objects can have an enable property set to false.

I am not sure what you're doing in constructor. Use code tag and repost code. If you're trying to instantiate a number of objects, you should call constructor multiple times in a for loop with new operator and collect the returned addresses with a pointer array, not to call it once and have it somehow create multiple objects. The call to the new operator creates an object and passes it to the constructor. Constructor assigns initial values to variables and acquires necessary resources to the object after the memory of the object is reserved.

@majenko - thanks for helping me clean up the code issue.

@liudr - The thought behind using the array was to have the ability to attach or detach sensors and compile the code for only those attached. The array size would be set using the SONAR_NUM variable which would be defined based on the number of sensors attached. I see your point in defining a larger array.

Pardon my inexperience but I’m a bit confused by your second paragraph (as you, I’m sure, were by my code.) In every case this class will have a child class of leftMotor, rightMotor and remoteControl. In the case of a single sensor it will have only one instance of distanceSensor. In the case of three sensors I need three instances of distanceSensor. It seems like I should do this in an array.

Are you suggesting I change the code to:

for(i, i <= SONAR_NUM, i++){
Robot()
            : leftMotor(LEFT_MOTOR_INIT), rightMotor(RIGHT_MOTOR_INIT),
              distanceSensor[i](DISTANCE_SENSOR_INIT[i]),
              distanceAverage[i](TOO_CLOSE*10),
              remoteControl(REMOTE_CONTROL_INIT)
}

It's not a good idea to do I/O initialization in a constructor. If you declare a global or static instance of the object, then the order in which the constructor gets called in relation to other initialization is undefined, which can lead to strange results if you do I/O in the constructor.

In the constructor, you should restrict yourself to storing data. Write a separate 'begin' method (that you call from setup()) to initialize the I/O ports.

The best way I can think of of doing this is to create the Sonar objects in your main code and then pass them to the class:

class Sonar {
  int pin;
public:
  Sonar(int pinIn) : pin(pinIn) {
  }
  int GetValue() { return 4; }
};
class Robot {
  Sonar* sonars;
  const uint8_t numsonars;
public:
  Robot(Sonar* sonarsIn, uint8_t numsonarsIn) : sonars(sonarsIn) , numsonars(numsonarsIn) {
  }
  void method() {
    for (uint8_t i=0; i<numsonars; i++) {
      int foo = sonars[i].GetValue();
    }
  }
};

Sonar sonars[4] {3, 4, 2, 1};
Robot robot(sonars, 4);
void setup() {}
void loop() {}

You could also construct the Sonar objects inside the class with new:

class Sonar {
  int pin;
public:
  Sonar(int pinIn) : pin(pinIn) {
  }
  int GetValue() { return 4; }
};
class Robot {
  Sonar* sonars;
  const uint8_t numsonars;
public:
  Robot(uint8_t numsonarsIn) : numsonars(numsonarsIn) {
    sonars = new Sonar[numsonars];
  }
  void method() {
    for (uint8_t i=0; i<numsonars; i++) {
      int foo = sonars[i].GetValue();
    }
  }
};

Sonar sonars[4] {3, 4, 2, 1};
Robot robot(sonars, 4);
void setup() {}
void loop() {}

There might be a way to do it with templates as well, but could get tricky.

Ok, so your array size is determined at compil time? Never mind then. What is the reason you put the objects in an array? Is it because you want to iterate through all objects, such as call .sense() on all of them?

If that is the case, I recommend adding two static member variables: a pointer array, and a counter. Every time constructor adds the "this" pointer to the next empty pointer array element and increment counter. Then write a static member function such as sense_all(), so it iterates through the pointer array, calling sense on all objects.

Thank you for the ideas. I currently have the sonar class defined in the main code and it is working well. My desire was to keep the system modular so additions or changes in sensors wouldn't effect the main code. After thinking about the issue, with your guys insight, I'm thinking that perhaps I'll make the multiple sensors transparent to the robot class. I think I'll just pass the initializing values in the Robot Constructor and then define the sonars in the child class and pass the distance and sonar number back to Robot in a function.

I'll have to work on this a little to see what might work.

@liudr - didn't see your post before mine.

You are exactly on target. I want to call through each of the sensors in order, spacing the timing to avoid conflicts, and have the results delivered through an interrupt routine.

My ignorance in C++ is telling when I say that I thought the for loop was doing exactly what you recommended. Could you point me to an example of the pointer array and counter you describe?