Example #1
0
class Calculator:
    '''
    In charge of the calculation on ATS software
    '''
    def __init__(self, rocket):
        self.data_buffer = CircularQueue(10)
        self.alt_buffer = CircularQueue(10)
        self.v_buffer = CircularQueue(10)
        self.rocket = rocket
        self.base_alt = 0

    def setBaseAlt(self, pressure):
        '''
        Sets the base altitude based on ground air pressure 
        We need to offset the altitude calculated from the US Standard Atmosphere model since it assumes
        ground pressure to be 1013.25 hPa at mean sea level, not at launch site sea level
        '''
        self.base_alt = pressure2alt(pressure)

    def compute(self, data):
        '''
        computes and stores the altitude and velocity at the new data point
        '''
        self.data_buffer.add(data)
        self.alt_buffer.add(pressure2alt(data.pressure))
        if (self.v_buffer.size() == 0):
            self.v_buffer.add(0)
        else:
            curr_alt = self.alt_buffer.get_last()
            prev_alt = self.alt_buffer.get_second_last()
            curr_time = data.time
            prev_time = self.data_buffer.get_second_last().time
            self.v_buffer.add(fda(prev_alt, curr_alt, prev_time, curr_time))

    def ode(self, g, A, Cd, rho, m, v):
        '''
        returns the acceleration of the launch vehicle during the coast state
        the launch vehicle's equation of motion is simplified to be only the sum of weight and drag
        '''
        return -g - ((A * Cd * rho * (v**2) * 0.5) / m)

    def predict(self):
        '''
        returns the predicted apogee altitude
        average value of velocity in the buffer is used as the initial value of velocity
        average value of altitude in the buffer is used as the initial value of altitude
        air density is initialized using the initial altitude value
        the predict function utilizes Runge-Kutta method to predict the apogee altitude 
        '''
        v_n = self.v_buffer.average()
        alt_n = self.alt_buffer.average()
        rho_n = alt2rho(alt_n)

        while (v_n > 0):
            k1 = self.ode(STANDARD_GRAVITY, self.rocket.surface_area,
                          self.rocket.drag_coeff, rho_n, self.rocket.mass, v_n)
            k2 = self.ode(STANDARD_GRAVITY, self.rocket.surface_area,
                          self.rocket.drag_coeff, rho_n, self.rocket.mass,
                          v_n + k1 * 0.5)
            k3 = self.ode(STANDARD_GRAVITY, self.rocket.surface_area,
                          self.rocket.drag_coeff, rho_n, self.rocket.mass,
                          v_n + k2 * 0.5)
            k4 = self.ode(STANDARD_GRAVITY, self.rocket.surface_area,
                          self.rocket.drag_coeff, rho_n, self.rocket.mass,
                          v_n + k3)
            v_n = v_n + STEP_SIZE * (k1 + 2.0 * k2 + 2.0 * k3 + k4) / 6.0
            alt_n = alt_n + STEP_SIZE * v_n
            rho_n = alt2rho(alt_n + self.base_alt)

        return alt_n

    def v_current(self):
        '''
        returns the current velocity of the launch vehicle as an average of the most recent velocity values
        '''
        return self.v_buffer.average()
Example #2
0
    def run(self):
        prelaunch_buffer = CircularQueue(PRELAUNCH_BUFFER_SIZE)
        print("moving to prelaunch state")
        while (self.rocket.state != RocketState.GROUND):
            data = self.sensor.getData()
            if (self.rocket.state == RocketState.PRELAUNCH):
                # PRELAUNCH state
                prelaunch_buffer.add(data)
                # Checking if the launch vehicle took off
                if data.total_accel() > TAKEOFF_DETECTION_THRESHOLD:
                    arr = prelaunch_buffer.toArray()
                    self.start_time = arr[
                        0].time  # setting start time of the launch vehicle
                    arr[-1].event = Event.TAKE_OFF  # the latest data will be marked as TAKE_OFF
                    total = 0.0
                    for point in arr:
                        point.normalize(self.start_time)
                        self.logger.write(point)
                        total += point.pressure
                    self.rocket.state = RocketState.MOTOR_ASCENT
                    self.calculator.setBaseAlt(
                        total / PRELAUNCH_BUFFER_SIZE
                    )  # base altitude is based on average pressure
                    print("moving to motor ascent state")
            elif (self.rocket.state == RocketState.MOTOR_ASCENT):
                # MOTOR_ASCENT state
                data.normalize(self.start_time)
                self.calculator.compute(data)
                # Checking if the motor burned up by checking the duration since take off
                if data.time >= self.rocket.motor_burnout_t + 1:
                    self.rocket.state = RocketState.COAST
                    data.event = Event.MOTOR_BURNOUT
                    print("moving to coast state")
                    self.base_time = data.time
                self.logger.write(data)
            elif (self.rocket.state == RocketState.COAST):
                # COAST state
                data.normalize(self.start_time)
                self.calculator.compute(data)

                if self.ats_state == 0 and (data.time - self.base_time >= 1):
                    # if been in closed state for more than 1 second, start opening the flaps
                    self.ats_state = 2
                    self.base_time = data.time
                    self.actuator.actuate()
                    data.command = "ACTUATE"
                elif self.ats_state == 1 and (data.time - self.base_time >= 1):
                    self.ats_state = -1
                    self.base_time = data.time
                    self.actuator.retract()
                    data.command = "RETRACT"
                elif self.ats_state == 2:
                    if (data.time - self.base_time < 2):
                        self.actuator.actuate()
                    else:
                        self.ats_state = 1
                        self.base_time = data.time
                        data.command = "COMPLETED ACTUATION"
                else:
                    if (data.time - self.base_time < 2):
                        self.actuator.retract()
                    else:
                        self.ats_state = 0
                        self.base_time = data.time
                        data.command = "COMPLETED RETRACTION"

                # if self.calculator.predict() > self.rocket.target_alt:
                #     self.actuator.actuate()
                # else:
                #     self.actuator.retract()
                print("Current velocity: {}".format(
                    self.calculator.v_current()))
                # Checking if velocity of the launch vehicle is negative
                if self.calculator.v_current() < 0:
                    data.event = Event.APOGEE
                    self.actuator.retract()
                    self.rocket.state = RocketState.DESCENT
                    self.apogee_time = data.time
                    print("moving to descent state")
                self.logger.write(data)
            elif (self.rocket.state == RocketState.DESCENT):
                # DESCENT state
                data.normalize(self.start_time)
                self.calculator.compute(data)
                print("Current velocity: {}".format(
                    self.calculator.v_current()))
                # Detect landing when velocity is be greated than -2 m/s and it has been at least 5 seconds after apogee
                if self.calculator.v_current(
                ) > -2 and data.time - self.apogee_time > 5:
                    data.event = Event.TOUCH_DOWN
                    self.rocket.state = RocketState.GROUND
                    print("moving to ground state")
                self.logger.write(data)
        # GROUND state
        for _ in range(5):
            data = self.sensor.getData()
            data.normalize(self.start_time)
            self.logger.write(data)
        self.logger.purge()

        self.shutdown()