luni64 / TeensyStep

Fast Stepper Motor Library for Teensy boards
https://luni64.github.io/TeensyStep/
MIT License
272 stars 56 forks source link

Wrong Positioning #70

Closed AlfaKeNTAvR closed 4 years ago

AlfaKeNTAvR commented 4 years ago

Hi Luni,

Here I am again with another problem. Actually, I think I've experienced similar problem when I was using AccelStepper and Arduino Mega. I've moved to Teensy 3.5 and TeensyStep, but I think I am experiencing it again.

The problem is the following: as an input I have an absolute angle position in degrees, after that it is converted to steps using degrees to steps ratio (360 degrees / 6400 steps per revolution). Since I am controlling a robotic arm with a laser pointer, I can see, that the actual position of the arm is wrong. I've double checked everything and have concluded, that the problem is in physical movement of the motors (the error is something like 1 or less degress). I've made a special testing stand with 14-bit absolute magnetic encoder. image

The output of the TeensyStep (getPosition()) is correct, however the angle from the absolute encoder deffers from it. The problem is that the error is not constant, it even changes the sign at a specific position and after that keep beeing +- stable. Here are my tests: Calculated - Input angle (desired); Encoder - Actual position from encoder; Steps - what was given as an input to setTargetAbs() function. image

I've already tried several stepper drivers and two motors, but the situation is pretty much the same. May that be a library problem? E.g. it shows up one thing, but actually loses some step signals while sending? Or maybe a sort of hardware problem?

If it might be helpful, here is my hardware: image

image

I think, if you were able to create such a great library, you may have experienced something similar to my problem. Thank you in advance!

Best regards, Nikita

luni64 commented 4 years ago

Hi Nikita, the internal step counter is incremented / decremented with each step. So, the number of STP pulses to your driver is exactly reflected by getPosition.

Of course your stepper / driver combination could loose steps, but despite a lot of urban legends this is very seldom the case. If you pulse too fast the motor usually gets completely stuck and you will hear a whining noise. However, you can easily check that. Move the motor to some position and mark the position of the laser pointer. Drive to some random positions and then back to the original position. Make sure that you approach the original position in the same direction as you did at the beginning. If something looses steps the laser will end up at a different position. The deviation will grow if you do more movements.

In my experience the reason for such things is almost always some mechanical problem.

1) Make sure that the coupling to the motor axis is fixed. I had cases when I was absolutely sure that the coupling is perfect, nevertheless the axis slipped. A marker on the axis and the coupling helps to check for slippage.

2) The positioning accuracy of cheap motors is surprisingly bad. Reproducibility however is usually good.

3) The measurement accuracy of cheap encoders is at least as bad as the motor accuracy :-)

4) The accuracy of the whole system depends on the coupling of the motor and the encoder. If the axes are tilt or not coaxial you get a significant measurement error.

Issues 2-4 can be checked by measuring motor steps and encoder values for a couple of turns and plot motor steps vs encoder position. Best to subtract the theoretical encoder angle (i.e. motorposition /6800 * 360) from the measured encoder angle.

Motor positioning errors usually have a period of 4 full steps (128 micro steps at your resolution) Encoder errors can be rather random but tend to be 360° periodic and are usually repeatable. Misalignment errors are also periodic with 360°.

If your system actually looses steps you'd see jumps in the curve.

Hope that helps

AlfaKeNTAvR commented 4 years ago

Hi Luni, Thanks for fast reply! That's definitely not a mechanical problem, because I've tested the motor with encoder on its shaft. Encoder is not the cheapest one - AS5048 from AMS (about 10 USD), I will test another one, but I already had some other successful project with this one. Actually, there is no step loses, I suppose, because the motor returns to its 0 position! That is the strangest thing. It moves with defferent absolute positioning errors, but since it just increments position I thought that the problem might be in the library...

To sum up, that's definitely not a:

  1. Coupling or other mechanical problem;
  2. Error in different positions is different, but the motor returns to the starting point perfectly;
  3. Absolute encoder is very precise, however I will test another PCB;
  4. No step lose take place, in other way it won't return to staring point;
  5. Stepper motors are good as well, I have several CNC machines using motors from the same supplier.
  6. Not sure about the stepper drivers, but if the were defective the motor would not return to starting point as well, I suppose.

