Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

High Resolution Quad Encoder Problem


  • Please log in to reply
25 replies to this topic

#1 Ahmed Atlam

Ahmed Atlam

    New Member

  • Members
  • Pip
  • 3 posts
  • LocationCairo, Egypt

Posted 25 September 2012 - 11:32 AM

Hey guys !
I am new here, first post ! I am a meng, so code and electronics are not really my strengths, but I know a few things from research and several projects. I am using a Netduino Plus for this project. It has some PID control and DAQ.

The Problem

I am currently stuck with a 1200 dots per rev shaft encoder. Its a quadrature encoder, giving a phase A and B. I managed to build a decoding circuit (flip-flops,AND & NOR gates) and now I have 2 wires that give pulses for each direction of rotation. I do NOT have a dedicated counter so I am using the pulses to interrupt on GPIO of the netduino (is that wrong? ). Interrupt ports work fine ( position ++; ) however, I need the netduino to be constantly monitoring the process set value through the ADC. That means a while(true) loop and here is where the interrupts from the encoder stop working because the processor is stuck in the loop. If I break the loop, interrupts work fine, but it is no longer monitoring the set value.
I also run into ALOT of out of memory exceptions ( without even adding the print to console to start graphing), specially when the motor starts going fast ( crashes asa duty cycle goes above 45).

Options I tried to consider with no luck:

1) send the the required set values through USB instead of an Analog signal

2) send the values over TCP :
Would love to, as it adds wireless control feature, easily interface with matlab DAQ and simulink. However, I need alot of help coding that (code examples appreciated). Also I was advised that this will consume memory very fast.


I think my major problem is that I am used to matlabs xpc, so memory and sampling times were almost never an issue, plus multi tasking and threading / multi core support was also available so monitoring multiple variables and updating multiple varriables at the same time was not an issue either.

Please help, any advice is much appreciated and welcomed !!
Thanks in advance !!

#2 koloy

koloy

    New Member

  • Members
  • Pip
  • 2 posts

Posted 26 September 2012 - 02:26 AM

My interest is in learning how to design and write VHDL code. There are many quadrature encoder routines available for download on the web, but grabbing code which someone else has written does not teach you very much.

#3 Ahmed Atlam

Ahmed Atlam

    New Member

  • Members
  • Pip
  • 3 posts
  • LocationCairo, Egypt

Posted 27 September 2012 - 05:03 AM

My interest is in learning how to design and write VHDL code. There are many quadrature encoder routines available for download on the web, but grabbing code which someone else has written does not teach you very much.


Well, I understand the concept and I dont have a problem writing the code for say a 2.4GHz processor x86 with a 4 GBs of ram sampling time of around 1e-6 second easily, the problem I had over here was using this high resolution encoder with a netduino thats all. Just to put things in perspective, if the shaft is rotating at 3 revs/second (180 rpm which is not much )thats 1200*3 = 3600 interrupts/second. I just need help on generating an efficient enough code for the netduino to be able to handle all that along side of some computation thats all. Like I said I am just not used to micro-framework.

#4 Igor Kondrasovas

Igor Kondrasovas

    Advanced Member

  • Members
  • PipPipPip
  • 105 posts
  • LocationPorto, Portugal

Posted 07 November 2012 - 06:27 PM

Well, I understand the concept and I dont have a problem writing the code for say a 2.4GHz processor x86 with a 4 GBs of ram sampling time of around 1e-6 second easily, the problem I had over here was using this high resolution encoder with a netduino thats all. Just to put things in perspective, if the shaft is rotating at 3 revs/second (180 rpm which is not much )thats 1200*3 = 3600 interrupts/second. I just need help on generating an efficient enough code for the netduino to be able to handle all that along side of some computation thats all. Like I said I am just not used to micro-framework.


Hello Ahmed,

Did you make any progress to use your encoder directly into Netduino? What were the results? Any progress?

Thank you,

Igor.

Igor Kondrasovas

www.inovativatec.com


#5 Nobby

