Skip to content

Commit 5ba97fb

Browse files
committed
Merge branch 'develop'
2 parents e0415b4 + 523be56 commit 5ba97fb

2 files changed

Lines changed: 67 additions & 21 deletions

File tree

nodes/noisify_odom

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ from std_msgs.msg import String
3232

3333

3434
def _noisy(std_dev):
35-
return std_dev * np.random.randn()
35+
# Use the standard deviation as the mean as well as the std deviation
36+
# This feels super hacky but for me better represents wheel encoder error
37+
# usually perceived distance travelled will be greater than actual distance
38+
return np.random.normal(std_dev, std_dev)
3639

3740

3841
def _SE3_to_pose_msg(pose):
@@ -70,8 +73,10 @@ class PoseNoisifier(object):
7073
self._lock = threading.Lock()
7174

7275
self._start_pose = None
76+
self._last_time = None
7377

74-
self._accumulated_error = np.eye(4)
78+
self._nodom = np.eye(4)
79+
self._initialised = False
7580
self._last_vel = Twist()
7681

7782
self._tf = tf2_ros.TransformBroadcaster()
@@ -88,25 +93,69 @@ class PoseNoisifier(object):
8893

8994
def pub(self, odom_msg):
9095
with self._lock:
96+
97+
current_time = rospy.get_time()
98+
time_diff = current_time - self._last_time
9199
# Bail if we don't have valid data to work with
92100
if self._start_pose is None:
93101
return
94102

95-
# Translate our clean odom into a noisy odom
96-
noisy_odom = np.matmul(self._accumulated_error,
97-
sp.pose_msg_to_SE3(odom_msg.pose))
103+
# Initialise that which needs initialisation
104+
if not self._initialised:
105+
self._nodom = sp.pose_msg_to_SE3(odom_msg.pose)
106+
self._last_odom = sp.pose_msg_to_SE3(odom_msg.pose)
107+
self._initialised = True
108+
109+
# Calculate the velocity of the last segment of time using odometery.
110+
# Note, previous version used command velocity but this differed too much
111+
# from "true" velocity
112+
# TODO enhancement would be to use actual wheel rotations and translate that into
113+
# an estimate of velocity but that is too much for now. Current version thinks
114+
# it is stationary even if the wheels keep spinning as the robot hits a wall
115+
current_odom = sp.pose_msg_to_SE3(odom_msg.pose)
116+
odom_diff = np.matmul(np.linalg.inv(self._last_odom), current_odom)
117+
vel_angular = sp.rpy_from_SE3(odom_diff)[2]/time_diff # angular.z
118+
vel_linear = odom_diff[0,3]/time_diff # linear.x
119+
120+
# Calculate current noisy pose from starting point (noisy odom pose)
121+
# Current velocity with some level of error transformed into an expected pose
122+
# Between last and current odom reading
123+
# NOTE error is now usually positive multiplier to better simulate wheel encoder
124+
# errors (always think you have travelled further than you have)
125+
lin_vel_noisy = vel_linear + \
126+
vel_linear * _noisy(self.noise_linear)
127+
ang_vel_noisy = vel_angular + \
128+
vel_angular * _noisy(self.noise_angular)
129+
130+
# Turn velocities back into distances
131+
lin_move = lin_vel_noisy * time_diff
132+
ang_move = ang_vel_noisy * time_diff
133+
134+
self._nodom = np.matmul(
135+
self._nodom,
136+
np.matmul(
137+
sp.SE3_from_translation(lin_move),
138+
sp.SE3_from_yaw(ang_move)),
139+
)
98140

99-
# Figure out "localisation" transform from map to odom frame
141+
# Calculate the error between what we read here and the true odometry
142+
odom_error = np.matmul(sp.pose_msg_to_SE3(odom_msg.pose),
143+
np.linalg.inv(self._nodom))
144+
145+
# Calculate localisation transform from map to odom frame to accomodate for
146+
# calculated error
100147
localisation = np.matmul(self._start_pose,
101-
np.linalg.inv(self._accumulated_error))
148+
odom_error)
102149

103150
# Publish our messages
104151
o = Odometry()
105152
o.header.stamp = odom_msg.header.stamp
106153
o.header.frame_id = self.out_frame_odom
107154
o.child_frame_id = self.out_frame_robot
108-
o.pose.pose = _SE3_to_pose_msg(noisy_odom)
155+
o.pose.pose = _SE3_to_pose_msg(self._nodom)
109156
o.pose.covariance = odom_msg.pose.covariance
157+
# TODO establish whether this twist should be the cmd vel twist
158+
# or calculated "true" velocity
110159
o.twist.twist = self._last_vel
111160
self._pub_odom.publish(o)
112161

@@ -121,22 +170,19 @@ class PoseNoisifier(object):
121170
t.header.stamp = odom_msg.header.stamp
122171
t.header.frame_id = self.out_frame_odom
123172
t.child_frame_id = self.out_frame_robot
124-
t.transform = _SE3_to_tf_msg(noisy_odom)
173+
t.transform = _SE3_to_tf_msg(self._nodom)
125174
self._tf.sendTransform(t)
126175

127-
# Update accumulated noise
128-
self._accumulated_error = np.matmul(
129-
self._accumulated_error,
130-
np.matmul(
131-
sp.SE3_from_translation(self._last_vel.linear.x *
132-
_noisy(self.noise_linear)),
133-
sp.SE3_from_yaw(self._last_vel.angular.z *
134-
_noisy(self.noise_angular))),
135-
)
176+
# Update time and odom
177+
self._last_time = current_time
178+
self._last_odom = current_odom
179+
180+
136181

137182
def update_start_pose(self, start_pose_msg):
138183
with self._lock:
139-
self._accumulated_error = np.eye(4)
184+
self._initialised = False
185+
self._last_time = rospy.get_time()
140186
self._start_pose = sp.wxyzXYZ_to_SE3(*np.array([
141187
float(x.strip()) for x in start_pose_msg.data.replace(
142188
'[', '').replace(']', '').split(',')

src/robot_callbacks.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ def _get_noisy_pose(controller, child_frame):
4848
odom_t_child = sp.tf_msg_to_SE3(
4949
controller.tf_buffer.lookup_transform('odom', child_frame,
5050
rospy.Time()))
51+
5152
# Noisy child should be init pose + odom_t_child
52-
return world_t_init_pose * odom_t_child
53+
return np.matmul(world_t_init_pose, odom_t_child)
5354

5455

5556
def _current_pose(controller):
@@ -120,7 +121,6 @@ def _move_to_pose(goal, publisher, controller):
120121
# Get latest position error
121122
current = sp.SE3_to_SE2(_current_pose(controller))
122123
error = np.matmul(np.linalg.inv(current), g)
123-
124124
# Calculate values used in the controller
125125
rho = np.linalg.norm(error[0:2, 2])
126126
alpha = np.arctan2(error[1, 2], error[0, 2])

0 commit comments

Comments
 (0)