Well, I have installed TeensyStep as a standard package with TeensyDuino, maybe there was a defective version?

Best regards, Nikita

luni64 commented 4 years ago

My remarks: 2) => Coupling is OK, good 3) => Which type is it? Do you have a link to the datasheet? 4) => Correct 6) + 5) => If you send me an excel or csv with motor positions vs encoder values I can have a look at it. Ideally some 5000 data points per revolution. You can do a simple rotateAsync and read out and print the encoder and motor positions in loop() say every 10 ms.

Believe me, this has nothing to do with the library or teensyduino etc. You can attach an LA to the step pin and count the pulses if you think that there is a problem, but since this is the key feature of any stepper code you can be sure that if you request n pulses you get n pulses.

AlfaKeNTAvR commented 4 years ago

Here's a link to the datasheet. I have an SPI version. https://ams.com/documents/20143/36005/AS5048_DS000298_4-00.pdf/910aef1f-6cd3-cbda-9d09-41f152104832

Okay, I will try to make excel files right now.

luni64 commented 4 years ago

Thanks for the datasheet. Depending on the precision of the magnet placement they specify an angular accuracy of +/- 0.8° up to +/- 1.2°. Translated into motor steps this is some +/- 20 motor steps (@ 6800 microsteps / rev).

Looking forward to your data.

AlfaKeNTAvR commented 4 years ago

Well, actually that's not exactly like you say, I think. Since that's a 14-bit resolution magnetic encoder, its precision is much better, than you say...

image

I am using a big magnet, so there should not be precision loss due to magnet positioning. Anyway, I tried to put everything +- precisely.

To be honest I cut two bits, so its resolution is 12-bit, which is still very precise.

AlfaKeNTAvR commented 4 years ago

Will it be okay, if I will create a dataset of points in degrees? Or should it be steps? I can translate degrees from the encoder to steps.

luni64 commented 4 years ago

Will it be okay, if I will create a dataset of points in degrees?

Sure, translation is trival

Well, actually that's not exactly like you say, I think. Since that's a 14-bit resolution magnetic encoder, its precision is much better, than you say...

Not really, the precision/resolution of a sensor has not much to do with its accuracy. It just tells you that they have a 14bit AD converter (or something equivalent). The accuracy obviously depends on the homegenity oft the magnet and of course on its placement. Actually 1° is quite good for a hall sensor based encoder. E.g. imagine that you would completely missalign the magnet. The system would still have 14bit precision but obviously a much worse accuracy.-> different things.

Here the accuracy spec (INL) image

If you need accuracy you should always go for an optical encoder e.g. https://www.heidenhain.de/de_EN/products/rotary-encoders/

AlfaKeNTAvR commented 4 years ago

Wow, I was thinkong wrong for such a long period of time... If so, I guess all of my tests are incorrect... And that is why the error was kind of random. What a pity... I am having some problems with synchronization of data from encoder and getPosition(), because I am doing this things on different controllers, so I will do it tomorrow. Yes, that's strange, but right now I am not able to synchronize 5V SPI of encoder with 3.3V SPI of Teensy...

To sum up, maybe there no reason to compare data from internal counter with encoder, because error was less than 1 degree, so it might simply be an encoder error.. However, strange, that it was the same every time I moved stepper to the same position. What do you think?

AlfaKeNTAvR commented 4 years ago

Thank you very much for pointing out my misunderstanding! I've read an article about the differences between Accuracy, Precision and Resolution. That's kind a funny that 2 of them are translated into my native language as the same)) image

luni64 commented 4 years ago

However, strange, that it was the same every time I moved stepper to the same position. What do you think?

