Execute loop for an assigned time frame

No.
change

  Serial.begin(9600);

to

  Serial.begin(115200);

in your code and in the serial monitor. 115200 is the modern standard

change

      float time1 = moving_distance1 * 1000 * distance_to_time; // unit is in milliseconds

to

      unsigned long time1 = moving_distance1 * 1000 * distance_to_time; // unit is in milliseconds

the fractional part of a float doesn't count in this calculation

      while ((timeNow1 - timeAtStart1) < time1) {

Thank you so much!

I adjusted to your advice. However it seems like it's not completely fixed but is closer to what i want.

This is the serial monitor:

14:52:39.955 -> ⸮⸮⸮⸮N⸮⸮⸮r⸮⸮⸮⸮⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a+a⸮⸮⸮a+a⸮⸮⸮a-q⸮⸮⸮a-qInput values: 10,0,0,0
14:52:46.034 -> ⸮⸮⸮a!Q21------------------ INPUT VALUES ------------------
14:52:46.034 -> Moving distance 1 (mm) = 10
14:52:46.034 -> Moving distance 2 (mm) = 0
14:52:46.073 -> Moving distance 3 (mm) = 0
14:52:46.073 -> target position for linear servo (mm) = 0
14:52:46.073 -> --------------------------------------------------
14:52:46.073 -> Time that the motor should run: 279 milliseconds
14:52:46.073 -> ⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!QMotor 1 rotation time: 299 milliseconds
14:52:46.356 -> Motor 1 roated clockwise for 10 mm.
14:52:46.356 -> ⸮⸮⸮a+aMotor 1 did not rotate.
14:52:46.392 -> ⸮⸮⸮a-qMotor 1 did not rotate.

I've adjusted the baud rate to 115200 in both the code and the serial monitor, but the serial monitor outputs odd characters. Also, the expected motor run time and actual run time has a 20 millisecond difference.

What should I do with the weird characters? and how should I adjust it so that the expected and actual runtime are the same?

odd characters in the serial monitor is really odd
I have to ask what exact type of microcontroller are you using?

im currently using an Arduino Uno R3 as my microcontroller.

Do you have the dynamixel servos connected to IO-pins 0,1?

not at the moment. I was using a simple arduino board with no pins connected just to see if the code/serial monitor was propertly working. I just did the simple google search and it seems like I need a LN-101 to properly serially communicate. That may be the issue

what is an LN101?
a standard Arduino-Uno R3 board should be able to communicate without any problems with a computer.
Is the DynamixelShield connected to the arduino?
What IO-pins does the DynamixelShield use?

Yes, im planning to use a dynamixel shield on top of the arduino uno board. However, when i was running the code above, the Arduino board was not connected to the arduino.

your while-loop

      while ((timeNow1 - timeAtStart1) < time1) {
        dxl.setGoalVelocity(DXL_ID_1, 300);
        timeNow1 = millis();
      }

executes the function-call

        dxl.setGoalVelocity(DXL_ID_1, 300);

which needs some time
after executing this function-call you update

        timeNow1 = millis();

this means the new value of timeNow1 is made
after the function-call and therefore has the additional milliseconds this function-call needs

use thiscode-version tp measure this time

#include <DynamixelShield.h>
#include <Servo.h>

#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA2560)
#include <SoftwareSerial.h>
SoftwareSerial soft_serial(7, 8); // DYNAMIXELShield UART RX/TX
#define DEBUG_SERIAL soft_serial
#elif defined(ARDUINO_SAM_DUE) || defined(ARDUINO_SAM_ZERO)
#define DEBUG_SERIAL SerialUSB
#else
#define DEBUG_SERIAL Serial
#endif

DynamixelShield dxl;
Servo myservo;

const uint8_t DXL_ID_1 = 1;
const uint8_t DXL_ID_2 = 2;
const uint8_t DXL_ID_3 = 3;

const float DXL_PROTOCOL_VERSION = 2.0;

float distance_to_time = 60 / (34.2 * 2 * PI * 10);

int pos = myservo.read();

void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);
  delay(10);

  // Servo setup
  myservo.write(0); // this ensures that the linear servo is initially at rest
  myservo.attach(11);

  // dynamixel port baud rate: 57600 bps
  dxl.begin(9600);

  // Set Port Protocol Version. This has to match with DYNAMIXEL protocol version.
  dxl.setPortProtocolVersion(DXL_PROTOCOL_VERSION);

  // Get DYNAMIXEL information
  dxl.ping(DXL_ID_1);
  dxl.ping(DXL_ID_2);
  dxl.ping(DXL_ID_3);

  // Turn off torque when configuring items in EEPROM area
  dxl.torqueOff(DXL_ID_1);
  dxl.setOperatingMode(DXL_ID_1, OP_VELOCITY);
  dxl.torqueOn(DXL_ID_1);

  dxl.torqueOff(DXL_ID_2);
  dxl.setOperatingMode(DXL_ID_2, OP_VELOCITY);
  dxl.torqueOn(DXL_ID_2);

  dxl.torqueOff(DXL_ID_3);
  dxl.setOperatingMode(DXL_ID_3, OP_VELOCITY);
  dxl.torqueOn(DXL_ID_3);

}

