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

F #he 948 improve calibration process #56

Open
wants to merge 25 commits into
base: noetic-devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
611aa77
fix progress bar logic
Jun 13, 2023
7018f5b
tf subscriber takes time to start up. Added a small sleep to make sur…
Jun 13, 2023
aa51421
add 'divisor' to tf callback, lets us only save every 'x' tf messages…
Jun 13, 2023
a6da349
save results from previous sphere_fit and use as the initial guess fo…
Jun 13, 2023
dec9b13
lint
Jun 13, 2023
814c95c
tidying
Jun 13, 2023
e024ce5
removed unused import
Jun 13, 2023
5ed88bf
add data divisor as input parameter (also raise exception on not-an-int)
Jun 14, 2023
17d5fd4
add data divisor as input parameter (also raise exception on not-an-int)
Jun 14, 2023
717d929
fix initial guess storage (was per hand, now per finger, now signific…
Jun 14, 2023
3b99a89
actually apply the fix I thought I'd apply in the previous commit
Jun 14, 2023
47c845d
turns out '_load_tf_callback' was missing ~80% of messages due to it'…
Jun 14, 2023
2a8e44e
now saves all tf messages and processes outside the callback, downsam…
Jun 15, 2023
c8cb706
make sure is valid for large values of
Jun 15, 2023
fefb9b8
add comment to explain
Jun 15, 2023
5955143
now set timer rate to desired_num_datapoints_per_sec for testing mode…
Jun 16, 2023
6992110
update default num datapoints per sec to 60
Jun 26, 2023
daf4b72
fix difference between bags and live tf messages, address PR comments
Jun 26, 2023
c39a539
Merge branch 'F_#HE_948_improve_calibration_process' of github.com:sh…
Jun 26, 2023
368f107
oops
Jun 26, 2023
c575a51
lint
Jun 26, 2023
4dad4ee
Merge branch 'noetic-devel' into F_#HE_948_improve_calibration_process
carebare47 Aug 15, 2023
c82377f
Merge branch 'noetic-devel' into F_#HE_948_improve_calibration_process
carebare47 Aug 24, 2023
385df1a
fixing cal score calc
Aug 31, 2023
60b5fcf
lint
Aug 31, 2023
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: 2 additions & 0 deletions launch/start.launch
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<arg name="boresight_calibration_file_path" default="$(find polhemus_ros_driver)/config"/>
<arg name="boresight_calibration_file_name" default="$(arg product_type)_calibration.yaml"/>
<arg name="boresight_calibration_file" default="$(arg boresight_calibration_file_path)/$(arg boresight_calibration_file_name)"/>
<arg name="calibration_data_divisor" default="1"/>
bdenoun marked this conversation as resolved.
Show resolved Hide resolved

<node pkg="polhemus_ros_driver" type="polhemus_tf_broadcaster" name="$(arg node_name)" output="screen">
<rosparam param="boresight_calibration_file" subst_value="True">$(arg boresight_calibration_file)</rosparam>
Expand All @@ -45,6 +46,7 @@

<node name="sr_knuckle_calibration" pkg="polhemus_ros_driver" type="knuckle_position_calibration_action_server.py" output="screen">
<param name="side" value="$(arg hands)" type="string"/>
<param name="calibration_data_divisor" value="$(arg calibration_data_divisor)" type="int"/>
</node>

</launch>
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA

import math
import os
from enum import Enum

Expand Down Expand Up @@ -102,8 +101,9 @@ def __init__(self, _hand_prefix: str):
class SrGloveCalibration:
SOURCE_TO_KNUCKLE_LIMITS = [[-0.1, -0.1, -0.1], [0.1, 0.1, 0.1]]
FINGER_LENGTH_LIMITS = [0.03, 0.15]
NUMBER_OF_CHECKPOINTS = 4

def __init__(self, side: str = "right"):
def __init__(self, side: str = "right", tf_data_divisor: int = 5):
"""
Initializes the calibration action server and the interactive marker server.
@param side: The hand(s) to calibrate - can be left, right or both
Expand Down Expand Up @@ -140,6 +140,14 @@ def __init__(self, side: str = "right"):
# Action server allowing the GUI to trigger and monitor a calibration
self._action_server = actionlib.SimpleActionServer("/calibration_action_server", CalibrateAction,
execute_cb=self._calibration, auto_start=False)
# How many times during calibration should we calculate the sphere fit and update quality %
self._progress_period = 1.0 / self.NUMBER_OF_CHECKPOINTS
if not isinstance(tf_data_divisor, int):
raise TypeError("tf_data_divisor must be an integer")

# Only save every 'x'th glove data point for calibration - trade-off between accuracy and computation time
self._tf_data_divisor = tf_data_divisor
self._tf_data_counter = 0
self._action_server.start()

def _update_current_knuckle_tf(self, hand: Hand):
Copy link

Choose a reason for hiding this comment

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

Suggested change
def _update_current_knuckle_tf(self, hand: Hand):
def _update_current_knuckle_tf(self, hand: Hand) -> None:

Expand Down Expand Up @@ -336,6 +344,8 @@ def _initialize_finger_data(self, hand: Hand):
hand.finger_data[finger]['residual'] = 0
hand.finger_data[finger]['data'] = []
hand.finger_data[finger]['center'] = self._create_marker(hand, finger, COLORS[i].value)
hand.finger_data[finger]['last_center_estimate'] = None
hand.finger_data[finger]['last_radius_estimate'] = None
self._marker_server.insert(hand.finger_data[finger]['center'])

def _create_marker(self, hand: Hand, finger: str, color):
Expand Down Expand Up @@ -392,18 +402,20 @@ def _create_control(quaternion: Quaternion, name: str):

def _load_tf_callback(self, data):
""" Callback for received TF data. """
for individual_transform in data.transforms:
for hand in self._hands.values():
for color_index, finger in enumerate(fingers):
if individual_transform.child_frame_id == hand.finger_data[finger]['polhemus_tf_name']:
pos = [individual_transform.transform.translation.x,
individual_transform.transform.translation.y,
individual_transform.transform.translation.z]

hand.finger_data[finger]['data'].append(pos)
data_point_marker = DataMarker(hand.polhemus_base_name, Point(*pos),
COLORS[color_index].value)
hand.pub.publish(data_point_marker)
if self._tf_data_counter % self._tf_data_divisor == 0:
bdenoun marked this conversation as resolved.
Show resolved Hide resolved
for individual_transform in data.transforms:
for hand in self._hands.values():
for color_index, finger in enumerate(fingers):
if individual_transform.child_frame_id == hand.finger_data[finger]['polhemus_tf_name']:
pos = [individual_transform.transform.translation.x,
Copy link

Choose a reason for hiding this comment

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

Suggested change
pos = [individual_transform.transform.translation.x,
position = [individual_transform.transform.translation.x,

individual_transform.transform.translation.y,
individual_transform.transform.translation.z]

hand.finger_data[finger]['data'].append(pos)
Copy link

Choose a reason for hiding this comment

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

Suggested change
hand.finger_data[finger]['data'].append(pos)
hand.finger_data[finger]['data'].append(position)

data_point_marker = DataMarker(hand.polhemus_base_name, Point(*pos),
COLORS[color_index].value)
hand.pub.publish(data_point_marker)
self._tf_data_counter += 1

def _calibration(self, goal: CalibrateGoal):
"""
Expand All @@ -428,6 +440,8 @@ def _calibration(self, goal: CalibrateGoal):
_result = CalibrateResult()

sub = rospy.Subscriber("/tf", TFMessage, self._load_tf_callback, queue_size=10)
rospy.sleep(0.5) # Ensure the tf subscriber has had time to start receiving messages
current_progress = 0.0
while rospy.Time.now().to_sec() - start < goal.time:
if self._action_server.is_preempt_requested():
rospy.loginfo("Calibration stopped.")
Expand All @@ -436,9 +450,10 @@ def _calibration(self, goal: CalibrateGoal):
break

_feedback.progress = ((rospy.Time.now().to_sec() - start)) / goal.time
if math.floor(_feedback.progress * 100) % 25 == 0 and math.floor(_feedback.progress * 100) != 0:
if (_feedback.progress - current_progress) > self._progress_period and _feedback.progress < 1.0:
self._get_knuckle_positions(hand)
_feedback.quality = self.get_calibration_quality(hand)
current_progress += self._progress_period
self._action_server.publish_feedback(_feedback)

sub.unregister()
Expand Down Expand Up @@ -483,13 +498,24 @@ def _get_knuckle_positions(self, hand: Hand, plot=False):
hand.pub.publish(solution_marker)
sphere_fit = SphereFit(data=hand.finger_data[finger]['data'], plot=plot)

initial_guess = None
if (hand.finger_data[finger]['last_center_estimate'] is not None and
hand.finger_data[finger]['last_radius_estimate'] is not None):
initial_guess = []
initial_guess.extend(hand.finger_data[finger]['last_center_estimate'].tolist())
initial_guess.append(hand.finger_data[finger]['last_radius_estimate'])

radius, center, residual = sphere_fit.fit_sphere(
SrGloveCalibration.SOURCE_TO_KNUCKLE_LIMITS[0], SrGloveCalibration.SOURCE_TO_KNUCKLE_LIMITS[1],
SrGloveCalibration.FINGER_LENGTH_LIMITS[0], SrGloveCalibration.FINGER_LENGTH_LIMITS[1])
SrGloveCalibration.FINGER_LENGTH_LIMITS[0], SrGloveCalibration.FINGER_LENGTH_LIMITS[1],
initial_guess=initial_guess)

if plot:
sphere_fit.plot_data()

hand.finger_data[finger]['last_center_estimate'] = center
hand.finger_data[finger]['last_radius_estimate'] = radius

hand.finger_data[finger]['residual'] = residual
hand.finger_data[finger]['length'].append(np.around(radius, 4))

Expand All @@ -516,4 +542,5 @@ def get_calibration_quality(hand: Hand):
if __name__ == "__main__":
rospy.init_node('sr_knuckle_calibration')
hand_side = rospy.get_param("~side", "both")
sr_glove_calibration = SrGloveCalibration(side=hand_side)
calibration_data_divisor = int(rospy.get_param("~calibration_data_divisor", 5))
sr_glove_calibration = SrGloveCalibration(side=hand_side, tf_data_divisor=calibration_data_divisor)