I would expect some systematic error on the motor/driver and the encoder. Usually those things are quite reproducible, (i.e. high precision). It is always a good idea to invest some time characterizing the system at work. I recommend to do this motorpos vs encoder experiment anyway. Looking at the periodicity will teach you a lot about the nature of the deviations. Instead of measuring on the fly you can as well do the following: 1) Move the motor at some random position within one revolution (0 <= p <=6800) 2) Wait some time until system oscillations stopped. 500ms should be fine but this obviously depends on your your mechanics. (You can check by reading out encoder values every say 1 ms after the motor stopped and determine when the readings get stable. If you plot this you will usually see some damped oscillation.) 3) Read out motor and encoder position and write them to Serial 4) Repeat for at least 5000 random positions

AlfaKeNTAvR commented 4 years ago

Hi Luni,

I was able to finish this terrible test, finally! I got this two microcontrollers send information more or less simultaniously with the help of a python serial sketch, which reads encoder data from Arduino Uno and stepper position from Teensy, but the period is not exacatly 10ms it is between 10 and 50ms, I think, but that's should not be a problem since we want to compare data in the same positions.

I've made a test on 500 random points. Was not able to do with 5000, it took something like an hour and than my computer just got reloaded... Anyway, during this test I've saved more than 20000 positions from encoder and getPosition(), guess that might be okay.

At the end, I've got a more than a 7 degrees error. The motor think it is at 0 position, however the encoder shows 7.25 degrees difference.

Here are the CSV files, I've opend them in Notepad++ and everything seems to be okay.

Data.zip

P.S. I don't know why, but you mentioned 6800 steps/rev, however I have 6400 (standart one on my driver)

UPD: Maybe the finial error was caused by to fast accelerations and velocity. Right now I am doing the same test but with lower acc and vel, like the ones I am using for my robot.

UPD2: During this test, sometimes I feel strange thing while holding the stepper. Feels, like it looses the step, however no load at all is connected to it, and nothing can cause this mechanically.

luni64 commented 4 years ago

I assumed the two data sets show encoder and stepper angles at the "same" (+/- 50 ms) time. So I can simply copy them one besides the other to compare?

I'm afraid the data does not make too much sense if you didn't collect them at the same time. Anyway, here some results. The following graph shows the error plotted against the stepper position. Data is clearly devided in two "blobs". If you look at the actual data you see that there is a jump in the Error at line 9616. The two blobs are devided by about 7.2°. I assume you had a step loss here. Step losses can only be multiples of 4 full steps which is 360° / 200 * 4 = 7.2° which explains this nicely

image

Just saw that you restarted the measurement. Please don't. It would be much better to do the procedure I described two posts above. I.e. move to a target, wait some time and read out both angles. This will eliminate the sync issues. If it takes too long better to reduce the investigated angle to say 10° and do as much points as possible.

AlfaKeNTAvR commented 4 years ago
  1. You've misunderstood me a bit, the data from the encoder and from the stepper is captured at the same time, however the period between two pairs of mesurements is not exactly 10 ms. So, yes, you can just compare two files, since they represent data at the same moments.

  2. Okay, I see the point. How could step loss happend if I have no load? The motor is not over heating (I held it in my hand during the test). Maybe I am sending new targets too fast? I experimented a bit with that, and found out that there should be a 10mcs delay after isRunning() function returns False before the new movement. Other way it will loss position somehow. I've put this delay in my function, so everything went okay. Maybe might another this kind of special thing?

UPD: Well, I think I might have found the problem of step loses. I had one driver signal cables disconnected and since I've connected GNDs from drivers in series and especially Enable cables are all connected to one pin of Teensy. One floating end of enable cable might be working as antenna, causing the stepper to turn on and off accidentally. Does it make sence?

  1. To sum up, I need to plot positions from stepper and encoder during a wait period between movements? And no "middle" mesurements while moving are needed?
luni64 commented 4 years ago

1) Good 2) You always have load if you accelerate a motor. In fact in cnc machines the moment of inertia of the rotating parts of the motor often generates a higher load then the rather slow movement of the driven slides. I don't know your mathematics/physics background, but I did some calculations a couple of years ago which demonstrate this. Let me know if you are interested.

3) Yes. It is absolutely necessary to eliminate any asyncronicity if you want to analyze that stuff.

Just saw your update (please don't, I dont get notifications if you change something, better to add a new comment) That of course might also be reason for the step loss

luni64 commented 4 years ago

Again 3) Just move to the target, wait 500ms and read out the values. Then move to the next target. Limit to 10° first to see if the data make sense. Would be good to end up with a measurement point every 0.1° or so.

luni64 commented 4 years ago

Again 2) You observed that you need to wait 10ms until you set the new target. That makes sense. IsRunning returns false directly after the last step. If you immediately start the motor after that, the time between the last step of the first movement and the first step of the second movement will be very short. This corresponds to a huge acceleration which the motor can't follow and looses this step (7.2°).

AlfaKeNTAvR commented 4 years ago
  1. Well, I have a bachelor degree in Mechatronics and Robotics and right now I am a first year student of a master degree, however there was not much practical experience except for my own projects like cnc machines, 3d-printer and the current industrial robot. My main specialisation is Intellectual Systems and Control systems, but I would definately like to discover your calculations after reaching some approaching deadlines) My e-mail is: bognik3@gmail.com

  2. Okay, now I see the task clearly, sorry for my misunderstanding. Will do this as soon as possible.

Yes, sure, writing to you is my first experience on github, I will create new comments if I want something to add.

Firstly, I tried 10 milliseconds delay, but after some testing, I changed it to 10 microseconds and it seemed to be working, maybe I should try to return 10 milliseconds for this tests.

luni64 commented 4 years ago

If you follow what I suggested above you will wait 500ms before you measure and restart the motor so this should be no problem :-)

Well, I have a bachelor degree in Mechatronics and Robotics and right now I am a first year student of a master degree,

That should be more than enough to understand my simple calculations :-). Here the file (it is in German but translation should be straight forward given the formulas) drehmomente gewindetrieb.xlsx

AlfaKeNTAvR commented 4 years ago

Okay, I will do so!

Used to study German at school, maybe will have some practice in mechanical terminology, ha-ha))

AlfaKeNTAvR commented 4 years ago

Tonight I left the stepper for 5000 points, however it did just 3715, because of an algorithm: I write to file only if I've recieved data from both controllers at the same moment, if any data is missing I just skip current point even though I have data from stepper. This is made to eliminate sync problems.

This time I've moved stepper to a random point, wait 100 milliseconds, read data from stepper and encoder, save it if I've recieved both data.

Data_3715.zip

I've still experienced small hits while holding the motor, not in an end or begining of the motion, but at some random position. It was like: acceleration, hit, movement, decceleration. These hits does not lead to step loss as you from the data. However, there plenty of them during the test. Why may this happen? I've tried another driver, actually from the same supplier, but it did not help. I've read about a resonance effect in stepper motors, but do not know if this is the case.

I will call the motor supplier today for any possible explanation.

luni64 commented 4 years ago

I had a quick look at your data. I usually look for periodic errors with 180° or 360° periodicity. Those errors are most probably due to encoder inaccuracy or not perfectly aligned mechanics. You can easily calculate that you get a 360° periodic error if the motor and encoder axis not perfectly aligned. Here a hand fitted superposition of 180° and 360° periodic errors with amplitudes of 0.5° and -0.25° respectively (red line) over the error (encoder - stepper angles).

image

The calculated curve fits nicely to the observation. So I conclude that the encoder and alignment errors contribute some 0.75° error in total.

The other typical error in such setups is generated by a micro-stepping inaccuracy. Especially cheap stepper drivers and cheap motors are not very good at this. Those errors usually show a periodicity of a full step angle, i.e. 1.8°. Unfortunately you have not enough data to clearly show the effect. If you are interested, you could redo the measurement by only moving to values from 0 - 10° to get more points in the interesting interval. Here the result with the available data.

image

The periodicy is not clearly shown, but I'm quite sure that you'd see it with more points.

-> Contribution from the Motor/Stepper is about +/- 0.15°.

Regarding your "hits": Difficult to say. Might be a defect in the motor bearing? Do you feel something strange if you rotate the motor by hand? They clearly show in the measurement so seem to be some real effect...

Here the Excel with the analysis test.xlsx

Hope that helps

AlfaKeNTAvR commented 4 years ago

Hello, Luni,