void loop() {
  // put your main code here, to run repeatedly:
  if (Serial.available() > 0) {
    String mess = Serial.readStringUntil('.'); // input values are time "__,__,__,__."
    Serial.print("Input values: ");
    Serial.println(mess);
    delay(10);

    int mess_1 = mess.indexOf(','); // this value represents the amount of time you want to activate motor 1
    String distance1 = mess.substring(0, mess_1); // positive value: clockwise | negative value: counterclockwise
    delay(10);

    int mess_2 = mess.indexOf(',', mess_1 + 1); // this value represents the amount of time you want to activate motor 2
    String distance2 = mess.substring(mess_1 + 1, mess_2); // positive value: clockwise | negative value: counterclockwise
    delay(10);

    int mess_3 = mess.indexOf(',', mess_2 + 1); // this value represents the amount of time you want to activate motor 3
    String distance3 = mess.substring(mess_2 + 1, mess_3); // positive value: clockwise | negative value: counterclockwise
    delay(10);

    int mess_4 = mess.indexOf(',', mess_3 + 1); // this value represents the amount of time you want to activate linear servo
    String position4 = mess.substring(mess_3 + 1, mess_4); // positive value: clockwise | negative value: counterclockwise
    delay(10);

    // convert string to integer
    int moving_distance1 = distance1.toInt();
    int moving_distance2 = distance2.toInt();
    int moving_distance3 = distance3.toInt();
    int target_position4 = position4.toInt();

    unsigned long startingtime = millis();
    dxl.setGoalVelocity(DXL_ID_1, 300);
    unsigned long endingtime = millis();

    Serial.print(endingtime - startingtime);

    Serial.println("------------------ INPUT VALUES ------------------");
    Serial.print("Moving distance 1 (mm) = ");
    Serial.println(moving_distance1);
    Serial.print("Moving distance 2 (mm) = ");
    Serial.println(moving_distance2);
    Serial.print("Moving distance 3 (mm) = ");
    Serial.println(moving_distance3);
    Serial.print("target position for linear servo (mm) = ");
    Serial.println(target_position4);
    Serial.println("--------------------------------------------------");

    if (moving_distance1 > 0) {
      float time1 = moving_distance1 * 1000 * distance_to_time; // unit is in milliseconds
      Serial.print("Time that the motor should run: ");
      Serial.print(time1);
      Serial.println(" milliseconds");

      unsigned long timeAtStart1 = millis();
      unsigned long timeNow1 = millis();

      unsigned long after_F_call;
      unsigned long before_F_call;
      while ((timeNow1 - timeAtStart1) < time1) {
        before_F_call = millis();
        dxl.setGoalVelocity(DXL_ID_1, 300);
        after_F_call = millis();
        timeNow1 = millis();
      }
      Serial.println("time for function-call dxl.setGoalVelocity(DXL_ID_1, 300)");
      Serial.print(after_F_call - before_F_call);
      Serial.println(" milliseconds");

      Serial.print("Motor 1 rotation time: ");
      Serial.print(timeNow1 - timeAtStart1);
      Serial.println(" milliseconds");
      Serial.print("Motor 1 roated clockwise for ");
      Serial.print(moving_distance1);
      Serial.println(" mm.");

    }
    else if (moving_distance1 < 0) {
      int time2 = (-1) * 1000 * moving_distance1 * distance_to_time;

      unsigned long timeAtStart2 = millis();
      unsigned long timeNow2 = millis();
      while ((timeNow2 - timeAtStart2) < time2) {
        dxl.setGoalVelocity(DXL_ID_1, 1324);
        timeNow2 = millis();
      }
      Serial.print("Motor 1 rotation time: ");
      Serial.print(timeNow2 - timeAtStart2);
      Serial.println(" milliseconds");
      Serial.print("Motor 1 rotated counterclockwise for ");
      Serial.print(moving_distance1 * (-1));
      Serial.println(" mm.");
    }
    else {
      dxl.setGoalVelocity(DXL_ID_1, 0, UNIT_RPM);
      Serial.println("Motor 1 did not rotate.");
    }


    // motor 2 control
    if (moving_distance2 > 0) {
      int time3 = 1000 * moving_distance2 * distance_to_time; // unit is in milliseconds
      unsigned long timeAtStart3 = millis();
      unsigned long timeNow3 = millis();
      while ((timeNow3 - timeAtStart3) <= time3) {
        dxl.setGoalVelocity(DXL_ID_2, 300);
        timeNow3 = millis();
      }
      Serial.print("Motor 2 rotation time: ");
      Serial.print(timeNow3 - timeAtStart3);
      Serial.println(" milliseconds");
      Serial.print("Motor 2 roated clockwise for ");
      Serial.print(moving_distance2);
      Serial.println(" mm.");

    }
    else if (moving_distance2 < 0) {
      int time4 = (-1) * 1000 * moving_distance2 * distance_to_time;
      unsigned long timeAtStart4 = millis();
      unsigned long timeNow4 = millis();
      while ((timeNow4 - timeAtStart4) < time4) {
        dxl.setGoalVelocity(DXL_ID_2, 1324);
        timeNow4 = millis();
      }
      Serial.print("Motor 2 rotation time: ");
      Serial.print(timeNow4 - timeAtStart4);
      Serial.println(" milliseconds");
      Serial.print("Motor 2 rotated counterclockwise for ");
      Serial.print(moving_distance2 * (-1));
      Serial.println(" mm.");
    }
    else {
      dxl.setGoalVelocity(DXL_ID_2, 0, UNIT_RPM);
      Serial.println("Motor 1 did not rotate.");
    }

    // motor 3 control
    if (moving_distance3 > 0) {
      int time5 = 1000 * moving_distance3 * distance_to_time; // unit is in milliseconds
      unsigned long timeAtStart5 = millis();
      unsigned long timeNow5 = millis();
      while ((timeNow5 - timeAtStart5) < time5) {
        dxl.setGoalVelocity(DXL_ID_3, 300);
        timeNow5 = millis();
      }
      Serial.print("Motor 3 rotation time: ");
      Serial.print(timeNow5 - timeAtStart5);
      Serial.println(" milliseconds");
      Serial.print("Motor 3 roated clockwise for ");
      Serial.print(moving_distance3);
      Serial.println(" mm.");

    }
    else if (moving_distance3 < 0) {
      int time6 = (-1) * 1000 * moving_distance3 * distance_to_time;
      unsigned long timeAtStart6 = millis();
      unsigned long timeNow6 = millis();
      while ((timeNow6 - timeAtStart6) < time6) {
        dxl.setGoalVelocity(DXL_ID_3, 1324);
        timeNow6 = millis();
      }
      Serial.print("Motor 3 rotation time: ");
      Serial.print(timeNow6 - timeAtStart6);
      Serial.println(" milliseconds");
      Serial.print("Motor 3 rotated counterclockwise for ");
      Serial.print(moving_distance3 * (-1));
      Serial.println(" mm.");
    }
    else {
      dxl.setGoalVelocity(DXL_ID_3, 0, UNIT_RPM);
      Serial.println("Motor 1 did not rotate.");
    }

    // linear servo

  }

}

