Skip to content

Streaming vs Command-Based Communication

This topic sits inside the industrial communication area of your roadmap, especially where systems exchange commands, status, events, measurements, and production information across machine boundaries.


PART 1 — WHY THIS DISTINCTION EXISTS

Industrial systems do not communicate in only one way.

They usually have two very different communication needs:

text
1. Discrete action:
   "Move axis X to position 120.5 mm"

2. Continuous data:
   "Camera is producing images at 60 FPS"
   "Sensor is producing position feedback every 2 ms"

These two cases behave very differently.

A command has a clear intention:

text
Do this operation.
Tell me whether it started, completed, failed, or timed out.

A stream is different:

text
Data keeps arriving over time.
The system must consume, buffer, process, drop, or persist it safely.

The biggest mistake is treating streams like repeated commands.

For example:

text
Bad mental model:

Camera frame 1  -> request/response
Camera frame 2  -> request/response
Camera frame 3  -> request/response
Camera frame 4  -> request/response
...

That design quickly becomes overloaded because streaming data is often high-frequency, high-volume, and potentially endless.

A better mental model is:

text
Command path controls behavior.
Streaming path moves data continuously.

In machine software, this difference matters because the system interacts with physical devices, long-running asynchronous operations, and timing-sensitive behavior. This is also consistent with the machine-control principle that physical actions are not just simple method calls; they must be state-driven, validated, and safely coordinated.


PART 2 — COMMAND-BASED COMMUNICATION

Command-based communication is used when one component asks another component to perform a specific action or return a specific piece of information.

Examples:

text
Move axis to position
Read current device status
Trigger autofocus
Open vacuum valve
Start inspection
Stop conveyor
Reset alarm

A command usually has:

text
clear intent
clear start
clear expected completion
clear success/failure result
timeout behavior
state validation

A typical command flow looks like this:

text
+----------------+          +------------------+          +----------------+
| Workflow       |          | Device Service   |          | Motion/Device  |
+----------------+          +------------------+          +----------------+
        |                            |                            |
        | MoveAxis(X, 120.5)         |                            |
        |--------------------------->|                            |
        |                            | Validate state/limits       |
        |                            |--------------------------->|
        |                            | Send command to device      |
        |                            |--------------------------->|
        |                            |                            |
        |                            | Wait for completion/fault   |
        |                            |<---------------------------|
        | Move completed / failed    |                            |
        |<---------------------------|                            |
        |                            |                            |

The important point is that the command represents an operation.

It is not just “send bytes and get bytes.” From a software architecture perspective, it represents a controlled state transition:

text
Idle -> Moving -> InPosition
Idle -> Moving -> Faulted
Idle -> CommandRejected
Moving -> Timeout

A strong design does not only ask:

text
Did the method return?

It asks:

text
Was the command accepted?
Did the physical action start?
Did it complete?
Was completion confirmed?
Did the state remain consistent?
What happens if it times out?

This is why command communication in industrial systems is often tied to state machines, workflow orchestration, alarms, interlocks, and recovery logic.


PART 3 — STREAMING COMMUNICATION

Streaming communication is used when data flows continuously over time.

Examples:

text
Camera image stream
Sensor telemetry
Position feedback
Vibration data
Temperature samples
Inspection result stream
Live defect overlay data

A stream does not usually work like:

text
Give me item 1.
Give me item 2.
Give me item 3.

Instead, the producer keeps producing data:

text
Here is frame 1.
Here is frame 2.
Here is frame 3.
Here is frame 4.
...

A streaming pipeline often looks like this:

text
+----------+     +----------+     +-------------+     +-------------+     +------+
| Camera   | --> | Buffer   | --> | Processing  | --> | Result Bus  | --> | UI   |
+----------+     +----------+     +-------------+     +-------------+     +------+
     |                |                |                   |                  |
     | frames         | queue/ring     | inspect/analyze   | defects/status   |
     | timestamps     | capacity       | CPU/GPU work      | publish          |
     | metadata       | drop policy    | latency budget    | display          |

The stream has different architectural concerns from commands:

text
How fast is data produced?
How fast can consumers process it?
What happens if consumers fall behind?
How much buffering is allowed?
Can old data be dropped?
Is every item critical?
How is the stream started and stopped?
How is data correlated with machine state?

In a vision machine, image streaming is a major example. The roadmap explicitly calls out frame grabbers, triggered image capture, image buffering, streaming, throughput trade-offs, and integration with machine motion as important concepts in inspection systems.


PART 4 — KEY DIFFERENCES

text
+----------------------+-----------------------------+------------------------------+
| Dimension            | Command-Based               | Streaming                    |
+----------------------+-----------------------------+------------------------------+
| Main purpose         | Control action              | Continuous data movement     |
| Shape                | Discrete                    | Continuous                   |
| Lifetime             | Has start/end               | May run indefinitely         |
| Volume               | Usually low/medium          | Often high                   |
| Result               | Success/failure/status      | Sequence of data items       |
| Timing concern       | Timeout/completion          | Throughput/latency/jitter    |
| Resource concern     | Pending operations          | Buffers, queues, memory      |
| Failure handling     | Retry, reject, abort        | Drop, pause, reconnect, drain|
| Example              | Move axis                   | Camera frames                |
+----------------------+-----------------------------+------------------------------+

