UnderAutomation
Eine Frage?

[email protected]

Kontakt
UnderAutomation
⌘Q
Fanuc SDK documentation
Frames, I/O & status
Documentation home

Stream Motion (J519)

Stream Motion is Fanuc's real-time streaming motion control interface over UDP. Send continuous motion commands at 125Hz or 250Hz for smooth, coordinated motion.

Stream Motion is Fanuc's real-time streaming motion control interface, available as the J519 paid option on compatible controllers. It enables external applications to send continuous motion commands to the robot at high frequency (125Hz or 250Hz), making it ideal for applications requiring smooth, coordinated motion such as:

  • Force control and adaptive machining
  • Sensor-guided motion
  • Real-time trajectory generation
  • Human-robot collaboration
  • Custom motion planning algorithms

Requirements

Controller Requirements

  • Fanuc controller with J519 Stream Motion option installed
  • Compatible robot model (not all models support Stream Motion - verify with Fanuc)
  • Network connectivity (UDP port 60015 by default)

Key Limitations

FeatureLimitation
Motion groupsGroup 1 (robot) + up to 3 auxiliary axes
Coordinate modeJoint OR Cartesian (cannot switch mid-session)
Update rate125Hz or 250Hz (controller dependent)
Control typePosition only (no velocity/torque control)

Quick Start

var robot = new FanucRobot();
var parameters = new ConnectionParameters("192.168.1.1");
parameters.StreamMotion.Enable = true;
robot.Connect(parameters);
float nextJ1 = 10, nextJ2 = 20, nextJ3 = 30, nextJ4 = 0, nextJ5 = -45, nextJ6 = 90;
robot.StreamMotion.StateReceived += (sender, e) =>
{
var state = e.State;
Console.WriteLine($"Position: J1={state.JointPosition.J1:F2}°");
if (state.Status.ReadyForCommands &&
!state.Status.InMotion &&
!state.Status.CommandReceived)
{
var command = new CommandPacket
{
DataStyle = DataStyle.Joint,
MotionData = new MotionData
{
J1 = nextJ1,
J2 = nextJ2,
J3 = nextJ3,
J4 = nextJ4,
J5 = nextJ5,
J6 = nextJ6
}
};
robot.StreamMotion.SendCommand(command);
}
};
robot.StreamMotion.Start();
// ... your application logic ...
robot.StreamMotion.Stop();

Architecture Overview

Stream Motion uses a UDP-based protocol with the following communication pattern:

┌─────────────────┐                      ┌─────────────────┐
│   Your App      │                      │   Fanuc Robot   │
│                 │                      │                 │
│  ┌───────────┐  │     Start Packet     │  ┌───────────┐  │
│  │  Stream   │──┼────────────────────> |  │  Stream   │  │
│  │  Motion   │  │                      │  │  Motion   │  │
│  │  Client   │<─┼──────────────────────┼──│  Server   │  │
│  └───────────┘  │   State Packets      │  └───────────┘  │
│       │         │   (~500Hz)           │       ▲         │
│       │         │                      │       │         │
│       └─────────┼──────────────────────┼───────┘         │
│                 │   Command Packets    │                 │
│                 │   (125/250Hz)        │                 │
└─────────────────┘                      └─────────────────┘

Communication Flow

  1. Connect - Establish UDP socket connection
  2. Start - Send start packet to begin streaming session
  3. Receive States - Robot sends state packets at ~500Hz
  4. Send Commands - Your app sends interpolated positions at 125/250Hz
  5. Stop - Send stop packet to end session
  6. Disconnect - Close socket

Robot Program Setup

A TP (Teach Pendant) program must be running on the robot to handle Stream Motion commands.

Required TP Program

Create a program named for instance START_STREAM_MOTION_J519.ls with this content:

/PROG START_STREAM_MOTION_J519
/ATTR
OWNER = MNEDITOR;
PROTECT = READ_WRITE;
TCD: STACK_SIZE = 0,
TASK_PRIORITY = 50,
TIME_SLICE = 0,
BUSY_LAMP_OFF = 0,
ABORT_REQUEST = 0,
PAUSE_REQUEST = 0;
DEFAULT_GROUP = 1,*,*,*,*;
CONTROL_CODE = 00000000 00000000;
/MN
1: LBL[1] ;
2: IBGN start[1] ;
3: IBGN end[1] ;
4: JMP LBL[1] ;
/POS
/END

