I have a test fixture with a number of communication/data acquisition devices on it that is used as an end of line test for a product.

Because of all the various sensors used in the bench and the need to run the test procedure in near real-time, I'm having a hard time structuring the program to be more friendly to modify later on. For example, a National Instruments USB data acquisition device is used to control an analog output (load) and monitor an analog input (current), a digital scale with a serial data interface measures position, an air pressure gauge with a different serial data interface, and the product is interfaced through a proprietary DLL that handles its own serial communication.

The hard part

The "real-time" aspect of the program is my biggest tripping point. For example, I need to time how long the product needs to go from position 0 to position 10,000 to the tenth of a second. While it's traveling, I need to ramp up an output of the NI DAQ when it reaches position 6,000 and ramp it down when it reaches position 8,000. This sort of control looks easy from browsing NI's LabVIEW docs but I'm stuck with C# for now. All external communication is done by polling which makes for lots of annoying loops.

I've slapped together a loose Producer Consumer model where the Producer thread loops through reading the sensors and sets the outputs. The Consumer thread executes functions containing timed loops that poll the Producer for current data and execute movement commands as required. The UI thread polls both threads for updating some gauges indicating current test progress.

Unsure where to start

Is there a more appropriate pattern for this type of application?

Are there any good resources for writing control loops in software (non-LabVIEW) that interface with external sensors and whatnot?


This is a good question that relies heavily on context. My approach will be to describe the patterns available for your review. The following is a high-level overview.

I'm looking in the pinnacle book Design Patterns - Elements of Reusable Object-Oriented Software, by Gamma, Helm, Johnson, and Vlissides. It is written for C++ but would be largely applicable in C#.

  1. Anti-Pattern. One down-side to design patterns is the potential to apply them just for the sake of doing so. It is important to realize that these patterns solve specific problems, and should not be implemented unless that problem exists. Doing so would be an anti-pattern.

  2. Facade. 'Provide a unified interface to a set of interfaces in a subsystem.' This sounds potentially useful for you to group all of your disparate Objects into a single interface. This will simplify your ability to access them should they all be grouped into a 'Singleton' called, something like, Sensors or Consumers.

  3. Singleton. Guarantee a single instance of an object. This may be helpful in collaboration with other patterns. This can be commonly used as Manager object, or a Proxy, for example.

  4. Proxy. 'Provide a surrogate placeholder to control access.' This may be helpful to review to abstract your connection points.

  5. Chain of Responsibility, Observer, Publisher Subscriber. These are the notion of decoupling interface dependencies. One of these may be helpful for you between your Producer Consumer so that your producer is not hung up waiting for a consumer to run, or respond. Instead what can happen is the events allow a separation between the two.

  6. Strategy. 'A family of algorithms, encapsulate each one, and make them interchangable.' This may be helpful for you if you have different behaviors that need to change dynamically for different states.

  7. Iterator. This may provide some optimization for your accumulation of loops.

Again, this is a high level overview. I am certain that some of these will not be a good fit for your implementation, but reviewing them can give a good idea of what optimization's are available.

Lastly, keep in mind that these patterns are best applied at Design Time. If you have a rather robust legacy implementation a high level of complex refactoring would be a reasonable expectation.

Also take a look around for C# specific patterns. Often times the original patterns posed above morph as they transcend languages. They may be essentially the same pattern, but with different implementation specific requirements, they can change names. Like PubSub/Observer.

Hope that helps. All the best! Nash


You have got the hardware that you have got. However... Windows OS wasn't designed for precision timing, as you probably know. The peripheral controllers (in the data acquisition devices) can usually do timing a lot better than Windows.

Ideally, the peripheral controller would have a functionality where it can receive a list of commands, which it would time and execute. Essentially, you would have real-time thread running on a dedicated controller.

Distributed control.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.