Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

draft #10000

Closed
wants to merge 4 commits into from
Closed

draft #10000

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion hardware/opentrons_hardware/scripts/sensor_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ async def handle_capacitive_sensor(
)
csv = CSVFormatter.build(metadata, list(metadata.to_dict().keys()))
# autozero
await capacitive.poll(messenger, pipette_mount, 10, timeout=10)
await capacitive.get_baseline(messenger, pipette_mount, 10, 10, timeout=10)
end_time = start_time + timedelta(minutes=command.minutes)
while datetime.now() < end_time:
data = await capacitive.read(messenger, pipette_mount, offset=False, timeout=10)
Expand Down
59 changes: 54 additions & 5 deletions hardware/opentrons_hardware/sensors/fdc1004.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,33 @@

from typing import Optional

from opentrons_hardware.drivers.can_bus.can_messenger import CanMessenger
import logging

from opentrons_hardware.drivers.can_bus.can_messenger import (
CanMessenger,
)
from opentrons_hardware.firmware_bindings.constants import SensorType, NodeId
from opentrons_hardware.firmware_bindings.messages.message_definitions import (
BindSensorOutputRequest,
)
from opentrons_hardware.firmware_bindings.messages.fields import (
SensorOutputBindingField,
SensorTypeField,
)
from opentrons_hardware.sensors.utils import (
ReadSensorInformation,
PollSensorInformation,
WriteSensorInformation,
SensorDataType,
)

from opentrons_hardware.firmware_bindings.messages.payloads import (
BindSensorOutputRequestPayload,
)
from .sensor_abc import AbstractAdvancedSensor
from .scheduler import SensorScheduler
from opentrons_hardware.firmware_bindings.constants import SensorOutputBinding

log = logging.getLogger(__name__)


class CapacitiveSensor(AbstractAdvancedSensor):
Expand All @@ -26,16 +42,49 @@ def __init__(
) -> None:
"""Constructor."""
super().__init__(zero_threshold, stop_threshold, offset, SensorType.capacitive)
self._scheduler = SensorScheduler()

async def bind_to_sync(
self,
can_messenger: CanMessenger,
node_id: NodeId,
binding: SensorOutputBinding = SensorOutputBinding.sync,
timeout: int = 1,
) -> None:
"""Send a BindSensorOutputRequest."""
await can_messenger.send(
node_id=node_id,
message=BindSensorOutputRequest(
payload=BindSensorOutputRequestPayload(
sensor=SensorTypeField(self._sensor_type),
binding=SensorOutputBindingField(binding),
)
),
)

async def get_report(
self,
node_id: NodeId,
can_messenger: CanMessenger,
timeout: int = 1,
) -> Optional[SensorDataType]:
"""This function retrieves ReadFromResponse messages.

This is meant to be called after a bind_to_sync call,
with the sensor being bound to "report".
"""
return await self._scheduler.read(can_messenger, node_id)