Nobby

    Advanced Member

  • Members
  • PipPipPip
  • 70 posts

Posted 08 November 2012 - 05:54 AM

Well, I understand the concept and I dont have a problem writing the code for say a 2.4GHz processor x86 with a 4 GBs of ram sampling time of around 1e-6 second easily, the problem I had over here was using this high resolution encoder with a netduino thats all. Just to put things in perspective, if the shaft is rotating at 3 revs/second (180 rpm which is not much )thats 1200*3 = 3600 interrupts/second. I just need help on generating an efficient enough code for the netduino to be able to handle all that along side of some computation thats all. Like I said I am just not used to micro-framework.


There's a couple of ways you can deal with your scenario. If your PID controller is for speed only then the only problem you'll face is convergence speed and possible overshoot depending on your performance specification. Even if the interrupt frequency basically matches the transport delay of the netduino hardware/framework, you just design your PID outer control loop as fast as the device can.

Position control for 3600 interrupts/sec is going to be hard. Depending on how smooth the control needs to be, you would probably have to slow the motor down. If you have to maintain a particular speed range then you'll most likely have jerky position control from lack of controller bandwidth and transport delay.

Although the netduino is capable of 100ns precision timing, most timing functions have 1ms precision. Do you have an option of a lower resolution encoder or do you need to have ridiculously fine position control?

#6 Igor Kondrasovas

Igor Kondrasovas

    Advanced Member

  • Members
  • PipPipPip
  • 105 posts
  • LocationPorto, Portugal

Posted 08 November 2012 - 05:10 PM

There's a couple of ways you can deal with your scenario. If your PID controller is for speed only then the only problem you'll face is convergence speed and possible overshoot depending on your performance specification. Even if the interrupt frequency basically matches the transport delay of the netduino hardware/framework, you just design your PID outer control loop as fast as the device can.

Position control for 3600 interrupts/sec is going to be hard. Depending on how smooth the control needs to be, you would probably have to slow the motor down. If you have to maintain a particular speed range then you'll most likely have jerky position control from lack of controller bandwidth and transport delay.

Although the netduino is capable of 100ns precision timing, most timing functions have 1ms precision. Do you have an option of a lower resolution encoder or do you need to have ridiculously fine position control?


I did the following test today to have a rough estimative of how fast a Netduino can handle interrupts:

1 - Create a small application on a Netduino Plus to use PWM to ouput signal pulses to simulate encoder pulses (only a single pulse for testing). I used a precision potentiometer to send pulses in frequences from 16 Hz (the minum value I could set) until a bit more than 100Hz.

2 - Create another small app in another Netduino to read the signals from the other Netduino using interrupts (edge high only). The interrupt routine simply incremented a variable that stores pulses. In the main loop, I print the pulse counts on the debug window and reset the counter.

The results are: Running at 16Hz, everything goes fine. Actually everything goes fine until about 30Hz, where my second netduino seems to be loosing pulses.

Does anyone else have similar (or different) results to share?

Thank you,

Igor.

Igor Kondrasovas

www.inovativatec.com


#7 carb

carb

    Advanced Member

  • Members
  • PipPipPip
  • 352 posts
  • LocationCrystal River, Florida

Posted 08 November 2012 - 09:43 PM

The results are: Running at 16Hz, everything goes fine. Actually everything goes fine until about 30Hz, where my second netduino seems to be loosing pulses.

Ijor,

I haven't tried anything like that but whould like to try it with the new Netduino Plus 2 if mine comes in this weekend. Can you post the code that you used for the test so I can get a fair test for comparision against a Netduino Plus 1.

Chuck

#8 Igor Kondrasovas

Igor Kondrasovas

    Advanced Member

  • Members
  • PipPipPip
  • 105 posts
  • LocationPorto, Portugal

Posted 09 November 2012 - 04:10 PM

Ijor,

I haven't tried anything like that but whould like to try it with the new Netduino Plus 2 if mine comes in this weekend. Can you post the code that you used for the test so I can get a fair test for comparision against a Netduino Plus 1.

