-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Introduce [Timed]RangefinderPoint. #1357
Introduce [Timed]RangefinderPoint. #1357
Conversation
So, this PR is about getting rid of direct uses of Sorry for the PR linediff size. |
@@ -30,14 +39,14 @@ message CompressedPointCloud { | |||
message TimedPointCloudData { | |||
int64 timestamp = 1; | |||
transform.proto.Vector3f origin = 2; | |||
repeated transform.proto.Vector4f point_data = 3; | |||
repeated TimedRangefinderPoint point_data = 3; |
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.
Is it ok to break compatibility here?
If not, perhaps we could rename the third field to point_data_legacy
and have the new TimedRangefinderPoint as the 4th field?
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.
yes, please do that. Let's not break it for now. We will have plenty of opportunities to do so :)
cartographer/sensor/range_data.cc
Outdated
std::transform( | ||
proto.misses().begin(), proto.misses().end(), std::back_inserter(misses), | ||
static_cast<Eigen::Vector3f (*)(const transform::proto::Vector3f&)>( | ||
transform::ToEigen)); |
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.
I'd say that this monstrosity disappearing is the highlight of this PR
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.
I cannot stop being surprised that we have such code in the first place... :)
@@ -190,7 +190,8 @@ LocalTrajectoryBuilder3D::AddRangeData( | |||
// maximum range. This way the free space up to the maximum range will | |||
// be updated. | |||
accumulated_range_data_.misses.push_back( | |||
origin_in_local + options_.max_range() / range * delta); | |||
hit_in_local.RestrictDistanceFromOrigin(origin_in_local, |
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 avoid breaking the data flow and discarding possible additional metadata here by
(1) computing hit_in_local
using operator*(Rigid, RangefinderPoint)
which is metadata-friendly
(2) avoiding creating a completely new RangefinderPoint
by using a RestrictDistanceFromOrigin
method, which is again metadata-friendly
@ojura Please consider presenting your design in the open house (today or in two weeks) to make sure implementation goes in the right direction. |
To address some concerns from yesterday: I believe this change does not increase complexity significantly and that it makes code more readable. It is made clear that a rangefinder point is being passed, and not just any |
aeb815c
to
f2edc50
Compare
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.
I like what you're doing here.
cartographer/io/points_batch.h
Outdated
@@ -52,7 +53,7 @@ struct PointsBatch { | |||
int trajectory_id; | |||
|
|||
// Geometry of the points in the map frame. | |||
std::vector<Eigen::Vector3f> points; | |||
cartographer::sensor::PointCloud points; |
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.
nit: just sensor::PointCloud
.
cartographer/sensor/point_cloud.h
Outdated
@@ -29,14 +30,14 @@ namespace sensor { | |||
|
|||
// Stores 3D positions of points. | |||
// For 2D points, the third entry is 0.f. | |||
typedef std::vector<Eigen::Vector3f> PointCloud; | |||
typedef std::vector<RangefinderPoint> PointCloud; |
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.
nit:
using PointCloud = std::...
here and below
@@ -20,6 +20,15 @@ option java_outer_classname = "Sensor"; | |||
|
|||
import "cartographer/transform/proto/transform.proto"; | |||
|
|||
message RangefinderPoint { | |||
transform.proto.Vector3f position = 1; |
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.
I am not sure I like 'position' name here. In ROS it was called just a point.
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.
Sure. We're not bound by ROS conventions here, though. A RangefinderPoint
having a point
member sounds kind of odd to me.
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.
When I see position
I always confuse it with pose
which also has orientation. What about x_y_z
or coordinates
? Or leave it as position
.
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.
At the robotics classes at my uni, we were taught the following definition of a robot pose: The combination of position and orientation is referred to as the pose of an object.
So if that's okay with you, I'd leave it as position :-)
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.
Yeah, it is ok. :) I did not have robotics classes :)
} | ||
|
||
message TimedRangefinderPoint { | ||
RangefinderPoint rangefinder_point = 1; |
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.
inline the type: transform.proto.Vector3f point = 1;
. It can happen that RangefinderPoint
has some metadata that we do not really want in TimedRangefinderPoint
.
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.
Okay, should the C++ implementation follow this as well? I.e. TimedRangefinderPoint
contains a Vector3f
?
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.
Yep
@@ -30,14 +39,14 @@ message CompressedPointCloud { | |||
message TimedPointCloudData { | |||
int64 timestamp = 1; | |||
transform.proto.Vector3f origin = 2; | |||
repeated transform.proto.Vector4f point_data = 3; | |||
repeated TimedRangefinderPoint point_data = 3; |
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.
yes, please do that. Let's not break it for now. We will have plenty of opportunities to do so :)
cartographer/sensor/range_data.cc
Outdated
std::transform( | ||
proto.misses().begin(), proto.misses().end(), std::back_inserter(misses), | ||
static_cast<Eigen::Vector3f (*)(const transform::proto::Vector3f&)>( | ||
transform::ToEigen)); |
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.
I cannot stop being surprised that we have such code in the first place... :)
@@ -32,7 +32,7 @@ struct TimedPointCloudData { | |||
|
|||
struct TimedPointCloudOriginData { | |||
struct RangeMeasurement { | |||
Eigen::Vector4f point_time; | |||
sensor::TimedRangefinderPoint point_time; |
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.
omit sensor::
.
namespace cartographer { | ||
namespace sensor { | ||
|
||
// Stores 3D position of a point observed by a rangefinder sensor. |
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.
- Please, use composition here.
- All data members should be in
private
section of the class. - Try to get rid of friend functions.
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.
About the friend operator*
: we typically apply a multiplication with a Rigid3
pose estimate from the left. Unfortunately, a member operator*
only allows this
as the left operand. So I see two solutions: either an overloaded friend operator*
like this, or a member function e.g. RangefinderPoint::ToLocal(Rigid3 pose_estimate)
which would do a left multiplication.
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.
Also, about composition: you mentioned you would inline the Vector3f
in TimedRangefinderPoint
proto. Does this mean that the C++ class should be the same?
Slicing a TimedRangefinderPoint
into a RangefinderPoint
then means a little bit of more work. Should I put it in a TimedRangefinderPoint::ToRangefinderPoint
member?
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.
Make them structs. As in proto.
struct TimedRangefinderPoint {
proto::RangefinderPoint ToProto() const;
Eigen::Vector3f position_;
float time_;
};
struct RangefinderPoint {
proto::RangefinderPoint ToProto() const;
Eigen::Vector3f position_;
};
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.
Isn't _
only for private members? Also, I think structs shouldn't have methods, IIRC ToProto/FromProto
are implemented as functions outside structs.
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.
In structs, you do not need _
, sorry, i just copied. Structs should not have complicated logic, yes. But serialization/deserialization can be put there. Up to you.
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.
Okay, cool. I'm only missing one more detail: where to implement discarding time? Member TimedRangefinderPoint::ToRangefinderPoint
or standalone function?
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.
Do you need it? Isn't it just a call to constructor of RangefinderPoint(timed_point.position)
?
Okay, the nits should be fixed. I updated the two new classes to be structs. |
cartographer/sensor/range_data.cc
Outdated
for (const auto& point_proto : proto.returns()) | ||
returns.push_back(FromProto(point_proto)); | ||
} else { | ||
returns.reserve(proto.returns_legacy().size()); |
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.
This should take care of deserializing old .pbstreams
return lhs.position == rhs.position && lhs.time == rhs.time; | ||
} | ||
|
||
RangefinderPoint FromProto( |
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.
@pifon2a WDYT about inlining all of these? Point processing functions seem like they could cause a bottleneck if not inlined.
namespace cartographer { | ||
namespace sensor { | ||
|
||
// Stores 3D position of a point observed by a rangefinder sensor. |
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.
Do you need it? Isn't it just a call to constructor of RangefinderPoint(timed_point.position)
?
const Eigen::Vector3f origin_in_local = | ||
range_data_poses[i] * | ||
synchronized_data.origins.at(synchronized_data.ranges[i].origin_index); | ||
const Eigen::Vector3f hit_in_local = range_data_poses[i] * hit.head<3>(); | ||
const Eigen::Vector3f delta = hit_in_local - origin_in_local; | ||
sensor::RangefinderPoint hit_in_local = |
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 I am not mistaken, you can write it like:
sensor::RangefinderPoint hit_in_local{range_data_poses[i] * hit.position}
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.
I disagree with this and the comment below. The whole point of this PR is to enable adding metadata by changing only rangefinder_point.h
. The rest of Cartographer should be written with an assumption that there is some hidden metadata in RangefinderPoint
. This metadata should be preserved throughout the SLAM pipeline. By constructing a completely new point here, and not using operator*
, we would discard this data.
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.
Could you provide an example of such metadata? And when it will be added to Cartographer.
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.
Please see the comment below. My primary motivation for this is keeping the laser ID (i.e. which laser of the e.g. 16 lasers on the lidar has observed the point). Currently, I do not plan on upstreaming this, but I would like to be able to do this with minimal interventions to Cartographer, hence this PR. But if there's interest, sure, why not.
Another possible metadata that we might want to add is the sensor ID, to help resolve issues like #947.
float time; | ||
}; | ||
|
||
template <class T> |
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.
since there is no metadata yet, I doubt that the operators*() are needed at all.
return proto; | ||
} | ||
|
||
inline RangefinderPoint ToRangefinderPoint( |
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.
ToRangefinderPoint/ToTimedRangefinderPoint are also not needed.
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.
For my use case, they absolutely are. If I decide to add an int LaserId
to [Timed]RangefinderPoint
in my fork, I want to be able to do this only by updating rangefinder_point.h
. In this case, I would update ToRangefinderPoint
to also copy over LaserId
. I want to avoid having to update the rest of Cartographer codebase for this. This is why I insist on using operator*
and these two functions.
if (proto.point_data().size() > 0) { | ||
timed_point_cloud.reserve(proto.point_data().size()); | ||
for (const auto& timed_point_proto : proto.point_data()) | ||
timed_point_cloud.push_back(FromProto(timed_point_proto)); |
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.
nit: unfortunately, style guide requires {} here.
@pifon2a Have I managed to convince you about |
Juraj, I want to take another look and then we merge today. Let me finish
some stuff first.
--
Cheers,
Alex
…On Fri, Aug 10, 2018 at 1:49 PM Juraj Oršulić ***@***.***> wrote:
@pifon2a <https://github.com/pifon2a> Have I managed to convince you?
Ready to merge?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1357 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AfA_b56DJ25SeEkqkXxDphZVLeEAhDCsks5uPXNNgaJpZM4VoQha>
.
|
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.
ok, looks fine.
RFC: cartographer-project/rfcs#36