Sculpture - preset animations

Hi folks -

This robotic sculpture - 11 feet long - cycles randomly through programmed moves stored in arrays.

The 6 actuators go HIGH at different times relative to each other using a time offset variable. This allows you to save combinations of movements - like a bottom section moving 800ms before the top, etc. Snake-like movement is possible this way.

These starting time offsets are the way to animate movements between the 6 sections since speed control is not yet possible here.

An example movement where first the middle section moves, then the bottom and the top:

move1[] {800, 0, 1000}

There are two axes ( A and B ), each running the above independently. Each loop is about 30 secs and then another of these preset moves[] are selected.

...and that's the part I can't quite get.

  1. I'm not able to cleanly pass those array values to the constructor, and
  2. Not able to get random() to reinit with each loop.

Thanks very much in advance for recommendations, happy to redo the whole thing:

#include <elapsedMillis.h>

// Pins
int
pinsA[] = {3, 11, 6},
pinsB[] = {5, 10, 9};

// Durations.  These are constants.
int
durationON = 2000,
durationFADE1 = durationON * .1,
durationFADE2 = durationON * .1,
durationOFF = durationON * 5;

bool serialPrintON = true;

// The animation delays between sections.  Each loop, three of these are supposed to be chosen randomly by r below;

unsigned long r = random(0,3);

// 3 vars to pass to the Constructors.  They're chosen by r above.

long offsetArray[5][3] = {
  {1000, 1000, 1000}, // Move 1
  {1200, 600, 1200}, // Move 2
  {0, 600, 1200}, // Move 3
  {0, 200, 400}, // Move 4
  {500, 200, 0}, // Move 5
};

// For some reason only the second array group above ever gets chosen, none of the others.

long offsetA1 = (offsetArray[r][0]);
long offsetA2 = (offsetArray[r][1]);
long offsetA3 = (offsetArray[r][2]);

long offsetB1 = (offsetArray[r][0]);
long offsetB2 = (offsetArray[r][1]);
long offsetB3 = (offsetArray[r][2]);

// Power - these are constants.
int
powerON = 255,
powerFADE1 = powerON * .7,
powerFADE2 = powerON * .3,
powerOFF = 0;

// Duration
int
duration = durationON,
fade1 = durationFADE1,
fade2 = durationFADE2,
fadepower1 = powerFADE1,
fadepower2 = powerFADE2,
interval = durationOFF;

class Constructor
{
    int
    sectionPin,
    sectionPinPower;

    long
    OnTime,
    FadeTime1,
    FadeTime2,
    FadePower1,
    FadePower2,
    OffTime,
    OffsetTime;

    unsigned long previousMillis;

  public:

    Constructor(int pin, long on, long fade1, long fade2, long fadepower1, long fadepower2, long off, long offset)
    {
      sectionPin = pin;
      pinMode(sectionPin, OUTPUT);

      // Durations
      OnTime = on;
      FadeTime1 = fade1;
      FadeTime2 = fade2;
      OffTime = off;
      OffsetTime = offset;

      //Power
      FadePower1 = fadepower1;
      FadePower2 = fadepower2;

      sectionPinPower = 0;
      previousMillis = 0;
    }

