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

ROS2 RVIZ Wheel Motion Discrepancy #15

Closed
00Doc-T opened this issue Mar 17, 2024 · 16 comments
Closed

ROS2 RVIZ Wheel Motion Discrepancy #15

00Doc-T opened this issue Mar 17, 2024 · 16 comments

Comments

@00Doc-T
Copy link

00Doc-T commented Mar 17, 2024

I'm running the ROS2 Control package, and have it plugged into a robot I'm developing. I'm using ODrive Botwheels, which should have encoder counts of 3200.

My model is scaled appropriately, and the wheel sizes are correct in my URDF.

The wheel is turning in RVIZ2 approximately 1/6 of the amount it is turning in reality. Has anyone else seen a similar issue.

There are two approaches that I can reason, to adjust things.

First would be to change the encoder counts per revolution in odrivetool setup.

The second would be to add a scaling factor into the hardware interface.

Am I missing something obvious here. Has anyone else seen a similar issue?

Thanks sincerely

-Chris

@anthonywebb
Copy link

Hi Chris. Funny you should mention it because we have seen this as well but have not had a chance yet to isolate or track it down. I also noticed that traveling 1 meter in the real world did not show a meter traveled in rviz. Probably should loop in @samuelsadok to see what might be off here.

@00Doc-T
Copy link
Author

00Doc-T commented Mar 18, 2024

I checked:
odrv0.axis0.pos_estimate
Out[19]: 1.0148515701293945
This is showing that one revolution of the wheel (perfomed by hand), is resulting in one revolution in the odrive.

I also used ros2 topic echo /joint_states
Which showed that the wheel was moving exactly 1 rotation, when moved a complete rotation in joint states.

It's the TF frame that is the issue, which is odd.

@anthonywebb
Copy link

@samuelsadok is there a problem with the hardware interface causing this discrepancy?

@samuelsadok
Copy link
Member

Since you say it's off by 1/6, it sounds a lot like an "off by 2*PI" error. ODrive typically uses turns and turns/s as units. I found it hard to find conclusive documentation on what ros2_control / ROS uses, and which part of the system defines it. But from what you say it sounds like it uses rad and rad/s.
Maybe you know where to find conclusive documentation? We could just add the factor in, but we'd also need to know what the right torque unit is.

Places that need to be changed:

msg.Input_Pos = axis.pos_setpoint_;
msg.Vel_FF = axis.vel_input_enabled_ ? axis.vel_setpoint_ : 0.0f;
msg.Torque_FF = axis.torque_input_enabled_ ? axis.torque_setpoint_ : 0.0f;

(and below)
pos_estimate_ = msg.Pos_Estimate;
vel_estimate_ = msg.Vel_Estimate;

(and below)

@anthonywebb
Copy link

I’ve found mention around that it is indeed radians/second. I’ve asked Denis for confirmation and also asked about the torque units as well. I assume he will chime in here with more clarity @samuelsadok

@anthonywebb
Copy link

@samuelsadok i have found other diffdrive hardware interfaces that use radians for position and radians/second for velocity. All use nM for torque.

The other piece of this that is suspect is are we properly handling the conversion from rad/s back to rev/s (or m/s whatever the odrive expects for velocity) when we send the command back to the odrive?

@samuelsadok
Copy link
Member

Thanks for digging into it. It seems there's really no definitive spec and we need to go by convention here.

I made a corresponding PR here: #17 but I don't have the hardware set up to test it. @00Doc-T if you can confirm that it fixes the discrepancy I will merge it.

@anthonywebb yes, both directions (ROS => ODrive / ODrive => ROS) are scaled in the PR.

@00Doc-T
Copy link
Author

00Doc-T commented Apr 2, 2024 via email

@harborhoffer
Copy link

I can confirm this does indeed fix the discrepancy.

@samuelsadok
Copy link
Member

ok, merged!

@00Doc-T
Copy link
Author

00Doc-T commented Apr 6, 2024

