Custom Scale Interaction

Note

Only available when USE_BOX_BOARD and SCALE_BOX are ON (in SETTINGS). Tare and calibrate the box scale from the MONITOR tab before using it.

While a task is running, the box scale is read in its own thread every period seconds (0.1 s by default) and the on_weight method of ScaleTriggerBase is called with every reading. By default it does nothing. You can override it to react to the weight (the animal stepping on a platform, a lever pressed with a given force, …).


Creating a custom ScaleTrigger

Create a file named scale_trigger.py inside your project’s code directory and define a class named ScaleTrigger that inherits from ScaleTriggerBase. The system will automatically detect it and use it instead of the default base class.

from village.custom_classes.scale_trigger_base import ScaleTriggerBase


class ScaleTrigger(ScaleTriggerBase):

    def __init__(self) -> None:
        super().__init__()
        self.period = 0.1  # seconds between readings
        self.on_platform = False

    def on_weight(self, weight: float, timestamp: float) -> None:
        """Called after every reading of the box scale.

        Available via self.task:
        - self.task.cam_box      — box camera (write_text, areas, position, …)
        - self.task.bpod         — Bpod controller (send_softcode_to_bpod, …)
        - self.task.gpio         — set_on()/set_off() for the output pin
        - any attribute defined in the task class
        """
        if weight > 10 and not self.on_platform:
            self.on_platform = True
            self.task.register_raspberry_event("PlatformIn", timestamp)
            self.task.bpod.send_softcode_to_bpod(1)
        elif weight < 5 and self.on_platform:
            self.on_platform = False
            self.task.register_raspberry_event("PlatformOut", timestamp)

Note

on_weight runs in the scale reader thread, not in the task thread. Keep it fast and avoid blocking calls: the next reading waits until it returns.

Choosing the period

A reading takes a few milliseconds and the thread sleeps between readings, so it barely loads the Raspberry Pi. The limit is the scale itself: it only gives about 10 new values per second, so a period below 0.1 s just repeats the same value. The minimum accepted is 0.02 s.

The last weight read is also available as scale_box.last_weight (from village.devices.scale import scale_box), without making a new reading.