Need faster tone() alternative for closed loop feedback

Hello

With Arduino Pro Micro (which is same as Leonardo) or Uno (in worst case) i need to make relatively stable by frequency alternative to the tone() function, which should output signal to digital pin in ranges from 0 Hz to around 6000-10000 Hz (higher is better of course). It will be connected to STEP/DIR three phase driver and I2C magnetic absolute encoder AS5600 to fix non smooth rotation of the servo motor at low rpm. Using this encoder (non incremental) is performance costly, i can't just measure time passed and to call digitalWrite(). I'm not much familiar with timer interrupts to create a code which generate square wave like tone() do and which could change it's requency pretty quick (and no conflicts with I2Cof any kinds), that's why asking for help or some kicks in right direction. Another thing, i prefer to avoid using external libraries for this, if possible, because want manually to adjust in the code various fixes against resonanse condition, acceleration when it's stuck, speed limiting, so on.

Thanks in advance

The STEP/DIR is used for stepper motor controllers.
Can you give a link to your motor and your driver ? or show a photo of it.

The I2C AS5600 is not fast enough to keep track of a high speed rotation. It gives the position now and then.

What is the problem with the Arduino tone() function ? Why is it slow.
You could replace the tone() function with a hardware timer, or with something that still works at 1Hz.

What is the lowest frequency that you need ?

1 Like

I do use three phase stepper driver 3DM683 by Leadshine and sewing machine servo motor Jack 563A which is cheaper alternative to CNC servo, just lower assembling quality, different dimentions and no encoder (but with hall sensors). That servo do have it's own driver, but my task is to rotate it with very low speed, below 6 turns per second (i set target as 6 just to have enough room for this to work properly, but really need way slower). Cogging effect is very annoying and do have around 20 positions per turn when it happens, so my task eliminate it.

Few blogs say AS5600 is enough for such low rpm, so i decided to try it. I never used yet I2C devices and this one should consume all the bandwidth, so i suppose there is almost not free time left for other things if i want good enough precision.

tone() function is generally slow to call, i need as quick as possible to do output corrected data to driver.

Lowest frequency i need is 0 Hz. Of course too low values can be implemented by reading time passed and digitalWrite, something like 0.1 Hz. But as i'm not familiar much with interrupts then do not know how to turn them off to output at low rpm by using digitalWrite() function from elapsed time calculations.

Leadshine stepper driver 3DM683 : http://www.leadshine.com/productdetail.aspx?&model=3dm683

Page at Jack Sewing Machine where they mention their 563A : https://www.jacksewingmachine.eu/servo-motors/servo-motors/
This might be a photo of the control board: https://www.college-sewing.co.uk/jk-18-220v-pcb-board-for-jk563a-750w-jack-servo-motor.html

I don't understand why they call it a "servo" motor.

For a slow rpm, the AS5600 is okay of course, but not up to 10 kHz.
The ToneAC library can go as low as 1Hz. I think you have to make a lower frequency yourself with digitalWrite() and delay or millis().

Why is the tone() function slow to call ? Who told you that ?
The lowest frequency it can do is about 31Hz.

With a led, you could test the low frequency.
With a millis-timer, a single pulse every few days is possible. I think that the maximum accurate frequency is lower than 100 Hz.

// Low frequency 50% duty cycle signal
// Using the Blink Without Delay
//   https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay
//
// For a motor driver, a short pulse should be enough.
// However, the minimal pulse width is not known.

float frequency = 1.0;        // start with 1 Hz blinking led
unsigned long previousMillis;
unsigned long interval = 500;

void setup() 
{
  Serial.begin(115200);
  Serial.setTimeout(50);
  Serial.println( "Enter a frequency, for example: 0.25");
  pinMode( 13, OUTPUT);
}

void loop() 
{
  unsigned long currentMillis = millis();

  // ---------------------------------------------------
  // Read Serial input for the frequency
  // ---------------------------------------------------
  if( Serial.available() > 0)
  {
    delay( 50);      // wait for whole line to be received, delays are bad
    frequency = Serial.parseFloat();      // this function can wait, delays are bad
    // remove any remaining characters
    while( Serial.available() > 0)
      Serial.read();

    Serial.print( "New frequency : ");
    Serial.println( frequency);
    float T = (1 / frequency) * 1000.0 * 0.5; // half T in milliseconds
    interval = (unsigned long) T;
  }

  // ---------------------------------------------------
  // millis-timer
  // ---------------------------------------------------
  if( currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;    // previousMillis += interval is better here

    // Invert the digital output
    int state = digitalRead(13);
    if( state == HIGH)
      state = LOW;
    else
      state = HIGH;
    digitalWrite( 13, state);
  }
}

