modelling gearbox backlash

Post Reply
keithmgould
Posts: 12
Joined: Thu May 31, 2018 5:21 pm

modelling gearbox backlash

Post by keithmgould » Thu Jun 21, 2018 5:50 pm

Hello!

I have a DC Motor with a gearbox and the gearbox gives backlash[1], in this case between dc motor and final shaft due to loose gears. It's about 0.1512 rads (or 8.663 degrees). I'd like to include this backlash in a motor model. Did not see much reference to "backlash" in this forum's history. Wondering if anyone has done it, or thoughts/brainstorm on suggestions?

[EDIT] All I have at the moment is a simple rotational joint, attached to a wheel. The goal is that when I change direction of the joint's rotation, the backlash will be reflected. So if the joint is rotating in a positive direction and I switch to a negative direction, I don't want the wheel to reflect this until the joint has rotated 8.663 degrees in negative direction. Of course I'm happy to add any amount of links and joints in between, if that is what is necessary.

Keith

1. https://en.wikipedia.org/wiki/Backlash_(engineering)
Last edited by keithmgould on Fri Jun 22, 2018 4:35 pm, edited 2 times in total.

User avatar
drleviathan
Posts: 431
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: modelling gearbox backlash

Post by drleviathan » Fri Jun 22, 2018 3:47 pm

It sounds like an interesting project. More info please.

You already have a working motor model using Bullet but it does not yet have the right amount of backlash? Or have you not even begun implementing the model but want to know if you would be able to model the backlash before you start?

There have been other posts about modeling mechanical contraptions with Bullet. For example this one about algorithmically designed doohickeys.

keithmgould
Posts: 12
Joined: Thu May 31, 2018 5:21 pm

Re: modelling gearbox backlash

Post by keithmgould » Fri Jun 22, 2018 4:33 pm

Hello, and thanks for responding. I've added a new section to the main description above which I believe answers your question. Thank you for any thoughts!

User avatar
drleviathan
Posts: 431
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: modelling gearbox backlash

Post by drleviathan » Sun Jun 24, 2018 1:49 pm

I can think of a few ways that might work:

(1) A pure physical model where multiple gears spin on their own hinge constraint and have teeth that engage each other. The backlash could be "tuned" by tweaking the shapes of the teeth and collision margins of the shapes. This method seems difficult: you'd need to iterate your mesh modeling several times, you'd need to use btCompoundShapes with many convex subshapes, and you'd probably need to keep your substep frame rate high (240Hz) to maintain correctness. I only mention this method because it seems possible in theory.

(2) Use a btGearConstraint in combination with a btHingeConstraint. The btGearConstraint allows you to set the gear ratio and the btHingeConstraint can have a lower- and upper-limit (according to the API, I don't have experience using it). I think this method would require three rigid bodies and three constrains: btFixedConstraint --> bodyA --> gearConstraint --> bodyB --> hingeConstraint --> bodyC. You would drive everything by updating the transform of the btFixedConstraint (bodyA's transform would be constrained to the world) and its motion would translate down the chain of constraints. My experience has been: it is possible to chain up to 9 constraints in a system for decent stability and perfomance at 60Hz, although the constraints get noticeably soft (springy lash) the longer the chain. For best results keep the substep framerate high (240Hz) and use the fewest number of constraints.

(3) Use a custom "action" that slams the angular velocity of the driven "wheel". You would derive DCMotor from btActionInterface, which requires you to override on pure virtual method: DCMotor::updateAction(). You would add your action to the DynamicsWorld and thereafter Bullet will call the updateAction() method once per substep. You would have to write your own logic in the class that tracks the driving input's state (phase + velocity + lash) and then use some "critically damped spring math with zero velocity history" (CDSMWZVH, which I could explain in more detail if you like) to compute an angular velocity to apply to the driven object to achieve the result you want. If the driven "wheel" is colliding with other bodies this method has odd effect: the wheel doesn't have the torque of the motor behind it, only its own inertia, so if the wheel's inertia tensor is small relative to the objects it is "pushing" then its effect will be weak. Note, the inertia tensor of a RigidBody can be updated on the fly, so you could artificially increase the inertia tensor when the motor is driving it and lower it when it is in play between the limits of its lash and since the CDSMWSVH logic is stable there is little risk that oscillating the inertia tensor in this case would pump energy into the system.