Program Explanation

LineInstructionDescription
1LBL[1]Loop label
2IBGN start[1]Start Stream Motion session
3IBGN end[1]End Stream Motion session
4JMP LBL[1]Loop back to handle next session

Running the Program

  1. Upload the program to the robot via FTP or teach pendant
  2. Start the program in AUTO mode
  3. The program loops, waiting for Stream Motion connections
  4. Your application connects and controls motion via UDP
  5. When streaming stops, the program loops back to wait for the next connection

Adding Custom Logic

You can add instructions outside the Stream Motion block:

/MN
1: LBL[1] ;
2: DO[1]=ON ; // Turn on output before streaming
3: IBGN start[1] ;
4: IBGN end[1] ;
5: DO[1]=OFF ; // Turn off output after streaming
6: WAIT 1.00(sec) ; // Wait before next session
7: JMP LBL[1] ;
/POS
/END

Connection and Streaming

Connecting to the Robot

var robot = new FanucRobot();
// Connect with default settings (port 60015)
var parameters = new ConnectionParameters("192.168.1.1");
parameters.StreamMotion.Enable = true;
robot.Connect(parameters);
// Standalone client
var client = new StreamMotionClient();
client.Connect("192.168.1.1");
// Start / stop streaming
robot.StreamMotion.Start();
Console.WriteLine($"Streaming: {robot.StreamMotion.IsStreaming}");
Console.WriteLine($"Frequency: {robot.StreamMotion.MeasuredFrequency:F1} Hz");
robot.StreamMotion.Stop();
robot.StreamMotion.Disconnect();

Standalone Client

You can also use the StreamMotionClient class directly without FanucRobot.

Starting and Stopping Streaming


State Packets

The robot sends state packets continuously at approximately 500Hz. Each packet contains the robot's current state.

StatePacket Properties

PropertyTypeDescription
SequenceNumberuintPacket sequence for synchronization
TimeStampuintRobot timestamp (ms, 2ms resolution)
StatusRobotStatusStatus flags
JointPositionMotionDataCurrent joint positions (J1-J9)
CartesianPositionMotionDataCurrent Cartesian position (X,Y,Z,W,P,R + E1-E3)
MotorCurrentsMotionDataMotor currents in Amperes
IOReadIOReadResultResult of I/O read operation

RobotStatus Flags

FlagDescription
ReadyForCommandsRobot is ready to receive command packets
CommandReceivedRobot has received and is processing a command
SystemReadySystem ready (SYSRDY)
InMotionRobot is currently executing motion

Handling State Packets

robot.StreamMotion.StateReceived += (sender, e) =>
{
var state = e.State;
// Read current joint positions
Console.WriteLine($"J1: {state.JointPosition.J1:F3}°");
Console.WriteLine($"J2: {state.JointPosition.J2:F3}°");
// Read Cartesian position
Console.WriteLine($"X: {state.CartesianPosition.X:F2} mm");
Console.WriteLine($"Y: {state.CartesianPosition.Y:F2} mm");
// Check status
Console.WriteLine($"Ready: {state.Status.ReadyForCommands}");
Console.WriteLine($"In Motion: {state.Status.InMotion}");
// Read motor currents
Console.WriteLine($"Motor 1: {state.MotorCurrents.Axis1:F2} A");
// Only send command when ready
bool canSend = state.Status.ReadyForCommands &&
!state.Status.CommandReceived &&
!state.Status.InMotion;
};

Command Packets

Command packets are sent to instruct the robot to move to a new position.

CommandPacket Properties

PropertyTypeDescription
DataStyleDataStyleJoint or Cartesian
MotionDataMotionDataTarget position
IsLastDataboolMarks end of motion sequence
ReadIOTypeIOTypeType of I/O to read
ReadIOIndexushortI/O index to read
ReadIOMaskushortI/O read mask
WriteIOTypeIOTypeType of I/O to write
WriteIOIndexushortI/O index to write
WriteIOMaskushortI/O write mask
WriteIOValueushortValue to write