Chuck


Hello Chuck,

It would be nice if you could share your results as well. I suspect something is wrong, since 30hz is very low. The other reason is that after 30Hz, instead of losing some pulses it seems my application is loosing all of them, since the counting goes to practically zero pulses per second.

The following code shows the "Encoder" application that will count the received pulses on the digital input 0 using interrupts and display the counted pulses every second, reseting the counter.

namespace Encoder
{
    public class Program
    {
        private static InterruptPort encoderIn;
        private static int pulses;

        public static void Main()
        {
            encoderIn = new InterruptPort(Pins.GPIO_PIN_D0, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);
            encoderIn.OnInterrupt += new NativeEventHandler(encoderIn_OnInterrupt);
            pulses = 0;

            while (true)
            {
                Debug.Print("Frequency=" + pulses.ToString());
                
                pulses = 0;
                Thread.Sleep(1000);
            }
        }

        static void encoderIn_OnInterrupt(uint data1, uint data2, DateTime time)
        {
            pulses++;
        }

    }
}


The following code generates a PWM pulse to simulate encoder behavior. When you turn the potentiometer on the anolog input the frequency increases. 16Hz is the slowest PWM pulse I could set.


namespace GeradorSinal
{
    public class Program
    {
        public static void Main()
        {
            PWM pwm = new PWM(PWMChannels.PWM_PIN_D9, 16, 0.5, false);
            AnalogInput pot = new AnalogInput(AnalogChannels.ANALOG_PIN_A0, 10);

            while (true)
            {
                pwm.Frequency = 16 + pot.Read() * 100;
                Debug.Print("Frequency=" + pwm.Frequency.ToString());
                
                System.Threading.Thread.Sleep(1000);
            }
        }

    }
}

Igor Kondrasovas

www.inovativatec.com


#9 Igor Kondrasovas

Igor Kondrasovas

    Advanced Member

  • Members
  • PipPipPip
  • 105 posts
  • LocationPorto, Portugal

Posted 10 November 2012 - 07:53 PM

Hello, Today I tried the same scenario using an Arduino to receive the pulses (acting like the component that will count pulses). As soon I started the tests I realized I got the same strange behavior when the frequency was around 30Hz. So, I was pretty sure I was doing something silly in my pulse generator code. As I don't have an oscilloscope in hands here, I doubted if the PWM class was keeping the duty cycle to 50% (as declared on the PWM construtor) after I set a new frequency. And I realized it was not! so the problem was when I increased frequency, I was also indirectly increasing the relative dutycycle (since the duration was fixed) until we got a fixed true logic level on the PWM output. That was the reson I could not read after 32 Hz (2x16Hz). All I did was to reinfoce duty cycle after setting a new frequency. Then I could get reading around 3.5KHz! After that my Netduino Classic stucked. I will upgrade it to .NET 4.2 and run the tests again as soon as I can, than I let you know the results. Thank you, Igor.

Igor Kondrasovas

www.inovativatec.com


#10 Igor Kondrasovas

Igor Kondrasovas

    Advanced Member

  • Members
  • PipPipPip
  • 105 posts
  • LocationPorto, Portugal

Posted 14 November 2012 - 05:19 PM


All I did was to reinfoce duty cycle after setting a new frequency. Then I could get reading around 3.5KHz! After that my Netduino Classic stucked. I will upgrade it to .NET 4.2 and run the tests again as soon as I can, than I let you know the results.

Thank you,

Igor.


Well, I did the tests running Firmware 4.2 and I got similar results as reported in this thread: http://forums.netdui...goodbye-net-mf/

Now I will make some readings about what this erros message is and why it is hapenning. Either way, I think I will have to use an external componet for encoder reading.

Igor.

Igor Kondrasovas

www.inovativatec.com


#11 magoldsm

magoldsm

    New Member

  • Members
  • Pip
  • 9 posts

Posted 03 March 2013 - 08:28 AM