    void Update() {

      unsigned long currentMillis = millis();

      if ((sectionPinPower == powerON) && ((currentMillis - previousMillis) >= (OnTime + OffsetTime)))

      {
        sectionPinPower = FadePower1;  // Turn to Fade 1
        previousMillis = currentMillis;
        analogWrite(sectionPin, sectionPinPower);
        if (serialPrintON) {
          printSerial(previousMillis, sectionPin, sectionPinPower, OnTime, FadeTime1, FadeTime2, FadePower1, FadePower2, OffTime, OffsetTime) ;
        }
      }

      else if ((sectionPinPower == FadePower1) && ((currentMillis - previousMillis) >= (FadeTime1 + OffsetTime)))

      {
        sectionPinPower = FadePower2;  // turn it to Fade 2
        previousMillis = currentMillis;
        analogWrite(sectionPin, sectionPinPower);
        if (serialPrintON) {
          printSerial(previousMillis, sectionPin, sectionPinPower, OnTime, FadeTime1, FadeTime2, FadePower1, FadePower2, OffTime, OffsetTime) ;
        }
      }

      else if ((sectionPinPower == FadePower2) && ((currentMillis - previousMillis) >= (FadeTime2 + OffsetTime)))

      {
        sectionPinPower = powerOFF;  // turn it off
        previousMillis = currentMillis;
        analogWrite(sectionPin, sectionPinPower);
        if (serialPrintON) {
          printSerial(previousMillis, sectionPin, sectionPinPower, OnTime, FadeTime1, FadeTime2, FadePower1, FadePower2, OffTime, OffsetTime) ;
        }
      }

      else if ((sectionPinPower == powerOFF) && ((currentMillis - previousMillis) >= (OffTime + OffsetTime)))

      {
        sectionPinPower = powerON;  // turn it on
        previousMillis = currentMillis;
        analogWrite(sectionPin, sectionPinPower);
        if (serialPrintON) {
          printSerial(previousMillis, sectionPin, sectionPinPower, OnTime, FadeTime1, FadeTime2, FadePower1, FadePower2, OffTime, OffsetTime) ;
        }
      }
    }
};



Constructor sectionA1(pinsA[0], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetA1);
Constructor sectionA2(pinsA[1], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetA2);
Constructor sectionA3(pinsA[2], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetA3);

Constructor sectionB1(pinsB[0], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetB1);
Constructor sectionB2(pinsB[1], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetB2);
Constructor sectionB3(pinsB[2], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetB3);

void setup()
{
  Serial.begin(115200);
  randomSeed(analogRead(0));
}


void loop()
{
  sectionA1.Update();
  sectionA2.Update();
  sectionA3.Update();

  sectionB1.Update();
  sectionB2.Update();
  sectionB3.Update();
}
  1. I'm not able to cleanly pass those array values to the constructor

Maybe show an attempt to do this so it is clearer what you mean here.

  1. Not able to get random() to reinit with each loop.

At the moment, the random() function is used to initialise a global variable only once during the execution of the program. You could modify the Update() method so it changes the value of OffsetTime (which is dependent on that randomly set variable) either on every call or say only when this is true:
sectionPinPower == powerON

Incidentally, the name "Constructor" for a class could lead to confusion.

Hi 6v6gt -

Here's my attempt to populate the 6 Classes at the bottom with a fresh set of randomly chosen vals from offsetArray, on each loop.

What's not working is:

  1. The Classes only populate with the second array. Something wrong with random().
  2. It doesn't refresh on each loop.

Here is what I'm doing:

  1. Randomly choose 3 arrays out of the five

  2. For each of the arrays, I assign indexes[0], [1], [2] to offset1/offset2/offset3.

Update() is pretty long so I did not include it here. Thanks!!!!

unsigned long r = random(0,2);

long offsetArray[5][3] = {
  {1000, 1000, 1000}, // Move 1
  {1200, 600, 1200}, // Move 2
  {0, 600, 1200}, // Move 3
  {0, 200, 400}, // Move 4
  {500, 200, 0}, // Move 5
};

long offsetA1 = (offsetArray[r][0]);
long offsetA2 = (offsetArray[r][1]);
long offsetA3 = (offsetArray[r][2]);

long offsetB1 = (offsetArray[r][0]);
long offsetB2 = (offsetArray[r][1]);
long offsetB3 = (offsetArray[r][2]);

Constructor sectionA1(pinsA[0], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetA1);
Constructor sectionA2(pinsA[1], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetA2);
Constructor sectionA3(pinsA[2], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetA3);

Constructor sectionB1(pinsB[0], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetB1);
Constructor sectionB2(pinsB[1], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetB2);
Constructor sectionB3(pinsB[2], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetB3);

void setup()
{
  Serial.begin(115200);
  randomSeed(analogRead(0));
}


void loop()
{
  sectionA1.Update();
  sectionA2.Update();
  sectionA3.Update();

  sectionB1.Update();
  sectionB2.Update();
  sectionB3.Update();
}

Air2air:
Something wrong with random().

I can assure you that the ‘random()’ function works exactly as documented. Whether how it works meets your expectations is another matter. If it doesn’t, then your expectations are wrong. Perhaps you could post an MCVE. This is the absolute minimum (but complete) code that will compile and demonstrate the problem. Nothing extra.

