Simple encoder pulse count
Hello all,
I'm a complete newb on this but I have been assigned a project that I'm desperately trying to get started on.
After looking it seems the propeller will do what I need. I'm need to so some inline ISO spec verification on a conveyor.
I cant seem to get the simplest part going though. Which is to read an encoder to derive belt speed.
I have a 5000 pulse encoder that with be running a 1/2" wheel for 10000 pulses an inch @ 56 " per sec. Or 560,000 pulses a sec.
How would I point the pins used to the counter on a cog?
I can see the return from the encoder with the microphone to vga by swapping in the pins connected vs the microphones. I'm using the demo board btw.
If could get that part squared away I think it's just as simple to capture the cnt at those edge points aswell and I can figure out belt speed via the differential .
Kind of a hodge podge trying to get a constant return from the counter.
But all it displays is the pin number on screen.
I'm a complete newb on this but I have been assigned a project that I'm desperately trying to get started on.
After looking it seems the propeller will do what I need. I'm need to so some inline ISO spec verification on a conveyor.
I cant seem to get the simplest part going though. Which is to read an encoder to derive belt speed.
I have a 5000 pulse encoder that with be running a 1/2" wheel for 10000 pulses an inch @ 56 " per sec. Or 560,000 pulses a sec.
How would I point the pins used to the counter on a cog?
I can see the return from the encoder with the microphone to vga by swapping in the pins connected vs the microphones. I'm using the demo board btw.
If could get that part squared away I think it's just as simple to capture the cnt at those edge points aswell and I can figure out belt speed via the differential .
Kind of a hodge podge trying to get a constant return from the counter.
But all it displays is the pin number on screen.
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
OBJ
text : "vga_text"
PUB start | i,a
ctrb := %01010
ctrb := 4
frqb := 1
'start term
text.start(16)
repeat 14
'repeat i from $A1 to $a2
'text.out(i)
text.str(string($A,12,$B,12,$C,2,"cnt"))
text.dec(cnt)
text.str(string($A,14,$B,1,$C,6,"test",$C,2))
text.dec(ctrb)
repeat
text.str(string($A,12,$B,6))
text.hex(i++, 8)
Comments
Is there a way to have a look at Your encoder setup? I am having trouble visualizing how it reads belt speed.
I will assume that Your code formatting was thrashed by the forums, and that everything is indented as it should be??
From what I could see, You get stuck in this repeat loop...
repeat text.str(string($A,12,$B,6)) text.hex(i++, 8)
It's the last three lines You have written, Your code will never leave this section after it enters..and as fast as the Prop is, You might only see one number on screen, maybe try some waitcnt's...
Also check the sub forum, robotics, and search around for encoder's,
One of The resident encoder expert's likes to lurk in that forum.
Just mention dynamic braking, and He will be along shortly...
Here's the idea. You would need to call this with cognew passing the input pin (assumes high-going) and the address of your speed variable. This will run in the background and 10x per second update the belt speed which is express in units of 0.1"/second
pri beltmonitor(encpin, spdpntr) | t, c ctra := %01010 << 26 | encpin ' set for positive edge frqa := 1 phsa := 0 t := cnt ' sync timing repeat waitcnt(t += (clkfreq / 10)) ' update 10x per second c := phsa ' capture count phsa := 0 ' reset for next long[spdpntr] := c / 5_600 ' write speed to hub
One is for the Parallax wheel encoder the coding just uses ina and logic
the other is for a different encoder and uses the propeller counters
feel free to adopt them to your needs
This does what I wanted but I cant seem to keep it from rebooting every time the counter gets to roughly 235 pulses.
The "if wait..." seems to have brought on the rebooting but why?
UPDATE: Seems fixed now after removing the "if"'s . Still accumulates the pulse count without them.
Strange how it crashes the system though.
I have set the accumulator for the read to both positive and negative add. So a pulse in either direction gives an add to the total.
Which of course isn't right. On my 5000 pulse encoder I get 10000 per rev now.
So after commenting out the "waitpne" and its adder I'm getting run away numbers. They are alot higher than they should be.
Adding the check for waitpne and all is back to just double.
I am missing something simple here but what?
PUB PulseMeasure ctra := %01000<<26 + 4 frqa := 1 repeat waitpeq(|<4,|<4,0) counter++ waitpne(|<4,|<4,0) counter++
Gives double, counting both trailing and rising edges, but how does that work with the pin being set to only rising?
PUB PulseMeasure ctra := %01000<<26 + 4 frqa := 1 repeat waitpeq(|<4,|<4,0) counter++ 'waitpne(|<4,|<4,0) ' counter++
Gives, very high, run away numbers.
with the code shown you can play with the variable count and the waitxxx till the cows come home
It just aint doing what you think
frqa := 1 <---- is the amount to accumulate in phsa for each event set by ctra
phsa := 0 <---- clears the counter
ctra := %01000<<26 + 4 <---- sets the mode and pin # - counting begins now
waitcnt(x+cnt) <---- accumulation time -- counter is now busy counting inphsa
counter := phsa <---- FETCH THE COUNT (accumulation continues in phsa)
Post edit ( because a lot of newbees see this stuff )
Using the waitxxx, count++ you are doing the accumulation by reading the pins directly so when you remove the waitpne the cog waits for pin high and bumps the count then repeats but the prop is so fast that the pin is still high so it bumps again and again and again till it finally goes low and the cycle repeats after the next high and you end up with a meaningless high count, In the case of the two active waitxxx's you get a bump on the positive edge and again on the negative edge, to count pulse by pulse remove one count++ but you still need to have both waitxxx to see the high and then the low so the cog can recognize the pulse. just reverse the order of the waitxxx to see positive pulses or negative pulses.
using ctra,freq,phsa the cog is doing it for you. You select the type of event and tell it what pin and off it goes. They are different ways of doing the same thing but this method is faster.
you should check out the counters tutorials.
Note that the discrepancy between the menu setting (in Hz) and the captured pulses has to do minor math errors in the synth object.
I just updated my earlier post you might want to re read it
Hope I helped too-
Of course, I see it now. I had the right approach to counting but mistakingly added twice. It was so simple. Wait for both pos and neg edges like I have, just don't add for each.
repeat waitpeq(|<4,|<4,0) counter++ waitpne(|<4,|<4,0) 'counter++ [B]Commenting this one or the other will do. This way I'm guessing adds after pulse but not until another loop passes[/B]
Could someone show me where I'm using the spin stuff? I thought the code there was assembly? I can see I've got a ways to go.
ctra := %01000<<26 + 4 frqa := 1
It may be better to give a better picture of what I need to do here.
I'm looking at different methods of collecting data for ISO specing inline for production.
I make gift cards.
Bit amplitude, distance , and time are the points I need to collect.
First thing I need, the pulse accumulator. I know with a 1/2 wheel on a 5k pulse per rev encoder I'll get 10k per inch or 1/10000th " resolution.
So , with using card detect from a pickup, I'll trigger the read and at each peak of card bits I'll gather the encoder , clock, and amplitude from the peak. With those pieces I can derive and information I need.
IE.. card speed to run against a voltage gain algorithm for comparison against spec cards. Encoder record separation for bit interval distance.
I'll have to work into it a bit decoder to verify sentinel locations but after that I think the standard f2f chips will do the full decoding off the same read for actual data returns to correlate data to specimen .
Thank you everyone, I've got at least a start here on what I need, a few more hundred hours of reading everything and I should be getting data.
Also for someone else needing something like this or for ridicule.
data displayed on vga:
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VAR long stack[10] long stack1[10] long counter long card OBJ text : "vga_text" PUB start|Count text.start(16) cognew(cardpulse,@stack) cognew(PulseMeasure,@stack1) dira[4] :=1 text.str(string($A,14,$B,1,$C,6,"test",$C,2)) repeat text.str(string($A,12,$B,5,"clk ")) text.dec(cnt) text.str(string($A,12,$B,8,"encd pul ")) text.dec(counter) text.str(string($A,12,$B,10,"card pul ")) text.dec(card) PUB cardpulse ctrb := %01000<<26 + 1 frqb := 1 phsa := 1 repeat waitpeq(|<1,|<1,0) card++ waitpne(|<1,|<1,0) 'card++ PUB PulseMeasure ctra := %01000<<26 + 4 frqa := 1 repeat waitpeq(|<4,|<4,0) counter++ waitpne(|<4,|<4,0) 'counter++
This is Spin code:
repeat waitpeq(|<4,|<4,0) waitpne(|<4,|<4,0) counter++
This is that code translated to Assembly (by me, the Propeller Tool doesn't compile Spin to native PASM):
dat org 0 entry waitpeq ina, SENSE_PIN ' wait for high nop waitpne ina, SENSE_PIN ' wait for low rdlong mycount, par ' get count from hub add mycount, #1 ' increment wrlong mycount, par ' put it back jmp #entry SENSE_PIN long 1 << 4 ' p4 mycount res 1
Again... the Spin code is not fast enough for your 560kHz pulse rate. What you can do, however, is put a counter in edge mode like I demoed above and let the counter do all the hard work. That IS possible in Spin because you're using a counter to count, and it does that while other code is running.
dat org 0 entry waitp[COLOR="red"]ne[/COLOR] ina, SENSE_PIN ' wait for high nop waitp[COLOR="red"]eq[/COLOR] ina, SENSE_PIN ' wait for low rdlong mycount, par ' get count from hub add mycount, #1 ' increment wrlong mycount, par ' put it back jmp #entry SENSE_PIN long 1 << 4 ' p4 mycount res 1
I'm looking at the code you posted most recently and I think you are missing what is being said, if I'm wrong I apologize.
The point is that there are two independent ways of counting transitions or pulses on i/o pins
The first is the repeat, waitxxx, count++ and I'm sure you understand that code now.
This method in spin is the slowest and doing the same thing in assembly is a bit faster,
either way you do not need to setup anything in the counters for this method to work.
The second method is to use one of the two independant HARDWARE counters available in each cog
You activate them by setting values into the ctra,frqa,phsa registers (or b for the second counter) and then
read the phsa (or b) register whenever you need the count.
This is the fastest method available on the propeller.
Got one more issue.
I can not get the proper response from setting one pin low using the samples you provided.
org 0 detecter waitpne ina, dectectPin ' wait for high waitpeq ina, dectectPin ' wait for low rdbyte meddct, par ' get count from hub add meddct, #1 ' increment wrbyte meddct, par ' put it back jmp #detecter dectectPin long 0 << 6 ' p4 meddct res 1
That should set the pin to check for low, right?
Using a LV-21a laser pickup, the out goes low on detect. If I set it to high it works in reverse. I get counting until I trigger the detect as the pin was set to for high. But on low setting I get nothing.
I've tried swapping the equal/not equals. Removing each as well with no luck.
Is there something else to detecting low on a pin that I'm missing? From the examples I can find they look similar.
Is there some out put that has to be switched on to make the pin high to wait for low or do I need to supply a check voltage on outside?
Thanks again, Joe.
Zero shifted right by any value is still zero. If you want to use P4 then it should be 1 << 4
And... waitpne is used to wait for a pin to go low. If your encoder is using an active-low pulse then this is what you want: look for low, look for high (end of pulse), update count.
Reset mask to 1 and installed pullup , all is well.
Thank you again.
detecter waitpeq ina, dectectPin wrbyte meddct,n1 waitpne ina, dectectPin wrbyte meddct,n2 jmp #detecter dectectPin long 1 << 6 n1 long 1 n2 long 0 meddct res 1
I can't seem to make this work. All I'm looking to do is use that as a global boolean flag , either low, card in and 1 or high = no card and 0.
What am I missing this time?
Got It
detecter waitpeq ina, dectectPin wrbyte meddct,n1 waitpne ina, dectectPin wrbyte meddct,n2 [B]Wrongly called internal variable vs the passed parameter from init[/B] jmp #detecter dectectPin long 1 << 6 n1 long 1 n2 long 0 meddct res 1
Corrected:
detecter waitpeq ina, dectectPin wrbyte n1,par waitpne ina, dectectPin wrbyte n2,par jmp #detecter dectectPin long 1 << 6 n1 long 1 n2 long 0 meddct res 1
I've chopped up the ADC demo script to experiment with amplitude recording but I cant seem to get it to work at the same time as another function.
They are running on separate cogs with separate variables yet if both are loaded neither work. But they work if one or the other is commented out, noted below in bold.
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 bits = 16 VAR long counter 'encoder accumulator long card 'card pulse accu byte detect 'card detect long val 'amplitude OBJ text : "vga_text" PUB start|Count text.start(16) cognew(@entry,@counter) cognew(@detecter,@detect) cognew(@cardmes,@card) '[B]Commenting this:[/B] cognew(@asm,@val) '[B]Or this makes the other one work again.[/B] text.str(string($A,6,$B,1,$C,6,"Testing",$C,2)) repeat text.str(string($A,12,$B,8,"clk ")) text.hex(cnt,8) text.str(string($A,12,$B,9,"encd pul ")) text.dec(counter) text.str(string($A,12,$B,10,"card pul ")) text.dec(card) text.str(string($A,12,$B,11,"card detct ")) text.dec(detect) text.str(string($A,12,$B,12,"card amp ")) text.dec(val) DAT org 0 entry waitpeq ina, SENSE_PIN ' wait for high nop waitpne ina, SENSE_PIN ' wait for low rdlong mycount, par ' get count from hub add mycount, #1 ' increment wrlong mycount, par ' put it back jmp #entry SENSE_PIN long 1 << 4 ' p4 mycount res 1 org 0 detecter waitpeq ina, dectectPin wrbyte n1,par ' wait for high waitpne ina, dectectPin ' wait for low wrbyte n2,par ' put it back jmp #detecter dectectPin long 1 << 6 ' p4 n1 long 1 n2 long 0 meddct res 1 org 0 cardmes waitpeq ina, cardPin ' wait for high waitpne ina, cardPin ' wait for low rdlong cardct, par ' get count from hub add cardct, #1 ' increment wrlong cardct, par ' put it back jmp #cardmes cardPin long 1 << 1 ' p4 cardct res 1 org 0 asm mov dira,asm_dira 'make pins 8 (ADC) and 0 (DAC) outputs movs ctra,#5 'POS W/FEEDBACK mode for CTRA movd ctra,#3 movi ctra,#%01001_000 mov frqa,#1 mov asm_cnt,cnt 'prepare for WAITCNT loop add asm_cnt,asm_cycles :spot waitcnt asm_cnt,asm_cycles 'wait for next CNT value (timing is determinant after WAITCNT) mov asm_sample,phsa 'capture PHSA and get difference sub asm_sample,asm_old add asm_old,asm_sample wrlong asm_sample, par jmp #:spot 'wait for next sample period asm_cycles long |< bits - 1 'sample time asm_dira long |< 3 'output mask asm_cnt res 1 asm_old res 1 asm_sample res 1
I've moved the pins around to get some physical separation but nothing different.
Anyone see what's causing this?