array of objects

For my model railroad I wrote a processing sketch which has several objects in an array list. When the program is running I can add and remove objects and toggle states of things etc etc.

Now I am writing the arduino side of the story. At the moment I am writing my Switch class. A switch object in the program is nothing more than a class to control a servo motor.

It may be that the servo is driven by an I2C servo driver board or that I use an I/O of the arduino itself. So when I make a new Switch I give 3 parameters to the constructor; the ID, the I/O pin and whether that pin is of the I2C driver or not.

As my modeltrack will contain several arduino nano's I want one universal program which lets me configure an arduino via the serial bus.

In Processing I had the convenience of dynamic sized array lists. But now.....

What I want to ask is the following. When the program is running, I'd like to be able to create a new switch object by sending instructions through the serial bus. And the arduino also needs to make switch objects with information collected from it's internal EEPROM after start up. I believe that this is all is not very problematic...

... but than... The arduino can receive an instruction via a RS485 network, telling him that switch 5 has to move to state true which will be 'curved'.

I believe that I need to construct a for-loop for this in which I call a switchArray_.getID() function of every switch untill I have a match on ID. And than call I can call switchArray*.setState(true) function to set the switch. Atleast this is what I want but...*_
This all means that I need somekind of a dynamic array to which I can add and perhaps also remove switches.
My first questions to you:
Is this possible and how would such a loop look like?
If it would not be possible, I could ofcourse create a fixed ammount Switch objects. Lets say I create 20 separate switches. Than I can build an array with a fixed size. And use setter functions from with data from EEPROM or serial bus
Last question:
what would the most practical solution be

Yes, you can dynamically create an array of objects (see C++ ‘new’ and ‘new[]’ operators). Resizing the array is a little more difficult using just the built-in types. But, why would you need to? Once you create a switch object, why would it ever “go away”. If you ever change the track layout, wouldn’t you just update the EEPROM info with the correct number of switches and restart your program? Regardless, the easiest way to “remove” an object might be to have them all organized in a linked list. In order “remove” an object you’d adjust the list’s pointers accordingly and destroy the unwanted object (see C++ ‘delete’ and ‘delete[]’) operators.

Finally, since you have multiple types of switches, your code might benefit from using polymorphism. Define a single (abstract) base switch class containing virtual methods for the interface (along with any common member variables and methods). Then, create specific child classes using inheritance from the base class.

The Nano has very little RAM, which makes dynamic memory allocation a risky business. It's ok to grab some memory at startup, but adding and dropping a lot of switches is likely to lead to fragmentation followed by allocation failures.

I'd be inclined to do the initial allocation based on config kept in EEPROM. Maybe allocate some extra slots for switches to be added and write their details back to EEPROM as they are added. If the Nano reports that it's out of spare objects, you can always reset it and get a new set of spares.

If you're really concerned about adding switches in large numbers, you could pull the current set of switch data over serial, do your python allocations and then push the new config back to be written to EEPROM.

Thank you for your awnsers. I had to look up what polymorphism precisely was. Polymorphism is heavily related to inheritance, I read. I believe that I was using polymorphism in my Processing sketch without knowing it :wink: . I have a parent class called 'railItems' and several subclasses. The parent class contains all the default functions like setPosition, getColumn etc etc.

However every child class has a unique Draw() function. And some child classes have some additional functions. At first I was using an interface but I ran into issues so I switched to inheritance instead. To call the Draw()functions was a bit trickier and was solved by:

for (int i = 0; i < railItems.size(); i++) {  
    anyClass = railItems.get(i);
    if(anyClass instanceof Switch) {  Switch sw = (Switch) anyClass; sw.Draw();}
    if(anyClass instanceof Detection) {Detection det = (Detection) anyClass; det.Draw();}
    if(anyClass instanceof Line) { Line ln = (Line) anyClass; ln.Draw();}
    if(anyClass instanceof Curve) { Curve cv = (Curve) anyClass; cv.Draw();}
    if(anyClass instanceof Memory) { Memory mem = (Memory) anyClass; mem.Draw();}
  }

Because of the arrayList I had to use the 'instanceof' keyword. Ofcourse my arduino's wont have this. Life is much easier using arrays with just one type, but I'd make my code so big.

So I get the idea of making one switch Class and several subclasses but I don't think I am going to use this. I have already written a setState function which takes a boolean 'I2C' as arguement and determens how to control the switch. This is easy enough. I do can make several constructrors.

Indeed I don't think I ever have to remove a switch and I could always erase the EEPROM or perhaps overwrite an existing switch, I thought extra functionality would not hurt but than again: "if it ain't broke, don't fix it" :smiley: :smiley: :smiley:

But to be clear. In arduino/C++ there is a method which gets the size of an array at run time???? if I call 'new' 10 times to make an array of 10 switchs, or must I use a counter to count how many times I call a constructor?

EDIT: new is java not c++, I ment calling an instructor

The 2kb ram size won't be an issue. I will be using a 16 channel I2C pwm driver board specially designed for servo motors (has the correct connectors and all). Setting the hardware address pins I can have up to 8 boards on the bus. That means 128 switches + max 17 extra switches? using remaining I/O pins. Even if I get to use 10 bytes per switch I still don't touch the 2kb. If I also use 8 MPC23017 chips for other I/O, then I will propably get a RAM issue...