I'm also trying to have a Netduino Plus 2 monitor a pair of quadrature encoders.  Based on the RPM, counts per revolution, etc, I determined I need to be able to track 8000 events per second.  I wondered if the Netduino could do this.

 

I created a program that timed how long an interrupt took from the time it triggered until the main loop resumed.  I jumpered D0 and D1 together so that D0 could cause an interrupt on D1:

 

 

[font="'courier new', courier, monospace;"]namespace InterruptMeasurement[/font]
[font="'courier new', courier, monospace;"]{[/font]
[font="'courier new', courier, monospace;"]    public class Program[/font]
[font="'courier new', courier, monospace;"]    {[/font]
[font="'courier new', courier, monospace;"]        static bool bInterrupt;[/font]
 
[font="'courier new', courier, monospace;"]        public static void Main()[/font]
[font="'courier new', courier, monospace;"]        {[/font]
[font="'courier new', courier, monospace;"]            InterruptPort portInt = new InterruptPort(Pins.GPIO_PIN_D0, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);[/font]
[font="'courier new', courier, monospace;"]            OutputPort portOut = new OutputPort(Pins.GPIO_PIN_D1, false);[/font]
[font="'courier new', courier, monospace;"]            OutputPort portTiming = new OutputPort(Pins.GPIO_PIN_D2, false);[/font]
 
[font="'courier new', courier, monospace;"]            portInt.OnInterrupt += switchInterrupt_OnInterrupt;[/font]
 
 
[font="'courier new', courier, monospace;"]            DateTime time;[/font]
[font="'courier new', courier, monospace;"]            while (true)[/font]
[font="'courier new', courier, monospace;"]            {[/font]
[font="'courier new', courier, monospace;"]                time = DateTime.Now;[/font]
[font="'courier new', courier, monospace;"]                portTiming.Write(true);[/font]
[font="'courier new', courier, monospace;"]                TimeSpan diffWrite = DateTime.Now - time;[/font]
 
[font="'courier new', courier, monospace;"]                bInterrupt = false;[/font]
[font="'courier new', courier, monospace;"]                time = DateTime.Now;[/font]
[font="'courier new', courier, monospace;"]                portOut.Write(true);[/font]
[font="'courier new', courier, monospace;"]                while (!bInterrupt)[/font]
[font="'courier new', courier, monospace;"]                    ;[/font]
[font="'courier new', courier, monospace;"]                TimeSpan diffInterrupt = DateTime.Now - time;[/font]
[font="'courier new', courier, monospace;"]                portOut.Write(false);[/font]
 
[font="'courier new', courier, monospace;"]                Debug.Print("Port Write: " + diffWrite.Ticks.ToString() + "ttTotal Time: " + diffInterrupt.Ticks.ToString() + "ttInterrupt: " + (diffInterrupt - diffWrite).Ticks.ToString());[/font]
[font="'courier new', courier, monospace;"]            }[/font]
[font="'courier new', courier, monospace;"]        }[/font]
 
[font="'courier new', courier, monospace;"]        static void switchInterrupt_OnInterrupt(UInt32 data1, UInt32 data2, DateTime time)[/font]
[font="'courier new', courier, monospace;"]        {[/font]
[font="'courier new', courier, monospace;"]            bInterrupt = true;[/font]
[font="'courier new', courier, monospace;"]        }[/font]
 
 
[font="'courier new', courier, monospace;"]    }[/font]
[font="'courier new', courier, monospace;"]}[/font]
 
Running this program, I found it takes around 18.5 msec to process an interrupt.  That's almost 2 orders of magnitude too slow.  It is also *way* longer than I would have expected a 168MHz processor to require, even accounting for byte code interpretation.
 
Anyone have any suggestions?  Do I need to create an encoder class in the runtime using C++?  How hard is that?


#12 cutlass

cutlass

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts
  • LocationNew England. :)

Posted 03 March 2013 - 10:44 PM

I'm also trying to have a Netduino Plus 2 monitor a pair of quadrature encoders.  Based on the RPM, counts per revolution, etc, I determined I
need to be able to track 8000 events per second.  I wondered if the Netduino could do this.

 

