add/remove from an array

Hi,

I was looking for a solution to store a set of values and then based on a condition remove one specific element from array. Can I use stack/ queue array to do this, if not please guide me through this.

Thank you.

Amirtk:
I was looking for a solution to store a set of values and then based on a condition remove one specific element from array. Can I use stack/ queue array to do this, if not please guide me through this.

Yes. You can assign values to elements in an array.

Here's one example.

      averagingBuffer[i][bufferIndex] = joystickInput;

The full program is attached to this post.

Do you need to actually remove elements from the array or would it be good enough to store a value indicating that the element being referenced is not being used ?

If you really do need to remove an element from an array then you will need to move the remaining elements around so if you can avoid this it will save time and complications.

thank you DuaneDegn. I am trying to understand for what you suggested....

UKHeliBob: The actual idea is for elevator buttons which need to be registered and due to some conditions which i will set, some floors need to be cancelled out along the car movement and before reaching to the requested floor. So what do you suggest for this application?

Keep a second array to record which floors are "cancelled".

const int MAX_FLOORS 10;
int ButtonFloors[MAX_FLOORS];
boolean CancelledFloors[MAX_FLOORS];

Amirtk:
Hi,

I was looking for a solution to store a set of values and then based on a condition remove one specific element from array. Can I use stack/ queue array to do this, if not please guide me through this.

Thank you.

Can you give an example?
e.g. what values we must think of?

possibly my set Class is helpful - yet another Set class - Libraries - Arduino Forum -

MorganS: would you explain more about this method or provide me an example. I am still in the learning stage...

robtillaart: the idea is for storing elevator buttons...

Amirtk:
I was looking for a solution to store a set of values and then based on a condition remove one specific element from array. Can I use stack/ queue array to do this, if not please guide me through this.

To change the value of an element in an array, you just set to a value. For example if you had an array named "myArray" and you wanted to set element #4 (the fifth element) to 99, then you'd use "myArray[4] = 99;".

Here's simple program which increments or decrements the value of the four element (element #3) of an array when a button is pressed. For good measure I had the fifth element (#4) of the array set to a value when the button is pressed. This example is pretty meaningless but I didn't want to write anything complicated.

I get the feeling I'm not understanding your question.

const byte ARRAY_SIZE = 10;
byte myArray[ARRAY_SIZE];

const byte ADD_PIN = 2;
const byte MINUS_PIN = 3;

const int DELAY_TIME = 50;


setup()
{
 for (int i = 0; i < ARRAY_SIZE; i++)
 {
   myArray[i] = i;
 }
 pinMode(ADD_PIN, INPUT_PULLUP);
 pinMode(MINUS_PIN, INPUT_PULLUP);
}

loop()
{
 if (digitalRead(ADD_PIN) == LOW)
 {
   myArray[3]++;
   myArray[4] = 99;
 }
   if (digitalRead(MINUS_PIN) == LOW)
 {
   myArray[3]--;
   myArray[4] = 22;
 }

 delay(DELAY_TIME);
}

I probably would use a struct containing two bit fields.

struct FLOOR
{
  byte selected: 1;
  byte skip: 1;
}

selected will be set if the button for a floor is pressed. skip is determined by your logic.

Simple example using an array for 8 floors.

#define NUMFLOORS 8

struct FLOOR
{
  byte selected: 1;   // bit 0
  byte skip: 1;       // bit 1
};

struct FLOOR floors[NUMFLOORS];

void setup()
{
  // the floors where to stop
  floors[2].selected = true;  // button floor2 pressed
  floors[3].selected = true;  // button floor3 pressed
  floors[3].skip = true;      // logic dictated that floor3 should be skipped

  // iterate though floors
  for (int cnt = 0; cnt < NUMFLOORS; cnt++)
  {
    if (floors[cnt].selected == true && floors[cnt].skip == false)
    {
      Serial.print("Stopped at floor ");
      Serial.println(cnt);
    }
    else
    {
      Serial.print("Skipped floor ");
      Serial.println(cnt);
    }
  }
}

void loop()
{
}

Each FLOOR element occupies one byte. You should be able to check the size of one element with e.g. Serial.println(sizeof(struct FLOOR)).

You can still use the remaining 6 bits for other stuff if you have to. Example below that adds a 2-bit variable (something) and a 4 bit variable (number)

struct FLOOR
{
  byte selected: 1;   // bit 0
  byte skip: 1;       // bit 1
  byte something: 2   // bits 2 and 3
  byte number: 4;     // bits 4 .. 7
};

You can read up on c bitfields; e.g. Bit-field - cppreference.com.

sterretje: i like this method but unfortunately i cant understand it.
Is there an easier method that i can store the buttons and when the elevator reach to the floor it remove it from array?

