-
Notifications
You must be signed in to change notification settings - Fork 97
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
Is it time for Moments? #118
Comments
I'm going to need to do some more research to fully understand the topic. One thing I have noticed so far is that moments are quantities. Torque is the moment of force. Volume is the moment of area. |
No, volume is not the moment of area. The characteristic that makes moments what they are is that they're proportional to a power of the radius from a frame of reference. Volumes and areas don't work that way, the 2L softdrink bottle doesn't get larger as it moves away from me... but the same force exerts more torque as it moves away. It's a subtype relation, non-moment quantities can be thought of as order zero moments (proportional to the radius from the measured thing to me, raised to the zeroth power), but moments in general cannot be thought of as quantities, since the measurement depends on the frame of reference. To give a good example of moments not behaving like quantities, imagine you're driving a front wheel drive electric car at a constant non-zero speed (in constant conditions). The motor is applying some constant torque about the front axle to combat rolling resistance and drag. But that same force measures differently from the back axle. It doesn't torque about the back axle at all, were it not for friction against the road the back wheels wouldn't spin. Other quantities don't work this way, the front and back axles agree on how much current is flowing through the motor, for example. Edit: Another way to see that non-zero moments aren't quantities is that they're not represented as individual numbers. More properly a torque is actually a 3-vector of quantities (since we're in 3D space and it's a first moment. For moments of inertia it takes 3^2=9 numbers since its a second moment in 3D space), so no single float can hold one (except for zeroth moments where you need 3^0=1 float). Of course, if we were to represent them that way we'd lose the "zero cost abstraction" property. For my use case (robotics) the frames of reference are actually discrete (this motor, that motor, etc), so I'd rather have the zero cost abstractions than physics-prof perfection, but I can see how others might want continuous frame representations (that said, I'm not volunteering to write the continuous frame version... and you probably wouldn't want me to anyway, I only learned this stuff yesterday). |
Poke. Any thoughts on this? |
Sorry for the delays, my recent free time went into releasing v0.22.0. I'll make this more of a priority over the next few days and respond with my thoughts. |
No rush, just making sure it's not forgotten |
The simplest formula to calculate the My inclination at this point is to leave moments, as an explicit type, out of Regarding your original proposal I believe the first two generic arguments are redundant. The |
I mean, if you want to just base it on dimensional analysis then Torque is the same thing as Energy, as are On the topic of my original proposal (which I would like to continue discussing with you (if you're up for it) since I now plan to roll it into its own crate (I need it at work)), I think I did a bad job explaining it from the get go. I'm not proposing to keep the length dimension(s) in a separate collection of bits than the quantity dimension. It's a true zero cost abstraction, so if the representation is f64 then a moment will only occupy those 64 bits. Because of that there needs to be some other way to prevent adding first moments with second moments (etc). Similarly, I think I botched the explanation of the If you'd rather hold off on adding moments that's fine, I'm perfectly happy to scratch my own itch. Could I persuade you to be a code reviewer for the new crate I'm going to start? |
I think it is more that I don't fully understand the usage of moments vs. what can already be done with quantities. Perhaps you could come up with some example code showing usage with what you expect things to look like and what compile-time checks would happen. Also if you have any thoughts about when you would want to use a moment vs. a quantity. If you want to create a branch in your fork of |
Sure, I plan to use moments for a couple of different projects, but the most obvious one is a driver for an ATI Axia Force/Torque sensor. Currently, it streams the following to users:
There are a few problems with this. First, the lack of units on the torques. Second, with the API designed this way it doesn't expose the frame of reference that the sensor is currently using (it can report in either the frame centered on its face, or at a configured Tool Center Point (which the industry confusingly shortens to TCP despite most of these robots being network accessible), and the frame its reporting in can be switched at will during operation). I easily could add a field for it, but that seems easy miss compared to being forced to take the frame into account. Alternatively, I could add an enum for the various frames, and then use something like a TorqueMagnitude quantity, but that still has the problems I ran into in that other issue where it's not clear how a Length and a Force know what |
As to why I'm leaning towards moments instead of quantities, partially it's to prohibit nonsense math (adding between frames), and partially it's to avoid having to create a new unit for each of the moment types I'm going to need for a different project (an RTDE driver for a UR5 robot arm) that exposes not just torques, but also rotational inertias and possibly one other moment that isn't coming to mind off the top of my head. |
It sounds like, at a more pragmatic level, you want to embed additional information (e.g. reference frames) as (type) parameters. I can certainly see how this is useful (especially for your use case), but I’m not certain whether it makes sense as part of the base I think this is a really cool idea and I’d love to see it happen (and it’d be interesting to see how it could work technically), but I foresee this being a great deal of complexity that I’m not sure belongs in the base Just my unsolicited thoughts. |
Stubbed out a bit of implementation before running out of time. Thoughts? Anything crucial missing? Re-doing all the // Order (rank?) is D::L.
struct Moment<F, D, U, V> {
frame: PhantomData<F>,
quantity: Quantity<D, U, V>
}
mod torque {
type Dimension = super::Dimension<...>;
type Torque<Frame, U, V> = Moment<Frame, Dimension, U, V>;
}
// Add, Sub, Mul, Div, One, Zero... all need impls. As a slight aside do you intend/desire to turn |
You might be overestimating my current Rust skill level. What is In that example, why does Torque have the U parameter? |
Similar to how Basically, you're going to need I'm starting to think this doesn't need to be as complex as I had feared! |
Thanks for the details @Aehmlo. One thing to add is that right now all quantities have the One thing I started thinking about is that using a type parameter for |
I'm not sure if it works in this case, but the whole use case for Problem with that is that it requires bumping the minimum Rust version (I believe |
(Thought I posted this yesterday, came back today and saw it was still a draft!)
trait T {}
impl T for f32 {}
impl T for f64 {}
fn f(x: i32) -> impl T {
if x > 0 { 0.0_f32 } else { 0.0_f64 }
}
fn main() {
} |
Yeah, I was thinking that we might have branching within the method body that would prevent |
I don't have a good answer for how to make the type runtime switchable (without resorting to an enum). If I stop trying to enforce that does it simplify this into the realm of the doable? I like @iliekturtles' implementation suggestion. I assume we can constrain it such that D::L is is non-negative? |
An See the following example proving that a #![allow(dead_code)]
use std::marker::PhantomData;
use typenum::{Cmp, Integer, IsGreater, Same, B1, N1, P1, Z0};
trait Dimension {
type L: Integer;
type M: Integer;
}
struct Quantity<D>
where
D: Dimension + ?Sized,
{
dimension: PhantomData<D>,
}
struct Moment<D>
where
D: Dimension + ?Sized,
D::L: Cmp<Z0> + IsGreater<Z0>,
<D::L as IsGreater<Z0>>::Output: Same<B1>,
{
quantity: Quantity<D>,
}
type M0 = Moment<Dimension<L = Z0, M = Z0>>;
type M1 = Moment<Dimension<L = P1, M = Z0>>;
type M2 = Moment<Dimension<L = N1, M = Z0>>;
fn main() {
// error: the trait bound `Same<B1>` is not satisfied.
//let _m0 = M0 { quantity: Quantity { dimension: PhantomData } };
let _m1 = M1 { quantity: Quantity { dimension: PhantomData, }, };
// let _m2 = M2 { quantity: Quantity { dimension: PhantomData } };
} |
Yeah, that looks great, way better than my initial straw man. Is the generic frame parameter really all that bad of a thing? |
A frame parameter vs a sized frame field have trade-offs. See #91 where the same essential issue exists for methods that have a generic parameter // Function requires run-time check to ensure that the sensor is set to the desired explicit
// frame. All uses of the torque after reading are checked at compile time. The frame can't
// be changed at run-time.
fn read_torque() -> Torque<ExplicitFrame> { ... } // Function requires run-time check to ensure that the sensor is set to the caller-given
// frame. All uses of torque after reading are checked at compile time. The `F` parameter
// will essentially infect all methods in the call-stack. There are limited options to change
// the frame at run-time.
fn read_torque<F>() -> Torque<F> { ... } // Torque needs a sized frame field to hold the sensor's frame. Provides the most flexibility
// at run-time but also requires run-time checks whenever the torque is used and the
// frame is relevant.
fn read_torque() -> Torque { ... } |
In pursuit of #117 I've been self educating on moments, what they are and what they mean, and I don't think that
Kind
s are the best way to implement them (although I'll be the first to admit that I'm new to this, so feel free to stomp all over what I'm saying, I welcome the opportunity to learn from this).I believe that a Moment belongs in the same category as a
Quantity
, or perhaps even higher thanQuantity
, since quantities can be thought of as zeroth moments. So a quantity has a kind, but a quantity is a moment.So, as a straw man proposal how do you feel about
Where math is permitted between moments when their orders are
Z0
, or when their orders and frames match (and, obviously, if the math would be otherwise allowed by the quantities). Then you could do something to the effect ofetc. I realize this isn't totally fleshed out, sorry about that, I'm brand new to this... but hopefully there's enough here to see what I mean?
The text was updated successfully, but these errors were encountered: