Passing float point array value to function

I'm wanting to drive two servos using the SlowMotionServo Library:

This library built is on top of Servo.h and drives the speed and angle of the servo. Instead of specifying the angle of the servo it wants a decimal value between 0 and 1.

I want to drive the servos from a floating point dual array as seen in the sketch below ( this is a simplifed example of a larger and more complex sketch but drives at the issue I'm having).

I'm I not doing something proper to pass the floating point value from the array to the write servo function servoY.goTo(). When I run the sketch my serial monitor (using ATTiny84) show that the array value passed to the servo write function is 0.00 ?

servo Y value = -0.0000000000
array table position =1
servo X value = 0.0000000000
servo Y value = 0.0000000000
array table position =2
servo X value = 0.0000000000
servo Y value = 0.0000000000
array table position =3
servo X value = 0.0000000000
servo Y value = 0.0000000000
array table position =4
servo X value = 0.0000000000
servo Y value = 0.0000000000
array table position =5
servo X value = 0.0000000000
servo Y value = 0.0000000000
array table position =6
servo X value = 0.0000000000
servo Y value = -0.0000000000
array table position =7
servo X value = 0.0000000000
servo Y value = 0.0000000000
array table position =8
servo X value = 0.0000000000
servo Y value = 0.0000000000
array table position =9
servo X value = 0.0000000000
servo Y value = 0.0000000000

Do I need to convert the floating point array value or characterize it in some manner for it to read the proper floating point value?

#include <SendOnlySoftwareSerial.h>
SendOnlySoftwareSerial mySerial(1);  // Tx pin

#include <Servo.h>
#include <SlowMotionServo.h>
SMSSmooth servoX;  // create servo object to control a servo with sinusoidal trajectory
SMSSmooth servoY;

const int servoPinX = 5;  // X axis (left/right)  the digital pin used for the servo
const int servoPinY = 6;  // Y axis (Spin on Y) the digital pin used for the servo

int servo_table_position;
float servoX_value;
float servoY_value;

int table_array_positions = 10;
const float movement_table[2][10] PROGMEM = {
  //1st table value is servoY postion, 2nd table value is myservoX position
  /* 0 */ { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 },
  /* 1 */ { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 },
};

void setup() {
  mySerial.begin(9600);
  delay(700);
  servo_table_position = 0;

  servoY.setPin(servoPinY);
  servoX.setPin(servoPinX);
  servoY.setMin(544);   //The value can range from 544 to 2400.
  servoY.setMax(2400);  //A value lower than 544 will be reset to 544 and a value greater than 2400 will be reset to 2400.
  servoX.setMin(544);
  servoX.setMax(2400);

  servoY.setSpeed(3.5);
  servoX.setSpeed(3.5);

  servoX.setReverted(false);  // Reverse the movement. By default reverted is false. If set to true, the trajectories are mirrored across an axis at time = 0.5.

  servoY.setInitialPosition(90);  // servo at 90 degrees
  servoX.setInitialPosition(0);   // servo at 90 degrees
  SlowMotionServo::update();
}

void loop() {

  servoX_value = movement_table[1][servo_table_position];
  servoX.goTo(servoX_value);  // X axis servo sweep
  mySerial.print("servo X value = ");
  mySerial.println(servoX_value,DEC);

  servoY_value = movement_table[0][servo_table_position];
  servoY.goTo(servoY_value);  // X axis servo sweep
  mySerial.print("servo Y value = ");
  mySerial.println(servoY_value,DEC);

  if (servo_table_position > table_array_positions - 1)
    servo_table_position = 0;
  mySerial.print("array table position =");
  mySerial.println(servo_table_position);

  SlowMotionServo::update();
  servo_table_position++;
  delay(1000);
}
1 Like

To access data stored in program memory, you need to use functions like pgm_read_word, etc. See the PROGMEM reference pages.

In any case, there is no need to store tables like this one in memory. Just calculate the value from the table indices.

const float movement_table[10][10] PROGMEM = {
  //1st table value is servoY postion, 2nd table value is myservoX position
  /* 0 */ { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 },
  /* 1 */ { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 },
};

Why you created an 10x10 array, while you need an 10x2 only?

@b707 that is a mistake (typo) should be

const float movement_table[2][10] PROGMEM = {

I've corrected my orginal entry...

@jremington Ah yes, I forgot about this. If I remove PROGMEM from my array it still does not work (i.e. passes 0.00).

I would like to use PROGMEM since my target chip is a ATTINY84. looking at the reference for PROGMEM i see how to assign an array using PROGMEM but the example is only for integers. If I apply it like shown:

servoX_value = pgm_read_byte(&movement_table[1][servo_table_position]);

I don't think this would work since it is reading on a byte from program memory location? Is there a "type" for pgm_read for floating point?

If you study the Reference Guide you will learn that there are function calls for floats, long integers, character strings, etc.

https://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html

#define pgm_read_float_near(address_short) __LPM_float((uint16_t)(address_short))

@jremington Thank you. that is what I was lookking for ( pgm_read_float_near ) and has solved my issue. code below working correctly now.

#include <SendOnlySoftwareSerial.h>
SendOnlySoftwareSerial mySerial(1);  // Tx pin

#include <Servo.h>
#include <SlowMotionServo.h>
SMSSmooth servoX;  // create servo object to control a servo with sinusoidal trajectory
SMSSmooth servoY;

const int servoPinX = 5;  // X axis (left/right)  the digital pin used for the servo
const int servoPinY = 6;  // Y axis (Spin on Y) the digital pin used for the servo

int servo_table_position;
float servoX_value;
float servoY_value;

int long currentMillis;
int long prev_currMillis = 0;

int table_array_positions = 3;
const float movement_table[2][3] PROGMEM = {
  //1st table value is servoY postion, 2nd table value is myservoX position
  /* 0 */ { 0.1, 0.5, 1.0 },
  /* 1 */ { 0.1, 0.5, 1.0 },
};

void setup() {
  //mySerial.begin(9600);
  delay(700);
  servo_table_position = 0;

  servoY.setPin(servoPinY);
  servoX.setPin(servoPinX);
  //servoY.setMin(544);   //The value can range from 544 to 2400.
  //servoY.setMax(2400);  //A value lower than 544 will be reset to 544 and a value greater than 2400 will be reset to 2400.
  //servoX.setMin(544);
  //servoX.setMax(2400);

  servoY.setSpeed(3);
  servoX.setSpeed(3);

  servoX.setReverted(false);  // Reverse the movement. By default reverted is false. If set to true, the trajectories are mirrored across an axis at time = 0.5.

  servoY.setInitialPosition(90);  // servo at 90 degrees
  servoX.setInitialPosition(0);   // servo at 90 degrees
  SlowMotionServo::update();
}

void loop() {
  currentMillis = millis();
  SlowMotionServo::update();
  move_servos();
}

void move_servos() {
  if (currentMillis - prev_currMillis > 5000) {
    servoX_value = pgm_read_float_near(&movement_table[1][servo_table_position]);
    servoX.goTo(servoX_value);  // X axis servo sweep
    mySerial.print("servo X value = ");
    mySerial.println(servoX_value, DEC);
    servoY_value = pgm_read_float_near(&movement_table[0][servo_table_position]);
    servoY.goTo(servoY_value);  // X axis servo sweep
    mySerial.print("servo Y value = ");
    mySerial.println(servoY_value, DEC);

    if (servo_table_position > table_array_positions - 1)
      servo_table_position = 0;
    mySerial.print("array table position =");
    mySerial.println(servo_table_position);

    servo_table_position++;

    prev_currMillis = currentMillis;
  }
}

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