if you are using just a pure arduino-uno R3 the odd characters in the serial monitor are really strange.

can you re-produce this behaviour multiple times?
and is it always the same?

15:26:09.227 -> ⸮⸮⸮N⸮⸮⸮r⸮⸮⸮⸮⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a+a⸮⸮⸮a+a⸮⸮⸮a-q⸮⸮⸮a-qInput values: 10,0,0,0
15:26:15.840 -> ⸮⸮⸮a!Q35------------------ INPUT VALUES ------------------
15:26:15.950 -> Moving distance 1 (mm) = 10
15:26:15.987 -> Moving distance 2 (mm) = 0
15:26:15.987 -> Moving distance 3 (mm) = 0
15:26:16.025 -> target position for linear servo (mm) = 0
15:26:16.063 -> --------------------------------------------------
15:26:16.133 -> Time that the motor should run: 279.22 milliseconds
15:26:16.203 -> ⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Qtime for function-call dxl.setGoalVelocity(DXL_ID_1, 300)
15:26:16.482 -> 34 milliseconds
15:26:16.517 -> Motor 1 rotation time: 308 milliseconds
15:26:16.554 -> Motor 1 roated clockwise for 10 mm.
15:26:16.588 -> ⸮⸮⸮a+aMotor 1 did not rotate.
15:26:16.662 -> ⸮⸮⸮a-qMotor 1 did not rotate.