Thank you very much for such a detailed response to my problem! You've done a great job and I really appreciate this. I clearly see you point now and I have recieved so much new interesting information about "stepper debugging", fantastic! From all the information and tests above, we can conclude that there is no serious position error for this stepper motor. As I assumed there have to be an error not less than a 2 degrees in total for 5 mm error in robots position, but in some positions I had more than 15 mm! I should definately do the same tests with the second stepper motor.

I've already contacted my stepper motor suppliers service center and now we are trying to find out where the problem is. It is definately not the bearing: when turned-off the motors shaft rorates smoothly.

When something new will become clear I can write back to you here, if you're interested.

Best regards, Nikita

luni64 commented 4 years ago

Great, looking forward to your results

AlfaKeNTAvR commented 4 years ago

Hey, Luni,

I've made a sort of a testing sequence for stepper motor hit problem. And what I found is something weird. Maybe you will have a clue? The motor does hits not in specific position, but during specific travel distances. Hits appear while moving to 227, 347, 1243, 2497, 4521 distances (current position - target position). This distances I found while testing motor movement with random positions. I also tried to find some sort of delta = 347 - 227 = 120. And during an interval of 347 + 120 = 457 the motor does several hits. But this delta does not seem to work any further.

Any ideas? I think the problem is somewhere in the software, howeverm I've simplified testing sketch to a very minimum.

#include "TeensyStep.h"

int enable_pin_4 = 8;

Stepper stepper_motor(31, 30);       // STEP pin: 2, DIR pin: 3
StepControl controller;    // Use default settings 

void setup()
{
  pinMode(31, OUTPUT);
  pinMode(30, OUTPUT);
  pinMode(29, OUTPUT);
  pinMode(28, OUTPUT);
  pinMode(27, OUTPUT);
  pinMode(26, OUTPUT);
  pinMode(25, OUTPUT);
  pinMode(24, OUTPUT);

  pinMode(enable_pin_4, OUTPUT);
  digitalWrite(enable_pin_4, HIGH);

  stepper_motor
            .setMaxSpeed(20800)
            .setAcceleration(10400)
            .setInverseRotation(true)
            .setStepPinPolarity(LOW);

  randomSeed(125);
}

volatile int cnt = 1;
volatile int pos = 0;

void loop()
{
  String mode = Serial.readStringUntil('_'); 

  if(mode == "1")
  {
    while (cnt <= 100) 
    {
      if(!controller.isRunning())
      {
        int new_pos = random(0, 6350);
        while(abs(new_pos - pos) < 5)
        {
          new_pos = random(0, 6350);
        }

        Serial.println(new_pos);
        delay(500);
        pos = new_pos; 

        stepper_motor.setTargetAbs(pos);  
        controller.move(stepper_motor);    // Do the move
        cnt ++;
      }      
    }
   cnt = 1; 
  }
  else if(mode == "2")
  {
    String position = Serial.readStringUntil('_'); 
    stepper_motor.setTargetAbs(position.toInt());  
    controller.move(stepper_motor);    // Do the move

  }
   else if(mode == "3")
  {
    String position = Serial.readStringUntil('_'); 
    stepper_motor.setTargetRel(position.toInt());  
    controller.move(stepper_motor);    // Do the move

  }
}

Thanks in advance, Nikita

AlfaKeNTAvR commented 4 years ago

UPD1: intervals remain the same even if I change a number of steps on my driver.

AlfaKeNTAvR commented 4 years ago

UPD2: Previous tests were made at speed 20800, acceleration 10400. I've changed speed to 800 and acceleration to 400 and there were no hits during the disntaces I've mentioned above. Now the intervals are the following: 83, 389, 415, 613... These intervals also produce no hits with speed 20800, acceleration 10400.

All in all, these distances are different and depend on the speed and acceleration.

luni64 commented 4 years ago

I was able to reproduce your issue. Since the current development branch does not show the problem I finally merged it into master. -> Can you please give V2.1 a try.

urbhar580 commented 4 years ago

Hi there, This is not a contribution to a solution, but only some information.

I haven't read this thread in great detail but thought that this error investigation of a stepper would be of interest, the error looks as yours on the graph "motor/driver Influence":

Twitter link