async def poll(
async def get_baseline(
self,
can_messenger: CanMessenger,
node_id: NodeId,
poll_for: int,
poll_for_ms: int,
sample_rate: int,
timeout: int = 1,
) -> Optional[SensorDataType]:
"""Poll the capacitive sensor."""
poll = PollSensorInformation(self._sensor_type, node_id, poll_for)
poll = PollSensorInformation(self._sensor_type, node_id, poll_for_ms)
scheduler = SensorScheduler()
return await scheduler.run_poll(poll, can_messenger, timeout)

Expand Down
65 changes: 56 additions & 9 deletions hardware/opentrons_hardware/sensors/mmr920C04.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,34 @@
from typing import Optional

from opentrons_hardware.drivers.can_bus.can_messenger import CanMessenger
from opentrons_hardware.firmware_bindings.constants import SensorType, NodeId
from opentrons_hardware.firmware_bindings.constants import (
SensorType,
NodeId,
SensorOutputBinding,
)
from opentrons_hardware.sensors.utils import (
ReadSensorInformation,
PollSensorInformation,
WriteSensorInformation,
SensorDataType,
)
from opentrons_hardware.firmware_bindings.messages.message_definitions import (
BindSensorOutputRequest,
)
from opentrons_hardware.firmware_bindings.messages.payloads import (
BindSensorOutputRequestPayload,
)
from opentrons_hardware.firmware_bindings.messages.fields import (
SensorOutputBindingField,
SensorTypeField,
)

import logging
from .scheduler import SensorScheduler
from .sensor_abc import AbstractAdvancedSensor

log = logging.getLogger(__name__)


class PressureSensor(AbstractAdvancedSensor):
"""MMR820C04 Driver."""
Expand All @@ -25,18 +42,50 @@ def __init__(
) -> None:
"""Constructor."""
super().__init__(zero_threshold, stop_threshold, offset, SensorType.pressure)
self._scheduler = SensorScheduler()

async def poll(
async def bind_to_sync(
self,
can_messenger: CanMessenger,
node_id: NodeId,
binding: SensorOutputBinding = SensorOutputBinding.sync,
timeout: int = 1,
) -> None:
"""Send a BindSensorOutputRequest."""
await can_messenger.send(
node_id=node_id,
message=BindSensorOutputRequest(
payload=BindSensorOutputRequestPayload(
sensor=SensorTypeField(self._sensor_type),
binding=SensorOutputBindingField(binding),
)
),
)

async def get_report(
self,
node_id: NodeId,
can_messenger: CanMessenger,
timeout: int = 1,
) -> Optional[SensorDataType]:
"""This function retrieves ReadFromResponse messages.

This is meant to be called after a bind_to_sync call,
with the sensor being bound to "report".
"""
return await self._scheduler.read(can_messenger, node_id)

async def get_baseline(
self,
can_messenger: CanMessenger,
node_id: NodeId,
poll_for_ms: int,
sample_rate: int,
timeout: int = 1,
) -> Optional[SensorDataType]:
"""Poll the pressure sensor."""
"""Poll the capacitive sensor."""
poll = PollSensorInformation(self._sensor_type, node_id, poll_for_ms)
scheduler = SensorScheduler()
return await scheduler.run_poll(poll, can_messenger, timeout)
return await self._scheduler.run_poll(poll, can_messenger, timeout)

async def poll_temperature(
self,
Expand All @@ -61,8 +110,7 @@ async def read(
) -> Optional[SensorDataType]:
"""Poll the read sensor."""
read = ReadSensorInformation(self._sensor_type, node_id, offset)
scheduler = SensorScheduler()
return await scheduler.send_read(read, can_messenger, timeout)
return await self._scheduler.send_read(read, can_messenger, timeout)

async def read_temperature(
self,
Expand All @@ -84,8 +132,7 @@ async def write(
) -> None:
"""Write to a register of the pressure sensor."""
write = WriteSensorInformation(self._sensor_type, node_id, data)
scheduler = SensorScheduler()
await scheduler.send_write(write, can_messenger)
await self._scheduler.send_write(write, can_messenger)

async def send_zero_threshold(
self,
Expand Down
27 changes: 25 additions & 2 deletions hardware/opentrons_hardware/sensors/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
WriteToSensorRequestPayload,
BaselineSensorRequestPayload,
)
from opentrons_hardware.firmware_bindings.messages.fields import SensorTypeField
from opentrons_hardware.firmware_bindings.messages.fields import (
SensorTypeField,
)

from opentrons_hardware.sensors.utils import (
ReadSensorInformation,
Expand All @@ -39,7 +41,6 @@
Int32Field,
)


log = logging.getLogger(__name__)


Expand Down Expand Up @@ -105,6 +106,28 @@ async def send_read(
data = await asyncio.wait_for(
self._wait_for_response(sensor.node_id, reader), timeout
)
print("wait_for_response done")
except asyncio.TimeoutError:
log.warning("Sensor Read timed out")
finally:
return data

async def read(
self,
can_messenger: CanMessenger,
node_id: NodeId,
) -> Optional[SensorDataType]:
"""Helper function for the get_report sensor driver.

This simply retrieves CAN messages without first
sending a ReadFromSensorRequest.
"""
data: Optional[SensorDataType] = SensorDataType.build(0)
with WaitableCallback(can_messenger) as reader:
try:
data = await self._wait_for_response(node_id, reader)
print(" read data = ", data)

except asyncio.TimeoutError:
log.warning("Sensor Read timed out")
finally:
Expand Down
36 changes: 33 additions & 3 deletions hardware/opentrons_hardware/sensors/sensor_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
from abc import ABC, abstractmethod

from typing import Optional

from opentrons_hardware.drivers.can_bus.can_messenger import CanMessenger
from opentrons_hardware.firmware_bindings.constants import NodeId, SensorType
from opentrons_hardware.firmware_bindings.constants import (
NodeId,
SensorType,
)
from opentrons_hardware.sensors.utils import SensorDataType
from opentrons_hardware.firmware_bindings.constants import SensorOutputBinding
from .scheduler import SensorScheduler


class AbstractBasicSensor(ABC):
Expand Down Expand Up @@ -45,6 +49,7 @@ def __init__(
self._stop_threshold: float = stop_threshold
self._offset: float = offset
self._sensor_type: SensorType = sensor_type
self._scheduler = SensorScheduler()

@property
def zero_threshold(self) -> float:
Expand Down Expand Up @@ -77,11 +82,23 @@ def offset(self, offset: float) -> None:
self._offset = offset

@abstractmethod
async def poll(
async def bind_to_sync(
self,
can_messenger: CanMessenger,
node_id: NodeId,
binding: SensorOutputBinding = SensorOutputBinding.sync,
timeout: int = 1,
) -> None:
"""Send a BindSensorOutputRequest."""
...

@abstractmethod
async def get_baseline(
self,
can_messenger: CanMessenger,
node_id: NodeId,
poll_for_ms: int,
sample_rate: int,
timeout: int = 1,
) -> Optional[SensorDataType]:
"""Poll the sensor for data."""
Expand All @@ -97,3 +114,16 @@ async def send_zero_threshold(
) -> Optional[SensorDataType]:
"""Send the zero threshold to the sensor."""
...

async def get_report(
self,
node_id: NodeId,
can_messenger: CanMessenger,
timeout: int = 1,
) -> Optional[SensorDataType]:
"""This function retrieves ReadFromResponse messages.

This is meant to be called after a bind_to_sync call,
with the sensor being bound to "report".
"""
...
12 changes: 11 additions & 1 deletion hardware/opentrons_hardware/sensors/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
from typing import List, overload

from opentrons_hardware.firmware_bindings.constants import NodeId, SensorType
from opentrons_hardware.firmware_bindings.utils.binary_serializable import Int32Field
from opentrons_hardware.firmware_bindings.messages.fields import (
SensorOutputBindingField,
)
from opentrons_hardware.firmware_bindings.utils.binary_serializable import (
Int32Field,
)


@dataclass
Expand All @@ -28,6 +33,11 @@ def build(cls, data: Int32Field) -> "SensorDataType":
def build(cls, data: List[int]) -> "SensorDataType":
...

@overload
@classmethod
def build(cls, data: SensorOutputBindingField) -> "SensorDataType":
...

@classmethod
def build(cls, data): # type: ignore[no-untyped-def]
"""Build function for sensor data type."""
Expand Down
Loading