This is the serial monitor after using your adjusted code! I changed the serial monitor baud rate to 9600 as well and it seems like the issue of printing odd numbers is still out there.

It also takes 34 milliseconds for the function to call

yes :frowning: even if i do it multiple times, it produces the weird characters.

OK I looked up the DynamixelShield.h-library.
Indeed the DynamixelShield.h-library uses the standard serial interface

This means change back the baudrate to

Serial.begin(9600);

whenever you want to do time measurings
store timestamps of millis() and do the printing after finishing executing the part of the code

change your while-loop to

      while ((timeNow1 - timeAtStart1) < time1) {
        timeNow1 = millis();
        dxl.setGoalVelocity(DXL_ID_1, 300);
      }

or even to

do {
  timeNow1 = millis();
  dxl.setGoalVelocity(DXL_ID_1, 300);
} while (timeNow1 - timeAtStart1) < time1);
1 Like

this has the same issue and outputs:

15:33:26.376 -> Input values: 10,0,0,0
15:33:26.413 -> ⸮⸮⸮a!Q34------------------ INPUT VALUES ------------------
15:33:26.525 -> Moving distance 1 (mm) = 10
15:33:26.525 -> Moving distance 2 (mm) = 0
15:33:26.563 -> Moving distance 3 (mm) = 0
15:33:26.601 -> target position for linear servo (mm) = 0
15:33:26.638 -> --------------------------------------------------
15:33:26.706 -> Time that the motor should run: 279.22 milliseconds
15:33:26.744 -> ⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!QMotor 1 rotation time: 308 milliseconds
15:33:27.069 -> Motor 1 roated clockwise for 10 mm.
15:33:27.106 -> ⸮⸮⸮a+aMotor 1 did not rotate.
15:33:27.175 -> ⸮⸮⸮a-qMotor 1 did not rotate.

in the serial monitor.

For the second method, does

do {
  timeNow1 = millis();
  dxl.setGoalVelocity(DXL_ID_1, 300);
} while (timeNow1 - timeAtStart1) < time1);

replace

while ((timeNow1 - timeAtStart1) < time1) {
        dxl.setGoalVelocity(DXL_ID_1, 300);
        timeNow1 = millis();
      }

?

Thank you so much for helping me by the way. I really appreciate it

I changed the first if statement as below:

if (moving_distance1 > 0) {
      float time1 = moving_distance1 * 1000 * distance_to_time; // unit is in milliseconds
      Serial.print("Time that the motor should run: ");
      Serial.print(time1);
      Serial.println(" milliseconds");

      unsigned long timeAtStart1 = millis();
      unsigned long timeNow1 = millis();
      do {
        timeNow1 = millis();
        dxl.setGoalVelocity(DXL_ID_1, 300);
      } while ((timeNow1 - timeAtStart1) < time1);
        Serial.print("Motor 1 rotation time: ");
        Serial.print(timeNow1 - timeAtStart1);
        Serial.println(" milliseconds");
        Serial.print("Motor 1 roated clockwise for ");
        Serial.print(moving_distance1);
        Serial.println(" mm.");

    }

The Serial Monitor output is:
15:39:44.425 -> ⸮⸮⸮N⸮⸮⸮r⸮⸮⸮⸮⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a+a⸮⸮⸮a+a⸮⸮⸮a-q⸮⸮⸮a-qInput values: 10,0,0,0
15:39:45.895 -> ⸮⸮⸮a!Q35------------------ INPUT VALUES ------------------
15:39:46.002 -> Moving distance 1 (mm) = 10
15:39:46.002 -> Moving distance 2 (mm) = 0
15:39:46.038 -> Moving distance 3 (mm) = 0
15:39:46.075 -> target position for linear servo (mm) = 0
15:39:46.108 -> --------------------------------------------------
15:39:46.180 -> Time that the motor should run: 279.22 milliseconds
15:39:46.214 -> ⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!QMotor 1 rotation time: 308 milliseconds
15:39:46.538 -> Motor 1 roated clockwise for 10 mm.
15:39:46.575 -> ⸮⸮⸮a+aMotor 1 did not rotate.
15:39:46.644 -> ⸮⸮⸮a-qMotor 1 did not rotate.

