Closed timkettering closed 10 years ago
zero() is the reset/calibration function; it turns the motor backwards enough steps to ensure the motor is against the lower stop. It makes no assumptions about starting position and has no way to know if the motor has hit the stop, so it just steps enough to hit the stop from any position. It's okay to step against the stop when you overshoot - it causes a bit of clicking but no damage.
If you are getting unpredictable results here are some potential causes: you could have a slipping needle, a needle that is too heavy (or more correctly requires too much torque to turn), insufficient coil voltage, or too little delay between steps (the default interval is pretty safe, so it should be okay). There are stop-less versions of the motor too, which will never hit a stop and will just spin a full 360 degrees. Those are pretty uncommon and need an external sensor to detect zero.
hi, thanks for the quick response. i've been playing around w/ the source since the original post. i have a x27 switec with a 3d printed plastic needle that is pretty firmly attached (and which hardly weighs anything), and using the code supplied in the library along with the example that is provided (switecx25example). i have not modified any defaults in the code other than adding a 1 second delay between zero() and the 1/2-way position in the example code, to better distinguish between the two phases.
what i do is upload this code to the arduino, then hit the "reset" button to run the program over and over. so the results should be repeatable w/ same results over and over.
usually it moves back, hits the stop and then moves 1/2 way around (as the example code should). but at a few occasions, it will just shake a bit in place and not go anywhere. at other times, it will move and seemingly bounce off the stop, coming to a stop at a different place, then that new place becomes the "zero" for all future resets until this occurs again.
i can't rule out that theres damage to the switec. i only have one unit with me right now, but i have six more coming in. i will try to rule out the damage, but it seems to work okay other than the odd behavior with zero().
just to ensure, the arduino 5V output should be adequate to drive the motor (just one motor, no other things are being operated). correct?
It sounds like some steps are being missed intermittently. In my experience this means either under-voltage or exceeding maximum step frequency. I would start by checking the voltage at the output of your IO lines with a multimeter, since it's simple. Even if you think it should be okay, it pays to check it. I've wasted a lot of time checking everything else because I was sure the voltage was okay when it wasn't. One possible cause is driving the Arduino with a 5V external supply instead of say 12V. The regulator knocks the voltage down enough to cause problems. Also check your connections to the 4 motor pins are nice and tight if you are using slip-on connectors.
The step period during the reset is defined by this constant.
Try cranking that way up; maybe double it and the motor should rotate half as fast during reset. See if that eliminates the intermittent failure. If it does it tells you something - but honestly that reset rate should be nowhere near the limits of the motor.
I'm always interested to see how these issues resolve so I can better understand the causes of failure, so please do keep me posted. This code is being used by lots of people so I'm pretty confident the issue is not the library.
thank you for your comments. i agree with you that odds are far more likely that its an issue w/ my motor or setup, but i wanted to make sure i understood the expected behavior of the library and the stepper motor itself before i went looking for an issue that may not be an issue.
i will verify this with another motor as soon as i get them - and we will know whether there is something worth pursuing or not.
thank you again!
its me again. i received six new X27 motors in the mail today. (just for reference, i am using them on the x25 breakout board that was devised by therengineer.com).
I reset all the x25 code back to the version found on this github repo and plugged in the arduino.
i tried your suggestion and increased the step period during the reset, from 800 to 2800 and ran the x25 example code, the needle moved much slower during the reset. (and it did not seem to go to the full left stop, but just to the full right stop before moving back to the center). but when entering needle positions in the serial monitor, it moved accurately to all the places. so it seems that zero() is functioning (if the lack of full left stop is indeed correct).
so it would seem there is a voltage issue, but what i find odd is that the needle moves much quicker during serial monitor inputs and has no trouble there hitting all the expected places. but during the zero(), it needs to move a lot slower??
hopefully you can give some insight.
Very interesting...
Before I launch into code stuff, one thing we haven't discussed I think is the needle position. The internal stops determine the range of motion of the motor, but don't put any conditions on the position of the actual needle. If you have a gauge that spans 315 degrees, it is up to you to get the needle oriented on the axle so that the needle lines up with the sweep of your gauge. It occurred to me that when you say the needle doesn't go to the full left stop, you may be making the assumption that the needle itself is already aligned in a meaningful way. When you call zero() the motor should run backwards until it hits its stop - the direction of the needle at that point is entirely dependent upon how you have placed the needle on the axle. To get the placement right, I zero the motor, then gently rotate the needle on the axle into the position it should be in at zero. That may be obvious, or not, but I want to cover all bases.
So moving on, assuming that there was no confusion about the needle orientation, it sounds like the zero function isn't working, but the setPosition/update code is. That is possible I guess, since they use quite different logic. The logic in the zero function is really dumb - it just steps backwards at a fixed time interval as many steps as you have specified for the motor - usually 945 steps. Conversely, setPosition/update use an acceleration table to shift from slow steps to faster steps once the needle is moving. It starts out at 3000mS and moves up to 600mS per step pretty quickly.
Since setPosition/update seems to work, I think you could try using the following code to improvise a replacement for the zero() function:
motor1.currentStep = motor1.steps-1; // tell the motor that it is at
full-scale deflection motor1.setPosition(0); // tell the motor to return to the zero position while (motor1.currentStep>0) motor1.update(); // call update until it returns to zero
That should force the motor against the lower stop, and reset the currentStep to 0 which is what zero does, except this will walk the motor up to speed more slowly, maybe useful if you have voltage issues. So just replace the call to motor1.zero() with the 3 lines above. If it works, we have a really good indication of what is happening.
To be clear, here's what the expected behaviour is, assuming you are running the sample code from https://github.com/clearwater/SwitecX25/blob/master/examples/X25SerialControl/X25SerialControl.ino
Hope that moves things forward.
Cheers, Guy
On Tue, Dec 31, 2013 at 12:46 PM, Tim Kettering notifications@github.comwrote:
its me again. i received six new X27 motors in the mail today. (just for reference, i am using them on the x25 breakout board that was devised by therengineer.com).
I reset all the x25 code back to the version found on this github repo and plugged in the arduino.
i tried your suggestion and increased the step period during the reset, from 800 to 2800 and ran the x25 example code, the needle moved much slower during the reset. (and it did not seem to go to the full left stop, but just to the full right stop before moving back to the center). but when entering needle positions in the serial monitor, it moved accurately to all the places. so it seems that zero() is functioning (if the lack of full left stop is indeed correct).
so it would seem there is a voltage issue, but what i find odd is that the needle moves much quicker during serial monitor inputs and has no trouble there hitting all the expected places. but during the zero(), it needs to move a lot slower??
hopefully you can give some insight.
— Reply to this email directly or view it on GitHubhttps://github.com/clearwater/SwitecX25/issues/4#issuecomment-31381397 .
Guy Carpenter Clearwater Software, Australia Tel: 0409 637 109
i am driving the motor off the Arduino Nano (and using the 5V output). it seems that a value less than 1500 for RESET_STEP_MICROSEC will lead to inconsistent zero results.
regarding setting the needle position. when i have the motor unpowered, the needle is free to move (since the motors are disengaged, or whatever it is they're doing inside the case). i can move the needle around and feel where it hits the stops.
i marked on paper just below the motor the low and high stops. so i can see where the needle should be stopping. i hope that answers your question above.
i also ran the code replacement you suggested, and it (visually) moved in the same manner as the zero() function, but a lot faster.
Just re-read this thread to try to get insight as I think I'm missing something. You wrote:
(and it did not seem to go to the full left stop, but just to the full right stop before moving back to the center). I think this is the key.
The reset code in the sample code here:
https://github.com/clearwater/SwitecX25/blob/master/examples/X25SerialControl/X25SerialControl.ino and also the code in the README here: https://github.com/clearwater/SwitecX25 do NOT run against the full right stop at all.
The fact that you are seeing it go to the full right stop then center suggests maybe you have the polarity reversed on your motor connections (which makes it run in reverse). Try swapping motor pins 1 and 4 which are the white and red wires in this picture: http://guy.carpenter.id.au/gaugette/resources/2012-04-04/imgp9232.jpg
On Tue, Dec 31, 2013 at 2:09 PM, Tim Kettering notifications@github.comwrote:
regarding setting the needle position. when i have the motor unpowered, the needle is free to move (since the motors are disengaged, or whatever it is they're doing inside the case). i can move the needle around and feel where it hits the stops.
i marked on paper just below the motor the low and high stops. so i can see where the needle should be stopping. i hope that answers your question above.
i also ran the code replacement you suggested, and it (visually) moved in the same manner as the zero() function, but a lot faster.
— Reply to this email directly or view it on GitHubhttps://github.com/clearwater/SwitecX25/issues/4#issuecomment-31383181 .
Guy Carpenter Clearwater Software, Australia Tel: 0409 637 109
hey! yeah that was correct. the wires were swapped and now the motor runs against the left stop. i also reverted back to using the motor.zero() code and the value back to 800.. and it seems to work fine now... i will test this out further and hopefully that will be the end of the issue here.
thanks so much for your help! i am working on developing a digital conversion for an analog tachometer i have on my 1971 Honda motorcycle. And this is a pretty critical part, haha!
:)
Very awesome project! Is it a CB? I gather have become quite the venerable (and valuable) classics.
On Tue, Dec 31, 2013 at 3:41 PM, Tim Kettering notifications@github.comwrote:
hey! yeah that was correct. the wires were swapped and now the motor runs against the left stop. i also reverted back to using the motor.zero() code and the value back to 800.. and it seems to work fine now... i will test this out further and hopefully that will be the end of the issue here.
thanks so much for your help! i am working on developing a digital conversion for an analog tachometer i have on my 1971 Honda motorcycle. And this is a pretty critical part, haha!
:)
— Reply to this email directly or view it on GitHubhttps://github.com/clearwater/SwitecX25/issues/4#issuecomment-31384790 .
Guy Carpenter Clearwater Software, Australia Tel: 0409 637 109
yes, its a Honda 1971 Honda CB350. All of the CBs are classics, but some of the CBs, especially the larger 550 and 750s are very highly desirable and have premium prices... the CB350 was made in far larger numbers and are more readily accessible for a reasonable price. :)
Last night I got all the wiring in place and the code all sorted out, the new motor works perfectly and there are no issues w/ the code! I'll close this out as a "working as intended" :+1:
Hi! Its me again. I actually have something to add to this issue.
Given your useful feedback, and initial testing done right when I closed out this issue, it seemed resolved, but now that my prototype has moved into more exhaustive testing and refinement, I am again encountering issues with inconsistent zero-ing results.
I have been experimenting with calling zero() repeatedly and approximately 80% of the time when I call zero(), it will correctly position the needle at zero. But the remaining 20% of the time it leaves the needle in an unacceptable position and often will require resetting the device again until it correctly zeros again.
I went back and tried increasing the RESET_STEP_MICROSEC value to something greater and at a point above 1600, it will correctly zero() without any trouble.
But what's interesting is that going from 800 to a slightly higher value, like say, 1000, actually leads to even worse results. A value of 1000 pretty much means it never will zero correctly. it just sweeps back to zero stop, stops somewhere in the middle. So to me it seems to suggest that there is some other factor in play here and not just simply a matter of increasing the microsec value == increased reliablity of the zero()
Running off a 5V arduino (Nano) - the only way I can get consistent zero() results is to slow RESET_STEP_MICROSEC to a value of around 2000. I will just move ahead with this value in place for now.
Have you done any tests to see if the needle positioning is reliable? I would write some code to move forward and backwards between two points and make sure it continues to position accurately. The problems you are experiencing are unusual, so I'd be worried there is something fundamentally wrong. One possibility is that your needle requires high torque to turn which would be the case if it is either very long or heavy. You could test that by replacing the needle with a piece of tape which has virtually no torque and see if your results change. If your zeroing problems are due to high torque, my suggestion would be to use the acceleration code for zeroing. In fact that should probably be the default - I'll keep that in mind when I next update the library.
Hi - thanks for the input. I am using this in a project where I am converting an analog tachometer to a digital input.
I have tested on three different X27 motors (with similiar results). I have written a test library that simulates the tach input and you can see the video I made of it here (https://www.youtube.com/watch?v=DMgwbGH8ITU). I have left this test cycle running for over 8 hours and the needle position is accurate even after the extended test. The needle is a lightweight aluminum pointer.. It has virtually no weight (when I hold it).
Your comment regarding the acceleration code is also what I am starting to lean towards. The only issues I am encountering is when I use the zero() function. If the motor zero()s correctly, then the test cycle can run for hours and the needle positioning is accurate all through.
It is my suspicion that the immediate acceleration and deacceleration of the zero() routine that causes problems. By sloping up the acceleration and deacceleration, it may be less disruptive.
Hello! I am using your library SwitecX25 to control stepper motors from a car cluster. (Thank you very much for your work!).
The photos below are the motors that I use. Your library is great for controlling them (I slightly adjusted the acceleration table and everything worked perfectly), although they are internally different from the usual X25 (X27) motors.
I have read everything that is written in this thread. But I am sure that it is possible to somehow determine mechanical zero (without additional sensors) or at least determine whether the motor is rotating or has already reached the stop.
Please watch this videos: https://youtu.be/XX63uoILXRI and https://youtu.be/cht971-WvT8 on Youtube, where you can clearly see how the cluster processor controls the motors:
It is also worth mentioning that on the cluster PCB the motors are connected directly to the processor, there are no position sensors.
Please tell me what you think about this? How can this work? Thanks in advance!
Nice pics and video. I think there is a lot of room for improvement with the noise from this code; I wish I had an excuse to dedicate some time to experimentation.
The best advice I can offer on silent power-on resets is to study this document: https://guy.carpenter.id.au/gaugette/resources/vid/2009111395111_Acceleration_&_reset_calculation_example.pdf which gives advice on customsing the acceleration table for quiet resets. You could easily modify this code to use different acceleration tables for reset and normal operation.
I've never seen anyone trying to sense motor stop by e.g. measuring current flow through the drive pins, although I've read this is possible with DC motors. (e.g. https://forum.arduino.cc/t/easy-way-to-determine-if-a-motor-has-stopped/157502) It would be a very interesting experiment to try. My suspicion from observing auto and motorcycle instruments is that they do not do this; they just quietly push against the stop.
Thank you for your quick answer!
In the second video I stopped the needle by my finger and the motor stopped. At the same time the second one continued its movement until it reached a mechanical stop inside the motor.
I think that if the motor had been rotating counterclockwise for the full number of steps (even at a slow speed), it should have continued moving after I removed my finger. But I still assume that the car cluster processor somehow determined that there was an obstruction in the needle's path.
I bought a logic analyzer and want to learn more about the signals to the motor contact during "working" movement and movement during "zeroing". I assume that there should be some difference and maybe an answer.
When I learn the difference in control signals, I will write in this thread, maybe it will give some result.
Hello! I connected my new logic analyzer to the dashboard motor and made measurements in the return to zero mode, as well as in the operating mode, sending a speed signal of 200 km/h to the dashboard. In addition, I connected the logic analyzer directly to the motor controlled by the Arduino Nano using your library.
The results were predictable. In all three cases, the motor control signal was different. I suggest you look at the graphs. The resolution on all three graphics is the same 100 px = 2 ms.
It is obvious that the dashboard developers have provided a more complicated algorithm for controlling the stepper motors. That is why the arrow movement is so smooth, without jerks.
It seems to me that a PWM signal with a frequency of 15.6 kHz is used here, judging by the measurements. And the control sequence for the motor outputs is completely different.
Also, the graphs clearly show the moment when the needle rests against the mechanical stop, which means the theory that the microcontroller understands the moment of the physical stop of the arrow is correct.
The only thing left to do is to write a motor control library with the same operating principle! 😄 😄 😄 (But I have no ideas on how to do this yet.😥) Maybe you will have some thoughts on this matter?...
@SamFisher015 there is quite a bit to digest there. Thanks for including such nice data.
Regarding PWM, this library supports microstepping via PWM only if using a driver chip like the X12 quad driver. (https://guy.carpenter.id.au/gaugette/2017/04/29/switecx25-quad-driver-tests/) which gives much smoother motion.
One very obvious characteristic of the X25 step pattern is that contacts 2 and 3 are common. Even with microstepping I would expect that pattern to be visible, and it isn't for your motor. Do you have any reference documentation for your motor?
The zeroing behaviour is really interesting, I'm still puzzling over that pattern.
I've been contemplating using something like an RP2040 to do microstepping without a dedicated driver chip. I hadn't considered stop detection as a possibility before this thread, but now I'm really curious about the possibility.
Ive been experimenting with your library and a X27 motor. And it seems like the results of zero() are unpredictable. The motor can come to a "zero" at various places. I have looked at the code for zero() and it just seems to unwind all existing steps, but I dont see how it determines whether the motor has actually run into the mechanical stop.
I'm hoping you can give some clarification how this should work. Cheers!