From af0809aacc3ff66bb05fdff72f43601089e2bfbd Mon Sep 17 00:00:00 2001 From: David Vo Date: Fri, 1 Mar 2019 09:37:14 +1100 Subject: [PATCH 1/3] magicbot: Add tunable update listener method This adds a way to add a callback for NT updates to tunables. --- magicbot/magic_tunable.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/magicbot/magic_tunable.py b/magicbot/magic_tunable.py index c45a5cd..5a65803 100644 --- a/magicbot/magic_tunable.py +++ b/magicbot/magic_tunable.py @@ -1,7 +1,7 @@ import functools import inspect import warnings -from typing import Generic, Optional, TypeVar +from typing import Callable, Generic, Optional, TypeVar from networktables import NetworkTables from ntcore.value import Value @@ -67,6 +67,7 @@ def execute(self): # "__doc__", "_mkv", "_nt", + "_update_cb", ) def __init__( @@ -87,16 +88,35 @@ def __init__( self._mkv = Value.getFactory(default) self._nt = NetworkTables + self._update_cb = None def __get__(self, instance, owner) -> V: if instance is not None: return instance._tunables[self].value return self - def __set__(self, instance, value) -> None: + def __set__(self, instance, value: V) -> None: v = instance._tunables[self] self._nt._api.setEntryValueById(v._local_id, self._mkv(value)) + def set_callback(self, callback: Callable[[V], None]) -> None: + """ + Set a method to be called when the tunable is updated over NetworkTables. + + This can be useful, for example, for changing PID gains on a + motor controller on the fly:: + + class Component: + pid: ... + + kP = tunable(0.01) + + @kP.set_callback + def set_kP(self, value: float) -> None: + self.pid.setP(value) + """ + self._update_cb = lambda inst, notif: callback(inst, notif.value.value) + def setup_tunables(component, cname: str, prefix: Optional[str] = "components") -> None: """ @@ -137,6 +157,13 @@ def setup_tunables(component, cname: str, prefix: Optional[str] = "components") ) tunables[prop] = ntvalue + if prop._update_cb: + prop._nt._api.addEntryListenerById( + ntvalue._local_id, + functools.partial(prop._update_cb, component), + NetworkTables.NotifyFlags.UPDATE, + ) + component._tunables = tunables From a56077e1a1dd78faa0877a2696e3a3a1312ed075 Mon Sep 17 00:00:00 2001 From: David Vo Date: Fri, 1 Mar 2019 10:21:24 +1100 Subject: [PATCH 2/3] tunable: Use one lambda as listener callback --- magicbot/magic_tunable.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/magicbot/magic_tunable.py b/magicbot/magic_tunable.py index 5a65803..258a3d7 100644 --- a/magicbot/magic_tunable.py +++ b/magicbot/magic_tunable.py @@ -115,7 +115,7 @@ class Component: def set_kP(self, value: float) -> None: self.pid.setP(value) """ - self._update_cb = lambda inst, notif: callback(inst, notif.value.value) + self._update_cb = callback def setup_tunables(component, cname: str, prefix: Optional[str] = "components") -> None: @@ -160,7 +160,7 @@ def setup_tunables(component, cname: str, prefix: Optional[str] = "components") if prop._update_cb: prop._nt._api.addEntryListenerById( ntvalue._local_id, - functools.partial(prop._update_cb, component), + lambda notif, cb=prop._update_cb: cb(component, notif.value.value), NetworkTables.NotifyFlags.UPDATE, ) From ee2ba91d5a35e1ff72bcf62e068b54487e0c5058 Mon Sep 17 00:00:00 2001 From: David Vo Date: Fri, 1 Mar 2019 10:29:19 +1100 Subject: [PATCH 3/3] tunable: Add warnings about callback usage --- magicbot/magic_tunable.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/magicbot/magic_tunable.py b/magicbot/magic_tunable.py index 258a3d7..4c8ad8d 100644 --- a/magicbot/magic_tunable.py +++ b/magicbot/magic_tunable.py @@ -114,6 +114,13 @@ class Component: @kP.set_callback def set_kP(self, value: float) -> None: self.pid.setP(value) + + .. note:: + The callback will be called on the NetworkTables I/O thread + (not the main robot thread). + + .. warning:: + This only supports instance methods on the same object as the tunable. """ self._update_cb = callback