Skip to main content

Position Types

Position variable types for storing and controlling multi-axis motion positions.

Namespace: ControlBee.Variables

Overview

Position types represent multi-dimensional motion coordinates that are mapped to physical motion axes. They provide:

  • Axis-mapped Storage - Positions are automatically linked to motion axes
  • Motion Control - Built-in methods for moving axes to stored positions
  • Position Teaching - Capture current axis positions
  • Change Tracking - Notifications when position values change
  • Index Access - Direct access to individual axis values

ControlBee provides four position types:

  • Position1D - Single-axis position (1 value)
  • Position2D - Two-axis position (2 values)
  • Position3D - Three-axis position (3 values)
  • Position4D - Four-axis position (4 values)

Choosing Position Type

Select the position type based on the number of axes to control:

public class MyActor : Actor
{
// Single axis (X only)
public Variable<Position1D> LoadPosX = new(VariableScope.Local);
public IAxis X;

// Two axes (X, Y)
public Variable<Position2D> ScanPosXY = new(VariableScope.Local);
public IAxis X, Y;

// Three axes (X, Y, Z)
public Variable<Position3D> PickPosXYZ = new(VariableScope.Local);
public IAxis X, Y, Z;

// Four axes (X, Y, Z, R)
public Variable<Position4D> AlignPosXYZR = new(VariableScope.Local);
public IAxis X, Y, Z, R;

public MyActor(ActorConfig config) : base(config)
{
X = config.AxisFactory.Create();
Y = config.AxisFactory.Create();
Z = config.AxisFactory.Create();
R = config.AxisFactory.Create();

// Map positions to axes (in order!)
PositionAxesMap.Add(LoadPosX, [X]);
PositionAxesMap.Add(ScanPosXY, [X, Y]);
PositionAxesMap.Add(PickPosXYZ, [X, Y, Z]);
PositionAxesMap.Add(AlignPosXYZR, [X, Y, Z, R]);
}
}

Properties

Values

public double[] Values { get; set; }

Array of position values for all axes.

Usage Example:

// Get all values
double[] values = pickPos.Value.Values; // [100.5, 200.3, 50.0]

// Set all values at once
pickPos.Value.Values = new double[] { 150.0, 250.0, 75.0 };

Indexer

public double this[int i] { get; set; }

Access individual axis values by index.

Usage Example:

// Get individual values
double x = pickPos.Value[0];
double y = pickPos.Value[1];
double z = pickPos.Value[2];

// Set individual values
pickPos.Value[0] = 100.0; // X position
pickPos.Value[1] = 200.0; // Y position
pickPos.Value[2] = 50.0; // Z position

Axes

public IAxis[] Axes { get; }

Array of axes mapped to this position. Automatically retrieved from PositionAxesMap.

Usage Example:

// Check which axes are mapped
foreach (var axis in pickPos.Value.Axes)
{
Console.WriteLine($"Axis position: {axis.ActualPosition}");
Console.WriteLine($"Axis moving: {axis.IsMoving}");
}

Size

public int Size { get; }

Number of axes/dimensions in this position.

Usage Example:

var size = pickPos.Value.Size;  // 3 for Position3D

Motion Methods

Move

public void Move()
public void Move(bool override)
public void Move(IAxis[] axes)
public void Move(IAxis[] axes, bool override)

Commands axes to move to the stored position.

Parameters:

  • override — If true, bypasses safety checks and moves directly
  • axes — Specific subset of axes to move

Usage Example:

// Move all mapped axes to stored position
pickPos.Value.Move();

// Move with override (skip safety checks)
pickPos.Value.Move(override: true);

// Move only X and Y axes
pickPos.Value.Move([X, Y]);

Wait

public void Wait()
public void Wait(IAxis[] axes)

Waits for all (or specified) axes to complete their motion.

Usage Example:

// Wait for all axes
pickPos.Value.Wait();

// Wait for specific axes
pickPos.Value.Wait([X, Y]);

MoveAndWait

public void MoveAndWait()
public void MoveAndWait(IAxis[] axes)

Commands motion and waits for completion.

Usage Example:

// Move all axes and wait
pickPos.Value.MoveAndWait();

// Move specific axes and wait
pickPos.Value.MoveAndWait([X, Z]);

Stop

public void Stop()

Immediately stops all mapped axes.

Usage Example:

// Emergency stop
pickPos.Value.Stop();

Position Teaching

SetPos (TeachCurrent)

public void SetPos()

Teaches the current position by reading all mapped axes.

Usage Example:

[Function]
public void TeachPickPos()
{
// Read current axis positions into variable
PickPos.Value.SetPos();
Console.WriteLine($"Taught position: X={PickPos.Value[0]}, Y={PickPos.Value[1]}, Z={PickPos.Value[2]}");
}

MoveToSavedPos

public void MoveToSavedPos(ActorItemMessage? message = null)

Moves to the saved position with optional custom speed profiles.

Usage Example:

// Move with default speed
PickPos.Value.MoveToSavedPos();

// Move with custom speeds
var message = new ActorItemMessage(this, "PickPos", "MoveToSavedPos", new Dict
{
["Speed"] = new double[] { 100.0, 120.0, 80.0 } // Custom speeds for each axis
});
PickPos.Value.MoveToSavedPos(message);