How can you like what you don't understand!
Apart from women that does not make sense.

It looks like you do not want to remove the array element at all which is hard in a C program. All you want to do is to store a value in the array that tells you something about that floor.
If you can actually decide what that something is then you can devise a set of numbers that will do that job. All you have decided so far is that you need one number that means do nothing.

t looks like you do not want to remove the array element at all which is hard in a C program. All you want to do is to store a value in the array that tells you something about that floor.

That is not what the OP says in post #3

Yes it is.

What he says he wants to do and what he needs to do are different things.

I think you need to define 'remove from array'. In my vocabulary, it means that the size of an array changes. And there are no ways to do that with a simple array. You will run into the same problem when using 'add to array'.

You can make use of a linked list instead of an array and remove items from the linked list; but it will add a memory overhead so might not be advisable and, if not implemented correctly, result in memory fragmentation.

Or you can make use of dynamically allocated memory that you keep on modifying on the fly; possibly not the best approach either.

Some other approaches were mentioned before and they probably are better / safer than using linked lists or dynamic memory allocation.

If you post your code, people might be able to help further. I for one am curious how you currently store selected floors in an array. If every element in your current array represents a floor, simply placing a 1 in that element can indicate that the elevator should stop and placing a 0 indicates that the floor should be skipped. If your approach is different, it would be useful for us to know :wink:

Not removing elements from an array, but based on my earlier code, you can set 'selected' to false when a floor is reached. Example code

    if (floors[cnt].selected == true && floors[cnt].skip == false)
    {
      Serial.print("Stopped at floor ");
      Serial.println(cnt);

      floors[cnt].selected = false;
    }

Amirtk:
sterretje: i like this method but unfortunately i cant understand it.

Not sure what there is 'not to understand'. Is it the struct? Or the bitfields?

A struct defines a custom type (just in case: int, char etc are types). You can combine anything in a struct.

struct PERSON
{
  char firstname[16];
  char lastname[32];
  byte age;
  char phone[16];
};

The above defines a 'logical' unit combining information about a person. You can e.g. create an array of contacts using the above.

The way I used the struct earlier uses bitfields. It allows an easy access to the single (or multiple) bits in a byte, char, long or whatever the type is that you use.

The below struct adds bitfields to the PERSON struct. It splits the original 'age' into two parts (in total occupying the same amount of space). 'age' is now limited to 127 years (7 bits) to make place for the gender field.

struct PERSON
{
  char firstname[16];
  char lastname[32];
  byte age: 7;
  byte gender: 1;
  char phone[16];
};

UKHeliBob:
What he says he wants to do and what he needs to do are different things.

Indeed this is a classic X-Y Problem

That is why he as not responded well to any of the excellent suggestions here. He is clearly inexperienced and perhaps doing an assignment.

However until he comes back and says exactly what he wants to do we are all wasting our time.

Amirtk:
The actual idea is for elevator buttons which need to be registered and due to some conditions which i will set, some floors need to be cancelled out along the car movement and before reaching to the requested floor. So what do you suggest for this application?

I would suggest you specify what these "some" things actually are and then we can all make progress. What ever they are you DO NOT NEED TO REMOVE AN ELEMENT FROM AN ARRAY.

Thanks for your suggestions. I am very new to arduino and meanwhile confused. The conditions would be sent from matlab to arduino by receiving a character like 'C' in order to cancel out the pressed buttons. but for now i just wanna figure out how to store the button presses. for example users press floor2 and floor3 buttons at a time and elevator suppose to respond to them and move towards the selected floors.

So far i just have done a two floors elevator and by pressing one button at a time...

but for now i just wanna figure out how to store the button presses.

An array has a number of levels, which makes it perfect for storing data about which floor the lift should visit.

Something like this perhaps

start of loop()
  read the call buttons in a for loop
    if a floor button has become pressed then set that level of the array to 1 (or any other convenient value)
  end of for loop
  //code here to read the array and move towards the next level where the array is set to 1
  //on arrival set the array at that level to 0
  //note that logic is required to determine whether the lift is currently stopped, moving up or moving down
  //to determine which direction to move in.
end of loop()

Hello again. Sorry i was away for a while.

I have done some programming but i have an issue. assume the car is in floor3 and i press floor1 and floor2 elevator only stops in floor2 and does not continue to floor1 anymore. How can I solve this problem?

Thank you.

const int maxfloors = 3;

byte carcall_buttons[maxfloors] = {22,24,46};
byte floor_sensors[maxfloors] = {25,26,47};

int buttonstate[3];
int sensorstate[3];

boolean registered[3] = {false, false, false};


int lastbuttonstate0 = LOW;
int lastbuttonstate1 = LOW;
int lastbuttonstate2 = LOW;

