mxbiflow 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mxbiflow/__init__.py +3 -0
- mxbiflow/assets/__init__.py +5 -0
- mxbiflow/assets/clicker.wav +0 -0
- mxbiflow/config_store.py +68 -0
- mxbiflow/data_logger.py +114 -0
- mxbiflow/default/__init__.py +4 -0
- mxbiflow/default/idle/assets/apple_v1.png +0 -0
- mxbiflow/default/idle/idle.py +57 -0
- mxbiflow/detector_bridge.py +87 -0
- mxbiflow/game.py +84 -0
- mxbiflow/infra/eventbus.py +31 -0
- mxbiflow/main.py +106 -0
- mxbiflow/models/animal.py +130 -0
- mxbiflow/models/reward.py +7 -0
- mxbiflow/models/session.py +145 -0
- mxbiflow/mxbiflow.py +43 -0
- mxbiflow/path.py +41 -0
- mxbiflow/scene/__init__.py +8 -0
- mxbiflow/scene/scene_manager.py +64 -0
- mxbiflow/scene/scene_protocol.py +22 -0
- mxbiflow/scheduler.py +90 -0
- mxbiflow/tasks/GNGSiD/models.py +70 -0
- mxbiflow/tasks/GNGSiD/stages/detect_stage/config.json +116 -0
- mxbiflow/tasks/GNGSiD/stages/detect_stage/detect_stage.py +161 -0
- mxbiflow/tasks/GNGSiD/stages/detect_stage/detect_stage_models.py +65 -0
- mxbiflow/tasks/GNGSiD/stages/discriminate_stage/config.json +70 -0
- mxbiflow/tasks/GNGSiD/stages/discriminate_stage/discriminate_stage.py +173 -0
- mxbiflow/tasks/GNGSiD/stages/discriminate_stage/discriminate_stage_models.py +80 -0
- mxbiflow/tasks/GNGSiD/stages/size_reduction_stage/config.json +83 -0
- mxbiflow/tasks/GNGSiD/stages/size_reduction_stage/size_reduction_models.py +58 -0
- mxbiflow/tasks/GNGSiD/stages/size_reduction_stage/size_reduction_stage.py +149 -0
- mxbiflow/tasks/GNGSiD/tasks/artifacts.py +13 -0
- mxbiflow/tasks/GNGSiD/tasks/detect/models.py +21 -0
- mxbiflow/tasks/GNGSiD/tasks/detect/scene.py +271 -0
- mxbiflow/tasks/GNGSiD/tasks/discriminate/discriminate_models.py +31 -0
- mxbiflow/tasks/GNGSiD/tasks/discriminate/discriminate_scene.py +336 -0
- mxbiflow/tasks/GNGSiD/tasks/touch/touch_models.py +17 -0
- mxbiflow/tasks/GNGSiD/tasks/touch/touch_scene.py +256 -0
- mxbiflow/tasks/GNGSiD/tasks/utils/targets.py +57 -0
- mxbiflow/tasks/cross_modal/bundle_dir.py +553 -0
- mxbiflow/tasks/cross_modal/config.py +41 -0
- mxbiflow/tasks/cross_modal/media.py +61 -0
- mxbiflow/tasks/cross_modal/models.py +57 -0
- mxbiflow/tasks/cross_modal/scene.py +252 -0
- mxbiflow/tasks/cross_modal/stage.py +218 -0
- mxbiflow/tasks/cross_modal/trial_io.py +23 -0
- mxbiflow/tasks/cross_modal/trial_schema.py +113 -0
- mxbiflow/tasks/default/error_task/error_scene.py +53 -0
- mxbiflow/tasks/default/idle_task/assets/apple_v1.png +0 -0
- mxbiflow/tasks/default/idle_task/idle_scene.py +85 -0
- mxbiflow/tasks/default/initial_habituation_training/README.md +188 -0
- mxbiflow/tasks/default/initial_habituation_training/stages/config.csv +7 -0
- mxbiflow/tasks/default/initial_habituation_training/stages/config.json +67 -0
- mxbiflow/tasks/default/initial_habituation_training/stages/initial_habituation_training_stage.py +172 -0
- mxbiflow/tasks/default/initial_habituation_training/stages/models.py +56 -0
- mxbiflow/tasks/default/initial_habituation_training/tasks/stay_to_reward/stay_to_reward.py +244 -0
- mxbiflow/tasks/default/initial_habituation_training/tasks/stay_to_reward/stay_to_reward_models.py +50 -0
- mxbiflow/tasks/task_protocol.py +26 -0
- mxbiflow/tasks/task_table.py +29 -0
- mxbiflow/tasks/two_alternative_choice/assets/starter.py +27 -0
- mxbiflow/tasks/two_alternative_choice/models.py +68 -0
- mxbiflow/tasks/two_alternative_choice/stages/size_reduction_stage/config.json +118 -0
- mxbiflow/tasks/two_alternative_choice/stages/size_reduction_stage/size_reduction_models.py +41 -0
- mxbiflow/tasks/two_alternative_choice/stages/size_reduction_stage/size_reduction_stage.py +122 -0
- mxbiflow/tasks/two_alternative_choice/tasks/touch/touch_models.py +19 -0
- mxbiflow/tasks/two_alternative_choice/tasks/touch/touch_scene.py +249 -0
- mxbiflow/timer/__init__.py +3 -0
- mxbiflow/timer/frame_timer.py +47 -0
- mxbiflow/timer/realtime_timer.py +0 -0
- mxbiflow/tmp_email.py +13 -0
- mxbiflow/ui/components/animal.py +87 -0
- mxbiflow/ui/components/baseconfig.py +68 -0
- mxbiflow/ui/components/card.py +18 -0
- mxbiflow/ui/components/device_card/__init__.py +17 -0
- mxbiflow/ui/components/device_card/detector/beambreak_detector_card.py +29 -0
- mxbiflow/ui/components/device_card/detector/fusion_detector.py +45 -0
- mxbiflow/ui/components/device_card/detector/mock_detector_card.py +20 -0
- mxbiflow/ui/components/device_card/detector/rfid_detector.py +40 -0
- mxbiflow/ui/components/device_card/device_card.py +67 -0
- mxbiflow/ui/components/device_card/rewarder/mock_rewarder_card.py +20 -0
- mxbiflow/ui/components/device_card/rewarder/rpi_gpio_rewarder.py +33 -0
- mxbiflow/ui/components/devices.py +183 -0
- mxbiflow/ui/components/dialog/__init__.py +3 -0
- mxbiflow/ui/components/dialog/add_devices_dialog.py +64 -0
- mxbiflow/ui/components/experiment_groups.py +122 -0
- mxbiflow/ui/experiment_panel.py +91 -0
- mxbiflow/ui/mxbi_panel.py +152 -0
- mxbiflow/utils/logger.py +19 -0
- mxbiflow/utils/serial.py +10 -0
- mxbiflow-0.1.1.dist-info/METADATA +168 -0
- mxbiflow-0.1.1.dist-info/RECORD +93 -0
- mxbiflow-0.1.1.dist-info/WHEEL +4 -0
- mxbiflow-0.1.1.dist-info/entry_points.txt +4 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
from pymxbi import MXBIModel
|
|
2
|
+
from pymxbi.detector import DetectorEnum, DetectorModel
|
|
3
|
+
from pymxbi.rewarder import RewarderEnum, RewarderModel
|
|
4
|
+
from PySide6.QtCore import Signal
|
|
5
|
+
from PySide6.QtWidgets import (
|
|
6
|
+
QApplication,
|
|
7
|
+
QHBoxLayout,
|
|
8
|
+
QMainWindow,
|
|
9
|
+
QPushButton,
|
|
10
|
+
QVBoxLayout,
|
|
11
|
+
QWidget,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from ..config_store import ConfigStore
|
|
15
|
+
from ..models.session import Options
|
|
16
|
+
from ..path import MXBI_CONFIG_PATH, OPTIONS_PATH
|
|
17
|
+
from .components.baseconfig import BaseConfig
|
|
18
|
+
from .components.device_card import (
|
|
19
|
+
BeambreakDetectorCard,
|
|
20
|
+
FusionDetectorCard,
|
|
21
|
+
MockDetectorCard,
|
|
22
|
+
MockRewarderCard,
|
|
23
|
+
RFIDDetectorCard,
|
|
24
|
+
RPIGpioPumpCard,
|
|
25
|
+
)
|
|
26
|
+
from .components.devices import Devices
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class MXBIPanel(QMainWindow):
|
|
30
|
+
accepted = Signal()
|
|
31
|
+
|
|
32
|
+
_REWARDER_CARD_FACTORIES: dict[str, type[QWidget]] = {
|
|
33
|
+
RewarderEnum.RPI_GPIO: RPIGpioPumpCard,
|
|
34
|
+
RewarderEnum.MOCK: MockRewarderCard,
|
|
35
|
+
}
|
|
36
|
+
_DETECTOR_CARD_FACTORIES: dict[str, type[QWidget]] = {
|
|
37
|
+
DetectorEnum.RFID_CONTINUOUS: RFIDDetectorCard,
|
|
38
|
+
DetectorEnum.BEAMBREAK_CONTINUOUS: BeambreakDetectorCard,
|
|
39
|
+
DetectorEnum.FUSION_CONTINUOUS: FusionDetectorCard,
|
|
40
|
+
DetectorEnum.MOCK: MockDetectorCard,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# -----------------------------
|
|
44
|
+
# Lifecycle / Init
|
|
45
|
+
# -----------------------------
|
|
46
|
+
|
|
47
|
+
def __init__(self):
|
|
48
|
+
super().__init__()
|
|
49
|
+
self._config = ConfigStore(MXBI_CONFIG_PATH, MXBIModel)
|
|
50
|
+
self._options = ConfigStore(OPTIONS_PATH, Options)
|
|
51
|
+
|
|
52
|
+
self._build_ui()
|
|
53
|
+
self._load_from_config()
|
|
54
|
+
self._bind_events()
|
|
55
|
+
|
|
56
|
+
# -----------------------------
|
|
57
|
+
# UI Construction
|
|
58
|
+
# -----------------------------
|
|
59
|
+
|
|
60
|
+
def _build_ui(self) -> None:
|
|
61
|
+
self.setWindowTitle("MXBI Configuration Panel")
|
|
62
|
+
|
|
63
|
+
self._widget_main = QWidget()
|
|
64
|
+
self._layout_main = QVBoxLayout()
|
|
65
|
+
self._widget_main.setLayout(self._layout_main)
|
|
66
|
+
self.setCentralWidget(self._widget_main)
|
|
67
|
+
|
|
68
|
+
self.base_config = BaseConfig(self, self._options.value.mxbis)
|
|
69
|
+
self._layout_main.addWidget(self.base_config)
|
|
70
|
+
self._build_device_groups()
|
|
71
|
+
self._layout_main.addLayout(self._build_buttons_row())
|
|
72
|
+
|
|
73
|
+
def _build_device_groups(self) -> None:
|
|
74
|
+
self.rewarders_group = Devices[RewarderModel](
|
|
75
|
+
self,
|
|
76
|
+
"Rewarders",
|
|
77
|
+
action_label="Add Rewarder",
|
|
78
|
+
device_types=list(RewarderEnum),
|
|
79
|
+
dialog_title="Add rewarder",
|
|
80
|
+
label="rewarder type:",
|
|
81
|
+
card_factories=self._REWARDER_CARD_FACTORIES,
|
|
82
|
+
)
|
|
83
|
+
self._layout_main.addWidget(self.rewarders_group)
|
|
84
|
+
|
|
85
|
+
self.detectors_group = Devices[DetectorModel](
|
|
86
|
+
self,
|
|
87
|
+
"Detectors",
|
|
88
|
+
action_label="Add Detector",
|
|
89
|
+
device_types=list(DetectorEnum),
|
|
90
|
+
dialog_title="Add detector",
|
|
91
|
+
label="detector type:",
|
|
92
|
+
card_factories=self._DETECTOR_CARD_FACTORIES,
|
|
93
|
+
)
|
|
94
|
+
self._layout_main.addWidget(self.detectors_group)
|
|
95
|
+
|
|
96
|
+
def _build_buttons_row(self) -> QHBoxLayout:
|
|
97
|
+
layout_buttons = QHBoxLayout()
|
|
98
|
+
self.save_button = QPushButton("Save")
|
|
99
|
+
self.cancel_button = QPushButton("Cancel")
|
|
100
|
+
self.continue_button = QPushButton("Continue")
|
|
101
|
+
layout_buttons.addWidget(self.cancel_button)
|
|
102
|
+
layout_buttons.addWidget(self.save_button)
|
|
103
|
+
layout_buttons.addWidget(self.continue_button)
|
|
104
|
+
return layout_buttons
|
|
105
|
+
|
|
106
|
+
# -----------------------------
|
|
107
|
+
# Load / Save
|
|
108
|
+
# -----------------------------
|
|
109
|
+
|
|
110
|
+
def _load_from_config(self) -> None:
|
|
111
|
+
self.base_config.load_from_model(self._config.value)
|
|
112
|
+
|
|
113
|
+
self.rewarders_group.load_models(self._config.value.rewarders)
|
|
114
|
+
self.detectors_group.load_models(self._config.value.detectors)
|
|
115
|
+
|
|
116
|
+
def _collect_result(self) -> None:
|
|
117
|
+
self.base_config.apply_to_model(self._config.value)
|
|
118
|
+
|
|
119
|
+
# Replace instead of append so repeated Save/Continue doesn't duplicate entries.
|
|
120
|
+
self._config.value.rewarders = self.rewarders_group.results()
|
|
121
|
+
self._config.value.detectors = self.detectors_group.results()
|
|
122
|
+
|
|
123
|
+
def _on_save(self) -> None:
|
|
124
|
+
self._collect_result()
|
|
125
|
+
self._config.save()
|
|
126
|
+
|
|
127
|
+
def _on_continue(self) -> None:
|
|
128
|
+
self._collect_result()
|
|
129
|
+
self._config.save()
|
|
130
|
+
self.close()
|
|
131
|
+
self.accepted.emit()
|
|
132
|
+
|
|
133
|
+
# -----------------------------
|
|
134
|
+
# Events / Menus
|
|
135
|
+
# -----------------------------
|
|
136
|
+
|
|
137
|
+
def _bind_events(self) -> None:
|
|
138
|
+
self.cancel_button.clicked.connect(self._on_cancel)
|
|
139
|
+
self.save_button.clicked.connect(self._on_save)
|
|
140
|
+
self.continue_button.clicked.connect(self._on_continue)
|
|
141
|
+
|
|
142
|
+
def _on_cancel(self) -> None:
|
|
143
|
+
self.close()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
if __name__ == "__main__":
|
|
147
|
+
import sys
|
|
148
|
+
|
|
149
|
+
app = QApplication(sys.argv)
|
|
150
|
+
window = MXBIPanel()
|
|
151
|
+
window.show()
|
|
152
|
+
sys.exit(app.exec())
|
mxbiflow/utils/logger.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
from loguru import logger
|
|
4
|
+
|
|
5
|
+
from ..path import LOG_PATH
|
|
6
|
+
|
|
7
|
+
logger.remove()
|
|
8
|
+
|
|
9
|
+
logger.add(sys.stderr, level="DEBUG")
|
|
10
|
+
|
|
11
|
+
logger.add(
|
|
12
|
+
f"{LOG_PATH}/mxbi.log",
|
|
13
|
+
rotation="10 MB",
|
|
14
|
+
retention="7 days",
|
|
15
|
+
compression="zip",
|
|
16
|
+
encoding="utf-8",
|
|
17
|
+
level="DEBUG",
|
|
18
|
+
serialize=True,
|
|
19
|
+
)
|
mxbiflow/utils/serial.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from serial import SerialBase
|
|
2
|
+
from serial.tools import list_ports
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def get_baudrates():
|
|
6
|
+
return [(str(baudrate), baudrate) for baudrate in SerialBase.BAUDRATES]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_all_ports():
|
|
10
|
+
return [port.device for port in list_ports.comports() if port.device is not None]
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: mxbiflow
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: mxbiflow is a toolkit based on pygame and pymxbi
|
|
5
|
+
Author: HuYang
|
|
6
|
+
Author-email: HuYang <huyangcommit@gmail.com>
|
|
7
|
+
Requires-Dist: gpiozero>=2.0.1
|
|
8
|
+
Requires-Dist: inflection>=0.5.1
|
|
9
|
+
Requires-Dist: keyring>=25.6.0
|
|
10
|
+
Requires-Dist: loguru>=0.7.3
|
|
11
|
+
Requires-Dist: matplotlib>=3.10.6
|
|
12
|
+
Requires-Dist: mss>=10.1.0
|
|
13
|
+
Requires-Dist: numpy>=2.3.3
|
|
14
|
+
Requires-Dist: pandas>=2.3.2
|
|
15
|
+
Requires-Dist: pillow>=11.3.0
|
|
16
|
+
Requires-Dist: pyaudio>=0.2.14
|
|
17
|
+
Requires-Dist: pydantic>=2.11.7
|
|
18
|
+
Requires-Dist: pygame-ce>=2.5.6
|
|
19
|
+
Requires-Dist: pymotego>=0.1.3
|
|
20
|
+
Requires-Dist: pymxbi>=0.1.2
|
|
21
|
+
Requires-Dist: pyserial>=3.5
|
|
22
|
+
Requires-Dist: pyside6>=6.10.1
|
|
23
|
+
Requires-Dist: qtawesome>=1.4.1
|
|
24
|
+
Requires-Dist: rich>=14.1.0
|
|
25
|
+
Requires-Dist: typer>=0.20.0
|
|
26
|
+
Requires-Dist: varname>=0.15.0
|
|
27
|
+
Requires-Python: >=3.14
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
## TODO
|
|
31
|
+
|
|
32
|
+
- [ ] session should be managed automatically
|
|
33
|
+
|
|
34
|
+
## Table of Contents
|
|
35
|
+
- [Task](https://github.com/Ccccraz/mxbi/blob/main/docs/task.md)
|
|
36
|
+
|
|
37
|
+
## Get Started 🚀
|
|
38
|
+
|
|
39
|
+
I typically use `uv` to manage a Python project, and I **highly recommend** you use `uv` to start the mxbi code as well.
|
|
40
|
+
|
|
41
|
+
```shell
|
|
42
|
+
cd # Go back to home
|
|
43
|
+
|
|
44
|
+
cd /path/your_favorite # Choose your favorite directory
|
|
45
|
+
|
|
46
|
+
git clone https://github.com/Ccccraz/mxbi.git # Clone the mxbi repository
|
|
47
|
+
|
|
48
|
+
cd mxbi # Enter the mxbi directory
|
|
49
|
+
|
|
50
|
+
uv sync # Install required dependencies
|
|
51
|
+
|
|
52
|
+
uv run mxbi # Start mxbi
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Current architecture
|
|
56
|
+
|
|
57
|
+
Currently, the entire code structure is divided into five main parts:
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
- **User GUI**: used for manually adjusting experiment settings
|
|
61
|
+
- **Task scheduler**: used for adjusting task difficulty and switching between tasks
|
|
62
|
+
- **Task**: used for executing specific tasks
|
|
63
|
+
- **Theater**: serves as the environment for task execution
|
|
64
|
+
- **Detector**: Detector, used to detect RFID tags
|
|
65
|
+
|
|
66
|
+
```mermaid
|
|
67
|
+
flowchart LR
|
|
68
|
+
user_gui -->|create theater| theater
|
|
69
|
+
theater -->|create scheduler| scheduler
|
|
70
|
+
scheduler -->|create task| task
|
|
71
|
+
task -->|adjust level| scheduler
|
|
72
|
+
scheduler -->|check rfid| detector
|
|
73
|
+
detector -->|control| scheduler
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Task Scheduler
|
|
77
|
+
|
|
78
|
+
There were too many different **states** in the original code, which made the code branch paths overly complex. Therefore, I decided to separate the task `scheduler`, ensuring that the tasks themselves are stateless and that their inputs and outputs are deterministic. The task scheduler will ensure that its initial state is correct.
|
|
79
|
+
|
|
80
|
+
Moreover, the `Protocol` is used to define the interface of Task, which enables the scheduler not only to adjust the difficulty but also to switch between tasks.
|
|
81
|
+
|
|
82
|
+
## Detector
|
|
83
|
+
|
|
84
|
+
### Overview
|
|
85
|
+
|
|
86
|
+
The RFID module should run in an independent thread, performing detection every **100 ms** and triggering corresponding callbacks based on the detection results.
|
|
87
|
+
|
|
88
|
+
### Detector States
|
|
89
|
+
|
|
90
|
+
- **NO_ANIMAL**: No animal detected
|
|
91
|
+
- **ANIMAL_PRESENT**: One animal detected
|
|
92
|
+
- **MORE_THAN_ONE_ANIMAL**: Multiple animals detected (defined as error behavior)
|
|
93
|
+
|
|
94
|
+
### Data Maintenance
|
|
95
|
+
|
|
96
|
+
- **current_animal**: Currently detected animal
|
|
97
|
+
- **history_animal**: Historical animal record
|
|
98
|
+
|
|
99
|
+
### State Transition Events
|
|
100
|
+
|
|
101
|
+
- **NO_ANIMAL → ANIMAL_PRESENT** and current_animal != history_animal: New animal appears
|
|
102
|
+
- **NO_ANIMAL → ANIMAL_PRESENT** and current_animal == history_animal: Animal returns
|
|
103
|
+
- **ANIMAL_PRESENT → NO_ANIMAL**: Animal leaves
|
|
104
|
+
- **ANIMAL_PRESENT → ANIMAL_PRESENT** and current_animal != history_animal: New animal appears
|
|
105
|
+
- **ANIMAL_PRESENT → MORE_THAN_ONE_ANIMAL**: Multiple animals detected (error behavior)
|
|
106
|
+
- **MORE_THAN_ONE_ANIMAL → ANIMAL_PRESENT**: Recovery
|
|
107
|
+
- **MORE_THAN_ONE_ANIMAL → NO_ANIMAL**: Recovery
|
|
108
|
+
|
|
109
|
+
### Scheduler State Regulation
|
|
110
|
+
|
|
111
|
+
- **ANIMAL_ENTERED** → Scheduler in SCHEDULE
|
|
112
|
+
- **ANIMAL_RETURNED** → Scheduler in SCHEDULE
|
|
113
|
+
- **ANIMAL_CHANGED** → Scheduler in SCHEDULE
|
|
114
|
+
- **ANIMAL_LEFT** → Scheduler in IDLE
|
|
115
|
+
- **ERROR_DETECTED** → Scheduler in ERROR
|
|
116
|
+
|
|
117
|
+
```mermaid
|
|
118
|
+
sequenceDiagram
|
|
119
|
+
participant RFID_Thread
|
|
120
|
+
participant Detector
|
|
121
|
+
participant Scheduler
|
|
122
|
+
|
|
123
|
+
loop Every 100 ms
|
|
124
|
+
RFID_Thread->>Detector: Perform detection
|
|
125
|
+
activate Detector
|
|
126
|
+
|
|
127
|
+
alt NO_ANIMAL → ANIMAL_PRESENT (current ≠ history)
|
|
128
|
+
Detector->>Detector: State transition
|
|
129
|
+
Detector->>Scheduler: ANIMAL_ENTERED
|
|
130
|
+
Scheduler->>Scheduler: Set to SCHEDULE
|
|
131
|
+
else NO_ANIMAL → ANIMAL_PRESENT (current = history)
|
|
132
|
+
Detector->>Detector: State transition
|
|
133
|
+
Detector->>Scheduler: ANIMAL_RETURNED
|
|
134
|
+
Scheduler->>Scheduler: Set to SCHEDULE
|
|
135
|
+
else ANIMAL_PRESENT → NO_ANIMAL
|
|
136
|
+
Detector->>Detector: State transition
|
|
137
|
+
Detector->>Scheduler: ANIMAL_LEFT
|
|
138
|
+
Scheduler->>Scheduler: Set to IDLE
|
|
139
|
+
else ANIMAL_PRESENT → ANIMAL_PRESENT (current ≠ history)
|
|
140
|
+
Detector->>Detector: State transition
|
|
141
|
+
Detector->>Scheduler: ANIMAL_CHANGED
|
|
142
|
+
Scheduler->>Scheduler: Set to SCHEDULE
|
|
143
|
+
else ANIMAL_PRESENT → MORE_THAN_ONE_ANIMAL
|
|
144
|
+
Detector->>Detector: State transition
|
|
145
|
+
Detector->>Scheduler: ERROR_DETECTED
|
|
146
|
+
Scheduler->>Scheduler: Set to ERROR
|
|
147
|
+
else MORE_THAN_ONE_ANIMAL → ANIMAL_PRESENT
|
|
148
|
+
Detector->>Detector: State transition
|
|
149
|
+
Detector->>Scheduler: Recovery event
|
|
150
|
+
Scheduler->>Scheduler: Set to SCHEDULE
|
|
151
|
+
else MORE_THAN_ONE_ANIMAL → NO_ANIMAL
|
|
152
|
+
Detector->>Detector: State transition
|
|
153
|
+
Detector->>Scheduler: Recovery event
|
|
154
|
+
Scheduler->>Scheduler: Set to IDLE
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
deactivate Detector
|
|
158
|
+
end
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Extract data model
|
|
162
|
+
|
|
163
|
+
The states in the original code were scattered across a large number of variables, so I tried to extract all the data models for unified management. You can find most of the data models under `src/mxbi/models`.
|
|
164
|
+
|
|
165
|
+
## TODO:
|
|
166
|
+
|
|
167
|
+
- More tasks
|
|
168
|
+
- More detailed instruction documents
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
mxbiflow/__init__.py,sha256=ozmSVFtsr5ddD7pThZNi_guF59SjTpumU1AuvAWbJK0,85
|
|
2
|
+
mxbiflow/assets/__init__.py,sha256=q4EMjlEE0iRc5LGRC-ecFfHcZVgDZTpcHFvpEv5LpSg,98
|
|
3
|
+
mxbiflow/assets/clicker.wav,sha256=EigwY1fa3iwx4JEsnur1PUIZBndrwaLCUv7C5FlSOD8,176582
|
|
4
|
+
mxbiflow/config_store.py,sha256=vVQI4Jv_DTwXL5wg2dvdmzaLuC1OcGDEZjC-GyQ5PW0,2134
|
|
5
|
+
mxbiflow/data_logger.py,sha256=01LtrBMYcm2zqASXdQJzmwRs6HNUCvtHK6S7TspgFOE,3619
|
|
6
|
+
mxbiflow/default/__init__.py,sha256=m4mByPSQBoqPot0ynQcUgK6PiPaCNuWEYQOdnWmkq4U,112
|
|
7
|
+
mxbiflow/default/idle/assets/apple_v1.png,sha256=bKrntrgfA82A2vgS5XLL3DEpC7NtY4kYCDoriG9q5Ko,2185277
|
|
8
|
+
mxbiflow/default/idle/idle.py,sha256=ZhDzXqmExsTXNuE7GncbNXmj8_VF0XdXsvYvXqJa_Nw,1470
|
|
9
|
+
mxbiflow/detector_bridge.py,sha256=D5hOCt7CgeZ5oReJql588nR-Va2wDMqnFxWieC_EvgU,2840
|
|
10
|
+
mxbiflow/game.py,sha256=pvsvSt_mfiGloJk-nQB7fDNzS48yOxz6_Ww8hTBcCwk,2439
|
|
11
|
+
mxbiflow/infra/eventbus.py,sha256=DnAHmRW13Emp6zfeZDJUwbiypHAzPKK62IpuUFOZguo,751
|
|
12
|
+
mxbiflow/main.py,sha256=aYvknPr68ZDc-Y-eJi-OfEkA-D9TQPCP5yK80aR1DAw,2935
|
|
13
|
+
mxbiflow/models/animal.py,sha256=3alb7ZUT-cmGFYE23oVVIAlTV6ye7Es1pRmE62VfH_E,3881
|
|
14
|
+
mxbiflow/models/reward.py,sha256=gmy6Cb-BPCpYvFmSPBJXUCJKIJQPp5BCJsWv-q0pt2A,138
|
|
15
|
+
mxbiflow/models/session.py,sha256=LKTTZ9bpONbsY4oG9MvlvMO2JOjY3-Klc0_KybWvN8Q,4188
|
|
16
|
+
mxbiflow/mxbiflow.py,sha256=zhkdhlFcpy-1lqH-gHU3QajW5bazf6BeLJtwbqSxKFs,980
|
|
17
|
+
mxbiflow/path.py,sha256=UD4FEew3QK6ni6PBiuZ67kyY1wUF2SQyAo_7lMhAGFA,1455
|
|
18
|
+
mxbiflow/scene/__init__.py,sha256=PpsHr3KKReFsc-MN3Gj1OmqvCCCQornT0mfdkxRqJtA,160
|
|
19
|
+
mxbiflow/scene/scene_manager.py,sha256=D1TN9T-SSeUu33fulTexx6hy0OS4zFuxu8SAUX41blg,1708
|
|
20
|
+
mxbiflow/scene/scene_protocol.py,sha256=U3SXoAAues5H8qIeQwY29PRRYAoUhPZMgoC6KDQtK2I,455
|
|
21
|
+
mxbiflow/scheduler.py,sha256=58lOoqiqpjhciIAyhcC9mTR_LtxwAdBuVUl7Dci3pCk,2536
|
|
22
|
+
mxbiflow/tasks/GNGSiD/models.py,sha256=cUZMIHRy-fIlA0vxkTObMRfDKsQtsQz2JL54Z9rXcl0,1209
|
|
23
|
+
mxbiflow/tasks/GNGSiD/stages/detect_stage/config.json,sha256=LRkH-tcQDku-NJbkBtEJMXhND4RLX7A2441VVSNPZz8,3718
|
|
24
|
+
mxbiflow/tasks/GNGSiD/stages/detect_stage/detect_stage.py,sha256=KDHFjSk1jnw2Uhve2pIu89nUlABPU8Abyrrj1EPNios,5530
|
|
25
|
+
mxbiflow/tasks/GNGSiD/stages/detect_stage/detect_stage_models.py,sha256=_AL0hotrxOZT2GFUXQ5l6a6kJ30pdilf2UAnymgMahQ,1502
|
|
26
|
+
mxbiflow/tasks/GNGSiD/stages/discriminate_stage/config.json,sha256=prV8qahUHfoLIXxKpBHH6AhliqpLxim0GVPMznFXh3k,2271
|
|
27
|
+
mxbiflow/tasks/GNGSiD/stages/discriminate_stage/discriminate_stage.py,sha256=8eBGdT0Zf2wbJLXQ7x7niVBTeP6MESgtGTt_U6TUqek,6419
|
|
28
|
+
mxbiflow/tasks/GNGSiD/stages/discriminate_stage/discriminate_stage_models.py,sha256=UvAbt18krt9sa73wjtYpN1PnzcWQkdLYR5ZO_OtLOq0,1938
|
|
29
|
+
mxbiflow/tasks/GNGSiD/stages/size_reduction_stage/config.json,sha256=ZcfVVnOc_RZ5cqUVH-LO1z9EPLL6-wxsCA7UHSwgAXw,2300
|
|
30
|
+
mxbiflow/tasks/GNGSiD/stages/size_reduction_stage/size_reduction_models.py,sha256=FFp9PB27forrphIn4oM2njnwi7SRq0DNhvdyiflWB10,1431
|
|
31
|
+
mxbiflow/tasks/GNGSiD/stages/size_reduction_stage/size_reduction_stage.py,sha256=SBneX5BN9tdgQVqF8UbbVNte6ue8ghbrOZvIugHN2ug,5172
|
|
32
|
+
mxbiflow/tasks/GNGSiD/tasks/artifacts.py,sha256=8f_pNYr6YrRBTF3VZrN5VHglJ0rugRqDU3vqc91pFNY,352
|
|
33
|
+
mxbiflow/tasks/GNGSiD/tasks/detect/models.py,sha256=SBrEC3ve8XpYAa9dm8pZsZr3MIhzpho_2zx0_MwqjhI,438
|
|
34
|
+
mxbiflow/tasks/GNGSiD/tasks/detect/scene.py,sha256=qiT8FpX3C8-t6MTcSejfwoiMrQ21RebHXVeqrfvKK2I,9206
|
|
35
|
+
mxbiflow/tasks/GNGSiD/tasks/discriminate/discriminate_models.py,sha256=wkxv1B5DD2V6wTSUy4nEjI1PGP7WjbG3TGcWDFPn8Hs,765
|
|
36
|
+
mxbiflow/tasks/GNGSiD/tasks/discriminate/discriminate_scene.py,sha256=5fhheLA6PzbzSf9HwVqr6_trl0X8L7YQxQfHuqA8bqc,11769
|
|
37
|
+
mxbiflow/tasks/GNGSiD/tasks/touch/touch_models.py,sha256=nh_Oyh6dCbHTjwaXGzuH-Pch_xe4dNBeTF-ZPQlzmyc,378
|
|
38
|
+
mxbiflow/tasks/GNGSiD/tasks/touch/touch_scene.py,sha256=LUthSquO14UuzhWy1vDdMb8f1dlNqfGQtwbcskBmMm4,8571
|
|
39
|
+
mxbiflow/tasks/GNGSiD/tasks/utils/targets.py,sha256=JLoE0r5wmctsKrkPFY402L764-4lHfPHlH-IOK4TcHE,1588
|
|
40
|
+
mxbiflow/tasks/cross_modal/bundle_dir.py,sha256=tDYCIlVl2yxgijDFh8uLfybF2EiTxJrPeK6emmgGPJY,19249
|
|
41
|
+
mxbiflow/tasks/cross_modal/config.py,sha256=2ySh_tETMfBqwMl6ano2luOpLOq4a1SalwILDuml2bM,1493
|
|
42
|
+
mxbiflow/tasks/cross_modal/media.py,sha256=Btz_ClXcK3Xwdl84K_lsh799bl6j9ZXE4JoYSuyzjho,1954
|
|
43
|
+
mxbiflow/tasks/cross_modal/models.py,sha256=hmfbB-niENbmM5Mmifk3lx6LOpd-kg9Y83Rh-pTUYUU,1050
|
|
44
|
+
mxbiflow/tasks/cross_modal/scene.py,sha256=ldSnvkOil4rBmk4r-IVsbjQg_t5fb2SWrFcKeEV5v5E,8282
|
|
45
|
+
mxbiflow/tasks/cross_modal/stage.py,sha256=ckB5p9jYbXqVocO7OV7XjS6uj6HlX4hOCPtZYmTc83k,8060
|
|
46
|
+
mxbiflow/tasks/cross_modal/trial_io.py,sha256=KUfixonadRVDZK4XROkY93V5DyhGIuSsIHkfaZxCJx4,669
|
|
47
|
+
mxbiflow/tasks/cross_modal/trial_schema.py,sha256=L_F2BIhyjrluErh0qVjV90f8fw9ybYITbD0N9VcKGSg,3804
|
|
48
|
+
mxbiflow/tasks/default/error_task/error_scene.py,sha256=2hcU6nTWTDm62wJGTgSSkOuvmKtyYB5Zur8TaSPWJqE,1396
|
|
49
|
+
mxbiflow/tasks/default/idle_task/assets/apple_v1.png,sha256=bKrntrgfA82A2vgS5XLL3DEpC7NtY4kYCDoriG9q5Ko,2185277
|
|
50
|
+
mxbiflow/tasks/default/idle_task/idle_scene.py,sha256=v5rK5mvkHizh6HuJlVUdLkKWmeKjPNBp9Dhx33HGRHM,2583
|
|
51
|
+
mxbiflow/tasks/default/initial_habituation_training/README.md,sha256=E0S5Bnf69-iHSgm9NVpzw41yAg41hlHC1tdbD4J5RKk,6517
|
|
52
|
+
mxbiflow/tasks/default/initial_habituation_training/stages/config.csv,sha256=gBWxw6l2kV0YzxdgwcmKzSR7io5UAzXZBuAixOQVLzk,243
|
|
53
|
+
mxbiflow/tasks/default/initial_habituation_training/stages/config.json,sha256=UG8tOmCwtQHKb45wX3kdH3NuLchZF3E_H08nJWf8abQ,2065
|
|
54
|
+
mxbiflow/tasks/default/initial_habituation_training/stages/initial_habituation_training_stage.py,sha256=1nk7Sj-zxgp_3NgG1FKfjmbbmFm2lLqOARZpEhm8YtQ,5658
|
|
55
|
+
mxbiflow/tasks/default/initial_habituation_training/stages/models.py,sha256=X3NWmL9ZCdhOZyCOZT7cOpOaKDBMEIv7UeTPCiLkxFg,1412
|
|
56
|
+
mxbiflow/tasks/default/initial_habituation_training/tasks/stay_to_reward/stay_to_reward.py,sha256=rDDb0KgmRJTjyKJIJ44n7ZF25YNrH5uEmxillWceS_8,8168
|
|
57
|
+
mxbiflow/tasks/default/initial_habituation_training/tasks/stay_to_reward/stay_to_reward_models.py,sha256=b1IpQP86F_aWUgFKTnvH3dOLNqjyGjp-BxBI9w5GzkE,947
|
|
58
|
+
mxbiflow/tasks/task_protocol.py,sha256=4Ard1waHI77ZpbgoB9v6u3Wka13hpLP4mgpArun4Wq4,655
|
|
59
|
+
mxbiflow/tasks/task_table.py,sha256=hXV1GYtgfRDpIBDpwraRDiWmYXFhEEQ32Le1ItBkFFg,1285
|
|
60
|
+
mxbiflow/tasks/two_alternative_choice/assets/starter.py,sha256=AMm7_yQOwXg0OuSKXHc-WSmu4tp87-ELPYwPe_cv75g,572
|
|
61
|
+
mxbiflow/tasks/two_alternative_choice/models.py,sha256=N7B3jn8sM02k7mv9pu5k26lqcREHuTEatiVwz2iZN5s,1181
|
|
62
|
+
mxbiflow/tasks/two_alternative_choice/stages/size_reduction_stage/config.json,sha256=S64uPhM7XwoYQ46g2R7Z2msru5ohT7kBP3WlHzUweM4,3179
|
|
63
|
+
mxbiflow/tasks/two_alternative_choice/stages/size_reduction_stage/size_reduction_models.py,sha256=1FGhsIHBZnZ52YPIo8tpAeNsto3ydqlSy7fuuEsl45o,1147
|
|
64
|
+
mxbiflow/tasks/two_alternative_choice/stages/size_reduction_stage/size_reduction_stage.py,sha256=vMu0XrrpnPr7rNZCA8USFYDCODgLd6rfNcxfoPV7VUs,4055
|
|
65
|
+
mxbiflow/tasks/two_alternative_choice/tasks/touch/touch_models.py,sha256=L8wEX7Nv4JVKTQX7zR0KcCNULx4FmiY3qI_ojWKwOk0,342
|
|
66
|
+
mxbiflow/tasks/two_alternative_choice/tasks/touch/touch_scene.py,sha256=OQZGa_nler82HKvDhuplxrtMD8nm06nx7p0vjFZdRGg,8395
|
|
67
|
+
mxbiflow/timer/__init__.py,sha256=lABOmME2FSR0EHGe-lz4p-d_PCBamZCjPQx0Mr1jwmE,62
|
|
68
|
+
mxbiflow/timer/frame_timer.py,sha256=Yfx-u_-Qe-HxODVIQYNtA-iwGd0dWckTx_lhaShdZY8,1331
|
|
69
|
+
mxbiflow/timer/realtime_timer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
|
+
mxbiflow/tmp_email.py,sha256=A7GpHoMIi9JjoKD10z4ohD6Mz-2D9lMLQvuP08H9zys,448
|
|
71
|
+
mxbiflow/ui/components/animal.py,sha256=4YQ6VF5ts1u96wmux_Kn3JLAhjJ9_s7nMtgtqXOy6LY,3269
|
|
72
|
+
mxbiflow/ui/components/baseconfig.py,sha256=rjsErRi7NZAO3Yb_5l8YCd1g7bPDyb0R85FaJoXvi-c,2297
|
|
73
|
+
mxbiflow/ui/components/card.py,sha256=LdI99dL3S21y72KOkbFD0ByiDuMk4ptuST3m5q2OOcc,484
|
|
74
|
+
mxbiflow/ui/components/device_card/__init__.py,sha256=m6cwCdcppCEXTBRa0VQXG1HtgkYNrusQKoUgO1_IkI4,569
|
|
75
|
+
mxbiflow/ui/components/device_card/detector/beambreak_detector_card.py,sha256=X0BuACjZZZpKCjqrOGySEn8KiUlCHCyCSt_HwR5iFXI,998
|
|
76
|
+
mxbiflow/ui/components/device_card/detector/fusion_detector.py,sha256=RvEpKTspIjPqLH3eKJkO-rkQOWlB22NECyjOkllV5Go,1757
|
|
77
|
+
mxbiflow/ui/components/device_card/detector/mock_detector_card.py,sha256=OZcl5nSgGWsVminqtOzjLYiWwIJxle9S7Luh018h2MM,606
|
|
78
|
+
mxbiflow/ui/components/device_card/detector/rfid_detector.py,sha256=2U28nlShCQs0udB-bIP1Kl1A5VCXy_lxKtGYZr_tack,1452
|
|
79
|
+
mxbiflow/ui/components/device_card/device_card.py,sha256=mP6S74fOciDW1tvZS2vDTKU8iUjVgXA9iiNYA6vqDRE,2030
|
|
80
|
+
mxbiflow/ui/components/device_card/rewarder/mock_rewarder_card.py,sha256=SxlMgu_QKJYfVnCngzr5rqmTLHF0f-bVw4c3CT30M1k,606
|
|
81
|
+
mxbiflow/ui/components/device_card/rewarder/rpi_gpio_rewarder.py,sha256=lf18Oqx7eI1lWBVyuH-RgfqYb9zJU7-HiX_6CiqG8C4,1067
|
|
82
|
+
mxbiflow/ui/components/devices.py,sha256=1r8D0OBBdyXEBkkmd96Ir6OqarRSxzWiq8ZJgdGMOfY,5351
|
|
83
|
+
mxbiflow/ui/components/dialog/__init__.py,sha256=N_P4NFqf7H10XbWV6tkc5PJR-aT-huXFfD9D2eUCpv0,79
|
|
84
|
+
mxbiflow/ui/components/dialog/add_devices_dialog.py,sha256=DrcDfBOQZzjARlj-K9kSFQGriOdo6Q7oIf2Zr1SNX-s,1737
|
|
85
|
+
mxbiflow/ui/components/experiment_groups.py,sha256=9CwJ4g4cfhKv3-JO5y9Qv-HlJfGB_gcBQEtNola2zdM,4258
|
|
86
|
+
mxbiflow/ui/experiment_panel.py,sha256=LOsOsYT7GwOEl0p6XXWvYoF-ugua6QySB8maXTnjNRw,2824
|
|
87
|
+
mxbiflow/ui/mxbi_panel.py,sha256=jLET_x2KGTo4Fr4XN0qo2mV7052QlD5M3Tzt1CKlNLk,4828
|
|
88
|
+
mxbiflow/utils/logger.py,sha256=6pMngPkcs-TWfHbI3I75mNqvTXQCFEFjXL8t2DNhoNE,296
|
|
89
|
+
mxbiflow/utils/serial.py,sha256=xAOymmyoU6JvOTC0HFL3DK1tVkTiXPLsC0plLZYMLKA,274
|
|
90
|
+
mxbiflow-0.1.1.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
91
|
+
mxbiflow-0.1.1.dist-info/entry_points.txt,sha256=cGSAdRH0zM2dvODbfV1or4Hdhxpq7j6eyEjnV2dYaeE,62
|
|
92
|
+
mxbiflow-0.1.1.dist-info/METADATA,sha256=Ag6-jZjo4rVZmdzHcHMPziFtZ0NPrtwszbBPqu9er14,5869
|
|
93
|
+
mxbiflow-0.1.1.dist-info/RECORD,,
|