MoveToHomePos

public void MoveToHomePos()

Moves all axes to their home positions (in reverse order for safety).

Usage Example:

[Function]
public void GoHome()
{
PickPos.Value.MoveToHomePos();
}

Position Comparison

IsNear

public bool IsNear(double range)

Checks if all axes are within the specified range of their target positions.

Usage Example:

// Check if within 0.1mm of target
if (pickPos.Value.IsNear(0.1))
{
Console.WriteLine("Position reached");
}

WaitForPosition

public void WaitForPosition(PositionComparisonType type)

Waits until all axes reach their target positions according to the comparison type.

Usage Example:

pickPos.Value.Move();
pickPos.Value.WaitForPosition(PositionComparisonType.InPosition);

Change Notifications

Position types implement INotifyValueChanged for tracking changes:

public event EventHandler<ValueChangedArgs>? ValueChanged;
public event EventHandler<ValueChangedArgs>? ValueChanging;

Usage Example:

public MyActor(ActorConfig config) : base(config)
{
// ...

PickPos.ValueChanged += (s, e) =>
{
Console.WriteLine($"Position changed: {PickPos.Value[0]}, {PickPos.Value[1]}, {PickPos.Value[2]}");
};
}

Usage Patterns

1. Basic Position Teaching and Motion

public class StageActor : Actor
{
public Variable<Position3D> LoadPos = new(VariableScope.Local);
public Variable<Position3D> UnloadPos = new(VariableScope.Local);

public IAxis X, Y, Z;

public StageActor(ActorConfig config) : base(config)
{
X = config.AxisFactory.Create();
Y = config.AxisFactory.Create();
Z = config.AxisFactory.Create();

PositionAxesMap.Add(LoadPos, [X, Y, Z]);
PositionAxesMap.Add(UnloadPos, [X, Y, Z]);
}

[Function]
public void TeachLoadPosition()
{
LoadPos.Value.SetPos();
}

[Function]
public void TeachUnloadPosition()
{
UnloadPos.Value.SetPos();
}

public void TransferMaterial()
{
// Move to load position
LoadPos.Value.MoveAndWait();
PickUpMaterial();

// Move to unload position
UnloadPos.Value.MoveAndWait();
PlaceMaterial();
}
}

2. Sequential Motion with Verification

public void PickSequence()
{
// Move Z up to safe height
SafeHeightPos.Value.MoveAndWait([Z]);

// Move XY to position
PickPos.Value.MoveAndWait([X, Y]);

// Lower Z to pick height
PickPos.Value.MoveAndWait([Z]);

// Verify position
if (!PickPos.Value.IsNear(0.1))
{
throw new Exception("Position error");
}

// Pick operation
Vacuum.TurnOn();
Thread.Sleep(500);

// Raise Z
SafeHeightPos.Value.MoveAndWait([Z]);
}

3. Position Offset

public void PickWithOffset(double xOffset, double yOffset)
{
// Clone and modify position
var offsetPos = (Position3D)PickPos.Value.Clone();
offsetPos[0] += xOffset; // Add X offset
offsetPos[1] += yOffset; // Add Y offset

// Move to offset position
offsetPos.MoveAndWait();
}

4. Grid Position Calculation

public class TrayActor : Actor
{
public Variable<Position3D> GridStartPos = new(VariableScope.Local);
public Variable<double> GridSpacingX = new(VariableScope.Local, 10.0);
public Variable<double> GridSpacingY = new(VariableScope.Local, 10.0);

public void MoveToGridCell(int row, int col)
{
var pos = (Position3D)GridStartPos.Value.Clone();
pos[0] += col * GridSpacingX.Value; // X offset
pos[1] += row * GridSpacingY.Value; // Y offset

pos.MoveAndWait();
}
}

Best Practices

1. Always Map Positions in Constructor

// ✅ Good
public MyActor(ActorConfig config) : base(config)
{
X = config.AxisFactory.Create();
PositionAxesMap.Add(LoadPos, [X]);
}

// ❌ Bad - Mapping missing
public MyActor(ActorConfig config) : base(config)
{
X = config.AxisFactory.Create();
// Forgot to add mapping - will throw exception!
}

2. Use Correct Axis Order

// ✅ Good - Correct order
PositionAxesMap.Add(PickPos, [X, Y, Z]);

// ❌ Bad - Wrong order
PositionAxesMap.Add(PickPos, [Z, Y, X]); // Will move to wrong positions!

3. Check Position Before Critical Operations

// ✅ Good - Verify position
PickPos.Value.MoveAndWait();
if (!PickPos.Value.IsNear(0.1))
{
throw new Exception("Position error - cannot pick");
}
PickMaterial();

// ❌ Bad - No verification
PickPos.Value.MoveAndWait();
PickMaterial(); // May pick from wrong position!

4. Use Sequential Motion for Safety

// ✅ Good - Safe Z-up first
SafeHeightPos.Value.MoveAndWait([Z]);
PickPos.Value.MoveAndWait([X, Y]);
PickPos.Value.MoveAndWait([Z]);

// ❌ Bad - May collide
PickPos.Value.MoveAndWait(); // All axes move at once!

See Also