-
Notifications
You must be signed in to change notification settings - Fork 0
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
F #he 948 improve calibration process #56
base: noetic-devel
Are you sure you want to change the base?
Conversation
…e we actually have data points when we first call fit_sphere(...) which prevents three numpy RuntimeWarnings (we were sometimes calling np.std on an empty list)
…. Speeds up computation but potentially reduces accuracy. Needs testing
…r the next sphere_fit. Speeds up computation time
src/polhemus_ros_driver/knuckle_position_calibration_action_server.py
Outdated
Show resolved
Hide resolved
src/polhemus_ros_driver/knuckle_position_calibration_action_server.py
Outdated
Show resolved
Hide resolved
src/polhemus_ros_driver/knuckle_position_calibration_action_server.py
Outdated
Show resolved
Hide resolved
…antly faster), and fix parameter from launch file
I reviewed and would accept, but first perhaps it would be useful to check how the calibration quality changes when changing the tf_data_divisor as we have discussed |
Agreed, checking that now |
…s execution time being too long (the number of msgs recieved was system-dependant and made it impossible to compare accuracy of calibration fits between runs). Modified code to save all tf messsages and process them in get_knuckle_positions. Added code to load a bag file for testing/tuning/comparing accuracy of calibration fits. Now that _load_tf_callback is recieving all the messages, the average number of msgs per second has gone up from ~15 to ~100, drastically increasing the computation of sphere fit. But, now we can add code to downsample to a KNOWN number of 'datapoints per second', giving the same performance across systems and lettings us actually figure out how many datapoints per second we need for a reasonable calibration fit
…pling to approximately a 'known' number of samples-per-second. Switched to MarkerArrays for faster marker publishing. Also general tidying
It turns out that the Added code to plug in a bag file of glove movements for testing purposes and moved the processing out of the callback so that the code catches every The bag file I've been testing with has ~120 messages per second. Setting
Setting
Setting
(Tests performed on a Ryzen 9 3900X) So, we should tune this value when we test on an events laptop in spectrum house soon |
while I remember, must update the rviz configs in sr_glove_calibration_gui before merging this. Will do this during testing |
self._marker_array.markers.append(data_point_marker) | ||
|
||
def get_number_of_markers(self): | ||
return self._marker_array.markers.__len__() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although valid, why not
return self._marker_array.markers.__len__() | |
return len(self._marker_array.markers) |
? Is the len method of marker_array does anything different than the len()
operator on iterable?
def __init__(self, side: str = "right"): | ||
def __init__(self, side: str = "right", | ||
desired_datapoints_per_sec: int = 20, | ||
testing_bag_file_path: str = ''): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually, when an argument is optional, we set it to None
, because an empty string remains a string, which is the valid "type" of data.
Is there a reason you used the empty string?
If you want to change this to None, then this becomes
testing_bag_file_path: str = ''): | |
testing_bag_file_path: Optional[str] = None) -> None: |
while adding from typing import Optional
def __init__(self, side: str = "right"): | ||
def __init__(self, side: str = "right", | ||
desired_datapoints_per_sec: int = 20, | ||
testing_bag_file_path: str = ''): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
testing_bag_file_path: str = ''): | |
testing_bag_file_path: str = '') -> None: |
to add the output type hint
@@ -73,10 +73,10 @@ class DataMarker(Marker): | |||
""" Class to store data about a marker to be published to rviz. """ | |||
_id = 0 | |||
|
|||
def __init__(self, frame_id: str, point: Point, color: ColorRGBA, size=0.002): | |||
def __init__(self, frame_id: str, time_stamp: rospy.Time, point: Point, color: ColorRGBA, size=0.002): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding output type hint
def __init__(self, frame_id: str, time_stamp: rospy.Time, point: Point, color: ColorRGBA, size=0.002): | |
def __init__(self, frame_id: str, time_stamp: rospy.Time, point: Point, color: ColorRGBA, size=0.002) -> None: |
self._marker_array = MarkerArray() | ||
self._pub = rospy.Publisher(f"/data_point_marker_{self.hand_prefix}", MarkerArray, queue_size=1000) | ||
|
||
def add_marker(self, frame_id: str, time_stamp: rospy.Time, point: Point, color: ColorRGBA): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def add_marker(self, frame_id: str, time_stamp: rospy.Time, point: Point, color: ColorRGBA): | |
def add_marker(self, frame_id: str, time_stamp: rospy.Time, point: Point, color: ColorRGBA) -> None: |
self._action_server.publish_feedback(_feedback) | ||
|
||
sub.unregister() | ||
self._get_knuckle_positions(hand) | ||
if self._testing_bag_file_path == '': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if self._testing_bag_file_path == '': | |
if self._testing_bag_file_path is None': |
|
||
def _get_knuckle_positions(self, hand: Hand, plot=False): | ||
def _get_knuckle_positions(self, hand: Hand, time_elapsed: float, plot=False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing output type hint. I know it's not your fault, but this naming convention of _get_x
that does not return anything (i.e. not a getter) confuses me a little... I think it would be better called _compute_knuckle_positions
. What do you think?
""" | ||
Updates the current solution for all fingers on the selected hand. | ||
@param hand: Selected hand | ||
@param time_elapsed: Time elapsed since the start of this calibration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you describe what's the unit? seconds? milliseconds?
@@ -509,11 +619,16 @@ def get_calibration_quality(hand: Hand): | |||
""" | |||
quality_list: List[float] = [] | |||
for finger in fingers: | |||
if len(hand.finger_data[finger]['residual']) == 0: | |||
print('no data recieved') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
print('no data recieved') | |
rospy.loginfo(f'No data received for finger {finger}') |
@@ -509,11 +619,16 @@ def get_calibration_quality(hand: Hand): | |||
""" | |||
quality_list: List[float] = [] | |||
for finger in fingers: | |||
if len(hand.finger_data[finger]['residual']) == 0: | |||
print('no data recieved') | |||
quality_list.append(np.std(hand.finger_data[finger]['residual'])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still add the standard deviation of a non-existing distribution?
…adow-robot/polhemus_ros_driver into F_#HE_948_improve_calibration_process
Proposed changes
Now runs faster / uses less compute
Fix progress bar logic
/tf callback was missing most messages due to callback execution time being too long. Now saves all messages and extracts a configurable subsample (can specify an approximate number of evenly distributed datapoints per second to keep)
Save result of previous sphere_fit as initial_guess for next sphere_fit (reduces computation time)
Add small sleep after tf subscriber, sometimes the subscriber warm-up time was longer than the first progress checkpoint, giving us empty lists which then got passed to np.std and threw numpy RuntimeWarnings
Added functionality to read from a rosbag for testing purposes
Publishing a MarkerArray instead of lots of Markers (saves cpu time)
Checklist
Before posting a PR ensure that from each of the below categories AT LEAST ONE BOX HAS BEEN CHECKED. If more than one category is applicable then more can be checked. Also ensure that the proposed changes have been filled out with relevant information for reviewers.
Tests
Documentation