int lastsensorstate0 = LOW;
int lastsensorstate1 = LOW;
int lastsensorstate2 = LOW;

const byte led1 = 27;
const byte led2 = 23;
const byte led3 = 48;

const int motor_up = 41;
const int motor_down = 42;
const int  En = 40;

enum state {down,stop};
state elevator_state;


void setup()
{
  for (int i = 0; i<maxfloors; i++)
  {
    pinMode (carcall_buttons[i], INPUT);
    pinMode (floor_sensors[i], INPUT);
  }

  pinMode (led1, OUTPUT);
  pinMode (led2, OUTPUT);
  pinMode (led3, OUTPUT);

  pinMode(motor_up, OUTPUT);
  pinMode(motor_down, OUTPUT);
  pinMode(En, OUTPUT);

  Serial.begin (9600);
}

void loop()
{
  
  ReadButtons();
  ReadSensors();
  FloorSelection();

  static int elevato_state = stop;

   switch (elevator_state)
  {
    case down:

    if (registered[0] == true || registered[1] == true)
    {
      if (sensorstate[2] == LOW)
      {
      movedown();
      elevator_state = stop;
      }
    }

    break;

    case stop:
    
    if (registered[1] == true && sensorstate[1] == LOW)
    {
      motor_stop();
      registered[1] = false;
      
      for (int i=0;i<maxfloors;i++)
      {
        Serial.println (registered[i]);
      }
      
    }
   
    if (registered[0] == true && sensorstate[0] == LOW)
    {
      motor_stop();
      registered[0] = false;

      for (int i=0;i<maxfloors;i++)
      {
        Serial.println (registered[i]);
      }
    }

    break;
  }
}


 
void ReadButtons()
{   

  for (int i=0;i<maxfloors;i++)
  {
    buttonstate[i] = digitalRead (carcall_buttons[i]);
  }
}

void ReadSensors()
{   

  for (int i=0;i<maxfloors;i++)
  {
    sensorstate[i] = digitalRead (floor_sensors[i]);
  }
}

void FloorSelection()
{

  for (int i=0;i<maxfloors;i++)
  {
  if (buttonstate[0] != lastbuttonstate0)
  {
    if (buttonstate[0] == HIGH)
    {
    registered [0] = true;
    
    delay(100);
    Serial.println (registered [i]);
    }
  }

  if (buttonstate[1] != lastbuttonstate1)
  {
    if (buttonstate[1] == HIGH)
    {
    registered [1] = true;
    
    delay(100);
   Serial.println (registered [i]);
    }
  }

  if (buttonstate[2] != lastbuttonstate2)
  {
    if (buttonstate[2] == HIGH)
    {
    registered [2] = true;
    
    delay(100);
   Serial.println (registered [i]);
    }
  }
}
}

void motor_stop()
{
  
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  Serial.println ("idle");

  digitalWrite(motor_up, LOW);
  digitalWrite(motor_down, LOW);
  digitalWrite(En, LOW);
} 

 void moveup()
{
  digitalWrite(led1, HIGH);
  digitalWrite(led2, LOW);
  Serial.println ("up");

  digitalWrite(motor_up, LOW);
  digitalWrite(motor_down, HIGH);
  digitalWrite(En, HIGH);
}


void movedown()
{
  digitalWrite(led1, LOW);
  digitalWrite(led2, HIGH);
  Serial.println ("down");

  digitalWrite(motor_up, LOW);
  digitalWrite(motor_down, HIGH);
  digitalWrite(En, HIGH);
}

Your problem is caused by the fact that after a stop, you never set the elevator state again to down. Solve that and your problem is solved.

The way you have coded it now is not very flexible; imagine you have to do this for 100 floors. You will have to implement lines like below a hundred times (for down only).

if (registered[0] == true && sensorstate[0] == LOW)

And this line will more than likely grow out of proportions as well

if (registered[0] == true || registered[1] == true)

A bit of a redesign is advisable. For the down movement, you can probably use something like