This sketch in Wokwi:

Note: Entering 0 Hz to stop the output can be added.

Thanks for response. Yeah, those links are correct to devices which i have, but it doesn't matter cause any can be used as the goal to implement closed loop for a STEP/DIR driver.

That motor is called servo because it's PMSM servo type, tear down pictures of such motors are exactly the same as CNC ones, just no encoder installed.

Regarding AS5600 and 10 kHz, i didn't mean data will be read that fast from it (as i understood from blogs it should be somewhere around 1 kHz max), but that higher frequency is for predictable rotation when data from encoder is delayed but still need to pump STEP output pin.

I said about slow performance of tone() function cause several months ago measured it for Uno when worked with another motor driver idea. Of course slow or fast is relative, but my current task it is bad. I just remember it's comparable or even slower than analogRead().

You probably have to switch between code for the full frequency range.
Using millis : 0.0000001 Hz to "less-then-100"
Arduino tone() : 31 Hz to a few hundred kHz ?
ToneAC : 1 Hz to more than 1MHz ?

So a PMSM Servo is not like a normal Servo motor, now I understand.

The Arduino tone() function might take a few microseconds, it is impossible that those microseconds are a problem for a mechanical motor.
If you call the tone() function hundreds times per second, then the sketch is wrong.

There are good libraries for measuring a rpm or frequency: FreqMeasure and FreqCount.
Even with those, you might have to switch between libraries for the full range.

Thanks, i'll try ToneAC soon. There are some divisions in it's code which are bad to performance and can be replaced by >> fortunately.

No, PMSM servo motors are normal servo, just designed to run with sinus shape of voltage instead of trapezoidal like BLDC (but BLDC are fine with sinus as well) and as i saw all PMSM are higher voltage by design as more powerful than low voltage servo motors, usually starting from 400 W and somewhere up to 15 kW.

If somebody curious, found my performance test of tone() function with Arduino Uno - 276 us. It's 2.5 times slower than analogRead().

Why would a few microseconds matter for such a motor ?
On this forum we see new users that worry about a few microseconds here and there and when we see the sketch, then there are many delay() in the sketch.

When you communicate with a I2C devices, then the Arduino is waiting most of the time. The function Wire.endTransmission() and Wire.requestFrom() are blocking, they wait until the complete I2C session has finished.
During that waiting, the Arduino does nothing, it is just sitting there and waiting (although interrupt routines are still running).

Guess you underestimate the problem, it's not few microseconds. For example, each division of unsigned long used in ToneAC takes 38 us, which is 26 kHz maximum already just to spin in cycle divisions. When feedback is delayed the smooth rotation to fix cogging issue simply do not work. The higher resolution and feedback response speed - the smoother result is. As i mentioned, motor have around 20 cogging positions per turn (most likely 21), it's 17 degrees each, so half of it for acceleration up and second half for acceleration down - 9 degrees. Somehow i have to change frequency at this moment as many times as possible to avoid vibration and noise. I hope something like 1-2 degrees would be enough to fix vibration from cogging, but that leads to 2000 tone() updates per second at maximal 360 rpm, which may fail with I2C and other calculations, simply calling tone() twice already near the performance limit. Cause of the slow encoder itself i want to make prediction algorithms, but they can't work if output can't be updated fast enough.

Thanks for the explanation.

I sure did. A lot !

Starting a hardware timer and only change a 16-bit register of the timer is very fast, but the range is limited. It can cause jitter, in the end you probably need as much code as tone() or ToneAC.

I doubt if your project can be done with an Arduino. I'm afraid that I have reached the limit of my knowledge.

In my opinion, your problem is not that you need a faster tone() alternative.
My suggestion is that you make a new topic (with a link to this one) and ask about the basic problem that you want to solve, and put it in the Motors, Mechanics, Power and CNC Category. You don't even have to mention tone() or ToneAC.
The topic title could have something with "anti cogging", "high speed", "motor control" "live adjust pulse frequency" or something like that.
Maybe you could add a picture of a anti-cogging signal.

Could you read about the https://xyproblem.info/ ?