gfvalvo:
I can assure you that the ‘random()’ function works exactly as documented. Whether how it works meets your expectations is another matter. If it doesn’t, then your expectations are wrong. Perhaps you could post an MCVE. This is the absolute minimum (but complete) code that will compile and demonstrate the problem. Nothing extra.

Sorry, I meant my implentation doesn't work, of course the lib does. Here is the full MCVE as you requested... thanks for the suggestions gfvalvo.

This compiles and in the serial monitor you will see the problem: offset values of 222 only, where I need random choices from all 5:

#include <elapsedMillis.h>

// Pins
int
pinsA[] = {3, 11, 6},
pinsB[] = {5, 10, 9};

// Durations constants 
int
durationON = 2000,
durationFADE1 = durationON * .1,
durationFADE2 = durationON * .1,
durationOFF = durationON * 5;

//Serial print ON
bool serialPrintON = true;

/*
 The randomization section that is supposed to grab 3 out of the 5 arrays, but only grabs the second one. 
*/

unsigned long r = random(0,2);

long offsetArray[5][3] = {
  {111, 111, 111}, // Move 1
  {222, 222, 222}, // Move 2
  {333, 333, 333}, // Move 3
  {444, 444, 444}, // Move 4
  {555, 555, 555}, // Move 5
};


long offsetA1 = (offsetArray[r][0]);
long offsetA2 = (offsetArray[r][1]);
long offsetA3 = (offsetArray[r][2]);

long offsetB1 = (offsetArray[r][0]);
long offsetB2 = (offsetArray[r][1]);
long offsetB3 = (offsetArray[r][2]);

/*
 Constants not related to the randomization
*/

// Power vars
float
powerON = 255,
powerFADE1 = powerON * .7,
powerFADE2 = powerON * .3,
powerOFF = 0;

// Duration vars
int
duration = durationON,
fade1 = durationFADE1,
fade2 = durationFADE2,
fadepower1 = powerFADE1,
fadepower2 = powerFADE2,
interval = durationOFF;


/* 
The millis loop where Update() changes the section states based on previousMillis.
*/


class Constructor
{
    int
    sectionPin,
    sectionPinPower;

    long
    OnTime,
    FadeTime1,
    FadeTime2,
    FadePower1,
    FadePower2,
    OffTime,
    OffsetTime;

    unsigned long previousMillis;

  public:

    Constructor(int pin, long on, long fade1, long fade2, long fadepower1, long fadepower2, long off, long offset)
    {
      sectionPin = pin;
      pinMode(sectionPin, OUTPUT);

      // Durations
      OnTime = on;
      FadeTime1 = fade1;
      FadeTime2 = fade2;
      OffTime = off;
      OffsetTime = offset;

      //Power
      FadePower1 = fadepower1;
      FadePower2 = fadepower2;

      sectionPinPower = 0;
      previousMillis = 0;
    }

    void Update() {

      unsigned long currentMillis = millis();

      if ((sectionPinPower == powerON) && ((currentMillis - previousMillis) >= (OnTime + OffsetTime)))

      {
        sectionPinPower = FadePower1;  // Turn to Fade 1
        previousMillis = currentMillis;
        analogWrite(sectionPin, sectionPinPower);
        if (serialPrintON) {
          printSerial(previousMillis, sectionPin, sectionPinPower, OnTime, FadeTime1, FadeTime2, FadePower1, FadePower2, OffTime, OffsetTime) ;
        }
      }

      else if ((sectionPinPower == FadePower1) && ((currentMillis - previousMillis) >= (FadeTime1 + OffsetTime)))

      {
        sectionPinPower = FadePower2;  // turn it to Fade 2
        previousMillis = currentMillis;
        analogWrite(sectionPin, sectionPinPower);
        if (serialPrintON) {
          printSerial(previousMillis, sectionPin, sectionPinPower, OnTime, FadeTime1, FadeTime2, FadePower1, FadePower2, OffTime, OffsetTime) ;
        }
      }

      else if ((sectionPinPower == FadePower2) && ((currentMillis - previousMillis) >= (FadeTime2 + OffsetTime)))

      {
        sectionPinPower = powerOFF;  // turn it off
        previousMillis = currentMillis;
        analogWrite(sectionPin, sectionPinPower);
        if (serialPrintON) {
          printSerial(previousMillis, sectionPin, sectionPinPower, OnTime, FadeTime1, FadeTime2, FadePower1, FadePower2, OffTime, OffsetTime) ;
        }
      }

      else if ((sectionPinPower == powerOFF) && ((currentMillis - previousMillis) >= (OffTime + OffsetTime)))

      {
        sectionPinPower = powerON;  // turn it on
        previousMillis = currentMillis;
        analogWrite(sectionPin, sectionPinPower);
        if (serialPrintON) {
          printSerial(previousMillis, sectionPin, sectionPinPower, OnTime, FadeTime1, FadeTime2, FadePower1, FadePower2, OffTime, OffsetTime) ;
        }
      }
    }
};


