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,