keithmgould
Posts: 12
Joined: Thu May 31, 2018 5:21 pm

Re: modelling gearbox backlash

Post by keithmgould » Fri Jun 29, 2018 10:01 pm

Thank you for the ideas!

It feels like idea 2 might be the way to go, though I'm new to Bullet, so I'm not certain. I'll try to get it working, and report back here.

keithmgould
Posts: 12
Joined: Thu May 31, 2018 5:21 pm

Re: modelling gearbox backlash

Post by keithmgould » Sat Jun 30, 2018 3:12 am

Hey guys,

After a bit of tinkering around I think I came up with a dead-simple solution for this:

Body: the main link.
Gear: a cylinder link. Attached to Body via a continuous joint.
Wheel: a cylinder link. Attached to Gear via a revolute joint with upper and lower limits.

Then set the force of the Wheel/Gear joint to zero, so that it is free to spin and constrained only by the limits.

Thats it!

I wrote it up in detail (with code and pictures) here:
http://kmgraml.blogspot.com/p/modeling-backlash.html

Would love to hear thoughts!

Thank you again @drleviathan for brainstorming!

keithmgould
Posts: 12
Joined: Thu May 31, 2018 5:21 pm

Re: modelling gearbox backlash

Post by keithmgould » Thu Jul 05, 2018 5:26 pm

Running into some trouble, hoping someone has some insight. I'm using the method explained in my post above. Yet it seems the constraints via the "limit" tag are not holding when there is resistance. Posting code here so its super easy to show the problem.

The very basic setup is a a "balancer" robot: a body, a gear on each side of the base, and a wheel attached to the gear. There is supposed to be backlash between each gear and wheel.

Given the script, I'd expect the gears to turn in sync, which should in turn, turn the wheels. however what happens is gears turn (in this case just one turns?), while the wheels do not.

Image

Would be super curious if anyone has thoughts as to what is going wrong?

Below is the URDF and script:

Code: Select all