Constructor sectionA1(pinsA[0], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetA1);
Constructor sectionA2(pinsA[1], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetA2);
Constructor sectionA3(pinsA[2], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetA3);

Constructor sectionB1(pinsB[0], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetB1);
Constructor sectionB2(pinsB[1], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetB2);
Constructor sectionB3(pinsB[2], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetB3);

void setup()
{
  Serial.begin(115200);
  randomSeed(analogRead(0));
}


void loop()
{
  sectionA1.Update();
  sectionA2.Update();
  sectionA3.Update();

  sectionB1.Update();
  sectionB2.Update();
  sectionB3.Update();
}


void printSerial(
  
  int prevMillis, 
  int sectionPin, 
  int sectionPower, 
  int OnTime, 
  int FadeTime1, 
  int FadeTime2, 
  int FadePower1, 
  int FadePower2, 
  int OffTime, 
  long OffsetTime
  ) {
  Serial.print(prevMillis);
  Serial.print(":\t");

  if ((sectionPin == pinsA[0]) || (sectionPin == pinsA[1]) || (sectionPin == pinsA[2])) {
    Serial.print("A pin ");
  } else if ((sectionPin == pinsB[0]) || (sectionPin == pinsB[1]) || (sectionPin == pinsB[2])) {
    Serial.print("B pin ");
  }
  Serial.print(sectionPin);

  Serial.print(":\tpower ");
  Serial.print(sectionPower);

  if (sectionPower == powerOFF) {
    Serial.print("\tOFF\tfor ");
    Serial.print(OffTime);
  } else if (sectionPower == FadePower1)  {
    Serial.print("\tFADE 1\tfor ");
    Serial.print(FadeTime1);
  } else if (sectionPower == FadePower2)  {
    Serial.print("\tFADE 2\tfor ");
    Serial.print(FadeTime2);
  } else if (sectionPower == powerON) {
    Serial.print("\tON\tfor ");
    Serial.print(OnTime);
  }

  Serial.print("ms,\toffset = ");
  Serial.print(OffsetTime);
  Serial.println("ms");

}

That code doesn't compile for me using IDE 1.8.5 -- at least not for an Uno, Mega, or Teensy 3.2. It will only compile if I add a function prototype at the top:

void printSerial(int prevMillis, int sectionPin, int sectionPower, int OnTime, int FadeTime1, int FadeTime2, int FadePower1, int FadePower2, int OffTime, long OffsetTime);

Does it compile for you as-is? What version IDE? What board?

Also, it's hardly "minimal". Can't you pare it down some and still show the problem? Does demonstrating the problem REALLY require 6 instances of the 'Constructor' class? If not, get rid of as many as possible. Can you show the problem with a simpler 'Update()' function? If so, make it simpler.

Many times in the process of making an MCVE by paring down the code, you'll find the problem yourself.

Also, set your compiler warnings to "All". The compiler is giving some warnings that you should pay attention to.

Thank you very much gfvalvo - doing all that right now. Didn't know about the compiler warnings, much appreciated.

IDE 1.8.9, testing on a Mega, then I put it on a Pro Mini for production.

I wasn't even aware that random() would work to initialize a global variable, generally I thought of it as a run-time function, but part of your problem is that random() will always generate the same sequence of pseudo-random numbers each time the sketch is run, unless you give it a randomSeed() command first, and randomSeed() doesn't seem to work outside of the actual code section.

Personally I would declare the variables without initializing them, then generate the random number and assign the values in setup.