I created a program that timed how long an interrupt took from the time it triggered until the main loop resumed.  I jumpered D0 and D1 together so that D0 could cause an interrupt on D1:

...

Running this program, I found it takes around 18.5 msec to process an interrupt.  That's almost 2 orders of magnitude too slow.  It is also
*way* longer than I would have expected a 168MHz processor to require, even accounting for byte code interpretation.
 
Anyone have any suggestions?  Do I need to create an encoder class in the runtime using C++?  How hard is that?

 

For your speeds and needs, it's simple. :)

1) Do not use C++ for real-time.  IMHO, unless someone knows how what's needed, and how to use C++ for a real-time system, they shouldn't even think of it.  And, no, you can not use a generic C++ compiler/OS. :)

 

2) Use C or assembler.

 

3) Use mult-level, pre-emptive, interruptable RTOS like Keil or freeRTOS.

http://www.keil.com/rl-arm/kernel.asp

Posted Image

Posted Image

 

4) FPGAs RULE!! :)  Processors do only one thing at once.  Even in multi-core processors, there's resource contention (like memory, cache, I/O, etc).

FPGAs are inherently parallel.

Consider something like the Xilinx Zynq ARM/FPGA hybrid.

http://www.xilinx.co...-7000/index.htm

http://www.zedboard.org/

 

 

I posted somewhere before the rough effective speed of .NETMF and the netduino boards.  Basically, .NETMF is 100% interpreted.  It's "slow" because it wants to maintain a small memory/flash/cache footprint.  IMHO, even ~100x/sec is really pushing it.

 

.NETMF is not like Win7/Win8, where the .NET programs can be faster than the old MFC programs.  And, in general, there's very little performance degradation verses writing "native C" code for Win7/8.

 

With the above said, there are many more applications and uses for something like a netduino, than for the "fast" real-time systems.

I think the smart phone market is ~10-30 million per month.  How about microwave ovens, washing machines, etc, etc.

 

Each product has it's niche.  I wouldn't use $300+ Xilinx Virtex 7, that can also suck up amps of power, in a $50 smart phone. :)

But, when I do PID/control stuff, I first run to the latest Xilinx.  I get it to work.  See the resources, speeds needs, and then downsize (LMAO!) if needed.  Most times, it doesn't make sense to spend the engineering time to cost optimize an FPGA.  But, there may be space and power (SWaP) reasons for going with the a smaller FPGA.  Or, it may make sense in a high volume product.

 

BTW, many micro processors now can handle a PID with an ~1,000 sample rate.

But, that also depends on what type of filtering etc is needed.

Doing fast rates with something like a kalman filter can be very hard to implement in a micro-processor.

 

Good Luck!



#13 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 04 March 2013 - 01:40 PM

You are of course correct in your elaboration around thread switching. I think FPGAs are awesome devices but one can't really expect Ahmed Atlam to get himself an FPGA board and take on the challenges of VHDL programming for this project. Besides, I think an FPGA would be overkill, an 8 bit PIC would probably suffice here. I would (like someone else also did earlier) question the need for such a high resolution rotational encoder. The Netduino uses a buffer to store interrupts (with time stamps) in wait for them to be processed. I don't know how many interrupt occurrences these buffers can hold but new interrupts are likely to be discarded as buffers get full. Maybe the main thread could pause for only a brief moment once in a while to allow some interrupts to be processed. At three revs per second, the effect of this would probably be sporadic gaps in the flow of interrupts but between the gaps, resolution would be high. I guess it would be like receiving small bursts of consecutive interrupts and nothing in between. Maybe one could figure out some clever way of making up for the gaps - Do you think it might be possible to extrapolate missing chunks of values between interrupts given the time duration of the gaps? Maybe you could compensate for it by taking the gaps into account in the PID algorithm? Igor was able to process interrupts at some 3,5kHz and that's not all that far away from the required 3,6kHz even though there's no room for any other processing. My "theory" is that you would get 3,6kHz in small bursts in between gaps. I often use IR remote control detectors in my Netduino mini projects and the data is modulated around a 38kHz pulse train - yet the detector is able to reliably recognize the buttons pressed while still performing other tasks in the meantime.

 