It also runs the do statement for extra time than I want it to be. What should I do? Is this happening again because of the time it takes to call dxl.setGoalVelocity(DXL_ID_1, 300)?

change to
unsigned long time1 = moving_distance1 * 1000UL * distance_to_time; // unit is in

do you see?
unsigned long time1

and

1000UL

Thank you so much!

Unfortunately, this outputted the exact same serial monitor (times) when i inputed the same values. Should I also change

float distance_to_time = 60 / (34.2 * 2 * PI * 10);

to

unsigned long distance_to_time = 60 / (34.2 * 2 * PI * 10);

no

I have no explanation for the strange characters
as a crosscheck you could comment out the function-call
to dxl.setGoalVelocity(DXL_ID_1, 300);
and replace it with a delay(34); to simulate the function call

while ((timeNow1 - timeAtStart1) < time1) {
        //dxl.setGoalVelocity(DXL_ID_1, 300);
       delay(34);
        timeNow1 = millis();
      }

this is the serial monitor output when using delay:

16:00:19.176 -> ------------------ INPUT VALUES ------------------
16:00:19.247 -> Moving distance 1 (mm) = 10
16:00:19.284 -> Moving distance 2 (mm) = 0
16:00:19.284 -> Moving distance 3 (mm) = 0
16:00:19.319 -> target position for linear servo (mm) = 0
16:00:19.356 -> --------------------------------------------------
16:00:19.428 -> Time that the motor should run: 279 milliseconds
16:00:19.715 -> Motor 1 rotation time: 305 milliseconds
16:00:19.751 -> Motor 1 roated clockwise for 10 mm.
16:00:19.787 -> ⸮⸮⸮a+aMotor 1 did not rotate.
16:00:19.856 -> ⸮⸮⸮a-qMotor 1 did not rotate.

Should I do

while ((timeNow1 - timeAtStart1) < time1 - 34) {
        dxl.setGoalVelocity(DXL_ID_1, 300);
        timeNow1 = millis();
      }

I tried

while ((timeNow1 - timeAtStart1) < time1 - 34) {
        dxl.setGoalVelocity(DXL_ID_1, 300);
        timeNow1 = millis();
}

And the serial monitor output was:

16:09:59.731 -> ⸮⸮⸮N⸮⸮⸮r⸮⸮⸮⸮⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a+a⸮⸮⸮a+a⸮⸮⸮a-q⸮⸮⸮a-qInput values: 10,0,0,0
16:10:00.689 -> ------------------ INPUT VALUES ------------------
16:10:00.727 -> Moving distance 1 (mm) = 10
16:10:00.762 -> Moving distance 2 (mm) = 0
16:10:00.798 -> Moving distance 3 (mm) = 0
16:10:00.835 -> target position for linear servo (mm) = 0
16:10:00.869 -> --------------------------------------------------
16:10:00.937 -> Time that the motor should run: 279 milliseconds
16:10:00.973 -> ⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!QMotor 1 rotation time: 274 milliseconds
16:10:01.257 -> Motor 1 roated clockwise for 10 mm.
16:10:01.291 -> ⸮⸮⸮a+aMotor 1 did not rotate.
16:10:01.365 -> ⸮⸮⸮a-qMotor 1 did not rotate.

Which is closer but not accurate.
When I changed the input values to 20,0,0,0.

the serial monitor outputs:
16:10:51.456 -> Input values: 20,0,0,0
16:10:51.490 -> ------------------ INPUT VALUES ------------------
16:10:51.564 -> Moving distance 1 (mm) = 20
16:10:51.602 -> Moving distance 2 (mm) = 0
16:10:51.602 -> Moving distance 3 (mm) = 0
16:10:51.640 -> target position for linear servo (mm) = 0
16:10:51.675 -> --------------------------------------------------
16:10:51.746 -> Time that the motor should run: 558 milliseconds
16:10:51.782 -> ⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!Q⸮⸮⸮a!QMotor 1 rotation time: 549 milliseconds
16:10:52.346 -> Motor 1 roated clockwise for 20 mm.
16:10:52.384 -> ⸮⸮⸮a+aMotor 1 did not rotate.
16:10:52.454 -> ⸮⸮⸮a-qMotor 1 did not rotate.

As the input values increase, the discrepency between expected and actual rotation time increases.