Writing a driver for two steppers is harder than I thought!
lardom
Posts: 1,659
I'm trying to write a stepper driver for differential steering and I'm getting chatter when I try to get them to run together. I used a stack of 60 longs and I only got them to run together smoothly after I put motor (1) @stack[5]. It chattered @stack[0]. The step pattern is in the DAT block which works fine for a single stepper. I think I should rewrite the driver so that both motors use a single 8-bit step pattern. I have to use 2pi to calculate the rate of turn and calling two methods in the same object with cognew/coginit does not appear to work.
I know someone has been down this road. I'm hoping that a single 8-bit variable is the way to approach this.
I know someone has been down this road. I'm hoping that a single 8-bit variable is the way to approach this.
Comments
I used a rotating 32 bit pattern.
Edit: The forum eats my "%" in front of the binary _InitialPattern value.
2nd Edit: Now it will let me add a percent sign. Strange.
I used 32 bits instead of just 8 so I could use the bit rotation opperator.
I personally thought it was pretty cool to use the rotating bits to drive the motor.
You could have two different stepPattern variables so you could rotate them independently from each other.
Just a thought. I know there are lots of other stepper motor objects out there that are a lot better than mine.
How do you enter code blocks? I don't have issues with the "%" getting eaten:
-Phil
I usually don't have a problem with it.
Edit: My latest attempt to edit the earlier post worked. I was (finally) able to add the "%" to my original post. It was strange that I couldn't before.
I deleted some other tests, to see if the percent sign would show up, I had made in this post.
My original post was missing four bits from the inital pattern. I've edited it.
@Larry, Sorry about the distraction from stepper motors.
I am surprised that Duane nor Phil mentioned it, but if you are seeking help, then you should post your source code so that others may try to find the source of your problem.
Bruce
Perhaps you may find something useful in the code below.
Bruce
EDIT: This is a combination of someoneelses code and mine, I forget the original author, this was just some test software for me using the HC595. I am sure you can find the original code in the OBEX. I am not trying to take credit for someoneelses work
@idbruce, I've uploaded the file and tried to comment it so someone else could understand what I was after. I'll study your file. Thanks
I don't understand.... You say that you are trying to control two steppers, but in your function calls, I only see pins 8-11 being used. Are you trying to control both steppers from the same four pins?
Bruce
idbruce, My naming conventions may be a bit quirky; motor #1 uses [11..8]. Motor #2 uses [15..12].
Irregardless of the last question and answer, from what I have read about differential steering, you want two independentantly operating motors.
If I was to attempt such a thing as differential steering (according to what I have read), this is what I would try.
- Acquire the system count value and add a future time.
- Create two instances of the same object and pass each instance the future time for execution and the pins being used.
BruceMixing cognew and coginit is a really bad idea. You should always use cognew to start new cogs.
There is only a handful cases where using coginit is an advantage. Most of the time you receive the disadvantage
that you the user is responsible for starting and stopping the right cogs.
If you do a cognew this cognew might just se cog no 2. and later on you do a coginit cog no 2 which will stop cog 2 from what is doing right now and start again with coginit cog no 2
a stack of 4 longs is way too small.
the real minimum is 9 longs.
you do
success:= cog := cognew(Full(distance,speed), @stack)
and later on
coginit(1, Full_Bk(R, speed), @stack[5])
coginit (2, Full_BkL(L, speed), @stack[30])
which means the coginit Full_Bk @stack[5] starts right in the middle of the stack of
cognew Full @stack
use a separate stackvariable for each cog with a size of minimum 20 longs just to assure that the stacks are big enough.
For further analysing what is happening I would add low-current LEDs to the outputs and would run the code through
in some kind of single-step-mode to see how the outputs are switched on off. Or as a software-replacement of the LEDs
to send the actual bitpattern to te serial terminal.
keep the questions coming
best regards
Stefan
Something along the lines of the altered file.
Bruce
By creating two instances of the same object, and controlling each motor seperately, you should be able to achieve a wider range of control, such as different speeds for each motor, as well as different directions.
Bruce
(Using 32-bit variables at the very least would eliminate the need to write a separate method for each wheel since I would only have to shift bits.)
Here is an example:
Here is an afterthought. Once again, if I was to attempt something like differential steering, I would use two objects, a math object to determine the movement required and a stepper object to make the movement happen.
I would first determine the movement required, and then I would send the required movements to the stepper object to make the required movements simultaneously with both wheels as previously suggested. That way the rotation of the individual tires are not bogged down by the necessary computations.
Bruce
I apologize for all the input, but this subject has caught my interest.
As I mentioned in the last post, I would attempt to keep as many computations out of the stepper driver as possible. With this in mind, and keeping in mind that I would have two instances for a single object, one for each wheel, I would also design the object so that I could call the individual types of movements to start a new cog. The following code should give you a brief idea of what I would do.
Bruce
I wanted to eliminate the DAT block as a possible cause.
In the code example that you provided, these cogs (wheels) will start three seconds apart.
What you really want is for both cogs to start on the same clock cycle. That is the reason behind the FutureTime variable that I offered as a solution.
Bruce
Try this instead:
For some reason, I cannot edit posts that contain "CODE" blocks. The previous example was missing something. Try this:
I just quickly reviewed your code and added to it. I must say that after closer examination, I don't like the way it looks. I will rewrite it and have a new piece of test code for you in a few minutes.
Bruce
Bruce
Did you try the last code I posted?
Bruce
When you use COGNEW on an object, the compiler actually calls the function first, waits for it to return, then launches the cog with that function.
When you call a local function in the SPIN program, it simply launches the COG with COGINIT.
The problem is that the COGNEW is actually executing the Start methods in serial.
The solution is to create 2 local subs that you call with COGNEW and those subs call the startup methods in the OBJ. This is a really esoteric bug and doesn't show up most times because most Start methods of OBJects return shortly after doing some setup of the COG.
This DOES work:
This ALSO works:
The question is, is this OFFICIALLY a SPIN compiler BUG?
Perhaps this "reboot" will get you back on track -- or at least get you unstuck.
No -- you're doing something wrong. The problem is we don't have the source for the objects refernced in the segment that you say is not working. Now... if you're thinking that you can declare methods as objects as your listing suggests you're trying, this doesn't work.
As as been pointed out, coginit is dangerous because it will overwrite anything in the target cog -- and that cog may be doing something you need. Use cognew instead, as I demonstrate in the working code attached above.