As for the memory issues, I too have experienced that many times and found it to be an annoying limitation of the Netduino Plus and it could be an effect of the interrupt buffers growing large. So it's not likely a problem with your code. If you don't need the networking capabilities in this project, you can always re-flash your N+ using a firmware image for a regular Netduino. This would leave significantly more RAM for your application.



#14 Spiked

Spiked

    Advanced Member

  • Members
  • PipPipPip
  • 129 posts

Posted 08 August 2014 - 06:19 PM

"Doing fast rates with something like a kalman filter can be very hard to implement in a micro-processor."

 

Which is why I am constantly amazed that over 8 years ago (July 2006) LEGO was able to build it into a kids toy, for $99, and nothing has been able to touch it yet that I have identified (as in available and working out of the box).  3 servo motors fully synced with PID control from encoders, while running an interpreted but multithreaded user programs, on an ancient ARM. Oh, and 4 sensors of about any connection type.  Sigh.

 

So I ordered a cyprus FPGA to explore this aspect of the hobby, not having any luck making the Netduino or an Arduino do what the 8 year old LEGO can do.  Any pointers to learning FPGAs?



#15 Juzzer

Juzzer

    Advanced Member

  • Members
  • PipPipPip
  • 135 posts
  • LocationHertfordshire, UK

Posted 08 August 2014 - 06:32 PM

For a few dollars you can do the same as Lego - just use LSI7366 SPI Quadrature IC's...

 



#16 Spiked

Spiked

    Advanced Member

  • Members
  • PipPipPip
  • 129 posts

Posted 08 August 2014 - 07:00 PM

Well that is certainly in the right direction, but a ways off from what I want to do fully.

 

So im guessing (sorry im a software guy) this is a chip I add externally? and it eliminates the need for tying up interrupt pins on the Xduino (x=ar or net)? which would be helpful since the Arduino only has 2 from what I've read, and the Netduinos cant really depend on accurate timing.

 

I still would like to add accurate hc-sr04 reading to the mix. Im guessing this does not do that?

 

BTW amazon and spark fun has never heard of a LSI7366.  But I see a data sheet on it (LS7366)

 

Then I need to figure out SPI ? And use a select for each encoder chip I assume?

 

Is this easier than using a FPGA?



#17 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 08 August 2014 - 07:19 PM

... the Netduinos cant really depend on accurate timing.

 

They cant, but some of them (gen 2) have [hardware] timers with quadrature encoder inputs  :P



#18 Spiked

Spiked

    Advanced Member

  • Members
  • PipPipPip
  • 129 posts

Posted 08 August 2014 - 07:24 PM

I know nothing about that. So, cant use or comment on something I do not know about. Apparently it is a secret?



#19 Juzzer

Juzzer

    Advanced Member

  • Members
  • PipPipPip
  • 135 posts
  • LocationHertfordshire, UK

Posted 08 August 2014 - 07:24 PM

The LSI7366 is a quadrature counter that can read encoder at millions of pulses per second.
On the micro side you can ask the chip via spi for its current count.
The chip also has the ability to raise events after a user selected count.
So yes, you need to add the chip yourself but it is a very simple circuit.
There are libraries for netmf and arduino.
Yes to having a CS pin per chip.
Much easier than a FPGA.
Adding ultrasound to the mix should be trivial.

#20 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 08 August 2014 - 08:40 PM

I know nothing about that. So, cant use or comment on something I do not know about. Apparently it is a secret?

 

If you are referring to quadrature encoder inputs then no, it is not a secret. It is described in the STM32 datasheet, in fact many [modern] microcontrollers have such interface. For STM32F4 there is firmware with QuadratureEncoder class by NicolasG (for FEZ Cerberus, but it should not require too much work to port it over to Netduino gen 2).






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.