MotionData Structure

MotionData holds 9 axis values that can be accessed by axis number or name.

Sending Commands

// MotionData: 9 axis values
var motion = new MotionData();
motion.J1 = 10.0f; motion.J2 = 20.0f; motion.J3 = 30.0f;
motion.J4 = 0.0f; motion.J5 = -45.0f; motion.J6 = 90.0f;
// Cartesian: motion.X, motion.Y, motion.Z, motion.W, motion.P, motion.R
// Full command packet
var command = new CommandPacket
{
DataStyle = DataStyle.Joint,
MotionData = new MotionData { J1 = 10, J2 = 20, J3 = 30, J4 = 0, J5 = -45, J6 = 90 },
IsLastData = false
};
robot.StreamMotion.SendCommand(command);
// Convenience: joint motion
robot.StreamMotion.SendJointCommand(
new MotionData { J1 = 10, J2 = 20, J3 = 30, J4 = 0, J5 = -45, J6 = 90 },
isLastData: false
);
// Convenience: Cartesian motion
robot.StreamMotion.SendCartesianCommand(
new MotionData { X = 500, Y = 100, Z = 300, W = 180, P = 0, R = 0 },
isLastData: false
);

Protocol State Machine

The Stream Motion protocol follows a strict state machine. Understanding this is critical for proper operation.

State Transitions

                    ┌─────────────────────────────────────┐
                    │                                     │
                    ▼                                     │
    ┌───────────────────────────┐                         │
    │     READY FOR COMMANDS    │                         │
    │  ReadyForCommands = true  │                         │
    │  CommandReceived = false  │                         │
    │  InMotion = false         │                         │
    └───────────────────────────┘                         │
                    │                                     │
                    │ Send Command                        │
                    ▼                                     │
    ┌───────────────────────────┐                         │
    │    COMMAND RECEIVED       │                         │
    │  CommandReceived = true   │                         │
    └───────────────────────────┘                         │
                    │                                     │
                    │ Robot starts motion                 │
                    ▼                                     │
    ┌───────────────────────────┐                         │
    │       IN MOTION           │                         │
    │  InMotion = true          │────────────────────────>┤
    │  (may receive multiple    │   Motion complete       │
    │   packets in this state)  │                         │
    └───────────────────────────┘                         │

Correct Command Timing

Only send the next command when ALL these conditions are met:

See the state packet handling above : check ReadyForCommands, CommandReceived, and InMotion flags before sending.

⚠️ Common Mistakes

MistakeConsequence
Sending commands too fastCommands dropped, erratic motion
Ignoring CommandReceivedDuplicate commands sent
Ignoring InMotionBuffer overflow, jerk errors
Not checking ReadyForCommandsCommands rejected

Motion Interpolation

Why Interpolation is Required

Stream Motion operates at 125Hz or 250Hz. Each command should represent a small incremental move. The robot's motion planner expects smooth, continuous position updates that respect:

  • Velocity limits - Maximum speed for each axis
  • Acceleration limits - Maximum rate of velocity change
  • Jerk limits - Maximum rate of acceleration change (smoothness)

Simple Linear Interpolation (Educational Example)

// Simple linear interpolator (educational)
public static float[] LinearInterpolate(float[] start, float[] target, double t)
{
float[] pos = new float[6];
for (int i = 0; i < 6; i++)
pos[i] = start[i] + (float)(t * (target[i] - start[i]));
return pos;
}
// S-curve interpolation (recommended for smooth motion)
public static float[] SCurveInterpolate(float[] start, float[] target, double t)
{
// S-curve: s(t) = 6t^5 - 15t^4 + 10t^3
double s = t * t * t * (t * (t * 6 - 15) + 10);
float[] pos = new float[6];
for (int i = 0; i < 6; i++)
pos[i] = start[i] + (float)(s * (target[i] - start[i]));
return pos;
}

For smooth, jerk-limited motion, use an S-curve or quintic polynomial profile. The snippet above shows both linear and S-curve approaches.

