From 1480a7da08fb200d77b5a694ab6b1676db4e74cc Mon Sep 17 00:00:00 2001
From: bruno-f-cruz <7049351+bruno-f-cruz@users.noreply.github.com>
Date: Mon, 4 May 2026 12:36:00 -0700
Subject: [PATCH 1/6] Add animal_offset to manipulator
---
schema/aind_behavior_dynamic_foraging.json | 227 +++++++++---------
.../AindBehaviorDynamicForaging.Generated.cs | 186 +++++++++++++-
src/Extensions/OperationControl.bonsai | 81 ++++++-
src/aind_behavior_dynamic_foraging/rig.py | 12 +-
4 files changed, 390 insertions(+), 116 deletions(-)
diff --git a/schema/aind_behavior_dynamic_foraging.json b/schema/aind_behavior_dynamic_foraging.json
index 21077953..de9b5f21 100644
--- a/schema/aind_behavior_dynamic_foraging.json
+++ b/schema/aind_behavior_dynamic_foraging.json
@@ -107,7 +107,7 @@
]
},
"manipulator": {
- "$ref": "#/$defs/AindManipulator",
+ "$ref": "#/$defs/DynamicForagingAindManipulator",
"description": "Manipulator"
},
"calibration": {
@@ -218,114 +218,6 @@
"title": "AindDynamicForagingTaskParameters",
"type": "object"
},
- "AindManipulator": {
- "description": "AindManipulator device definition",
- "properties": {
- "device_type": {
- "const": "StepperDriver",
- "default": "StepperDriver",
- "title": "Device Type",
- "type": "string"
- },
- "calibration": {
- "$ref": "#/$defs/AindManipulatorCalibration",
- "default": {
- "description": "AindManipulator calibration and settings",
- "full_step_to_mm": {
- "x": 0.01,
- "y1": 0.01,
- "y2": 0.01,
- "z": 0.01
- },
- "axis_configuration": [
- {
- "axis": 2,
- "max_limit": 25.0,
- "maximum_step_interval": 2000,
- "microstep_resolution": 0,
- "min_limit": -0.01,
- "motor_operation_mode": 0,
- "step_acceleration_interval": 100,
- "step_interval": 100
- },
- {
- "axis": 3,
- "max_limit": 25.0,
- "maximum_step_interval": 2000,
- "microstep_resolution": 0,
- "min_limit": -0.01,
- "motor_operation_mode": 0,
- "step_acceleration_interval": 100,
- "step_interval": 100
- },
- {
- "axis": 1,
- "max_limit": 25.0,
- "maximum_step_interval": 2000,
- "microstep_resolution": 0,
- "min_limit": -0.01,
- "motor_operation_mode": 0,
- "step_acceleration_interval": 100,
- "step_interval": 100
- },
- {
- "axis": 4,
- "max_limit": 25.0,
- "maximum_step_interval": 2000,
- "microstep_resolution": 0,
- "min_limit": -0.01,
- "motor_operation_mode": 0,
- "step_acceleration_interval": 100,
- "step_interval": 100
- }
- ],
- "homing_order": [
- 2,
- 3,
- 1,
- 4
- ],
- "initial_position": {
- "x": 0.0,
- "y1": 0.0,
- "y2": 0.0,
- "z": 0.0
- }
- },
- "description": "Calibration for the device."
- },
- "who_am_i": {
- "const": 1130,
- "default": 1130,
- "title": "Who Am I",
- "type": "integer"
- },
- "serial_number": {
- "default": null,
- "description": "Device serial number",
- "oneOf": [
- {
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "title": "Serial Number"
- },
- "port_name": {
- "description": "Device port name",
- "title": "Port Name",
- "type": "string"
- }
- },
- "required": [
- "port_name"
- ],
- "title": "AindManipulator",
- "type": "object",
- "x-sgen-typename": "AllenNeuralDynamics.AindManipulator.AindManipulator"
- },
"AindManipulatorCalibration": {
"description": "AindManipulator calibration class",
"properties": {
@@ -1470,6 +1362,123 @@
"title": "Distribution",
"x-sgen-typename": "AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution"
},
+ "DynamicForagingAindManipulator": {
+ "description": "a calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the animal position relative to the initial position.",
+ "properties": {
+ "device_type": {
+ "const": "StepperDriver",
+ "default": "StepperDriver",
+ "title": "Device Type",
+ "type": "string"
+ },
+ "calibration": {
+ "$ref": "#/$defs/AindManipulatorCalibration",
+ "default": {
+ "description": "AindManipulator calibration and settings",
+ "full_step_to_mm": {
+ "x": 0.01,
+ "y1": 0.01,
+ "y2": 0.01,
+ "z": 0.01
+ },
+ "axis_configuration": [
+ {
+ "axis": 2,
+ "max_limit": 25.0,
+ "maximum_step_interval": 2000,
+ "microstep_resolution": 0,
+ "min_limit": -0.01,
+ "motor_operation_mode": 0,
+ "step_acceleration_interval": 100,
+ "step_interval": 100
+ },
+ {
+ "axis": 3,
+ "max_limit": 25.0,
+ "maximum_step_interval": 2000,
+ "microstep_resolution": 0,
+ "min_limit": -0.01,
+ "motor_operation_mode": 0,
+ "step_acceleration_interval": 100,
+ "step_interval": 100
+ },
+ {
+ "axis": 1,
+ "max_limit": 25.0,
+ "maximum_step_interval": 2000,
+ "microstep_resolution": 0,
+ "min_limit": -0.01,
+ "motor_operation_mode": 0,
+ "step_acceleration_interval": 100,
+ "step_interval": 100
+ },
+ {
+ "axis": 4,
+ "max_limit": 25.0,
+ "maximum_step_interval": 2000,
+ "microstep_resolution": 0,
+ "min_limit": -0.01,
+ "motor_operation_mode": 0,
+ "step_acceleration_interval": 100,
+ "step_interval": 100
+ }
+ ],
+ "homing_order": [
+ 2,
+ 3,
+ 1,
+ 4
+ ],
+ "initial_position": {
+ "x": 0.0,
+ "y1": 0.0,
+ "y2": 0.0,
+ "z": 0.0
+ }
+ },
+ "description": "Calibration for the device."
+ },
+ "who_am_i": {
+ "const": 1130,
+ "default": 1130,
+ "title": "Who Am I",
+ "type": "integer"
+ },
+ "serial_number": {
+ "default": null,
+ "description": "Device serial number",
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "title": "Serial Number"
+ },
+ "port_name": {
+ "description": "Device port name",
+ "title": "Port Name",
+ "type": "string"
+ },
+ "animal_offset": {
+ "$ref": "#/$defs/ManipulatorPosition",
+ "default": {
+ "x": 0.0,
+ "y1": 0.0,
+ "y2": 0.0,
+ "z": 0.0
+ },
+ "description": "Offset of the animal position relative to the `initial_position` parameter"
+ }
+ },
+ "required": [
+ "port_name"
+ ],
+ "title": "DynamicForagingAindManipulator",
+ "type": "object"
+ },
"DynamicForagingSoundCard": {
"description": "A calibrated sound card for the dynamic foraging rig. This is a subclass of the HarpSoundCard that includes the sound card calibration.",
"properties": {
diff --git a/src/Extensions/AindBehaviorDynamicForaging.Generated.cs b/src/Extensions/AindBehaviorDynamicForaging.Generated.cs
index 0479d069..23ddcdc4 100644
--- a/src/Extensions/AindBehaviorDynamicForaging.Generated.cs
+++ b/src/Extensions/AindBehaviorDynamicForaging.Generated.cs
@@ -43,7 +43,7 @@ public partial class AindDynamicForagingRig
private HarpEnvironmentSensor _harpEnvironmentSensor;
- private AllenNeuralDynamics.AindManipulator.AindManipulator _manipulator;
+ private DynamicForagingAindManipulator _manipulator;
private RigCalibration _calibration;
@@ -55,7 +55,7 @@ public AindDynamicForagingRig()
_harpBehavior = new HarpBehavior();
_harpClockGenerator = new HarpWhiteRabbit();
_harpSoundCard = new DynamicForagingSoundCard();
- _manipulator = new AllenNeuralDynamics.AindManipulator.AindManipulator();
+ _manipulator = new DynamicForagingAindManipulator();
_calibration = new RigCalibration();
}
@@ -324,7 +324,7 @@ public HarpEnvironmentSensor HarpEnvironmentSensor
[System.Xml.Serialization.XmlIgnoreAttribute()]
[Newtonsoft.Json.JsonPropertyAttribute("manipulator", Required=Newtonsoft.Json.Required.Always)]
[System.ComponentModel.DescriptionAttribute("Manipulator")]
- public AllenNeuralDynamics.AindManipulator.AindManipulator Manipulator
+ public DynamicForagingAindManipulator Manipulator
{
get
{
@@ -2661,6 +2661,180 @@ protected override bool PrintMembers(System.Text.StringBuilder stringBuilder)
}
+ ///
+ /// a calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the animal position relative to the initial position.
+ ///
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Bonsai.Sgen", "0.9.0.0 (Newtonsoft.Json v13.0.0.0)")]
+ [System.ComponentModel.DescriptionAttribute("a calibrated manipulator for the dynamic foraging rig. This is a subclass of the " +
+ "AindManipulator that includes an offset of the animal position relative to the i" +
+ "nitial position.")]
+ [Bonsai.WorkflowElementCategoryAttribute(Bonsai.ElementCategory.Source)]
+ [Bonsai.CombinatorAttribute(MethodName="Generate")]
+ public partial class DynamicForagingAindManipulator
+ {
+
+ private string _deviceType;
+
+ private AllenNeuralDynamics.AindManipulator.AindManipulatorCalibration _calibration;
+
+ private int _whoAmI;
+
+ private string _serialNumber;
+
+ private string _portName;
+
+ private AllenNeuralDynamics.AindManipulator.ManipulatorPosition _animalOffset;
+
+ public DynamicForagingAindManipulator()
+ {
+ _deviceType = "StepperDriver";
+ _calibration = new AllenNeuralDynamics.AindManipulator.AindManipulatorCalibration();
+ _whoAmI = 1130;
+ _animalOffset = new AllenNeuralDynamics.AindManipulator.ManipulatorPosition();
+ }
+
+ protected DynamicForagingAindManipulator(DynamicForagingAindManipulator other)
+ {
+ _deviceType = other._deviceType;
+ _calibration = other._calibration;
+ _whoAmI = other._whoAmI;
+ _serialNumber = other._serialNumber;
+ _portName = other._portName;
+ _animalOffset = other._animalOffset;
+ }
+
+ [Newtonsoft.Json.JsonPropertyAttribute("device_type")]
+ public string DeviceType
+ {
+ get
+ {
+ return _deviceType;
+ }
+ set
+ {
+ _deviceType = value;
+ }
+ }
+
+ ///
+ /// Calibration for the device.
+ ///
+ [System.Xml.Serialization.XmlIgnoreAttribute()]
+ [Newtonsoft.Json.JsonPropertyAttribute("calibration")]
+ [System.ComponentModel.DescriptionAttribute("Calibration for the device.")]
+ public AllenNeuralDynamics.AindManipulator.AindManipulatorCalibration Calibration
+ {
+ get
+ {
+ return _calibration;
+ }
+ set
+ {
+ _calibration = value;
+ }
+ }
+
+ [Newtonsoft.Json.JsonPropertyAttribute("who_am_i")]
+ public int WhoAmI
+ {
+ get
+ {
+ return _whoAmI;
+ }
+ set
+ {
+ _whoAmI = value;
+ }
+ }
+
+ ///
+ /// Device serial number
+ ///
+ [Newtonsoft.Json.JsonPropertyAttribute("serial_number")]
+ [System.ComponentModel.DescriptionAttribute("Device serial number")]
+ public string SerialNumber
+ {
+ get
+ {
+ return _serialNumber;
+ }
+ set
+ {
+ _serialNumber = value;
+ }
+ }
+
+ ///
+ /// Device port name
+ ///
+ [Newtonsoft.Json.JsonPropertyAttribute("port_name", Required=Newtonsoft.Json.Required.Always)]
+ [System.ComponentModel.DescriptionAttribute("Device port name")]
+ public string PortName
+ {
+ get
+ {
+ return _portName;
+ }
+ set
+ {
+ _portName = value;
+ }
+ }
+
+ ///
+ /// Offset of the animal position relative to the `initial_position` parameter
+ ///
+ [System.Xml.Serialization.XmlIgnoreAttribute()]
+ [Newtonsoft.Json.JsonPropertyAttribute("animal_offset")]
+ [System.ComponentModel.DescriptionAttribute("Offset of the animal position relative to the `initial_position` parameter")]
+ public AllenNeuralDynamics.AindManipulator.ManipulatorPosition AnimalOffset
+ {
+ get
+ {
+ return _animalOffset;
+ }
+ set
+ {
+ _animalOffset = value;
+ }
+ }
+
+ public System.IObservable Generate()
+ {
+ return System.Reactive.Linq.Observable.Defer(() => System.Reactive.Linq.Observable.Return(new DynamicForagingAindManipulator(this)));
+ }
+
+ public System.IObservable Generate(System.IObservable source)
+ {
+ return System.Reactive.Linq.Observable.Select(source, _ => new DynamicForagingAindManipulator(this));
+ }
+
+ protected virtual bool PrintMembers(System.Text.StringBuilder stringBuilder)
+ {
+ stringBuilder.Append("DeviceType = " + _deviceType + ", ");
+ stringBuilder.Append("Calibration = " + _calibration + ", ");
+ stringBuilder.Append("WhoAmI = " + _whoAmI + ", ");
+ stringBuilder.Append("SerialNumber = " + _serialNumber + ", ");
+ stringBuilder.Append("PortName = " + _portName + ", ");
+ stringBuilder.Append("AnimalOffset = " + _animalOffset);
+ return true;
+ }
+
+ public override string ToString()
+ {
+ System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();
+ stringBuilder.Append(GetType().Name);
+ stringBuilder.Append(" { ");
+ if (PrintMembers(stringBuilder))
+ {
+ stringBuilder.Append(" ");
+ }
+ stringBuilder.Append("}");
+ return stringBuilder.ToString();
+ }
+ }
+
+
///
/// A calibrated sound card for the dynamic foraging rig. This is a subclass of the HarpSoundCard that includes the sound card calibration.
///
@@ -7634,6 +7808,11 @@ public System.IObservable Process(System.IObservable(source);
}
+ public System.IObservable Process(System.IObservable source)
+ {
+ return Process(source);
+ }
+
public System.IObservable Process(System.IObservable source)
{
return Process(source);
@@ -7804,6 +7983,7 @@ public System.IObservable Process(System.IObservable source)
[System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))]
+ [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))]
diff --git a/src/Extensions/OperationControl.bonsai b/src/Extensions/OperationControl.bonsai
index 9735b8ab..bf1430ef 100644
--- a/src/Extensions/OperationControl.bonsai
+++ b/src/Extensions/OperationControl.bonsai
@@ -632,7 +632,7 @@
- Manipulator
+ ManipulatorTask
@@ -882,6 +882,81 @@
+
+ ManipulatorInitialization
+
+
+
+
+ PT0.5S
+
+
+
+
+ HomeMotors
+
+
+
+
+
+ WaitForHomed
+
+
+
+ IsHomed
+
+
+
+ PT0.2S
+
+
+
+
+
+
+ Source1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PT10S
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
CameraControl
@@ -1516,8 +1591,8 @@
-
-
+
+
\ No newline at end of file
diff --git a/src/aind_behavior_dynamic_foraging/rig.py b/src/aind_behavior_dynamic_foraging/rig.py
index c1a94f0d..a8956f33 100644
--- a/src/aind_behavior_dynamic_foraging/rig.py
+++ b/src/aind_behavior_dynamic_foraging/rig.py
@@ -62,6 +62,16 @@ class DynamicForagingSoundCard(harp.HarpSoundCard):
)
+class DynamicForagingAindManipulator(aind_manipulator.AindManipulator):
+ """a calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the animal position relative to the initial position."""
+
+ animal_offset: aind_manipulator.ManipulatorPosition = Field(
+ aind_manipulator.ManipulatorPosition(x=0, y1=0, y2=0, z=0),
+ description="Offset of the animal position relative to the `initial_position` parameter",
+ validate_default=True,
+ )
+
+
class AindDynamicForagingRig(rig.Rig):
version: Literal[__semver__] = __semver__
triggered_camera_controller: cameras.CameraController[cameras.SpinnakerCamera] = Field(
@@ -79,5 +89,5 @@ class AindDynamicForagingRig(rig.Rig):
harp_environment_sensor: Optional[harp.HarpEnvironmentSensor] = Field(
default=None, description="Harp environment sensor"
)
- manipulator: aind_manipulator.AindManipulator = Field(description="Manipulator")
+ manipulator: DynamicForagingAindManipulator = Field(description="Manipulator")
calibration: RigCalibration = Field(description="Calibration models")
From 1cc3b5621c8369d02b39276510c1979529f7487e Mon Sep 17 00:00:00 2001
From: bruno-f-cruz <7049351+bruno-f-cruz@users.noreply.github.com>
Date: Mon, 4 May 2026 12:53:45 -0700
Subject: [PATCH 2/6] Add automatic homing and initial position to
initialization
---
schema/aind_behavior_dynamic_foraging.json | 6 +-
.../AindBehaviorDynamicForaging.Generated.cs | 26 ++++----
src/Extensions/Hardware.bonsai | 61 ++++++++++---------
.../OffsetInitialPositionWithSubject.cs | 30 +++++++++
src/Extensions/OperationControl.bonsai | 35 +++++++++--
src/aind_behavior_dynamic_foraging/rig.py | 6 +-
6 files changed, 112 insertions(+), 52 deletions(-)
create mode 100644 src/Extensions/OffsetInitialPositionWithSubject.cs
diff --git a/schema/aind_behavior_dynamic_foraging.json b/schema/aind_behavior_dynamic_foraging.json
index de9b5f21..8fce8b58 100644
--- a/schema/aind_behavior_dynamic_foraging.json
+++ b/schema/aind_behavior_dynamic_foraging.json
@@ -1363,7 +1363,7 @@
"x-sgen-typename": "AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution"
},
"DynamicForagingAindManipulator": {
- "description": "a calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the animal position relative to the initial position.",
+ "description": "a calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the subject position relative to the initial position.",
"properties": {
"device_type": {
"const": "StepperDriver",
@@ -1462,7 +1462,7 @@
"title": "Port Name",
"type": "string"
},
- "animal_offset": {
+ "subject_offset": {
"$ref": "#/$defs/ManipulatorPosition",
"default": {
"x": 0.0,
@@ -1470,7 +1470,7 @@
"y2": 0.0,
"z": 0.0
},
- "description": "Offset of the animal position relative to the `initial_position` parameter"
+ "description": "Offset of the subject position relative to the `initial_position` parameter"
}
},
"required": [
diff --git a/src/Extensions/AindBehaviorDynamicForaging.Generated.cs b/src/Extensions/AindBehaviorDynamicForaging.Generated.cs
index 23ddcdc4..b508d0dd 100644
--- a/src/Extensions/AindBehaviorDynamicForaging.Generated.cs
+++ b/src/Extensions/AindBehaviorDynamicForaging.Generated.cs
@@ -2662,12 +2662,12 @@ protected override bool PrintMembers(System.Text.StringBuilder stringBuilder)
///
- /// a calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the animal position relative to the initial position.
+ /// a calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the subject position relative to the initial position.
///
[System.CodeDom.Compiler.GeneratedCodeAttribute("Bonsai.Sgen", "0.9.0.0 (Newtonsoft.Json v13.0.0.0)")]
[System.ComponentModel.DescriptionAttribute("a calibrated manipulator for the dynamic foraging rig. This is a subclass of the " +
- "AindManipulator that includes an offset of the animal position relative to the i" +
- "nitial position.")]
+ "AindManipulator that includes an offset of the subject position relative to the " +
+ "initial position.")]
[Bonsai.WorkflowElementCategoryAttribute(Bonsai.ElementCategory.Source)]
[Bonsai.CombinatorAttribute(MethodName="Generate")]
public partial class DynamicForagingAindManipulator
@@ -2683,14 +2683,14 @@ public partial class DynamicForagingAindManipulator
private string _portName;
- private AllenNeuralDynamics.AindManipulator.ManipulatorPosition _animalOffset;
+ private AllenNeuralDynamics.AindManipulator.ManipulatorPosition _subjectOffset;
public DynamicForagingAindManipulator()
{
_deviceType = "StepperDriver";
_calibration = new AllenNeuralDynamics.AindManipulator.AindManipulatorCalibration();
_whoAmI = 1130;
- _animalOffset = new AllenNeuralDynamics.AindManipulator.ManipulatorPosition();
+ _subjectOffset = new AllenNeuralDynamics.AindManipulator.ManipulatorPosition();
}
protected DynamicForagingAindManipulator(DynamicForagingAindManipulator other)
@@ -2700,7 +2700,7 @@ protected DynamicForagingAindManipulator(DynamicForagingAindManipulator other)
_whoAmI = other._whoAmI;
_serialNumber = other._serialNumber;
_portName = other._portName;
- _animalOffset = other._animalOffset;
+ _subjectOffset = other._subjectOffset;
}
[Newtonsoft.Json.JsonPropertyAttribute("device_type")]
@@ -2782,20 +2782,20 @@ public string PortName
}
///
- /// Offset of the animal position relative to the `initial_position` parameter
+ /// Offset of the subject position relative to the `initial_position` parameter
///
[System.Xml.Serialization.XmlIgnoreAttribute()]
- [Newtonsoft.Json.JsonPropertyAttribute("animal_offset")]
- [System.ComponentModel.DescriptionAttribute("Offset of the animal position relative to the `initial_position` parameter")]
- public AllenNeuralDynamics.AindManipulator.ManipulatorPosition AnimalOffset
+ [Newtonsoft.Json.JsonPropertyAttribute("subject_offset")]
+ [System.ComponentModel.DescriptionAttribute("Offset of the subject position relative to the `initial_position` parameter")]
+ public AllenNeuralDynamics.AindManipulator.ManipulatorPosition SubjectOffset
{
get
{
- return _animalOffset;
+ return _subjectOffset;
}
set
{
- _animalOffset = value;
+ _subjectOffset = value;
}
}
@@ -2816,7 +2816,7 @@ protected virtual bool PrintMembers(System.Text.StringBuilder stringBuilder)
stringBuilder.Append("WhoAmI = " + _whoAmI + ", ");
stringBuilder.Append("SerialNumber = " + _serialNumber + ", ");
stringBuilder.Append("PortName = " + _portName + ", ");
- stringBuilder.Append("AnimalOffset = " + _animalOffset);
+ stringBuilder.Append("SubjectOffset = " + _subjectOffset);
return true;
}
diff --git a/src/Extensions/Hardware.bonsai b/src/Extensions/Hardware.bonsai
index 83ea5065..c1730e20 100644
--- a/src/Extensions/Hardware.bonsai
+++ b/src/Extensions/Hardware.bonsai
@@ -4,11 +4,12 @@
xmlns:harp="clr-namespace:Bonsai.Harp;assembly=Bonsai.Harp"
xmlns:p1="clr-namespace:AllenNeuralDynamics.WhiteRabbit;assembly=AllenNeuralDynamics.WhiteRabbit"
xmlns:rx="clr-namespace:Bonsai.Reactive;assembly=Bonsai.Core"
+ xmlns:p2="clr-namespace:;assembly=Extensions"
xmlns:beh="clr-namespace:Harp.Behavior;assembly=Harp.Behavior"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:cv="clr-namespace:Bonsai.Vision;assembly=Bonsai.Vision"
- xmlns:p2="clr-namespace:OpenCV.Net;assembly=OpenCV.Net"
- xmlns:p3="clr-namespace:AllenNeuralDynamics.Core;assembly=AllenNeuralDynamics.Core"
+ xmlns:p3="clr-namespace:OpenCV.Net;assembly=OpenCV.Net"
+ xmlns:p4="clr-namespace:AllenNeuralDynamics.Core;assembly=AllenNeuralDynamics.Core"
xmlns:spk="clr-namespace:Bonsai.Spinnaker;assembly=Bonsai.Spinnaker"
xmlns="https://bonsai-rx.org/2018/workflow">
@@ -132,7 +133,10 @@
RigSchema
- Manipulator.Calibration
+ Manipulator
+
+
+
RigSchema
@@ -228,24 +232,25 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
+
@@ -399,7 +404,7 @@
-
+
RegionOfInterest
0
@@ -414,21 +419,21 @@
-
+
Default
- 19000
- 0
- 1
-
- Mono8
-
- 0
- 0
- 0
- 0
-
-
+ 19000
+ 0
+ 1
+
+ Mono8
+
+ 0
+ 0
+ 0
+ 0
+
+
diff --git a/src/Extensions/OffsetInitialPositionWithSubject.cs b/src/Extensions/OffsetInitialPositionWithSubject.cs
new file mode 100644
index 00000000..e79f0f0f
--- /dev/null
+++ b/src/Extensions/OffsetInitialPositionWithSubject.cs
@@ -0,0 +1,30 @@
+using Bonsai;
+using System;
+using System.ComponentModel;
+using System.Linq;
+using System.Reactive.Linq;
+using AindDynamicForagingDataSchema;
+using AllenNeuralDynamics.AindManipulator;
+using Newtonsoft.Json;
+
+[Combinator]
+[Description("Offsets the initial position of the manipulator with the subject's calibration.")]
+[WorkflowElementCategory(ElementCategory.Transform)]
+public class OffsetInitialPositionWithSubject
+{
+ public IObservable Process(IObservable source)
+ {
+ return source.Select(value =>
+ {
+ // Make a quick deep-copy just in case.
+ var calibration = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value.Calibration));
+ if (calibration == null)
+ {
+ throw new InvalidOperationException("Manipulator does not contain a valid initial position.");
+ }
+ calibration.InitialPosition = calibration.InitialPosition + value.SubjectOffset;
+ return calibration;
+ }
+ );
+ }
+}
diff --git a/src/Extensions/OperationControl.bonsai b/src/Extensions/OperationControl.bonsai
index bf1430ef..105cedb9 100644
--- a/src/Extensions/OperationControl.bonsai
+++ b/src/Extensions/OperationControl.bonsai
@@ -895,9 +895,6 @@
HomeMotors
-
-
-
WaitForHomed
@@ -948,12 +945,40 @@
+
+ GoToInit
+
+
+
+ Source1
+
+
+
+ GoToInitialPosition
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
diff --git a/src/aind_behavior_dynamic_foraging/rig.py b/src/aind_behavior_dynamic_foraging/rig.py
index a8956f33..8608a95c 100644
--- a/src/aind_behavior_dynamic_foraging/rig.py
+++ b/src/aind_behavior_dynamic_foraging/rig.py
@@ -63,11 +63,11 @@ class DynamicForagingSoundCard(harp.HarpSoundCard):
class DynamicForagingAindManipulator(aind_manipulator.AindManipulator):
- """a calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the animal position relative to the initial position."""
+ """A calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the subject position relative to the initial position."""
- animal_offset: aind_manipulator.ManipulatorPosition = Field(
+ subject_offset: aind_manipulator.ManipulatorPosition = Field(
aind_manipulator.ManipulatorPosition(x=0, y1=0, y2=0, z=0),
- description="Offset of the animal position relative to the `initial_position` parameter",
+ description="Offset of the subject position relative to the `initial_position` parameter",
validate_default=True,
)
From e323df8ecc787758ac6e68549f3eca84a26fd4f9 Mon Sep 17 00:00:00 2001
From: bruno-f-cruz <7049351+bruno-f-cruz@users.noreply.github.com>
Date: Mon, 4 May 2026 16:29:56 -0700
Subject: [PATCH 3/6] Remove unused log
---
src/Extensions/Logging.bonsai | 21 +--------------------
1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/src/Extensions/Logging.bonsai b/src/Extensions/Logging.bonsai
index 26f8a32f..fffea67f 100644
--- a/src/Extensions/Logging.bonsai
+++ b/src/Extensions/Logging.bonsai
@@ -775,22 +775,6 @@
AdditionalSoftwareEvents
-
- ManipulatorPosition
-
-
-
- 1
-
-
-
-
- InitialManipulatorPosition
-
-
-
- SoftwareEvent
-
RngSeedValue
@@ -822,12 +806,9 @@
-
+
-
-
-
From 48520cea770de0eefd58f26a3583ba70c785eefb Mon Sep 17 00:00:00 2001
From: bruno-f-cruz <7049351+bruno-f-cruz@users.noreply.github.com>
Date: Wed, 13 May 2026 16:26:17 -0700
Subject: [PATCH 4/6] Ensure sequence never ends when homing motor
---
src/Extensions/OperationControl.bonsai | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/Extensions/OperationControl.bonsai b/src/Extensions/OperationControl.bonsai
index 105cedb9..7931b7d4 100644
--- a/src/Extensions/OperationControl.bonsai
+++ b/src/Extensions/OperationControl.bonsai
@@ -887,11 +887,20 @@
-
+
+ 0
+
+
+
+
PT0.5S
+
+ This is a publish subject!
+
+
HomeMotors
@@ -976,9 +985,11 @@
-
-
+
+
+
+
From f454b97e19c6add119e5b2b92f97111b73aa7619 Mon Sep 17 00:00:00 2001
From: Micah Woodard
Date: Mon, 18 May 2026 08:27:51 -0700
Subject: [PATCH 5/6] regenerates
---
schema/aind_behavior_dynamic_foraging.json | 2 +-
src/Extensions/AindBehaviorDynamicForaging.Generated.cs | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/schema/aind_behavior_dynamic_foraging.json b/schema/aind_behavior_dynamic_foraging.json
index 8fce8b58..4b61a1be 100644
--- a/schema/aind_behavior_dynamic_foraging.json
+++ b/schema/aind_behavior_dynamic_foraging.json
@@ -1363,7 +1363,7 @@
"x-sgen-typename": "AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution"
},
"DynamicForagingAindManipulator": {
- "description": "a calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the subject position relative to the initial position.",
+ "description": "A calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the subject position relative to the initial position.",
"properties": {
"device_type": {
"const": "StepperDriver",
diff --git a/src/Extensions/AindBehaviorDynamicForaging.Generated.cs b/src/Extensions/AindBehaviorDynamicForaging.Generated.cs
index b508d0dd..98105055 100644
--- a/src/Extensions/AindBehaviorDynamicForaging.Generated.cs
+++ b/src/Extensions/AindBehaviorDynamicForaging.Generated.cs
@@ -2662,10 +2662,10 @@ protected override bool PrintMembers(System.Text.StringBuilder stringBuilder)
///
- /// a calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the subject position relative to the initial position.
+ /// A calibrated manipulator for the dynamic foraging rig. This is a subclass of the AindManipulator that includes an offset of the subject position relative to the initial position.
///
[System.CodeDom.Compiler.GeneratedCodeAttribute("Bonsai.Sgen", "0.9.0.0 (Newtonsoft.Json v13.0.0.0)")]
- [System.ComponentModel.DescriptionAttribute("a calibrated manipulator for the dynamic foraging rig. This is a subclass of the " +
+ [System.ComponentModel.DescriptionAttribute("A calibrated manipulator for the dynamic foraging rig. This is a subclass of the " +
"AindManipulator that includes an offset of the subject position relative to the " +
"initial position.")]
[Bonsai.WorkflowElementCategoryAttribute(Bonsai.ElementCategory.Source)]
From 55f8453f66972636ecdc1dabc2b792c11f9a8fc7 Mon Sep 17 00:00:00 2001
From: Micah Woodard
Date: Mon, 18 May 2026 10:19:52 -0700
Subject: [PATCH 6/6] updates rig example
---
examples/rig.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/examples/rig.py b/examples/rig.py
index 4216c5d7..67b32378 100644
--- a/examples/rig.py
+++ b/examples/rig.py
@@ -2,7 +2,6 @@
from aind_behavior_services.rig import cameras
from aind_behavior_services.rig.aind_manipulator import (
- AindManipulator,
AindManipulatorCalibration,
Axis,
AxisConfiguration,
@@ -15,7 +14,12 @@
)
from aind_behavior_services.rig.water_valve import Measurement, calibrate_water_valves
-from aind_behavior_dynamic_foraging.rig import AindDynamicForagingRig, DynamicForagingSoundCard, RigCalibration
+from aind_behavior_dynamic_foraging.rig import (
+ AindDynamicForagingRig,
+ DynamicForagingAindManipulator,
+ DynamicForagingSoundCard,
+ RigCalibration,
+)
manipulator_calibration = AindManipulatorCalibration(
full_step_to_mm=(ManipulatorPosition(x=0.010, y1=0.010, y2=0.010, z=0.010)),
@@ -60,7 +64,7 @@
harp_lickometer_left=None,
harp_lickometer_right=None,
harp_clock_generator=HarpWhiteRabbit(port_name="COM11"),
- manipulator=AindManipulator(port_name="COM9", calibration=manipulator_calibration),
+ manipulator=DynamicForagingAindManipulator(port_name="COM9", calibration=manipulator_calibration),
calibration=RigCalibration(
water_valve_left=water_valve_calibration,
water_valve_right=water_valve_calibration,