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

make hamilton heater shaker async #425

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
35 changes: 19 additions & 16 deletions pylabrobot/heating_shaking/hamilton.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
from enum import Enum
from typing import Literal

Expand Down Expand Up @@ -51,19 +52,21 @@ def serialize(self) -> dict:
"shaker_index": self.shaker_index,
}

def _send_command(self, command: str, **kwargs):
assert len(command) == 2, "Command must be 2 characters long"
args = "".join([f"{key}{value}" for key, value in kwargs.items()])
self.io.write(f"T{self.shaker_index}{command}id{str(self.command_id).zfill(4)}{args}".encode())

self.command_id = (self.command_id + 1) % 10_000
return self.io.read()
async def _send_command(self, command: str, **kwargs):
assert len(command) == 2, "Command must be 2 characters long"

args = "".join([f"{key}{value}" for key, value in kwargs.items()])
await asyncio.to_thread(self.io.write, f"T{self.shaker_index}{command}id{str(self.command_id).zfill(4)}{args}".encode())

self.command_id = (self.command_id + 1) % 10_000
response = await asyncio.to_thread(self.io.read)
return response
Comment on lines +55 to +63
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually i don't think the read or write themselves take so long and introducing multithreading leads to potential complications

i think it's better to do many small reads and asyncio.sleep in between

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it's better to do many small reads and asyncio.sleep in between

Shouldn't the read be awaitable? Such that a await self.io.read() should be sufficient? Otherwise each backend using the io layer needs to implement this logic again?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better idea, will go with that


async def shake(
self,
speed: float = 800,
direction: Literal[0, 1] = 0,
acceleration: int = 1_000,
acceleration: int = 500,
):
"""
speed: steps per second
Expand All @@ -83,7 +86,7 @@ async def stop_shaking(self):
await self._wait_for_stop()

async def _move_plate_lock(self, position: PlateLockPosition):
return self._send_command("LP", lp=position.value)
return await self._send_command("LP", lp=position.value)

async def lock_plate(self):
await self._move_plate_lock(PlateLockPosition.LOCKED)
Expand All @@ -93,34 +96,34 @@ async def unlock_plate(self):

async def _initialize_lock(self):
"""Firmware command initialize lock."""
result = self._send_command("LI")
result = await self._send_command("LI")
return result

async def _start_shaking(self, direction: int, speed: int, acceleration: int):
"""Firmware command for starting shaking."""
speed_str = str(speed).zfill(4)
acceleration_str = str(acceleration).zfill(5)
return self._send_command("SB", st=direction, sv=speed_str, sr=acceleration_str)
return await self._send_command("SB", st=direction, sv=speed_str, sr=acceleration_str)

async def _stop_shaking(self):
"""Firmware command for stopping shaking."""
return self._send_command("SC")
return await self._send_command("SC")

async def _wait_for_stop(self):
"""Firmware command for waiting for shaking to stop."""
return self._send_command("SW")
return await self._send_command("SW")

async def set_temperature(self, temperature: float):
"""set temperature in Celsius"""
temp_str = f"{round(10*temperature):04d}"
return self._send_command("TA", ta=temp_str)
return await self._send_command("TA", ta=temp_str)

async def get_current_temperature(self) -> float:
"""get temperature in Celsius"""
response = self._send_command("RT").decode("ascii")
response = await self._send_command("RT").decode("ascii")
temp = str(response).split(" ")[1].strip("+")
return float(temp) / 10

async def deactivate(self):
"""turn off heating"""
return self._send_command("TO")
return await self._send_command("TO")
Loading