Access a position array in a "circular" manner.. any help?

Hi forum.
Let's try to explain my problem:
I know for sure it's easy but I cannot figure it out..

I have defined a 360 entry array "complete_array[360]" each column representing the 360 degrees circular position that fed into a servo will move it in a sinusoidal way back and forth.

Let's consider just one servo:
the function read_from_array as following:

void read_from_array() {
  if (millis() - previous_interval >= servo_update_interval) {
      pwm.setPWM(servo, 0, complete_array[array_Index]);
    }
    if (array_Index >= 359) array_Index = 0;
    else array_Index++;
    previous_interval = millis();
  }
}

Simply every updated interval it reads the array_index and sets the servo to that position.
Now my question:
I would like to access that array in different manners and starting from different starting positions using the millis() method:
from beginning to the end ( ok that's what it is doing actually) but also
from end to beginning,
back and forth, (begin->END->END-> BEGIN)
from a defined position (let's say 200 until the end and then back starting from 0).
all this using millis()
Maybe too hours of coding are obfuscating my poor C skills....
Just to keep it simple I will further explain my end goal, if someone is interested.
Thank You,
Best regards.

What would determine the pattern and start point? Parameters to the function?

Hello

Here is an example : Untitled project - Wokwi Arduino and ESP32 Simulator

1 Like

Each of your access manners is a variation on a for loop. You can define the start position, end position and step value (positive or negative) and use the for loop variable to access an element of the array

Which Arduino board are you using ?
What type of variable does the array hold ?
How frequently will you be accessing the values ?
Could you not calculate the required value on the fly rather than holding them in an array ?

Thanks.
That works pretty well for back and forth.
Thank You pal

Hi , thanks for your reply.
It's a choice from the serial port menu.
for now I have to think as a single variable I set from the beginning.

Glad you asked.
Now, in reality the goal is to build a bidmensional array of int 360 x 16 .
Have already built it and due to its size it's stored inside FLASH.
Each column contains as said before the circular position across 360 degrees of a single servo and each row is the 1/16 shifted position for each of the 16 servo.
Putting all the servo in a row the result is a sinusoidal movement across 16 servo.
Nothing fancy. the code was explained in this forum.
Now my goal is to replicate the row of 16 servo stacking them in a 4 or 8 or even 16 horizontal layers.
If every of the 4 / 8 / 16 rows is fed with the same array_position the result will be a 2D sinusoidal sine wave across the whole matrix.
Feeding every row starting with different array_position will result in a traversal sine wave or other fancy effects - I hope...
Hope I have been clear.
You asked why not calculate the required value on the fly?
Because I am afraid it would be a mess on the UNO and even in my brain keeping it all together.
Have You maybe a cleverer solution to this?
Regards

Exactly which servos are you using ?
Your mention of circular position, 360 degrees and servos worries me

No room for worries here. obviously the 360 circular degrees of a sin(x) value function are mapped to a smooth excursion between min and max position of the servo used (160degrees).

Not obvious at all as this is the first mention of such mapping. As a matter of interest, are you using servo.write() or servo.writeMicroseconds() to control the servos ?

I am using pwm.setPWM(servo,0,position) from Adafruit_PWMServoDriver.h> library.
Servo are interfaced through the PCA9685 shield.

Understood

Any little help my friend? thanks
let's suppose for simplicity I use only 8 servo for first row and other 8 out of 16 available for the second row.
I need to run following code to get both rows in sync:

void read_from_array() {
  if (millis() - previous_interval >= servo_update_interval) {
     for (int servo = 0; servo < 8; servo++) {
      pwm.setPWM(servo, 0, complete_array[array_Index][servo]); // FOR FIRST ROW "A"
      pwm.setPWM(servo+8, 0, complete_array[array_Index][servo]); // FOR SECOND ROW "B"
    }
    if (array_Index >= 359) array_Index = 0;
    else array_Index++;
    previous_interval = millis();
  }
}

This would make both rows read the same value and move each servo in sync.

But shifting for example 10values after for the second row would be:

pwm.setPWM(servo, 0, complete_array[array_Index][servo]); // FOR FIRST ROW "A"
pwm.setPWM(servo+8, 0, complete_array[array_Index+10][servo]); // FOR SECOND ROW "B"

But then I cannot read 10 value after the end of the array....
Thank You

You could use the modulo operator:

pwm.setPWM(servo + 8, 0, complete_array[(array_Index + 10) % 360][servo]); // FOR SECOND ROW "B"

Not really understanding why you need a 360 x 16 array. Since you have a 1/16 shift (22.5 degrees) two rows would be needed, but all the other rows are just identical data starting at a different offset.

1 Like

You made it! Thanks a lot.

Yes, of course but how would you assign the correct column for each 1/16 degree shifted servo lying on same row?
having a 2x360 matrix, how would you modify:

for (int servo = 0; servo < 16; servo++) {
      pwm.setPWM(servo, 0, complete_array[array_Index][servo]);

Do I need to deconstruct the for loop and assign for every servo a different array index?

Best regards and thanks again

Ok. Got it by myself. Thanks again David_2018

just in case this makes it more visual


#include <Servo.h>
const byte servoPins[] = {2, 3, 4, 5, 6, 7};
const byte servoCount = sizeof servoPins / sizeof * servoPins;
const int offset[servoCount] = {0, 10, 20, 30, 40, 50}; // offest index in the animation

Servo servos[servoCount];

// would be better in PROGMEM but too lazy for that :) 
const int animation[] = { // sinusoidal animation starting at 90°
  90,  91,  93,  94,  96,  97,  99, 100, 102, 104, 105, 107, 108, 110, 111, 113, 114, 116,
  117, 119, 120, 122, 123, 125, 126, 128, 129, 130, 132, 133, 135, 136, 137, 139, 140, 141,
  142, 144, 145, 146, 147, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161,
  162, 163, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 172, 173, 174, 174, 175,
  175, 176, 176, 176, 177, 177, 178, 178, 178, 178, 179, 179, 179, 179, 179, 179, 179, 179,
  180, 179, 179, 179, 179, 179, 179, 179, 179, 178, 178, 178, 178, 177, 177, 176, 176, 176,
  175, 175, 174, 174, 173, 172, 172, 171, 170, 170, 169, 168, 167, 167, 166, 165, 164, 163,
  162, 161, 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 147, 146, 145, 144,
  142, 141, 140, 139, 137, 136, 135, 133, 132, 130, 129, 128, 126, 125, 123, 122, 120, 119,
  117, 116, 114, 113, 111, 110, 108, 107, 105, 104, 102, 100,  99,  97,  96,  94,  93,  91,
  90,  88,  86,  85,  83,  82,  80,  79,  77,  75,  74,  72,  71,  69,  68,  66,  65,  63,
  62,  60,  59,  57,  56,  54,  53,  51,  50,  49,  47,  46,  44,  43,  42,  40,  39,  38,
  37,  35,  34,  33,  32,  30,  29,  28,  27,  26,  25,  24,  23,  22,  21,  20,  19,  18,
  17,  16,  15,  14,  13,  12,  12,  11,  10,   9,   9,   8,   7,   7,   6,   5,   5,   4,
  4,   3,   3,   3,   2,   2,   1,   1,   1,   1,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   1,   2,   2,   3,   3,   3,
  4,   4,   5,   5,   6,   7,   7,   8,   9,   9,  10,  11,  12,  12,  13,  14,  15,  16,
  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  32,  33,  34,  35,
  37,  38,  39,  40,  42,  43,  44,  46,  47,  49,  50,  51,  53,  54,  56,  57,  59,  60,
  62,  63,  65,  66,  68,  69,  71,  72,  74,  75,  77,  79,  80,  82,  83,  85,  86,  88,
};
const size_t animationCount = sizeof animation / sizeof * animation;

void setup() {
  for (byte i = 0; i < servoCount; i++) {
    servos[i].write(animation[offset[i] % animationCount]); // set initial position based on offset before attaching
    servos[i].attach(servoPins[i]);
  }
  delay(3000); // time to see the offset at start
}

void loop() {
  for (int i = 0; i < animationCount; i++) {
    for (byte s = 0; s < servoCount; s++)servos[s].write(animation[(i + offset[s]) % animationCount]);
    delay(7);
  }
}

Thanks J-M-L.
That definitively solved my request!
Thanks a lot

Glad it helped!
Season’s greetings

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.