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

[RSDK-732] Create Quaternion and corresponding FFI namespace #10

Merged
merged 6 commits into from
Nov 10, 2022

Conversation

gvaradarajan
Copy link
Member

No description provided.

/// represented according to the Tait-Bryan formalism and applied
/// in the Z-Y'-X" order (where Z -> yaw, Y -> pitch, X -> roll).
/// The return value is a list of [roll, pitch, yaw]
pub fn to_euler_angles(&self) -> [f64;3] {
Copy link
Member

Choose a reason for hiding this comment

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

It may be worthwhile to allow the user to specify the rotation order for to/from euler angles.

https://github.com/go-gl/mathgl/blob/v1.0.0/mgl64/quat.go#L265

Copy link
Member

Choose a reason for hiding this comment

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

Specifying the rotation order is just a permutation at the very end (or very beginning), yeah? That sounds like a nice-to-have, but not something for the MVP. I wouldn't write anything more than a TODO for it yet (but am open to being wrong!).

Copy link
Member Author

Choose a reason for hiding this comment

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

we don't currently though, is there a reason for that?

Copy link
Member Author

Choose a reason for hiding this comment

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

any chance we can leave this as a follow-up? I'm pretty sure the most popular representation is ZYX

Copy link
Member

Choose a reason for hiding this comment

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

The reason we don't currently is because the library I linked exists and does it :)
The other two common (at least, I've seen them be in use) representations are XYZ and ZYZ.
But I don't think it needs to gate this PR, as long as it goes on a to-do list (or a library that already implements this is found)

Copy link
Member

Choose a reason for hiding this comment

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

Here's one for the common extrinsic and intrinsic representations, a quick google found it. I like the idea of having this as our own feature should we need it/ something external causes bugs. I think we should keep it to Tait-Bryan which Gautham has written in for the time being.

Copy link
Member

@penguinland penguinland left a comment

Choose a reason for hiding this comment

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

I haven't looked at the FFI file yet, but here's a start. Looks very good so far!

pub mod vector3;
pub mod quaternion;
Copy link
Member

Choose a reason for hiding this comment

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

I worry that I'm sounding like a broken record at this point, but I still think these files should all end in newlines, because not ending in a new line is not POSIX-compliant and some text editors aren't going to like that. I'd still be happy to help you configure your text editor to do this automatically, if you want. If you want to do it on your own, I think a decent starting point is https://thoughtbot.com/blog/no-newline-at-end-of-file

Copy link
Member

Choose a reason for hiding this comment

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

Not a broken record; not ending in a newline is AFAIK explicitly against our internal style guide as well, and will break all sorts of things. Please make sure you keep calling this out wherever you see it.

src/spatialmath/vector3.rs Show resolved Hide resolved
src/spatialmath/quaternion.rs Show resolved Hide resolved
/// represented according to the Tait-Bryan formalism and applied
/// in the Z-Y'-X" order (where Z -> yaw, Y -> pitch, X -> roll).
/// The return value is a list of [roll, pitch, yaw]
pub fn to_euler_angles(&self) -> [f64;3] {
Copy link
Member

Choose a reason for hiding this comment

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

Specifying the rotation order is just a permutation at the very end (or very beginning), yeah? That sounds like a nice-to-have, but not something for the MVP. I wouldn't write anything more than a TODO for it yet (but am open to being wrong!).

roll = roll_sin_pitch_cos.atan2(roll_cos_pitch_cos);
}


Copy link
Member

Choose a reason for hiding this comment

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

Mild preference to get rid of one of these blank lines. One blank line is enough inside a function.

}

pub fn conjugate(&self) -> Self {
Self { real: self.real, i: self.i * -1.0, j: self.j * -1.0, k: self.k * -1.0 }
Copy link
Member

Choose a reason for hiding this comment

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

DIscussion question: I had expected -1.0 * self.i, rather than self.i * -1.0, because normally when you write math, the numbers come before the letters. Do other folks prefer this ordering instead? I'm not against it, but it did surprise me a little.


/// Allocates the vector to the heap with a stable memory address and
/// returns the raw pointer (for use by the FFI interface)
pub(crate) fn to_raw_pointer(&self) -> *mut Self {
Copy link
Member

Choose a reason for hiding this comment

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

Naive question: does this have to be here, or could we put it in the FFI stuff instead with the code it goes with, so we don't need the comment? Maybe there's a reason it needs to be here, but I don't see it yet.

Copy link
Member Author

Choose a reason for hiding this comment

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

I can move, l'll do it for vector as well

impl std::ops::Add<Quaternion> for Quaternion {
type Output = Quaternion;

fn add(self, _rhs: Quaternion) -> Quaternion {
Copy link
Member

Choose a reason for hiding this comment

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

Normally, having a variable start with an underscore in Rust means "suppress the compiler warnings about unused variables. We know this one isn't used yet." but this one is used. Can we rename it rhs? Same question for several more ops below, too.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't know why I made this an _, I can remove

let mut quat = Quaternion::new(
0.0,
(1.0_f64 / 3.0_f64).sqrt() * 0.5,
(1.0_f64 / 3.0_f64).sqrt() * -0.5,
Copy link
Member

Choose a reason for hiding this comment

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

I'm mildly surprised that we're multiplying on the right by a constant, and a negative one at that. Could these lines become -0.5 * (1.0_f64 / 3.0_f64).sqrt()) and similar? Maybe that's too nitpicky and this is good as-is.

#[test]
fn get_scaled_returns_scaled_quaternion() {
let quat = Quaternion::new(0.1, 0.2, 0.3, 0.4);
let quat_orig = Quaternion::new(0.1, 0.2, 0.3, 0.4);
Copy link
Member

Choose a reason for hiding this comment

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

Mild preference for let quat_orig = quat.clone() here. By defining it twice, it feels like we don't have a single point of truth on this thing.

src/spatialmath/quaternion.rs Show resolved Hide resolved
/// represented according to the Tait-Bryan formalism and applied
/// in the Z-Y'-X" order (where Z -> yaw, Y -> pitch, X -> roll).
/// The return value is a list of [roll, pitch, yaw]
pub fn to_euler_angles(&self) -> [f64;3] {
Copy link
Member

Choose a reason for hiding this comment

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

Here's one for the common extrinsic and intrinsic representations, a quick google found it. I like the idea of having this as our own feature should we need it/ something external causes bugs. I think we should keep it to Tait-Bryan which Gautham has written in for the time being.

src/ffi/spatialmath/quaternion.rs Outdated Show resolved Hide resolved
src/ffi/spatialmath/quaternion.rs Show resolved Hide resolved
src/spatialmath/quaternion.rs Show resolved Hide resolved
src/spatialmath/quaternion.rs Show resolved Hide resolved
/// The return value is a pointer to a list of [roll, pitch, yaw]
/// as C doubles
#[no_mangle]
pub unsafe extern "C" fn quaternion_to_euler_angles(quat_ptr: *const Quaternion) -> *const c_double {
Copy link
Member

Choose a reason for hiding this comment

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

is thera a function to free this?

Copy link
Member Author

Choose a reason for hiding this comment

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

to free the quaternion? Or the euler angles?

Copy link
Member

Choose a reason for hiding this comment

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

to free the *const c_double, I couldn't find the proper fucntion


/// Allocates the quaternion to the heap with a stable memory address and
/// returns the raw pointer (for use by the FFI interface)
fn to_raw_pointer(quat: &Quaternion) -> *mut Quaternion {
Copy link
Member

Choose a reason for hiding this comment

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

this is somewhat misleading, you're actually copying the quaternion before boxing it

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah this is definitely fair, but you asking this brings up something I wish I thought about earlier: should I have done it this way? Should I be copying the quaternion before returning it? I think it's still fine, but I'm not sure

Copy link
Member

Choose a reason for hiding this comment

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

I think it's okay the only type of scenario where I see this being an issue is if you own a reference in some rust data structure and use that reference to change the quaternion you sent to FFI using to_raw_pointer in this case the code calling the FFI won't see the changes made on the Rust side. Given that we use simple data structures we should not run into this so ok just keep this in mind as we grow the library

Copy link
Member

@npmenard npmenard left a comment

Choose a reason for hiding this comment

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

Looks great!! Done with first pass.

You should run cargo clippy and fix the errors it surface (could be done in a 2nd PR)

Euler angles are in radians but it's not specified either in the doc or the function

All the unsafe functions should have a #safety section especially since you are working with pointers.

Cloning vs Copy, you have to decide which one you're using mixing them is a bit weird especially since they essentially do the same. I would stick with copying since its only 3/4 f64 !

@gvaradarajan
Copy link
Member Author

gvaradarajan commented Nov 9, 2022

Looks great!! Done with first pass.

You should run cargo clippy and fix the errors it surface (could be done in a 2nd PR)

Euler angles are in radians but it's not specified either in the doc or the function

All the unsafe functions should have a #safety section especially since you are working with pointers.

Cloning vs Copy, you have to decide which one you're using mixing them is a bit weird especially since they essentially do the same. I would stick with copying since its only 3/4 f64 !

I'm going to correct the clippy errors from vector in this PR, I'll just forget to do it later

@gvaradarajan gvaradarajan requested a review from npmenard November 9, 2022 19:46
Copy link
Member

@npmenard npmenard left a comment

Choose a reason for hiding this comment

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

LGTM

@gvaradarajan gvaradarajan merged commit 67781fa into viamrobotics:main Nov 10, 2022
@gvaradarajan gvaradarajan deleted the RSDK-732-orientations branch December 5, 2022 23:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants