示例#1
0
    def update(self, sendcan, enabled, CS, frame, actuators):
        """ Controls thread """

        P = self.params

        # Send CAN commands.
        can_sends = []
        canbus = self.canbus

        ### STEER ###

        if (frame % P.STEER_STEP) == 0:

            final_steer = actuators.steer if enabled else 0.
            apply_steer = final_steer * P.STEER_MAX
            # limits due to driver torque
            driver_max_torque = P.STEER_MAX + (
                P.STEER_DRIVER_ALLOWANCE + CS.steer_torque_driver *
                P.STEER_DRIVER_FACTOR) * P.STEER_DRIVER_MULTIPLIER
            driver_min_torque = -P.STEER_MAX + (
                -P.STEER_DRIVER_ALLOWANCE + CS.steer_torque_driver *
                P.STEER_DRIVER_FACTOR) * P.STEER_DRIVER_MULTIPLIER
            max_steer_allowed = max(min(P.STEER_MAX, driver_max_torque), 0)
            min_steer_allowed = min(max(-P.STEER_MAX, driver_min_torque), 0)
            apply_steer = clip(apply_steer, min_steer_allowed,
                               max_steer_allowed)

            # slow rate if steer torque increases in magnitude
            if self.apply_steer_last > 0:
                apply_steer = clip(
                    apply_steer,
                    max(self.apply_steer_last - P.STEER_DELTA_DOWN,
                        -P.STEER_DELTA_UP),
                    self.apply_steer_last + P.STEER_DELTA_UP)
            else:
                apply_steer = clip(
                    apply_steer, self.apply_steer_last - P.STEER_DELTA_UP,
                    min(self.apply_steer_last + P.STEER_DELTA_DOWN,
                        P.STEER_DELTA_UP))

            apply_steer = int(round(apply_steer))
            self.apply_steer_last = apply_steer

            lkas_enabled = enabled and not CS.steer_not_allowed

            if not lkas_enabled:
                apply_steer = 0

            if self.car_fingerprint == CAR.CX5:
                #counts from 0 to 15 then back to 0
                ctr = (frame / P.STEER_STEP) % 16
                #ctr = CS.CAM_LKAS.ctr #(frame / P.STEER_STEP) % 16

                if ctr != -1 and self.last_cam_ctr != ctr:
                    self.last_cam_ctr = ctr
                    #line_not_visible = CS.CAM_LKAS.lnv
                    if CS.v_ego_raw > 4:
                        line_not_visible = 0
                    else:
                        line_not_visible = 1

                    e1 = CS.CAM_LKAS.err1
                    e2 = CS.CAM_LKAS.err2

                    #  assuming controlsd runs at 83 hz
                    #  2000ms => 166.6
                    #  1000ms => 83.3
                    #  500ms  => 41.65

                    tsec = 167
                    osec = 83
                    hsec = 42
                    qsec = 21
                    q3sec = 62

                    if CS.steer_lkas.handsoff == 1 and self.ldw == 0:
                        self.handsoff_ctr += 1
                        if self.handsoff_ctr > tsec:
                            self.ldw_ctr = osec
                            self.handsoff_ctr = 0
                            self.ldw = 1
                            if apply_steer > 0:
                                self.ldwr = 1
                                self.ldwl = 0
                            else:
                                self.ldwr = 0
                                self.ldwl = 1
                    #else:
                    #  self.handsoff_ctr = 0

                    if self.ldw == 0 and CS.steer_lkas.block == 1 and CS.v_ego_raw > 54 and apply_steer != 0:
                        self.ldw = 1
                        self.ldw_ctr = osec
                        if apply_steer > 0:
                            self.ldwr = 1
                            self.ldwl = 0
                        else:
                            self.ldwr = 0
                            self.ldwl = 1

                    ldw = 0
                    if self.ldw_ctr > 0:
                        self.ldw_ctr -= 1
                        if self.ldw_ctr == 0:
                            self.ldw = 0
                            self.ldwl = 0
                            self.ldwr = 0
                        elif self.ldw_ctr < q3sec and self.ldw_ctr > qsec:
                            ldw = 1

                    can_sends.append(
                        mazdacan.create_steering_control(
                            self.packer_pt, canbus.powertrain,
                            CS.CP.carFingerprint, ctr, apply_steer,
                            line_not_visible, 1, 1, e1, e2, ldw))

                    # send lane info msgs at 1/8 rate of steer msgs
                    if (ctr % 8 == 0):
                        can_sends.append(
                            mazdacan.create_cam_lane_info(
                                self.packer_pt, canbus.powertrain,
                                CS.CP.carFingerprint, line_not_visible,
                                CS.cam_laneinfo, CS.steer_lkas, self.ldwr,
                                self.ldwl))

                    #can_sends.append(mazdacan.create_lkas_msg(self.packer_pt, canbus.powertrain, CS.CP.carFingerprint, CS.CAM_LKAS))

                    #can_sends.append(mazdacan.create_lane_track(self.packer_pt, canbus.powertrain, CS.CP.carFingerprint, CS.CAM_LT))

            sendcan.send(
                can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
示例#2
0
    def publish_logs(self, CS, start_time, actuators, lac_log):
        """Send actuators and hud commands to the car, send controlsstate and MPC logging"""

        CC = car.CarControl.new_message()
        CC.enabled = self.enabled
        CC.actuators = actuators

        CC.cruiseControl.override = True
        CC.cruiseControl.cancel = not self.CP.pcmCruise or (
            not self.enabled and CS.cruiseState.enabled)
        if self.joystick_mode and self.sm.rcv_frame[
                'testJoystick'] > 0 and self.sm['testJoystick'].buttons[0]:
            CC.cruiseControl.cancel = True

        # TODO remove car specific stuff in controls
        # Some override values for Honda
        # brake discount removes a sharp nonlinearity
        brake_discount = (1.0 - clip(-actuators.accel * (3.0 / 4.0), 0.0, 1.0))
        speed_override = max(0.0,
                             (self.LoC.v_pid + CS.cruiseState.speedOffset) *
                             brake_discount)
        CC.cruiseControl.speedOverride = float(
            speed_override if self.CP.pcmCruise else 0.0)
        CC.cruiseControl.accelOverride = float(
            self.CI.calc_accel_override(CS.aEgo, self.a_target, CS.vEgo,
                                        self.v_target))

        CC.hudControl.setSpeed = float(self.v_cruise_kph * CV.KPH_TO_MS)
        CC.hudControl.speedVisible = self.enabled
        CC.hudControl.lanesVisible = self.enabled
        CC.hudControl.leadVisible = self.sm['longitudinalPlan'].hasLead

        right_lane_visible = self.sm['lateralPlan'].rProb > 0.5
        left_lane_visible = self.sm['lateralPlan'].lProb > 0.5
        CC.hudControl.rightLaneVisible = bool(right_lane_visible)
        CC.hudControl.leftLaneVisible = bool(left_lane_visible)

        recent_blinker = (self.sm.frame - self.last_blinker_frame
                          ) * DT_CTRL < 5.0  # 5s blinker cooldown
        ldw_allowed = self.is_ldw_enabled and CS.vEgo > LDW_MIN_SPEED and not recent_blinker \
                        and not self.active and self.sm['liveCalibration'].calStatus == Calibration.CALIBRATED

        meta = self.sm['modelV2'].meta
        if len(meta.desirePrediction) and ldw_allowed:
            l_lane_change_prob = meta.desirePrediction[Desire.laneChangeLeft -
                                                       1]
            r_lane_change_prob = meta.desirePrediction[Desire.laneChangeRight -
                                                       1]
            l_lane_close = left_lane_visible and (
                self.sm['modelV2'].laneLines[1].y[0] > -(1.08 + CAMERA_OFFSET))
            r_lane_close = right_lane_visible and (
                self.sm['modelV2'].laneLines[2].y[0] < (1.08 - CAMERA_OFFSET))

            CC.hudControl.leftLaneDepart = bool(
                l_lane_change_prob > LANE_DEPARTURE_THRESHOLD and l_lane_close)
            CC.hudControl.rightLaneDepart = bool(
                r_lane_change_prob > LANE_DEPARTURE_THRESHOLD and r_lane_close)

        if CC.hudControl.rightLaneDepart or CC.hudControl.leftLaneDepart:
            self.events.add(EventName.ldw)

        clear_event = ET.WARNING if ET.WARNING not in self.current_alert_types else None
        alerts = self.events.create_alerts(self.current_alert_types,
                                           [self.CP, self.sm, self.is_metric])
        self.AM.add_many(self.sm.frame, alerts, self.enabled)
        self.AM.process_alerts(self.sm.frame, clear_event)
        CC.hudControl.visualAlert = self.AM.visual_alert

        if not self.read_only and self.initialized:
            # send car controls over can
            can_sends = self.CI.apply(CC)
            self.pm.send(
                'sendcan',
                can_list_to_can_capnp(can_sends,
                                      msgtype='sendcan',
                                      valid=CS.canValid))

        force_decel = (self.sm['driverMonitoringState'].awarenessStatus < 0.) or \
                      (self.state == State.softDisabling)

        # Curvature & Steering angle
        params = self.sm['liveParameters']
        steer_angle_without_offset = math.radians(CS.steeringAngleDeg -
                                                  params.angleOffsetAverageDeg)
        curvature = -self.VM.calc_curvature(steer_angle_without_offset,
                                            CS.vEgo)

        # controlsState
        dat = messaging.new_message('controlsState')
        dat.valid = CS.canValid
        controlsState = dat.controlsState
        controlsState.alertText1 = self.AM.alert_text_1
        controlsState.alertText2 = self.AM.alert_text_2
        controlsState.alertSize = self.AM.alert_size
        controlsState.alertStatus = self.AM.alert_status
        controlsState.alertBlinkingRate = self.AM.alert_rate
        controlsState.alertType = self.AM.alert_type
        controlsState.alertSound = self.AM.audible_alert
        controlsState.canMonoTimes = list(CS.canMonoTimes)
        controlsState.longitudinalPlanMonoTime = self.sm.logMonoTime[
            'longitudinalPlan']
        controlsState.lateralPlanMonoTime = self.sm.logMonoTime['lateralPlan']
        controlsState.enabled = self.enabled
        controlsState.active = self.active
        controlsState.curvature = curvature
        controlsState.state = self.state
        controlsState.engageable = not self.events.any(ET.NO_ENTRY)
        controlsState.longControlState = self.LoC.long_control_state
        controlsState.vPid = float(self.LoC.v_pid)
        controlsState.vCruise = float(self.v_cruise_kph)
        controlsState.upAccelCmd = float(self.LoC.pid.p)
        controlsState.uiAccelCmd = float(self.LoC.pid.i)
        controlsState.ufAccelCmd = float(self.LoC.pid.f)
        controlsState.cumLagMs = -self.rk.remaining * 1000.
        controlsState.startMonoTime = int(start_time * 1e9)
        controlsState.forceDecel = bool(force_decel)
        controlsState.canErrorCounter = self.can_error_counter

        if self.joystick_mode:
            controlsState.lateralControlState.debugState = lac_log
        elif self.CP.steerControlType == car.CarParams.SteerControlType.angle:
            controlsState.lateralControlState.angleState = lac_log
        elif self.CP.lateralTuning.which() == 'pid':
            controlsState.lateralControlState.pidState = lac_log
        elif self.CP.lateralTuning.which() == 'lqr':
            controlsState.lateralControlState.lqrState = lac_log
        elif self.CP.lateralTuning.which() == 'indi':
            controlsState.lateralControlState.indiState = lac_log
        self.pm.send('controlsState', dat)

        # carState
        car_events = self.events.to_msg()
        cs_send = messaging.new_message('carState')
        cs_send.valid = CS.canValid
        cs_send.carState = CS
        cs_send.carState.events = car_events
        self.pm.send('carState', cs_send)

        # carEvents - logged every second or on change
        if (self.sm.frame % int(1. / DT_CTRL)
                == 0) or (self.events.names != self.events_prev):
            ce_send = messaging.new_message('carEvents', len(self.events))
            ce_send.carEvents = car_events
            self.pm.send('carEvents', ce_send)
        self.events_prev = self.events.names.copy()

        # carParams - logged every 50 seconds (> 1 per segment)
        if (self.sm.frame % int(50. / DT_CTRL) == 0):
            cp_send = messaging.new_message('carParams')
            cp_send.carParams = self.CP
            self.pm.send('carParams', cp_send)

        # carControl
        cc_send = messaging.new_message('carControl')
        cc_send.valid = CS.canValid
        cc_send.carControl = CC
        self.pm.send('carControl', cc_send)

        # copy CarControl to pass to CarInterface on the next iteration
        self.CC = CC
示例#3
0
    def update_stat(self, CS, enabled, sendcan):
        if not self.LoC:
            self.LoC = LongControl(CS.CP, tesla_compute_gb)

        can_sends = []
        if CS.pedal_interceptor_available and not CS.cstm_btns.get_button_status(
                "pedal"):
            # pedal hardware, enable button
            CS.cstm_btns.set_button_status("pedal", 1)
            print "enabling pedal"
        elif not CS.pedal_interceptor_available:
            if CS.cstm_btns.get_button_status("pedal"):
                # no pedal hardware, disable button
                CS.cstm_btns.set_button_status("pedal", 0)
                print "disabling pedal"
            print "Pedal unavailable."
            return

        # check if we had error before
        if self.pedal_interceptor_state != CS.pedal_interceptor_state:
            self.pedal_interceptor_state = CS.pedal_interceptor_state
            CS.cstm_btns.set_button_status(
                "pedal", 1 if self.pedal_interceptor_state > 0 else 0)
            if self.pedal_interceptor_state > 0:
                # send reset command
                idx = self.pedal_idx
                self.pedal_idx = (self.pedal_idx + 1) % 16
                can_sends.append(teslacan.create_pedal_command_msg(0, 0, idx))
                sendcan.send(
                    can_list_to_can_capnp(can_sends,
                                          msgtype='sendcan').to_bytes())
                CS.UE.custom_alert_message(
                    3, "Pedal Interceptor Off (state %s)" %
                    self.pedal_interceptor_state, 150, 3)
            else:
                CS.UE.custom_alert_message(3, "Pedal Interceptor On", 150, 3)
        # disable on brake
        if CS.brake_pressed and self.enable_pedal_cruise:
            self.enable_pedal_cruise = False
            self.reset(0.)
            CS.UE.custom_alert_message(3, "PDL Disabled", 150, 4)
            CS.cstm_btns.set_button_status("pedal", 1)
            print "brake pressed"

        prev_enable_pedal_cruise = self.enable_pedal_cruise
        # process any stalk movement
        curr_time_ms = _current_time_millis()
        speed_uom_kph = 1.
        if CS.imperial_speed_units:
            speed_uom_kph = CV.MPH_TO_KPH
        if (CS.cruise_buttons == CruiseButtons.MAIN
                and self.prev_cruise_buttons != CruiseButtons.MAIN):
            double_pull = curr_time_ms - self.last_cruise_stalk_pull_time < 750
            self.last_cruise_stalk_pull_time = curr_time_ms
            ready = (CS.cstm_btns.get_button_status("pedal") > PCCState.OFF
                     and enabled and CruiseState.is_off(CS.pcm_acc_status))
            if ready and double_pull:
                # A double pull enables ACC. updating the max ACC speed if necessary.
                self.enable_pedal_cruise = True
                self.LoC.reset(CS.v_ego)
                # Increase PCC speed to match current, if applicable.
                self.pedal_speed_kph = max(CS.v_ego * CV.MS_TO_KPH,
                                           self.pedal_speed_kph)
            else:
                # A single pull disables PCC (falling back to just steering).
                self.enable_pedal_cruise = False
        # Handle pressing the cancel button.
        elif CS.cruise_buttons == CruiseButtons.CANCEL:
            self.enable_pedal_cruise = False
            self.pedal_speed_kph = 0.
            self.last_cruise_stalk_pull_time = 0
        # Handle pressing up and down buttons.
        elif (self.enable_pedal_cruise
              and CS.cruise_buttons != self.prev_cruise_buttons):
            # Real stalk command while PCC is already enabled. Adjust the max PCC
            # speed if necessary.
            actual_speed_kph = CS.v_ego * CV.MS_TO_KPH
            if CS.cruise_buttons == CruiseButtons.RES_ACCEL:
                self.pedal_speed_kph = max(self.pedal_speed_kph,
                                           actual_speed_kph) + speed_uom_kph
            elif CS.cruise_buttons == CruiseButtons.RES_ACCEL_2ND:
                self.pedal_speed_kph = max(
                    self.pedal_speed_kph, actual_speed_kph) + 5 * speed_uom_kph
            elif CS.cruise_buttons == CruiseButtons.DECEL_SET:
                self.pedal_speed_kph = min(self.pedal_speed_kph,
                                           actual_speed_kph) - speed_uom_kph
            elif CS.cruise_buttons == CruiseButtons.DECEL_2ND:
                self.pedal_speed_kph = min(
                    self.pedal_speed_kph, actual_speed_kph) - 5 * speed_uom_kph
            # Clip PCC speed between 0 and 170 KPH.
            self.pedal_speed_kph = clip(self.pedal_speed_kph, MIN_PCC_V_KPH,
                                        MAX_PCC_V_KPH)
        # If something disabled cruise control, disable PCC too
        elif self.enable_pedal_cruise and CS.pcm_acc_status:
            self.enable_pedal_cruise = False

        # Notify if PCC was toggled
        if prev_enable_pedal_cruise and not self.enable_pedal_cruise:
            CS.UE.custom_alert_message(3, "PCC Disabled", 150, 4)
            CS.cstm_btns.set_button_status("pedal", PCCState.STANDBY)
        elif self.enable_pedal_cruise and not prev_enable_pedal_cruise:
            CS.UE.custom_alert_message(2, "PCC Enabled", 150)
            CS.cstm_btns.set_button_status("pedal", PCCState.ENABLED)

        # Update the UI to show whether the current car state allows PCC.
        if CS.cstm_btns.get_button_status("pedal") in [
                PCCState.STANDBY, PCCState.NOT_READY
        ]:
            if enabled and CruiseState.is_off(CS.pcm_acc_status):
                CS.cstm_btns.set_button_status("pedal", PCCState.STANDBY)
            else:
                CS.cstm_btns.set_button_status("pedal", PCCState.NOT_READY)

        # Update prev state after all other actions.
        self.prev_cruise_buttons = CS.cruise_buttons
        self.prev_pcm_acc_status = CS.pcm_acc_status
示例#4
0
    def update(self, sendcan, enabled, CS, frame, actuators, pcm_cancel_cmd,
               hud_alert, audible_alert):

        # *** compute control surfaces ***
        ts = sec_since_boot()

        # steer torque is converted back to CAN reference (positive when steering right)
        apply_accel = actuators.gas - actuators.brake
        apply_accel, self.accel_steady = accel_hysteresis(
            apply_accel, self.accel_steady, enabled)
        apply_accel = int(
            round(clip(apply_accel * ACCEL_SCALE, ACCEL_MIN, ACCEL_MAX)))

        # steer torque is converted back to CAN reference (positive when steering right)
        apply_steer = int(round(actuators.steer * STEER_MAX))

        max_lim = min(
            max(CS.steer_torque_motor + STEER_ERROR_MAX, STEER_ERROR_MAX),
            STEER_MAX)
        min_lim = max(
            min(CS.steer_torque_motor - STEER_ERROR_MAX, -STEER_ERROR_MAX),
            -STEER_MAX)

        apply_steer = clip(apply_steer, min_lim, max_lim)

        # slow rate if steer torque increases in magnitude
        if self.last_steer > 0:
            apply_steer = clip(
                apply_steer,
                max(self.last_steer - STEER_DELTA_DOWN, -STEER_DELTA_UP),
                self.last_steer + STEER_DELTA_UP)
        else:
            apply_steer = clip(
                apply_steer, self.last_steer - STEER_DELTA_UP,
                min(self.last_steer + STEER_DELTA_DOWN, STEER_DELTA_UP))

        if not enabled and CS.pcm_acc_status:
            # send pcm acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated
            pcm_cancel_cmd = 1

        # dropping torque immediately might cause eps to temp fault. On the other hand, safety_toyota
        # cuts steer torque immediately anyway TODO: monitor if this is a real issue
        if not enabled or CS.steer_error:
            apply_steer = 0

        # on entering standstill, send standstill request
        if CS.standstill and not self.last_standstill:
            self.standstill_req = True
        if CS.pcm_acc_status != 8:
            # pcm entered standstill or it's disabled
            self.standstill_req = False

        self.last_steer = apply_steer
        self.last_accel = apply_accel
        self.last_standstill = CS.standstill

        can_sends = []

        #*** control msgs ***
        #print "steer", apply_steer, min_lim, max_lim, CS.steer_torque_motor

        # toyota can trace shows this message at 42Hz, with counter adding alternatively 1 and 2;
        # sending it at 100Hz seem to allow a higher rate limit, as the rate limit seems imposed
        # on consecutive messages
        if ECU.CAM in self.fake_ecus:
            can_sends.append(create_steer_command(apply_steer, frame))

        if ECU.APGS in self.fake_ecus:
            can_sends.append(create_ipas_steer_command(apply_steer))

        # accel cmd comes from DSU, but we can spam can to cancel the system even if we are using lat only control
        if (frame % 3 == 0 and ECU.DSU in self.fake_ecus) or (
                pcm_cancel_cmd and ECU.CAM in self.fake_ecus):
            if ECU.DSU in self.fake_ecus:
                can_sends.append(
                    create_accel_command(apply_accel, pcm_cancel_cmd,
                                         self.standstill_req))
            else:
                can_sends.append(create_accel_command(0, pcm_cancel_cmd,
                                                      False))

        if frame % 10 == 0 and ECU.CAM in self.fake_ecus:
            for addr in TARGET_IDS:
                can_sends.append(create_video_target(frame / 10, addr))

        # ui mesg is at 100Hz but we send asap if:
        # - there is something to display
        # - there is something to stop displaying
        alert_out = process_hud_alert(hud_alert, audible_alert)
        steer, fcw, sound1, sound2 = alert_out

        if (any(alert_out) and not self.alert_active) or \
           (not any(alert_out) and self.alert_active):
            send_ui = True
            self.alert_active = not self.alert_active
        else:
            send_ui = False

        if (frame % 100 == 0 or send_ui) and ECU.CAM in self.fake_ecus:
            can_sends.append(create_ui_command(steer, sound1, sound2))
            can_sends.append(create_fcw_command(fcw))

        #*** static msgs ***

        for (addr, ecu, cars, bus, fr_step, vl) in STATIC_MSGS:
            if frame % fr_step == 0 and ecu in self.fake_ecus and self.car_fingerprint in cars:
                # special cases
                if fr_step == 5 and ecu == ECU.CAM and bus == 1:
                    cnt = (((frame / 5) % 7) + 1) << 5
                    vl = chr(cnt) + vl
                elif addr in (0x489, 0x48a) and bus == 0:
                    # add counter for those 2 messages (last 4 bits)
                    cnt = ((frame / 100) % 0xf) + 1
                    if addr == 0x48a:
                        # 0x48a has a 8 preceding the counter
                        cnt += 1 << 7
                    vl += chr(cnt)

                can_sends.append(make_can_msg(addr, vl, bus, False))

        sendcan.send(
            can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
示例#5
0
    def update(self, sendcan, enabled, CS, frame, actuators, \
               pcm_speed, pcm_override, pcm_cancel_cmd, pcm_accel, \
               hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert, \
               snd_beep, snd_chime):
        """ Controls thread """

        # TODO: Make the accord work.
        if CS.accord or not self.enable_camera:
            return

        # *** apply brake hysteresis ***
        brake, self.braking, self.brake_steady = actuator_hystereses(
            actuators.brake, self.braking, self.brake_steady, CS.v_ego,
            CS.civic)

        # *** no output if not enabled ***
        if not enabled and CS.pcm_acc_status:
            # send pcm acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated
            pcm_cancel_cmd = True

        # *** rate limit after the enable check ***
        self.brake_last = rate_limit(brake, self.brake_last, -2., 1. / 100)

        # vehicle hud display, wait for one update from 10Hz 0x304 msg
        #TODO: use enum!!
        if hud_show_lanes:
            hud_lanes = 0x04
        else:
            hud_lanes = 0x00

        # TODO: factor this out better
        if enabled:
            if hud_show_car:
                hud_car = 0xe0
            else:
                hud_car = 0xd0
        else:
            hud_car = 0xc0

        #print chime, alert_id, hud_alert
        fcw_display, steer_required, acc_alert = process_hud_alert(hud_alert)

        hud = HUDData(int(pcm_accel), int(round(hud_v_cruise)), 0x01,
                      hud_car, 0xc1, 0x41, hud_lanes + steer_required,
                      int(snd_beep), 0x48, (snd_chime << 5) + fcw_display,
                      acc_alert)

        if not all(isinstance(x, int) and 0 <= x < 256 for x in hud):
            print "INVALID HUD", hud
            hud = HUDData(0xc6, 255, 64, 0xc0, 209, 0x41, 0x40, 0, 0x48, 0, 0)

        # **** process the car messages ****

        # *** compute control surfaces ***
        tt = sec_since_boot()
        GAS_MAX = 1004
        BRAKE_MAX = 1024 / 4
        if CS.civic:
            is_fw_modified = os.getenv("DONGLE_ID") in ['b0f5a01cf604185cxxx']
            STEER_MAX = 0x1FFF if is_fw_modified else 0x1000
        elif CS.crv:
            STEER_MAX = 0x300  # CR-V only uses 12-bits and requires a lower value
        else:
            STEER_MAX = 0xF00
        GAS_OFFSET = 328

        # steer torque is converted back to CAN reference (positive when steering right)
        apply_gas = int(clip(actuators.gas * GAS_MAX, 0, GAS_MAX - 1))
        apply_brake = int(clip(self.brake_last * BRAKE_MAX, 0, BRAKE_MAX - 1))
        apply_steer = int(
            clip(-actuators.steer * STEER_MAX, -STEER_MAX, STEER_MAX))

        # any other cp.vl[0x18F]['STEER_STATUS'] is common and can happen during user override. sending 0 torque to avoid EPS sending error 5
        if CS.steer_not_allowed:
            apply_steer = 0

        # Send CAN commands.
        can_sends = []

        # Send steering command.
        if CS.accord:
            idx = frame % 2
            can_sends.append(
                hondacan.create_accord_steering_control(apply_steer, idx))
        else:
            idx = frame % 4
            can_sends.extend(
                hondacan.create_steering_control(apply_steer, CS.crv, idx))

        # Send gas and brake commands.
        if (frame % 2) == 0:
            idx = (frame / 2) % 4
            can_sends.append(
                hondacan.create_brake_command(apply_brake, pcm_override,
                                              pcm_cancel_cmd, hud.chime, idx))
            if not CS.brake_only:
                # send exactly zero if apply_gas is zero. Interceptor will send the max between read value and apply_gas.
                # This prevents unexpected pedal range rescaling
                gas_amount = (apply_gas + GAS_OFFSET) * (apply_gas > 0)
                can_sends.append(hondacan.create_gas_command(gas_amount, idx))

        # Send dashboard UI commands.
        if (frame % 10) == 0:
            idx = (frame / 10) % 4
            can_sends.extend(
                hondacan.create_ui_commands(pcm_speed, hud, CS.civic,
                                            CS.accord, CS.crv, idx))

        # radar at 20Hz, but these msgs need to be sent at 50Hz on ilx (seems like an Acura bug)
        if CS.civic or CS.accord or CS.crv:
            radar_send_step = 5
        else:
            radar_send_step = 2

        if (frame % radar_send_step) == 0:
            idx = (frame / radar_send_step) % 4
            can_sends.extend(
                hondacan.create_radar_commands(CS.v_ego, CS.civic, CS.accord,
                                               CS.crv, idx))

        sendcan.send(
            can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
示例#6
0
 def _can_tx(self, tx_addr, dat, bus):
     """Helper function to send single message"""
     msg = [tx_addr, 0, dat, bus]
     self.sendcan.send(can_list_to_can_capnp([msg], msgtype='sendcan'))
示例#7
0
def data_send(sm, pm, CS, CI, CP, VM, state, events, actuators, v_cruise_kph, rk, AM,
              LaC, LoC, read_only, start_time, v_acc, a_acc, lac_log, events_prev,
              last_blinker_frame, is_ldw_enabled, can_error_counter):
  """Send actuators and hud commands to the car, send controlsstate and MPC logging"""

  CC = car.CarControl.new_message()
  CC.enabled = isEnabled(state)
  CC.actuators = actuators

  CC.cruiseControl.override = True
  CC.cruiseControl.cancel = not CP.enableCruise or (not isEnabled(state) and CS.cruiseState.enabled)

  # Some override values for Honda
  brake_discount = (1.0 - clip(actuators.brake * 3., 0.0, 1.0))  # brake discount removes a sharp nonlinearity
  CC.cruiseControl.speedOverride = float(max(0.0, (LoC.v_pid + CS.cruiseState.speedOffset) * brake_discount) if CP.enableCruise else 0.0)
  CC.cruiseControl.accelOverride = CI.calc_accel_override(CS.aEgo, sm['plan'].aTarget, CS.vEgo, sm['plan'].vTarget)

  CC.hudControl.setSpeed = float(v_cruise_kph * CV.KPH_TO_MS)
  CC.hudControl.speedVisible = isEnabled(state)
  CC.hudControl.lanesVisible = isEnabled(state)
  CC.hudControl.leadVisible = sm['plan'].hasLead

  right_lane_visible = sm['pathPlan'].rProb > 0.5
  left_lane_visible = sm['pathPlan'].lProb > 0.5
  CC.hudControl.rightLaneVisible = bool(right_lane_visible)
  CC.hudControl.leftLaneVisible = bool(left_lane_visible)

  recent_blinker = (sm.frame - last_blinker_frame) * DT_CTRL < 5.0  # 5s blinker cooldown
  calibrated = sm['liveCalibration'].calStatus == Calibration.CALIBRATED
  ldw_allowed = CS.vEgo > 31 * CV.MPH_TO_MS and not recent_blinker and is_ldw_enabled and not isActive(state) and calibrated

  md = sm['model']
  if len(md.meta.desirePrediction):
    l_lane_change_prob = md.meta.desirePrediction[log.PathPlan.Desire.laneChangeLeft - 1]
    r_lane_change_prob = md.meta.desirePrediction[log.PathPlan.Desire.laneChangeRight - 1]

    l_lane_close = left_lane_visible and (sm['pathPlan'].lPoly[3] < (1.08 - CAMERA_OFFSET))
    r_lane_close = right_lane_visible and (sm['pathPlan'].rPoly[3] > -(1.08 + CAMERA_OFFSET))

    if ldw_allowed:
      CC.hudControl.leftLaneDepart = bool(l_lane_change_prob > LANE_DEPARTURE_THRESHOLD and l_lane_close)
      CC.hudControl.rightLaneDepart = bool(r_lane_change_prob > LANE_DEPARTURE_THRESHOLD and r_lane_close)

  if CC.hudControl.rightLaneDepart or CC.hudControl.leftLaneDepart:
    AM.add(sm.frame, 'ldwPermanent', False)
    events.append(create_event('ldw', [ET.PERMANENT]))

  AM.process_alerts(sm.frame)
  CC.hudControl.visualAlert = AM.visual_alert

  if not read_only:
    # send car controls over can
    can_sends = CI.apply(CC)
    pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid))

  force_decel = (sm['dMonitoringState'].awarenessStatus < 0.) or (state == State.softDisabling)

  # controlsState
  dat = messaging.new_message('controlsState')
  dat.valid = CS.canValid
  dat.controlsState = {
    "alertText1": AM.alert_text_1,
    "alertText2": AM.alert_text_2,
    "alertSize": AM.alert_size,
    "alertStatus": AM.alert_status,
    "alertBlinkingRate": AM.alert_rate,
    "alertType": AM.alert_type,
    "alertSound": AM.audible_alert,
    "driverMonitoringOn": sm['dMonitoringState'].faceDetected,
    "canMonoTimes": list(CS.canMonoTimes),
    "planMonoTime": sm.logMonoTime['plan'],
    "pathPlanMonoTime": sm.logMonoTime['pathPlan'],
    "enabled": isEnabled(state),
    "active": isActive(state),
    "vEgo": CS.vEgo,
    "vEgoRaw": CS.vEgoRaw,
    "angleSteers": CS.steeringAngle,
    "curvature": VM.calc_curvature((CS.steeringAngle - sm['pathPlan'].angleOffset) * CV.DEG_TO_RAD, CS.vEgo),
    "steerOverride": CS.steeringPressed,
    "state": state,
    "engageable": not bool(get_events(events, [ET.NO_ENTRY])),
    "longControlState": LoC.long_control_state,
    "vPid": float(LoC.v_pid),
    "vCruise": float(v_cruise_kph),
    "upAccelCmd": float(LoC.pid.p),
    "uiAccelCmd": float(LoC.pid.i),
    "ufAccelCmd": float(LoC.pid.f),
    "angleSteersDes": float(LaC.angle_steers_des),
    "vTargetLead": float(v_acc),
    "aTarget": float(a_acc),
    "jerkFactor": float(sm['plan'].jerkFactor),
    "gpsPlannerActive": sm['plan'].gpsPlannerActive,
    "vCurvature": sm['plan'].vCurvature,
    "decelForModel": sm['plan'].longitudinalPlanSource == log.Plan.LongitudinalPlanSource.model,
    "cumLagMs": -rk.remaining * 1000.,
    "startMonoTime": int(start_time * 1e9),
    "mapValid": sm['plan'].mapValid,
    "forceDecel": bool(force_decel),
    "canErrorCounter": can_error_counter,
  }

  if CP.lateralTuning.which() == 'pid':
    dat.controlsState.lateralControlState.pidState = lac_log
  elif CP.lateralTuning.which() == 'lqr':
    dat.controlsState.lateralControlState.lqrState = lac_log
  elif CP.lateralTuning.which() == 'indi':
    dat.controlsState.lateralControlState.indiState = lac_log
  pm.send('controlsState', dat)

  # carState
  cs_send = messaging.new_message('carState')
  cs_send.valid = CS.canValid
  cs_send.carState = CS
  cs_send.carState.events = events
  pm.send('carState', cs_send)

  # carEvents - logged every second or on change
  events_bytes = events_to_bytes(events)
  if (sm.frame % int(1. / DT_CTRL) == 0) or (events_bytes != events_prev):
    ce_send = messaging.new_message('carEvents', len(events))
    ce_send.carEvents = events
    pm.send('carEvents', ce_send)

  # carParams - logged every 50 seconds (> 1 per segment)
  if (sm.frame % int(50. / DT_CTRL) == 0):
    cp_send = messaging.new_message('carParams')
    cp_send.carParams = CP
    pm.send('carParams', cp_send)

  # carControl
  cc_send = messaging.new_message('carControl')
  cc_send.valid = CS.canValid
  cc_send.carControl = CC
  pm.send('carControl', cc_send)

  return CC, events_bytes
示例#8
0
  def update(self, sendcan, enabled, CS, frame, actuators,
             pcm_cancel_cmd, hud_alert, audible_alert, forwarding_camera):
    #update custom UI buttons and alerts
    CS.UE.update_custom_ui()
    if (frame % 1000 == 0):
      CS.cstm_btns.send_button_info()
      CS.UE.uiSetCarEvent(CS.cstm_btns.car_folder,CS.cstm_btns.car_name)

    # *** compute control surfaces ***

    # gas and brake
    apply_accel = actuators.gas - actuators.brake
    apply_accel, self.accel_steady = accel_hysteresis(apply_accel, self.accel_steady, enabled)
    apply_accel = clip(apply_accel * ACCEL_SCALE, ACCEL_MIN, ACCEL_MAX)
    # Get the angle from ALCA.
    alca_enabled = False
    alca_steer = 0.
    alca_angle = 0.
    turn_signal_needed = 0
    # Update ALCA status and custom button every 0.1 sec.
    if self.ALCA.pid == None:
      self.ALCA.set_pid(CS)
    if (frame % 10 == 0):
      self.ALCA.update_status(CS.cstm_btns.get_button_status("alca") > 0)
    # steer torque
    alca_angle, alca_steer, alca_enabled, turn_signal_needed = self.ALCA.update(enabled, CS, frame, actuators)
    apply_steer = int(round(alca_steer * STEER_MAX))

    max_lim = min(max(CS.steer_torque_motor + STEER_ERROR_MAX, STEER_ERROR_MAX), STEER_MAX)
    min_lim = max(min(CS.steer_torque_motor - STEER_ERROR_MAX, -STEER_ERROR_MAX), -STEER_MAX)

    apply_steer = clip(apply_steer, min_lim, max_lim)

    # slow rate if steer torque increases in magnitude
    if self.last_steer > 0:
      apply_steer = clip(apply_steer, max(self.last_steer - STEER_DELTA_DOWN, - STEER_DELTA_UP), self.last_steer + STEER_DELTA_UP)
    else:
      apply_steer = clip(apply_steer, self.last_steer - STEER_DELTA_UP, min(self.last_steer + STEER_DELTA_DOWN, STEER_DELTA_UP))

    # dropping torque immediately might cause eps to temp fault. On the other hand, safety_toyota
    # cuts steer torque immediately anyway TODO: monitor if this is a real issue
    # only cut torque when steer state is a known fault
    if CS.steer_state in [9, 25]:
      self.last_fault_frame = frame

    # Cut steering for 2s after fault
    if not enabled or (frame - self.last_fault_frame < 200):
      apply_steer = 0
      apply_steer_req = 0
    else:
      apply_steer_req = 1

    self.steer_angle_enabled, self.ipas_reset_counter = \
      ipas_state_transition(self.steer_angle_enabled, enabled, CS.ipas_active, self.ipas_reset_counter)
    #print self.steer_angle_enabled, self.ipas_reset_counter, CS.ipas_active


    # steer angle
    if self.steer_angle_enabled and CS.ipas_active:

      apply_angle = alca_angle
      angle_lim = interp(CS.v_ego, ANGLE_MAX_BP, ANGLE_MAX_V)
      apply_angle = clip(apply_angle, -angle_lim, angle_lim)

      # windup slower
      if self.last_angle * apply_angle > 0. and abs(apply_angle) > abs(self.last_angle):
        angle_rate_lim = interp(CS.v_ego, ANGLE_DELTA_BP, ANGLE_DELTA_V)
      else:
        angle_rate_lim = interp(CS.v_ego, ANGLE_DELTA_BP, ANGLE_DELTA_VU)

      apply_angle = clip(apply_angle, self.last_angle - angle_rate_lim, self.last_angle + angle_rate_lim)
    else:
      apply_angle = CS.angle_steers

    if not enabled and CS.pcm_acc_status:
      # send pcm acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated
      pcm_cancel_cmd = 1

    # on entering standstill, send standstill request
    if CS.standstill and not self.last_standstill:
      self.standstill_req = True
    if CS.pcm_acc_status != 8:
      # pcm entered standstill or it's disabled
      self.standstill_req = False

    self.last_steer = apply_steer
    self.last_angle = apply_angle
    self.last_accel = apply_accel
    self.last_standstill = CS.standstill

    can_sends = []

    #*** control msgs ***
    #print "steer", apply_steer, min_lim, max_lim, CS.steer_torque_motor

    # toyota can trace shows this message at 42Hz, with counter adding alternatively 1 and 2;
    # sending it at 100Hz seem to allow a higher rate limit, as the rate limit seems imposed
    # on consecutive messages
    if ECU.CAM in self.fake_ecus:
      if self.angle_control:
        can_sends.append(create_steer_command(self.packer, 0., 0, frame))
      else:
        can_sends.append(create_steer_command(self.packer, apply_steer, apply_steer_req, frame))

    if self.angle_control:
      can_sends.append(create_ipas_steer_command(self.packer, apply_angle, self.steer_angle_enabled,
                                                 ECU.APGS in self.fake_ecus))
    elif ECU.APGS in self.fake_ecus:
      can_sends.append(create_ipas_steer_command(self.packer, 0, 0, True))

    # accel cmd comes from DSU, but we can spam can to cancel the system even if we are using lat only control
    if (frame % 3 == 0 and ECU.DSU in self.fake_ecus) or (pcm_cancel_cmd and ECU.CAM in self.fake_ecus):
      if ECU.DSU in self.fake_ecus:
        can_sends.append(create_accel_command(self.packer, apply_accel, pcm_cancel_cmd, self.standstill_req))
      else:
        can_sends.append(create_accel_command(self.packer, 0, pcm_cancel_cmd, False))

    if frame % 10 == 0 and ECU.CAM in self.fake_ecus and not forwarding_camera:
      for addr in TARGET_IDS:
        can_sends.append(create_video_target(frame/10, addr))

    # ui mesg is at 100Hz but we send asap if:
    # - there is something to display
    # - there is something to stop displaying
    alert_out = process_hud_alert(hud_alert, audible_alert)
    steer, fcw, sound1, sound2 = alert_out

    if (any(alert_out) and not self.alert_active) or \
       (not any(alert_out) and self.alert_active):
      send_ui = True
      self.alert_active = not self.alert_active
    else:
      send_ui = False

    if (frame % 100 == 0 or send_ui) and ECU.CAM in self.fake_ecus:
      can_sends.append(create_ui_command(self.packer, steer, sound1, sound2))

    if frame % 100 == 0 and ECU.DSU in self.fake_ecus:
      can_sends.append(create_fcw_command(self.packer, fcw))

    #*** static msgs ***

    for (addr, ecu, cars, bus, fr_step, vl) in STATIC_MSGS:
      if frame % fr_step == 0 and ecu in self.fake_ecus and self.car_fingerprint in cars and not (ecu == ECU.CAM and forwarding_camera):
        # special cases
        if fr_step == 5 and ecu == ECU.CAM and bus == 1:
          cnt = (((frame / 5) % 7) + 1) << 5
          vl = chr(cnt) + vl
        elif addr in (0x489, 0x48a) and bus == 0:
          # add counter for those 2 messages (last 4 bits)
          cnt = ((frame/100)%0xf) + 1
          if addr == 0x48a:
            # 0x48a has a 8 preceding the counter
            cnt += 1 << 7
          vl += chr(cnt)

        can_sends.append(make_can_msg(addr, vl, bus, False))


    sendcan.send(can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
示例#9
0
    def update(self, sendcan, enabled, CS, frame, actuators, \
               pcm_speed, pcm_override, pcm_cancel_cmd, pcm_accel, \
               hud_v_cruise, hud_show_lanes, hud_show_car, \
               hud_alert, snd_beep, snd_chime):
        """ Controls thread """

        if not self.enable_camera:
            return

        # *** apply brake hysteresis ***
        brake, self.braking, self.brake_steady = actuator_hystereses(
            actuators.brake, self.braking, self.brake_steady, CS.v_ego,
            CS.CP.carFingerprint)

        # *** no output if not enabled ***
        if not enabled and CS.pcm_acc_status:
            # send pcm acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated
            pcm_cancel_cmd = True

        # *** rate limit after the enable check ***
        self.brake_last = rate_limit(brake, self.brake_last, -2., 1. / 100)

        # vehicle hud display, wait for one update from 10Hz 0x304 msg
        if hud_show_lanes:
            hud_lanes = 1
        else:
            hud_lanes = 0

        if enabled:
            if hud_show_car:
                hud_car = 2
            else:
                hud_car = 1
        else:
            hud_car = 0

        # For lateral control-only, send chimes as a beep since we don't send 0x1fa
        if CS.CP.radarOffCan:
            snd_beep = snd_beep if snd_beep != 0 else snd_chime

        #print chime, alert_id, hud_alert
        fcw_display, steer_required, acc_alert = process_hud_alert(hud_alert)

        hud = HUDData(int(pcm_accel),
                      int(round(hud_v_cruise)), 1, hud_car, 0xc1, hud_lanes,
                      int(snd_beep), snd_chime, fcw_display, acc_alert,
                      steer_required, CS.read_distance_lines)

        # **** process the car messages ****

        # *** compute control surfaces ***
        BRAKE_MAX = 1024 / 4
        if CS.CP.carFingerprint in (CAR.ACURA_ILX):
            STEER_MAX = 0xF00
        elif CS.CP.carFingerprint in (CAR.CRV, CAR.ACURA_RDX):
            STEER_MAX = 0x3e8  # CR-V only uses 12-bits and requires a lower value (max value from energee)
        else:
            STEER_MAX = 0x1000

        #update custom UI buttons and alerts
        CS.UE.update_custom_ui()
        if (frame % 1000 == 0):
            CS.cstm_btns.send_button_info()
            CS.UE.uiSetCarEvent(CS.cstm_btns.car_folder, CS.cstm_btns.car_name)

        # Get the angle from ALCA.
        alca_enabled = False
        alca_steer = 0.
        alca_angle = 0.
        turn_signal_needed = 0
        # Update ALCA status and custom button every 0.1 sec.
        if self.ALCA.pid == None:
            self.ALCA.set_pid(CS)
        if (frame % 10 == 0):
            self.ALCA.update_status(CS.cstm_btns.get_button_status("alca") > 0)
        # steer torque
        alca_angle, alca_steer, alca_enabled, turn_signal_needed = self.ALCA.update(
            enabled, CS, frame, actuators)

        # steer torque is converted back to CAN reference (positive when steering right)
        apply_gas = clip(actuators.gas, 0., 1.)
        apply_brake = int(clip(self.brake_last * BRAKE_MAX, 0, BRAKE_MAX - 1))
        apply_steer = int(clip(-alca_steer * STEER_MAX, -STEER_MAX, STEER_MAX))
        if not CS.lane_departure_toggle_on:
            apply_steer = 0
        # any other cp.vl[0x18F]['STEER_STATUS'] is common and can happen during user override. sending 0 torque to avoid EPS sending error 5
        lkas_active = enabled and not CS.steer_not_allowed and CS.lkMode

        # Send CAN commands.
        can_sends = []

        # Send steering command.
        idx = frame % 4
        can_sends.append(
            hondacan.create_steering_control(self.packer, apply_steer,
                                             lkas_active, CS.CP.carFingerprint,
                                             idx))

        # Send dashboard UI commands.
        if (frame % 10) == 0:
            idx = (frame / 10) % 4
            can_sends.extend(
                hondacan.create_ui_commands(self.packer, pcm_speed, hud,
                                            CS.CP.carFingerprint, idx))

        if CS.CP.radarOffCan:
            # If using stock ACC, spam cancel command to kill gas when OP disengages.
            if pcm_cancel_cmd:
                can_sends.append(
                    hondacan.spam_buttons_command(self.packer,
                                                  CruiseButtons.CANCEL, idx))
            elif CS.stopped:
                if CS.CP.carFingerprint in (CAR.ACCORD, CAR.ACCORD_15,
                                            CAR.ACCORDH):
                    if CS.lead_distance > (self.prev_lead_distance +
                                           float(kegman.conf['leadDistance'])):
                        can_sends.append(
                            hondacan.spam_buttons_command(
                                self.packer, CruiseButtons.RES_ACCEL, idx))
                elif CS.CP.carFingerprint in (CAR.CIVIC_BOSCH):
                    if CS.hud_lead == 1:
                        can_sends.append(
                            hondacan.spam_buttons_command(
                                self.packer, CruiseButtons.RES_ACCEL, idx))
                else:
                    can_sends.append(
                        hondacan.spam_buttons_command(self.packer,
                                                      CruiseButtons.RES_ACCEL,
                                                      idx))
            else:
                self.prev_lead_distance = CS.lead_distance

        else:
            # Send gas and brake commands.
            if (frame % 2) == 0:
                idx = frame / 2
                pump_on, self.last_pump_ts = brake_pump_hysteresys(
                    apply_brake, self.apply_brake_last, self.last_pump_ts)
                can_sends.append(
                    hondacan.create_brake_command(self.packer, apply_brake,
                                                  pump_on, pcm_override,
                                                  pcm_cancel_cmd, hud.chime,
                                                  hud.fcw, idx))
                self.apply_brake_last = apply_brake

                if CS.CP.enableGasInterceptor:
                    # send exactly zero if apply_gas is zero. Interceptor will send the max between read value and apply_gas.
                    # This prevents unexpected pedal range rescaling
                    can_sends.append(
                        create_gas_command(self.packer, apply_gas, idx))

        sendcan.send(
            can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
  def test_honda_lkas_hud(self):
    self.longMessage = True

    sendcan = messaging.pub_sock('sendcan')

    car_name = HONDA.CIVIC
    params = CarInterface.get_params(car_name)
    CI = CarInterface(params, CarController)

    # Get parser
    parser_signals = [
      ('SET_ME_X41', 'LKAS_HUD', 0),
      ('SET_ME_X48', 'LKAS_HUD', 0),
      ('STEERING_REQUIRED', 'LKAS_HUD', 0),
      ('SOLID_LANES', 'LKAS_HUD', 0),
      ('LEAD_SPEED', 'RADAR_HUD', 0),
      ('LEAD_STATE', 'RADAR_HUD', 0),
      ('LEAD_DISTANCE', 'RADAR_HUD', 0),
      ('ACC_ALERTS', 'RADAR_HUD', 0),
    ]

    VA = car.CarControl.HUDControl.VisualAlert

    parser = CANParser(CI.cp.dbc_name, parser_signals, [], 0, sendcan=True, tcp_addr="127.0.0.1")
    time.sleep(0.2)  # Slow joiner syndrome


    alerts = {
      VA.none: 0,
      VA.brakePressed: 10,
      VA.wrongGear: 6,
      VA.seatbeltUnbuckled: 5,
      VA.speedTooHigh: 8,
    }

    for steer_required in [True, False]:
      for lanes in [True, False]:
        for alert in alerts.keys():
          control = car.CarControl.new_message()
          hud = car.CarControl.HUDControl.new_message()

          control.enabled = True

          if steer_required:
            hud.visualAlert = VA.steerRequired
          else:
            hud.visualAlert = alert

          hud.lanesVisible = lanes
          control.hudControl = hud

          CI.update(control)

          for _ in range(25):
            can_sends = CI.apply(control)
            sendcan.send(can_list_to_can_capnp(can_sends, msgtype='sendcan'))

          for _ in range(5):
            parser.update(int(sec_since_boot() * 1e9), False)
            time.sleep(0.01)

          self.assertEqual(0x41, parser.vl['LKAS_HUD']['SET_ME_X41'])
          self.assertEqual(0x48, parser.vl['LKAS_HUD']['SET_ME_X48'])
          self.assertEqual(steer_required, parser.vl['LKAS_HUD']['STEERING_REQUIRED'])
          self.assertEqual(lanes, parser.vl['LKAS_HUD']['SOLID_LANES'])

          self.assertEqual(0x1fe, parser.vl['RADAR_HUD']['LEAD_SPEED'])
          self.assertEqual(0x7, parser.vl['RADAR_HUD']['LEAD_STATE'])
          self.assertEqual(0x1e, parser.vl['RADAR_HUD']['LEAD_DISTANCE'])
          self.assertEqual(alerts[alert] if not steer_required else 0, parser.vl['RADAR_HUD']['ACC_ALERTS'])
  def test_honda_brake(self):
    self.longMessage = True

    sendcan = messaging.pub_sock('sendcan')

    car_name = HONDA.CIVIC

    params = CarInterface.get_params(car_name)
    CI = CarInterface(params, CarController)

    # Get parser
    parser_signals = [
      ('COMPUTER_BRAKE', 'BRAKE_COMMAND', 0),
      ('BRAKE_PUMP_REQUEST', 'BRAKE_COMMAND', 0),  # pump_on
      ('CRUISE_OVERRIDE', 'BRAKE_COMMAND', 0),  # pcm_override
      ('CRUISE_FAULT_CMD', 'BRAKE_COMMAND', 0),  # pcm_fault_cmd
      ('CRUISE_CANCEL_CMD', 'BRAKE_COMMAND', 0),  # pcm_cancel_cmd
      ('COMPUTER_BRAKE_REQUEST', 'BRAKE_COMMAND', 0),  # brake_rq
      ('SET_ME_0X80', 'BRAKE_COMMAND', 0),
      ('BRAKE_LIGHTS', 'BRAKE_COMMAND', 0),  # brakelights
      ('FCW', 'BRAKE_COMMAND', 0),
    ]
    parser = CANParser(CI.cp.dbc_name, parser_signals, [], 0, sendcan=True, tcp_addr="127.0.0.1")
    time.sleep(0.2)  # Slow joiner syndrome

    VA = car.CarControl.HUDControl.VisualAlert

    for override in [True, False]:
      for cancel in [True, False]:
        for fcw in [True, False]:
          steps = 25 if not override and not cancel else 2
          for brake in np.linspace(0., 0.95, steps):
            control = car.CarControl.new_message()

            hud = car.CarControl.HUDControl.new_message()
            if fcw:
              hud.visualAlert = VA.fcw

            cruise = car.CarControl.CruiseControl.new_message()
            cruise.cancel = cancel
            cruise.override = override

            actuators = car.CarControl.Actuators.new_message()
            actuators.brake = float(brake)

            control.enabled = True
            control.actuators = actuators
            control.hudControl = hud
            control.cruiseControl = cruise

            CI.update(control)

            CI.CS.steer_not_allowed = False

            for _ in range(20):
              can_sends = CI.apply(control)
              sendcan.send(can_list_to_can_capnp(can_sends, msgtype='sendcan'))

            for _ in range(5):
              parser.update(int(sec_since_boot() * 1e9), False)
              time.sleep(0.01)

            brake_command = parser.vl['BRAKE_COMMAND']['COMPUTER_BRAKE']
            min_expected_brake = int(1024 / 4 * (actuators.brake - 0.02))
            max_expected_brake = int(1024 / 4 * (actuators.brake + 0.02))
            braking = actuators.brake > 0

            braking_ok = min_expected_brake <= brake_command <= max_expected_brake
            if steps == 2:
              braking_ok = True

            self.assertTrue(braking_ok, msg="Car: %s, brake %.2f" % (car_name, brake))
            self.assertEqual(0x80, parser.vl['BRAKE_COMMAND']['SET_ME_0X80'])
            self.assertEqual(braking, parser.vl['BRAKE_COMMAND']['BRAKE_PUMP_REQUEST'])
            self.assertEqual(braking, parser.vl['BRAKE_COMMAND']['COMPUTER_BRAKE_REQUEST'])
            self.assertEqual(braking, parser.vl['BRAKE_COMMAND']['BRAKE_LIGHTS'])
            self.assertFalse(parser.vl['BRAKE_COMMAND']['CRUISE_FAULT_CMD'])
            self.assertEqual(override, parser.vl['BRAKE_COMMAND']['CRUISE_OVERRIDE'])
            self.assertEqual(cancel, parser.vl['BRAKE_COMMAND']['CRUISE_CANCEL_CMD'])
            self.assertEqual(fcw, bool(parser.vl['BRAKE_COMMAND']['FCW']))
示例#12
0
sendcan = messaging.pub_sock('sendcan')


BEFORE = [
"\x10\x15\x30\x0B\x00\x00\x00\x00",
"\x21\x00\x00\x00\x00\x00\x00\x00",
]

LEFT = "\x22\x00\x00\x08\x00\x00\x00\x00"
RIGHT = "\x22\x00\x00\x04\x00\x00\x00\x00"
OFF = "\x22\x00\x00\x00\x00\x00\x00\x00"

AFTER = "\x23\x00\x00\x00\x00\x00\x00\x00"

i = 0
j = 0
while True:
   i += 1

   if i % 10 == 0:
     j += 1

   cur = RIGHT if j % 2 == 0 else OFF
   can_list = [make_can_msg(1984, d, 0, False) for d in BEFORE]
   can_list.append(make_can_msg(1984, cur, 0, False))
   can_list.append(make_can_msg(1984, AFTER, 0, False))

   for m in can_list:
     sendcan.send(can_list_to_can_capnp([m], msgtype='sendcan').to_bytes())
     time.sleep(0.01)
示例#13
0
    def update(self, sendcan, enabled, CS, frame, actuators):
        """ Controls thread """

        P = self.params

        # Send CAN commands.
        can_sends = []
        canbus = self.canbus

        ### STEER ###

        if (frame % P.STEER_STEP) == 0:

            final_steer = actuators.steer if enabled else 0.
            apply_steer = final_steer * P.STEER_MAX
            # limits due to driver torque
            driver_max_torque = P.STEER_MAX + (
                P.STEER_DRIVER_ALLOWANCE + CS.steer_torque_driver *
                P.STEER_DRIVER_FACTOR) * P.STEER_DRIVER_MULTIPLIER
            driver_min_torque = -P.STEER_MAX + (
                -P.STEER_DRIVER_ALLOWANCE + CS.steer_torque_driver *
                P.STEER_DRIVER_FACTOR) * P.STEER_DRIVER_MULTIPLIER
            max_steer_allowed = max(min(P.STEER_MAX, driver_max_torque), 0)
            min_steer_allowed = min(max(-P.STEER_MAX, driver_min_torque), 0)
            apply_steer = clip(apply_steer, min_steer_allowed,
                               max_steer_allowed)

            # slow rate if steer torque increases in magnitude
            if self.apply_steer_last > 0:
                apply_steer = clip(
                    apply_steer,
                    max(self.apply_steer_last - P.STEER_DELTA_DOWN,
                        -P.STEER_DELTA_UP),
                    self.apply_steer_last + P.STEER_DELTA_UP)
            else:
                apply_steer = clip(
                    apply_steer, self.apply_steer_last - P.STEER_DELTA_UP,
                    min(self.apply_steer_last + P.STEER_DELTA_DOWN,
                        P.STEER_DELTA_UP))

            apply_steer = int(round(apply_steer))
            self.apply_steer_last = apply_steer

            lkas_enabled = enabled and not CS.steer_not_allowed

            if not lkas_enabled:
                apply_steer = 0

            if self.car_fingerprint == CAR.OUTBACK:

                if apply_steer != 0:
                    chksm_steer = apply_steer * -1
                    chksm_engage = 1
                else:
                    chksm_steer = 0
                    chksm_engage = 0

                #counts from 0 to 7 then back to 0
                idx = (frame / P.STEER_STEP) % 8
                steer2 = (chksm_steer >> 8) & 0x1F
                steer1 = chksm_steer - (steer2 << 8)
                byte2 = steer2
                checksum = (idx + steer2 + steer1 + chksm_engage) % 256

            if (self.car_fingerprint == CAR.XV2018):

                #counts from 0 to 15 then back to 0 + 16 for enable bit

                chksm_steer = apply_steer * -1
                if chksm_steer != 0:
                    left3 = 32
                else:
                    left3 = 0

                idx = ((frame / P.STEER_STEP) % 16) + 16
                steer2 = (chksm_steer >> 8) & 0x1F
                steer1 = chksm_steer - (steer2 << 8)
                byte2 = steer2 + left3

                checksum = ((idx + steer1 + byte2) % 256) + 35
            can_sends.append(
                subarucan.create_steering_control(self.packer_pt,
                                                  canbus.powertrain,
                                                  CS.CP.carFingerprint, idx,
                                                  steer1, byte2, checksum))

        sendcan.send(
            can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
示例#14
0
def fingerprint(logcan, sendcan):
    if os.getenv("SIMULATOR2") is not None:
        return ("simulator2", None, "")
    elif os.getenv("SIMULATOR") is not None:
        return ("simulator", None, "")

    finger = {0: {}, 2: {}}  # collect on bus 0 or 2
    cloudlog.warning("waiting for fingerprint...")
    candidate_cars = all_known_cars()
    can_seen_frame = None
    can_seen = False

    # works on standard 11-bit addresses for diagnostic. Tested on Toyota and Subaru;
    # Honda uses the extended 29-bit addresses, and unfortunately only works from OBDII
    vin_query_msg = [[0x7df, 0, '\x02\x09\x02'.ljust(8, "\x00"), 0],
                     [0x7e0, 0, '\x30'.ljust(8, "\x00"), 0]]

    vin_cnts = [1, 2]  # number of messages to wait for at each iteration
    vin_step = 0
    vin_cnt = 0
    vin_responded = False
    vin_never_responded = True
    vin_dat = []
    vin = ""

    frame = 0

    while True:
        a = messaging.recv_one(logcan)

        for can in a.can:
            can_seen = True

            # have we got a VIN query response?
            if can.src == 0 and can.address == 0x7e8:
                vin_never_responded = False
                # basic sanity checks on ISO-TP response
                if is_vin_response_valid(can.dat, vin_step, vin_cnt):
                    vin_dat += can.dat[2:] if vin_step == 0 else can.dat[1:]
                    vin_cnt += 1
                    if vin_cnt == vin_cnts[vin_step]:
                        vin_responded = True
                        vin_step += 1

            # ignore everything not on bus 0 and with more than 11 bits,
            # which are ussually sporadic and hard to include in fingerprints.
            # also exclude VIN query response on 0x7e8.
            # Include bus 2 for toyotas to disambiguate cars using camera messages
            # (ideally should be done for all cars but we can't for Honda Bosch)
            if (can.src == 0 or (only_toyota_left(candidate_cars) and can.src == 2)) and \
               can.address < 0x800 and can.address != 0x7e8:
                finger[can.src][can.address] = len(can.dat)
                candidate_cars = eliminate_incompatible_cars(
                    can, candidate_cars)

        if can_seen_frame is None and can_seen:
            can_seen_frame = frame

        # if we only have one car choice and the time_fingerprint since we got our first
        # message has elapsed, exit. Toyota needs higher time_fingerprint, since DSU does not
        # broadcast immediately
        if len(candidate_cars) == 1 and can_seen_frame is not None:
            time_fingerprint = 1.0 if only_toyota_left(candidate_cars) else 0.1
            if (frame - can_seen_frame) > (time_fingerprint * 100):
                break

        # bail if no cars left or we've been waiting for more than 2s since can_seen
        elif len(candidate_cars) == 0 or (can_seen_frame is not None and
                                          (frame - can_seen_frame) > 200):
            return None, finger, ""

        # keep sending VIN qury if ECU isn't responsing.
        # sendcan is probably not ready due to the zmq slow joiner syndrome
        # TODO: VIN query temporarily disabled until we have the harness
        if False and can_seen and (vin_never_responded or
                                   (vin_responded
                                    and vin_step < len(vin_cnts))):
            sendcan.send(
                can_list_to_can_capnp([vin_query_msg[vin_step]],
                                      msgtype='sendcan'))
            vin_responded = False
            vin_cnt = 0

        frame += 1

    # only report vin if procedure is finished
    if vin_step == len(vin_cnts) and vin_cnt == vin_cnts[-1]:
        vin = "".join(vin_dat[3:])

    cloudlog.warning("fingerprinted %s", candidate_cars[0])
    cloudlog.warning("VIN %s", vin)
    return candidate_cars[0], finger, vin
示例#15
0
  def update(self, sendcan, enabled, CS, frame, actuators, \
             pcm_speed, pcm_override, pcm_cancel_cmd, pcm_accel, \
             hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert, \
             snd_beep, snd_chime):

    """ Controls thread """

    if not self.enable_camera:
      return

    # *** apply brake hysteresis ***
    brake, self.braking, self.brake_steady = actuator_hystereses(actuators.brake, self.braking, self.brake_steady, CS.v_ego, CS.CP.carFingerprint)

    # *** no output if not enabled ***
    if not enabled and CS.pcm_acc_status:
      # send pcm acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated
      pcm_cancel_cmd = True

    # *** rate limit after the enable check ***
    self.brake_last = rate_limit(brake, self.brake_last, -2., 1./100)

    # vehicle hud display, wait for one update from 10Hz 0x304 msg
    if hud_show_lanes:
      hud_lanes = 1
    else:
      hud_lanes = 0

    # TODO: factor this out better
    if enabled:
      if hud_show_car:
        hud_car = 2
      else:
        hud_car = 1
    else:
      hud_car = 0

    # For lateral control-only, send chimes as a beep since we don't send 0x1fa
    if CS.CP.safetyModel == car.CarParams.SafetyModels.hondaBosch:
      snd_beep = snd_beep if snd_beep is not 0 else snd_chime

    #print chime, alert_id, hud_alert
    fcw_display, steer_required, acc_alert = process_hud_alert(hud_alert)

    hud = HUDData(int(pcm_accel), int(round(hud_v_cruise)), 1, hud_car,
                  0xc1, hud_lanes, int(snd_beep), snd_chime, fcw_display, acc_alert, steer_required)

    if not all(isinstance(x, int) and 0 <= x < 256 for x in hud):
      print "INVALID HUD", hud
      hud = HUDData(0xc6, 255, 64, 0xc0, 209, 0x40, 0, 0, 0, 0)

    # **** process the car messages ****

    # *** compute control surfaces ***
    BRAKE_MAX = 1024/4
    if CS.CP.carFingerprint in (CAR.ACURA_ILX):
      STEER_MAX = 0xF00
    elif CS.CP.carFingerprint in (CAR.CRV, CAR.ACURA_RDX):
      STEER_MAX = 0x3e8  # CR-V only uses 12-bits and requires a lower value (max value from energee)
    else:
      is_fw_modified = os.getenv("DONGLE_ID") in ['99c94dc769b5d96e']
      STEER_MAX = 0x1FFF if is_fw_modified else 0x1000

    # steer torque is converted back to CAN reference (positive when steering right)
    apply_gas = clip(actuators.gas, 0., 1.)
    apply_brake = int(clip(self.brake_last * BRAKE_MAX, 0, BRAKE_MAX - 1))
    apply_steer = int(clip(-actuators.steer * STEER_MAX, -STEER_MAX, STEER_MAX))

    # any other cp.vl[0x18F]['STEER_STATUS'] is common and can happen during user override. sending 0 torque to avoid EPS sending error 5
    if CS.steer_not_allowed:
      apply_steer = 0

    # Send CAN commands.
    can_sends = []

    # Send steering command.
    idx = frame % 4
    can_sends.append(hondacan.create_steering_control(self.packer, apply_steer, enabled, CS.CP.carFingerprint, idx))

    # Send dashboard UI commands.
    if (frame % 10) == 0:
      idx = (frame/10) % 4
      can_sends.extend(hondacan.create_ui_commands(self.packer, pcm_speed, hud, CS.CP.carFingerprint, idx))

    if CS.CP.safetyModel == car.CarParams.SafetyModels.hondaBosch:
      # If using stock ACC, spam cancel command to kill gas when OP disengages.
      if pcm_cancel_cmd:
        can_sends.append(hondacan.create_cancel_command(idx))
      if CS.stopped:
        can_sends.append(hondacan.create_resume_command(idx))
    else:
      # Send gas and brake commands.
      if (frame % 2) == 0:
        idx = (frame / 2) % 4
        can_sends.append(
          hondacan.create_brake_command(self.packer, apply_brake, pcm_override,
                                      pcm_cancel_cmd, hud.chime, hud.fcw, idx))
        if CS.CP.enableGasInterceptor:
          # send exactly zero if apply_gas is zero. Interceptor will send the max between read value and apply_gas.
          # This prevents unexpected pedal range rescaling
          can_sends.append(hondacan.create_gas_command(self.packer, apply_gas, idx))

      # radar at 20Hz, but these msgs need to be sent at 50Hz on ilx (seems like an Acura bug)
      if CS.CP.carFingerprint == CAR.ACURA_ILX:
        radar_send_step = 2
      else:
        radar_send_step = 5

      if (frame % radar_send_step) == 0:
        idx = (frame/radar_send_step) % 4
        can_sends.extend(hondacan.create_radar_commands(CS.v_ego, CS.CP.carFingerprint, idx))

    sendcan.send(can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
示例#16
0
    def update(self, sendcan, enabled, CS, frame, actuators, \
               pcm_speed, pcm_override, pcm_cancel_cmd, pcm_accel, \
               hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert, \
               snd_beep, snd_chime):
        """ Controls thread """

        ## Todo add code to detect Tesla DAS (camera) and go into listen and record mode only (for AP1 / AP2 cars)
        if not self.enable_camera:
            return

        # *** no output if not enabled ***
        if not enabled and CS.pcm_acc_status:
            # send pcm acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated
            pcm_cancel_cmd = True

        # vehicle hud display, wait for one update from 10Hz 0x304 msg
        if hud_show_lanes:
            hud_lanes = 1
        else:
            hud_lanes = 0

        # TODO: factor this out better
        if enabled:
            if hud_show_car:
                hud_car = 2
            else:
                hud_car = 1
        else:
            hud_car = 0

        # For lateral control-only, send chimes as a beep since we don't send 0x1fa
        #if CS.CP.radarOffCan:

        #print chime, alert_id, hud_alert
        fcw_display, steer_required, acc_alert = process_hud_alert(hud_alert)

        hud = HUDData(int(pcm_accel),
                      int(round(hud_v_cruise)), 1, hud_car, 0xc1, hud_lanes,
                      int(snd_beep), snd_chime, fcw_display, acc_alert,
                      steer_required)

        if not all(isinstance(x, int) and 0 <= x < 256 for x in hud):
            print "INVALID HUD", hud
            hud = HUDData(0xc6, 255, 64, 0xc0, 209, 0x40, 0, 0, 0, 0)

        # **** process the car messages ****

        # *** compute control surfaces ***

        STEER_MAX = 420
        # Prevent steering while stopped
        MIN_STEERING_VEHICLE_VELOCITY = 0.05  # m/s
        vehicle_moving = (CS.v_ego >= MIN_STEERING_VEHICLE_VELOCITY)

        # Basic highway lane change logic
        changing_lanes = CS.right_blinker_on or CS.left_blinker_on

        #upodate custom UI buttons and alerts
        CS.UE.update_custom_ui()

        if (frame % 1000 == 0):
            CS.cstm_btns.send_button_info()

        # Update statuses for custom buttons every 0.1 sec.
        if self.ALCA.pid == None:
            self.ALCA.set_pid(CS)
        if (frame % 10 == 0):
            self.ALCA.update_status(CS.cstm_btns.get_button_status("alca") > 0)
            #print CS.cstm_btns.get_button_status("alca")

        if CS.pedal_interceptor_available:
            #update PCC module info
            self.PCC.update_stat(CS, True, sendcan)
            self.ACC.enable_adaptive_cruise = False
        else:
            # Update ACC module info.
            self.ACC.update_stat(CS, True)
            self.PCC.enable_pedal_cruise = False

        # Update HSO module info.
        human_control = False

        # update CS.v_cruise_pcm based on module selected.
        if self.ACC.enable_adaptive_cruise:
            CS.v_cruise_pcm = self.ACC.acc_speed_kph
        elif self.PCC.enable_pedal_cruise:
            CS.v_cruise_pcm = self.PCC.pedal_speed_kph
        else:
            CS.v_cruise_pcm = CS.v_cruise_actual
        # Get the angle from ALCA.
        alca_enabled = False
        turn_signal_needed = 0
        alca_steer = 0.
        apply_angle, alca_steer, alca_enabled, turn_signal_needed = self.ALCA.update(
            enabled, CS, frame, actuators)
        apply_angle = -apply_angle  # Tesla is reversed vs OP.
        human_control = self.HSO.update_stat(CS, enabled, actuators, frame)
        human_lane_changing = changing_lanes and not alca_enabled
        enable_steer_control = (enabled and not human_lane_changing
                                and not human_control and vehicle_moving)

        angle_lim = interp(CS.v_ego, ANGLE_MAX_BP, ANGLE_MAX_V)
        apply_angle = clip(apply_angle, -angle_lim, angle_lim)
        # Windup slower.
        if self.last_angle * apply_angle > 0. and abs(apply_angle) > abs(
                self.last_angle):
            angle_rate_lim = interp(CS.v_ego, ANGLE_DELTA_BP, ANGLE_DELTA_V)
        else:
            angle_rate_lim = interp(CS.v_ego, ANGLE_DELTA_BP, ANGLE_DELTA_VU)

        apply_angle = clip(apply_angle, self.last_angle - angle_rate_lim,
                           self.last_angle + angle_rate_lim)
        # If human control, send the steering angle as read at steering wheel.
        if human_control:
            apply_angle = CS.angle_steers
        # If blinker is on send the actual angle.
        #if (changing_lanes and (CS.laneChange_enabled < 2)):
        #  apply_angle = CS.angle_steers
        # Send CAN commands.
        can_sends = []
        send_step = 5

        if (True):
            #First we emulate DAS.
            #send DAS_bootID
            if not self.sent_DAS_bootID:
                can_sends.append(teslacan.create_DAS_bootID_msg())
                self.sent_DAS_bootID = True
            else:
                #get speed limit
                for socket, _ in self.poller.poll(0):
                    if socket is self.speedlimit:
                        self.speedlimit_mph = ui.SpeedLimitData.from_bytes(
                            socket.recv()).speed * CV.MS_TO_MPH
                #send DAS_info
                if frame % 100 == 0:
                    can_sends.append(
                        teslacan.create_DAS_info_msg(CS.DAS_info_msg))
                    CS.DAS_info_msg += 1
                    CS.DAS_info_msg = CS.DAS_info_msg % 10
                #send DAS_status
                # TODO: forward collission warning
                if frame % 50 == 0:
                    op_status = 0x02
                    hands_on_state = 0x00
                    forward_collission_warning = 0  #1 if needed
                    if hud_alert == AH.FCW:
                        forward_collission_warning = 0x01
                    cc_state = 0  #cruise state: 0 unavailable, 1 available, 2 enabled, 3 hold
                    speed_limit_kph = int(self.speedlimit_mph)
                    alca_state = 0x08
                    if enabled:
                        op_status = 0x03
                        alca_state = 0x08 + turn_signal_needed
                        if self.ALCA.laneChange_cancelled:
                            alca_state = 0x14
                        #if not enable_steer_control:
                        #op_status = 0x04
                        #hands_on_state = 0x03
                        if hud_alert == AH.STEER:
                            if snd_chime == CM.MUTE:
                                hands_on_state = 0x03
                            else:
                                hands_on_state = 0x05
                    can_sends.append(
                        teslacan.create_DAS_status_msg(
                            CS.DAS_status_idx, op_status, speed_limit_kph,
                            alca_state, hands_on_state,
                            forward_collission_warning, cc_state))
                    CS.DAS_status_idx += 1
                    CS.DAS_status_idx = CS.DAS_status_idx % 16
                #send DAS_status2
                if frame % 50 == 0:
                    collision_warning = 0x00
                    acc_speed_limit_mph = CS.v_cruise_pcm * CV.KPH_TO_MPH
                    if hud_alert == AH.FCW:
                        collision_warning = 0x01
                    can_sends.append(
                        teslacan.create_DAS_status2_msg(
                            CS.DAS_status2_idx, max(1, acc_speed_limit_mph),
                            collision_warning))
                    CS.DAS_status2_idx += 1
                    CS.DAS_status2_idx = CS.DAS_status2_idx % 16
                #send DAS_bodyControl
                if frame % 50 == 0:
                    can_sends.append(
                        teslacan.create_DAS_bodyControls_msg(
                            CS.DAS_bodyControls_idx, turn_signal_needed))
                    CS.DAS_bodyControls_idx += 1
                    CS.DAS_bodyControls_idx = CS.DAS_bodyControls_idx % 16
                #send DAS_control
                if frame % 4 == 0:
                    acc_speed_limit_kph = self.ACC.new_speed  #pcm_speed * CV.MS_TO_KPH
                    accel_min = -15
                    accel_max = 5
                    speed_control_enabled = enabled and (acc_speed_limit_kph >
                                                         0)
                    can_sends.append(
                        teslacan.create_DAS_control(CS.DAS_control_idx,
                                                    speed_control_enabled,
                                                    acc_speed_limit_kph,
                                                    accel_min, accel_max))
                    CS.DAS_control_idx += 1
                    CS.DAS_control_idx = CS.DAS_control_idx % 8
                #send DAS_lanes
                if frame % 10 == 0:
                    can_sends.append(
                        teslacan.create_DAS_lanes_msg(CS.DAS_lanes_idx))
                    CS.DAS_lanes_idx += 1
                    CS.DAS_lanes_idx = CS.DAS_lanes_idx % 16
                #send DAS_pscControl
                if frame % 4 == 0:
                    can_sends.append(
                        teslacan.create_DAS_pscControl_msg(
                            CS.DAS_pscControl_idx))
                    CS.DAS_pscControl_idx += 1
                    CS.DAS_pscControl_idx = CS.DAS_pscControl_idx % 16
                #send DAS_telemetryPeriodic
                if frame % 4 == 0:
                    can_sends.append(
                        teslacan.create_DAS_telemetryPeriodic(
                            CS.DAS_telemetryPeriodic1_idx,
                            CS.DAS_telemetryPeriodic2_idx))
                    CS.DAS_telemetryPeriodic2_idx += 1
                    CS.DAS_telemetryPeriodic2_idx = CS.DAS_telemetryPeriodic2_idx % 10
                    if CS.DAS_telemetryPeriodic2_idx == 0:
                        CS.DAS_telemetryPeriodic1_idx += 2
                        CS.DAS_telemetryPeriodic1_idx = CS.DAS_telemetryPeriodic1_idx % 16
                #send DAS_telemetryEvent
                if frame % 10 == 0:
                    #can_sends.append(teslacan.create_DAS_telemetryEvent(CS.DAS_telemetryEvent1_idx,CS.DAS_telemetryEvent2_idx))
                    CS.DAS_telemetryEvent2_idx += 1
                    CS.DAS_telemetryEvent2_idx = CS.DAS_telemetryEvent2_idx % 10
                    if CS.DAS_telemetryEvent2_idx == 0:
                        CS.DAS_telemetryEvent1_idx += 2
                        CS.DAS_telemetryEvent1_idx = CS.DAS_telemetryEvent1_idx % 16
                #send DAS_visualDebug
                if (frame + 1) % 10 == 0:
                    can_sends.append(teslacan.create_DAS_visualDebug_msg())
                #send DAS_chNm
                if (frame + 2) % 10 == 0:
                    can_sends.append(teslacan.create_DAS_chNm())
                #send DAS_objects
                if frame % 3 == 0:
                    can_sends.append(
                        teslacan.create_DAS_objects_msg(CS.DAS_objects_idx))
                    CS.DAS_objects_idx += 1
                    CS.DAS_objects_idx = CS.DAS_objects_idx % 16
                #send DAS_warningMatrix0
                if frame % 6 == 0:
                    can_sends.append(
                        teslacan.create_DAS_warningMatrix0(
                            CS.DAS_warningMatrix0_idx))
                    CS.DAS_warningMatrix0_idx += 1
                    CS.DAS_warningMatrix0_idx = CS.DAS_warningMatrix0_idx % 16
                #send DAS_warningMatrix3
                if (frame + 3) % 6 == 0:
                    apUnavailable = 0
                    gas_to_resume = 0
                    alca_cancelled = 0
                    if enabled and not enable_steer_control:
                        apUnavailable = 1
                    if self.ALCA.laneChange_cancelled:
                        alca_cancelled = 1
                    can_sends.append(
                        teslacan.create_DAS_warningMatrix3(
                            CS.DAS_warningMatrix3_idx, apUnavailable,
                            alca_cancelled, gas_to_resume))
                    CS.DAS_warningMatrix3_idx += 1
                    CS.DAS_warningMatrix3_idx = CS.DAS_warningMatrix3_idx % 16
                #send DAS_warningMatrix1
                if frame % 100 == 0:
                    can_sends.append(
                        teslacan.create_DAS_warningMatrix1(
                            CS.DAS_warningMatrix1_idx))
                    CS.DAS_warningMatrix1_idx += 1
                    CS.DAS_warningMatrix1_idx = CS.DAS_warningMatrix1_idx % 16
            # end of DAS emulation """
            idx = frame % 16
            can_sends.append(
                teslacan.create_steering_control(enable_steer_control,
                                                 apply_angle, idx))
            can_sends.append(teslacan.create_epb_enable_signal(idx))
            cruise_btn = None
            if self.ACC.enable_adaptive_cruise and not CS.pedal_interceptor_available:
                cruise_btn = self.ACC.update_acc(enabled, CS, frame, actuators,
                                                 pcm_speed)

            #add fake carConfig to trigger IC to display AP
            if frame % 2 == 0:
                carConfig_msg = teslacan.create_GTW_carConfig_msg(
                    real_carConfig_data=CS.real_carConfig,
                    dasHw=1,
                    autoPilot=1,
                    fRadarHw=1)
                #can_sends.append(carConfig_msg)

            if cruise_btn or (turn_signal_needed > 0 and frame % 2 == 0):
                cruise_msg = teslacan.create_cruise_adjust_msg(
                    spdCtrlLvr_stat=cruise_btn,
                    turnIndLvr_Stat=0,  #turn_signal_needed,
                    real_steering_wheel_stalk=CS.steering_wheel_stalk)
                # Send this CAN msg first because it is racing against the real stalk.
                can_sends.insert(0, cruise_msg)
            apply_accel = 0.
            if CS.pedal_interceptor_available and frame % 5 == 0:  # pedal processed at 20Hz
                apply_accel, accel_needed, accel_idx = self.PCC.update_pdl(
                    enabled, CS, frame, actuators, pcm_speed)
                can_sends.append(
                    teslacan.create_pedal_command_msg(apply_accel,
                                                      int(accel_needed),
                                                      accel_idx))
            self.last_angle = apply_angle
            self.last_accel = apply_accel
            sendcan.send(
                can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
示例#17
0
def fingerprint(logcan, sendcan):
    if os.getenv("SIMULATOR2") is not None:
        return ("simulator2", None, "")
    elif os.getenv("SIMULATOR") is not None:
        return ("simulator", None, "")

    finger = {}
    cloudlog.warning("waiting for fingerprint...")
    candidate_cars = all_known_cars()
    can_seen_ts = None
    can_seen = False

    # works on standard 11-bit addresses for diagnostic. Tested on Toyota and Subaru;
    # Honda uses the extended 29-bit addresses, and unfortunately only works from OBDII
    vin_query_msg = [[0x7df, 0, '\x02\x09\x02'.ljust(8, "\x00"), 0],
                     [0x7e0, 0, '\x30'.ljust(8, "\x00"), 0]]

    vin_cnts = [1, 2]  # number of messages to wait for at each iteration
    vin_step = 0
    vin_cnt = 0
    vin_responded = False
    vin_never_responded = True
    vin_dat = []
    vin = ""

    while 1:
        for a in messaging.drain_sock(logcan):
            for can in a.can:
                can_seen = True

                # have we got a VIN query response?
                if can.src == 0 and can.address == 0x7e8:
                    vin_never_responded = False
                    # basic sanity checks on ISO-TP response
                    if is_vin_response_valid(can.dat, vin_step, vin_cnt):
                        vin_dat += can.dat[2:] if vin_step == 0 else can.dat[1:]
                        vin_cnt += 1
                        if vin_cnt == vin_cnts[vin_step]:
                            vin_responded = True
                            vin_step += 1

                # ignore everything not on bus 0 and with more than 11 bits,
                # which are ussually sporadic and hard to include in fingerprints.
                # also exclude VIN query response on 0x7e8
                if can.src == 0 and can.address < 0x800 and can.address != 0x7e8:
                    finger[can.address] = len(can.dat)
                    candidate_cars = eliminate_incompatible_cars(
                        can, candidate_cars)

        if can_seen_ts is None and can_seen:
            can_seen_ts = sec_since_boot()  # start time
        ts = sec_since_boot()
        # if we only have one car choice and the time_fingerprint since we got our first
        # message has elapsed, exit. Toyota needs higher time_fingerprint, since DSU does not
        # broadcast immediately
        if len(candidate_cars) == 1 and can_seen_ts is not None:
            time_fingerprint = 1.0 if ("TOYOTA" in candidate_cars[0] or "LEXUS"
                                       in candidate_cars[0]) else 0.1
            if (ts - can_seen_ts) > time_fingerprint:
                break

        # bail if no cars left or we've been waiting for more than 2s since can_seen
        elif len(candidate_cars) == 0 or (can_seen_ts is not None and
                                          (ts - can_seen_ts) > 2.):
            return None, finger, ""

        # keep sending VIN qury if ECU isn't responsing.
        # sendcan is probably not ready due to the zmq slow joiner syndrome
        if can_seen and (vin_never_responded or
                         (vin_responded and vin_step < len(vin_cnts))):
            sendcan.send(
                can_list_to_can_capnp([vin_query_msg[vin_step]],
                                      msgtype='sendcan'))
            vin_responded = False
            vin_cnt = 0

        time.sleep(0.01)

    # only report vin if procedure is finished
    if vin_step == len(vin_cnts) and vin_cnt == vin_cnts[-1]:
        vin = "".join(vin_dat[3:])

    cloudlog.warning("fingerprinted %s", candidate_cars[0])
    cloudlog.warning("VIN %s", vin)
    return candidate_cars[0], finger, vin
示例#18
0
    def update(self, sendcan, enabled, CS, frame, actuators, \
               hud_v_cruise, hud_show_lanes, hud_show_car, chime, chime_cnt):
        """ Controls thread """

        P = self.params

        # Send CAN commands.
        can_sends = []
        canbus = self.canbus

        ### STEER ###

        if (frame % P.STEER_STEP) == 0:
            final_steer = actuators.steer if enabled else 0.
            apply_steer = final_steer * P.STEER_MAX

            apply_steer = apply_std_steer_torque_limits(
                apply_steer, self.apply_steer_last, CS.steer_torque_driver, P)

            lkas_enabled = enabled and not CS.steer_not_allowed and CS.v_ego > 3.

            if not lkas_enabled:
                apply_steer = 0

            self.apply_steer_last = apply_steer
            idx = (frame / P.STEER_STEP) % 4

            if self.car_fingerprint == CAR.VOLT:
                can_sends.append(
                    gmcan.create_steering_control(self.packer_pt,
                                                  canbus.powertrain,
                                                  apply_steer, idx,
                                                  lkas_enabled))
            if self.car_fingerprint == CAR.CADILLAC_CT6:
                can_sends += gmcan.create_steering_control_ct6(
                    self.packer_pt, canbus, apply_steer, CS.v_ego, idx,
                    lkas_enabled)

        ### GAS/BRAKE ###

        if self.car_fingerprint == CAR.VOLT:
            # no output if not enabled, but keep sending keepalive messages
            # threat pedals as one
            final_pedal = actuators.gas - actuators.brake

            # *** apply pedal hysteresis ***
            final_brake, self.brake_steady = actuator_hystereses(
                final_pedal, self.pedal_steady)

            if not enabled:
                apply_gas = P.MAX_ACC_REGEN  # TODO: do we really need to send max regen when not enabled?
                apply_brake = 0
            else:
                apply_gas = int(
                    round(interp(final_pedal, P.GAS_LOOKUP_BP,
                                 P.GAS_LOOKUP_V)))
                apply_brake = int(
                    round(
                        interp(final_pedal, P.BRAKE_LOOKUP_BP,
                               P.BRAKE_LOOKUP_V)))

            # Gas/regen and brakes - all at 25Hz
            if (frame % 4) == 0:
                idx = (frame / 4) % 4

                at_full_stop = enabled and CS.standstill
                near_stop = enabled and (CS.v_ego < P.NEAR_STOP_BRAKE_PHASE)
                can_sends.append(
                    gmcan.create_friction_brake_command(
                        self.packer_ch, canbus.chassis, apply_brake, idx,
                        near_stop, at_full_stop))

                at_full_stop = enabled and CS.standstill
                can_sends.append(
                    gmcan.create_gas_regen_command(self.packer_pt,
                                                   canbus.powertrain,
                                                   apply_gas, idx, enabled,
                                                   at_full_stop))

            # Send dashboard UI commands (ACC status), 25hz
            if (frame % 4) == 0:
                can_sends.append(
                    gmcan.create_acc_dashboard_command(
                        canbus.powertrain, enabled,
                        hud_v_cruise / CV.MS_TO_KPH, hud_show_car))

            # Radar needs to know current speed and yaw rate (50hz),
            # and that ADAS is alive (10hz)
            time_and_headlights_step = 10
            tt = sec_since_boot()

            if frame % time_and_headlights_step == 0:
                idx = (frame / time_and_headlights_step) % 4
                can_sends.append(
                    gmcan.create_adas_time_status(
                        canbus.obstacle, int((tt - self.start_time) * 60),
                        idx))
                can_sends.append(
                    gmcan.create_adas_headlights_status(canbus.obstacle))

            speed_and_accelerometer_step = 2
            if frame % speed_and_accelerometer_step == 0:
                idx = (frame / speed_and_accelerometer_step) % 4
                can_sends.append(
                    gmcan.create_adas_steering_status(canbus.obstacle, idx))
                can_sends.append(
                    gmcan.create_adas_accelerometer_speed_status(
                        canbus.obstacle, CS.v_ego, idx))

            # Send ADAS keepalive, 10hz
            if frame % P.ADAS_KEEPALIVE_STEP == 0:
                can_sends += gmcan.create_adas_keepalive(canbus.powertrain)

        # Send chimes
        if self.chime != chime:
            duration = 0x3c

            # There is no 'repeat forever' chime command
            # TODO: Manage periodic re-issuing of chime command
            # and chime cancellation
            if chime_cnt == -1:
                chime_cnt = 10

            if chime != 0:
                can_sends.append(
                    gmcan.create_chime_command(canbus.sw_gmlan, chime,
                                               duration, chime_cnt))

            # If canceling a repeated chime, cancel command must be
            # issued for the same chime type and duration
            self.chime = chime

        sendcan.send(
            can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
示例#19
0
    def update(self, sendcan, enabled, CS, frame, actuators, \
               hud_v_cruise, hud_show_lanes, hud_show_car, chime, chime_cnt):
        """ Controls thread """

        # Sanity check.
        if not self.allow_controls:
            return

        P = self.params
        # Send CAN commands.
        can_sends = []
        canbus = self.canbus

        ### STEER ###

        if (frame % P.STEER_STEP) == 0:
            lkas_enabled = enabled and not CS.steer_not_allowed and CS.lkMode and CS.v_ego > P.MIN_STEER_SPEED and not CS.left_blinker_on and not CS.right_blinker_on
            if lkas_enabled:
                apply_steer = actuators.steer * P.STEER_MAX
                apply_steer = apply_std_steer_torque_limits(
                    apply_steer, self.apply_steer_last, CS.steer_torque_driver,
                    P)
            else:
                apply_steer = 0

            self.apply_steer_last = apply_steer
            idx = (frame / P.STEER_STEP) % 4

            if self.car_fingerprint in SUPERCRUISE_CARS:
                can_sends += gmcan.create_steering_control_ct6(
                    self.packer_pt, canbus, apply_steer, CS.v_ego, idx,
                    lkas_enabled)
            else:
                can_sends.append(
                    gmcan.create_steering_control(self.packer_pt,
                                                  canbus.powertrain,
                                                  apply_steer, idx,
                                                  lkas_enabled))

        ### GAS/BRAKE ###

        if self.car_fingerprint not in SUPERCRUISE_CARS:
            # no output if not enabled, but keep sending keepalive messages
            # treat pedals as one
            final_pedal = actuators.gas - actuators.brake

            # *** apply pedal hysteresis ***
            final_brake, self.brake_steady = actuator_hystereses(
                final_pedal, self.pedal_steady)

            if not enabled:
                # Stock ECU sends max regen when not enabled.
                apply_gas = P.MAX_ACC_REGEN
                apply_brake = 0
            else:
                apply_gas = int(
                    round(interp(final_pedal, P.GAS_LOOKUP_BP,
                                 P.GAS_LOOKUP_V)))
                apply_brake = int(
                    round(
                        interp(final_pedal, P.BRAKE_LOOKUP_BP,
                               P.BRAKE_LOOKUP_V)))

            # Gas/regen and brakes - all at 25Hz
            if (frame % 4) == 0:
                idx = (frame / 4) % 4

                car_stopping = apply_gas < P.ZERO_GAS
                standstill = CS.pcm_acc_status == AccState.STANDSTILL
                at_full_stop = enabled and standstill and car_stopping
                near_stop = enabled and (
                    CS.v_ego < P.NEAR_STOP_BRAKE_PHASE) and car_stopping
                can_sends.append(
                    gmcan.create_friction_brake_command(
                        self.packer_ch, canbus.chassis, apply_brake, idx,
                        near_stop, at_full_stop))

                # Auto-resume from full stop by resetting ACC control
                acc_enabled = enabled
                if standstill and not car_stopping:
                    acc_enabled = False

                can_sends.append(
                    gmcan.create_gas_regen_command(self.packer_pt,
                                                   canbus.powertrain,
                                                   apply_gas, idx, acc_enabled,
                                                   at_full_stop))

            # Send dashboard UI commands (ACC status), 25hz
            follow_level = CS.get_follow_level()
            if (frame % 4) == 0:
                can_sends.append(
                    gmcan.create_acc_dashboard_command(
                        self.packer_pt, canbus.powertrain, enabled,
                        hud_v_cruise * CV.MS_TO_KPH, hud_show_car,
                        follow_level))

            # Radar needs to know current speed and yaw rate (50hz),
            # and that ADAS is alive (10hz)
            time_and_headlights_step = 10
            tt = sec_since_boot()

            if frame % time_and_headlights_step == 0:
                idx = (frame / time_and_headlights_step) % 4
                can_sends.append(
                    gmcan.create_adas_time_status(
                        canbus.obstacle, int((tt - self.start_time) * 60),
                        idx))
                can_sends.append(
                    gmcan.create_adas_headlights_status(canbus.obstacle))

            speed_and_accelerometer_step = 2
            if frame % speed_and_accelerometer_step == 0:
                idx = (frame / speed_and_accelerometer_step) % 4
                can_sends.append(
                    gmcan.create_adas_steering_status(canbus.obstacle, idx))
                can_sends.append(
                    gmcan.create_adas_accelerometer_speed_status(
                        canbus.obstacle, CS.v_ego, idx))

            if frame % P.ADAS_KEEPALIVE_STEP == 0:
                can_sends += gmcan.create_adas_keepalive(canbus.powertrain)

            # Show green icon when LKA torque is applied, and
            # alarming orange icon when approaching torque limit.
            # If not sent again, LKA icon disappears in about 5 seconds.
            # Conveniently, sending camera message periodically also works as a keepalive.
            lka_active = CS.lkas_status == 1
            lka_critical = lka_active and abs(actuators.steer) > 0.9
            lka_icon_status = (lka_active, lka_critical)
            if frame % P.CAMERA_KEEPALIVE_STEP == 0 \
                or lka_icon_status != self.lka_icon_status_last:
                can_sends.append(
                    gmcan.create_lka_icon_command(canbus.sw_gmlan, lka_active,
                                                  lka_critical))
                self.lka_icon_status_last = lka_icon_status

        # Send chimes
        if self.chime != chime:
            duration = 0x3c

            # There is no 'repeat forever' chime command
            # TODO: Manage periodic re-issuing of chime command
            # and chime cancellation
            if chime_cnt == -1:
                chime_cnt = 10

            if chime != 0:
                can_sends.append(
                    gmcan.create_chime_command(canbus.sw_gmlan, chime,
                                               duration, chime_cnt))

            # If canceling a repeated chime, cancel command must be
            # issued for the same chime type and duration
            self.chime = chime

        sendcan.send(
            can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
示例#20
0
def steer_thread():
  poller = messaging.Poller()

  logcan = messaging.sub_sock('can')
  health = messaging.sub_sock('health')
  joystick_sock = messaging.sub_sock('testJoystick', conflate=True, poller=poller)

  carstate = messaging.pub_sock('carState')
  carcontrol = messaging.pub_sock('carControl')
  sendcan = messaging.pub_sock('sendcan')

  button_1_last = 0
  enabled = False

  # wait for health and CAN packets
  hw_type = messaging.recv_one(health).health.hwType
  has_relay = hw_type in [HwType.blackPanda, HwType.uno]
  print("Waiting for CAN messages...")
  messaging.get_one_can(logcan)

  CI, CP = get_car(logcan, sendcan, has_relay)
  Params().put("CarParams", CP.to_bytes())

  CC = car.CarControl.new_message()

  while True:

    # send
    joystick = messaging.recv_one(joystick_sock)
    can_strs = messaging.drain_sock_raw(logcan, wait_for_one=True)
    CS = CI.update(CC, can_strs)

    # Usually axis run in pairs, up/down for one, and left/right for
    # the other.
    actuators = car.CarControl.Actuators.new_message()

    if joystick is not None:
      axis_3 = clip(-joystick.testJoystick.axes[3] * 1.05, -1., 1.)          # -1 to 1
      actuators.steer = axis_3
      actuators.steerAngle = axis_3 * 43.   # deg
      axis_1 = clip(-joystick.testJoystick.axes[1] * 1.05, -1., 1.)          # -1 to 1
      actuators.gas = max(axis_1, 0.)
      actuators.brake = max(-axis_1, 0.)

      pcm_cancel_cmd = joystick.testJoystick.buttons[0]
      button_1 = joystick.testJoystick.buttons[1]
      if button_1 and not button_1_last:
        enabled = not enabled

      button_1_last = button_1

      print("enable", enabled, "steer", actuators.steer, "accel", actuators.gas - actuators.brake)

      hud_alert = 0
      audible_alert = 0
      if joystick.testJoystick.buttons[2]:
        audible_alert = "beepSingle"
      if joystick.testJoystick.buttons[3]:
        audible_alert = "chimeRepeated"
        hud_alert = "steerRequired"

    CC.actuators.gas = actuators.gas
    CC.actuators.brake = actuators.brake
    CC.actuators.steer = actuators.steer
    CC.actuators.steerAngle = actuators.steerAngle
    CC.hudControl.visualAlert = hud_alert
    CC.hudControl.setSpeed = 20
    CC.cruiseControl.cancel = pcm_cancel_cmd
    CC.enabled = enabled
    can_sends = CI.apply(CC)
    sendcan.send(can_list_to_can_capnp(can_sends, msgtype='sendcan'))

    # broadcast carState
    cs_send = messaging.new_message()
    cs_send.init('carState')
    cs_send.carState = copy(CS)
    carstate.send(cs_send.to_bytes())

    # broadcast carControl
    cc_send = messaging.new_message()
    cc_send.init('carControl')
    cc_send.carControl = copy(CC)
    carcontrol.send(cc_send.to_bytes())
示例#21
0
    def update(self, sendcan, enabled, CS, frame, actuators, \
               pcm_speed, pcm_override, pcm_cancel_cmd, pcm_accel, \
               hud_v_cruise, hud_show_lanes, hud_show_car, \
               hud_alert, snd_beep, snd_chime):
        """ Controls thread """

        if not self.enable_camera:
            return

        # *** apply brake hysteresis ***
        brake, self.braking, self.brake_steady = actuator_hystereses(
            actuators.brake, self.braking, self.brake_steady, CS.v_ego,
            CS.CP.carFingerprint)

        # *** no output if not enabled ***
        if not enabled and CS.pcm_acc_status:
            # send pcm acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated
            pcm_cancel_cmd = True

        # *** rate limit after the enable check ***
        self.brake_last = rate_limit(brake, self.brake_last, -2., 1. / 100)

        # vehicle hud display, wait for one update from 10Hz 0x304 msg
        if hud_show_lanes and CS.lkMode and not CS.left_blinker_on and not CS.right_blinker_on:
            hud_lanes = 1
        else:
            hud_lanes = 0

        if enabled:
            if hud_show_car:
                hud_car = 2
            else:
                hud_car = 1
        else:
            hud_car = 0

        # For lateral control-only, send chimes as a beep since we don't send 0x1fa
        if CS.CP.radarOffCan:
            snd_beep = snd_beep if snd_beep is not 0 else snd_chime

        # Do not send audible alert when steering is disabled or blinkers on
        #if not CS.lkMode or CS.left_blinker_on or CS.right_blinker_on:
        #  snd_chime = 0

        #print chime, alert_id, hud_alert
        fcw_display, steer_required, acc_alert = process_hud_alert(hud_alert)

        hud = HUDData(int(pcm_accel),
                      int(round(hud_v_cruise)), 1, hud_car, 0xc1, hud_lanes,
                      int(snd_beep), snd_chime, fcw_display, acc_alert,
                      steer_required, CS.read_distance_lines, CS.lkMode,
                      self.speed_units)

        # **** process the car messages ****

        # *** compute control surfaces ***
        BRAKE_MAX = 1024 / 4
        if CS.CP.carFingerprint in (CAR.ACURA_ILX):
            STEER_MAX = 0xF00
        elif CS.CP.carFingerprint in (CAR.CRV, CAR.ACURA_RDX):
            STEER_MAX = 0x3e8  # CR-V only uses 12-bits and requires a lower value (max value from energee)
        else:
            STEER_MAX = 0x1000

        # steer torque is converted back to CAN reference (positive when steering right)
        apply_gas = clip(actuators.gas, 0., 1.)
        apply_brake = int(clip(self.brake_last * BRAKE_MAX, 0, BRAKE_MAX - 1))
        apply_steer = int(
            clip(-actuators.steer * STEER_MAX, -STEER_MAX, STEER_MAX))

        lkas_active = enabled and not CS.steer_not_allowed and CS.lkMode and not CS.left_blinker_on and not CS.right_blinker_on  # add LKAS button to toggle steering

        # Send CAN commands.
        can_sends = []

        # Send steering command.
        idx = frame % 4
        can_sends.append(
            hondacan.create_steering_control(self.packer, apply_steer,
                                             lkas_active, CS.CP.carFingerprint,
                                             idx))

        # Send dashboard UI commands.
        if (frame % 10) == 0:
            idx = (frame / 10) % 4
            can_sends.extend(
                hondacan.create_ui_commands(self.packer, pcm_speed, hud,
                                            CS.CP.carFingerprint, idx))

        if CS.CP.radarOffCan:
            # If using stock ACC, spam cancel command to kill gas when OP disengages.
            if pcm_cancel_cmd:
                can_sends.append(
                    hondacan.spam_buttons_command(self.packer,
                                                  CruiseButtons.CANCEL, idx))
            elif CS.stopped:
                can_sends.append(
                    hondacan.spam_buttons_command(self.packer,
                                                  CruiseButtons.RES_ACCEL,
                                                  idx))

        else:
            # Send gas and brake commands.
            if (frame % 2) == 0:
                idx = (frame / 2) % 4
                pump_on, self.last_pump_ts = brake_pump_hysteresys(
                    apply_brake, self.apply_brake_last, self.last_pump_ts)
                can_sends.append(
                    hondacan.create_brake_command(self.packer, apply_brake,
                                                  pump_on, pcm_override,
                                                  pcm_cancel_cmd, hud.chime,
                                                  hud.fcw, idx))
                self.apply_brake_last = apply_brake

                if CS.CP.enableGasInterceptor:
                    # send exactly zero if apply_gas is zero. Interceptor will send the max between read value and apply_gas.
                    # This prevents unexpected pedal range rescaling
                    can_sends.append(
                        hondacan.create_gas_command(self.packer, apply_gas,
                                                    idx))

        sendcan.send(
            can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
示例#22
0
    def update(self, sendcan, enabled, CS, frame, actuators, \
               pcm_speed, pcm_override, pcm_cancel_cmd, pcm_accel, \
               hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert, \
               snd_beep, snd_chime):
        """ Controls thread """

        ## Todo add code to detect Tesla DAS (camera) and go into listen and record mode only (for AP1 / AP2 cars)
        if not self.enable_camera:
            return

        # *** no output if not enabled ***
        if not enabled and CS.pcm_acc_status:
            # send pcm acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated
            pcm_cancel_cmd = True

        # vehicle hud display, wait for one update from 10Hz 0x304 msg
        if hud_show_lanes:
            hud_lanes = 1
        else:
            hud_lanes = 0

        # TODO: factor this out better
        if enabled:
            if hud_show_car:
                hud_car = 2
            else:
                hud_car = 1
        else:
            hud_car = 0

        # For lateral control-only, send chimes as a beep since we don't send 0x1fa
        #if CS.CP.radarOffCan:

        #print chime, alert_id, hud_alert
        fcw_display, steer_required, acc_alert = process_hud_alert(hud_alert)

        hud = HUDData(int(pcm_accel),
                      int(round(hud_v_cruise)), 1, hud_car, 0xc1, hud_lanes,
                      int(snd_beep), snd_chime, fcw_display, acc_alert,
                      steer_required)

        if not all(isinstance(x, int) and 0 <= x < 256 for x in hud):
            print "INVALID HUD", hud
            hud = HUDData(0xc6, 255, 64, 0xc0, 209, 0x40, 0, 0, 0, 0)

        # **** process the car messages ****

        # *** compute control surfaces ***

        STEER_MAX = 420
        # Prevent steering while stopped
        MIN_STEERING_VEHICLE_VELOCITY = 0.05  # m/s
        vehicle_moving = (CS.v_ego >= MIN_STEERING_VEHICLE_VELOCITY)

        # Basic highway lane change logic
        changing_lanes = CS.right_blinker_on or CS.left_blinker_on

        #upodate custom UI buttons and alerts
        CS.UE.update_custom_ui()

        if (frame % 1000 == 0):
            CS.cstm_btns.send_button_info()

        # Update statuses for custom buttons every 0.1 sec.
        if self.ALCA.pid == None:
            self.ALCA.set_pid(CS)
        if (frame % 10 == 0):
            self.ALCA.update_status(CS.cstm_btns.get_button_status("alca") > 0)
            #print CS.cstm_btns.get_button_status("alca")

        if CS.pedal_hardware_present:
            #update PCC module info
            self.PCC.update_stat(CS, True, sendcan)
            self.ACC.enable_adaptive_cruise = False
        else:
            # Update ACC module info.
            self.ACC.update_stat(CS, True)
            self.PCC.enable_pedal_cruise = False

        # Update HSO module info.
        human_control = False

        # update CS.v_cruise_pcm based on module selected.
        if self.ACC.enable_adaptive_cruise:
            CS.v_cruise_pcm = self.ACC.acc_speed_kph
        elif self.PCC.enable_pedal_cruise:
            CS.v_cruise_pcm = self.PCC.pedal_speed_kph
        else:
            CS.v_cruise_pcm = CS.v_cruise_actual
        # Get the angle from ALCA.
        alca_enabled = False
        turn_signal_needed = 0
        alca_steer = 0.
        apply_angle, alca_steer, alca_enabled, turn_signal_needed = self.ALCA.update(
            enabled, CS, frame, actuators)
        apply_angle = -apply_angle  # Tesla is reversed vs OP.
        human_control = self.HSO.update_stat(CS, enabled, actuators, frame)
        human_lane_changing = changing_lanes and not alca_enabled
        enable_steer_control = (enabled and not human_lane_changing
                                and not human_control)

        angle_lim = interp(CS.v_ego, ANGLE_MAX_BP, ANGLE_MAX_V)
        apply_angle = clip(apply_angle, -angle_lim, angle_lim)
        # Windup slower.
        if self.last_angle * apply_angle > 0. and abs(apply_angle) > abs(
                self.last_angle):
            angle_rate_lim = interp(CS.v_ego, ANGLE_DELTA_BP, ANGLE_DELTA_V)
        else:
            angle_rate_lim = interp(CS.v_ego, ANGLE_DELTA_BP, ANGLE_DELTA_VU)

        apply_angle = clip(apply_angle, self.last_angle - angle_rate_lim,
                           self.last_angle + angle_rate_lim)
        # If human control, send the steering angle as read at steering wheel.
        if human_control:
            apply_angle = CS.angle_steers
        # If blinker is on send the actual angle.
        #if (changing_lanes and (CS.laneChange_enabled < 2)):
        #  apply_angle = CS.angle_steers
        # Send CAN commands.
        can_sends = []
        send_step = 5

        if (True):
            """#First we emulate DAS.
      if (CS.DAS_info_frm == -1):
        #initialize all frames
        CS.DAS_info_frm = frame # 1.00 s interval
        CS.DAS_status_frm = (frame + 10) % 100 # 0.50 s interval
        CS.DAS_status2_frm = (frame + 35) % 100 # 0.50 s interval in between DAS_status
        CS.DAS_bodyControls_frm = (frame + 40) % 100 # 0.50 s interval
        CS.DAS_lanes_frm = (frame + 5) % 100 # 0.10 s interval 
        CS.DAS_objects_frm = (frame + 2) % 100 # 0.03 s interval
        CS.DAS_pscControl_frm = (frame + 3) % 100 # 0.04 s interval
      if (CS.DAS_info_frm == frame):
        can_sends.append(teslacan.create_DAS_info_msg(CS.DAS_info_msg))
        CS.DAS_info_msg += 1
        CS.DAS_info_msg = CS.DAS_info_msg % 10
      if (CS.DAS_status_frm == frame):
        can_sends.append(teslacan.create_DAS_status_msg(CS.DAS_status_idx))
        CS.DAS_status_idx += 1
        CS.DAS_status_idx = CS.DAS_status_idx % 16
        CS.DAS_status_frm = (CS.DAS_status_frm + 50) % 100
      if (CS.DAS_status2_frm == frame):
        can_sends.append(teslacan.create_DAS_status2_msg(CS.DAS_status2_idx))
        CS.DAS_status2_idx += 1
        CS.DAS_status2_idx = CS.DAS_status2_idx % 16
        CS.DAS_status2_frm = (CS.DAS_status2_frm + 50) % 100
      if (CS.DAS_bodyControls_frm == frame):
        can_sends.append(teslacan.create_DAS_bodyControls_msg(CS.DAS_bodyControls_idx))
        CS.DAS_bodyControls_idx += 1
        CS.DAS_bodyControls_idx = CS.DAS_bodyControls_idx % 16
        CS.DAS_bodyControls_frm = (CS.DAS_bodyControls_frm + 50) % 100
      if (CS.DAS_lanes_frm == frame):
        can_sends.append(teslacan.create_DAS_lanes_msg(CS.DAS_lanes_idx))
        CS.DAS_lanes_idx += 1
        CS.DAS_lanes_idx = CS.DAS_lanes_idx % 16
        CS.DAS_lanes_frm = (CS.DAS_lanes_frm + 10) % 100
      if (CS.DAS_pscControl_frm == frame):
        can_sends.append(teslacan.create_DAS_pscControl_msg(CS.DAS_pscControl_idx))
        CS.DAS_pscControl_idx += 1
        CS.DAS_pscControl_idx = CS.DAS_pscControl_idx % 16
        CS.DAS_pscControl_frm = (CS.DAS_pscControl_frm + 4) % 100
      if (CS.DAS_objects_frm == frame):
        can_sends.append(teslacan.create_DAS_objects_msg(CS.DAS_objects_idx))
        CS.DAS_objects_idx += 1
        CS.DAS_objects_idx = CS.DAS_objects_idx % 16
        CS.DAS_objects_frm = (CS.DAS_objects_frm + 3) % 100
      # end of DAS emulation """
            idx = frame % 16
            can_sends.append(
                teslacan.create_steering_control(enable_steer_control,
                                                 apply_angle, idx))
            can_sends.append(teslacan.create_epb_enable_signal(idx))
            cruise_btn = None
            if self.ACC.enable_adaptive_cruise and not self.PCC.pedal_hardware_present:
                cruise_btn = self.ACC.update_acc(enabled, CS, frame, actuators,
                                                 pcm_speed)
            if (cruise_btn != None) or ((turn_signal_needed > 0) and
                                        (frame % 2 == 0)):
                cruise_msg = teslacan.create_cruise_adjust_msg(
                    spdCtrlLvr_stat=cruise_btn,
                    turnIndLvr_Stat=turn_signal_needed,
                    real_steering_wheel_stalk=CS.steering_wheel_stalk)
                # Send this CAN msg first because it is racing against the real stalk.
                can_sends.insert(0, cruise_msg)
            apply_accel = 0.
            if self.PCC.pedal_hardware_present:  # and (frame % 10) == 0:
                apply_accel, accel_needed, accel_idx = self.PCC.update_pdl(
                    enabled, CS, frame, actuators, pcm_speed)
                can_sends.append(
                    teslacan.create_pedal_command_msg(apply_accel,
                                                      int(accel_needed),
                                                      accel_idx))
            self.last_angle = apply_angle
            self.last_accel = apply_accel
            sendcan.send(
                can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
示例#23
0
    def update(self, sendcan, enabled, CS, frame, actuators, pcm_cancel_cmd,
               hud_alert, audible_alert, forwarding_camera, left_line,
               right_line, lead, left_lane_depart, right_lane_depart):

        #update custom UI buttons and alerts
        CS.UE.update_custom_ui()
        if (frame % 1000 == 0):
            CS.cstm_btns.send_button_info()
            CS.UE.uiSetCarEvent(CS.cstm_btns.car_folder, CS.cstm_btns.car_name)

        # *** compute control surfaces ***

        # gas and brake

        apply_gas = clip(actuators.gas, 0., 1.)

        if CS.CP.enableGasInterceptor:
            # send only negative accel if interceptor is detected. otherwise, send the regular value
            # +0.06 offset to reduce ABS pump usage when OP is engaged
            apply_accel = 0.06 - actuators.brake
        else:
            apply_accel = actuators.gas - actuators.brake

        apply_accel, self.accel_steady = accel_hysteresis(
            apply_accel, self.accel_steady, enabled)
        apply_accel = clip(apply_accel * ACCEL_SCALE, ACCEL_MIN, ACCEL_MAX)
        # Get the angle from ALCA.
        alca_enabled = False
        alca_steer = 0.
        alca_angle = 0.
        turn_signal_needed = 0
        # Update ALCA status and custom button every 0.1 sec.
        if self.ALCA.pid == None and not CS.indi_toggle:
            self.ALCA.set_pid(CS)
        if (frame % 10 == 0):
            self.ALCA.update_status(CS.cstm_btns.get_button_status("alca") > 0)
        # steer torque
        alca_angle, alca_steer, alca_enabled, turn_signal_needed = self.ALCA.update(
            enabled, CS, frame, actuators)
        #apply_steer = int(round(alca_steer * STEER_MAX))

        self.phantom.update()
        # steer torque
        if self.phantom.data["status"]:
            apply_steer = int(round(self.phantom.data["angle"]))
            if abs(CS.angle_steers) > 400:
                apply_steer = 0
        else:
            apply_steer = int(round(alca_steer * SteerLimitParams.STEER_MAX))
            if abs(CS.angle_steers) > 100:
                apply_steer = 0
        if not CS.lane_departure_toggle_on:
            apply_steer = 0

        # only cut torque when steer state is a known fault
        if CS.steer_state in [3, 7, 9, 11, 25]:
            self.last_fault_frame = frame

        # Cut steering for 2s after fault
        cutout_time = 100 if self.phantom.data["status"] else 200

        if not enabled or (frame - self.last_fault_frame < cutout_time):
            apply_steer = 0
            apply_steer_req = 0
        else:
            apply_steer_req = 1

        apply_steer = apply_toyota_steer_torque_limits(apply_steer,
                                                       self.last_steer,
                                                       CS.steer_torque_motor,
                                                       SteerLimitParams)
        if apply_steer == 0 and self.last_steer == 0:
            apply_steer_req = 0

        if not enabled and right_lane_depart and CS.v_ego > 12.5 and not CS.right_blinker_on:
            apply_steer = self.last_steer + 3
            apply_steer = min(apply_steer, 800)
            #print "right"
            #print apply_steer
            apply_steer_req = 1

        if not enabled and left_lane_depart and CS.v_ego > 12.5 and not CS.left_blinker_on:
            apply_steer = self.last_steer - 3
            apply_steer = max(apply_steer, -800)
            #print "left"
            #print apply_steer
            apply_steer_req = 1

        self.steer_angle_enabled, self.ipas_reset_counter = \
          ipas_state_transition(self.steer_angle_enabled, enabled, CS.ipas_active, self.ipas_reset_counter)
        #print("{0} {1} {2}".format(self.steer_angle_enabled, self.ipas_reset_counter, CS.ipas_active))

        # steer angle
        if self.steer_angle_enabled and CS.ipas_active:

            apply_angle = alca_angle
            #apply_angle = actuators.steerAngle
            angle_lim = interp(CS.v_ego, ANGLE_MAX_BP, ANGLE_MAX_V)
            apply_angle = clip(apply_angle, -angle_lim, angle_lim)

            # windup slower
            if self.last_angle * apply_angle > 0. and abs(apply_angle) > abs(
                    self.last_angle):
                angle_rate_lim = interp(CS.v_ego, ANGLE_DELTA_BP,
                                        ANGLE_DELTA_V)
            else:
                angle_rate_lim = interp(CS.v_ego, ANGLE_DELTA_BP,
                                        ANGLE_DELTA_VU)

            apply_angle = clip(apply_angle, self.last_angle - angle_rate_lim,
                               self.last_angle + angle_rate_lim)
        else:
            apply_angle = CS.angle_steers

        if not enabled and CS.pcm_acc_status:
            # send pcm acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated
            pcm_cancel_cmd = 1

        # on entering standstill, send standstill request
        #if CS.standstill and not self.last_standstill:
        #  self.standstill_req = True
        if CS.pcm_acc_status != 8:
            # pcm entered standstill or it's disabled
            self.standstill_req = False

        self.last_steer = apply_steer
        self.last_angle = apply_angle
        self.last_accel = apply_accel
        self.last_standstill = CS.standstill

        can_sends = []

        # Enable blindspot debug mode once
        if BLINDSPOTDEBUG:
            self.blindspot_poll_counter += 1
        if self.blindspot_poll_counter > 1000:  # 10 seconds after start
            if CS.left_blinker_on:
                self.blindspot_blink_counter_left += 1
                #print "debug Left Blinker on"
            elif CS.right_blinker_on:
                self.blindspot_blink_counter_right += 1
            else:
                self.blindspot_blink_counter_left = 0
                self.blindspot_blink_counter_right = 0
                #print "debug Left Blinker off"
                if self.blindspot_debug_enabled_left:
                    can_sends.append(
                        set_blindspot_debug_mode(LEFT_BLINDSPOT, False))
                    self.blindspot_debug_enabled_left = False
                    #print "debug Left blindspot debug disabled"
                if self.blindspot_debug_enabled_right:
                    can_sends.append(
                        set_blindspot_debug_mode(RIGHT_BLINDSPOT, False))
                    self.blindspot_debug_enabled_right = False
                    #print "debug Right blindspot debug disabled"
            if self.blindspot_blink_counter_left > 9 and not self.blindspot_debug_enabled_left:  #check blinds
                can_sends.append(set_blindspot_debug_mode(
                    LEFT_BLINDSPOT, True))
                #print "debug Left blindspot debug enabled"
                self.blindspot_debug_enabled_left = True
            if self.blindspot_blink_counter_right > 5 and not self.blindspot_debug_enabled_right:  #enable blindspot debug mode
                if CS.v_ego > 6:  #polling at low speeds switches camera off
                    can_sends.append(
                        set_blindspot_debug_mode(RIGHT_BLINDSPOT, True))
                    #print "debug Right blindspot debug enabled"
                    self.blindspot_debug_enabled_right = True
        if self.blindspot_debug_enabled_left:
            if self.blindspot_poll_counter % 20 == 0 and self.blindspot_poll_counter > 1001:  # Poll blindspots at 5 Hz
                can_sends.append(poll_blindspot_status(LEFT_BLINDSPOT))
        if self.blindspot_debug_enabled_right:
            if self.blindspot_poll_counter % 20 == 10 and self.blindspot_poll_counter > 1005:  # Poll blindspots at 5 Hz
                can_sends.append(poll_blindspot_status(RIGHT_BLINDSPOT))

        #*** control msgs ***
        #print("steer {0} {1} {2} {3}".format(apply_steer, min_lim, max_lim, CS.steer_torque_motor)

        # toyota can trace shows this message at 42Hz, with counter adding alternatively 1 and 2;
        # sending it at 100Hz seem to allow a higher rate limit, as the rate limit seems imposed
        # on consecutive messages
        if ECU.CAM in self.fake_ecus:
            if self.angle_control:
                can_sends.append(
                    create_steer_command(self.packer, 0., 0, frame))
            else:
                can_sends.append(
                    create_steer_command(self.packer, apply_steer,
                                         apply_steer_req, frame))

        if self.angle_control:
            can_sends.append(
                create_ipas_steer_command(self.packer, apply_angle,
                                          self.steer_angle_enabled, ECU.APGS
                                          in self.fake_ecus))
        elif ECU.APGS in self.fake_ecus:
            can_sends.append(create_ipas_steer_command(self.packer, 0, 0,
                                                       True))

        if CS.cstm_btns.get_button_status("tr") > 0:
            distance = 1
        else:
            distance = 0

        # accel cmd comes from DSU, but we can spam can to cancel the system even if we are using lat only control
        if (frame % 3 == 0 and ECU.DSU in self.fake_ecus) or (
                pcm_cancel_cmd and ECU.CAM in self.fake_ecus):
            lead = lead or CS.v_ego < 12.  # at low speed we always assume the lead is present do ACC can be engaged
            if ECU.DSU in self.fake_ecus:
                can_sends.append(
                    create_accel_command(self.packer, apply_accel,
                                         pcm_cancel_cmd, self.standstill_req,
                                         lead, distance))
            else:
                can_sends.append(
                    create_accel_command(self.packer, 0, pcm_cancel_cmd, False,
                                         lead, distance))

        if (frame % 2 == 0) and (CS.CP.enableGasInterceptor):
            # send exactly zero if apply_gas is zero. Interceptor will send the max between read value and apply_gas.
            # This prevents unexpected pedal range rescaling
            can_sends.append(
                create_gas_command(self.packer, apply_gas, frame // 2))

        if frame % 10 == 0 and ECU.CAM in self.fake_ecus and not forwarding_camera:
            for addr in TARGET_IDS:
                can_sends.append(create_video_target(frame // 10, addr))

        # ui mesg is at 100Hz but we send asap if:
        # - there is something to display
        # - there is something to stop displaying
        alert_out = process_hud_alert(hud_alert, audible_alert)
        steer, fcw, sound1, sound2 = alert_out

        if (any(alert_out) and not self.alert_active) or \
           (not any(alert_out) and self.alert_active):
            send_ui = True
            self.alert_active = not self.alert_active
        else:
            send_ui = False
        if (frame % 100 == 0 or send_ui) and ECU.CAM in self.fake_ecus:
            can_sends.append(
                create_ui_command(self.packer, steer, sound1, sound2,
                                  left_line, right_line, left_lane_depart,
                                  right_lane_depart))

        if frame % 100 == 0 and ECU.DSU in self.fake_ecus and self.car_fingerprint not in TSSP2_CAR:
            can_sends.append(create_fcw_command(self.packer, fcw))

        #*** static msgs ***

        for (addr, ecu, cars, bus, fr_step, vl) in STATIC_MSGS:
            if frame % fr_step == 0 and ecu in self.fake_ecus and self.car_fingerprint in cars and not (
                    ecu == ECU.CAM and forwarding_camera):
                # special cases
                if fr_step == 5 and ecu == ECU.CAM and bus == 1:
                    cnt = (((frame // 5) % 7) + 1) << 5
                    vl = chr(cnt) + vl
                elif addr in (0x489, 0x48a) and bus == 0:
                    # add counter for those 2 messages (last 4 bits)
                    cnt = ((frame // 100) % 0xf) + 1
                    if addr == 0x48a:
                        # 0x48a has a 8 preceding the counter
                        cnt += 1 << 7
                    vl += chr(cnt)

                can_sends.append(make_can_msg(addr, vl, bus, False))

        sendcan.send(can_list_to_can_capnp(can_sends, msgtype='sendcan'))
示例#24
0
    def step(self,
             v_lead=0.0,
             cruise_buttons=None,
             grade=0.0,
             publish_model=True):
        gen_dbc, gen_signals, gen_checks = get_can_signals(CP)
        sgs = [s[0] for s in gen_signals]
        msgs = [s[1] for s in gen_signals]
        cks_msgs = set(check[0] for check in gen_checks)
        cks_msgs.add(0x18F)
        cks_msgs.add(0x30C)

        # ******** get messages sent to the car ********
        can_msgs = []
        for a in messaging.drain_sock(Plant.sendcan):
            can_msgs.extend(can_capnp_to_can_list(a.sendcan, [0, 2]))
        self.cp.update_can(can_msgs)

        # ******** get live100 messages for plotting ***
        live100_msgs = []
        for a in messaging.drain_sock(Plant.live100):
            live100_msgs.append(a.live100)

        fcw = None
        for a in messaging.drain_sock(Plant.plan):
            if a.plan.fcw:
                fcw = True

        if self.cp.vl[0x1fa]['COMPUTER_BRAKE_REQUEST']:
            brake = self.cp.vl[0x1fa]['COMPUTER_BRAKE'] * 0.003906248
        else:
            brake = 0.0

        if self.cp.vl[0x200]['GAS_COMMAND'] > 0:
            gas = self.cp.vl[0x200]['GAS_COMMAND'] / 256.0
        else:
            gas = 0.0

        if self.cp.vl[0xe4]['STEER_TORQUE_REQUEST']:
            steer_torque = self.cp.vl[0xe4]['STEER_TORQUE'] * 1.0 / 0xf00
        else:
            steer_torque = 0.0

        distance_lead = self.distance_lead_prev + v_lead * self.ts

        # ******** run the car ********
        speed, acceleration = car_plant(self.distance_prev, self.speed_prev,
                                        grade, gas, brake)
        distance = self.distance_prev + speed * self.ts
        speed = self.speed_prev + self.ts * acceleration
        if speed <= 0:
            speed = 0
            acceleration = 0

        # ******** lateral ********
        self.angle_steer -= (steer_torque / 10.0) * self.ts

        # *** radar model ***
        if self.lead_relevancy:
            d_rel = np.maximum(0., distance_lead - distance)
            v_rel = v_lead - speed
        else:
            d_rel = 200.
            v_rel = 0.
        lateral_pos_rel = 0.

        # print at 5hz
        if (self.rk.frame % (self.rate / 5)) == 0:
            print "%6.2f m  %6.2f m/s  %6.2f m/s2   %.2f ang   gas: %.2f  brake: %.2f  steer: %5.2f     lead_rel: %6.2f m  %6.2f m/s" % (
                distance, speed, acceleration, self.angle_steer, gas, brake,
                steer_torque, d_rel, v_rel)

        # ******** publish the car ********
        # TODO: the order is this list should not matter, but currently everytime we change carstate we break this test. Fix it!
        vls = [
            self.speed_sensor(speed),
            self.speed_sensor(speed),
            self.speed_sensor(speed),
            self.speed_sensor(speed),
            self.speed_sensor(speed),
            self.angle_steer,
            self.angle_steer_rate,
            0,
            0,
            0,
            0,
            0,  # Doors
            0,
            0,  # Blinkers
            0,  # Cruise speed offset
            self.gear_choice,
            speed != 0,
            self.brake_error,
            self.brake_error,
            self.v_cruise,
            not self.seatbelt,
            self.seatbelt,  # Seatbelt
            self.brake_pressed,
            0.,
            cruise_buttons,
            self.esp_disabled,
            0,  # HUD lead
            self.user_brake,
            self.steer_error,
            self.gear_shifter,
            self.pedal_gas,
            self.cruise_setting,
            self.acc_status,
            self.user_gas,
            self.main_on,
            0,  # EPB State
            0,  # Brake hold
            0,  # Interceptor feedback
            # 0,
        ]

        # TODO: publish each message at proper frequency
        can_msgs = []
        for msg in set(msgs):
            msg_struct = {}
            indxs = [i for i, x in enumerate(msgs) if msg == msgs[i]]
            for i in indxs:
                msg_struct[sgs[i]] = vls[i]

            if "COUNTER" in honda.get_signals(msg):
                msg_struct["COUNTER"] = self.rk.frame % 4

            msg = honda.lookup_msg_id(msg)
            msg_data = honda.encode(msg, msg_struct)

            if "CHECKSUM" in honda.get_signals(msg):
                msg_data = fix(msg_data, msg)

            can_msgs.append([msg, 0, msg_data, 0])

        # add the radar message
        # TODO: use the DBC
        if self.rk.frame % 5 == 0:
            radar_state_msg = '\x79\x00\x00\x00\x00\x00\x00\x00'
            radar_msg = to_3_byte(d_rel*16.0) + \
                        to_3_byte(int(lateral_pos_rel*16.0)&0x3ff) + \
                        to_3s_byte(int(v_rel*32.0)) + \
                        "0f00000"
            can_msgs.append([0x400, 0, radar_state_msg, 1])
            can_msgs.append([0x445, 0, radar_msg.decode("hex"), 1])
        Plant.logcan.send(can_list_to_can_capnp(can_msgs).to_bytes())

        # ******** publish a fake model going straight and fake calibration ********
        # note that this is worst case for MPC, since model will delay long mpc by one time step
        if publish_model and self.rk.frame % 5 == 0:
            md = messaging.new_message()
            cal = messaging.new_message()
            md.init('model')
            cal.init('liveCalibration')
            md.model.frameId = 0
            for x in [md.model.path, md.model.leftLane, md.model.rightLane]:
                x.points = [0.0] * 50
                x.prob = 1.0
                x.std = 1.0
            md.model.lead.dist = float(d_rel)
            md.model.lead.prob = 1.
            md.model.lead.std = 0.1
            cal.liveCalibration.calStatus = 1
            cal.liveCalibration.calPerc = 100
            # fake values?
            Plant.model.send(md.to_bytes())
            Plant.cal.send(cal.to_bytes())

        # ******** update prevs ********
        self.speed = speed
        self.distance = distance
        self.distance_lead = distance_lead

        self.speed_prev = speed
        self.distance_prev = distance
        self.distance_lead_prev = distance_lead

        self.rk.keep_time()
        return (distance, speed, acceleration, distance_lead, brake, gas,
                steer_torque, fcw, live100_msgs)
示例#25
0
  def step(self, v_lead=0.0, cruise_buttons=None, grade=0.0, publish_model = True):
    gen_signals, gen_checks = get_can_signals(CP)
    sgs = [s[0] for s in gen_signals]
    msgs = [s[1] for s in gen_signals]
    cks_msgs = set(check[0] for check in gen_checks)
    cks_msgs.add(0x18F)
    cks_msgs.add(0x30C)

    # ******** get messages sent to the car ********
    can_msgs = []
    for a in messaging.drain_sock(Plant.sendcan):
      can_msgs.extend(can_capnp_to_can_list(a.sendcan, [0,2]))
    self.cp.update_can(can_msgs)

    # ******** get controlsState messages for plotting ***
    controls_state_msgs = []
    for a in messaging.drain_sock(Plant.controls_state):
      controls_state_msgs.append(a.controlsState)

    fcw = None
    for a in messaging.drain_sock(Plant.plan):
      if a.plan.fcw:
        fcw = True

    if self.cp.vl[0x1fa]['COMPUTER_BRAKE_REQUEST']:
      brake = self.cp.vl[0x1fa]['COMPUTER_BRAKE'] * 0.003906248
    else:
      brake = 0.0

    if self.cp.vl[0x200]['GAS_COMMAND'] > 0:
      gas = self.cp.vl[0x200]['GAS_COMMAND'] / 256.0
    else:
      gas = 0.0

    if self.cp.vl[0xe4]['STEER_TORQUE_REQUEST']:
      steer_torque = self.cp.vl[0xe4]['STEER_TORQUE']*1.0/0xf00
    else:
      steer_torque = 0.0

    distance_lead = self.distance_lead_prev + v_lead * self.ts

    # ******** run the car ********
    speed, acceleration = car_plant(self.distance_prev, self.speed_prev, grade, gas, brake)
    distance = self.distance_prev + speed * self.ts
    speed = self.speed_prev + self.ts * acceleration
    if speed <= 0:
      speed = 0
      acceleration = 0

    # ******** lateral ********
    self.angle_steer -= (steer_torque/10.0) * self.ts

    # *** radar model ***
    if self.lead_relevancy:
      d_rel = np.maximum(0., distance_lead - distance)
      v_rel = v_lead - speed
    else:
      d_rel = 200.
      v_rel = 0.
    lateral_pos_rel = 0.

    # print at 5hz
    if (self.rk.frame % (self.rate//5)) == 0:
      print("%6.2f m  %6.2f m/s  %6.2f m/s2   %.2f ang   gas: %.2f  brake: %.2f  steer: %5.2f     lead_rel: %6.2f m  %6.2f m/s" % (distance, speed, acceleration, self.angle_steer, gas, brake, steer_torque, d_rel, v_rel))

    # ******** publish the car ********
    vls_tuple = namedtuple('vls', [
           'XMISSION_SPEED',
           'WHEEL_SPEED_FL', 'WHEEL_SPEED_FR', 'WHEEL_SPEED_RL', 'WHEEL_SPEED_RR',
           'STEER_ANGLE', 'STEER_ANGLE_RATE', 'STEER_TORQUE_SENSOR',
           'LEFT_BLINKER', 'RIGHT_BLINKER',
           'GEAR',
           'WHEELS_MOVING',
           'BRAKE_ERROR_1', 'BRAKE_ERROR_2',
           'SEATBELT_DRIVER_LAMP', 'SEATBELT_DRIVER_LATCHED',
           'BRAKE_PRESSED', 'BRAKE_SWITCH',
           'CRUISE_BUTTONS',
           'ESP_DISABLED',
           'HUD_LEAD',
           'USER_BRAKE',
           'STEER_STATUS',
           'GEAR_SHIFTER',
           'PEDAL_GAS',
           'CRUISE_SETTING',
           'ACC_STATUS',

           'CRUISE_SPEED_PCM',
           'CRUISE_SPEED_OFFSET',

           'DOOR_OPEN_FL', 'DOOR_OPEN_FR', 'DOOR_OPEN_RL', 'DOOR_OPEN_RR',

           'CAR_GAS',
           'MAIN_ON',
           'EPB_STATE',
           'BRAKE_HOLD_ACTIVE',
           'INTERCEPTOR_GAS',
           'IMPERIAL_UNIT',
           ])
    vls = vls_tuple(
           self.speed_sensor(speed),
           self.speed_sensor(speed), self.speed_sensor(speed), self.speed_sensor(speed), self.speed_sensor(speed),
           self.angle_steer, self.angle_steer_rate, 0, #Steer torque sensor
           0, 0,  # Blinkers
           self.gear_choice,
           speed != 0,
           self.brake_error, self.brake_error,
           not self.seatbelt, self.seatbelt,  # Seatbelt
           self.brake_pressed, 0., #Brake pressed, Brake switch
           cruise_buttons,
           self.esp_disabled,
           0,  # HUD lead
           self.user_brake,
           self.steer_error,
           self.gear_shifter,
           self.pedal_gas,
           self.cruise_setting,
           self.acc_status,

           self.v_cruise,
           0,  # Cruise speed offset

           0, 0, 0, 0,  # Doors

           self.user_gas,
           self.main_on,
           0,  # EPB State
           0,  # Brake hold
           0,  # Interceptor feedback
           False
           )

    # TODO: publish each message at proper frequency
    can_msgs = []
    for msg in set(msgs):
      msg_struct = {}
      indxs = [i for i, x in enumerate(msgs) if msg == msgs[i]]
      for i in indxs:
        msg_struct[sgs[i]] = getattr(vls, sgs[i])

      if "COUNTER" in honda.get_signals(msg):
        msg_struct["COUNTER"] = self.rk.frame % 4

      if "COUNTER_PEDAL" in honda.get_signals(msg):
        msg_struct["COUNTER_PEDAL"] = self.rk.frame % 0xf

      msg = honda.lookup_msg_id(msg)
      msg_data = honda.encode(msg, msg_struct)

      if "CHECKSUM" in honda.get_signals(msg):
        msg_data = fix(msg_data, msg)

      if "CHECKSUM_PEDAL" in honda.get_signals(msg):
        msg_struct["CHECKSUM_PEDAL"] = crc8_pedal([ord(i) for i in msg_data][:-1])
        msg_data = honda.encode(msg, msg_struct)

      can_msgs.append([msg, 0, msg_data, 0])

    # add the radar message
    # TODO: use the DBC
    if self.rk.frame % 5 == 0:
      radar_state_msg = '\x79\x00\x00\x00\x00\x00\x00\x00'
      radar_msg = to_3_byte(d_rel*16.0) + \
                  to_3_byte(int(lateral_pos_rel*16.0)&0x3ff) + \
                  to_3s_byte(int(v_rel*32.0)) + \
                  "0f00000"
      can_msgs.append([0x400, 0, radar_state_msg, 1])
      can_msgs.append([0x445, 0, radar_msg.decode("hex"), 1])

    # add camera msg so controlsd thinks it's alive
    msg_struct["COUNTER"] = self.rk.frame % 4
    msg = honda.lookup_msg_id(0xe4)
    msg_data = honda.encode(msg, msg_struct)
    msg_data = fix(msg_data, 0xe4)
    can_msgs.append([0xe4, 0, msg_data, 2])

    Plant.logcan.send(can_list_to_can_capnp(can_msgs))

    # Fake sockets that controlsd subscribes to
    live_parameters = messaging.new_message()
    live_parameters.init('liveParameters')
    live_parameters.liveParameters.valid = True
    live_parameters.liveParameters.sensorValid = True
    live_parameters.liveParameters.steerRatio = CP.steerRatio
    live_parameters.liveParameters.stiffnessFactor = 1.0
    Plant.live_params.send(live_parameters.to_bytes())

    driver_monitoring = messaging.new_message()
    driver_monitoring.init('driverMonitoring')
    driver_monitoring.driverMonitoring.descriptor = [0.] * 7
    Plant.driverMonitoring.send(driver_monitoring.to_bytes())

    health = messaging.new_message()
    health.init('health')
    health.health.controlsAllowed = True
    Plant.health.send(health.to_bytes())

    thermal = messaging.new_message()
    thermal.init('thermal')
    thermal.thermal.freeSpace = 1.
    thermal.thermal.batteryPercent = 100
    Plant.thermal.send(thermal.to_bytes())

    # ******** publish a fake model going straight and fake calibration ********
    # note that this is worst case for MPC, since model will delay long mpc by one time step
    if publish_model and self.rk.frame % 5 == 0:
      md = messaging.new_message()
      cal = messaging.new_message()
      md.init('model')
      cal.init('liveCalibration')
      md.model.frameId = 0
      for x in [md.model.path, md.model.leftLane, md.model.rightLane]:
        x.points = [0.0]*50
        x.prob = 1.0
        x.std = 1.0
      md.model.lead.dist = float(d_rel)
      md.model.lead.prob = 1.
      md.model.lead.std = 0.1
      cal.liveCalibration.calStatus = 1
      cal.liveCalibration.calPerc = 100
      # fake values?
      Plant.model.send(md.to_bytes())
      Plant.cal.send(cal.to_bytes())

    # ******** update prevs ********
    self.speed = speed
    self.distance = distance
    self.distance_lead = distance_lead

    self.speed_prev = speed
    self.distance_prev = distance
    self.distance_lead_prev = distance_lead

    self.rk.keep_time()
    return (distance, speed, acceleration, distance_lead, brake, gas, steer_torque, fcw, controls_state_msgs)
示例#26
0
    def update(self, sendcan, enabled, CS, frame, actuators, pcm_cancel_cmd,
               hud_alert, audible_alert, forwarding_camera, left_line,
               right_line, lead):

        # *** compute control surfaces ***

        # gas and brake

        apply_gas = clip(actuators.gas, 0., 1.)

        if CS.CP.enableGasInterceptor:
            # send only send brake values if interceptor is detected. otherwise, send the regular value
            # +0.06 offset to reduce ABS pump usage when OP is engaged
            apply_accel = 0.06 - actuators.brake
        else:
            apply_accel = actuators.gas - actuators.brake

        apply_accel, self.accel_steady = accel_hysteresis(
            apply_accel, self.accel_steady, enabled)
        apply_accel = clip(apply_accel * ACCEL_SCALE, ACCEL_MIN, ACCEL_MAX)

        # steer torque
        apply_steer = int(round(actuators.steer * SteerLimitParams.STEER_MAX))

        apply_steer = apply_toyota_steer_torque_limits(apply_steer,
                                                       self.last_steer,
                                                       CS.steer_torque_motor,
                                                       SteerLimitParams)

        # only cut torque when steer state is a known fault
        if CS.steer_state in [9, 25]:
            self.last_fault_frame = frame

        # Cut steering for 2s after fault
        if not enabled or (frame - self.last_fault_frame < 200):
            apply_steer = 0
            apply_steer_req = 0
        else:
            apply_steer_req = 1

        self.steer_angle_enabled, self.ipas_reset_counter = \
          ipas_state_transition(self.steer_angle_enabled, enabled, CS.ipas_active, self.ipas_reset_counter)
        #print self.steer_angle_enabled, self.ipas_reset_counter, CS.ipas_active

        # steer angle
        if self.steer_angle_enabled and CS.ipas_active:
            apply_angle = actuators.steerAngle
            angle_lim = interp(CS.v_ego, ANGLE_MAX_BP, ANGLE_MAX_V)
            apply_angle = clip(apply_angle, -angle_lim, angle_lim)

            # windup slower
            if self.last_angle * apply_angle > 0. and abs(apply_angle) > abs(
                    self.last_angle):
                angle_rate_lim = interp(CS.v_ego, ANGLE_DELTA_BP,
                                        ANGLE_DELTA_V)
            else:
                angle_rate_lim = interp(CS.v_ego, ANGLE_DELTA_BP,
                                        ANGLE_DELTA_VU)

            apply_angle = clip(apply_angle, self.last_angle - angle_rate_lim,
                               self.last_angle + angle_rate_lim)
        else:
            apply_angle = CS.angle_steers

        if not enabled and CS.pcm_acc_status:
            # send pcm acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated
            pcm_cancel_cmd = 1

        # on entering standstill, send standstill request
        if CS.standstill and not self.last_standstill:
            self.standstill_req = True
        if CS.pcm_acc_status != 8:
            # pcm entered standstill or it's disabled
            self.standstill_req = False

        self.last_steer = apply_steer
        self.last_angle = apply_angle
        self.last_accel = apply_accel
        self.last_standstill = CS.standstill

        can_sends = []

        #*** control msgs ***
        #print "steer", apply_steer, min_lim, max_lim, CS.steer_torque_motor

        # toyota can trace shows this message at 42Hz, with counter adding alternatively 1 and 2;
        # sending it at 100Hz seem to allow a higher rate limit, as the rate limit seems imposed
        # on consecutive messages
        if ECU.CAM in self.fake_ecus:
            if self.angle_control:
                can_sends.append(
                    create_steer_command(self.packer, 0., 0, frame))
            else:
                can_sends.append(
                    create_steer_command(self.packer, apply_steer,
                                         apply_steer_req, frame))

        if self.angle_control:
            can_sends.append(
                create_ipas_steer_command(self.packer, apply_angle,
                                          self.steer_angle_enabled, ECU.APGS
                                          in self.fake_ecus))
        elif ECU.APGS in self.fake_ecus:
            can_sends.append(create_ipas_steer_command(self.packer, 0, 0,
                                                       True))

        # accel cmd comes from DSU, but we can spam can to cancel the system even if we are using lat only control
        if (frame % 3 == 0 and ECU.DSU in self.fake_ecus) or (
                pcm_cancel_cmd and ECU.CAM in self.fake_ecus):
            lead = lead or CS.v_ego < 12.  # at low speed we always assume the lead is present do ACC can be engaged
            if ECU.DSU in self.fake_ecus:
                can_sends.append(
                    create_accel_command(self.packer, apply_accel,
                                         pcm_cancel_cmd, self.standstill_req,
                                         lead))
            else:
                can_sends.append(
                    create_accel_command(self.packer, 0, pcm_cancel_cmd, False,
                                         lead))

        if CS.CP.enableGasInterceptor:
            # send exactly zero if apply_gas is zero. Interceptor will send the max between read value and apply_gas.
            # This prevents unexpected pedal range rescaling
            can_sends.append(create_gas_command(self.packer, apply_gas))

        if frame % 10 == 0 and ECU.CAM in self.fake_ecus and not forwarding_camera:
            for addr in TARGET_IDS:
                can_sends.append(create_video_target(frame / 10, addr))

        # ui mesg is at 100Hz but we send asap if:
        # - there is something to display
        # - there is something to stop displaying
        alert_out = process_hud_alert(hud_alert, audible_alert)
        steer, fcw, sound1, sound2 = alert_out

        if (any(alert_out) and not self.alert_active) or \
           (not any(alert_out) and self.alert_active):
            send_ui = True
            self.alert_active = not self.alert_active
        else:
            send_ui = False

        if (frame % 100 == 0 or send_ui) and ECU.CAM in self.fake_ecus:
            can_sends.append(
                create_ui_command(self.packer, steer, sound1, sound2,
                                  left_line, right_line))

        if frame % 100 == 0 and ECU.DSU in self.fake_ecus:
            can_sends.append(create_fcw_command(self.packer, fcw))

        #*** static msgs ***

        for (addr, ecu, cars, bus, fr_step, vl) in STATIC_MSGS:
            if frame % fr_step == 0 and ecu in self.fake_ecus and self.car_fingerprint in cars and not (
                    ecu == ECU.CAM and forwarding_camera):
                # special cases
                if fr_step == 5 and ecu == ECU.CAM and bus == 1:
                    cnt = (((frame / 5) % 7) + 1) << 5
                    vl = chr(cnt) + vl
                elif addr in (0x489, 0x48a) and bus == 0:
                    # add counter for those 2 messages (last 4 bits)
                    cnt = ((frame / 100) % 0xf) + 1
                    if addr == 0x48a:
                        # 0x48a has a 8 preceding the counter
                        cnt += 1 << 7
                    vl += chr(cnt)

                can_sends.append(make_can_msg(addr, vl, bus, False))

        sendcan.send(
            can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes())
示例#27
0
    def publish_logs(self, CS, start_time, CC, lac_log):
        """Send actuators and hud commands to the car, send controlsstate and MPC logging"""

        # Orientation and angle rates can be useful for carcontroller
        # Only calibrated (car) frame is relevant for the carcontroller
        orientation_value = list(
            self.sm['liveLocationKalman'].calibratedOrientationNED.value)
        if len(orientation_value) > 2:
            CC.orientationNED = orientation_value
        angular_rate_value = list(
            self.sm['liveLocationKalman'].angularVelocityCalibrated.value)
        if len(angular_rate_value) > 2:
            CC.angularVelocity = angular_rate_value

        CC.cruiseControl.cancel = CS.cruiseState.enabled and (
            not self.enabled or not self.CP.pcmCruise)
        if self.joystick_mode and self.sm.rcv_frame[
                'testJoystick'] > 0 and self.sm['testJoystick'].buttons[0]:
            CC.cruiseControl.cancel = True

        hudControl = CC.hudControl
        hudControl.setSpeed = float(self.v_cruise_kph * CV.KPH_TO_MS)
        hudControl.speedVisible = self.enabled
        hudControl.lanesVisible = self.enabled
        hudControl.leadVisible = self.sm['longitudinalPlan'].hasLead

        hudControl.rightLaneVisible = True
        hudControl.leftLaneVisible = True

        recent_blinker = (self.sm.frame - self.last_blinker_frame
                          ) * DT_CTRL < 5.0  # 5s blinker cooldown
        ldw_allowed = self.is_ldw_enabled and CS.vEgo > LDW_MIN_SPEED and not recent_blinker \
                        and not CC.latActive and self.sm['liveCalibration'].calStatus == Calibration.CALIBRATED

        model_v2 = self.sm['modelV2']
        desire_prediction = model_v2.meta.desirePrediction
        if len(desire_prediction) and ldw_allowed:
            right_lane_visible = self.sm['lateralPlan'].rProb > 0.5
            left_lane_visible = self.sm['lateralPlan'].lProb > 0.5
            l_lane_change_prob = desire_prediction[Desire.laneChangeLeft - 1]
            r_lane_change_prob = desire_prediction[Desire.laneChangeRight - 1]

            lane_lines = model_v2.laneLines
            l_lane_close = left_lane_visible and (lane_lines[1].y[0] >
                                                  -(1.08 + CAMERA_OFFSET))
            r_lane_close = right_lane_visible and (lane_lines[2].y[0] <
                                                   (1.08 - CAMERA_OFFSET))

            hudControl.leftLaneDepart = bool(
                l_lane_change_prob > LANE_DEPARTURE_THRESHOLD and l_lane_close)
            hudControl.rightLaneDepart = bool(
                r_lane_change_prob > LANE_DEPARTURE_THRESHOLD and r_lane_close)

        if hudControl.rightLaneDepart or hudControl.leftLaneDepart:
            self.events.add(EventName.ldw)

        clear_event_types = set()
        if ET.WARNING not in self.current_alert_types:
            clear_event_types.add(ET.WARNING)
        if self.enabled:
            clear_event_types.add(ET.NO_ENTRY)

        alerts = self.events.create_alerts(
            self.current_alert_types,
            [self.CP, CS, self.sm, self.is_metric, self.soft_disable_timer])
        self.AM.add_many(self.sm.frame, alerts)
        current_alert = self.AM.process_alerts(self.sm.frame,
                                               clear_event_types)
        if current_alert:
            hudControl.visualAlert = current_alert.visual_alert

        if not self.read_only and self.initialized:
            # send car controls over can
            self.last_actuators, can_sends = self.CI.apply(CC)
            self.pm.send(
                'sendcan',
                can_list_to_can_capnp(can_sends,
                                      msgtype='sendcan',
                                      valid=CS.canValid))
            CC.actuatorsOutput = self.last_actuators

        force_decel = (self.sm['driverMonitoringState'].awarenessStatus < 0.) or \
                      (self.state == State.softDisabling)

        # Curvature & Steering angle
        params = self.sm['liveParameters']

        steer_angle_without_offset = math.radians(CS.steeringAngleDeg -
                                                  params.angleOffsetDeg)
        curvature = -self.VM.calc_curvature(steer_angle_without_offset,
                                            CS.vEgo, params.roll)

        # controlsState
        dat = messaging.new_message('controlsState')
        dat.valid = CS.canValid
        controlsState = dat.controlsState
        if current_alert:
            controlsState.alertText1 = current_alert.alert_text_1
            controlsState.alertText2 = current_alert.alert_text_2
            controlsState.alertSize = current_alert.alert_size
            controlsState.alertStatus = current_alert.alert_status
            controlsState.alertBlinkingRate = current_alert.alert_rate
            controlsState.alertType = current_alert.alert_type
            controlsState.alertSound = current_alert.audible_alert

        controlsState.canMonoTimes = list(CS.canMonoTimes)
        controlsState.longitudinalPlanMonoTime = self.sm.logMonoTime[
            'longitudinalPlan']
        controlsState.lateralPlanMonoTime = self.sm.logMonoTime['lateralPlan']
        controlsState.enabled = self.enabled
        controlsState.active = self.active
        controlsState.curvature = curvature
        controlsState.desiredCurvature = self.desired_curvature
        controlsState.desiredCurvatureRate = self.desired_curvature_rate
        controlsState.state = self.state
        controlsState.engageable = not self.events.any(ET.NO_ENTRY)
        controlsState.longControlState = self.LoC.long_control_state
        controlsState.vPid = float(self.LoC.v_pid)
        controlsState.vCruise = float(self.v_cruise_kph)
        controlsState.upAccelCmd = float(self.LoC.pid.p)
        controlsState.uiAccelCmd = float(self.LoC.pid.i)
        controlsState.ufAccelCmd = float(self.LoC.pid.f)
        controlsState.cumLagMs = -self.rk.remaining * 1000.
        controlsState.startMonoTime = int(start_time * 1e9)
        controlsState.forceDecel = bool(force_decel)
        controlsState.canErrorCounter = self.can_rcv_error_counter

        lat_tuning = self.CP.lateralTuning.which()
        if self.joystick_mode:
            controlsState.lateralControlState.debugState = lac_log
        elif self.CP.steerControlType == car.CarParams.SteerControlType.angle:
            controlsState.lateralControlState.angleState = lac_log
        elif lat_tuning == 'pid':
            controlsState.lateralControlState.pidState = lac_log
        elif lat_tuning == 'torque':
            controlsState.lateralControlState.torqueState = lac_log
        elif lat_tuning == 'indi':
            controlsState.lateralControlState.indiState = lac_log

        self.pm.send('controlsState', dat)

        # carState
        car_events = self.events.to_msg()
        cs_send = messaging.new_message('carState')
        cs_send.valid = CS.canValid
        cs_send.carState = CS
        cs_send.carState.events = car_events
        self.pm.send('carState', cs_send)

        # carEvents - logged every second or on change
        if (self.sm.frame % int(1. / DT_CTRL)
                == 0) or (self.events.names != self.events_prev):
            ce_send = messaging.new_message('carEvents', len(self.events))
            ce_send.carEvents = car_events
            self.pm.send('carEvents', ce_send)
        self.events_prev = self.events.names.copy()

        # carParams - logged every 50 seconds (> 1 per segment)
        if (self.sm.frame % int(50. / DT_CTRL) == 0):
            cp_send = messaging.new_message('carParams')
            cp_send.carParams = self.CP
            self.pm.send('carParams', cp_send)

        # carControl
        cc_send = messaging.new_message('carControl')
        cc_send.valid = CS.canValid
        cc_send.carControl = CC
        self.pm.send('carControl', cc_send)

        # copy CarControl to pass to CarInterface on the next iteration
        self.CC = CC
示例#28
0
    def update(self, sendcan, enabled, CS, frame, actuators, pcm_cancel_cmd,
               hud_alert, audible_alert):

        # *** compute control surfaces ***

        # gas and brake
        apply_accel = actuators.gas - actuators.brake
        apply_accel, self.accel_steady = accel_hysteresis(
            apply_accel, self.accel_steady, enabled)
        apply_accel = clip(apply_accel * ACCEL_SCALE, ACCEL_MIN, ACCEL_MAX)

        # steer torque
        apply_steer = int(round(actuators.steer * STEER_MAX))
        # TODO use these values to decide if we should use apply_steer or apply_angle
        outp = 'carcontroller apply_steer %s  actuators.steerAngle %s' % (
            apply_steer, actuators.steerAngle)
        # print outp
        logging.info(outp)

        # max_lim = min(max(CS.steer_torque_motor + STEER_ERROR_MAX, STEER_ERROR_MAX), STEER_MAX)
        # min_lim = max(min(CS.steer_torque_motor - STEER_ERROR_MAX, -STEER_ERROR_MAX), -STEER_MAX)

        # apply_steer = clip(apply_steer, min_lim, max_lim)
        apply_steer = clip(apply_steer, -STEER_MAX, STEER_MAX)

        # slow rate if steer torque increases in magnitude
        if self.last_steer > 0:
            apply_steer = clip(
                apply_steer,
                max(self.last_steer - STEER_DELTA_DOWN, -STEER_DELTA_UP),
                self.last_steer + STEER_DELTA_UP)
        else:
            apply_steer = clip(
                apply_steer, self.last_steer - STEER_DELTA_UP,
                min(self.last_steer + STEER_DELTA_DOWN, STEER_DELTA_UP))

        #self.steer_angle_enabled, self.ipas_reset_counter = \
        #  ipas_state_transition(self.steer_angle_enabled, enabled, CS.ipas_active, self.ipas_reset_counter)
        #print self.steer_angle_enabled, self.ipas_reset_counter, CS.ipas_active

        # steer angle
        self.steer_angle_enabled = True  #!!! TODO use if we are doing apply_angle (instead of apply_steer)
        if self.steer_angle_enabled:
            apply_angle = actuators.steerAngle
            angle_lim = interp(CS.v_ego, ANGLE_MAX_BP, ANGLE_MAX_V)
            apply_angle = clip(apply_angle, -angle_lim, angle_lim)

            # windup slower
            if self.last_angle * apply_angle > 0. and abs(apply_angle) > abs(
                    self.last_angle):
                angle_rate_lim = interp(CS.v_ego, ANGLE_DELTA_BP,
                                        ANGLE_DELTA_V)
            else:
                angle_rate_lim = interp(CS.v_ego, ANGLE_DELTA_BP,
                                        ANGLE_DELTA_VU)

            apply_angle = clip(apply_angle, self.last_angle - angle_rate_lim,
                               self.last_angle + angle_rate_lim)
            outp = '  apply_angle:%s  angle_lim:%s  angle_rate_lim:%s  apply_steer:%s' % (
                apply_angle, angle_lim, angle_rate_lim, apply_steer)
            # print outp
            logging.info(outp)
            outp = '  CS.angle_steers:%s  CS.v_ego:%s' % (CS.angle_steers,
                                                          CS.v_ego)
            # print outp
            logging.info(outp)


#    else:
#      apply_angle = CS.angle_steers  # just sets it to the current steering angle

        self.standstill_req = False  #?

        moving_fast = True  # for status message
        if CS.v_ego < 5:  # don't steer if going under 6mph to not lock out LKAS (was < 3)
            apply_angle = 0
            apply_steer = 0
            moving_fast = False

        if self.last_steer == 0 and apply_steer != 0:
            self.send_new_status = True
        self.last_steer = apply_steer
        self.last_angle = apply_angle
        self.last_accel = apply_accel
        self.last_standstill = CS.standstill

        can_sends = []

        #*** control msgs ***
        #print "steer", apply_steer, min_lim, max_lim, CS.steer_torque_motor
        # can_sends.append(create_steer_command(self.packer, apply_steer, frame))
        # TODO verify units and see if we want apply_steer or apply_angle

        # frame is 100Hz (0.01s period)
        if (self.ccframe % 10 == 0):  # 0.1s period
            new_msg = create_2d9(self.car_fingerprint)
            sendcan.send(
                can_list_to_can_capnp([new_msg], msgtype='sendcan').to_bytes())
            can_sends.append(new_msg)
        if (self.ccframe % 25 == 0) or self.send_new_status:  # 0.25s period
            if (self.ccframe - self.prev_2a6
                ) < 20:  # at least 200ms (20 frames) since last 2a6.
                self.send_new_status = True  # will not send, so send next time.
                apply_steer = 0  # cannot steer yet, waiting for 2a6 to be sent.
                last_steer = 0
                last_angle = 0
            else:
                new_msg = create_2a6(CS.gear_shifter, apply_steer, moving_fast,
                                     self.car_fingerprint)
                sendcan.send(
                    can_list_to_can_capnp([new_msg],
                                          msgtype='sendcan').to_bytes())
                can_sends.append(new_msg)
                self.send_new_status = False
                self.prev_2a6 = self.ccframe
        new_msg = create_292(int(apply_steer * CAR_UNITS_PER_DEGREE), frame,
                             moving_fast)
        sendcan.send(
            can_list_to_can_capnp([new_msg], msgtype='sendcan').to_bytes())
        can_sends.append(new_msg)  # degrees * 5.1 -> car steering units
        for msg in can_sends:
            [addr, _, dat, _] = msg
            outp = ('make_can_msg:%s  len:%d  %s' %
                    ('0x{:02x}'.format(addr), len(dat), ' '.join(
                        '{:02x}'.format(ord(c)) for c in dat)))
            logging.info(outp)

        self.ccframe += 1
示例#29
0
    def publish_logs(self, CS, start_time, actuators, v_acc, a_acc, lac_log):
        """Send actuators and hud commands to the car, send controlsstate and MPC logging"""

        CC = car.CarControl.new_message()
        CC.enabled = self.enabled
        CC.actuators = actuators

        CC.cruiseControl.override = True
        CC.cruiseControl.cancel = not self.CP.enableCruise or (
            not self.enabled and CS.cruiseState.enabled)

        # Some override values for Honda
        # brake discount removes a sharp nonlinearity
        brake_discount = (1.0 - clip(actuators.brake * 3., 0.0, 1.0))
        speed_override = max(0.0,
                             (self.LoC.v_pid + CS.cruiseState.speedOffset) *
                             brake_discount)
        CC.cruiseControl.speedOverride = float(
            speed_override if self.CP.enableCruise else 0.0)
        CC.cruiseControl.accelOverride = self.CI.calc_accel_override(
            CS.aEgo, self.sm['plan'].aTarget, CS.vEgo, self.sm['plan'].vTarget)

        CC.hudControl.setSpeed = float(self.v_cruise_kph * CV.KPH_TO_MS)
        CC.hudControl.speedVisible = self.enabled
        CC.hudControl.lanesVisible = self.enabled
        CC.hudControl.leadVisible = self.sm['plan'].hasLead

        right_lane_visible = self.sm['pathPlan'].rProb > 0.5
        left_lane_visible = self.sm['pathPlan'].lProb > 0.5
        CC.hudControl.rightLaneVisible = bool(right_lane_visible)
        CC.hudControl.leftLaneVisible = bool(left_lane_visible)

        recent_blinker = (self.sm.frame - self.last_blinker_frame
                          ) * DT_CTRL < 5.0  # 5s blinker cooldown
        ldw_allowed = self.is_ldw_enabled and CS.vEgo > LDW_MIN_SPEED and not recent_blinker \
                        and not self.active and self.sm['liveCalibration'].calStatus == Calibration.CALIBRATED

        meta = self.sm['model'].meta
        if len(meta.desirePrediction) and ldw_allowed:
            l_lane_change_prob = meta.desirePrediction[Desire.laneChangeLeft -
                                                       1]
            r_lane_change_prob = meta.desirePrediction[Desire.laneChangeRight -
                                                       1]
            l_lane_close = left_lane_visible and (self.sm['pathPlan'].lPoly[3]
                                                  < (1.08 - CAMERA_OFFSET))
            r_lane_close = right_lane_visible and (self.sm['pathPlan'].rPoly[3]
                                                   > -(1.08 + CAMERA_OFFSET))

            CC.hudControl.leftLaneDepart = bool(
                l_lane_change_prob > LANE_DEPARTURE_THRESHOLD and l_lane_close)
            CC.hudControl.rightLaneDepart = bool(
                r_lane_change_prob > LANE_DEPARTURE_THRESHOLD and r_lane_close)

        if CC.hudControl.rightLaneDepart or CC.hudControl.leftLaneDepart:
            self.events.add(EventName.ldw)

        alerts = self.events.create_alerts(self.current_alert_types,
                                           [self.CP, self.sm, self.is_metric])
        self.AM.add_many(self.sm.frame, alerts, self.enabled)
        self.AM.process_alerts(self.sm.frame)
        CC.hudControl.visualAlert = self.AM.visual_alert

        if not self.read_only:
            # send car controls over can
            can_sends = self.CI.apply(CC)
            self.pm.send(
                'sendcan',
                can_list_to_can_capnp(can_sends,
                                      msgtype='sendcan',
                                      valid=CS.canValid))

        force_decel = (self.sm['dMonitoringState'].awarenessStatus < 0.) or \
                        (self.state == State.softDisabling)

        steer_angle_rad = (CS.steeringAngle -
                           self.sm['pathPlan'].angleOffset) * CV.DEG_TO_RAD

        # controlsState
        dat = messaging.new_message('controlsState')
        dat.valid = CS.canValid
        controlsState = dat.controlsState
        controlsState.alertText1 = self.AM.alert_text_1
        controlsState.alertText2 = self.AM.alert_text_2
        controlsState.alertSize = self.AM.alert_size
        controlsState.alertStatus = self.AM.alert_status
        controlsState.alertBlinkingRate = self.AM.alert_rate
        controlsState.alertType = self.AM.alert_type
        controlsState.alertSound = self.AM.audible_alert
        controlsState.driverMonitoringOn = self.sm[
            'dMonitoringState'].faceDetected
        controlsState.canMonoTimes = list(CS.canMonoTimes)
        controlsState.planMonoTime = self.sm.logMonoTime['plan']
        controlsState.pathPlanMonoTime = self.sm.logMonoTime['pathPlan']
        controlsState.enabled = self.enabled
        controlsState.active = self.active
        controlsState.vEgo = CS.vEgo
        controlsState.vEgoRaw = CS.vEgoRaw
        controlsState.angleSteers = CS.steeringAngle
        controlsState.curvature = self.VM.calc_curvature(
            steer_angle_rad, CS.vEgo)
        controlsState.steerOverride = CS.steeringPressed
        controlsState.state = self.state
        controlsState.engageable = not self.events.any(ET.NO_ENTRY)
        controlsState.longControlState = self.LoC.long_control_state
        controlsState.vPid = float(self.LoC.v_pid)
        controlsState.vCruise = float(self.v_cruise_kph)
        controlsState.upAccelCmd = float(self.LoC.pid.p)
        controlsState.uiAccelCmd = float(self.LoC.pid.i)
        controlsState.ufAccelCmd = float(self.LoC.pid.f)
        controlsState.angleSteersDes = float(self.LaC.angle_steers_des)
        controlsState.vTargetLead = float(v_acc)
        controlsState.aTarget = float(a_acc)
        controlsState.jerkFactor = float(self.sm['plan'].jerkFactor)
        controlsState.gpsPlannerActive = self.sm['plan'].gpsPlannerActive
        controlsState.vCurvature = self.sm['plan'].vCurvature
        controlsState.decelForModel = self.sm[
            'plan'].longitudinalPlanSource == LongitudinalPlanSource.model
        controlsState.cumLagMs = -self.rk.remaining * 1000.
        controlsState.startMonoTime = int(start_time * 1e9)
        controlsState.mapValid = self.sm['plan'].mapValid
        controlsState.forceDecel = bool(force_decel)
        controlsState.canErrorCounter = self.can_error_counter

        if self.CP.lateralTuning.which() == 'pid':
            controlsState.lateralControlState.pidState = lac_log
        elif self.CP.lateralTuning.which() == 'lqr':
            controlsState.lateralControlState.lqrState = lac_log
        elif self.CP.lateralTuning.which() == 'indi':
            controlsState.lateralControlState.indiState = lac_log
        self.pm.send('controlsState', dat)

        # carState
        car_events = self.events.to_msg()
        cs_send = messaging.new_message('carState')
        cs_send.valid = CS.canValid
        cs_send.carState = CS
        cs_send.carState.events = car_events
        self.pm.send('carState', cs_send)

        # carEvents - logged every second or on change
        if (self.sm.frame % int(1. / DT_CTRL)
                == 0) or (self.events.names != self.events_prev):
            ce_send = messaging.new_message('carEvents', len(self.events))
            ce_send.carEvents = car_events
            self.pm.send('carEvents', ce_send)
        self.events_prev = self.events.names.copy()

        # carParams - logged every 50 seconds (> 1 per segment)
        if (self.sm.frame % int(50. / DT_CTRL) == 0):
            cp_send = messaging.new_message('carParams')
            cp_send.carParams = self.CP
            self.pm.send('carParams', cp_send)

        # carControl
        cc_send = messaging.new_message('carControl')
        cc_send.valid = CS.canValid
        cc_send.carControl = CC
        self.pm.send('carControl', cc_send)

        # copy CarControl to pass to CarInterface on the next iteration
        self.CC = CC
示例#30
0
    def test_panda_safety_carstate(self):
        """
      Assert that panda safety matches openpilot's carState
    """
        if self.CP.dashcamOnly:
            self.skipTest("no need to check panda safety for dashcamOnly")

        CC = car.CarControl.new_message()

        # warm up pass, as initial states may be different
        for can in self.can_msgs[:300]:
            for msg in can_capnp_to_can_list(can.can, src_filter=range(64)):
                to_send = package_can_msg(msg)
                self.safety.safety_rx_hook(to_send)
                self.CI.update(CC, (can_list_to_can_capnp([
                    msg,
                ]), ))

        if not self.CP.pcmCruise:
            self.safety.set_controls_allowed(0)

        controls_allowed_prev = False
        CS_prev = car.CarState.new_message()
        checks = defaultdict(lambda: 0)
        for can in self.can_msgs:
            CS = self.CI.update(CC, (can.as_builder().to_bytes(), ))
            for msg in can_capnp_to_can_list(can.can, src_filter=range(64)):
                to_send = package_can_msg(msg)
                ret = self.safety.safety_rx_hook(to_send)
                self.assertEqual(1, ret,
                                 f"safety rx failed ({ret=}): {to_send}")

            # TODO: check rest of panda's carstate (steering, ACC main on, etc.)

            # TODO: make the interceptor thresholds in openpilot and panda match, then remove this exception
            gas_pressed = CS.gasPressed
            if self.CP.enableGasInterceptor and gas_pressed and not self.safety.get_gas_pressed_prev(
            ):
                # panda intentionally has a higher threshold
                if self.CP.carName == "toyota" and 15 < CS.gas < 15 * 1.5:
                    gas_pressed = False
            checks[
                'gasPressed'] += gas_pressed != self.safety.get_gas_pressed_prev(
                )

            # TODO: remove this exception once this mismatch is resolved
            brake_pressed = CS.brakePressed
            if CS.brakePressed and not self.safety.get_brake_pressed_prev():
                if self.CP.carFingerprint in (
                        HONDA.PILOT, HONDA.PASSPORT,
                        HONDA.RIDGELINE) and CS.brake > 0.05:
                    brake_pressed = False
            checks[
                'brakePressed'] += brake_pressed != self.safety.get_brake_pressed_prev(
                )

            if self.CP.pcmCruise:
                # On most pcmCruise cars, openpilot's state is always tied to the PCM's cruise state.
                # On Honda Nidec, we always engage on the rising edge of the PCM cruise state, but
                # openpilot brakes to zero even if the min ACC speed is non-zero (i.e. the PCM disengages).
                if self.CP.carName == "honda" and self.CP.carFingerprint not in HONDA_BOSCH:
                    # only the rising edges are expected to match
                    if CS.cruiseState.enabled and not CS_prev.cruiseState.enabled:
                        checks[
                            'controlsAllowed'] += not self.safety.get_controls_allowed(
                            )
                else:
                    checks[
                        'controlsAllowed'] += not CS.cruiseState.enabled and self.safety.get_controls_allowed(
                        )
            else:
                # Check for enable events on rising edge of controls allowed
                button_enable = any(evt.enable for evt in CS.events)
                mismatch = button_enable != (
                    self.safety.get_controls_allowed()
                    and not controls_allowed_prev)
                checks['controlsAllowed'] += mismatch
                controls_allowed_prev = self.safety.get_controls_allowed()
                if button_enable and not mismatch:
                    self.safety.set_controls_allowed(False)

            if self.CP.carName == "honda":
                checks[
                    'mainOn'] += CS.cruiseState.available != self.safety.get_acc_main_on(
                    )

            CS_prev = CS

        # TODO: add flag to toyota safety
        if self.CP.carFingerprint == TOYOTA.SIENNA and checks[
                'brakePressed'] < 25:
            checks['brakePressed'] = 0

        failed_checks = {k: v for k, v in checks.items() if v > 0}
        self.assertFalse(
            len(failed_checks),
            f"panda safety doesn't agree with openpilot: {failed_checks}")