Another way to see it:

text
Command communication:

+----------+        command         +----------+
| Caller   | ---------------------> | Device   |
|          | <--------------------- |          |
+----------+        response        +----------+


Streaming communication:

+----------+      data data data data data      +----------+
| Producer | =================================> | Consumer |
+----------+                                    +----------+

Commands are about control flow.

Streams are about data flow.

That sentence is very important.

In industrial systems, control flow and data flow often interact, but they should not be confused.


PART 5 — BACKPRESSURE & FLOW CONTROL

Backpressure means:

text
The producer is generating data faster than the consumer can process it.

This is common in streaming systems.

Example:

text
Camera produces 100 images/second.
Image processing can handle 60 images/second.
UI can display only 30 images/second.
Storage can persist only 50 images/second.

If the design has no backpressure strategy, queues grow:

text
+--------+       +---------------------------+       +------------+
| Camera | ----> | Frame Queue               | ----> | Processor  |
+--------+       | grows... grows... grows...|       +------------+
                 +---------------------------+
                              |
                              v
                       memory pressure
                       GC pressure
                       latency increase
                       eventual crash

A streaming system needs an explicit policy:

text
buffer temporarily
drop old data
drop new data
sample data
slow the producer
split critical and non-critical streams
write to disk asynchronously
stop acquisition safely

For example, live UI display may drop old frames:

text
If UI is slow, show latest frame only.
Do not queue 10,000 old frames.

But inspection data may not be droppable:

text
If every wafer image is required for quality decision,
the system must slow acquisition, increase capacity, or fail the run safely.

Command-based systems rarely face the same kind of backpressure because commands are usually bounded. You may have command queue overload, but that is usually a design smell: machine commands should often be serialized, validated, and controlled.

You usually do not want this:

text
Move X
Move X
Move X
Move X
Move X
Move X

queued blindly.

A command path should usually reject or coordinate conflicting commands rather than buffering unlimited intent.


PART 6 — COMBINING STREAMING & COMMAND MODELS

Real machines use both models together.

Example:

text
Command: start acquisition
Stream: receive images
Command: stop acquisition

A combined flow:

text
+-----------+        +----------------+        +-------------+        +-----------+
| Workflow  |        | Camera Service |        | Camera HW   |        | Pipeline  |
+-----------+        +----------------+        +-------------+        +-----------+
     |                       |                       |                       |
     | StartAcquisition      |                       |                       |
     |---------------------->|                       |                       |
     |                       | Configure/arm camera  |                       |
     |                       |---------------------->|                       |
     |                       | Acquisition started   |                       |
     |                       |<----------------------|                       |
     | Started               |                       |                       |
     |<----------------------|                       |                       |
     |                       |                       | Frame 1               |
     |                       |<======================|======================>|
     |                       |                       | Frame 2               |
     |                       |<======================|======================>|
     |                       |                       | Frame 3               |
     |                       |<======================|======================>|
     | StopAcquisition       |                       |                       |
     |---------------------->|                       |                       |
     |                       | Stop camera           |                       |
     |                       |---------------------->|                       |
     |                       | Drain/complete stream |                       |
     |                       |----------------------------------------------->|
     | Stopped               |                       |                       |
     |<----------------------|                       |                       |

The hard part is not the command itself.

The hard part is coordinating command state with stream lifecycle:

text
Was the stream really started?
Are frames from the old run or the new run?
When stop is requested, do we discard pending frames or process them?
Can the pipeline finish cleanly?
What happens if the camera continues sending frames after stop?
What happens if stop occurs while processing is behind?

This is where many real bugs happen.

A good design gives the stream a lifecycle:

text
NotConfigured
Configured
Starting
Streaming
Stopping
Draining
Stopped
Faulted

The command path controls lifecycle transitions.

The streaming path moves data only when lifecycle permits it.


PART 7 — REAL-WORLD FAILURE SCENARIOS

1. Treating streaming as command calls

What it looks like:

text
Each frame is handled like an independent request.
Each frame triggers synchronous processing.
The system waits too much.
Throughput collapses.

Why it happens:

text
Engineers apply request/response thinking to high-frequency data.

How to fix it:

text
Use a streaming pipeline.
Use bounded queues.
Separate acquisition, processing, storage, and UI.
Avoid blocking the producer path.

2. Buffer grows without limit

What it looks like:

text
Machine works for 10 minutes.
Then memory grows.
Then UI becomes slow.
Then GC spikes.
Then acquisition becomes unstable.
Eventually the app crashes.

Why it happens:

text
Producer is faster than consumer.
Queue has no capacity limit.
No drop/slow/fail policy exists.

