aboutsummaryrefslogtreecommitdiffstats
path: root/System_Python/system_BASE_2371.py
blob: 1e532fae605d333091910aed6de70179ae06c9f8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/usr/bin/env python
from motor import Motor
from encoder import Encoder
import math

# IO pin definitions
### Motor pins
motor_speed_pin = 17
motor_forward_pin = 27
motor_reverse_pin = 22
### Encoder pins (shared by both encoders)
encoder_clock_pin = 2
encoder_data_pin = 3
### Angular encoder pins
encoder_angular_cs_pin = 4
### Linear encoder pins
encoder_linear_cs_pin = 5


# System Class
# This is the primary interface a student will use to control the pendulum.
class System:
    def __init__(self):
        # Initialize the motor.
        self.motor = Motor(motor_speed_pin, motor_forward_pin, motor_reverse_pin)
        # Initialize the angular encoder.
        self.encoder_angular = Encoder(encoder_clock_pin, encoder_angular_cs_pin, encoder_data_pin)
        self.encoder_angular.set_zero()
        # Initialize the linear encoder.
        self.encoder_linear = Linear_Encoder(encoder_clock_pin, encoder_linear_cs_pin, encoder_data_pin)
        self.encoder_linear.set_zero()
    # END __init__()
    
    # Get the values of the encoders to determine the angular and linear position of the pendulum.
    # Values are returned as a tuple: (angle, linear).
    ### angle: 0 indicates the pendulum is exactly straight up.
    #####      180 or -180 indicate the pendulum is exactly straight down.
    #####      Positive values indicate the pendulum is leaning to the right.
    #####      Negative values indicate the pendulum is leaning to the left.
    ### linear: 0 indicates the pendulum is exactly in the middle of the track.
    #####       Positive values indicate the pendulum is right-of-center.
    #####       Negative values indicate the pendulum is left-of-center.
    def measure(self):
        angular_position = self.encoder_angular.read_position('Degrees')
        if angular_position > 180:
            angular_position = angular_position - 360
        #linear_position = self.encoder_linear.read_position()
        linear_position = 0
        return (angular_position, linear_position)
    # END measure()
    
    # Adjust the pendulum's linear position using the motor.
    ### speed: Acceptable values range from -100 to 100 (as a percentage), with 100/-100 being the maximum adjustment speed.
    #####      Negative values will move the pendulum to the left.
    #####      Positive values will move the pendulum to the right.
    def adjust(self, speed):
        # cap the speed inputs
        if speed > 100.0:
            speed = 100.0
        if speed < -100.0:
            speed = -100.0
        # change the motor speed
        # TODO: Make sure the motor is oriented so that positive speed the correct direction (same for negative). Change the values otherwise.
        self.motor.coast()
        self.motor.move(speed)
    # END adjust()
# END System

# Linear Encoder class
# This class is to help with using an absolute encoder for linear position sensing as assembled in the physical system.
# The function definitions here are the same as with the regular encoder (pseudo-interface).
class Linear_Encoder:
    DIAMETER = 4.0 # MEASURE THIS
    
    def __init__(self, clk_pin, cs_pin, data_pin):
        self.encoder = Encoder(clk_pin, cs_pin, data_pin)
        self.set_zero()
    def set_zero(self):
        # Set the zero position for the encoder
        self.encoder.set_zero()
        # Reset the internal position counter
        self.rotations = 0
        self.last_position = 0
    def read_position(self):
        # Read the position of the encoder 
        position = self.encoder.read_position('Raw')
        # Compare to last known position
        # NOTE: For now, assume that we are moving the smallest possible distance (i.e. 5 -> 1 is -4, not 1020)
        if position - self.last_position > 0:
            if position < 512 and self.last_position > 512:
                # We are moving to the right (positive) and have completed a new rotation
                self.rotations = self.rotations + 1
        else:
            if position > 512 and self.last_position < 512:
                # We are moving to the left (negative) and have completed a new rotation
                self.rotations = self.rotations - 1
        # Save the last position for the next calculation
        self.last_position = position
            
        # compute the position based on the system parameters
        # linear position = (2pi*r)(n) + (2pi*r)(position/1024) = (2pi*r)(n + position/1024) = (pi*d)(n + position/1024)
        return (math.pi*DIAMETER)*(self.rotations + position/1024)