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

Update quanser sim #81

Merged
merged 24 commits into from
Mar 26, 2024
Merged
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
eff8b59
use control freq as render fps
Armandpl Mar 25, 2024
befbb61
make robot, motor and pendulum dynamics configurable
Armandpl Mar 25, 2024
93b4cfd
bring back quanser sim, take reduction ratio in account
Armandpl Mar 25, 2024
db09c6c
comment out non working code
Armandpl Mar 25, 2024
6c6550f
make robot configurable so that we can configure encoders CPRs
Armandpl Mar 25, 2024
fc750f8
move pygame to package deps, fix #75
Armandpl Mar 25, 2024
607f6dc
fix syntax error in default args, comment out reset pid for now
Armandpl Mar 25, 2024
092216c
match new Robot interface
Armandpl Mar 25, 2024
5137f56
use policy mean at inference
Armandpl Mar 25, 2024
f0aaff3
fix arg name
Armandpl Mar 25, 2024
f6c7217
add test to make sure we can detect the pendulum falling
Armandpl Mar 25, 2024
2229306
flatten history
Armandpl Mar 25, 2024
e208c39
use a smaller integration step
Armandpl Mar 25, 2024
881e03c
match quanser sim
Armandpl Mar 25, 2024
4d11d21
disable deadzone for now
Armandpl Mar 25, 2024
5ca13e1
remove unnecessary extra call to reset, make sure to pass down seed a…
Armandpl Mar 25, 2024
3e00a44
fix reset functions
Armandpl Mar 25, 2024
6d59c42
fix reset functions
Armandpl Mar 25, 2024
6831ab8
fix robot x pos in render, x=0=center
Armandpl Mar 26, 2024
da55b1e
clamp torque using the stall torque
Armandpl Mar 26, 2024
fd1120f
upgrade actions versions, add os in deps cache key
Armandpl Mar 26, 2024
be44372
extend ignores in flake8 ci config instead of replacing them
Armandpl Mar 26, 2024
7064f0f
ignore key doesn't exist, just extend the default list of ignored codes
Armandpl Mar 26, 2024
f26c03b
update configs, still doesn't transfer
Armandpl Mar 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
make robot, motor and pendulum dynamics configurable
  • Loading branch information
Armandpl committed Mar 25, 2024
commit befbb618a78fe17115ef74ca4647ed3443e40797
130 changes: 83 additions & 47 deletions furuta/robot.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import struct
from dataclasses import dataclass

import numpy as np
import serial


class Robot:
def __init__(self, device="dev/ttyACM0", baudrate=921600):
def __init__(
self,
device="dev/ttyACM0",
baudrate=921600,
motor_encoder_cpr=400,
pendulum_encoder_cpr=5120 * 4,
):
self.ser = serial.Serial(device, baudrate)
self.motor_encoder_cpr = 400
self.pendulum_encoder_cpr = 5120 * 4
# self.motor_encoder_cpr = 211.2
# self.pendulum_encoder_cpr = 8192
self.motor_encoder_cpr = motor_encoder_cpr
self.pendulum_encoder_cpr = pendulum_encoder_cpr

def step(self, motor_command: float):
direction = motor_command < 0
Expand Down Expand Up @@ -39,51 +44,78 @@ def close(self):


class MotorDynamics:
def __init__(self):
self.R = 8.0 # resistance (Ohm)
self.r = 6.25 # gear ratio
self.J_mot = 1.0 * 1e-8 # motor inertia (kg m^2)
self.Kc = 0.235 # torque constant (N-m/A)
self.Ke = 0.235 # back-emf constant (V-s/rad)
self.f_v = 1e-3 # viscous damping (N-m-s/rad)
self.tau_c = 0.005 # Coulomb (N-m)
self.tau_s = 0.03 # stiction (N-m)
self.f_s = 0.03 / 9.81
self.f_c = 0.005 / 9.81
self.phi_dot_eps = 0.01 # limit stiction speed (rad/s)
self.L = 0.24 # inductance (H)
def __init__(
self,
V=24.0, # voltage (V) only used to store the value to rescale RL actions from [-1, 1] to [-V, V]
R=8.0, # resistance (Ohm)
r=6.25, # gear ratio
J_mot=1.0 * 1e-8, # motor inertia (kg m^2)
Kc=0.235, # torque constant (N-m/A)
Ke=0.235, # back-emf constant (V-s/rad)
f_v=1e-3, # viscous damping (N-m-s/rad)
f_s=1e-1, # Coulomb
f_c=5e-2, # striction
phi_dot_eps=0.01, # limit stiction speed (rad/s)
L=0.24, # inductance (H)
):
self.V = V
self.R = R
self.r = r
self.J_mot = J_mot
self.Kc = Kc
self.Ke = Ke
self.f_v = f_v
self.f_s = f_s
self.f_c = f_c
self.phi_dot_eps = phi_dot_eps
self.L = L