That reminds me of this old one...

 randomNumber = 6;  //chosen by fair dice roll

You only rolled the dice once. You never call random() again in your code.

david_2018:
I wasn't even aware that random() would work to initialize a global variable, generally I thought of it as a run-time function, but part of your problem is that random() will always generate the same sequence of pseudo-random numbers each time the sketch is run, unless you give it a randomSeed() command first, and randomSeed() doesn't seem to work outside of the actual code section.

Personally I would define the variables without initializing them, then generate the random number and assign the values in setup.

Yeah let me try that last part now and post the results, thank you david_2018.

david_2018:
I wasn't even aware that random() would work to initialize a global variable, generally I thought of it as a run-time function, but part of your problem is that random() will always generate the same sequence of pseudo-random numbers each time the sketch is run, unless you give it a randomSeed() command first, and randomSeed() doesn't seem to work outside of the actual code section.

C++ does indeed allow dynamic initialization of global variables. But, you need to be careful about assumptions you make about the order of initialization and what is initialized in other compilation units.

It will probably "work" in this case. But, as you surmised, will always return the same first "random" number.

Just in case this is not clear, the statement:

unsigned long r = random(0,2) ;

(a) returns either 0 or 1 (not 2) and (b) subsequent uses of the variable r will not return a new random number because r is not an alias for a function or C/C++ macro. It is a simple variable.

If you want different random numbers to be used during the execution of your sketch, you must call the random() function each time you need a fresh random number.

Thanks again, took your advice and I am able to get only the Move 1 array below, and am confused whyI'm still not getting a new rand val with random(0,4) in the loop as shown here.

Isn't it firing each loop?

long offsetArray[5][3] = {
  {111, 112, 113}, // Move 1
  {221, 222, 223}, // Move 2
  {331, 332, 333}, // Move 3
  {441, 442, 443}, // Move 4
  {551, 552, 553}, // Move 5
};



void setup()
{
  Serial.begin(115200);
  randomSeed(analogRead(0));
}

unsigned long r;

loopClass
sectionA1(pinsA[0], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetArray[r][0]);

void loop()
{

  r = random(0, 4);
  
  sectionA1.Update();
}

It is an order of execution issue.
This happens once and early in the execution of your program:

loopClass sectionA1(pinsA[0], duration, fade1, fade2, fadepower1, fadepower2, interval, offsetArray[r][0]);

that is when the object sectionA1 is instantiated.

That means that the new value of 'r' in the loop here:

void loop()
{

  r = random(0, 4);
 
  sectionA1.Update();
}

is never "seen". You could alter Update() to read read 'r' directly or pass 'r' as a parameter to Update() then it would get a fresh value of 'r' each time it is called.

in computers and chips random numbers need to come from somewhere. there are no dice. so chips and processors use anything they can that might be random to generate random numbers. computers can use randomly fluctuating CPU heat reading or whatever random noise. these sources are called "seeds". arduino's default function uses the random reading from just one pin. this works if you are true getting a random fluctuation from the one pin that you have chosen but I have had problems with certain pins on certain boards not producing enough randomness too.

fortunatly the math to apply for using these numbers is simple. the math modulus (or remainder) of your highest number is going to give you your most random possibility.

if you are not getting a random enough reading from your one pin you can use multiple random seeds to improve the randomness. i dont think multiple seeds are supported with the official random function like most other operating systems would do in the background.

arduino boards also have a very sensitive clock that keeps track of microseconds that can also be used.
if there are small differences in time when your function is called it can add to the randomness.

if you have any type of finely reading sensors you can use them too.
the more randomness you have to work with the closer you can get to true random

anyways here is a small code function example of stacking multiple pins and things to improve your randomness. the example scetch im giving you prints 100 random numbers based on three pins randomness and time.

byte randomnumber;
void setup() { Serial.begin(9600);
byte i = 100;
while(i>0){i--;
randomnumber = shuffle(randomnumber,10,analogRead(A0));
randomnumber = shuffle(randomnumber,10,analogRead(A1));
randomnumber = shuffle(randomnumber,10,analogRead(A2));
int m = int(micros());if(m<0){m*=-1;}
randomnumber = shuffle(randomnumber,10,m);
Serial.print(" "+String(randomnumber));
}

}