Here is a video explaining why you get a periodic error of 50 on a 200 step motor:

Youtube Link

I am also noting that you use a 3.3V signal to a driver that might want a differential 5V signal? In that case this Quadruple Differential Line Driver might be of interest. It will take a 3.3V signal and turn it in to a differential signal that is less sensitive to noice.

Octopart Link

AlfaKeNTAvR commented 4 years ago

I was able to reproduce your issue. Since the current development branch does not show the problem I finally merged it into master. -> Can you please give V2.1 a try.

Hi Luni,

Yeah, at a first glance it seems to be working! I will make a couple of other tests and tell you for sure. What was the problem? Now, I am curious about it, because I've spent quite some time debagging it and reassembling the whole electrimechanical system for many-many times, ha-ha))

Best regards, Nikita

AlfaKeNTAvR commented 4 years ago

Hi there, This is not a contribution to a solution, but only some information.

I haven't read this thread in great detail but thought that this error investigation of a stepper would be of interest, the error looks as yours on the graph "motor/driver Influence":

Twitter link

Here is a video explaining why you get a periodic error of 50 on a 200 step motor:

Youtube Link

I am also noting that you use a 3.3V signal to a driver that might want a differential 5V signal? In that case this Quadruple Differential Line Driver might be of interest. It will take a 3.3V signal and turn it in to a differential signal that is less sensitive to noice.

Octopart Link

Hello,

Thank you for your reply, I will take a look! As for the 3.3V, I already use SN74HCT245N for fast 3.3V to 5V convertion as Luni suggested.

Best regards, Nikita

luni64 commented 4 years ago

Yeah, at a first glance it seems to be working! I will make a couple of other tests and tell you for sure. What was the problem?

I had a look at the generated pulses and found that in those "hit" cases you get the following issue:

image

Zoomed further in: image

You see that in those cases during deceleration the step frequency suddenly increases which generates your "hits".

Since I fixed a couple of bugs in the development branch during the last year I gave it a try. Probably fixed your bug unintentionally.... If you are interested in details I recommend to go through the commits of the last year but honestly, I currently don't have the time for it.

Let me know if it works stably now.

AlfaKeNTAvR commented 4 years ago

Yeah, at a first glance it seems to be working! I will make a couple of other tests and tell you for sure. What was the problem?

I had a look at the generated pulses and found that in those "hit" cases you get the following issue:

image

Zoomed further in: image

You see that in those cases during deceleration the step frequency suddenly increases which generates your "hits".

Since I fixed a couple of bugs in the development branch during the last year I gave it a try. Probably fixed your bug unintentionally.... If you are interested in details I recommend to go through the commits of the last year but honestly, I currently don't have the time for it.

Let me know if it works stably now.

Thanks for the reply! Yeah, I see now, I think that's enough for me) Will write back after some testing!

AlfaKeNTAvR commented 4 years ago

Hey Luni,

I've spent some hours testing and everything is okay with a movement, no hits, thank you very much!

However, right now I'm experiencing strange problem while executing homing functions, which use RotateController. It seems like something at the end is blocking. After finishing homing, I am no longer able to send commands using Serial port. Before 2.1 version everything was working correctly. I will make more tests to find the exact peice of code, where the problem occurs.

Best regards, Nikita

AlfaKeNTAvR commented 4 years ago

UPD1: Everything's okay again. Just commented some essential code by myself while testing those hits.

luni64 commented 4 years ago

Perfect! Let me know if you find something not working or behaving strange. V2.1 is not as much tested as the older versions are...

AlfaKeNTAvR commented 4 years ago

Sure! Will not close the issue, still testing my robots' movement and it is still not operating correctly... 75% that it's not caused by the libarary, but it will be easier to ask something new in this thread again)

AlfaKeNTAvR commented 4 years ago

Considering positioning of the robot, now everything is tested and works fine! It took too long to find the issue and it was not about the stepper positioning)) Thanks again, closing the issue.

AlfaKeNTAvR commented 3 years ago

Hey, Luni! I've finally made a good video of my project based on your library! Hope, you will be interested! Contact me via email bognik3@gmail.com, so I can send you the video file if needed.