for(cnt = MAXFLOORS -1;cnt>=0;cnt++_
{
  ....
  ....
  if (registered[cnt] == true && sensorstate[cnt] == LOW)
  ....
  ....
}

But a full redesign is very advisable.

The below shows how I would approach an elevator; maybe you can borrow parts of it

#include <Arduino.h>

#define MAXFLOORS 8         // maximum number of floors (up to 256)
#define FLOORINTERVAL 5000  // time to move from one floor to another; used for sensor simulation
#define FLOORDELAY 1000     // time that elevator waits on floor to allow people to get out and in

// direction options
enum DIRECTION
{
  UP,
  DOWN,
  NONE
};
// current direction
DIRECTION direction = NONE;

// flag indicating if elevator has stopped at floor
bool fStopped = true;

byte floors[MAXFLOORS];
byte sensors[MAXFLOORS];
byte buttons[MAXFLOORS];
byte currentfloor = 0;      // limit to 256 floors

void setup() {
  // seed random number generator
  randomSeed(analogRead(A0));
  // set current sensor
  sensors[currentfloor] = HIGH;
  // start serial comms
  Serial.begin(9600);
  Serial.println(F("Started"));
}

void loop() {
  static unsigned long prevMillis = 0;

  ReadButtons();
  ReadSensors();

  switch (direction)
  {
    case UP:
      if (floors[currentfloor] == 1)
      {
        floors[currentfloor] = 0;
        carStop();
        Serial.print(F("Stopped at floor "));
        Serial.println(currentfloor);
        prevMillis = millis();
      }
      break;
    case DOWN:
      if (floors[currentfloor] == 1)
      {
        floors[currentfloor] = 0;
        carStop();
        Serial.print(F("Stopped at floor "));
        Serial.println(currentfloor);
        prevMillis = millis();
      }
      break;
    case NONE:
      direction = getNextDirection();
      switch (direction)
      {
        case UP:
          Serial.println(F("Moving up to next selected floor"));
          carMoveup();
          break;
        case DOWN:
          Serial.println(F("Moving down to next selected floor"));
          carMovedown();
          break;
        case NONE:
          break;
      }
      break;
  }

  if (fStopped && millis() - prevMillis > FLOORDELAY)
  {
    direction = getNextDirection();
    switch (direction)
    {
      case UP:
        Serial.println(F("Doors closing. Moving up to next selected floor"));
        carMoveup();
        break;
      case DOWN:
        Serial.println(F("Doors closing. Moving down to next selected floor"));
        carMovedown();
        break;
    }
  }
}

// simulate button presses
void ReadButtons()
{
  static unsigned long prevMillis = 0;
  static unsigned long wait = 0;

  // use a random interval between button presses
  if (wait == 0)
  {
    wait = random(500, 5000);
    prevMillis = millis();
  }

  // if interval not expired
  if (millis() - prevMillis < wait)
  {
    return;
  }
  else
  {
    // reset wait so we can pick a new random delay the next time
    wait = 0;
  }

  // randomly pick a floor
  byte fl = random(0, MAXFLOORS);
  if (fl != currentfloor)
    floors[fl] = 1;
  Serial.print(F("Current floor: "));
  Serial.println(currentfloor);
  Serial.println(F("Selected floors"));
  for (int cnt = 0; cnt < MAXFLOORS; cnt++)
  {
    if (floors[cnt] == 1)
      Serial.println(cnt);
  }
}

// simulate reading of sensors while elevator moves
void ReadSensors()
{
  static unsigned long prevMillis = 0;

  switch (direction)
  {
    case UP:
      if (currentfloor < MAXFLOORS - 1)
      {
        if (millis() - prevMillis > FLOORINTERVAL)
        {
          sensors[currentfloor] = LOW;
          sensors[currentfloor + 1] = HIGH;
          currentfloor++;
          Serial.print(F("Reached floor "));
          Serial.println(currentfloor);
          prevMillis = millis();
        }
      }
      break;
    case DOWN:
      if (currentfloor > 0)
      {
        if (millis() - prevMillis > FLOORINTERVAL)
        {
          sensors[currentfloor] = LOW;
          sensors[currentfloor - 1] = HIGH;
          currentfloor--;
          Serial.print(F("Reached floor "));
          Serial.println(currentfloor);
          prevMillis = millis();
        }
      }
      break;
    case NONE:
      break;
  }
}

// determine next direction
DIRECTION getNextDirection()
{
  // current direction UP or NONE
  if (direction == UP || direction == NONE)
  {
    for (int cnt = currentfloor + 1; cnt < MAXFLOORS; cnt++)
    {
      if (floors[cnt] == 1)
        return UP;
    }
    for (int cnt = currentfloor - 1; cnt >= 0; cnt--)
    {
      if (floors[cnt] == 1)
        return DOWN;
    }
    return NONE;
  }

  // current direction DOWN
  if (direction == DOWN)
  {
    for (int cnt = currentfloor - 1; cnt >= 0; cnt--)
    {
      if (floors[cnt] == 1)
        return DOWN;
    }
    for (int cnt = currentfloor + 1; cnt < MAXFLOORS; cnt++)
    {
      if (floors[cnt] == 1)
        return UP;
    }
    return NONE;
  }
}

void carStop()
{
  fStopped = true;
}

void carMoveup()
{
  fStopped = false;
}

void carMovedown()
{
  fStopped = false;
}

Note that I have simulated button presses (in ReadButtons) and sensor readings (in ReadSensors); also note that the sensor logic is reversed compared to yours.