Integration with Stream Motion

Combine the interpolator with the Stream Motion state machine to send smoothly interpolated positions at each cycle.


Querying Axis Limits

Before commanding motion, you can query the robot's axis limits. This must be done before starting streaming.

// Query velocity limits for axis 1
var velocityAck = robot.StreamMotion.RequestThreshold(1, ThresholdType.Velocity);
Console.WriteLine($"Axis 1 max velocity: {velocityAck.ThresholdsNoLoad[19]:F2} deg/s");
// Query acceleration limits
var accelAck = robot.StreamMotion.RequestThreshold(1, ThresholdType.Acceleration);
// Query jerk limits
var jerkAck = robot.StreamMotion.RequestThreshold(1, ThresholdType.Jerk);
// Query all axes
for (uint axis = 1; axis <= 6; axis++)
{
var ack = robot.StreamMotion.RequestThreshold(axis, ThresholdType.Velocity);
Console.WriteLine($"J{axis} max velocity: {ack.ThresholdsNoLoad[19]:F2} deg/s");
}

AckPacket Threshold Arrays

The threshold arrays contain 20 values at different velocity percentages:

IndexVelocity %
05%
110%
......
19100%

Use ThresholdsNoLoad for unloaded robot and ThresholdsMaxLoad for maximum payload.


I/O Operations

Stream Motion supports reading and writing digital I/O during motion.

Reading I/O

var motionData = new MotionData { J1 = 10, J2 = 20, J3 = 30, J4 = 0, J5 = -45, J6 = 90 };
// Read I/O during motion
var readCommand = new CommandPacket
{
DataStyle = DataStyle.Joint,
MotionData = motionData,
ReadIOType = IOType.DI,
ReadIOIndex = 1,
ReadIOMask = 0xFFFF
};
robot.StreamMotion.SendCommand(readCommand);
// Write I/O during motion
var writeCommand = new CommandPacket
{
DataStyle = DataStyle.Joint,
MotionData = motionData,
WriteIOType = IOType.DO,
WriteIOIndex = 1,
WriteIOMask = 0x0001,
WriteIOValue = 0x0001
};
robot.StreamMotion.SendCommand(writeCommand);

Writing I/O


Best Practices

var command = new CommandPacket
{
DataStyle = DataStyle.Joint,
MotionData = new MotionData { J1 = 10, J2 = 20, J3 = 30, J4 = 0, J5 = -45, J6 = 90 }
};
// Always check state before sending
robot.StreamMotion.StateReceived += (s, e) =>
{
if (e.State.Status.ReadyForCommands &&
!e.State.Status.CommandReceived &&
!e.State.Status.InMotion)
{
robot.StreamMotion.SendCommand(command);
}
};
// Handle errors
robot.StreamMotion.ReceiveError += (s, e) =>
{
Console.WriteLine($"Error: {e.Exception.Message}");
};
// Query limits before motion
for (uint i = 1; i <= 6; i++)
{
var ack = robot.StreamMotion.RequestThreshold(i, ThresholdType.Velocity);
}
// Clean shutdown
try { robot.StreamMotion.Start(); }
finally
{
if (robot.StreamMotion.IsStreaming) robot.StreamMotion.Stop();
}

1. Always Implement Proper Interpolation

2. Respect the Protocol State Machine

3. Handle Errors Gracefully

4. Query Limits Before Motion

5. Clean Shutdown


Troubleshooting

Common Errors

ErrorCauseSolution
"Joint jerk limit exceeded"Motion too fast/abruptImplement proper S-curve interpolation
"Robot not ready for commands"Wrong stateWait for ReadyForCommands=true
Connection timeoutNetwork issueCheck IP, port, firewall
"Streaming already started"Double startCheck IsStreaming before Start()
Commands not executedSent too fastFollow protocol state machine

Diagnostic Logging