<?xml version="1.0"?>
<robot name="bot">

  <!-- colors ................................................................. -->
  <material name="red">
    <color rgba="0.8 0 0 1"/>
  </material>

 <material name="green">
    <color rgba="0 0.8 0 0.75"/>
  </material>

  <material name="blue">
    <color rgba="0 0 0.8 1"/>
  </material>

  <material name="orange">
    <color rgba="0.8 0.4 0 0.75"/>
  </material>

  <!-- main body (base) .................................................................-->

  <link name="body">
    <visual>
      <geometry>
        <box size="0.1016 0.0254 0.6604"/>
      </geometry>
      <origin xyz="0 0 0.3302" />
      <material name="blue"/>
    </visual>

    <collision>
      <geometry>
        <box size="0.1016 0.0254 0.6604"/>
      </geometry>
      <origin xyz="0 0 0.3302" />
    </collision>
    <inertial>
      <origin rpy="0 0 0" xyz="0 0 0.2159"/>
      <mass value="1.767" />
      <inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.01" iyz="0.0" izz="0.01"/>
    </inertial>
  </link>

  <!-- right Gear .................................................................-->
  <link name="rightGear">
    <visual>
      <geometry>
        <cylinder length="0.02" radius="0.03"/>
      </geometry>
      <origin xyz="0 0 0" rpy="0 1.5708 0"/>
      <material name="green"/>
    </visual>
    <inertial>
      <mass value=".00001" />
      <inertia ixx="0.0000001" ixy="0.0" ixz="0.0" iyy="0.0000001" iyz="0.0" izz="0.0000001"/>
    </inertial>
  </link>
  <joint name="rightGearToBox" type="continuous">
    <origin xyz="0.061 0 0.01905" />
    <parent link="body"/>
    <child link="rightGear"/>
    <axis xyz="1 0 0"/>
  </joint>

  <!-- right gear indicator .................................................................-->
  <link name="rightGearIndicator">
    <visual>
      <geometry>
        <box size="0.01 0.01 0.01"/>
      </geometry>
      <material name="red"/>
    </visual>
    <inertial>
        <mass value=".0000" />
        <inertia ixx="0.000000" ixy="0.0" ixz="0.0" iyy="0.000000" iyz="0.0" izz="0.000000"/>
    </inertial>
  </link>
  <joint name="indicatorTorightGear" type="fixed">
    <origin xyz="0 0.03 0"/>
    <parent link="rightGear"/>
    <child link="rightGearIndicator"/>
  </joint>

  <!-- right Wheel .................................................................-->
  <link name="rightWheel">
    <visual>
      <geometry>
        <cylinder length="0.0254" radius="0.042"/>
      </geometry>
      <origin rpy="0 1.5708 0"/>
      <material name="orange"/>
    </visual>
    <collision>
      <geometry>
        <cylinder length="0.0254" radius="0.042"/>
      </geometry>
      <origin rpy="0 1.5708 0"/>
    </collision>
    <inertial>
      <mass value=".1" />
      <inertia ixx="0.00004453" ixy="0.0" ixz="0.0" iyy="0.00004453" iyz="0.0" izz="0.00007938"/>
    </inertial>
  </link>

  <joint name="rightGearToWheel" type="revolute">
    <limit lower="-0.0756" upper="0.0756" />
    <origin xyz="0.04 0 0"/>
    <parent link="rightGear"/>
    <child link="rightWheel"/>
    <axis xyz="1 0 0"/>
  </joint>

  <!-- right Wheel Indicator .................................................................-->
  <link name="rightWheelIndicator">
    <visual>
      <geometry>
        <box size="0.01 0.01 0.01"/>
      </geometry>
      <material name="red"/>
    </visual>
    <inertial>
      <mass value=".0000" />
      <inertia ixx="0.000000" ixy="0.0" ixz="0.0" iyy="0.000000" iyz="0.0" izz="0.000000"/>
    </inertial>
  </link>

  <joint name="indicatorToRightWheel" type="fixed">
    <origin xyz="0 0.042 0"/>
    <parent link="rightWheel"/>
    <child link="rightWheelIndicator"/>
  </joint>


<!-- LEFT SIDE ........... -->

  <!-- leftGear .................................................................-->
  <link name="leftGear">
    <visual>
      <geometry>
        <cylinder length="0.02" radius="0.03"/>
      </geometry>
      <origin xyz="0 0 0" rpy="0 1.5708 0"/>
      <material name="green"/>
    </visual>
    <inertial>
      <mass value=".00001" />
      <inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.01" iyz="0.0" izz="0.01"/>
    </inertial>
  </link>
  <joint name="leftGearToBox" type="continuous">
    <origin xyz="-0.061 0 0.01905" />
    <parent link="body"/>
    <child link="leftGear"/>
    <axis xyz="1 0 0"/>
  </joint>

  <!-- leftGearIndicator .................................................................-->
  <link name="leftGearIndicator">
    <visual>
      <geometry>
        <box size="0.01 0.01 0.01"/>
      </geometry>
      <material name="red"/>
    </visual>
    <inertial>
      <mass value=".0000" />
      <inertia ixx="0.000000" ixy="0.0" ixz="0.0" iyy="0.000000" iyz="0.0" izz="0.000000"/>
    </inertial>
  </link>

  <joint name="indicatorLeftInnerJoint" type="fixed">
    <origin xyz="0 0.03 0"/>
    <parent link="leftGear"/>
    <child link="leftGearIndicator"/>
  </joint>

  <!-- leftWheel .................................................................-->
  <link name="leftWheel">
    <visual>
      <geometry>
        <cylinder length="0.0254" radius="0.042"/>
      </geometry>
      <origin rpy="0 1.5708 0"/>
      <material name="orange"/>
    </visual>
    <collision>
      <geometry>
        <cylinder length="0.0254" radius="0.042"/>
      </geometry>
      <origin rpy="0 1.5708 0"/>
    </collision>
    <inertial>
      <mass value=".1" />
      <inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.01" iyz="0.0" izz="0.01"/>
    </inertial>
  </link>
  <joint name="leftGearToWheel" type="revolute">
    <limit lower="-0.0756" upper="0.0756" />
    <origin xyz="-0.04 0 0"/>
    <parent link="leftGear"/>
    <child link="leftWheel"/>
    <axis xyz="1 0 0"/>
  </joint>

  <!-- leftWheelIndicator .................................................................-->
  <link name="leftWheelIndicator">
    <visual>
      <geometry>
        <box size="0.01 0.01 0.01"/>
      </geometry>
      <material name="red"/>
    </visual>
    <inertial>
      <mass value=".0000" />
      <inertia ixx="0.000000" ixy="0.0" ixz="0.0" iyy="0.000000" iyz="0.0" izz="0.000000"/>
    </inertial>
  </link>
  <joint name="leftWheelIndicator" type="fixed">
    <origin xyz="0 0.042 0"/>
    <parent link="leftWheel"/>
    <child link="leftWheelIndicator"/>
  </joint>

