@7:48 that screwdriver scraping on the scope screen makes my teeth hurt X_X
@RalphBacon2 жыл бұрын
OMG 😲 it was indeed the screwdriver scraping over the screen. No damage done though, it was super light pressure - but I should have used a plastic indicator!
@rolandberendonck39003 жыл бұрын
Hi Ralph, I am still blown away about your original code, the simplicity, the use of that static variable and the speed and the responsiveness of the encoder in action. I have tried a few sketches and debouncing circuits, but your solution is absolutely the best! And these little boys are so very great to incorporate into our projects. So thanks very much :)
@RalphBacon3 жыл бұрын
You're very welcome, Roland! Coincidentally I've been looking closely at an alternative way of reading a Rotary Encoder from a suggestion by viewer Marko Pinteric. I've understood his code but have yet to try it out. In the meantime my code will have to suffice!
@rolandberendonck39003 жыл бұрын
@@RalphBacon I am looking forward to that Ralph, but he has to come up with something really really clever to beat your code!!
@leonardohomem4 жыл бұрын
@Ralph thanks for this whole lesson and experiments. I have consulted several sources on how to debounce and make these cheap encoders more accurate... None of them reduced the lack of accuracy without slowing down the readings... I used the CLK falling ISR + a HW debounce with the 1nF / 100k RC filter and now it works like a consumer product. Thanks again!
@RalphBacon4 жыл бұрын
You're most welcome, Leonardo, I'm glad it worked for you.
@bikefarmtaiwan18007 жыл бұрын
Hi again Ralf- thanks for another interesting and useful video. You have managed to fill an empty spot for all those that want to improve their knowledge with respect to what you teach and share. This is a great resource and I wanted to let you know it is much appreciated.
@RalphBacon7 жыл бұрын
Spread the word indeed, Bikefarm Taiwan; the more people that get to know about Arduinos and their cousins the better the world will be as we implement solutions to problems we never even imagined could be solved by such a small device. You are most welcome, thank you very much for posting.
@arsenic1987 Жыл бұрын
Hmmm.. Old video, but hey, I couldn't help but notice that the change in code of lastInterruptTime changes to a "minimum time between pulses".. But contact-bounce _was_ taken care of by just "waiting around" for a TOTAL of 5ms.. A single contact bounce of 5 milliseconds sounds like a VERY long bounce to me. Usually the bounces are in the microseconds range. But there might be 10-20 bounces, thus a total wait of 5ms is "probably good". But after moving it outside the if-clause, you could definitely reduce the time to make it more responsive, since every teeny bounce would reset the time.
@RalphBacon Жыл бұрын
Well, I reckon that 5mS is probably a reasonable time to wait for a switch bounce; some really bad switches can bounce for 20mS according to switch-bounce guru Jack Ganssle. I think I put the pdf of his work in my GitHub, definitely worth a read. I've just created a tiny switch bounce PCB with SMD components for a project I'm working on. Works like a dream and it's based on Jack's circuit. In that case, of course, hardware does the debouncing and no delays of any kind are required, the nirvana of software developers.
@hoggif5 жыл бұрын
I had problems with a clicky rotary switch when I used them first. I learned you really need to debounce them or measure every edge change. If you handle all edge changes, you need usually no debounce, because then bouncing up signal is counted like up-down-up-down-up-down-up (which is same result as a single "up" because the up-down pairs are cancelled). If detents give you more than one count, just divide it with a suitable value. I found quickly too that with very fast turning you probably start missing pulses. I think with every switch it is always very important to assume bouncing edges even if you have them or not. In future code may be pain to debug if you use different switch or you may get a buggy appliance by just replacing a broken rotary with another model that has debouncing you did not have before. BTW, my favourite method of debouncing often was using a timer interrupt and tracking if you have enough similar readings in a row. If you read 101010101111111, you may detect switch is probably stable 1 after several similar values. (and likewise 010101010100000000000 must surely mean stable 0 for now). If you need a "push" event, just keep track of the stable value and as stable value changes (happens only once), register a push. (or like every n events if you want a repeating button effect).
@RalphBacon5 жыл бұрын
There speaks the voice of experience, hoggif! Yes, switch bounce should definitely be carefully considered and catered for. I've even come across commercial products that do NOT do this well and it results in a piece of equipment that becomes a pain to use (I have a DAB radio that does this). Thanks for posting your experience of switch bounce, I hope others reading this take due note!
@loftos17 жыл бұрын
Hi Ralph, I had this problem when I was designing a rope counter for measuring rope off a reel, I overcame the bounce issue by using a Schmitt trigger, but as you said you can only rotate a mechanical encoder so fast so I used an optical one in the end for my application. The use of a schmitt trigger gives you a lovely clean output signal though on a mechanical encoder.
@RalphBacon7 жыл бұрын
I'm thinking that you and another viewer who has commented here (#I Suck at Gaming) are singing from the same hymn sheet - hardware debouncing is obviously a solution. That said, an optical encoder obviously circumvents all the bounce issues but a Schmitt trigger is also a (much cheaper) solution too. Perhaps I need to fully investigate this...
@icarossavvides26413 жыл бұрын
Can't check it at the moment but most microcontrollers have some Schmitt inputs, I would expect the atmel family does too. As Mentioned elsewhere, it cannot be stressed too much that reading the datasheet of the microcontroller you're using is a must.
@Ray-ej3jb6 жыл бұрын
You mention that the Uno's and Nano 's don't like/do Interrupts on High - Is this also true for the Mega? Does this apply to the main INT pins or to all all the interrupts associated with the pins eg Int On Change.
@RalphBacon6 жыл бұрын
It's also true for the Mega, Ray. If you code HIGH it actually gets compiled as a CHANGE. On the Mega you can choose the following pins for a hardware interrupt: 2, 3, 18, 19, 20, 21. Only on Due, Zero and MKR1000 boards can you code a proper HIGH detection. Pin change detection is similarly limited to RISING or FALLING and you have to do all the detective work as to why you are suddenly in the ISR. It won't tell you the pin that got triggered nor the value! More info on pin change stuff here: playground.arduino.cc/Code/Interrupts
@spock28844 жыл бұрын
Hello Ralph, thanks for sharing. I personally tries to do a strict separation between input, calculation and output. The shown method for decoding the rotary decoder volatile this. What i don't like is that the isr calculates a value. I think it's to limited and it throws away halve of the input information(the speed). I have made a decoding method that doesn't change a number but returns a value that give the direction and the time since the last puls. The calculation of the value that has to be changed is calculated in the sketch. That way i'm more flexible. This way i can add dynamics to the behavior. If the time is short the increment can be bigger.
@RalphBacon4 жыл бұрын
And yours is definitely a better way of doing it, Spock, but I know that jumping around in the code during a demo just confuses people! So my way is not ideal but does show the principle. In Real Life your way is the way to go. Thanks for posting and Live Long and Prosper.
@terryschabert7929 Жыл бұрын
How much overhead does the serial.write affect the sensitivity of the resolver, or the perceived errors in the count? The interrupt may take too long or the serial.write may act as an additional interrupt when it is buffered.
@RalphBacon Жыл бұрын
Serial.print (or write) takes a relatively _huge_ amount of time which is why they must never be included in any interrupt routines (other than when debugging, and even then keep the output to as short as possible).
@jeffschroeder4805 Жыл бұрын
If you were using a micro-controller with more interrupt pins, could you use 2 to determine direction and count detents and another 2 to count pulses in between detents? That might allow you to simplify the code and reduce the likelihood of losing track of the direction.
@RalphBacon Жыл бұрын
Quite possibly, although it would not be usual to use two interrupt pins for one rotary encoder. Most manufacturers just ensure you turn the knob slowly enough for the underlying code to keep up (my radio does this and just ignores me if I try and spin it too fast). However, that said, perhaps your approach could work - if you ever get the time (and inclination) do try it out and report back!
@OneIdeaTooMany4 жыл бұрын
I purchased a rotary encoder and it's doing the same thing. Seeing this video really helped me to understand what's going on. Thank you!
@RalphBacon4 жыл бұрын
Glad it helped, Solman!
@KW-ei3pi Жыл бұрын
Hey Ralph. At about 6 minutes, you mentioned that the detent encoder has built-in pull up resistors. Would that be true of all detent encoders? That would explain why my works without needing to call a pull up in code. Thanks
@RalphBacon Жыл бұрын
If you buy a "module" where the rotary encoder is already mounted on a tiny PCB, then undoubtedly the manufacturer has added pull-up resistors (but never guaranteed, of course). They do this so it works "out of the box" and they don't get lots of negative feedback from noobs who are unaware of the need of pullups (or INPUT_PULLUP in your sketch).
@AnalogDude_2 жыл бұрын
i believe there also ones that have leds inside and also "friction-less". Would like to try these.
@RalphBacon2 жыл бұрын
The ones with LEDs inside are called _optical_ rotary encoders and can turn at ridiculous rates, with zero bounce. The frictionless ones are called _stepless_ rotary encoders but require a bit more coding to use without getting confused exactly which state it's in.
@AnalogDude_2 жыл бұрын
@@RalphBacon i have one standard alpha, it's soldered on a board, but would you try again?, using a 200Hz timer, hardcore direct access to the port not using the "Arduino language" and via bit masking to isolate the needed pins, sampling the pins is what i did. the timer interrupt takes the port value and the mainloop handles it.
@willofirony7 жыл бұрын
With all due respect, I suspect that KillerExtreme has missed the point regarding rotary encoders. They are not physically confined (like, say, a potentiometer) to one full rotation or less. So, the resolution is decided by firmware. If his application needs finer control, he simply changes the mapping of the encoder's input to his output so that more degrees of turn are required to affect the output. Infact, having more steps per degree of turn, reduces the resolution of the control loop. Bounce: I agree with you, regarding lack of response in volume controls, etc. I do suspect one can become more sensitive to this phenomenon, the more familiar one is with the functionality of UIs. Those "plebs" who are blissfully ignorant of how these things work, respond to such inconvenience with "Oh, it is OK, It always does that". Is knowledge such a valuable thing?
@RalphBacon7 жыл бұрын
You are correct, Michael, in stating that detecting each pulse edge *reduces* resolution - my video clearly showed that having it that sensitive made it awkward to use. If #KillerExtreme wanted to use his rotary encoder for precisely tuning a radio then fewer pulses for a given amount of travel work better. On the subject of... On the subject of Bounce, you are once again IMHO correct. Ignorance is indeed bliss. Whenever my car radio's volume control does not respond as I expect it to I think 'missed pulse detection again' instead of 'must turn it slower'!!! Too much knowledge is indeed a dangerous thing.
@ismzaxxon7 жыл бұрын
Commercially, You dont do so many pulses. As encoders age, they get worse. Also, when you have an inbuilt push button, fast changes causes last minute changes...hence complaints from customers.
@willofirony7 жыл бұрын
At least I was correct in assuming you deserved respect :-)
@jeffbluejets26266 жыл бұрын
One can get a 600 ppr optical rotary encoder from Ebay these days for as little as Aus$13.00 - $14.00 . I am about to look at using them in fact (as a counter) or rather as a dual counter for sync on a spindle to leadscrew and that is what brought me here. This brings up another query you may be able to help me with, using 2 of these optical rotary encoders, one on the spindle and one on the leadscrew, if I am to use both interrupt pins , would any problem arise from missing pulses ? As I understand it only one interrupt can happen at a time. Possible it is explained somewhere, ( need to look further) just thought I'd ask while I'm here.
@RalphBacon6 жыл бұрын
Well, Jeff, an interrupt can't be interrupted, so if your code was dealing with a pulse from one Rotary Encoder and the other one then triggered an interrupt, that interrupt would be queued to run once the first one was completed. So no missed pulses but if your ISR is too long you could have too many queued up.
@jeffbluejets26264 жыл бұрын
Hi Ralph, could you explain line 34 a bit more as it appears max and min are reversed. I did a search of that particular line to see if I could understand it but nothing really came up.
@RalphBacon4 жыл бұрын
The "min" function takes the lower of the two values. So, if we do min(100, 54) we will get 54. If we have min(100, 244) we get 100. We could write it with the values either way round. I suspect the max() in the middle of it has confused you. Arduino state: "Perhaps counter-intuitively, max() is often used to constrain the lower end of a variable’s range, while min() is used to constrain the upper end of the range." Basically, that line restricts the maximum to 100 regardless of what the value is. Write a small sketch (it will take 5 minutes) and use the Serial input to enter two numbers to see how it works. That way, Jeff, you will truly understand it.
@chrisw14624 жыл бұрын
Rising and Falling for iterrupts are fairly well defined. The logic in the microcontroller has a set point where a low becomes a high and vice versa. When the signal crosses that value, the 'rising' or 'falling' interrupt would be triggered. The 'change' interrupt is triggered no matter which way it goes. If your input were a slowly moving ramp signal, you could get some wacky readings, since the rising point will be different from the falling point, voltage-wise. But with an on/off signal like the encoder, we don't have to worry about that. The code for using all four different states of a rotary encoder like this is fairly common. You need to read both pins on the change, and you need to know which one caused the interrupt. If pin A causes the Change interrupt and it's now High, it was rising. If pin B causes the interrupt and it's now low, it was falling. In the two separate ISR's, you have four states each: For the A interrupt: Pin A rising while B is low, or A rising while B is high. A falling / B high. A falling / B low. The B change interrupt would have similar states. If you study the timing diagram, you'll see that of these 8 states, four can only occur during clockwise rotation, and the other four can only occur during counterclockwise rotation. So you know immediately on getting the interrupt which way the encoder is turning, even if it skips due to being turned too fast. To halve the resolution, you could use Rising and Falling for A only, for example, and just ignore the other states. You'd only need to read B instead of both, since the interrupt already tells you A is Rising or Falling. This would be close to the code in the video, except you definitely know which way the encoder is turning. Taking it further, you could interrupt on one state - for example, A Rising. The ISR would only check B. If B is low, it's turning one way. High, it's the other. It's important to note that the debounce time is effectively doubled if you check all states, since the interrupt will be called two times more than the original code. If you use only Rising or only Falling, it would be simply 5 ms, or half the original code. This is important because it will affect how fast you can turn the knob. If you check all states, you get really high resolution, but the ISR is busy ignoring you for 120 ms for every full rotation. It won't take much speed to miss a few ticks, especially if you get a noisy encoder and have to increase the time above 5 ms. Most mechanical rotary encoders use wipers on a rotary disk with conductive fingers. It isn't a sprung contact pushed out of the way like a switch or relay - the wiper only has to move the thickness of the finger plating. The crossing does cause noise on the signal which will look like bounce, but it's much smaller than a sprung contact bounce. A 5 ms dead time wouldn't be long enough to debounce a sprung switch, but it works fine here, and even lower might be possible with a new encoder. Older ones get dirty and worn, of course, and will need more debounce time.
@RalphBacon4 жыл бұрын
Good explanation! And I've discovered there are good Rotary Encoders and bad ones, in terms of switch bounce. The one used in my car, for example, is undoubtedly a much higher quality than the one I used in this video. Ironically, I bet General Motors paid about the same as they bought a few million of them!
@ismzaxxon7 жыл бұрын
I have known Nick for 10 years plus(via forums) Nick and I were using Atmel chips for that time. Arduino is an Atmel micro. Nick knows arduino as all we had years ago was machine code for these devices. As a side note, memory was so small, that we had to use machine code rather than wastefull C. C even uses RAM for contants and string that don't change etc.
@RalphBacon7 жыл бұрын
If I tell you Terry (and don't spread it around) that I used to have to program in assembler for the 6502 chip with just 4K memory, you will appreciate that I understand totally where you're coming from! These days, memory constraints are the last thing on developers' minds until you try and use the same techniques you use in commercial .NET-style programming on an Arduino. Hah! Then you suddenly realise that you really must write efficient code, and not have constant 'strings' in your code memory, which requires a bit of a paradigm shift in programming thinking. Nice to have someone on board with this appreciation!
@Roy_Tellason4 жыл бұрын
There are a few of us out there, I used to do z80 assembler back when...
@williammiller75437 жыл бұрын
Ralph, Thanks for the update. Would you consider doing this with an ESP32? I'm using a ESP32 to control a Sous Vide cooker/PID loop. and would like to use the encoder to control a menu for time and temp changes and I'm not sure how to use an interrupt with the ESP32. I don't want to be sitting there checking the state of the encoder constantly. The program could be away from the PID loop for a second or two but it cannot be gone for any extended time or the temp will be way off. I've switched most of my project MC work over to an ESP-8266 and now a ESP32 because of its additional features
@RalphBacon7 жыл бұрын
The ESP32 is certainly the flavour of the month! And you're in luck as the ESP32 has two cores, with 32 interrupts each. Exactly how to use them is best understood by reading this: esp-idf.readthedocs.io/en/latest/api-reference/system/intr_alloc.html from the makers, Espressiff. This is a good document (v3) to read anyway. In due course, and as my understanding of the ESP32 increases, I will no doubt be doing something with it that requires interrupts. For the ESP8266 it's even easier as you can use any of the GPIO pins (except GPIO16). Wow, spoilt for choice. Thinking about it, my original sketch for Rotary Encoders should run unmodified on an ESP8266 board (eg ESPDuino), but I haven't tried it (yet). You might want to though (and let us know whether it works as expected). I'll add the task to my ever-growing list, William, so if you don't do this before me keep your eyes peeled for a video on interrupts on the ESP32 in due course.
@williammiller75437 жыл бұрын
Thanks for your quick responce. I'll give yor suggestion about trying the original rotary sketch on a ESP-8266. I have the parts needed and I'll let you know.
@andrewferg87374 жыл бұрын
Had the same issue with reversing errors on a 3 pin no-detent encoder. This debounce function cleared it up: bool debounce(int Button) // generalized function for active LOW button debounce { byte count = 0; for(byte i = 0; i < 5; i++) { if (digitalRead(Button) == 0) count++; delay(10); } if(count > 2) return 1; else return 0; }
@RalphBacon4 жыл бұрын
That's quite a thorough test you've done there for debouncing, Andrew. I've found most switches do not bounce for longer than 5ms and even "bad" ones are done by 20ms (which probably means I should choose a better switch). Anyway, if that debounce routine works for you keep using it and thanks for sharing it here.
@fredriksjoblom51616 жыл бұрын
Have you tried going over specs on your capacitor values? I saw a guy with similar problems, and he solved it by simply changing the 1nF caps to 100nF ones to give the microcontroller a longer time to cach these events.
@RalphBacon6 жыл бұрын
That's certainly one way to try and address the problem of switch bounce, Frederik. The main issue is that it may work for one switch but not another (so if you were a manufacturer you want repeatability of behaviour and that may not be the case here). I like the hardware solution but it involves further hardware and connections; the software solution can be made to work for almost any device but can introduce longer delays before a change is acknowledged. It's a minefield, don't you think?
@Roy_Tellason4 жыл бұрын
I have one of those rotary encoders which came as one item of many in that batch of stuff I bought from banggood a while back, and hadn't gotten around to playing with it yet. I had no idea that contact bounce was going to be so much of an issue with it! My thinking while viewing this video was that optical was probably the way to go, and then you commented a bit after that about how expensive they were. I wonder if that's changed any since then? Perhaps salvage from a mouse might be the ticket...
@RalphBacon4 жыл бұрын
Contact bounce can be dealt with very successfully within software (as I showed). Hardware debounce is better (video #98) but not essential. Optical is ideal but then you are talking more money. Salvage from a mouse is a great idea if you can get a mouse with a ball these days.
@KJW6487 жыл бұрын
Optic rotary encoder ! could you make one, with a cheap or old mouse wheel ?!? :)
@RalphBacon7 жыл бұрын
That's a really kind offer, Kuk, but I really want to use 'standard' components that others can then source too. I don't know why optical encoders are so expensive, when as you say, they were used in old mice that you could buy for £3 - but an optical rotary encoder is nearly 10 times that cost. Thanks again for the offer, stay tuned for more on encoders and interrupts!
@crayzeape22307 жыл бұрын
Ralph, did you read Kuk Willson's post as "I could make you one" perhaps? Kuk Willson, yes, you could use the optical encoder from a mouse.
@RalphBacon7 жыл бұрын
Yup. Thank goodness I declined his "offer"!!! Well, I came to my PC this morning and had a zillion messages from last night's video. Obviously I didn't read this one correctly although I feel Kuk probably would have built me one if I had asked! Right Kuk? Er, Kuk? Obviously, he's just popped out for a minute...
@paulpvhl19305 жыл бұрын
@@RalphBacon This is old, but … I read it as you did Ralph until I looked again. I find this type of cognition error fascinating. Looks like we both read the separated exclamation as a capital I, possibly because the following c was lowercase. I love it!
@jimbooth20102 жыл бұрын
Nice info, thanks. I am currently working on a rotary encoder project.
@RalphBacon2 жыл бұрын
Sounds great! Good luck with your project, Jim.
@icarossavvides26413 жыл бұрын
Not sure exactly what killer-x-treme's problem is but I'm assuming he (?) wants a high resolution so he can tune the VCO in small steps? Well he's got a built in switch so I would have thought an obvious and reliable solution might be to have multiple step weightings selectable by pressing the switch? Course = 10MHz steps, press, 1MHz steps, press 100KHz steps etc. On heritage analogue instrumentation we used to have two knobs, course and fine.
@RalphBacon3 жыл бұрын
Sounds like a plan worth exploring. Let's hope he reads your comment.
@andreweastland96347 жыл бұрын
Interesting video, thanks. You need to add another layer to your code that looks at the last state of the pins. Although there are only 4 possible states, not all states are valid depending on what the previous state was. This way you can filter a lot of the spurious noise. E.g. if the last state was a=on, b=on then the only valid state to follow this is a=on,b=off or a=off,b=on, neither of the other two states are valid and so should be ignored. If you add this logic to your code you will improve the accuracy dramatically.
@RalphBacon7 жыл бұрын
That is an excellent suggestion, Andrew. Hmm, I might try this out quickly as the hardware is still strewn over my desk! Thanks for the suggestion.
@ipadize Жыл бұрын
i have never had good experience with these encoders. Then i found out about the Bourns ACE128 absolute encoder and also there is a library for the arduino available, which works perfectly. Yeah it doesnt have a clicky button and maybe has too much resolution (128ppr) but you can just divide the raw number by some amount which feels appropriate.
@RalphBacon Жыл бұрын
That's a lot of non clicks for a single turn of the knob, for sure. But as you say, using a subset (eg 5 clicks) to equal one step would be fine. I'll check out that encoder, thanks for the info.
@ipadize Жыл бұрын
@@RalphBacon fyj, you can connect the encoder either via 8 pins + ground or connect the encoder to a i2c module
@maxximumb7 жыл бұрын
Great video. I wondered how rotary encoders knew which direction they were moving. I've never used one so never needed to find out. But now I know. You mentioned that optical rotary encoders were expensive, what are the rotary components in mouse wheels? They have a slotted wheel between and LED and what I'm guessing is a photodiode of some type. Is this an optical rotary encoder, or a different type all together?
@RalphBacon7 жыл бұрын
A (non-laser) mouse is a very good example of an optical rotary encoder - but they are not something you could easily wire up and include in your latest Arduino project! I don't know why standard optical rotary encoders are so expensive (£20 - £50). Perhaps they are designed to be connected to a motor that you are trying to measure the speed of. Or the Chinese manufacturers haven't overproduced them yet so they are not readily available on eBay at low cost. Whatever, they are currently beyond my price range so we'll have to wait until they drop in price... Nice to hear from you again Maxx.
@maxximumb7 жыл бұрын
Ah, I've just been looking through my parts bin and found that most mice have just a 3 pin rotary encoder. The optical one must have been from a more expensive mouse that I salvaged. But I did find more optical encoders in printers that I've taken apart for parts. That might be a source for optical rotary encoders if you needed one on the cheap. I ask all my friends and family for their old electronics, good supply of motors, encoders, MOSFETS, and other components. It's harder to salvage SMD parts, but I've yet to find an electronic cast off without some useful parts. Even if it's just wires and cables.
@RalphBacon7 жыл бұрын
Too true, salvaged parts can often realise good finds, even if only for experimentation. Optical rotary encoders are used in many places as you mention - except in the Arduino hobbyist world it seems. Oh well... non-optical still do the trick for 99% of the uses we need them for!
@maxximumb7 жыл бұрын
I'm slowly collecting stepper motors and rods etc, to make myself a CNC. This isn't going to be a fast project, but I thought to use printer optical rotary encoders to give the Adruino feedback as to the cutting head's location on the x/y axis.
@RalphBacon7 жыл бұрын
I don't see why that would not work. Perhaps you could read up how 3D printers know where the printing head is, if it works for a 3D printer it will work for a CNC machine too?
@retronexusnet7 жыл бұрын
Hi! Can you please make a video about how to code for a dual rotary encoder?
@RalphBacon7 жыл бұрын
I'm not sure I really know what a DUAL rotary encoder is - have you got a link that I can use, or a part number?
@retronexusnet7 жыл бұрын
It would be fantastic.. building a homecockpit... and these are used tons... www.leobodnar.com/shop/index.php?main_page=product_info&products_id=196
@peoplethesedaysberetarded7 жыл бұрын
A dual rotary encoder is the same as a single, except with more pins. Look up "dual concentric rotary encoder" or Elma E75 (sorry, E37). There's an inner and outer ring, both of which can be turned. These lead to more pins on the back and you can monitor these just as you would two regular encoders (except they have a common ground and common body). But: dual rotary encoders are EXPENSIVE. I can order a bag of 10 rotary encoders for a couple dollars, delivered. But one dual rotary encoder comes to around $14 delivered.
@retronexusnet7 жыл бұрын
You are right... ELMA are by the way the official supplier for Boeing cockpits and have the best quality. It would be great to learn more about them though.
@RalphBacon7 жыл бұрын
I've had a look at this, #konturgestaltung, and as #ISuckAtGaming has mentioned these are effectively two rotary encoders in a single body. The outer sleeve on the shaft controls one A/B set, the inner shaft controls another. They are not joined internally (other than the ground). To use these you would simply treat them electronically as two entirely separate encoders, but remember than an Arduino only has two interrupts so if you use my original sketch from video#19 with an extra interrupt for the second encoder's A/B pair it would work exactly as expected. Does any of this make sense to you?
@dinodubroja74333 жыл бұрын
Low is not zero, it's around 0.3 volts, so you could use RAISING bridge as a trigger for the counter same as you use FALLING, no worries.
@RalphBacon3 жыл бұрын
Hmm, interesting suggestion. I'll add it to my list of things to investigate.
@andymouse5 жыл бұрын
Hi Ralph, having watched Greatscott use a motor from a hard drive as an encoder I thought I would have a go myself, and I had great results with it, I did it a little differently but it was quite good fun and was hoping "Killer X Treme" reads this !!!
@RalphBacon5 жыл бұрын
That's great news, Andy, success can be so sweet!
@eastern8157 жыл бұрын
Good video and watch your video still learn a lot. Could you make a tutorial about OV7670 with FIFO? There are some tutorial about ov7670 but no fifo and the resolution is no good. So I bought a fifo one. But I can not figure out it how to work. So if you make a tutorial video about ov7670 with fifo. I will appreciate you. Thanks!
@RalphBacon7 жыл бұрын
The Jtron OV7670 comes in multiple flavours, Zhang yixin, one VGA, one 300K pixels, and some with the AL422 frame buffer chip (thus making them FIFO). I don't think I have the FIFO module (I acquired one a while ago) which means the Arduino will be too slow to capture a frame, but I will check. It's a useful, cheap camera for making simple snapshots to an SD card - the Arduino can easily do this. Stay tuned, this would be a good video for Arduinites (even if you might have to use a Mega rather than an Uno).
@RalphBacon7 жыл бұрын
Would you believe it but my camera *does* have the AL422 chip on it so I will now have to do a video on how to capture photos onto an SD card using an Arduino (MEGA, probably). Woo hoo!
@eastern8157 жыл бұрын
That's a good news ha ha. Looking forward to your tutorial video Master Ralph.
@ismzaxxon7 жыл бұрын
Slow increments is normal, use pushbutton function to have counter add more than one. Push button again to return to normal increment of 1.
@RalphBacon7 жыл бұрын
Ah yes, that would work. Perhaps we (OK, me) try too hard to solve problems 100% when the good old 80/20 rules applies (if it's good enough...).
@MC_AU7 жыл бұрын
a common solution to that is keeping track of the interval between pulses... Then you can make the ‘speed’ proportional to the rate of rotation.
@RalphBacon7 жыл бұрын
@MC That works if we accept each pulse as being a proper pulse without rejecting it, designating it a 'bounce'. However. I've just completed a small debounce circuit which means we must be able to trust each pulse as being a true pulse (no more debounce timings) so your method would then work really well.
@Krishnavisweswaran5 жыл бұрын
Could you try the following code and see if it works better for responsiveness and bounce detection? It should work for both types of encoders (as long as you use either INPUT or INPUT_PULLUP appropriately.) // Clock signal const unsigned int pinA = 2; // Data signal. We are not going to use an interrupt on this. // So can be some other pin to save the HW interrupt pin. const unsigned int pinB = 3; volatile int count = 0; void isr() { static int lastClk = -1; // Initialize to an invalid state. int clk = digitalRead(pinA); if(clk == lastClk) return; // Bounce! lastClk = clk; int data = digitalRead(pinB); if(clk == data) { // anti-clockwise // remove the 'count > 0 check if you want to allow -ve values if(count > 0) count--; } else { // clockwise count++; } } void setup() { Serial.begin(115200); pinMode(pinA, INPUT); // use INPUT_PULLUP if required. pinMode(pinB, INPUT); attachInterrupt(digitalPinToInterrupt(pinA), isr, CHANGE); Serial.println("start"); } void loop() { static int oldCount = -1; if(oldCount != count) { Serial.print(oldCount < count ? "UP" : "DOWN"); Serial.println(count); oldCount = count; } delay(200); }
@RalphBacon5 жыл бұрын
I have a better idea, Krishna. You get a Rotary Encoder, an Arduino Uno and _you_ try it out. That way you get experience and learn the answer to your own question. How about it?
@erikisberg38864 жыл бұрын
Thank You for an excellent review of the troubles with rotary encoders! I am an EE and have seen many variants of these missbehaviours over the years. I concur that analog filtering, schmidt triggers and proper software in a tasteful mix is the way to go to achieve good performance. It is usually a good idea to start with the oscilloscope first and figure out the timeconstants of the noise and the desired signals. I have also noticed the behaviour You showed as in the car stero and found it very annoying.
@RalphBacon4 жыл бұрын
Thank you very much! Without a doubt, Schmitt triggers are a foolproof way to go but you need more components. Thanks for posting.
@pekkagronfors73047 жыл бұрын
Great video. Very interesting about rotary encoders.
@RalphBacon7 жыл бұрын
Glad you liked it Pekka, as you can see it generated a lot of conversation regarding debounce methods!
@pekkagronfors73047 жыл бұрын
Yes, many suggestions and ideas. I look forward to yet another rotary encoder video :-)
@ArjanvanVught5 жыл бұрын
I really would like to see the same code on a STM32
@RalphBacon5 жыл бұрын
Hmm, I'm not really familiar with the STM32 (didn't I do a video on it once?) but as long as it has a hardware interrupt pin it should work pretty much the same, I would have thought...
@Taki7o72 жыл бұрын
You do not count the steps in between. Basically, you have to make 2 little ticks with that. I solved it like so: void doEncoderA() { if ( rotating ) delay (1); if ( digitalRead(encoderPinA) != A_set ) { A_set = !A_set; if ( (A_set && !B_set) || (!A_set && B_set) ) { encoderPos += 0.1; Consumer.write(MEDIA_VOLUME_UP); } rotating = false; } } void doEncoderB() { if ( rotating ) delay (1); if ( digitalRead(encoderPinB) != B_set ) { B_set = !B_set; if ( (B_set && !A_set) || (!B_set && A_set) ) { encoderPos -= 0.1; Consumer.write(MEDIA_VOLUME_DOWN); } rotating = false; } } And making the counter variables floats instead of ints
@RalphBacon2 жыл бұрын
Thanks for sharing! I'm not sure about making the counter a float (why?) but if this all works for you, then it works! 👍
@jonshygye50057 жыл бұрын
Using a "noisy" signal to trigger interrupts just seems a poor choice. Those spurious interrupts can cause a performance hit and the incorrect readings. Just cleaning up the interrupt signal should suffice.
@RalphBacon7 жыл бұрын
That does seem to be the consensus, Jon. So I've built a simple Schmitt trigger buffer to clean up those pulses which appears to work nicely but I need to inject a rubbish signal to prove it can work to you guys in extreme cases. Hmm, a simple triangle-wave signal injector, now there's a topic for a future video maybe... Thanks for posting and adding your voice to the "use a hardware debouncer!" clamour, I am now persuaded this is the way to go!
@tubical717 жыл бұрын
Using a little bit of added hardware will help a lot regarding de-bouncing and encoder detection speed/tracking. Here to see: kzbin.info/www/bejne/rqiUeXx8hMqSf80 I added some schmitt-triggers at both encoder switch pins, basically a 7414 which has four of them inside and simply daisy-chained two of them on one encoder pin. The first one also has an RC filter 15kOhms in series with an 0.33muF cap to ground to eleminate spikes. This setup works up to hundrets of RPMs...
@RalphBacon7 жыл бұрын
Now that's interesting as I designed a simple debounce circuit using a quad nand gate CD4013B with the intention of using two per pin (in series) to ensure the signal was not inverted. Sounds like my logic is good, given your experiences. I also am including an RC filter as suggested by the makers of a dual rotary encoder, but I might adjust the values to your ones as you have had success. Thanks for this #TubiCal, appreciated.
@janhellstrom41657 жыл бұрын
Hello Ralph, I have tried your Rotary Encoder code and it seems to work fine. I intend to use it in my attempt to make a speed controller for my CNC spindle, but I have some questions about your isr routine. In Arduino's homepage: www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/ you can read "Generally, an ISR should be as short and fast as possible" and also "millis() relies on interrupts to count, so it will never increment inside an ISR" Your isr routine is quite long and you are using the millis function. Could that give me any problem if I add more code for PID-regulation and so on? I like your videos with clear and good explanations! Regards Jan
@RalphBacon7 жыл бұрын
Hey, Jan! Let's try and clear up any confusion over ISRs! I have often stated that an ISR should do the least amount of work possible - but I'm doing demos in my videos which necessitate putting Serial.print and other long-winded stuff in there, just to show the point I'm making - BUT which should NEVER be put there in a real sketch. If you can get away with just incrementing (or decrementing) a counter that's the best possible scenario. Using millis() in the Rotary Encoder sketch is absolutely fine and is an accepted way of stopping switch bounce (where the mechanical switch actually bounces a few times in an extremely short period of time, almost always less than 5ms, but which is an eternity to even a humble Arduino Uno, so it counts EACH of those bounces). The millis() value will NOT increase whilst inside the ISR but that's fine - we can safely use a 'snapshot' value for that aforementioned debounce feature. What you don't want to be doing is putting logic inside there. Let the main loop() function do all that by checking the count (or whatever) you're updating inside the ISR. That includes PID calculations! Remember that whilst the ISR is running, the main loop() is BLOCKED, not a good situation. Further requests to the ISR just get queued, making the situation worse! I hope this helps in your sketch design, but do come back with more questions as you develop your code. I'm really happy you like my videos and thanks for posting an interesting question.
@ipadize Жыл бұрын
28:58 i have some with 512ppr for my servo motors and i could spin them at 6000 rpm without a problem (i was using Mesa hardware though, really good stuff)
@RalphBacon Жыл бұрын
I'm guessing that those RE were optical then? A mechanical one would never survive (nor work at) those speeds!
@ipadize Жыл бұрын
@@RalphBacon yes optical, also shaft mounted. HEDS 5540-i14
@joelsmart94855 жыл бұрын
Wow Ralph and Julian Lett would have to be mates I think they share the same work mat
@RalphBacon5 жыл бұрын
He stole his from me. Mine's newer. And bigger.
@shalbsb3 жыл бұрын
thank you for exist. This video is so cool!
@RalphBacon3 жыл бұрын
Glad you liked it!
@johnnymotorboat88246 жыл бұрын
In case anyone missed it. When one pulse goes high, the other goes low. Well off to take my counter-depressant and counter psychotic medication.
@RalphBacon6 жыл бұрын
It's not as simple as that, David. The pulses are out of phase by 90 degrees, so turning the encoder in one direction gives you a particular value on the pins whilst turning it in the opposite direction gives you a different value - that's how we can determine direction.
@markopinteric3 жыл бұрын
There is no need for "dead time" (5ms) because, unlike common switches, the rotary encoder has to go through four different stages to create one event. I wrote software that checks this, has no dead time, and works perfectly whether you turn the encoder fast or slow. I would be happy if you could try it out and see if it solves your problems. The code and explanation can be found on the website www.pinteric.com/rotary.html.
@RalphBacon3 жыл бұрын
I'm intrigued in how you resolved the switch bounce issue if you don't ignore signal for a specific length of time after the first such signal. I've looked (very briefly) at your webpage and I intend to read in more detail when I have a few spare moments. I especially like the "impossible movement" signal which can be ignored, I'm guessing. I'd love to try your code out but my (new) workshop is in disarray (typical British understatement) so it will be a while before I can do that. Thanks for the info, appreciated.
@markopinteric3 жыл бұрын
@@RalphBacon Very simply, in order to confirm one move left/right encoder must go through successive four states. Bouncing between two neighboring states is ignored, which is why I don't need dead time. Impossible movements (when one state is skipped) lead to movement to be ignored. I already got feedback from one person that (after looking for several years for this) confirmed my algorithm solved his problem.
@boldford7 жыл бұрын
Hi Ralph. There's not much wrong with Rainharvester's suggestion. By using it you tend to encourage people to treat rotary encoders with a little more respect. Were you to spin my car's radio volume control like you did your own for demo I wouldn't be overly happy. Consumer products aren't meant to be "squaddie proof"!
@RalphBacon7 жыл бұрын
Agreed, Brian, I was definitely abusing that volume control but purely in the interests of science! If nothing else, the fact that is *doesn't* respond when turned quickly makes me turn it very slowly indeed in day-to-day use. It has trained me! But given this is not some cheap Far Eastern component built down to a price but is a commercial, robust item in a GM/Vauxhall/Opel car I felt it would survive a couple of quick spins! Did you not find it interesting though that it also went "backwards" in relation to the direction of spin on a couple of occasions? So we are not alone in the Arduino world in getting either the logic or hardware to behave correctly. Loved the "squaddie proof" comparison (with no offense to any squaddies on my channel!), personally I think it might just survive :)
@boldford7 жыл бұрын
Great channel. I waiting for some REs to arrive so I can simulate multi-multi-turn pots to set CV & CC on a lab PSU. I have learned, although it has a magnitude reduced ripple, the Arduino derived 3.3v isn't too hot as a reference as it's anything but stable over a range of temperatures.
@RalphBacon7 жыл бұрын
Sounds like you need a temperature compensated voltage source, Brian. Maybe a MAXIM MAX6143, or TI MC34063AP. I'm guessing there must be dozens out there, that you can run from the 9v/12v that you have available and get it rock solid. Have you noticed that some chips are now only available as surface mounts? Makes the soldering a bit trickier!
@boldford7 жыл бұрын
SMD = An excuse to practice real use of the recently obtained microscope/camera.
@RalphBacon7 жыл бұрын
You've just given me justification for getting one. Thanks!!!
@josepheccles93413 жыл бұрын
If someone needs to have a fast encoder, they should use an optical encoder.
@RalphBacon3 жыл бұрын
Not just fast but no switch bounce either! Win win.
@lohikarhu7344 жыл бұрын
a 'detented' encoder is far, far from 'standard... more typical are continuous encoders, with far more steps per revolution, like 1024 per rev...
@RalphBacon4 жыл бұрын
Hmm, the one in my car (volume, tuning) is detented. Makes it a more positive action, I feel. Not to say it's not standard, I suppose. Depends on its use, I would imagine.
@hm-yt7lv7 жыл бұрын
please Ralph you are talking quickly some time i can't understanding some world .i like your channel.
@RalphBacon7 жыл бұрын
I'm sorry about that Hafedh, try switching on the (auto) subtitles, that may help you (depending on whether Google can correctly understand me). In the future I will bear in mind that many of my viewers do not have English as their mother tongue and I will slow down. But I am glad you still like my channel.
@TheKetsa7 жыл бұрын
I'm not a native english speaker and I can understand you no problem.
@RalphBacon7 жыл бұрын
For which I'm profoundly relieved, #TheKetsa. But sometimes I do notice I either mumble a word or don't speak that clearly - something that competent English speakers will still understand but which viewers with a poorer grasp of English would struggle with. Even my cat, Benny, doesn't always understand me. Or pretends not to. Hmmm.... Thanks for confirming that on the whole my English is OK!
@scottmitten22487 жыл бұрын
If you click on the settings icon (Little Gear) in the bottom right of the KZbin window, you can adjust the speed. 0.75 might be easier to understand without sounding weird. (I often watch videos at higher speed in my native language if I'm looking for an overview, or general interest, but slow it down if I'm really trying to grasp a concept. Can be pretty handy.
@RalphBacon7 жыл бұрын
Couldn't agree more Scott! I often listen to courses at x1.5 in English but slow it right down when I need to follow instructions and so forth. This should really help non-native English speakers (other than me not gabbling, mumbling or anything else that doesn't sound like BBC English!).
@mwngt125 жыл бұрын
Hi Ralph, Many thanks for your video. Please I have a query as I came across a particular situation in my project: I’m using MEGA2560 R3 and want to read 4 pulses per step from my encoder. It’s a step-less BOURNS encoder with 36 PPR (eu.mouser.com/datasheet/2/54/CW1J-777413.pdf), so my aim is to read 144 pulses per turn. After online research and testing, I managed to write a simple code that debounces the encoder through software -see below- (this includes two CHANGE ISRs, each for the encoder pins A & B, and a variable to count the pulses in either direction.) After completing the circuitry and the coding for one encoder, I’m getting one of the strangest things: even though my board always detects 144 pulses per one turn in total (whether I turn the knob slowly or really fast), at certain points it seems to mistaken the input signal from one pin as though it came from the other, thus messing with the Counter’s final value due to flipping the increment's sign at those particular instances. Looking deeper into it, I simplified the code further to only print out on the screen either “A” or “B” at the end of either ISR, indicating which pin has been triggered on the encoder, followed by 1 or 0 to state whether that pin had come to a low or high state. So in a normal turn of the knob, I get a nice toggle like this: A0 B0 A1 B1 A0 B0 A1 B1 A0 B0 A1 B1 … But then I also get something like this: A0 B0 A1 A0 A1 B1 B0 A0 B1 A1 B0 B1 B0 B1 B0 A0 … I don’t know if you’ve ever come across such an issue, as I’ve not yet succeeded to find an explanation on how this could happen, that is, if it were not due to the code itself, but rather maybe a hardware issue. But if it's from the code, could it be that the interrupts are queuing up because I'm turning the knob too fast? or another reason? Any input or assistance on this matter would be much appreciated. Many thanks for your help in advance, and for reference, here’s the code that I wrote so far: const int encPinA = 2; //interrupt pin const int encPinB = 3; //interrupt pin volatile int p = 0; // counter volatile uint8_t a; volatile uint8_t b; volatile uint8_t a0; volatile uint8_t b0; void setup() { pinMode(encPinA, INPUT_PULLUP); pinMode(encPinB, INPUT_PULLUP); a0 = digitalRead(encPinA); b0 = digitalRead(encPinB); Serial.begin(9600); attachInterrupt(digitalPinToInterrupt(encPinA), ISREncPinA, CHANGE); attachInterrupt(digitalPinToInterrupt(encPinB), ISREncPinB, CHANGE); } void ISREncPinA() { b = digitalRead(encPinB); if (b0 != b) { b0 = b; (b0 == a0 ? p++ : p--); Serial.println(p); } } void ISREncPinB() { a = digitalRead(encPinA); if (a0 != a) { a0 = a; (a0 != b0 ? p++ : p--); Serial.println(p); } } void loop() { }
@RalphBacon5 жыл бұрын
The problem you're describing I have also experienced with these stepless rotary encoders. I believe it's switch bounce that is confusing the µC. Some work better than others. Stepless always work poorly compared to stepped devices too. There's no easy solution. By the time you have catered for switch bounce you might miss one or more positions. I would clean up the Rotary Encoder pins with a hardware switch debouncer as I described in video #96. At least that way you can take out any software coding for bounce.
@mwngt125 жыл бұрын
@@RalphBacon Thank you soo much for getting back to my inquiry. Truth is, I'm mounting the encoder on the output shaft of a DC motor (perhaps not the most ideal way to read a motor position/RPM though I saw it implemented successfully online, plus the motor is slow enough for the encoder to work.) As my project had become a bit more complex, I eventually decided to abandon the software debounce solution and go to good 'ol hardware, since I'll have several motors to read from, and to eliminate the false positives the Arduino has to filter out from all the encoders, and give it more space to do more important stuff. Kindly I have another question that came to mind yesterday regarding declaring and running an ISR from inside a Class. What things should I pay attention to, or new concepts to learn and comprehend, to implement this successfully with little hassle, as perhaps otherwise it might better to leave the ISRs in the main sketch instead. What do you think? Once more, very great videos. unlike in other channels, this one has very little video editing effects (music, intros, visuals ...etc) that would somewhat otherwise distract the viewer, and should make them feel comfortable and focused learning new materials. Many thanks again Ralph
@lsfornells5 жыл бұрын
One problem with using external interrupts on these mechanical encoders is that there’s no way to reliably filter contact bounces. A better approach is reading the encoder inputs inside a fast timer interrupt and only accept steady changes of the input pins. This also has the advantage that you can use any regular input pins for the encoder. This approach works extremely well at any encoder rotation speed, from very slow to significantly fast. In case you want to have a look, this is is demonstrated here: github.com/John-Lluch/Encoder
@RalphBacon5 жыл бұрын
I don't usually disagree with my viewers, on the basis they know more than me, but on this occasion, I think my hardware solution is the best I found, Isfornells. 100% reliable too, at least in my testing! And... If you watch my video #19 (the original Rotary Encoder video) the software solution worked pretty well too, at the speeds I was using it anyway. The trouble with "accepting steady states" is that it involves multiple reads, which are time-consuming and not best suited to an interrupt routine, IMHO. Debouncing has got to occur somewhere, after all. Using "any pin" for an interrupt might work well for some but my video was targetted at using the built-in interrupt pins precisely because they can be relied on. Each to their own! If you have a solution that works well for you it might work well for others too so thanks for sharing the link, you never know who might read this in the future. Thanks for posting, appreciated.
@alanesq14 жыл бұрын
I have been struggling recently to reliably use a cheap rotary encoder on a menu and finally found a method which works very reliably for me, so thought I would share it here in case it is of use to anyone else. see: alanesq.eu5.net/temp/rotary-encoder.txt It stores the last received pin states and the debouncing mostly happens simply by ignoring any repeats of the same pin states then just through a series of if statements it looks for a valid change in the pins (e.g. when turning one direction the pin states just alternate between 0,1 and 1,0). btw - you can see the menu I have used this on here: github.com/alanesq/BasicOLEDMenu
@RalphBacon4 жыл бұрын
That is great, Alan, nice and reliable is exactly what we need with these cheaper rotary encoders, thanks for sharing.