How to fix it:

text
Use bounded buffers.
Measure queue depth.
Define overflow policy.
Apply backpressure.
Fail safely if critical data cannot be processed.

3. Dropping data incorrectly

What it looks like:

text
Live display looks fine.
But inspection result is missing frames.
Defect count is wrong.
Traceability record is incomplete.

Why it happens:

text
The system uses the same drop policy for all data.
It treats critical inspection data like preview UI frames.

How to fix it:

text
Classify streams by criticality.

Preview frames:
  may drop old frames.

Inspection frames:
  usually must be processed, persisted, or explicitly marked failed.

Telemetry:
  may aggregate or sample depending on purpose.

4. Command issued without considering streaming state

What it looks like:

text
Operator clicks Stop.
Motion stops.
But processing continues using old frames.
UI still shows new results.
Workflow thinks run is complete while pipeline is still active.

Why it happens:

text
Command lifecycle and stream lifecycle are not coordinated.

How to fix it:

text
Stop command must coordinate:
- stop producer
- mark stream closing
- drain or discard remaining data according to policy
- complete pipeline
- publish final state

5. Stream continues after system expects it to stop

What it looks like:

text
Acquisition stopped.
New run starts.
Frames from previous run appear in current run.
Results are associated with the wrong wafer or product.

Why it happens:

text
No run/session identity is attached to stream data.
Old data is not rejected.
Pipeline completion is not awaited.

How to fix it:

text
Attach session/run IDs to frames.
Reject frames from inactive sessions.
Complete old pipeline before starting new one.
Make stream ownership explicit.

PART 8 — SOFTWARE DESIGN IMPLICATIONS

The main design rule is:

text
Do not force one communication model to handle every problem.

Bad design:

text
+-------------------+
| One Device Service |
+-------------------+
| MoveAxis()         |
| ReadStatus()       |
| GetNextFrame()     |
| ProcessFrame()     |
| SaveResult()       |
| StopEverything()   |
+-------------------+

This mixes command handling, streaming, processing, lifecycle, and storage into one component.

A better design separates responsibilities:

text
+-------------------+        +----------------------+
| Workflow/Orchestr. | -----> | Command Services     |
+-------------------+        +----------------------+
        |                    | MoveAxis             |
        |                    | StartAcquisition     |
        |                    | StopAcquisition      |
        |                    +----------------------+
        |
        v
+-------------------+        +----------------------+        +----------------+
| Stream Lifecycle  | -----> | Acquisition Pipeline | -----> | Consumers      |
+-------------------+        +----------------------+        +----------------+
| session id        |        | bounded buffers      |        | inspection     |
| start/stop state  |        | backpressure policy  |        | storage        |
| ownership         |        | completion handling  |        | UI preview     |
+-------------------+        +----------------------+        +----------------+

This separation gives you:

text
clear command semantics
controlled streaming lifecycle
bounded resource usage
better diagnostics
safer stop/start behavior
cleaner recovery

In .NET terms, the command side may look like application services and workflow state machines.

The streaming side often uses producer-consumer patterns, bounded channels, queues, pipelines, cancellation tokens, and explicit completion signals.

But the important architectural idea is not the specific .NET API.

The important idea is:

text
Commands change machine intent and state.
Streams carry continuous data produced by that state.

PART 9 — INTERVIEW / REAL-WORLD TALKING POINTS

A strong explanation:

text
In industrial systems, command-based communication is used for discrete control actions such as moving an axis, starting acquisition, or reading status. It has clear intent, validation, timeout, completion, and failure semantics.

Streaming communication is used for continuous data such as camera frames, sensor telemetry, or position feedback. It is not naturally bounded, so the design must handle throughput, buffering, backpressure, data loss policy, and lifecycle.

The mistake is treating streaming data as many small commands. That causes blocking, queue growth, latency, memory pressure, and sometimes incorrect machine behavior.

A good architecture separates the command path from the streaming path. Commands control lifecycle and state. Streams move data through bounded pipelines with explicit backpressure and completion behavior.

When to use command-based communication:

text
Use it when you need to request a specific action or state change:
- move axis
- start operation
- stop operation
- reset fault
- read status
- apply recipe

When to use streaming communication:

text
Use it when data arrives continuously or at high frequency:
- camera frames
- sensor readings
- encoder feedback
- live inspection results
- telemetry

Common mistakes:

text
Treating every frame as a request/response call
Using unbounded queues
Ignoring stream lifecycle
Dropping critical data silently
Blocking acquisition while doing slow processing
Letting UI consume raw high-rate streams directly
Starting a new run before the old stream is fully stopped
Not tagging stream data with session/run identity

What strong engineers understand:

text
Commands are about control flow.
Streams are about data flow.

Commands need correctness, validation, timeout, and state transition handling.
Streams need throughput control, buffering policy, backpressure, and lifecycle management.

Real industrial systems need both, but they must be designed as separate paths that coordinate through explicit state.

Docs-first project memory for AI-assisted implementation.