</robot>

Code: Select all

import pybullet as p
import pybullet_data
import time


physicsClient = p.connect(p.GUI)
p.setAdditionalSearchPath(pybullet_data.getDataPath())
p.setGravity(0,0,-9.8)
planeId = p.loadURDF("plane.urdf")
gearBoxId = p.loadURDF("beaker.urdf")

numJoints = p.getNumJoints(gearBoxId)
print("Number of joints: {}".format(numJoints))

joints = {}
for i in range(0, numJoints):
	info = p.getJointInfo(gearBoxId, i)
	if(str(info[1]) == "b'leftGearToBox'"):
			joints['leftGearToBox'] = info
	if(str(info[1]) == "b'leftGearToWheel'"):
			joints['leftGearToWheel'] = info
	if(str(info[1]) == "b'rightGearToBox'"):
			joints['rightGearToBox'] = info
	if(str(info[1]) == "b'rightGearToWheel'"):
			joints['rightGearToWheel'] = info

def setVelocity(vel, target, force):
	p.setJointMotorControl2(bodyUniqueId=gearBoxId, 
		jointIndex=joints[target][0], 
		controlMode=p.VELOCITY_CONTROL,
		targetVelocity = vel,
		force=force)

# because revolute motors are "active", we need t0
# set the force to 0 so they act as pure constraints
setVelocity(0, 'leftGearToWheel', 0)
setVelocity(0, 'rightGearToWheel', 0)

# set the gears moving forward
setVelocity(10, 'leftGearToBox', 100)
setVelocity(10, 'rightGearToBox', 100)

# put camera at an interesting place
distance = 2
yaw = 20
height = -30
p.resetDebugVisualizerCamera(distance, yaw, height, [0,0,0])

while True:
		p.stepSimulation()
		time.sleep(.001)

p.disconnect()

User avatar
drleviathan
Posts: 431
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: modelling gearbox backlash

Post by drleviathan » Wed Jul 11, 2018 3:50 pm

I haven't used pybullet or URDF files yet, so you're outside my own expertise. But when I look at your URDF file I see that you're connecting a red indicator to things wheel via a fixed constraint and this indicator has zero mass and inertia tensor. Dunno what this means in URDF land, but in Bullet such an object can only be static or kinematic. If you lock a dynamic cylinder to a static box via a fixed constraint then my expectation would be the cylinder would not turn. (I dunno why your right wheel is spinning in that gif, but I'm sorta brainstorming here because I don't know what is actually wrong.)

So the first thing I would try would be to lose the indicators to see if things suddenly start working.

Second thing: your robot is very small with light masses. So small, in fact, that the collision margins might cause some problems with your dynamics. My advice would be to start with a larger robot with dimensions and masses. Hint: maybe pretend "centimeter" means "meter". If that works then you can scale time and gravity to get the effective dynamics of a small thing while keeping the dimensions closer to unity.

Finally, if none of that helps, maybe start with any working URDF robot with wheels and gradually tweak it toward the robot you want. You would be starting with something that works and you could make sure it still works after each incremental change you make.

Post Reply