Sorry, i thought this question suit this forum category better as it's more generic request about programming, doubt many people here did such exotic task as i need to do. Even without taking in a count hardware side, just a way to change very quick frequency of the signal is the solution for me.
Here on the video at 2:28 what kind of problem i have (but with 21 positions per turn): https://youtu.be/Rp8YyCMY4vs?t=148
And attached picture is what kind of signal i need, black lines is the moment where tone() should be executed to change frequency. Those waves not need to be exactly square type, cause motor driver count only 0 to 1 change.

Hi,
Is this for a CNC spindle drive?

Tom... :smiley: :+1: :coffee: :australia:

Hi! I know people use such servo motors as CNC spindle, that's why it catched my eye. But i want to try use it for robotics as much cheaper alternative to CNC servos yet same powerful and silent. Motors from hoverboard were not suitable by dimentions and rotor inertia and i didn't find yet anything better than servos.

Hi,

For position control or speed?

Tom... :smiley: :+1: :coffee: :australia:

It's for direct drive wheels which should be controlled by other sensors to keep balance and to move. No need fast speed or precision, quick enough response to not fall is a must and as low noise as possible cause use at home. I tested various elements for this idea separately but several years was not lucky buying different motors which do not suit this task. BLM57180 was the best with very tiny cogging, but it's torque is around 8 times lower than sewing machine servo motor.

What is the required torque and the required rpm ?

How does the robotics mechanic look like?

best regards Stefan

Experiments with hoverboard motors made me think that 2.1 Nm is enough. But this new servo motor gives even bigger torque (there is no datasheet, so i set current and measured temperature as limitation factor and got over 3 Nm at 2.9 amps rms). 360 rpm max seems enough too. There is no body for the robot, i just use aluminium construction profile 20*20 to build something quick. Basically it's like self controlled hoverboard scooter with two wheels which must keep balance and some other motors on it to apply tracking in other axes. Initially wanted to use it for video recording platform but realized it can be used for other interesting things.

C'mon, i just asked programming solution to the problem, mechanical details do not matter at all.

Yes you asked for programming details. The reason I asked for the overview is this:
details versus overview:

We are talking about details. Please give an overview over your whole project.
in mimimum 70% of all cases knowing the whole thing offers completely different and much better working solutions.

This is like

here is an analogon that shall show what can happen if you just ask for details:

newcomer: "I want to do better cutting please help me sharpening. "
Expert: Sure I can help you. What kind of cutting-tool are you using?
newcomer: a scissor.
Expert: OK take this sharpening tool
newcomer: Yea works great Next question How can I make it cut faster I need to finish faster.
expert: Motorised scissors.
newcomer Yea works great though still not fast enough.

expert: Ok can you give an overview about what you are cutting.
newcomer: the green of a football-arena.
expert: Oha! take a big mowing tractor with a seven boom spindel-mower and GPS-steering
and the job is done within two hours (instead of weeks)

In the beginning the newcomer always just told details.
The expert was assuming the newcomer knows that his basic approach is well suited.
which turns out to be very bad suited
that's the reason why it is always a good idea to give an overview and to explain what shall happen in the end.

If you want to keep the project a secret. You can do so. Though others can only make suggestions to the known details.

best regards Stefan

Haha, funny example, i like it. Of course it's not a secret, i just get used that providing more details make people lose the track of initial goal, discussion turns to flood often. Alright, i'll try next time write more when ask for help.
Primary goal was to create kinda camera gymbal stabilizer which can do simple tasks similar to robotic arm but not limited by single place. Basically same as perfect cameraman with stabilizer. And for two wheels self balancing can't work with open loop cause of cogging effect, so i have to do at least compensation of the cogging. Ignored incremental encoders, cause they increase length by 1.5 times and more difficult to install to such motor.

I detect a difference in the definition of “servo motor” between the professional robotics world, and the hobbyist world. In the latter, you’re usually talking about a gadget with a small dc motor, a gear train, and some feedback so that a 50Hz PWM signal can move a shaft to a particular angular position. Usually under $20 and under 100g total weight.

You seem to be talking about a precision multiphase motor that is considerably larger and more powerful. I’ve also seen them called servo motors as well, and always wondered how such different beasts ended up with similar names.

If the divisions in actone can be replaced with shifts, are you sure the compiler optimization isn’t already doing that?

Your summaries of the problem help explain why there are so many special purpose microcontrollers and peripherals aimed at “motor control.” You may need one of them, though.