Guest User

cart_pole

a guest
Mar 8th, 2017
178
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.81 KB | None | 0 0
  1. """
  2. Double pole simulation. Physics.
  3. """
  4. from math import sin, cos, pi, radians as rad
  5.  
  6. import numpy as np
  7.  
  8. C43 = 4/3.0
  9. C34 = 3/4.0
  10. HALF_PI = pi/2
  11.  
  12. def runge_kutta4(current_y, y_deriv_func, step):
  13.     """
  14.    Fourth order Runge Kutta
  15.    http://lpsa.swarthmore.edu/NumInt/NumIntFourth.html
  16.    for example
  17.    y' = -2*y
  18.    then y_deriv_func = y' that accepts y
  19.    and y is current_y
  20.    """
  21.  
  22.     k1 = y_deriv_func(current_y)
  23.     y1 = current_y + k1 * step / 2
  24.  
  25.     k2 = y_deriv_func(y1)
  26.     y2 = current_y + k2 * step / 2
  27.  
  28.     k3 = y_deriv_func(y2)
  29.     y3 = current_y + k3 * step
  30.  
  31.     k4 = y_deriv_func(y3)
  32.  
  33.     next_y = current_y + (k1 + 2*k2 + 2*k3 + k4)*step/6
  34.  
  35.     return next_y
  36.  
  37. def runge_kutta4_for_poles(pole, y_deriv_func, step):
  38.     """
  39.    Fourth order Runge Kutta
  40.    http://lpsa.swarthmore.edu/NumInt/NumIntFourth.html
  41.    for example
  42.    y' = -2*y
  43.    then y_deriv_func = y' that accepts y
  44.    and y is current_y
  45.    """
  46.     current_y = pole.vel
  47.     k1 = y_deriv_func(pole, current_y)
  48.     y1 = current_y + k1 * step / 2
  49.  
  50.     k2 = y_deriv_func(pole, y1)
  51.     y2 = current_y + k2 * step / 2
  52.  
  53.     k3 = y_deriv_func(pole, y2)
  54.     y3 = current_y + k3 * step
  55.  
  56.     k4 = y_deriv_func(pole, y3)
  57.  
  58.     next_y = current_y + (k1 + 2*k2 + 2*k3 + k4)*step/6
  59.  
  60.     return next_y
  61.  
  62.  
  63.  
  64. class Pole:
  65.  
  66.     def __init__(self, angle, velocity, acceleration, mass, half_length):
  67.         """
  68.        angle - angle from vertical in rad +-15?
  69.        maybe sincos are valid with small values in this situation
  70.        angular velocity in rad/sec
  71.        acceleration in rad/sec**2
  72.        mass of poles in kg
  73.        poles lengths from the pivot to the center of mass
  74.        thus h_len = 0.5 is 1 meter pole
  75.        """
  76.         self.angle = angle
  77.         self.vel = velocity
  78.         self.acc = acceleration
  79.         self.mass = mass
  80.         self.h_len = half_length
  81.  
  82. class PoledCart:
  83.     """
  84.    double pole physics implementation
  85.    """
  86.  
  87.     def __init__(self, number_of_poles = 1):
  88.         #number of poles
  89.         self.pole_number = number_of_poles
  90.         starting_angle = 0.00
  91.         #starting_angle = 3.14
  92.         self.poles = []
  93.         p_masses = [0.1]*self.pole_number
  94.         #p_angles = [starting_angle]*self.pole_number
  95.         p_angles = [0.0, rad(1.0)]
  96.         p_h_lens = [0.05, 0.5]
  97.         p_accels = [0.0]*self.pole_number
  98.         p_vels = [0.0]*self.pole_number
  99.         for i in range(self.pole_number):
  100.             self.poles.append(Pole(p_angles[i],
  101.                              p_vels[i],
  102.                              p_accels[i],
  103.                              p_masses[i],
  104.                              p_h_lens[i]))
  105.         #offset from the middle of the track (0.0)
  106.         self.cart_pos = 0.0
  107.         #velocity in m/s
  108.         self.cart_vel = 0.0
  109.         #acceleration in m/s**2
  110.         self.cart_acc = 0.0
  111.         #gravity m/2**2 #up is positive!
  112.         self.gravity = -9.81
  113.         #mass of cart in kg
  114.         self.cart_mass = 1.0
  115.         #time in seconds
  116.         self.time = 0.0
  117.         #magitude of force applied to the center of
  118.         #cart's mass at time self.time
  119.         #in newtons usually constant of +-10  or +-1 newtons
  120.         self.applied_force = 0.0
  121.         #track limit from the center thus +-2.4m = 4.8m is length of the track
  122.         self.track_limit = 2.4
  123.         #pole failure angle +- 36 degrees from 0. variable is in rads
  124.         self.p_failure_angle = rad(36)
  125.         self.failed = False
  126.         #time step in seconds
  127.         self.time_step = 0.01
  128.         self.cart_fric = 0.05
  129.         self.p_fric = 0.000002
  130.         #if enabled poles are always above the cart
  131.         self.stop_at_zero_deg = True
  132.         #how to approximate
  133.  
  134.     def cart_acc_given_vel(self, cart_vel):
  135.         p_forces = 0.0
  136.         total_effective_poles_mass = 0.0
  137.         for p in self.poles:
  138.             buff = self.p_fric * p.vel / (p.mass * p.h_len) + self.gravity * sin(p.angle)
  139.             force = p.mass * p.h_len * p.vel**2 * sin(p.angle) +\
  140.                     C34 * p.mass * cos(p.angle) * buff
  141.             p_forces += force
  142.             total_effective_poles_mass += p.mass * (1 - C34 * cos(p.angle)**2)
  143.  
  144.  
  145.         cart_acc = self.applied_force - self.cart_fric * np.sign(cart_vel) + p_forces
  146.  
  147.         cart_acc /= self.cart_mass + total_effective_poles_mass
  148.  
  149.         return cart_acc
  150.  
  151.     def pole_acc_given_vel(self, p, pole_vel):
  152.         p.acc = -C34/p.h_len * (self.cart_acc * cos(p.angle) +\
  153.                     self.gravity * sin(p.angle) + self.p_fric * pole_vel / (p.mass * p.h_len))
  154.         return p.acc
  155.  
  156.     def update_state(self):
  157.         self.time += self.time_step
  158.  
  159.         self.cart_vel = runge_kutta4(self.cart_vel, self.cart_acc_given_vel, self.time_step)
  160.         for pole in self.poles:
  161.             pole.vel = runge_kutta4_for_poles(pole, self.pole_acc_given_vel, self.time_step)
  162.  
  163.         self.cart_acc = self.cart_acc_given_vel(self.cart_vel)
  164.  
  165.  
  166.         self.cart_pos += self.time_step * self.cart_vel
  167.  
  168.         for p in self.poles:
  169.             p.angle += self.time_step * p.vel
  170.             self.pole_acc_given_vel(pole, pole.vel)
  171.  
  172.         if not -self.track_limit <= self.cart_pos <= self.track_limit:
  173.             self.failed = True
  174.             #print('Track limit fail at', self.cart_pos)
  175.  
  176.         for p in self.poles:
  177.             if not -self.p_failure_angle <= p.angle <= self.p_failure_angle:
  178.                 self.failed = True
  179.                 #print('Pole fail', p.h_len, p.angle)
  180.                 #return
  181.             if not -HALF_PI <= p.angle <= HALF_PI:
  182.                 if p.angle > HALF_PI:
  183.                     p.angle = HALF_PI
  184.                 elif p.angle < -HALF_PI:
  185.                     p.angle = -HALF_PI
  186.                 p.vel *= -0.9
  187.  
  188. def discrete_actuator_force(action):
  189.     return 10.0 if action[0] > 0.5 else -10.0
Advertisement
Add Comment
Please, Sign In to add comment