robot.StreamMotion.StateReceived += (s, e) =>
{
var state = e.State;
Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] " +
$"Seq={state.SequenceNumber} " +
$"Ready={state.Status.ReadyForCommands} " +
$"CmdRcv={state.Status.CommandReceived} " +
$"Motion={state.Status.InMotion} " +
$"J1={state.JointPosition.J1:F3}");
};
Console.WriteLine($"Robot frequency: {robot.StreamMotion.RobotFrequency:F1} Hz");
Console.WriteLine($"Measured frequency: {robot.StreamMotion.MeasuredFrequency:F1} Hz");
Console.WriteLine($"Packets received: {robot.StreamMotion.PacketCount}");

Checking Frequencies


Complete Example

Here's a complete example that moves the robot through a sequence of waypoints:

class StreamMotionExample
{
private FanucRobot _robot;
private float[][] _waypoints;
private int _currentWaypoint;
private bool _waitingForAck;
private readonly object _lock = new object();
public void Run()
{
_robot = new FanucRobot();
// Define waypoints (J1-J6 in degrees)
_waypoints = new float[][]
{
new float[] { 0, 0, 0, 0, 0, 0 },
new float[] { 30, 10, -20, 0, 45, 0 },
new float[] { -30, 20, -40, 90, 0, 45 },
new float[] { 0, 0, 0, 0, 0, 0 }
};
_currentWaypoint = 0;
try
{
// Connect
Console.WriteLine("Connecting to robot...");
var parameters = new ConnectionParameters("192.168.1.1");
parameters.StreamMotion.Enable = true;
_robot.Connect(parameters);
Console.WriteLine("Connected!");
// Query axis limits
for (uint axis = 1; axis <= 6; axis++)
{
var ack = _robot.StreamMotion.RequestThreshold(axis, ThresholdType.Velocity);
Console.WriteLine($" J{axis} max velocity: {ack.ThresholdsNoLoad[19]:F1} deg/s");
}
// Setup event handlers
_robot.StreamMotion.StateReceived += OnStateReceived;
_robot.StreamMotion.ReceiveError += OnReceiveError;
// Start streaming
_robot.StreamMotion.Start();
// Wait for user to stop
Console.WriteLine("Moving through waypoints... Press Enter to stop.");
Console.ReadLine();
}
finally
{
// Clean shutdown
if (_robot.StreamMotion.IsStreaming)
_robot.StreamMotion.Stop();
_robot.StreamMotion.Disconnect();
}
}
private void OnStateReceived(object sender, StateReceivedEventArgs e)
{
lock (_lock)
{
var status = e.State.Status;
if (_waitingForAck)
{
if (!status.InMotion && !status.CommandReceived)
_waitingForAck = false;
else
return;
}
if (!status.ReadyForCommands || status.InMotion || status.CommandReceived)
return;
// Advance to next waypoint
_currentWaypoint = (_currentWaypoint + 1) % _waypoints.Length;
float[] target = _waypoints[_currentWaypoint];
Console.WriteLine($"Moving to waypoint {_currentWaypoint}");
var command = new CommandPacket
{
DataStyle = DataStyle.Joint,
MotionData = new MotionData
{
J1 = target[0],
J2 = target[1],
J3 = target[2],
J4 = target[3],
J5 = target[4],
J6 = target[5]
},
IsLastData = true
};
_robot.StreamMotion.SendCommand(command);
_waitingForAck = true;
}
}
private void OnReceiveError(object sender, ReceiveErrorEventArgs e)
{
Console.WriteLine($"Error: {e.Exception.Message}");
}
static void Main(string[] args)
{
new StreamMotionExample().Run();
}
}

Summary

Stream Motion (J519) provides powerful real-time robot control, but requires careful implementation:

  1. Install J519 option on your controller
  2. Run the TP program with IBGN start[] / IBGN end[]
  3. Implement smooth interpolation - never jump to positions
  4. Follow the protocol state machine - check status before sending
  5. Query and respect axis limits - velocity, acceleration, jerk
  6. Handle errors gracefully - implement reconnection logic

Integrieren Sie Roboter von Universal Robots, Fanuc, Yaskawa, ABB oder Staubli ganz einfach in Ihre .NET-, Python-, LabVIEW- oder Matlab-Anwendungen

UnderAutomation
KontaktLegal

© All rights reserved.