void loop() {
  // put your main code here, to run repeatedly:

}

byte shuffle (byte start,byte limit,int seed){
  
  while(seed>limit){seed-=limit;}
  seed+=start;
  while(seed>limit){seed-=limit;}
  return seed;
  
  }

taterking:
arduino's default function uses the random reading from just one pin.

No the Arduino pseudo random generator starts always with the same value, unless randomSeed is used.

@Air2air

    Constructor(int pin, long on, long fade1, long fade2, long fadepower1, long fadepower2, long off, long offset)
    {
      sectionPin = pin;
      pinMode(sectionPin, OUTPUT);

You should not include hardware related code in a constructor.
The system may not be initialized properly at the time the constructor is called.
Move the hardware initializations to a seperate function (begin is a commonly used name for such a function),
that will be called from setup, where it is save to use the hardware.

When I made my comment, I was intending something more like this:

to declare the variables:

byte r; 

long offsetA1;
long offsetA2;
long offsetA3;

long offsetB1;
long offsetB2;
long offsetB3;

and to initialize the variables:

void setup()
{
  Serial.begin(115200);
  randomSeed(analogRead(0));
  r = random(0, 5);
  offsetA1 = (offsetArray[r][0]);
  offsetA2 = (offsetArray[r][1]);
  offsetA3 = (offsetArray[r][2]);
  offsetB1 = (offsetArray[r][0]);
  offsetB2 = (offsetArray[r][1]);
  offsetB3 = (offsetArray[r][2]);
}

I'm not really sure how you would update the offset variables within loop, since you would presumably need to synchronize the change in value with the timing elements of the program, and with the various sections running on different timing delays that could get complex. I can understand the basic logic of your code, but I lack the knowledge of c language to understand constructors and their use.

taterking:
in computers and chips random numbers need to come from somewhere. there are no dice. so chips and processors use anything they can that might be random to generate random numbers. computers can use randomly fluctuating CPU heat reading or whatever random noise. these sources are called "seeds". arduino's default function uses the random reading from just one pin. this works if you are true getting a random fluctuation from the one pin that you have chosen but I have had problems with certain pins on certain boards not producing enough randomness too.

fortunatly the math to apply for using these numbers is simple. the math modulus (or remainder) of your highest number is going to give you your most random possibility.

if you are not getting a random enough reading from your one pin you can use multiple random seeds to improve the randomness. i dont think multiple seeds are supported with the official random function like most other operating systems would do in the background.

arduino boards also have a very sensitive clock that keeps track of microseconds that can also be used.
if there are small differences in time when your function is called it can add to the randomness.

if you have any type of finely reading sensors you can use them too.
the more randomness you have to work with the closer you can get to true random

anyways here is a small code function example of stacking multiple pins and things to improve your randomness. the example scetch im giving you prints 100 random numbers based on three pins randomness and time.

byte randomnumber;

void setup() { Serial.begin(9600);
byte i = 100;
while(i>0){i--;
randomnumber = shuffle(randomnumber,10,analogRead(A0));
randomnumber = shuffle(randomnumber,10,analogRead(A1));
randomnumber = shuffle(randomnumber,10,analogRead(A2));
int m = int(micros());if(m<0){m*=-1;}
randomnumber = shuffle(randomnumber,10,m);
Serial.print(" "+String(randomnumber));
}

}

void loop() {
  // put your main code here, to run repeatedly:

}

byte shuffle (byte start,byte limit,int seed){
 
  while(seed>limit){seed-=limit;}
  seed+=start;
  while(seed>limit){seed-=limit;}
  return seed;
 
  }

Taterking - thanks for that, modifying it now to choose 1 array out of 5 randomly, I need only one number each time the main loop runs:

  byte i = 1;
  while (i > 0) {
    i--;
    randomnumber = shuffle(randomnumber, 5, analogRead(A0));
    randomnumber = shuffle(randomnumber, 5, analogRead(A1));
    randomnumber = shuffle(randomnumber, 5, analogRead(A2));
    int m = int(micros()); if (m < 0) {
      m *= -1;
    }
    randomnumber = shuffle(randomnumber, 5, m);
    Serial.println(" " + String(randomnumber));
  }