def compute_motor_torque(self, U, phi_dot):
"""
This method computes the steady state torque in output of the gear box
U: is the volatge applied to the motor
U: is the voltage applied to the motor
phi_dot: is the angular velocity in output of the gear box (as measured by encoders)
return: the torque in output of the gear box
"""
return self.r * self.Kc * (U - self.Ke * self.r * phi_dot) / self.R


class PendulumDynamics:
def __init__(self):
def __init__(
self,
g=9.81, # m/s^2
m_bearing=11.5 * 1e-3, # kg
l_bearing=25.0 * 1e-3, # m
m_enc=17.0 * 1e-3, # kg
l_enc=35.0 * 1e-3, # m
m_shaft=2.8 * 1e-3, # kg
l_shaft=15.0 * 1e-3, # m
m_mount=5.25 * 1e-3, # kg
l_p=74.0 * 1e-3, # m
M=28.0 * 1e-3, # kg
L=86.0 * 1e-3, # m
f_p=4e-3, # N-m-s/rad
motor: MotorDynamics = MotorDynamics(),
):
# Gravity
self.g = 9.81 # m/s^2
self.g = g # m/s^2
# Bearings
self.m_bearing = 11.5 * 1e-3 # kg
self.l_bearing = 25.0 * 1e-3 # m
self.m_bearing = m_bearing # kg
self.l_bearing = l_bearing # m
# Encoder
self.m_enc = 17.0 * 1e-3 # kg
self.l_enc = 35.0 * 1e-3 # m
# Shaft
self.m_shaft = 2.8 * 1e-3 # kg
self.l_shaft = 15.0 * 1e-3 # m
self.m_enc = m_enc # kg
self.l_enc = l_enc # m
# Shaft Collars
self.m_shaft = m_shaft # kg
self.l_shaft = l_shaft # m
# Mount
self.m_mount = 5.25 * 1e-3 # kg
self.l_mount = self.l_bearing # m
self.m_mount = m_mount # kg
self.l_mount = l_bearing # m
# Pendulum
self.l_p = 74.0 * 1e-3 # m
self.M = 28.0 * 1e-3 # kg
self.L = 86.0 * 1e-3 # m
self.f_p = 4e-3 # viscous damping (N-m-s/rad)
self.l_p = l_p # m
self.M = M # kg
self.L = L # m
self.f_p = f_p # viscous damping (N-m-s/rad)
# Motor
self.motor = MotorDynamics()
# Inertia
Expand All @@ -97,9 +129,10 @@ def __init__(self):
# Init dynamics
self.phi_ddot = 0.0
self.th_ddot = 0.0
self.mot = motor

def __call__(self, x, u):
phi, th, phi_dot, th_dot = x[0], x[1], x[2], x[3]
_, th, phi_dot, th_dot = x[0], x[1], x[2], x[3]
# Shorter names
J = self.J
M = self.M
Expand All @@ -112,28 +145,31 @@ def __call__(self, x, u):
J_th = J + M * (L**2 + l_p**2) * c**2
# Compute motor friction
tau_f = 0.0
F_n = np.abs(self.M * self.th_ddot * self.L / s)
# F_n = np.abs(self.M * self.th_ddot * self.L / s)
tau = (
M * g * l_p * s**2
- M * L * l_p * s**2 * c * phi_dot**2
+ M * L * l_p * c * th_dot**2
+ 2 * M * L**2 * s * c * th_dot * phi_dot
+ u
)
if abs(phi_dot) < mot.phi_dot_eps:
# Stiction
tau_s = mot.f_s * F_n
if abs(tau) < tau_s:
tau_f = tau
else:
tau_f = np.sign(tau) * mot.f_s * F_n
else:
# Coulomb
tau_c = mot.f_c * F_n
tau_f = np.sign(phi_dot) * tau_c + mot.f_v * phi_dot
# if abs(phi_dot) < mot.phi_dot_eps:
# # Stiction
# tau_s = mot.f_s * F_n
# if abs(tau) < tau_s:
# tau_f = tau
# else:
# tau_f = np.sign(tau) * mot.f_s * F_n
# else:
# Coulomb
# tau_c = mot.f_c * F_n
tau_c = 0.01
tau_f = np.sign(phi_dot) * tau_c + mot.f_v * phi_dot

# Compute dynamics
phi_ddot = (tau - tau_f) / J_th
th_ddot = (g * s - L * s * c * phi_dot**2 + l_p * s * phi_ddot - f_p * th_dot / M) / L
self.phi_ddot = phi_ddot
self.th_ddot = th_ddot
# return np.array([phi_dot, th_dot, phi_ddot, th_ddot])
return phi_ddot, th_ddot