could somebody help me find a bug in my method?
kutalinelucas
Posts: 80
I was wondering if somebody could help me spot the bug in my system!
When a certain value is passed to the object below, the "Quadrature Encoder" obex is started in a new cog, and another new cog is started to turn a DC motor until the Pos[0] variable (which stores the encoder value from 'Quadrature Encoder') reaches a given value...
But I'm having some unexpected results...
Firstly the motor will turn a random amount of revolutions, about 50% of the time it revolves three times when I tell the PWM loop to exit after Pos[0] >50, which would normally make sense as my encoder has 18 pulses/rev, but I think the OBEX is set-up as an absolute encoder, so i'm not sure if the counter is re-set at the end of each revolution. The rest of the time it will spin freely or stop after any given amount of revolutions.
The other issue I have is that sometimes I can send the instruction to the motor and the cog shuts down and the program returns to the bottom of the stack as expected...more often that not it does not, I'm guessing all the other objects above the one above are OK, because if the value passed is above #30, the LED toggles and waits for the next instruction.
I'm guessing the prop stack is pretty large right? just because I think the motor turning is 4 objects deep and maybe 7 stacks high...I can post the code if it'll help. Thanks loads
Martyn.
When a certain value is passed to the object below, the "Quadrature Encoder" obex is started in a new cog, and another new cog is started to turn a DC motor until the Pos[0] variable (which stores the encoder value from 'Quadrature Encoder') reaches a given value...
CON delay = 3_000_000 VAR long rotation long motmov Long fwdstack[30] Long motstack2[12] Long Pos[2] Byte fwdCogId OBJ Encoder : "Quadrature Encoder" PUB start(reconstructed_data, Motor_ident) : Pass DIRA[8]~~ motmov := reconstructed_data if motmov < 30 Encoder.Start(12, 1, 0, @Pos) Pass := (fwdCogId := cognew(turn_motorfwd,@fwdstack) + 1) > 0 RETURN if motmov > 30 !OUTA[8] RETURN PUB turn_motorfwd | Time , Ratio DIRA[10]~~ 'PWM to H-bridge DIRA[12]~~ 'motor enable DIRA[9]~~ 'LED2 DIRA[12..13]~ 'ENCODER... '!OUTA[9] Ratio := 15_000 time := cnt OUTA[12]~~ REPEAT waitcnt(Time += 20_000 - Ratio) 'start pwm OUTA[10]~~ waitcnt(Time += Ratio) OUTA[10]~ IF Pos[0] >= 100 'IF encoder ticks > 50 (12/rev)... OUTA[10..12]~ 'pull motor outptut and PWM low QUIT fwdCogStop PUB fwdCogStop 'exit and stop cog if fwdCogId cogstop(fwdCogId~ -1) RETURN
But I'm having some unexpected results...
Firstly the motor will turn a random amount of revolutions, about 50% of the time it revolves three times when I tell the PWM loop to exit after Pos[0] >50, which would normally make sense as my encoder has 18 pulses/rev, but I think the OBEX is set-up as an absolute encoder, so i'm not sure if the counter is re-set at the end of each revolution. The rest of the time it will spin freely or stop after any given amount of revolutions.
The other issue I have is that sometimes I can send the instruction to the motor and the cog shuts down and the program returns to the bottom of the stack as expected...more often that not it does not, I'm guessing all the other objects above the one above are OK, because if the value passed is above #30, the LED toggles and waits for the next instruction.
I'm guessing the prop stack is pretty large right? just because I think the motor turning is 4 objects deep and maybe 7 stacks high...I can post the code if it'll help. Thanks loads
Martyn.
Comments
I've done a few motor control projects using the object that's attached. It lets you control one or two motors with speeds from -100 (full reverse) to 100 (full forward; 0, of course, is stop. You need two pins per motor; one for PWM the other for direction control. The counters are used to create the PWM output so it is very precise, though we are limited to two motors when using this strategy.
If you are compelled to stop the PWM output and disconnect it (programmatically) from the motors you can still do that with this object using the .stop() method.
I need to control 4 motors in both directions (Aggghhh). Initially I have two cogs monitoring Enable and data signals, where a motor identification and required rotation (recieved from a PIC18F) is passed to another method. Within this second method is a switch statement, which will call one of four 'move-motor' objects. Then I'm just looking to start a cog to send a PWM to a L293d driver until a variable acumulated from the Pos[0] variable reaches the value of the recieved data.
As the motor needs to be operated in both directions, the movement data recieved from the pic has the same rotation value, but #30 is added to illustrate that the motor should be turned counter-clockwise, but this will just be subtracted off the rotation data.
So...in the object above, if the recieved_data was above 30 (ccw), I would like to...
1. Check if a cog as been started to run the motor cw, if so, stop it
2. Send PWM pulse until Pos[0] > recieved_data, using a dedicated output for the directional input of the H-bridge
3. Stop cog and return to top object
To be honest this method just seemed intuitive, coming from a high-level-language background, and I currently don't have the time to investigate all the powers of the prop...but I will.
The motor doesn't have to be so precise...give or take 1/2 rad would be acceptable. I can post all of my code or send you a link to a page on this forum if you are intreted in what I'm trying to do...
As I said i'm SURE it won't be the most optimised method for doing this...but do you think it could work?
...oh yeah, I can't use the prop counters because I'm looking to get up to four motors running independantly and simultainiously, and I believe theres only 2 dedicated on the prop? And variable speed isn't too much of an issue either
As I pointed out, the object allows you to control speed and direction. I have used this code in a professional product; it works quite well and I think with looming deadlines this will be easier to implement than what you're working through now.
Humans are interesting... what you find intuitive I find very confusing. I treat motor control like a car: the engine is running and I can be in forward, neutral, or reverse as required, and set the speed with the accelerator pedal. It seems to me that your main cog can monitor the enables, a serial cog could take care of that, and two motor driver cogs would handle your motors -- four cogs total.
To be candid, I don't -- but I can't see the whole thing (circuit and code would be required for that). You seem to be wanting to use cogs where it is not necessary, and that just complicates things.
I must be calleing the method incorrectly, because the prop freezes until the Drive_motor.Stop method is called, and the motor does not turn but this is what I'm trying to do...
Sorry for being a pain
You're going to use two pins from the L293 for each motor; one will be the PWM pin, the other will be the direction pin. For example if you were using OUT1 and OUT2 (L293D.3 and L293D.6) for the motor, you could use IN1 (L293D.2) for PWM, and IN2 (L293D.7) for direction. When the direction pin is low the motor should go forward; when high it should go in reverse -- this is how the code is structured.
If you can find a copy of the July 2011 issue of Nuts & Volts all of this is covered in my column. I've attached my L293 schematic from that column.
The circuit and all peripheral code aside, the program freezes (or gets stuck in a loop) where ever I call 'drive_motor.Start(12, 10, 0, 0, 15_000)', unless it is shortly followed by 'drive_motor.Stop' directly after...thats why I thought there was a problem in the way I am calling the method...
The set_speed and stop don't seem to cause any problems tho...
This is killing me! but its my problem so thanks for all the help, and the code
Martyn
I'd just like to add a request that you keep your questions (about this problem) in this thread.
You're "SOS thread" comment gave me the impression you will start a new thread if you're still having trouble. Please keep using this thread.
Restating the same problem in a different thread causes questions to be asked that may already have been answered.
I've learned a lot by reading this thread. (I often learn a lot from JonnyMac's posts.)
I have a project with four motors and four encoders. This has been interesting to me.
Duane
But I do still have the generic problem of not being able to return to the parent object after calling jon's motor object...
I've attached the three files I'm currently working on...'MUL_COG' waits for the enable; 'get_data' reads in the recieved byte, and 'move_motor' should turn the motor and is the one I'm having major problems with, and of course jm_dual_motor_ez. I'm assuming once jon's object is called a new cog is started the run the motor so the drive_motor.Start should return from where it has been called, but I'm deffinatly going wrong somewhere
All I want to crack is how to change the direction of the motors depending on a certain (even hard coded) condition, like
Sorry for being a pain in the ***...but I can't see the wood for the trees...i'm sure it'll be plain sailing once I can turn one motor proportional to an input variable, but i've just been stuck on this for too ling and could really do with the help
The code starts executing the method init
which calls encoder.start and drive_motor.start
then method main is called
the commands inside main are executed ONE time and as there is no repeat-loop to keep the cog alive. The code-execution ends after
Drive_motor.Set_Speed(0, -100)
RETURN
As indention is critical the if-conditions have no effect.
I guess what you wanted to code is something like
Anyway the code example above does not allow to test changing the motordirection while the code is running
You have to change the value of variable "move" by hand recompile the code and run the code again.
keep the questions coming
best regards
Stefan
Here's a bit of code that shows you how you might control four motors with two of the objects.
Edit: Listing corrected 20 AUG 2011
Note: Listing is partial; for example only (see below for complete code)
Stefan, I realise the program I posted had no dynamic variables, but I was just trying to get some kind of motor direction from a hard-coded variable, believe me I have spent 2 DAYS trying to call this method so i've been throwing in any approach I can conjour to little avail
Jon, I can't get the above code to run. The motor energises but does not rotate, and I believe the motor_speed of motor one is set at 1, as it should but then the program does not progress past the first methdo call, just as I have found no matter how I approach the problem
It should be soo simple but it's quickly turning into the biggest head-ache i've had all year!
The only observation I have made is that only the instruction proceeding a Set_speed method call will execute. So something as simple as...
Will never proceed past the OUTA[8]~~ instruction (which is an LED, the second LED will never turn on). This is why I'm starting to think there may be something going on with the object...i've tried to go through it but I only seem to make matters worse
to narrow down the problem we have to reduce the possible sources of bugs down to one.
Your code seems to have only a few lines but is already complex in that way that there are minimum of ten different possabilities where the bug comes from.
Guessing around in this situation when having almost no experience is slowing things down.
So to reduce possible bugsources down to one we have to divide the project in little pieces.
If you want to proceed faster than this you have to provide your full code attached to a posting and a schematic of how all the things are wired together.
In the propelertool there is an archive-project funtion.
You will find it in the main-menu under file - archive -project...
This will create a zip-file that contains all files nescessary to compile your code.
Please attach a schematic of how the things are wired together.
Now dividing into small pieces mean:
Your DC-motor is connected to a H-Brdge - right?
Can you switch on the motor at all?
If no
The H-Bridge has inputs for turning the motor left or right.
Depending on your H-Bridge circuit you have to take care which transistors to turn on at the same time and which not. If you do it wrong the transistor might get shortcutted.
Disconnect the motor
If you connect +3.3V from the propeller-board directly to the H-Bridge and then measure the voltage on the outputs that were going to the motor. What voltages do you measure?
If Yes always only add one line of code to a working example and test again if it still works.
Add serial debug-output to watch the program-flow of your code.
In your code above the codeline "Drive_motor12.Set_Speed(0, 100)" inside of the method pause is really bad coding-style never do this again.
pause makes a pause of 500 milliseconds = half a second that is pretty short
After executing the last pause(500) command the code stays inside the infinite (and empty) repeat-loop
I don't know if the motor keeps running in this situation.
Jon's and your code are missing the constants
These two constants should ALWAYS be set. Without setting up these constants the propeller runs in RCFAST-clock-mode.
To state something obvious did you connect the ground of the propeller with the ground of your H-Bridge powersupply?
If not the result is unreliable function of your circuit.
I haven't finished yet on possible reasons why it does not work. To get there at highest possible speed is to provide full code
and schematics. Drawed schematics. Pictures of wirings don't tell much until you labeled each wire with a name.
Labeling wires with names will take more time than drawing a schematic. The schematic can be hand-drawn. They don't have to be beautifil or professional they just have to be informative
If t has taken you two days to get to the point you described above by fiddling around, this was very ineffective. If you take two days to go through exercises of the PE-Kit-lab you will be further
down the road than with guessing around.
So please attach the most working code-version as a an archived project to a posting that we can analyse from there.
keep the detailed information coming
best regards
Stefan
Mea culpa. It was late, I was a little tired, and I didn't test the listing. It has been corrected above and this morning I tracked down a small DC motor in my junk drawer and connected it to the L293 on the PPDB. The program is actually running (only one motor). I've attached everything for your convenience.
As Stefan points out, you do need to setup the clock for the Propeller; my listing was partial (should have made that clear) and I was expecting you would fold it into a full program.
Another thing to be careful with: you need to ensure that the power supply you're using can give the motor the volts and current that it wants to run 100%. While testing the attached program I tried a 12v motor using 5v from the PDB; it was Smile. When I used a 5v motor everything ran as smoothly as it should.
There is no reason in Heaven or on Earth to have changed my pause() method -- it's tested and works perfectly as is. The point of this programming style is to be able to use existing code without mucking with it. I know you're frustrated, and I may have contributed a bit to that frustraion (and I'm sorry for it), but "throwing everything" at a problem sometimes means we pick up pots and pans when we're in a gun fight, and that doesn't help.
I encourage you NOT to modify existing methods that I or other [known] experienced programmers post, unless the modification suits all the programs where the method could logically be used.
And why do you add RETURN to the end of methods? It is not necessary in Spin unless you're returning a value. It seems like you're attempting to apply old BASIC-style coding to Spin, and I think that is hindering you a tad.
Good luck with your project; I hope the code I posted above sets things straight.
Sorry for all the hassle, especially as, although the snippets i've been posting are less than ideal you never would have seen the problem.
Jon and stefan, thankyou so much for your time and attention, and when I have a few stars under my belt, I hope I get the chance to sort you out
I've been putting in 'ruturn' methods because, as I understand it, they don't hurt and it (may) help in illustrating the program flow, just as in the same way i've been declaring the direction of pins individually, just to keep track.
It's fustrating because I had a good feeling about spin two days ago, and I do have experiance of programming over quite an array of languages, and I think this is the first time I have been stuck in such a rut...and all because I plugged the ground into the wrong bloody hole!!!
But again, thank you so much for all the help and attention
No offense taken, I was just trying to save you from myself (as I wish others would do for me from time-to-time! ) As you can see in the complete listing there is a program constant called MS_001 that is the number of clock ticks in one millisecond. Again, I should be more careful when posting code fragments.
I'm glad you got things sorted with your wiring -- now you can have some fun!
I haven't included the encoder bit yet, and apart from not being able to reverse the motor, everyhting else seems to work ok. I can motor forward, and I can change the motor speed if I send the reverse instruction, but cannot set the speed below zero...
I've attached the project archive, but it's move_motor.spin which is being a pain, would there be any chance you could have a quick look at it for me?
(just to re-itterate, the motors spin both ways with your demo program, and when i set the speed in the cog where the object is originally called...so it isn't a hardware issue)
i looked into your code but I don't understand why you start and stop the cogs all the time.
Can you please explain the logic of the code in normal words.
I haven't analysed all details but I think it will be enough to start a cog per motor ONCE and them just set the speed to a value plus or minus whatever you like.
Did you make some tests when a speed is hardcoded and a negative value?
keep the questions coming
best regards
Stefan