Having that said. I have a rather small layout and it is modulary build. Even if I would be so rich to buy 128 switches I'd propably have 8-10 nano's underneath my tracks. So I won't be using more than 1 servo board per nano :smiley:

bask185:
But to be clear. In arduino/C++ there is a method which gets the size of an array at run time???? if I call 'new' 10 times to make an array of 10 switchs, or must I use a counter to count how many times I call a constructor?

EDIT: new is java not c++, I ment calling an instructor

That’s incorrect, both ‘new’ and ‘new[]’ are indeed C++ operators. That’s why I told you to look them up:

  MyClass *ptr;
  ptr = new MyClass;

Creates a new object of type MyClass by allocating the required memory and calling the constructor. A pointer to the newly created object is returned.

  MyClass *arrayPtr;
  arrayPtr = new MyClass[numElements];

Creates a new array of MyClass objects (with numElement elements) by allocating the required memory and calling the constructor for each element. A pointer to the first element in the newly created array is returned. You don’t need a method to get the size of the array because you supplied that size when you created it. So, you KNOW the size.

C(++) does not feature the "instanceof" keyword. It does, however, support dynamic casting:

if (Switch *sw = dynamic_cast<Switch*>(anyClass))
{
  //"anyClass" was of type "Switch*"
  sw->Draw();
}
else ...

Of course, it is easier to use polymorphism and have a base class where all shared methods are virtual! :slight_smile:

Danois90:
Of course, it is easier to use polymorphism and have a base class where all shared methods are virtual! :slight_smile:

Exactly my point in Reply #1.

Consider a musical example.

Using Static Allocation:

class Musician {
  public:
    virtual void tuneUp() = 0;
    virtual void play() = 0;
};

class GuitarPlayer : public Musician {
  public:
    virtual void tuneUp() {
      // Turn tuning post to adjust string tension
    }
    virtual void play() {
      // pluckStrings();
    }
};

class TrumpetPlayer : public Musician {
  public:
    virtual void tuneUp() {
      // Dump out spit
      // Move tuning slide
    }
    virtual void play() {
      // blowIntoHorn();
    }
};

GuitarPlayer guitar;
TrumpetPlayer trumpet;

Musician *musicians[] = {&guitar, &trumpet};
const uint8_t numMusicians = sizeof(musicians) / sizeof(musicians[0]);

void setup() {
  for (uint8_t i = 0; i < numMusicians; i++) {
    musicians[i]->tuneUp();
  }
}

void loop() {
  for (uint8_t i = 0; i < numMusicians; i++) {
    musicians[i]->play();
  }
}

Using Dynamic Allocation:

class Musician {
  public:
    virtual void tuneUp() = 0;
    virtual void play() = 0;
};

class GuitarPlayer : public Musician {
  public:
    virtual void tuneUp() {
      // Turn tuning post to adjust string tension
    }
    virtual void play() {
      // pluckStrings();
    }
};

class TrumpetPlayer : public Musician {
  public:
    virtual void tuneUp() {
      // Dump out spit
      // Move tuning slide
    }
    virtual void play() {
      // blowIntoHorn();
    }
};

Musician **musicians;
uint8_t numMusicians;

void setup() {
  uint8_t numTrumpet, numGuitar, index = 0;

  // numTrumpet = read from EEPROM
  // numGuitar = read from EEPROM
  numMusicians = numTrumpet + numGuitar;
  musicians = new Musician*[numMusicians];

  for (uint8_t i = 0; i < numTrumpet; i++) {
    musicians[index] = new TrumpetPlayer;
    index++;
  }

  for (uint8_t i = 0; i < numGuitar; i++) {
    musicians[index] = new GuitarPlayer;
    index++;
  }

  for (uint8_t i = 0; i < numMusicians; i++) {
    musicians[i]->tuneUp();
  }
}

void loop() {
  for (uint8_t i = 0; i < numMusicians; i++) {
    musicians[i]->play();
  }
}

gfvalvo:
That’s incorrect, both ‘new’ and ‘new[]’ are indeed C++ operators. That’s why I told you to look them up:

Yeah, I know// :sleeping: . My brain was not entirely turned on. It was 30 minutes later on the toilet that I realized I posted something dumbs. I work with arduino libraries often enough to know that you always use new()

I was looking at your code and it looks interesting. I had to look op what "virtual" did though, hadn't seen that word before.

What I haven't told yet is that I also have a 3rd type of switches which uses a bi-polair electromagnet. Those will be controlled with a 5V relais board. And this ofcourse can also be done by an I/O of an MCP23017 so I count a total of 4 different ways of operating a switch.

I made a separate .cpp and .h file for the Switch class and I think I'll simply use arguements to tell the constructor how to control the switch. I'll be using the fixed pointer array though. This code for the class has to written once, it might become a little complex but once functional I never to open the files again, atleast that is my hope :smiley:

bask185:
I think I'll simply use arguements to tell the constructor how to control the switch.

It's your project and there are many ways to skin the cat. To me, using polymorphism has an appealing elegance.