I updated the files. Now motion is appropriately transformed in RVIZ. Has anyone noted that their motors are now underpowered pretty heavily?

@anthonywebb
Copy link

It was remarkable to me how little force I had to apply to stop the wheel from turning. I was trying to remember if I tested that before using the canbus control or not. But yes I feel like I could use some more spunk out of the motor. Probably need some more concrete tests.

@00Doc-T
Copy link
Author

00Doc-T commented Apr 11, 2024

@samuelsadok

To follow this up, commenting out the 2pi changes in the sections regarding velocity, and leaving them in regards to position, along with changing the controllers.yaml file open loop to false fixed all issues. RVIZ has the correct positions, and the velocities are appropriate.

Code as below.

       if (axis.pos_input_enabled_) {
            Set_Input_Pos_msg_t msg;
            msg.Input_Pos = axis.pos_setpoint_ / (2 * M_PI);
            msg.Vel_FF = axis.vel_input_enabled_ ? (axis.vel_setpoint_   /*(2 * M_PI)*/) : 0.0f;
            msg.Torque_FF = axis.torque_input_enabled_ ? axis.torque_setpoint_ : 0.0f;
            axis.send(msg);
        } else if (axis.vel_input_enabled_) {
            Set_Input_Vel_msg_t msg;
            msg.Input_Vel = axis.vel_setpoint_ /*/ (2 * M_PI)*/;
            msg.Input_Torque_FF = axis.torque_input_enabled_ ? axis.torque_setpoint_ : 0.0f;
            axis.send(msg);
        } else if (axis.torque_input_enabled_) {
            Set_Input_Torque_msg_t msg;
            msg.Input_Torque = axis.torque_setpoint_;
            axis.send(msg);
        } else {
            // no control enabled - don't send any setpoint
        }
    }

    return return_type::OK;
}

void ODriveHardwareInterface::on_can_msg(const can_frame& frame) {
    for (auto& axis : axes_) {
        if ((frame.can_id >> 5) == axis.node_id_) {
            axis.on_can_msg(timestamp_, frame);
        }
    }
}

void Axis::on_can_msg(const rclcpp::Time&, const can_frame& frame) {
    uint8_t cmd = frame.can_id & 0x1f;

    auto try_decode = [&]<typename TMsg>(TMsg& msg) {
        if (frame.can_dlc < Get_Encoder_Estimates_msg_t::msg_length) {
            RCLCPP_WARN(rclcpp::get_logger("ODriveHardwareInterface"), "message %d too short", cmd);
            return false;
        }
        msg.decode_buf(frame.data);
        return true;
    };

    switch (cmd) {
        case Get_Encoder_Estimates_msg_t::cmd_id: {
            if (Get_Encoder_Estimates_msg_t msg; try_decode(msg)) {
                pos_estimate_ = msg.Pos_Estimate * (2 * M_PI);
                vel_estimate_ = msg.Vel_Estimate /** (2 * M_PI)*/;

    pose_covariance_diagonal : [0.001, 0.001, 0.001, 0.001, 0.001, 0.01]
    twist_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.01]

    open_loop: false
    enable_odom_tf: true

    cmd_vel_timeout: 0.5

@samuelsadok
Copy link
Member

Hmm this would contradict our earlier understanding that rad/s is the expected convention.

Do you mind sharing the launchfile (and additional files) that you're using to test this? Then I can see if I see any other issues.

And again, if you can refer to any documentation that defines the unit convention, that would also help.

@00Doc-T
Copy link
Author

00Doc-T commented May 12, 2024

I uploaded a most recent copy of my code, and provided you access.

@samuelsadok
Copy link
Member

Thanks! Given that the repo is private, can you hit me up on Discord or email ([email protected]) to let me know further details? E.g. which command to run and what to expect. If the issue can be seen without hardware that would be easiest cause I don't have a BotWheel Explorer near me, otherwise I would have to remote into one at another place. If you wanna demo the issue in a call that might also be an option.

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

No branches or pull requests

4 participants