Ejemplo n.º 1
0
def controlsd_thread(gctx=None, rate=100, default_bias=0.):
    gc.disable()

    # start the loop
    set_realtime_priority(3)

    context = zmq.Context()
    params = Params()

    # Pub Sockets
    live100 = messaging.pub_sock(context, service_list['live100'].port)
    carstate = messaging.pub_sock(context, service_list['carState'].port)
    carcontrol = messaging.pub_sock(context, service_list['carControl'].port)
    livempc = messaging.pub_sock(context, service_list['liveMpc'].port)

    is_metric = params.get("IsMetric") == "1"
    passive = params.get("Passive") != "0"

    # No sendcan if passive
    if not passive:
        sendcan = messaging.pub_sock(context, service_list['sendcan'].port)
    else:
        sendcan = None

    # Sub sockets
    poller = zmq.Poller()
    thermal = messaging.sub_sock(context,
                                 service_list['thermal'].port,
                                 conflate=True,
                                 poller=poller)
    health = messaging.sub_sock(context,
                                service_list['health'].port,
                                conflate=True,
                                poller=poller)
    cal = messaging.sub_sock(context,
                             service_list['liveCalibration'].port,
                             conflate=True,
                             poller=poller)
    driver_monitor = messaging.sub_sock(context,
                                        service_list['driverMonitoring'].port,
                                        conflate=True,
                                        poller=poller)
    gps_location = messaging.sub_sock(context,
                                      service_list['gpsLocationExternal'].port,
                                      conflate=True,
                                      poller=poller)
    logcan = messaging.sub_sock(context, service_list['can'].port)

    CC = car.CarControl.new_message()
    CI, CP = get_car(logcan, sendcan, 1.0 if passive else None)

    if CI is None:
        raise Exception("unsupported car")

    # if stock camera is connected, then force passive behavior
    if not CP.enableCamera:
        passive = True
        sendcan = None

    if passive:
        CP.safetyModel = car.CarParams.SafetyModels.noOutput

    # Get FCW toggle from settings
    fcw_enabled = params.get("IsFcwEnabled") == "1"
    geofence = None

    PL = Planner(CP, fcw_enabled)
    LoC = LongControl(CP, CI.compute_gb)
    VM = VehicleModel(CP)
    LaC = LatControl(CP)
    AM = AlertManager()
    driver_status = DriverStatus()

    if not passive:
        AM.add("startup", False)

    # Write CarParams for radard and boardd safety mode
    params.put("CarParams", CP.to_bytes())

    state = State.disabled
    soft_disable_timer = 0
    v_cruise_kph = 255
    v_cruise_kph_last = 0
    overtemp = False
    free_space = False
    cal_status = Calibration.INVALID
    cal_perc = 0
    mismatch_counter = 0
    low_battery = False

    rk = Ratekeeper(rate, print_delay_threshold=2. / 1000)

    # Read angle offset from previous drive, fallback to default
    angle_offset = default_bias
    calibration_params = params.get("CalibrationParams")
    if calibration_params:
        try:
            calibration_params = json.loads(calibration_params)
            angle_offset = calibration_params["angle_offset2"]
        except (ValueError, KeyError):
            pass

    prof = Profiler(False)  # off by default

    while True:
        prof.checkpoint("Ratekeeper", ignore=True)

        # Sample data and compute car events
        CS, events, cal_status, cal_perc, overtemp, free_space, low_battery, mismatch_counter = data_sample(
            CI, CC, thermal, cal, health, driver_monitor, gps_location, poller,
            cal_status, cal_perc, overtemp, free_space, low_battery,
            driver_status, geofence, state, mismatch_counter, params)
        prof.checkpoint("Sample")

        # Define longitudinal plan (MPC)
        plan, plan_ts = calc_plan(CS, CP, events, PL, LaC, LoC, v_cruise_kph,
                                  driver_status, geofence)
        prof.checkpoint("Plan")

        if not passive:
            # update control state
            state, soft_disable_timer, v_cruise_kph, v_cruise_kph_last = \
              state_transition(CS, CP, state, events, soft_disable_timer, v_cruise_kph, AM)
            prof.checkpoint("State transition")

        # Compute actuators (runs PID loops and lateral MPC)
        actuators, v_cruise_kph, driver_status, angle_offset = state_control(
            plan, CS, CP, state, events, v_cruise_kph, v_cruise_kph_last, AM,
            rk, driver_status, PL, LaC, LoC, VM, angle_offset, passive,
            is_metric, cal_perc)
        prof.checkpoint("State Control")

        # Publish data
        CC = data_send(PL.perception_state, plan, plan_ts, CS, CI, CP, VM,
                       state, events, actuators, v_cruise_kph, rk, carstate,
                       carcontrol, live100, livempc, AM, driver_status, LaC,
                       LoC, angle_offset, passive)
        prof.checkpoint("Sent")

        rk.keep_time()  # Run at 100Hz
        prof.display()
Ejemplo n.º 2
0
def manager_init(spinner=None):
    params = Params()
    params.manager_start()

    default_params = [
        ("CommunityFeaturesToggle", "0"),
        ("CompletedTrainingVersion", "0"),
        ("IsRHD", "0"),
        ("IsMetric", "0"),
        ("RecordFront", "0"),
        ("HasAcceptedTerms", "0"),
        ("HasCompletedSetup", "0"),
        ("IsUploadRawEnabled", "1"),
        ("IsLdwEnabled", "1"),
        ("LastUpdateTime",
         datetime.datetime.utcnow().isoformat().encode('utf8')),
        ("OpenpilotEnabledToggle", "1"),
        ("VisionRadarToggle", "0"),
        ("LaneChangeEnabled", "1"),
        ("IsDriverViewEnabled", "0"),
    ]

    # set unset params
    for k, v in default_params:
        if params.get(k) is None:
            params.put(k, v)

    # is this dashcam?
    if os.getenv("PASSIVE") is not None:
        params.put("Passive", str(int(os.getenv("PASSIVE"))))

    if params.get("Passive") is None:
        raise Exception("Passive must be set to continue")

    if EON:
        update_apks()

    os.umask(0)  # Make sure we can create files with 777 permissions

    # Create folders needed for msgq
    try:
        os.mkdir("/dev/shm")
    except FileExistsError:
        pass
    except PermissionError:
        print("WARNING: failed to make /dev/shm")

    # set dongle id
    reg_res = register(spinner)
    if reg_res:
        dongle_id = reg_res
    else:
        raise Exception("server registration failed")
    os.environ['DONGLE_ID'] = dongle_id  # Needed for swaglog and loggerd

    if not dirty:
        os.environ['CLEAN'] = '1'

    cloudlog.bind_global(dongle_id=dongle_id,
                         version=version,
                         dirty=dirty,
                         device=HARDWARE.get_device_type())
    crash.bind_user(id=dongle_id)
    crash.bind_extra(version=version,
                     dirty=dirty,
                     device=HARDWARE.get_device_type())

    # ensure shared libraries are readable by apks
    if EON:
        os.chmod(BASEDIR, 0o755)
        os.chmod("/dev/shm", 0o777)
        os.chmod(os.path.join(BASEDIR, "cereal"), 0o755)
        os.chmod(os.path.join(BASEDIR, "cereal", "libmessaging_shared.so"),
                 0o755)
Ejemplo n.º 3
0
class TestParams(unittest.TestCase):
    def setUp(self):
        self.tmpdir = tempfile.mkdtemp()
        print("using", self.tmpdir)
        self.params = Params(self.tmpdir)

    def tearDown(self):
        shutil.rmtree(self.tmpdir)

    def test_params_put_and_get(self):
        self.params.put("DongleId", "cb38263377b873ee")
        assert self.params.get("DongleId") == b"cb38263377b873ee"

    def test_params_non_ascii(self):
        st = b"\xe1\x90\xff"
        self.params.put("CarParams", st)
        assert self.params.get("CarParams") == st

    def test_params_get_cleared_panda_disconnect(self):
        self.params.put("CarParams", "test")
        self.params.put("DongleId", "cb38263377b873ee")
        assert self.params.get("CarParams") == b"test"
        self.params.panda_disconnect()
        assert self.params.get("CarParams") is None
        assert self.params.get("DongleId") is not None

    def test_params_get_cleared_manager_start(self):
        self.params.put("CarParams", "test")
        self.params.put("DongleId", "cb38263377b873ee")
        assert self.params.get("CarParams") == b"test"
        self.params.manager_start()
        assert self.params.get("CarParams") is None
        assert self.params.get("DongleId") is not None

    def test_params_two_things(self):
        self.params.put("DongleId", "bob")
        self.params.put("AthenadPid", "123")
        assert self.params.get("DongleId") == b"bob"
        assert self.params.get("AthenadPid") == b"123"

    def test_params_get_block(self):
        def _delayed_writer():
            time.sleep(0.1)
            self.params.put("CarParams", "test")

        threading.Thread(target=_delayed_writer).start()
        assert self.params.get("CarParams") is None
        assert self.params.get("CarParams", True) == b"test"

    def test_params_unknown_key_fails(self):
        with self.assertRaises(UnknownKeyName):
            self.params.get("swag")

    def test_params_permissions(self):
        permissions = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH

        self.params.put("DongleId", "cb38263377b873ee")
        st_mode = os.stat(f"{self.tmpdir}/d/DongleId").st_mode
        assert (st_mode & permissions) == permissions
Ejemplo n.º 4
0
def thermald_thread():
  # prevent LEECO from undervoltage
  BATT_PERC_OFF = 10 if LEON else 3

  health_timeout = int(1000 * 2.5 * DT_TRML)  # 2.5x the expected health frequency

  # now loop
  thermal_sock = messaging.pub_sock('thermal')
  health_sock = messaging.sub_sock('health', timeout=health_timeout)
  location_sock = messaging.sub_sock('gpsLocation')

  ignition = False
  fan_speed = 0
  count = 0

  off_ts = None
  started_ts = None
  started_seen = False
  thermal_status = ThermalStatus.green
  thermal_status_prev = ThermalStatus.green
  usb_power = True
  usb_power_prev = True

  network_type = NetworkType.none
  network_strength = NetworkStrength.unknown

  current_filter = FirstOrderFilter(0., CURRENT_TAU, DT_TRML)
  health_prev = None
  fw_version_match_prev = True
  current_connectivity_alert = None
  time_valid_prev = True
  should_start_prev = False

  is_uno = (read_tz(29, clip=False) < -1000)
  if is_uno or not ANDROID:
    handle_fan = handle_fan_uno
  else:
    setup_eon_fan()
    handle_fan = handle_fan_eon

  params = Params()
  pm = PowerMonitoring(is_uno)

  while 1:
    health = messaging.recv_sock(health_sock, wait=True)
    location = messaging.recv_sock(location_sock)
    location = location.gpsLocation if location else None
    msg = read_thermal()

    # clear car params when panda gets disconnected
    if health is None and health_prev is not None:
      params.panda_disconnect()
    health_prev = health

    if health is not None:
      usb_power = health.health.usbPowerMode != log.HealthData.UsbPowerMode.client

    # get_network_type is an expensive call. update every 10s
    if (count % int(10. / DT_TRML)) == 0:
      try:
        network_type = get_network_type()
        network_strength = get_network_strength(network_type)
      except Exception:
        cloudlog.exception("Error getting network status")

    msg.thermal.freeSpace = get_available_percent(default=100.0) / 100.0
    msg.thermal.memUsedPercent = int(round(psutil.virtual_memory().percent))
    msg.thermal.cpuPerc = int(round(psutil.cpu_percent()))
    msg.thermal.networkType = network_type
    msg.thermal.networkStrength = network_strength
    msg.thermal.batteryPercent = get_battery_capacity()
    msg.thermal.batteryStatus = get_battery_status()
    msg.thermal.batteryCurrent = get_battery_current()
    msg.thermal.batteryVoltage = get_battery_voltage()
    msg.thermal.usbOnline = get_usb_present()

    # Fake battery levels on uno for frame
    if is_uno:
      msg.thermal.batteryPercent = 100
      msg.thermal.batteryStatus = "Charging"

    current_filter.update(msg.thermal.batteryCurrent / 1e6)

    # TODO: add car battery voltage check
    max_cpu_temp = max(msg.thermal.cpu0, msg.thermal.cpu1,
                       msg.thermal.cpu2, msg.thermal.cpu3) / 10.0
    max_comp_temp = max(max_cpu_temp, msg.thermal.mem / 10., msg.thermal.gpu / 10.)
    bat_temp = msg.thermal.bat / 1000.

    fan_speed = handle_fan(max_cpu_temp, bat_temp, fan_speed, ignition)
    msg.thermal.fanSpeed = fan_speed

    # thermal logic with hysterisis
    if max_cpu_temp > 107. or bat_temp >= 63.:
      # onroad not allowed
      thermal_status = ThermalStatus.danger
    elif max_comp_temp > 92.5 or bat_temp > 60.:  # CPU throttling starts around ~90C
      # hysteresis between onroad not allowed and engage not allowed
      thermal_status = clip(thermal_status, ThermalStatus.red, ThermalStatus.danger)
    elif max_cpu_temp > 87.5:
      # hysteresis between engage not allowed and uploader not allowed
      thermal_status = clip(thermal_status, ThermalStatus.yellow, ThermalStatus.red)
    elif max_cpu_temp > 80.0:
      # uploader not allowed
      thermal_status = ThermalStatus.yellow
    elif max_cpu_temp > 75.0:
      # hysteresis between uploader not allowed and all good
      thermal_status = clip(thermal_status, ThermalStatus.green, ThermalStatus.yellow)
    else:
      # all good
      thermal_status = ThermalStatus.green

    # **** starting logic ****

    # Check for last update time and display alerts if needed
    now = datetime.datetime.utcnow()

    # show invalid date/time alert
    time_valid = now.year >= 2019
    if time_valid and not time_valid_prev:
      params.delete("Offroad_InvalidTime")
    if not time_valid and time_valid_prev:
      params.put("Offroad_InvalidTime", json.dumps(OFFROAD_ALERTS["Offroad_InvalidTime"]))
    time_valid_prev = time_valid

    # Show update prompt
    try:
      last_update = datetime.datetime.fromisoformat(params.get("LastUpdateTime", encoding='utf8'))
    except (TypeError, ValueError):
      last_update = now
    dt = now - last_update

    update_failed_count = params.get("UpdateFailedCount")
    update_failed_count = 0 if update_failed_count is None else int(update_failed_count)

    if dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1:
      if current_connectivity_alert != "expired":
        current_connectivity_alert = "expired"
        params.delete("Offroad_ConnectivityNeededPrompt")
        params.put("Offroad_ConnectivityNeeded", json.dumps(OFFROAD_ALERTS["Offroad_ConnectivityNeeded"]))
    elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
      remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0))
      if current_connectivity_alert != "prompt" + remaining_time:
        current_connectivity_alert = "prompt" + remaining_time
        alert_connectivity_prompt = copy.copy(OFFROAD_ALERTS["Offroad_ConnectivityNeededPrompt"])
        alert_connectivity_prompt["text"] += remaining_time + " days."
        params.delete("Offroad_ConnectivityNeeded")
        params.put("Offroad_ConnectivityNeededPrompt", json.dumps(alert_connectivity_prompt))
    elif current_connectivity_alert is not None:
      current_connectivity_alert = None
      params.delete("Offroad_ConnectivityNeeded")
      params.delete("Offroad_ConnectivityNeededPrompt")

    # start constellation of processes when the car starts
    ignition = health is not None and (health.health.ignitionLine or health.health.ignitionCan)

    do_uninstall = params.get("DoUninstall") == b"1"
    accepted_terms = params.get("HasAcceptedTerms") == terms_version
    completed_training = params.get("CompletedTrainingVersion") == training_version

    panda_signature = params.get("PandaFirmware")
    fw_version_match = (panda_signature is None) or (panda_signature == FW_SIGNATURE)   # don't show alert is no panda is connected (None)

    should_start = ignition

    # with 2% left, we killall, otherwise the phone will take a long time to boot
    should_start = should_start and msg.thermal.freeSpace > 0.02

    # confirm we have completed training and aren't uninstalling
    should_start = should_start and accepted_terms and completed_training and (not do_uninstall)

    # check for firmware mismatch
    should_start = should_start and fw_version_match

    # check if system time is valid
    should_start = should_start and time_valid

    # don't start while taking snapshot
    if not should_start_prev:
      is_taking_snapshot = params.get("IsTakingSnapshot") == b"1"
      should_start = should_start and (not is_taking_snapshot)

    if fw_version_match and not fw_version_match_prev:
      params.delete("Offroad_PandaFirmwareMismatch")
    if not fw_version_match and fw_version_match_prev:
      params.put("Offroad_PandaFirmwareMismatch", json.dumps(OFFROAD_ALERTS["Offroad_PandaFirmwareMismatch"]))

    # if any CPU gets above 107 or the battery gets above 63, kill all processes
    # controls will warn with CPU above 95 or battery above 60
    if thermal_status >= ThermalStatus.danger:
      should_start = False
      if thermal_status_prev < ThermalStatus.danger:
        params.put("Offroad_TemperatureTooHigh", json.dumps(OFFROAD_ALERTS["Offroad_TemperatureTooHigh"]))
    else:
      if thermal_status_prev >= ThermalStatus.danger:
        params.delete("Offroad_TemperatureTooHigh")

    if should_start:
      if not should_start_prev:
        params.delete("IsOffroad")

      off_ts = None
      if started_ts is None:
        started_ts = sec_since_boot()
        started_seen = True
        os.system('echo performance > /sys/class/devfreq/soc:qcom,cpubw/governor')
    else:
      if should_start_prev or (count == 0):
        params.put("IsOffroad", "1")

      started_ts = None
      if off_ts is None:
        off_ts = sec_since_boot()
        os.system('echo powersave > /sys/class/devfreq/soc:qcom,cpubw/governor')

      # shutdown if the battery gets lower than 3%, it's discharging, we aren't running for
      # more than a minute but we were running
      if msg.thermal.batteryPercent < BATT_PERC_OFF and msg.thermal.batteryStatus == "Discharging" and \
         started_seen and (sec_since_boot() - off_ts) > 60:
        os.system('LD_LIBRARY_PATH="" svc power shutdown')

    # Offroad power monitoring
    pm.calculate(health)
    msg.thermal.offroadPowerUsage = pm.get_power_used()

    msg.thermal.chargingError = current_filter.x > 0. and msg.thermal.batteryPercent < 90  # if current is positive, then battery is being discharged
    msg.thermal.started = started_ts is not None
    msg.thermal.startedTs = int(1e9*(started_ts or 0))

    msg.thermal.thermalStatus = thermal_status
    thermal_sock.send(msg.to_bytes())

    if usb_power_prev and not usb_power:
      params.put("Offroad_ChargeDisabled", json.dumps(OFFROAD_ALERTS["Offroad_ChargeDisabled"]))
    elif usb_power and not usb_power_prev:
      params.delete("Offroad_ChargeDisabled")

    thermal_status_prev = thermal_status
    usb_power_prev = usb_power
    fw_version_match_prev = fw_version_match
    should_start_prev = should_start

    # report to server once per minute
    if (count % int(60. / DT_TRML)) == 0:
      cloudlog.event("STATUS_PACKET",
                     count=count,
                     health=(health.to_dict() if health else None),
                     location=(location.to_dict() if location else None),
                     thermal=msg.to_dict())

    count += 1
Ejemplo n.º 5
0
    def __init__(self, sm=None, pm=None, can_sock=None):
        config_realtime_process(3, Priority.CTRL_HIGH)

        # Setup sockets
        self.pm = pm
        if self.pm is None:
            self.pm = messaging.PubMaster([
                'sendcan', 'controlsState', 'carState', 'carControl',
                'carEvents', 'carParams'
            ])

        self.sm = sm
        if self.sm is None:
            self.sm = messaging.SubMaster([
                'thermal', 'health', 'model', 'liveCalibration',
                'dMonitoringState', 'plan', 'pathPlan', 'liveLocationKalman'
            ])

        self.can_sock = can_sock
        if can_sock is None:
            can_timeout = None if os.environ.get('NO_CAN_TIMEOUT',
                                                 False) else 100
            self.can_sock = messaging.sub_sock('can', timeout=can_timeout)

        # wait for one health and one CAN packet
        hw_type = messaging.recv_one(self.sm.sock['health']).health.hwType
        has_relay = hw_type in [HwType.blackPanda, HwType.uno, HwType.dos]
        print("Waiting for CAN messages...")
        get_one_can(self.can_sock)

        self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'],
                                   has_relay)

        # read params
        params = Params()
        self.is_metric = params.get("IsMetric", encoding='utf8') == "1"
        self.is_ldw_enabled = params.get("IsLdwEnabled",
                                         encoding='utf8') == "1"
        internet_needed = (params.get("Offroad_ConnectivityNeeded",
                                      encoding='utf8') is not None) and (
                                          params.get("DisableUpdates") != b"1")
        community_feature_toggle = params.get("CommunityFeaturesToggle",
                                              encoding='utf8') == "1"
        openpilot_enabled_toggle = params.get("OpenpilotEnabledToggle",
                                              encoding='utf8') == "1"
        passive = params.get("Passive", encoding='utf8') == "1" or \
                  internet_needed or not openpilot_enabled_toggle

        # detect sound card presence and ensure successful init
        sounds_available = HARDWARE.get_sound_card_online()

        car_recognized = self.CP.carName != 'mock'
        # If stock camera is disconnected, we loaded car controls and it's not dashcam mode
        controller_available = self.CP.enableCamera and self.CI.CC is not None and not passive and not self.CP.dashcamOnly
        community_feature_disallowed = self.CP.communityFeature and not community_feature_toggle
        self.read_only = not car_recognized or not controller_available or \
                           self.CP.dashcamOnly or community_feature_disallowed
        if self.read_only:
            self.CP.safetyModel = car.CarParams.SafetyModel.noOutput

        # Write CarParams for radard and boardd safety mode
        cp_bytes = self.CP.to_bytes()
        params.put("CarParams", cp_bytes)
        put_nonblocking("CarParamsCache", cp_bytes)

        self.CC = car.CarControl.new_message()
        self.AM = AlertManager()
        self.events = Events()

        self.LoC = LongControl(self.CP, self.CI.compute_gb)
        self.VM = VehicleModel(self.CP)

        if self.CP.lateralTuning.which() == 'pid':
            self.LaC = LatControlPID(self.CP)
        elif self.CP.lateralTuning.which() == 'indi':
            self.LaC = LatControlINDI(self.CP)
        elif self.CP.lateralTuning.which() == 'lqr':
            self.LaC = LatControlLQR(self.CP)

        self.state = State.disabled
        self.enabled = False
        self.active = False
        self.can_rcv_error = False
        self.soft_disable_timer = 0
        self.v_cruise_kph = 255
        self.v_cruise_kph_last = 0
        self.mismatch_counter = 0
        self.can_error_counter = 0
        self.last_blinker_frame = 0
        self.saturated_count = 0
        self.distance_traveled = 0
        self.last_functional_fan_frame = 0
        self.events_prev = []
        self.current_alert_types = [ET.PERMANENT]

        self.sm['liveCalibration'].calStatus = Calibration.CALIBRATED
        self.sm['thermal'].freeSpace = 1.
        self.sm['dMonitoringState'].events = []
        self.sm['dMonitoringState'].awarenessStatus = 1.
        self.sm['dMonitoringState'].faceDetected = False

        self.startup_event = get_startup_event(car_recognized,
                                               controller_available, hw_type)

        if not sounds_available:
            self.events.add(EventName.soundsUnavailable, static=True)
        if internet_needed:
            self.events.add(EventName.internetConnectivityNeeded, static=True)
        if community_feature_disallowed:
            self.events.add(EventName.communityFeatureDisallowed, static=True)
        if not car_recognized:
            self.events.add(EventName.carUnrecognized, static=True)
        if hw_type == HwType.whitePanda:
            self.events.add(EventName.whitePandaUnsupported, static=True)

        # controlsd is driven by can recv, expected at 100Hz
        self.rk = Ratekeeper(100, print_delay_threshold=None)
        self.prof = Profiler(False)  # off by default
Ejemplo n.º 6
0
def controlsd_thread(gctx=None, rate=100, default_bias=0.):
    gc.disable()

    # start the loop
    set_realtime_priority(3)

    context = zmq.Context()
    params = Params()

    # pub
    live100 = messaging.pub_sock(context, service_list['live100'].port)
    carstate = messaging.pub_sock(context, service_list['carState'].port)
    carcontrol = messaging.pub_sock(context, service_list['carControl'].port)
    livempc = messaging.pub_sock(context, service_list['liveMpc'].port)

    passive = params.get("Passive") != "0"
    if not passive:
        while 1:
            try:
                sendcan = messaging.pub_sock(context,
                                             service_list['sendcan'].port)
                break
            except zmq.error.ZMQError:
                kill_defaultd()
    else:
        sendcan = None

    # sub
    poller = zmq.Poller()
    thermal = messaging.sub_sock(context,
                                 service_list['thermal'].port,
                                 conflate=True,
                                 poller=poller)
    health = messaging.sub_sock(context,
                                service_list['health'].port,
                                conflate=True,
                                poller=poller)
    cal = messaging.sub_sock(context,
                             service_list['liveCalibration'].port,
                             conflate=True,
                             poller=poller)
    driver_monitor = messaging.sub_sock(context,
                                        service_list['driverMonitoring'].port,
                                        conflate=True,
                                        poller=poller)
    gps_location = messaging.sub_sock(context,
                                      service_list['gpsLocationExternal'].port,
                                      conflate=True,
                                      poller=poller)

    logcan = messaging.sub_sock(context, service_list['can'].port)

    CC = car.CarControl.new_message()

    CI, CP = get_car(logcan, sendcan, 1.0 if passive else None)

    if CI is None:
        raise Exception("unsupported car")

    # if stock camera is connected, then force passive behavior
    if not CP.enableCamera:
        passive = True
        sendcan = None

    if passive:
        CP.safetyModel = car.CarParams.SafetyModels.noOutput

    fcw_enabled = params.get("IsFcwEnabled") == "1"
    geofence = None
    try:
        from selfdrive.controls.lib.geofence import Geofence
        geofence = Geofence(params.get("IsGeofenceEnabled") == "1")
    except ImportError:
        # geofence not available
        params.put("IsGeofenceEnabled", "-1")

    PL = Planner(CP, fcw_enabled)
    LoC = LongControl(CP, CI.compute_gb)
    VM = VehicleModel(CP)
    LaC = LatControl(VM)
    AM = AlertManager()
    driver_status = DriverStatus()

    if not passive:
        AM.add("startup", False)

    # write CarParams
    params.put("CarParams", CP.to_bytes())

    state = State.disabled
    soft_disable_timer = 0
    v_cruise_kph = 255
    v_cruise_kph_last = 0
    overtemp = False
    free_space = False
    cal_status = Calibration.UNCALIBRATED
    mismatch_counter = 0

    rk = Ratekeeper(rate, print_delay_threshold=2. / 1000)

    # learned angle offset
    angle_offset = default_bias
    calibration_params = params.get("CalibrationParams")
    if calibration_params:
        try:
            calibration_params = json.loads(calibration_params)
            angle_offset = calibration_params["angle_offset2"]
        except (ValueError, KeyError):
            pass

    prof = Profiler(False)  # off by default

    while 1:

        prof.checkpoint("Ratekeeper", ignore=True)

        # sample data and compute car events
        CS, events, cal_status, overtemp, free_space, mismatch_counter = data_sample(
            CI, CC, thermal, cal, health, driver_monitor, gps_location, poller,
            cal_status, overtemp, free_space, driver_status, geofence, state,
            mismatch_counter, params)
        prof.checkpoint("Sample")

        # define plan
        plan, plan_ts = calc_plan(CS, CP, events, PL, LaC, LoC, v_cruise_kph,
                                  driver_status, geofence)
        prof.checkpoint("Plan")

        if not passive:
            # update control state
            state, soft_disable_timer, v_cruise_kph, v_cruise_kph_last = \
              state_transition(CS, CP, state, events, soft_disable_timer, v_cruise_kph, AM)
            prof.checkpoint("State transition")

        # compute actuators
        actuators, v_cruise_kph, driver_status, angle_offset = state_control(
            plan, CS, CP, state, events, v_cruise_kph, v_cruise_kph_last, AM,
            rk, driver_status, PL, LaC, LoC, VM, angle_offset, passive)
        prof.checkpoint("State Control")

        # publish data
        CC = data_send(PL.perception_state, plan, plan_ts, CS, CI, CP, VM,
                       state, events, actuators, v_cruise_kph, rk, carstate,
                       carcontrol, live100, livempc, AM, driver_status, LaC,
                       LoC, angle_offset, passive)
        prof.checkpoint("Sent")

        # *** run loop at fixed rate ***
        rk.keep_time()

        prof.display()
Ejemplo n.º 7
0
def controlsd_thread(gctx=None):
    gc.disable()

    # start the loop
    set_realtime_priority(3)

    params = Params()

    tinklaClient = TinklaClient()

    # Pub Sockets
    sendcan = messaging.pub_sock(service_list['sendcan'].port)
    controlsstate = messaging.pub_sock(service_list['controlsState'].port)
    carstate = messaging.pub_sock(service_list['carState'].port)
    carcontrol = messaging.pub_sock(service_list['carControl'].port)
    carevents = messaging.pub_sock(service_list['carEvents'].port)
    carparams = messaging.pub_sock(service_list['carParams'].port)

    is_metric = params.get("IsMetric") == "1"
    passive = params.get("Passive") != "0"

    sm = messaging.SubMaster([
        'thermal', 'health', 'liveCalibration', 'driverMonitoring', 'plan',
        'pathPlan', 'liveParameters'
    ])

    logcan = messaging.sub_sock(service_list['can'].port)

    # wait for health and CAN packets
    hw_type = messaging.recv_one(sm.sock['health']).health.hwType
    is_panda_black = hw_type == log.HealthData.HwType.blackPanda
    wait_for_can(logcan)

    CI, CP = get_car(logcan, sendcan, is_panda_black)
    logcan.close()

    # TODO: Use the logcan socket from above, but that will currenly break the tests
    can_timeout = None if os.environ.get('NO_CAN_TIMEOUT', False) else 100
    can_sock = messaging.sub_sock(service_list['can'].port,
                                  timeout=can_timeout)

    car_recognized = CP.carName != 'mock'
    # If stock camera is disconnected, we loaded car controls and it's not chffrplus
    controller_available = CP.enableCamera and CI.CC is not None and not passive
    read_only = not car_recognized or not controller_available
    if read_only:
        CP.safetyModel = car.CarParams.SafetyModel.elm327  # diagnostic only

    # Write CarParams for radard and boardd safety mode
    params.put("CarParams", CP.to_bytes())
    params.put("LongitudinalControl",
               "1" if CP.openpilotLongitudinalControl else "0")

    CC = car.CarControl.new_message()
    AM = AlertManager()

    startup_alert = get_startup_alert(car_recognized, controller_available)
    AM.add(sm.frame, startup_alert, False)

    LoC = LongControl(CP, CI.compute_gb)
    VM = VehicleModel(CP)

    if CP.lateralTuning.which() == 'pid':
        LaC = LatControlPID(CP)
    elif CP.lateralTuning.which() == 'indi':
        LaC = LatControlINDI(CP)
    elif CP.lateralTuning.which() == 'lqr':
        LaC = LatControlLQR(CP)

    driver_status = DriverStatus()

    state = State.disabled
    soft_disable_timer = 0
    v_cruise_kph = 255
    v_cruise_kph_last = 0
    overtemp = False
    free_space = False
    cal_status = Calibration.INVALID
    cal_perc = 0
    mismatch_counter = 0
    low_battery = False
    events_prev = []

    sm['pathPlan'].sensorValid = True
    sm['pathPlan'].posenetValid = True

    # detect sound card presence
    sounds_available = not os.path.isfile('/EON') or (
        os.path.isdir('/proc/asound/card0')
        and open('/proc/asound/card0/state').read().strip() == 'ONLINE')

    # controlsd is driven by can recv, expected at 100Hz
    rk = Ratekeeper(100, print_delay_threshold=None)

    prof = Profiler(False)  # off by default

    while True:
        start_time = sec_since_boot()
        prof.checkpoint("Ratekeeper", ignore=True)

        # Sample data and compute car events
        CS, events, cal_status, cal_perc, overtemp, free_space, low_battery, mismatch_counter =\
          data_sample(CI, CC, sm, can_sock, cal_status, cal_perc, overtemp, free_space, low_battery,
                      driver_status, state, mismatch_counter, params)
        prof.checkpoint("Sample")

        # Create alerts
        if not sm.all_alive_and_valid():
            events.append(
                create_event('commIssue', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
            logAllAliveAndValidInfoToTinklad(sm=sm, tinklaClient=tinklaClient)
        if not sm['pathPlan'].mpcSolutionValid:
            events.append(
                create_event('plannerError',
                             [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE]))
        if not sm['pathPlan'].sensorValid:
            events.append(
                create_event('sensorDataInvalid', [ET.NO_ENTRY, ET.PERMANENT]))
        if not sm['pathPlan'].paramsValid:
            events.append(create_event('vehicleModelInvalid', [ET.WARNING]))
        if not sm['pathPlan'].posenetValid:
            events.append(
                create_event('posenetInvalid', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
        if not sm['plan'].radarValid:
            events.append(
                create_event('radarFault', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
        if sm['plan'].radarCanError:
            events.append(
                create_event('radarCanError', [ET.NO_ENTRY, ET.SOFT_DISABLE]))
        if not CS.canValid:
            events.append(
                create_event('canError', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE]))
            tinklaClient.logCANErrorEvent(source="carcontroller",
                                          canMessage=0,
                                          additionalInformation="Invalid CAN")
        if not sounds_available:
            events.append(
                create_event('soundsUnavailable', [ET.NO_ENTRY, ET.PERMANENT]))

        # Only allow engagement with brake pressed when stopped behind another stopped car
        if CS.brakePressed and sm[
                'plan'].vTargetFuture >= STARTING_TARGET_SPEED and not CP.radarOffCan and CS.vEgo < 0.3:
            events.append(
                create_event('noTarget', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE]))

        if not read_only:
            # update control state
            state, soft_disable_timer, v_cruise_kph, v_cruise_kph_last = \
              state_transition(sm.frame, CS, CP, state, events, soft_disable_timer, v_cruise_kph, AM)
            prof.checkpoint("State transition")

        # Compute actuators (runs PID loops and lateral MPC)
        actuators, v_cruise_kph, driver_status, v_acc, a_acc, lac_log = \
          state_control(sm.frame, sm.rcv_frame, sm['plan'], sm['pathPlan'], sm['liveParameters'], CS, CP, state, events, v_cruise_kph, v_cruise_kph_last, AM, rk,
                        driver_status, LaC, LoC, VM, read_only, is_metric, cal_perc)

        rk.keep_time(1. / 10000)  # Run at 100Hz
        prof.checkpoint("State Control")

        # Publish data
        CC, events_prev = data_send(sm, CS, CI, CP, VM, state, events,
                                    actuators, v_cruise_kph, rk, carstate,
                                    carcontrol, carevents, carparams,
                                    controlsstate, sendcan, AM, driver_status,
                                    LaC, LoC, read_only, start_time, v_acc,
                                    a_acc, lac_log, events_prev)
        prof.checkpoint("Sent")

        rk.monitor_time()
        prof.display()
Ejemplo n.º 8
0
    def __init__(self, gctx, rate=100):
        self.rate = rate

        # *** log ***
        context = zmq.Context()

        # pub
        self.live100 = messaging.pub_sock(context,
                                          service_list['live100'].port)
        self.carstate = messaging.pub_sock(context,
                                           service_list['carState'].port)
        self.carcontrol = messaging.pub_sock(context,
                                             service_list['carControl'].port)
        sendcan = messaging.pub_sock(context, service_list['sendcan'].port)

        # sub
        self.thermal = messaging.sub_sock(context,
                                          service_list['thermal'].port)
        self.health = messaging.sub_sock(context, service_list['health'].port)
        logcan = messaging.sub_sock(context, service_list['can'].port)
        self.cal = messaging.sub_sock(context,
                                      service_list['liveCalibration'].port)

        self.CC = car.CarControl.new_message()
        self.CI, self.CP = get_car(logcan, sendcan)
        self.PL = Planner(self.CP)
        self.AM = AlertManager()
        self.LoC = LongControl()
        self.LaC = LatControl()
        self.VM = VehicleModel(self.CP)

        # write CarParams
        params = Params()
        params.put("CarParams", self.CP.to_bytes())

        # fake plan
        self.plan_ts = 0
        self.plan = log.Plan.new_message()
        self.plan.lateralValid = False
        self.plan.longitudinalValid = False

        # controls enabled state
        self.enabled = False
        self.last_enable_request = 0

        # learned angle offset
        self.angle_offset = 0
        calibration_params = params.get("CalibrationParams")
        if calibration_params:
            try:
                calibration_params = json.loads(calibration_params)
                self.angle_offset = calibration_params["angle_offset"]
            except (ValueError, KeyError):
                pass

        # rear view camera state
        self.rear_view_toggle = False
        self.rear_view_allowed = (params.get("IsRearViewMirror") == "1")

        self.v_cruise_kph = 255

        # 0.0 - 1.0
        self.awareness_status = 1.0

        self.soft_disable_timer = None

        self.overtemp = False
        self.free_space = 1.0
        self.cal_status = Calibration.UNCALIBRATED
        self.cal_perc = 0

        self.rk = Ratekeeper(self.rate, print_delay_threshold=2. / 1000)
Ejemplo n.º 9
0
    def __init__(self, sm=None, pm=None, can_sock=None):
        config_realtime_process(4 if TICI else 3, Priority.CTRL_HIGH)

        # Setup sockets
        self.pm = pm
        if self.pm is None:
            self.pm = messaging.PubMaster([
                'sendcan', 'controlsState', 'carState', 'carControl',
                'carEvents', 'carParams'
            ])

        self.sm = sm
        if self.sm is None:
            ignore = ['driverCameraState', 'managerState'
                      ] if SIMULATION else None
            self.sm = messaging.SubMaster([
                'deviceState', 'pandaState', 'modelV2', 'liveCalibration',
                'driverMonitoringState', 'longitudinalPlan', 'lateralPlan',
                'liveLocationKalman', 'roadCameraState', 'driverCameraState',
                'managerState', 'liveParameters', 'radarState'
            ],
                                          ignore_alive=ignore)

        self.can_sock = can_sock
        if can_sock is None:
            can_timeout = None if os.environ.get('NO_CAN_TIMEOUT',
                                                 False) else 100
            self.can_sock = messaging.sub_sock('can', timeout=can_timeout)

        # wait for one pandaState and one CAN packet
        hw_type = messaging.recv_one(
            self.sm.sock['pandaState']).pandaState.pandaType
        has_relay = hw_type in [
            PandaType.blackPanda, PandaType.uno, PandaType.dos
        ]
        print("Waiting for CAN messages...")
        get_one_can(self.can_sock)

        self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'],
                                   has_relay)

        # read params
        params = Params()
        self.is_metric = params.get_bool("IsMetric")
        self.is_ldw_enabled = params.get_bool("IsLdwEnabled")
        community_feature_toggle = params.get_bool("CommunityFeaturesToggle")
        openpilot_enabled_toggle = params.get_bool("OpenpilotEnabledToggle")
        passive = params.get_bool("Passive") or not openpilot_enabled_toggle

        # detect sound card presence and ensure successful init
        sounds_available = HARDWARE.get_sound_card_online()

        car_recognized = self.CP.carName != 'mock'
        # If stock camera is disconnected, we loaded car controls and it's not dashcam mode
        controller_available = self.CP.enableCamera and self.CI.CC is not None and not passive and not self.CP.dashcamOnly
        community_feature_disallowed = self.CP.communityFeature and not community_feature_toggle
        self.read_only = not car_recognized or not controller_available or \
                           self.CP.dashcamOnly or community_feature_disallowed
        if self.read_only:
            self.CP.safetyModel = car.CarParams.SafetyModel.noOutput

        # Write CarParams for radard and boardd safety mode
        cp_bytes = self.CP.to_bytes()
        params.put("CarParams", cp_bytes)
        put_nonblocking("CarParamsCache", cp_bytes)

        self.CC = car.CarControl.new_message()
        self.AM = AlertManager()
        self.events = Events()

        self.LoC = LongControl(self.CP, self.CI.compute_gb)
        self.VM = VehicleModel(self.CP)

        if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
            self.LaC = LatControlAngle(self.CP)
        elif self.CP.lateralTuning.which() == 'pid':
            self.LaC = LatControlPID(self.CP)
        elif self.CP.lateralTuning.which() == 'indi':
            self.LaC = LatControlINDI(self.CP)
        elif self.CP.lateralTuning.which() == 'lqr':
            self.LaC = LatControlLQR(self.CP)

        self.state = State.disabled
        self.enabled = False
        self.active = False
        self.can_rcv_error = False
        self.soft_disable_timer = 0
        self.v_cruise_kph = 255
        self.v_cruise_kph_last = 0
        self.mismatch_counter = 0
        self.can_error_counter = 0
        self.last_blinker_frame = 0
        self.saturated_count = 0
        self.distance_traveled = 0
        self.last_functional_fan_frame = 0
        self.events_prev = []
        self.current_alert_types = [ET.PERMANENT]
        self.logged_comm_issue = False

        # scc smoother
        self.is_cruise_enabled = False
        self.cruiseVirtualMaxSpeed = 0
        self.clu_speed_ms = 0.
        self.apply_accel = 0.
        self.fused_accel = 0.
        self.lead_drel = 0.
        self.aReqValue = 0.
        self.aReqValueMin = 0.
        self.aReqValueMax = 0.
        self.angle_steers_des = 0.

        self.sm['liveCalibration'].calStatus = Calibration.CALIBRATED
        self.sm['deviceState'].freeSpacePercent = 100
        self.sm['driverMonitoringState'].events = []
        self.sm['driverMonitoringState'].awarenessStatus = 1.
        self.sm['driverMonitoringState'].faceDetected = False
        self.sm['liveParameters'].valid = True

        self.startup_event = get_startup_event(car_recognized,
                                               controller_available, hw_type)

        if not sounds_available:
            self.events.add(EventName.soundsUnavailable, static=True)
        if community_feature_disallowed:
            self.events.add(EventName.communityFeatureDisallowed, static=True)
        if not car_recognized:
            self.events.add(EventName.carUnrecognized, static=True)
        elif self.read_only:
            self.events.add(EventName.dashcamMode, static=True)

        # controlsd is driven by can recv, expected at 100Hz
        self.rk = Ratekeeper(100, print_delay_threshold=None)
        self.prof = Profiler(False)  # off by default
Ejemplo n.º 10
0
def regen_segment(lr, frs=None, outdir=FAKEDATA):

    lr = list(lr)
    if frs is None:
        frs = dict()

    # setup env
    params = Params()
    params.clear_all()
    params.put_bool("Passive", False)
    params.put_bool("OpenpilotEnabledToggle", True)
    params.put_bool("CommunityFeaturesToggle", True)
    params.put_bool("CommunityFeaturesToggle", True)
    cal = messaging.new_message('liveCalibration')
    cal.liveCalibration.validBlocks = 20
    cal.liveCalibration.rpyCalib = [0.0, 0.0, 0.0]
    params.put("CalibrationParams", cal.to_bytes())

    os.environ["LOG_ROOT"] = outdir
    os.environ["SIMULATION"] = "1"

    os.environ['SKIP_FW_QUERY'] = ""
    os.environ['FINGERPRINT'] = ""
    for msg in lr:
        if msg.which() == 'carParams':
            car_fingerprint = msg.carParams.carFingerprint
            if len(msg.carParams.carFw) and (car_fingerprint in FW_VERSIONS):
                params.put("CarParamsCache",
                           msg.carParams.as_builder().to_bytes())
            else:
                os.environ['SKIP_FW_QUERY'] = "1"
                os.environ['FINGERPRINT'] = car_fingerprint

    #TODO: init car, make sure starts engaged when segment is engaged

    fake_daemons = {
        'sensord': [
            multiprocessing.Process(target=replay_service,
                                    args=('sensorEvents', lr)),
        ],
        'pandad': [
            multiprocessing.Process(target=replay_service, args=('can', lr)),
            multiprocessing.Process(target=replay_service,
                                    args=('pandaStates', lr)),
        ],
        #'managerState': [
        #  multiprocessing.Process(target=replay_service, args=('managerState', lr)),
        #],
        'thermald': [
            multiprocessing.Process(target=replay_service,
                                    args=('deviceState', lr)),
        ],
        'camerad': [
            *replay_cameras(lr, frs),
        ],

        # TODO: fix these and run them
        'paramsd': [
            multiprocessing.Process(target=replay_service,
                                    args=('liveParameters', lr)),
        ],
        'locationd': [
            multiprocessing.Process(target=replay_service,
                                    args=('liveLocationKalman', lr)),
        ],
    }

    try:
        # start procs up
        ignore = list(
            fake_daemons.keys()) + ['ui', 'manage_athenad', 'uploader']
        ensure_running(managed_processes.values(),
                       started=True,
                       not_run=ignore)
        for procs in fake_daemons.values():
            for p in procs:
                p.start()

        for _ in tqdm(range(60)):
            # ensure all procs are running
            for d, procs in fake_daemons.items():
                for p in procs:
                    if not p.is_alive():
                        raise Exception(f"{d}'s {p.name} died")
            time.sleep(1)
    finally:
        # kill everything
        for p in managed_processes.values():
            p.stop()
        for procs in fake_daemons.values():
            for p in procs:
                p.terminate()

    r = params.get("CurrentRoute", encoding='utf-8')
    return os.path.join(outdir, r + "--0")
Ejemplo n.º 11
0
def register():
    params = Params()
    params.put("Version", version)
    params.put("TrainingVersion", training_version)
    params.put("GitCommit", get_git_commit())
    params.put("GitBranch", get_git_branch())
    params.put("GitRemote", get_git_remote())

    dongle_id, access_token = params.get("DongleId"), params.get("AccessToken")

    try:
        if dongle_id is None or access_token is None:
            cloudlog.info("getting pilotauth")
            resp = api_get("v1/pilotauth/",
                           method='POST',
                           timeout=15,
                           imei=get_imei(),
                           serial=get_serial())
            dongleauth = json.loads(resp.text)
            dongle_id, access_token = dongleauth["dongle_id"].encode(
                'ascii'), dongleauth["access_token"].encode('ascii')

            params.put("DongleId", dongle_id)
            params.put("AccessToken", access_token)
        return dongle_id, access_token
    except Exception:
        cloudlog.exception("failed to authenticate")
        return None
Ejemplo n.º 12
0
def manager_init():
  params = Params()
  params.manager_start()

  default_params = [
    ("CommunityFeaturesToggle", "0"),
    ("EndToEndToggle", "0"),
    ("CompletedTrainingVersion", "0"),
    ("IsRHD", "0"),
    ("IsMetric", "1"),
    ("RecordFront", "0"),
    ("HasAcceptedTerms", "0"),
    ("HasCompletedSetup", "0"),
    ("IsUploadRawEnabled", "1"),
    ("IsLdwEnabled", "0"),
    ("LastUpdateTime", datetime.datetime.utcnow().isoformat().encode('utf8')),
    ("OpenpilotEnabledToggle", "1"),
    ("VisionRadarToggle", "0"),
    ("IsDriverViewEnabled", "0"),
    ("IsOpenpilotViewEnabled", "0"),
    ("OpkrAutoShutdown", "2"),
    ("OpkrAutoScreenDimming", "0"),
    ("OpkrUIBrightness", "0"),
    ("OpkrUIBrightness", "0"),
    ("OpkrUIVolumeBoost", "0"),
    ("OpkrEnableDriverMonitoring", "1"),
    ("OpkrEnableLogger", "0"),
    ("OpkrEnableGetoffAlert", "1"),
    ("OpkrAutoResume", "1"),
    ("OpkrVariableCruise", "1"),
    ("OpkrLaneChangeSpeed", "45"),
    ("OpkrAutoLaneChangeDelay", "0"),
    ("OpkrSteerAngleCorrection", "0"),
    ("PutPrebuiltOn", "0"),
    ("FingerprintIssuedFix", "0"),
    ("LdwsCarFix", "0"),
    ("LateralControlMethod", "0"),
    ("CruiseStatemodeSelInit", "1"),
    ("InnerLoopGain", "35"),
    ("OuterLoopGain", "20"),
    ("TimeConstant", "14"),
    ("ActuatorEffectiveness", "20"),
    ("Scale", "1750"),
    ("LqrKi", "10"),
    ("DcGain", "30"),
    ("IgnoreZone", "1"),
    ("PidKp", "20"),
    ("PidKi", "40"),
    ("PidKd", "150"),
    ("PidKf", "5"),
    ("CameraOffsetAdj", "60"),
    ("SteerRatioAdj", "150"),
    ("SteerRatioMaxAdj", "180"),
    ("SteerActuatorDelayAdj", "0"),
    ("SteerRateCostAdj", "45"),
    ("SteerLimitTimerAdj", "40"),
    ("TireStiffnessFactorAdj", "85"),
    ("SteerMaxBaseAdj", "300"),
    ("SteerMaxAdj", "384"),
    ("SteerDeltaUpBaseAdj", "3"),
    ("SteerDeltaUpAdj", "3"),
    ("SteerDeltaDownBaseAdj", "7"),
    ("SteerDeltaDownAdj", "7"),
    ("SteerMaxvAdj", "10"),
    ("OpkrBatteryChargingControl", "1"),
    ("OpkrBatteryChargingMin", "70"),
    ("OpkrBatteryChargingMax", "80"),
    ("LeftCurvOffsetAdj", "0"),
    ("RightCurvOffsetAdj", "0"),
    ("DebugUi1", "0"),
    ("DebugUi2", "0"),
    ("OpkrBlindSpotDetect", "1"),
    ("OpkrMaxAngleLimit", "90"),
    ("OpkrSpeedLimitOffset", "0"),
    ("LimitSetSpeedCamera", "0"),
    ("LimitSetSpeedCameraDist", "0"),
    ("OpkrLiveSteerRatio", "1"),
    ("OpkrVariableSteerMax", "1"),
    ("OpkrVariableSteerDelta", "0"),
    ("FingerprintTwoSet", "1"),
    ("OpkrVariableCruiseProfile", "0"),
    ("OpkrLiveTune", "0"),
    ("OpkrDrivingRecord", "0"),
    ("OpkrTurnSteeringDisable", "0"),
    ("CarModel", ""),
    ("OpkrHotspotOnBoot", "0"),
    ("OpkrSSHLegacy", "1"),
    ("ShaneFeedForward", "0"),
    ("CruiseOverMaxSpeed", "0"),
    ("OpkrMapDecelOnly", "0"),
    ("JustDoGearD", "0"),
    ("LanelessMode", "0"),
    ("ComIssueGone", "0"),
    ("MaxSteer", "384"),
    ("MaxRTDelta", "112"),
    ("MaxRateUp", "3"),
    ("MaxRateDown", "7"),
    ("SteerThreshold", "150"),
  ]

  if params.get("RecordFrontLock", encoding='utf-8') == "1":
    params.put("RecordFront", "1")

  # set unset params
  for k, v in default_params:
    if params.get(k) is None:
      params.put(k, v)

  # is this dashcam?
  if os.getenv("PASSIVE") is not None:
    params.put("Passive", str(int(os.getenv("PASSIVE"))))

  if params.get("Passive") is None:
    raise Exception("Passive must be set to continue")

  if EON:
    update_apks()

  os.umask(0)  # Make sure we can create files with 777 permissions

  # Create folders needed for msgq
  try:
    os.mkdir("/dev/shm")
  except FileExistsError:
    pass
  except PermissionError:
    print("WARNING: failed to make /dev/shm")

  # set dongle id
  reg_res = register(show_spinner=True)
  if reg_res:
    dongle_id = reg_res
  else:
    raise Exception("server registration failed")
  os.environ['DONGLE_ID'] = dongle_id  # Needed for swaglog and loggerd

  if not dirty:
    os.environ['CLEAN'] = '1'

  cloudlog.bind_global(dongle_id=dongle_id, version=version, dirty=dirty,
                       device=HARDWARE.get_device_type())
  crash.bind_user(id=dongle_id)
  crash.bind_extra(version=version, dirty=dirty, device=HARDWARE.get_device_type())

  # ensure shared libraries are readable by apks
  if EON:
    os.chmod(BASEDIR, 0o755)
    os.chmod("/dev/shm", 0o777)
    os.chmod(os.path.join(BASEDIR, "cereal"), 0o755)
    os.chmod(os.path.join(BASEDIR, "cereal", "libmessaging_shared.so"), 0o755)
Ejemplo n.º 13
0
def manager_init():

  # update system time from panda
  set_time(cloudlog)

  params = Params()
  params.manager_start()

  default_params = [
    ("CompletedTrainingVersion", "0"),
    ("HasAcceptedTerms", "0"),
    ("LastUpdateTime", datetime.datetime.utcnow().isoformat().encode('utf8')),
    ("OpenpilotEnabledToggle", "1"),
  ]

  if TICI:
    default_params.append(("IsUploadRawEnabled", "1"))

  if params.get_bool("RecordFrontLock"):
    params.put_bool("RecordFront", True)

  # set unset params
  for k, v in default_params:
    if params.get(k) is None:
      params.put(k, v)

  # is this dashcam?
  if os.getenv("PASSIVE") is not None:
    params.put_bool("Passive", bool(int(os.getenv("PASSIVE"))))

  if params.get("Passive") is None:
    raise Exception("Passive must be set to continue")

  os.umask(0)  # Make sure we can create files with 777 permissions

  # Create folders needed for msgq
  try:
    os.mkdir("/dev/shm")
  except FileExistsError:
    pass
  except PermissionError:
    print("WARNING: failed to make /dev/shm")

  # set version params
  params.put("Version", version)
  params.put("TermsVersion", terms_version)
  params.put("TrainingVersion", training_version)
  params.put("GitCommit", get_git_commit(default=""))
  params.put("GitBranch", get_git_branch(default=""))
  params.put("GitRemote", get_git_remote(default=""))

  # set dongle id
  reg_res = register(show_spinner=True)
  if reg_res:
    dongle_id = reg_res
  else:
    serial = params.get("HardwareSerial")
    raise Exception(f"Registration failed for device {serial}")
  os.environ['DONGLE_ID'] = dongle_id  # Needed for swaglog

  if not dirty:
    os.environ['CLEAN'] = '1'

  cloudlog.bind_global(dongle_id=dongle_id, version=version, dirty=dirty,
                       device=HARDWARE.get_device_type())

  if comma_remote and not (os.getenv("NOLOG") or os.getenv("NOCRASH") or PC):
    crash.init()
  crash.bind_user(id=dongle_id)
  crash.bind_extra(dirty=dirty, origin=origin, branch=branch, commit=commit,
                   device=HARDWARE.get_device_type())
Ejemplo n.º 14
0
class LatControlPID(object):
  def __init__(self, CP):
    kegman_conf(CP)
    self.frame = 0
    self.pid = PIController((CP.lateralTuning.pid.kpBP, CP.lateralTuning.pid.kpV),
                            (CP.lateralTuning.pid.kiBP, CP.lateralTuning.pid.kiV),
                            k_f=CP.lateralTuning.pid.kf, pos_limit=1.0)
    self.angle_steers_des = 0.
    self.total_poly_projection = max(0.0, CP.lateralTuning.pid.polyReactTime + CP.lateralTuning.pid.polyDampTime)
    self.poly_smoothing = max(1.0, CP.lateralTuning.pid.polyDampTime * 100.)
    self.poly_scale = CP.lateralTuning.pid.polyScale
    self.poly_factor = CP.lateralTuning.pid.polyFactor
    self.poly_scale = CP.lateralTuning.pid.polyScale
    self.path_error = 0.0
    self.cur_poly_scale = 0.0
    self.p_poly = [0., 0., 0., 0.]
    self.s_poly = [0., 0., 0., 0.]
    self.p_prob = 0.
    self.damp_angle_steers = 0.
    self.damp_time = 0.1
    self.react_mpc = 0.0
    self.damp_mpc = 0.25
    self.angle_ff_ratio = 0.0
    self.gernbySteer = True
    self.standard_ff_ratio = 0.0
    self.angle_ff_gain = 1.0
    self.rate_ff_gain = CP.lateralTuning.pid.rateFFGain
    self.angle_ff_bp = [[0.5, 5.0],[0.0, 1.0]]
    self.steer_p_scale = CP.lateralTuning.pid.steerPscale
    self.calculate_rate = True
    self.prev_angle_steers = 0.0
    self.rough_steers_rate = 0.0
    self.steer_counter = 1
    self.lane_change_adjustment = 0.0
    self.lane_changing = 0.0
    self.starting_angle = 0.0
    self.half_lane_width = 0.0
    self.steer_counter_prev = 1
    self.params = Params()
    self.prev_override = False
    self.driver_assist_offset = 0.0
    self.driver_assist_hold = False
    self.angle_bias = 0.

    try:
      lateral_params = self.params.get("LateralParams")
      lateral_params = json.loads(lateral_params)
      self.angle_ff_gain = max(1.0, float(lateral_params['angle_ff_gain']))
    except:
      self.angle_ff_gain = 1.0

  def live_tune(self, CP):
    self.frame += 1
    if self.frame % 3600 == 0:
      self.params.put("LateralParams", json.dumps({'angle_ff_gain': self.angle_ff_gain}))
    if self.frame % 300 == 0:
      # live tuning through /data/openpilot/tune.py overrides interface.py settings
      kegman = kegman_conf()
      self.pid._k_i = ([0.], [float(kegman.conf['Ki'])])
      self.pid._k_p = ([0.], [float(kegman.conf['Kp'])])
      self.pid.k_f = (float(kegman.conf['Kf']))
      self.damp_time = (float(kegman.conf['dampTime']))
      self.react_mpc = (float(kegman.conf['reactMPC']))
      self.damp_mpc = (float(kegman.conf['dampMPC']))
      self.total_poly_projection = max(0.0, float(kegman.conf['polyReact']) + float(kegman.conf['polyDamp']))
      self.poly_smoothing = max(1.0, float(kegman.conf['polyDamp']) * 100.)
      self.poly_factor = float(kegman.conf['polyFactor'])

  def get_projected_path_error(self, v_ego, angle_feedforward, angle_steers, live_params, path_plan, VM):
    curv_factor = interp(abs(angle_feedforward), [1.0, 5.0], [0.0, 1.0])
    self.p_poly[3] += (path_plan.pPoly[3] - self.p_poly[3]) / self.poly_smoothing
    self.p_poly[2] += curv_factor * (path_plan.pPoly[2] - self.p_poly[2]) / (self.poly_smoothing * 1.5)
    self.p_poly[1] += curv_factor * (path_plan.pPoly[1] - self.p_poly[1]) / (self.poly_smoothing * 3.0)
    self.p_poly[0] += curv_factor * (path_plan.pPoly[0] - self.p_poly[0]) / (self.poly_smoothing * 4.5)
    self.p_prob += (path_plan.pProb - self. p_prob) / (self.poly_smoothing)
    self.s_poly[1] = float(np.tan(VM.calc_curvature(np.radians(angle_steers - live_params.angleOffset), float(v_ego))))
    x = int(float(v_ego) * self.total_poly_projection * interp(abs(angle_feedforward), [0., 5.], [0.25, 1.0]))
    self.p_pts = np.polyval(self.p_poly, np.arange(0, x))
    self.s_pts = np.polyval(self.s_poly, np.arange(0, x))
    return self.p_prob * (np.sum(self.p_pts) - np.sum(self.s_pts))

  def reset(self):
    self.pid.reset()

  def adjust_angle_gain(self):
    if (self.pid.f > 0) == (self.pid.i > 0) and abs(self.pid.i) >= abs(self.previous_integral):
      if not abs(self.pid.f + self.pid.i + self.pid.p) > 1: self.angle_ff_gain *= 1.0001
    elif self.angle_ff_gain > 1.0:
      self.angle_ff_gain *= 0.9999
    self.previous_integral = self.pid.i

  def update_lane_state(self, angle_steers, driver_opposing_lane, blinkers_on, path_plan):
    if self.lane_changing > 0.0:
      if self.lane_changing > 2.75 or (not blinkers_on and self.lane_changing < 1.0 and abs(path_plan.cPoly[3]) < 0.5 and min(abs(self.starting_angle - angle_steers), abs(self.angle_steers_des - angle_steers)) < 1.5):
        self.lane_changing = 0.0
      elif 2.25 <= self.lane_changing < 2.5 and abs(path_plan.lPoly[3] + path_plan.rPoly[3]) < abs(path_plan.cPoly[3]):
        self.lane_changing = 2.5
      elif 2.0 <= self.lane_changing < 2.25 and (path_plan.lPoly[3] + path_plan.rPoly[3]) * path_plan.cPoly[3] < 0:
        self.lane_changing = 2.25
      elif self.lane_changing < 2.0 and self.half_lane_width < 1.05 * abs(path_plan.lPoly[3] + path_plan.rPoly[3]):
        self.lane_changing = 2.0
      else:
        self.lane_changing = max(self.lane_changing + 0.01, abs(path_plan.lPoly[3] + path_plan.rPoly[3]))
      if blinkers_on:
        self.lane_change_adjustment = 0.0
      else:
        self.lane_change_adjustment = interp(self.lane_changing, [0.0, 1.0, 2.0, 2.25, 2.5, 2.75], [1.0, 0.0, 0.0, 0.1, .2, 1.0])
      #print("%0.2f lane_changing  %0.2f adjustment  %0.2f p_poly   %0.2f avg_poly" % (self.lane_changing, self.lane_change_adjustment, path_plan.cPoly[3], path_plan.lPoly[3] + path_plan.rPoly[3]))
    elif driver_opposing_lane and (blinkers_on or abs(path_plan.cPoly[3]) > 0.5 or min(abs(self.starting_angle - angle_steers), abs(self.angle_steers_des - angle_steers)) > 1.5):
      self.lane_changing = 0.01
    else:
      self.half_lane_width = (path_plan.lPoly[3] - path_plan.rPoly[3]) / 2.
      self.starting_angle = angle_steers
      self.lane_change_adjustment = 1.0

  def update(self, active, v_ego, angle_steers, angle_steers_rate, steer_override, blinkers_on, CP, VM, path_plan, live_params):

    if angle_steers_rate == 0.0 and self.calculate_rate:
      if angle_steers != self.prev_angle_steers:
        self.steer_counter_prev = self.steer_counter
        self.rough_steers_rate = (self.rough_steers_rate + 100.0 * (angle_steers - self.prev_angle_steers) / self.steer_counter_prev) / 2.0
        self.steer_counter = 0.0
      elif self.steer_counter >= self.steer_counter_prev:
        self.rough_steers_rate = (self.steer_counter * self.rough_steers_rate) / (self.steer_counter + 1.0)
      self.steer_counter += 1.0
      angle_steers_rate = self.rough_steers_rate
    else:
      # If non-zero angle_rate is provided, stop calculating angle rate
      self.calculate_rate = False

    pid_log = log.ControlsState.LateralPIDState.new_message()
    pid_log.steerAngle = float(angle_steers)
    pid_log.steerRate = float(angle_steers_rate)

    max_bias_change = 0.0002 / (abs(self.angle_bias) + 0.0001)
    self.angle_bias = float(clip(live_params.angleOffset - live_params.angleOffsetAverage, self.angle_bias - max_bias_change, self.angle_bias + max_bias_change))
    self.live_tune(CP)

    if v_ego < 0.3 or not active:
      output_steer = 0.0
      self.lane_changing = 0.0
      self.previous_integral = 0.0
      self.damp_angle_steers= 0.0
      self.damp_rate_steers_des = 0.0
      self.damp_angle_steers_des = 0.0
      pid_log.active = False
      self.pid.reset()
    else:
      self.angle_steers_des = path_plan.angleSteers
      if not self.driver_assist_hold:
        self.damp_angle_steers_des += (interp(sec_since_boot() + self.damp_mpc + self.react_mpc, path_plan.mpcTimes, path_plan.mpcAngles) - self.damp_angle_steers_des) / max(1.0, self.damp_mpc * 100.)
        self.damp_rate_steers_des += (interp(sec_since_boot() + self.damp_mpc + self.react_mpc, path_plan.mpcTimes, path_plan.mpcRates) - self.damp_rate_steers_des) / max(1.0, self.damp_mpc * 100.)
        self.damp_angle_steers += (angle_steers - self.angle_bias + self.damp_time * angle_steers_rate - self.damp_angle_steers) / max(1.0, self.damp_time * 100.)
      else:
        self.damp_angle_steers = angle_steers
        self.damp_angle_steers_des = self.damp_angle_steers + self.driver_assist_offset

      if steer_override and abs(self.damp_angle_steers) > abs(self.damp_angle_steers_des) and self.pid.saturated:
        self.damp_angle_steers_des = self.damp_angle_steers

      steers_max = get_steer_max(CP, v_ego)
      self.pid.pos_limit = steers_max
      self.pid.neg_limit = -steers_max
      angle_feedforward = float(self.damp_angle_steers_des - path_plan.angleOffset)
      self.angle_ff_ratio = interp(abs(angle_feedforward), self.angle_ff_bp[0], self.angle_ff_bp[1])
      rate_feedforward = (1.0 - self.angle_ff_ratio) * self.rate_ff_gain * self.damp_rate_steers_des
      steer_feedforward = float(v_ego)**2 * (rate_feedforward + angle_feedforward * self.angle_ff_ratio * self.angle_ff_gain)

      if len(self.poly_scale) > 0:
        if abs(self.damp_angle_steers_des) > abs(self.damp_angle_steers):
          self.cur_poly_scale += 0.05 * (interp(abs(self.damp_rate_steers_des), self.poly_scale[0], self.poly_scale[1]) - self.cur_poly_scale)
        else:
          self.cur_poly_scale += 0.05 * (interp(abs(self.damp_rate_steers_des), self.poly_scale[0], self.poly_scale[2]) - self.cur_poly_scale)
      else:
        self.cur_poly_scale = 1.0

      if len(self.steer_p_scale) > 0:
        if abs(self.damp_angle_steers_des) > abs(self.damp_angle_steers):
          p_scale = interp(abs(angle_feedforward), self.steer_p_scale[0], self.steer_p_scale[1])
        else:
          p_scale = interp(abs(angle_feedforward), self.steer_p_scale[0], self.steer_p_scale[2])
      else:
        p_scale = 1.0

      if CP.carName == "honda" and steer_override and not self.prev_override and not self.driver_assist_hold and self.pid.saturated and abs(angle_steers) < abs(self.damp_angle_steers_des) and not blinkers_on:
        self.driver_assist_hold = True
        self.driver_assist_offset = self.damp_angle_steers_des - self.damp_angle_steers
      else:
        self.driver_assist_hold = steer_override and self.driver_assist_hold

      self.path_error = float(v_ego) * float(self.get_projected_path_error(v_ego, angle_feedforward, angle_steers, live_params, path_plan, VM)) * self.poly_factor * self.cur_poly_scale * self.angle_ff_gain

      if self.driver_assist_hold and not steer_override and abs(angle_steers) > abs(self.damp_angle_steers_des):
        #self.angle_bias = 0.0
        driver_opposing_i = False
      elif (steer_override and self.pid.saturated) or self.driver_assist_hold or self.lane_changing > 0.0 or blinkers_on:
        #self.angle_bias = 0.0
        self.path_error = 0.0

      if self.gernbySteer and not steer_override and v_ego > 10.0:
        if abs(angle_steers) > (self.angle_ff_bp[0][1] / 2.0):
          self.adjust_angle_gain()
        else:
          self.previous_integral = self.pid.i

      driver_opposing_i = steer_override and self.pid.i * self.pid.p > 0 and not self.pid.saturated and not self.driver_assist_hold

      deadzone = 0.0
      output_steer = self.pid.update(self.damp_angle_steers_des, self.damp_angle_steers, check_saturation=(v_ego > 10), override=driver_opposing_i,
                                     add_error=float(self.path_error), feedforward=steer_feedforward, speed=v_ego, deadzone=deadzone, p_scale=p_scale)

      driver_opposing_op = steer_override and (angle_steers - self.prev_angle_steers) * output_steer < 0
      self.update_lane_state(angle_steers, driver_opposing_op, blinkers_on, path_plan)
      output_steer *= self.lane_change_adjustment

      pid_log.active = True
      pid_log.p = float(self.pid.p)
      pid_log.i = float(self.pid.i)
      pid_log.f = float(self.pid.f)
      pid_log.p2 = float(self.pid.p2)
      pid_log.output = float(output_steer)
      pid_log.saturated = bool(self.pid.saturated)
      pid_log.angleFFRatio = self.angle_ff_ratio
      pid_log.angleBias = self.angle_bias

    self.prev_angle_steers = angle_steers
    self.prev_override = steer_override
    self.sat_flag = self.pid.saturated
    return output_steer, float(self.angle_steers_des), pid_log
Ejemplo n.º 15
0
def register():
    params = Params()
    params.put("Version", version)
    params.put("TermsVersion", terms_version)
    params.put("TrainingVersion", training_version)

    params.put("GitCommit", get_git_commit(default=""))
    params.put("GitBranch", get_git_branch(default=""))
    params.put("GitRemote", get_git_remote(default=""))
    params.put("SubscriberInfo", get_subscriber_info())

    # create a key for auth
    # your private key is kept on your device persist partition and never sent to our servers
    # do not erase your persist partition
    if not os.path.isfile(PERSIST + "/comma/id_rsa.pub"):
        cloudlog.warning("generating your personal RSA key")
        mkdirs_exists_ok(PERSIST + "/comma")
        assert os.system("openssl genrsa -out " + PERSIST +
                         "/comma/id_rsa.tmp 2048") == 0
        assert os.system("openssl rsa -in " + PERSIST +
                         "/comma/id_rsa.tmp -pubout -out " + PERSIST +
                         "/comma/id_rsa.tmp.pub") == 0
        os.rename(PERSIST + "/comma/id_rsa.tmp", PERSIST + "/comma/id_rsa")
        os.rename(PERSIST + "/comma/id_rsa.tmp.pub",
                  PERSIST + "/comma/id_rsa.pub")

    # make key readable by app users (ai.comma.plus.offroad)
    os.chmod(PERSIST + '/comma/', 0o755)
    os.chmod(PERSIST + '/comma/id_rsa', 0o744)

    dongle_id, access_token = params.get(
        "DongleId", encoding='utf8'), params.get("AccessToken",
                                                 encoding='utf8')
    public_key = open(PERSIST + "/comma/id_rsa.pub").read()

    # create registration token
    # in the future, this key will make JWTs directly
    private_key = open(PERSIST + "/comma/id_rsa").read()

    # late import
    import jwt
    register_token = jwt.encode(
        {
            'register': True,
            'exp': datetime.utcnow() + timedelta(hours=1)
        },
        private_key,
        algorithm='RS256')

    try:
        cloudlog.info("getting pilotauth")
        resp = api_get("v2/pilotauth/",
                       method='POST',
                       timeout=15,
                       imei=get_imei(0),
                       imei2=get_imei(1),
                       serial=get_serial(),
                       public_key=public_key,
                       register_token=register_token)
        dongleauth = json.loads(resp.text)
        dongle_id, access_token = dongleauth["dongle_id"], dongleauth[
            "access_token"]

        params.put("DongleId", dongle_id)
        params.put("AccessToken", access_token)
        return dongle_id, access_token
    except Exception:
        cloudlog.exception("failed to authenticate")
        if dongle_id is not None and access_token is not None:
            return dongle_id, access_token
        else:
            return None
Ejemplo n.º 16
0
def python_replay_process(cfg, lr):
    sub_sockets = [s for _, sub in cfg.pub_sub.items() for s in sub]
    pub_sockets = [s for s in cfg.pub_sub.keys() if s != 'can']

    fsm = FakeSubMaster(pub_sockets)
    fpm = FakePubMaster(sub_sockets)
    args = (fsm, fpm)
    if 'can' in list(cfg.pub_sub.keys()):
        can_sock = FakeSocket()
        args = (fsm, fpm, can_sock)

    all_msgs = sorted(lr, key=lambda msg: msg.logMonoTime)
    pub_msgs = [
        msg for msg in all_msgs if msg.which() in list(cfg.pub_sub.keys())
    ]

    params = Params()
    params.clear_all()
    params.manager_start()
    params.put("OpenpilotEnabledToggle", "1")
    params.put("Passive", "0")
    params.put("CommunityFeaturesToggle", "1")

    os.environ['NO_RADAR_SLEEP'] = "1"
    os.environ['SKIP_FW_QUERY'] = "1"
    os.environ['FINGERPRINT'] = ""
    for msg in lr:
        if msg.which() == 'carParams':
            os.environ['FINGERPRINT'] = msg.carParams.carFingerprint

    manager.prepare_managed_process(cfg.proc_name)
    mod = importlib.import_module(manager.managed_processes[cfg.proc_name])
    thread = threading.Thread(target=mod.main, args=args)
    thread.daemon = True
    thread.start()

    if cfg.init_callback is not None:
        if 'can' not in list(cfg.pub_sub.keys()):
            can_sock = None
        cfg.init_callback(all_msgs, fsm, can_sock)

    CP = car.CarParams.from_bytes(params.get("CarParams", block=True))

    # wait for started process to be ready
    if 'can' in list(cfg.pub_sub.keys()):
        can_sock.wait_for_recv()
    else:
        fsm.wait_for_update()

    log_msgs, msg_queue = [], []
    for msg in tqdm(pub_msgs):
        if cfg.should_recv_callback is not None:
            recv_socks, should_recv = cfg.should_recv_callback(
                msg, CP, cfg, fsm)
        else:
            recv_socks = [
                s for s in cfg.pub_sub[msg.which()]
                if (fsm.frame + 1) % int(service_list[msg.which()].frequency /
                                         service_list[s].frequency) == 0
            ]
            should_recv = bool(len(recv_socks))

        if msg.which() == 'can':
            can_sock.send(msg.as_builder().to_bytes())
        else:
            msg_queue.append(msg.as_builder())

        if should_recv:
            fsm.update_msgs(0, msg_queue)
            msg_queue = []

            recv_cnt = len(recv_socks)
            while recv_cnt > 0:
                m = fpm.wait_for_msg()
                log_msgs.append(m)

                recv_cnt -= m.which() in recv_socks
    return log_msgs
Ejemplo n.º 17
0
class Calibrator(object):
    def __init__(self, param_put=False):
        self.param_put = param_put
        self.vp = copy.copy(VP_INIT)
        self.vps = []
        self.cal_status = Calibration.UNCALIBRATED
        self.write_counter = 0
        self.just_calibrated = False
        self.params = Params()
        calibration_params = self.params.get("CalibrationParams")
        if calibration_params:
            try:
                calibration_params = json.loads(calibration_params)
                self.vp = np.array(calibration_params["vanishing_point"])
                self.vps = np.tile(
                    self.vp, (calibration_params['valid_points'], 1)).tolist()
                self.update_status()
            except Exception:
                cloudlog.exception(
                    "CalibrationParams file found but error encountered")

    def update_status(self):
        start_status = self.cal_status
        if len(self.vps) < INPUTS_NEEDED:
            self.cal_status = Calibration.UNCALIBRATED
        else:
            self.cal_status = Calibration.CALIBRATED if is_calibration_valid(
                self.vp) else Calibration.INVALID
        end_status = self.cal_status

        self.just_calibrated = False
        if start_status == Calibration.UNCALIBRATED and end_status == Calibration.CALIBRATED:
            self.just_calibrated = True

    def handle_cam_odom(self, log):
        trans, rot = log.cameraOdometry.trans, log.cameraOdometry.rot
        if np.linalg.norm(trans) > MIN_SPEED_FILTER and abs(
                rot[2]) < MAX_YAW_RATE_FILTER:
            new_vp = eon_intrinsics.dot(
                view_frame_from_device_frame.dot(trans))
            new_vp = new_vp[:2] / new_vp[2]
            self.vps.append(new_vp)
            self.vps = self.vps[-INPUTS_WANTED:]
            self.vp = np.mean(self.vps, axis=0)
            self.update_status()
            self.write_counter += 1
            if self.param_put and (self.write_counter % WRITE_CYCLES == 0
                                   or self.just_calibrated):
                cal_params = {
                    "vanishing_point": list(self.vp),
                    "valid_points": len(self.vps)
                }
                self.params.put("CalibrationParams", json.dumps(cal_params))
            return new_vp

    def send_data(self, livecalibration):
        calib = get_calib_from_vp(self.vp)
        extrinsic_matrix = get_view_frame_from_road_frame(
            0, calib[1], calib[2], model_height)
        ke = eon_intrinsics.dot(extrinsic_matrix)
        warp_matrix = get_camera_frame_from_model_frame(ke)
        warp_matrix_big = get_camera_frame_from_bigmodel_frame(ke)

        cal_send = messaging.new_message()
        cal_send.init('liveCalibration')
        cal_send.liveCalibration.calStatus = self.cal_status
        cal_send.liveCalibration.calPerc = min(
            len(self.vps) * 100 / INPUTS_NEEDED, 100)
        cal_send.liveCalibration.warpMatrix2 = map(float,
                                                   warp_matrix.flatten())
        cal_send.liveCalibration.warpMatrixBig = map(float,
                                                     warp_matrix_big.flatten())
        cal_send.liveCalibration.extrinsicMatrix = map(
            float, extrinsic_matrix.flatten())

        livecalibration.send(cal_send.to_bytes())
Ejemplo n.º 18
0
def main():
  update_failed_count = 0
  overlay_init_done = False
  wait_helper = WaitTimeHelper()
  params = Params()
  carSettings = CarSettings()
  doAutoUpdate = carSettings.doAutoUpdate

  if not os.geteuid() == 0:
    raise RuntimeError("updated must be launched as root!")

  # Set low io priority
  p = psutil.Process()
  if psutil.LINUX:
    p.ionice(psutil.IOPRIO_CLASS_BE, value=7)

  ov_lock_fd = open('/tmp/safe_staging_overlay.lock', 'w')
  try:
    fcntl.flock(ov_lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
  except IOError:
    raise RuntimeError("couldn't get overlay lock; is another updated running?")

  while True:
    update_failed_count += 1
    time_wrong = datetime.datetime.now().year < 2019
    ping_failed = subprocess.call(["ping", "-W", "4", "-c", "1", "8.8.8.8"])
    if doAutoUpdate:
      # Wait until we have a valid datetime to initialize the overlay
      if not (ping_failed or time_wrong):
        try:
          # If the git directory has modifcations after we created the overlay
          # we need to recreate the overlay
          if overlay_init_done:
            overlay_init_fn = os.path.join(BASEDIR, ".overlay_init")
            git_dir_path = os.path.join(BASEDIR, ".git")
            new_files = run(["find", git_dir_path, "-newer", overlay_init_fn])

            if len(new_files.splitlines()):
              cloudlog.info(".git directory changed, recreating overlay")
              overlay_init_done = False

          if not overlay_init_done:
            init_ovfs()
            overlay_init_done = True

          if params.get("IsOffroad") == b"1":
            attempt_update()
            update_failed_count = 0
          else:
            cloudlog.info("not running updater, openpilot running")

        except subprocess.CalledProcessError as e:
          cloudlog.event(
            "update process failed",
            cmd=e.cmd,
            output=e.output,
            returncode=e.returncode
          )
          overlay_init_done = False
        except Exception:
          cloudlog.exception("uncaught updated exception, shouldn't happen")

      params.put("UpdateFailedCount", str(update_failed_count))
    wait_between_updates(wait_helper.ready_event)
    if wait_helper.shutdown:
      break

  # We've been signaled to shut down
  dismount_ovfs()
Ejemplo n.º 19
0
            print("frame: ", "engaged:", is_openpilot_engaged, "; throttle: ",
                  round(vc.throttle, 3), "; steer(c/deg): ",
                  round(vc.steer, 3), round(steer_out, 3), "; brake: ",
                  round(vc.brake, 3))

        rk.keep_time()


if __name__ == "__main__":

    # make sure params are in a good state
    params = Params()
    params.clear_all()
    set_params_enabled()
    params.delete("Offroad_ConnectivityNeeded")
    params.put("CalibrationParams",
               '{"calib_radians": [0,0,0], "valid_blocks": 20}')

    from multiprocessing import Process, Queue
    q = Queue()
    p = Process(target=go, args=(q, ))
    p.daemon = True
    p.start()

    if args.joystick:
        # start input poll for joystick
        from lib.manual_ctrl import wheel_poll_thread
        wheel_poll_thread(q)
    else:
        # start input poll for keyboard
        from lib.keyboard_ctrl import keyboard_poll_thread
        keyboard_poll_thread(q)
Ejemplo n.º 20
0
def main():
    os.environ['PARAMS_PATH'] = PARAMS

    if ANDROID:
        # the flippening!
        os.system(
            'LD_LIBRARY_PATH="" content insert --uri content://settings/system --bind name:s:user_rotation --bind value:i:1'
        )

        # disable bluetooth
        os.system('service call bluetooth_manager 8')

    params = Params()
    params.manager_start()

    default_params = [
        ("CommunityFeaturesToggle", "0"),
        ("CompletedTrainingVersion", "0"),
        ("IsRHD", "0"),
        ("IsMetric", "0"),
        ("RecordFront", "0"),
        ("HasAcceptedTerms", "0"),
        ("HasCompletedSetup", "0"),
        ("IsUploadRawEnabled", "1"),
        ("IsLdwEnabled", "1"),
        ("IsGeofenceEnabled", "-1"),
        ("SpeedLimitOffset", "0"),
        ("LongitudinalControl", "0"),
        ("LimitSetSpeed", "0"),
        ("LimitSetSpeedNeural", "0"),
        ("LastUpdateTime",
         datetime.datetime.utcnow().isoformat().encode('utf8')),
        ("OpenpilotEnabledToggle", "1"),
        ("LaneChangeEnabled", "1"),
        ("IsDriverViewEnabled", "0"),
    ]

    # set unset params
    for k, v in default_params:
        if params.get(k) is None:
            params.put(k, v)

    # is this chffrplus?
    if os.getenv("PASSIVE") is not None:
        params.put("Passive", str(int(os.getenv("PASSIVE"))))

    if params.get("Passive") is None:
        raise Exception("Passive must be set to continue")

    init_params_vals(params, put_nonblocking)
    update_params_vals(params)

    if ANDROID:
        update_apks()
    manager_init(params.get('dp_reg') == b'1')
    manager_prepare(spinner)
    spinner.close()

    if os.getenv("PREPAREONLY") is not None:
        return

    # dp
    del managed_processes['tombstoned']
    if params.get("dp_logger") == b'0':
        del managed_processes['loggerd']
        del managed_processes['logmessaged']
        del managed_processes['proclogd']
        del managed_processes['logcatd']
        del managed_processes['deleter']
    if params.get("dp_uploader") == b'0' or \
        params.get("dp_atl") == b'1' or \
        params.get("dp_steering_monitor") == b'0':
        del managed_processes['uploader']
    if params.get("dp_updated") == b'0':
        del managed_processes['updated']

    # SystemExit on sigterm
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit(1))

    try:
        manager_thread()
    except Exception:
        traceback.print_exc()
        crash.capture_exception()
    finally:
        cleanup_all_processes(None, None)

    if params.get("DoUninstall", encoding='utf8') == "1":
        uninstall()
Ejemplo n.º 21
0
            if car_model not in non_tested_cars:
                print("TEST FAILED: Missing route for car '%s'" % car_model)
                sys.exit(1)

    print("Preparing processes")
    for p in tested_procs:
        manager.prepare_managed_process(p)

    results = {}
    for route, checks in routes.items():
        get_route_log(route)

        params = Params()
        params.clear_all()
        params.manager_start()
        params.put("OpenpilotEnabledToggle", "1")
        params.put("CommunityFeaturesToggle", "1")
        params.put("Passive", "1" if route in passive_routes else "0")

        os.environ['SKIP_FW_QUERY'] = "1"
        if checks.get('fingerprintSource', None) == 'fixed':
            os.environ['FINGERPRINT'] = checks['carFingerprint']
        else:
            os.environ['FINGERPRINT'] = ""

        print("testing ", route, " ", checks['carFingerprint'])
        print("Starting processes")
        for p in tested_procs:
            manager.start_managed_process(p)

        # Start unlogger
Ejemplo n.º 22
0
def main():
    # the flippening!
    os.system(
        'LD_LIBRARY_PATH="" content insert --uri content://settings/system --bind name:s:user_rotation --bind value:i:1'
    )

    # disable bluetooth
    os.system('service call bluetooth_manager 8')

    if os.getenv("NOLOG") is not None:
        del managed_processes['loggerd']
        del managed_processes['tombstoned']
    if os.getenv("NOUPLOAD") is not None:
        del managed_processes['uploader']
    if os.getenv("NOVISION") is not None:
        del managed_processes['visiond']
    if os.getenv("LEAN") is not None:
        del managed_processes['uploader']
        del managed_processes['loggerd']
        del managed_processes['logmessaged']
        del managed_processes['logcatd']
        del managed_processes['tombstoned']
        del managed_processes['proclogd']
    if os.getenv("NOCONTROL") is not None:
        del managed_processes['controlsd']
        del managed_processes['plannerd']
        del managed_processes['radard']

    # support additional internal only extensions
    try:
        import selfdrive.manager_extensions
        selfdrive.manager_extensions.register(register_managed_process)  # pylint: disable=no-member
    except ImportError:
        pass

    params = Params()
    params.manager_start()

    # set unset params
    if params.get("IsMetric") is None:
        params.put("IsMetric", "0")
    if params.get("RecordFront") is None:
        params.put("RecordFront", "0")
    if params.get("HasAcceptedTerms") is None:
        params.put("HasAcceptedTerms", "0")
    if params.get("IsUploadRawEnabled") is None:
        params.put("IsUploadRawEnabled", "1")
    if params.get("IsUploadVideoOverCellularEnabled") is None:
        params.put("IsUploadVideoOverCellularEnabled", "1")
    if params.get("IsGeofenceEnabled") is None:
        params.put("IsGeofenceEnabled", "-1")
    if params.get("SpeedLimitOffset") is None:
        params.put("SpeedLimitOffset", "0")
    if params.get("LongitudinalControl") is None:
        params.put("LongitudinalControl", "0")
    if params.get("LimitSetSpeed") is None:
        params.put("LimitSetSpeed", "0")
    if params.get("LimitSetSpeedNeural") is None:
        params.put("LimitSetSpeedNeural", "0")

    # is this chffrplus?
    if os.getenv("PASSIVE") is not None:
        params.put("Passive", str(int(os.getenv("PASSIVE"))))

    if params.get("Passive") is None:
        raise Exception("Passive must be set to continue")

    # put something on screen while we set things up
    if os.getenv("PREPAREONLY") is not None:
        spinner_proc = None
    else:
        spinner_text = "chffrplus" if params.get(
            "Passive") == "1" else "openpilot"
        spinner_proc = subprocess.Popen(
            ["./spinner", "loading %s" % spinner_text],
            cwd=os.path.join(BASEDIR, "selfdrive", "ui", "spinner"),
            close_fds=True)
    try:
        manager_update()
        manager_init()
        manager_prepare()
    finally:
        if spinner_proc:
            spinner_proc.terminate()

    if os.getenv("PREPAREONLY") is not None:
        return

    # SystemExit on sigterm
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit(1))

    try:
        manager_thread()
    except Exception:
        traceback.print_exc()
        crash.capture_exception()
    finally:
        cleanup_all_processes(None, None)

    if params.get("DoUninstall") == "1":
        uninstall()
Ejemplo n.º 23
0
def register(spinner=None):
    params = Params()
    params.put("Version", "kegman-ultimate-0.001")
    params.put("TermsVersion", terms_version)
    params.put("TrainingVersion", training_version)

    params.put("GitCommit", get_git_commit(default=""))
    params.put("GitBranch", get_git_branch(default=""))
    params.put("GitRemote", get_git_remote(default=""))
    params.put("SubscriberInfo", HARDWARE.get_subscriber_info())

    IMEI = params.get("IMEI", encoding='utf8')
    HardwareSerial = params.get("HardwareSerial", encoding='utf8')

    needs_registration = (None in [IMEI, HardwareSerial])

    # create a key for auth
    # your private key is kept on your device persist partition and never sent to our servers
    # do not erase your persist partition
    if not os.path.isfile(PERSIST + "/comma/id_rsa.pub"):
        needs_registration = True
        cloudlog.warning("generating your personal RSA key")
        mkdirs_exists_ok(PERSIST + "/comma")
        assert os.system("openssl genrsa -out " + PERSIST +
                         "/comma/id_rsa.tmp 2048") == 0
        assert os.system("openssl rsa -in " + PERSIST +
                         "/comma/id_rsa.tmp -pubout -out " + PERSIST +
                         "/comma/id_rsa.tmp.pub") == 0
        os.rename(PERSIST + "/comma/id_rsa.tmp", PERSIST + "/comma/id_rsa")
        os.rename(PERSIST + "/comma/id_rsa.tmp.pub",
                  PERSIST + "/comma/id_rsa.pub")

    # make key readable by app users (ai.comma.plus.offroad)
    os.chmod(PERSIST + '/comma/', 0o755)
    os.chmod(PERSIST + '/comma/id_rsa', 0o744)

    dongle_id = params.get("DongleId", encoding='utf8')
    needs_registration = needs_registration or dongle_id is None

    if needs_registration:
        if spinner is not None:
            spinner.update("registering device")

        # Create registration token, in the future, this key will make JWTs directly
        private_key = open(PERSIST + "/comma/id_rsa").read()
        public_key = open(PERSIST + "/comma/id_rsa.pub").read()
        register_token = jwt.encode(
            {
                'register': True,
                'exp': datetime.utcnow() + timedelta(hours=1)
            },
            private_key,
            algorithm='RS256')

        # Block until we get the imei
        imei1, imei2 = None, None
        while imei1 is None and imei2 is None:
            try:
                imei1, imei2 = HARDWARE.get_imei(0), HARDWARE.get_imei(1)
            except Exception:
                cloudlog.exception("Error getting imei, trying again...")
                time.sleep(1)

        serial = HARDWARE.get_serial()
        params.put("IMEI", imei1)
        params.put("HardwareSerial", serial)

        while True:
            try:
                cloudlog.info("getting pilotauth")
                resp = api_get("v2/pilotauth/",
                               method='POST',
                               timeout=15,
                               imei=imei1,
                               imei2=imei2,
                               serial=serial,
                               public_key=public_key,
                               register_token=register_token)
                dongleauth = json.loads(resp.text)
                dongle_id = dongleauth["dongle_id"]
                params.put("DongleId", dongle_id)
                break
            except Exception:
                cloudlog.exception("failed to authenticate")
                time.sleep(1)

    return dongle_id
Ejemplo n.º 24
0
def set_params(new_version: bool, failed_count: int,
               exception: Optional[str]) -> None:
    params = Params()

    params.put("UpdateFailedCount", str(failed_count))

    last_update = datetime.datetime.utcnow()
    if failed_count == 0:
        t = last_update.isoformat()
        params.put("LastUpdateTime", t.encode('utf8'))
    else:
        try:
            t = params.get("LastUpdateTime", encoding='utf8')
            last_update = datetime.datetime.fromisoformat(t)
        except (TypeError, ValueError):
            pass

    if exception is None:
        params.delete("LastUpdateException")
    else:
        params.put("LastUpdateException", exception)

    # Write out release notes for new versions
    if new_version:
        try:
            with open(os.path.join(FINALIZED, "RELEASES.md"), "rb") as f:
                r = f.read().split(b'\n\n', 1)[0]  # Slice latest release notes
            try:
                params.put("ReleaseNotes", parse_markdown(r.decode("utf-8")))
            except Exception:
                params.put("ReleaseNotes", r + b"\n")
        except Exception:
            params.put("ReleaseNotes", "")
        params.put_bool("UpdateAvailable", True)

    # Handle user prompt
    for alert in ("Offroad_UpdateFailed", "Offroad_ConnectivityNeeded",
                  "Offroad_ConnectivityNeededPrompt"):
        set_offroad_alert(alert, False)

    now = datetime.datetime.utcnow()
    dt = now - last_update
    if failed_count > 15 and exception is not None:
        if get_tested_branch():
            extra_text = "Ensure the software is correctly installed"
        else:
            extra_text = exception
        set_offroad_alert("Offroad_UpdateFailed", True, extra_text=extra_text)
    elif dt.days > DAYS_NO_CONNECTIVITY_MAX and failed_count > 1:
        set_offroad_alert("Offroad_ConnectivityNeeded", True)
    elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
        remaining = max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 1)
        set_offroad_alert(
            "Offroad_ConnectivityNeededPrompt",
            True,
            extra_text=f"{remaining} day{'' if remaining == 1 else 's'}.")
Ejemplo n.º 25
0
def main():
  if ANDROID:
    # the flippening!
    os.system('LD_LIBRARY_PATH="" content insert --uri content://settings/system --bind name:s:user_rotation --bind value:i:1')

    # disable bluetooth
    os.system('service call bluetooth_manager 8')

  params = Params()
  params.manager_start()

  default_params = [
    ("CommunityFeaturesToggle", "1"),
    ("CompletedTrainingVersion", "0"),
    ("IsRHD", "0"),
    ("IsMetric", "1"),
    ("RecordFront", "0"),
    ("HasAcceptedTerms", "0"),
    ("HasCompletedSetup", "0"),
    ("IsUploadRawEnabled", "1"),
    ("IsLdwEnabled", "1"),
    ("LastUpdateTime", datetime.datetime.utcnow().isoformat().encode('utf8')),
    ("OpenpilotEnabledToggle", "1"),
    ("LaneChangeEnabled", "1"),
    ("IsDriverViewEnabled", "0"),
  ]

  # set unset params
  for k, v in default_params:
    if params.get(k) is None:
      params.put(k, v)

  # is this chffrplus?
  if os.getenv("PASSIVE") is not None:
    params.put("Passive", str(int(os.getenv("PASSIVE"))))

  if params.get("Passive") is None:
    raise Exception("Passive must be set to continue")

  if ANDROID:
    update_apks()
  manager_init()
  manager_prepare(spinner)
  spinner.close()

  if os.getenv("PREPAREONLY") is not None:
    return

  # SystemExit on sigterm
  signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit(1))

  try:
    manager_thread()
  except Exception:
    traceback.print_exc()
    crash.capture_exception()
  finally:
    cleanup_all_processes(None, None)

  if params.get("DoUninstall", encoding='utf8') == "1":
    uninstall()
Ejemplo n.º 26
0
def init_overlay() -> None:

    overlay_init_file = Path(os.path.join(BASEDIR, ".overlay_init"))

    # Re-create the overlay if BASEDIR/.git has changed since we created the overlay
    if overlay_init_file.is_file():
        git_dir_path = os.path.join(BASEDIR, ".git")
        new_files = run(
            ["find", git_dir_path, "-newer",
             str(overlay_init_file)])
        if not len(new_files.splitlines()):
            # A valid overlay already exists
            return
        else:
            cloudlog.info(".git directory changed, recreating overlay")

    cloudlog.info("preparing new safe staging area")

    params = Params()
    params.put_bool("UpdateAvailable", False)
    set_consistent_flag(False)
    dismount_overlay()
    if TICI:
        run(["sudo", "rm", "-rf", STAGING_ROOT])
    if os.path.isdir(STAGING_ROOT):
        shutil.rmtree(STAGING_ROOT)

    for dirname in [
            STAGING_ROOT, OVERLAY_UPPER, OVERLAY_METADATA, OVERLAY_MERGED
    ]:
        os.mkdir(dirname, 0o755)

    if os.lstat(BASEDIR).st_dev != os.lstat(OVERLAY_MERGED).st_dev:
        raise RuntimeError(
            "base and overlay merge directories are on different filesystems; not valid for overlay FS!"
        )

    # Leave a timestamped canary in BASEDIR to check at startup. The device clock
    # should be correct by the time we get here. If the init file disappears, or
    # critical mtimes in BASEDIR are newer than .overlay_init, continue.sh can
    # assume that BASEDIR has used for local development or otherwise modified,
    # and skips the update activation attempt.
    consistent_file = Path(os.path.join(BASEDIR, ".overlay_consistent"))
    if consistent_file.is_file():
        consistent_file.unlink()
    overlay_init_file.touch()

    os.sync()
    overlay_opts = f"lowerdir={BASEDIR},upperdir={OVERLAY_UPPER},workdir={OVERLAY_METADATA}"

    mount_cmd = [
        "mount", "-t", "overlay", "-o", overlay_opts, "none", OVERLAY_MERGED
    ]
    if TICI:
        run(["sudo"] + mount_cmd)
        run(["sudo", "chmod", "755", os.path.join(OVERLAY_METADATA, "work")])
    else:
        run(mount_cmd)

    git_diff = run(["git", "diff"], OVERLAY_MERGED, low_priority=True)
    params.put("GitDiff", git_diff)
    cloudlog.info(f"git diff output:\n{git_diff}")
Ejemplo n.º 27
0
def thermald_thread():
    health_timeout = int(1000 * 2.5 *
                         DT_TRML)  # 2.5x the expected health frequency

    # now loop
    thermal_sock = messaging.pub_sock('thermal')
    health_sock = messaging.sub_sock('health', timeout=health_timeout)
    location_sock = messaging.sub_sock('gpsLocation')

    fan_speed = 0
    count = 0

    startup_conditions = {
        "ignition": False,
    }
    startup_conditions_prev = startup_conditions.copy()

    off_ts = None
    started_ts = None
    started_seen = False
    thermal_status = ThermalStatus.green
    usb_power = True
    current_branch = get_git_branch()

    network_type = NetworkType.none
    network_strength = NetworkStrength.unknown
    wifiIpAddress = 'N/A'

    current_filter = FirstOrderFilter(0., CURRENT_TAU, DT_TRML)
    cpu_temp_filter = FirstOrderFilter(0., CPU_TEMP_TAU, DT_TRML)
    health_prev = None
    should_start_prev = False
    handle_fan = None
    is_uno = False

    params = Params()
    pm = PowerMonitoring()
    no_panda_cnt = 0

    thermal_config = get_thermal_config()

    while 1:
        health = messaging.recv_sock(health_sock, wait=True)
        location = messaging.recv_sock(location_sock)
        location = location.gpsLocation if location else None
        msg = read_thermal(thermal_config)

        if health is not None:
            usb_power = health.health.usbPowerMode != log.HealthData.UsbPowerMode.client

            # If we lose connection to the panda, wait 5 seconds before going offroad
            if health.health.hwType == log.HealthData.HwType.unknown:
                no_panda_cnt += 1
                if no_panda_cnt > DISCONNECT_TIMEOUT / DT_TRML:
                    if startup_conditions["ignition"]:
                        cloudlog.error("Lost panda connection while onroad")
                    startup_conditions["ignition"] = False
            else:
                no_panda_cnt = 0
                startup_conditions[
                    "ignition"] = health.health.ignitionLine or health.health.ignitionCan

            # Setup fan handler on first connect to panda
            if handle_fan is None and health.health.hwType != log.HealthData.HwType.unknown:
                is_uno = health.health.hwType == log.HealthData.HwType.uno

                if (not EON) or is_uno:
                    cloudlog.info("Setting up UNO fan handler")
                    handle_fan = handle_fan_uno
                else:
                    cloudlog.info("Setting up EON fan handler")
                    setup_eon_fan()
                    handle_fan = handle_fan_eon

            # Handle disconnect
            if health_prev is not None:
                if health.health.hwType == log.HealthData.HwType.unknown and \
                  health_prev.health.hwType != log.HealthData.HwType.unknown:
                    params.panda_disconnect()
            health_prev = health

        # get_network_type is an expensive call. update every 10s
        if (count % int(10. / DT_TRML)) == 0:
            try:
                network_type = HARDWARE.get_network_type()
                network_strength = HARDWARE.get_network_strength(network_type)
                wifiIpAddress = HARDWARE.get_ip_address()
            except Exception:
                cloudlog.exception("Error getting network status")

        msg.thermal.freeSpace = get_available_percent(default=100.0) / 100.0
        msg.thermal.memUsedPercent = int(round(
            psutil.virtual_memory().percent))
        msg.thermal.cpuPerc = int(round(psutil.cpu_percent()))
        msg.thermal.networkType = network_type
        msg.thermal.networkStrength = network_strength
        msg.thermal.wifiIpAddress = wifiIpAddress
        msg.thermal.batteryPercent = get_battery_capacity()
        msg.thermal.batteryStatus = get_battery_status()
        msg.thermal.batteryCurrent = get_battery_current()
        msg.thermal.batteryVoltage = get_battery_voltage()
        msg.thermal.usbOnline = get_usb_present()

        # Fake battery levels on uno for frame
        if (not EON) or is_uno:
            msg.thermal.batteryPercent = 100
            msg.thermal.batteryStatus = "Charging"
            msg.thermal.bat = 0

        current_filter.update(msg.thermal.batteryCurrent / 1e6)

        # TODO: add car battery voltage check
        max_cpu_temp = cpu_temp_filter.update(max(msg.thermal.cpu))
        max_comp_temp = max(max_cpu_temp, msg.thermal.mem,
                            max(msg.thermal.gpu))
        bat_temp = msg.thermal.bat

        if handle_fan is not None:
            fan_speed = handle_fan(max_cpu_temp, bat_temp, fan_speed,
                                   startup_conditions["ignition"])
            msg.thermal.fanSpeed = fan_speed

        # If device is offroad we want to cool down before going onroad
        # since going onroad increases load and can make temps go over 107
        # We only do this if there is a relay that prevents the car from faulting
        is_offroad_for_5_min = (started_ts is None) and (
            (not started_seen) or (off_ts is None) or
            (sec_since_boot() - off_ts > 60 * 5))
        if max_cpu_temp > 107. or bat_temp >= 63. or (is_offroad_for_5_min
                                                      and max_cpu_temp > 70.0):
            # onroad not allowed
            thermal_status = ThermalStatus.danger
        elif max_comp_temp > 96.0 or bat_temp > 60.:
            # hysteresis between onroad not allowed and engage not allowed
            thermal_status = clip(thermal_status, ThermalStatus.red,
                                  ThermalStatus.danger)
        elif max_cpu_temp > 94.0:
            # hysteresis between engage not allowed and uploader not allowed
            thermal_status = clip(thermal_status, ThermalStatus.yellow,
                                  ThermalStatus.red)
        elif max_cpu_temp > 80.0:
            # uploader not allowed
            thermal_status = ThermalStatus.yellow
        elif max_cpu_temp > 75.0:
            # hysteresis between uploader not allowed and all good
            thermal_status = clip(thermal_status, ThermalStatus.green,
                                  ThermalStatus.yellow)
        else:
            # all good
            thermal_status = ThermalStatus.green

        # **** starting logic ****

        # Check for last update time and display alerts if needed
        now = datetime.datetime.utcnow()

        # show invalid date/time alert
        startup_conditions["time_valid"] = now.year >= True
        set_offroad_alert_if_changed("Offroad_InvalidTime",
                                     (not startup_conditions["time_valid"]))

        # Show update prompt
        try:
            last_update = now  #datetime.datetime.fromisoformat(params.get("LastUpdateTime", encoding='utf8'))
        except (TypeError, ValueError):
            last_update = now
        dt = now - last_update

        update_failed_count = 0  #params.get("UpdateFailedCount")
        update_failed_count = 0 if update_failed_count is None else int(
            update_failed_count)
        last_update_exception = params.get("LastUpdateException",
                                           encoding='utf8')

        if update_failed_count > 15 and last_update_exception is not None:
            if current_branch in ["release2", "dashcam"]:
                extra_text = "Ensure the software is correctly installed"
            else:
                extra_text = last_update_exception

            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         False)
            set_offroad_alert_if_changed("Offroad_UpdateFailed",
                                         True,
                                         extra_text=extra_text)
        elif dt.days > DAYS_NO_CONNECTIVITY_MAX and update_failed_count > 1:
            set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", True)
        elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT:
            remaining_time = str(max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 0))
            set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         True,
                                         extra_text=f"{remaining_time} days.")
        else:
            set_offroad_alert_if_changed("Offroad_UpdateFailed", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeeded", False)
            set_offroad_alert_if_changed("Offroad_ConnectivityNeededPrompt",
                                         False)

        startup_conditions["not_uninstalling"] = not params.get(
            "DoUninstall") == b"1"
        startup_conditions["accepted_terms"] = params.get(
            "HasAcceptedTerms") == terms_version

        panda_signature = params.get("PandaFirmware")
        startup_conditions["fw_version_match"] = (panda_signature is None) or (
            panda_signature == FW_SIGNATURE
        )  # don't show alert is no panda is connected (None)
        set_offroad_alert_if_changed(
            "Offroad_PandaFirmwareMismatch",
            (not startup_conditions["fw_version_match"]))

        # with 2% left, we killall, otherwise the phone will take a long time to boot
        startup_conditions["free_space"] = msg.thermal.freeSpace > 0.02
        startup_conditions["completed_training"] = params.get("CompletedTrainingVersion") == training_version or \
                                                   (current_branch in ['dashcam', 'dashcam-staging'])
        startup_conditions["not_driver_view"] = not params.get(
            "IsDriverViewEnabled") == b"1"
        startup_conditions["not_taking_snapshot"] = not params.get(
            "IsTakingSnapshot") == b"1"
        # if any CPU gets above 107 or the battery gets above 63, kill all processes
        # controls will warn with CPU above 95 or battery above 60
        startup_conditions[
            "device_temp_good"] = thermal_status < ThermalStatus.danger
        set_offroad_alert_if_changed(
            "Offroad_TemperatureTooHigh",
            (not startup_conditions["device_temp_good"]))
        should_start = all(startup_conditions.values())

        startup_conditions[
            "hardware_supported"] = health is not None and health.health.hwType not in [
                log.HealthData.HwType.whitePanda,
                log.HealthData.HwType.greyPanda
            ]
        set_offroad_alert_if_changed(
            "Offroad_HardwareUnsupported", health is not None
            and not startup_conditions["hardware_supported"])

        if should_start:
            if not should_start_prev:
                params.delete("IsOffroad")

            off_ts = None
            if started_ts is None:
                started_ts = sec_since_boot()
                started_seen = True
                os.system(
                    'echo performance > /sys/class/devfreq/soc:qcom,cpubw/governor'
                )
        else:
            if startup_conditions["ignition"] and (startup_conditions !=
                                                   startup_conditions_prev):
                cloudlog.event("Startup blocked",
                               startup_conditions=startup_conditions)
            if should_start_prev or (count == 0):
                params.put("IsOffroad", "1")

            started_ts = None
            if off_ts is None:
                off_ts = sec_since_boot()
                os.system(
                    'echo powersave > /sys/class/devfreq/soc:qcom,cpubw/governor'
                )

        # Offroad power monitoring
        pm.calculate(health)
        msg.thermal.offroadPowerUsage = pm.get_power_used()
        msg.thermal.carBatteryCapacity = max(0, pm.get_car_battery_capacity())

        # Check if we need to disable charging (handled by boardd)
        msg.thermal.chargingDisabled = pm.should_disable_charging(
            health, off_ts)

        # Check if we need to shut down
        if pm.should_shutdown(health, off_ts, started_seen, LEON):
            cloudlog.info(f"shutting device down, offroad since {off_ts}")
            # TODO: add function for blocking cloudlog instead of sleep
            time.sleep(10)
            os.system('LD_LIBRARY_PATH="" svc power shutdown')

        msg.thermal.chargingError = current_filter.x > 0. and msg.thermal.batteryPercent < 90  # if current is positive, then battery is being discharged
        msg.thermal.started = started_ts is not None
        msg.thermal.startedTs = int(1e9 * (started_ts or 0))

        msg.thermal.thermalStatus = thermal_status
        thermal_sock.send(msg.to_bytes())

        set_offroad_alert_if_changed("Offroad_ChargeDisabled", (not usb_power))

        should_start_prev = should_start
        startup_conditions_prev = startup_conditions.copy()

        # report to server once per minute
        if (count % int(60. / DT_TRML)) == 0:
            cloudlog.event("STATUS_PACKET",
                           count=count,
                           health=(health.to_dict() if health else None),
                           location=(location.to_dict() if location else None),
                           thermal=msg.to_dict())

        count += 1
Ejemplo n.º 28
0
def main():
    params = Params()

    if params.get_bool("DisableUpdates"):
        cloudlog.warning("updates are disabled by the DisableUpdates param")
        exit(0)

    ov_lock_fd = open(LOCK_FILE, 'w')
    try:
        fcntl.flock(ov_lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
    except IOError as e:
        raise RuntimeError(
            "couldn't get overlay lock; is another instance running?") from e

    # Set low io priority
    proc = psutil.Process()
    if psutil.LINUX:
        proc.ionice(psutil.IOPRIO_CLASS_BE, value=7)

    # Check if we just performed an update
    if Path(os.path.join(STAGING_ROOT, "old_openpilot")).is_dir():
        cloudlog.event("update installed")

    if not params.get("InstallDate"):
        t = datetime.datetime.utcnow().isoformat()
        params.put("InstallDate", t.encode('utf8'))

    overlay_init = Path(os.path.join(BASEDIR, ".overlay_init"))
    overlay_init.unlink(missing_ok=True)

    first_run = True
    last_fetch_time = 0
    update_failed_count = 0

    # Set initial params for offroad alerts
    set_params(False, 0, None)

    # Wait for IsOffroad to be set before our first update attempt
    wait_helper = WaitTimeHelper(proc)
    wait_helper.sleep(30)

    # Run the update loop
    #  * every 1m, do a lightweight internet/update check
    #  * every 10m, do a full git fetch
    while not wait_helper.shutdown:
        update_now = wait_helper.ready_event.is_set()
        wait_helper.ready_event.clear()

        # Don't run updater while onroad or if the time's wrong
        time_wrong = datetime.datetime.utcnow().year < 2019
        is_onroad = not params.get_bool("IsOffroad")
        if is_onroad or time_wrong:
            wait_helper.sleep(30)
            cloudlog.info("not running updater, not offroad")
            continue

        # Attempt an update
        exception = None
        new_version = False
        update_failed_count += 1
        try:
            init_overlay()

            internet_ok, update_available = check_for_update()
            if internet_ok and not update_available:
                update_failed_count = 0

            # Fetch updates at most every 10 minutes
            if internet_ok and (update_now or
                                time.monotonic() - last_fetch_time > 60 * 10):
                new_version = fetch_update(wait_helper)
                update_failed_count = 0
                last_fetch_time = time.monotonic()

                if first_run and not new_version and os.path.isdir(
                        NEOSUPDATE_DIR):
                    shutil.rmtree(NEOSUPDATE_DIR)
                first_run = False
        except subprocess.CalledProcessError as e:
            cloudlog.event("update process failed",
                           cmd=e.cmd,
                           output=e.output,
                           returncode=e.returncode)
            exception = f"command failed: {e.cmd}\n{e.output}"
            overlay_init.unlink(missing_ok=True)
        except Exception as e:
            cloudlog.exception("uncaught updated exception, shouldn't happen")
            exception = str(e)
            overlay_init.unlink(missing_ok=True)

        try:
            set_params(new_version, update_failed_count, exception)
        except Exception:
            cloudlog.exception(
                "uncaught updated exception while setting params, shouldn't happen"
            )

        wait_helper.sleep(60)

    dismount_overlay()
Ejemplo n.º 29
0
    def __init__(self, sm=None, pm=None, can_sock=None):
        config_realtime_process(4 if TICI else 3, Priority.CTRL_HIGH)

        # Setup sockets
        self.pm = pm
        if self.pm is None:
            self.pm = messaging.PubMaster([
                'sendcan', 'controlsState', 'carState', 'carControl',
                'carEvents', 'carParams'
            ])

        self.camera_packets = ["roadCameraState", "driverCameraState"]
        if TICI:
            self.camera_packets.append("wideRoadCameraState")

        params = Params()
        self.joystick_mode = params.get_bool("JoystickDebugMode")
        joystick_packet = ['testJoystick'] if self.joystick_mode else []

        self.sm = sm
        if self.sm is None:
            ignore = ['driverCameraState', 'managerState'
                      ] if SIMULATION else None
            self.sm = messaging.SubMaster(
                [
                    'deviceState', 'pandaState', 'modelV2', 'liveCalibration',
                    'driverMonitoringState', 'longitudinalPlan', 'lateralPlan',
                    'liveLocationKalman', 'managerState', 'liveParameters',
                    'radarState'
                ] + self.camera_packets + joystick_packet,
                ignore_alive=ignore,
                ignore_avg_freq=['radarState', 'longitudinalPlan'])

        self.can_sock = can_sock
        if can_sock is None:
            can_timeout = None if os.environ.get('NO_CAN_TIMEOUT',
                                                 False) else 100
            self.can_sock = messaging.sub_sock('can', timeout=can_timeout)

        if TICI:
            self.log_sock = messaging.sub_sock('androidLog')

        # wait for one pandaState and one CAN packet
        hw_type = messaging.recv_one(
            self.sm.sock['pandaState']).pandaState.pandaType
        has_relay = hw_type in [
            PandaType.blackPanda, PandaType.uno, PandaType.dos
        ]
        print("Waiting for CAN messages...")
        get_one_can(self.can_sock)

        self.CI, self.CP = get_car(self.can_sock, self.pm.sock['sendcan'],
                                   has_relay)

        # read params
        self.is_metric = params.get_bool("IsMetric")
        self.is_ldw_enabled = params.get_bool("IsLdwEnabled")
        community_feature_toggle = params.get_bool("CommunityFeaturesToggle")
        openpilot_enabled_toggle = params.get_bool("OpenpilotEnabledToggle")
        passive = params.get_bool("Passive") or not openpilot_enabled_toggle

        # detect sound card presence and ensure successful init
        sounds_available = HARDWARE.get_sound_card_online()

        car_recognized = self.CP.carName != 'mock'

        controller_available = self.CI.CC is not None and not passive and not self.CP.dashcamOnly
        community_feature = self.CP.communityFeature or \
                            self.CP.fingerprintSource == car.CarParams.FingerprintSource.can
        community_feature_disallowed = community_feature and (
            not community_feature_toggle)
        self.read_only = not car_recognized or not controller_available or \
                           self.CP.dashcamOnly or community_feature_disallowed
        if self.read_only:
            self.CP.safetyModel = car.CarParams.SafetyModel.noOutput

        # Write CarParams for radard
        cp_bytes = self.CP.to_bytes()
        params.put("CarParams", cp_bytes)
        put_nonblocking("CarParamsCache", cp_bytes)

        self.CC = car.CarControl.new_message()
        self.AM = AlertManager()
        self.events = Events()

        self.LoC = LongControl(self.CP)
        self.VM = VehicleModel(self.CP)

        if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
            self.LaC = LatControlAngle(self.CP)
        elif self.CP.lateralTuning.which() == 'pid':
            self.LaC = LatControlPID(self.CP)
        elif self.CP.lateralTuning.which() == 'indi':
            self.LaC = LatControlINDI(self.CP)
        elif self.CP.lateralTuning.which() == 'lqr':
            self.LaC = LatControlLQR(self.CP)

        self.initialized = False
        self.state = State.disabled
        self.enabled = False
        self.active = False
        self.can_rcv_error = False
        self.soft_disable_timer = 0
        self.v_cruise_kph = 255
        self.v_cruise_kph_last = 0
        self.mismatch_counter = 0
        self.can_error_counter = 0
        self.last_blinker_frame = 0
        self.saturated_count = 0
        self.distance_traveled = 0
        self.last_functional_fan_frame = 0
        self.events_prev = []
        self.current_alert_types = [ET.PERMANENT]
        self.logged_comm_issue = False
        self.v_target = 0.0
        self.a_target = 0.0

        # scc smoother
        self.is_cruise_enabled = False
        self.applyMaxSpeed = 0
        self.clu_speed_ms = 0.
        self.apply_accel = 0.
        self.fused_accel = 0.
        self.lead_drel = 0.
        self.aReqValue = 0.
        self.aReqValueMin = 0.
        self.aReqValueMax = 0.
        self.sccStockCamStatus = 0
        self.sccStockCamAct = 0

        self.left_lane_visible = False
        self.right_lane_visible = False

        self.wide_camera = TICI and params.get_bool('EnableWideCamera')

        # TODO: no longer necessary, aside from process replay
        self.sm['liveParameters'].valid = True

        self.startup_event = get_startup_event(car_recognized,
                                               controller_available,
                                               self.CP.fuzzyFingerprint,
                                               len(self.CP.carFw) > 0)

        if not sounds_available:
            self.events.add(EventName.soundsUnavailable, static=True)
        if community_feature_disallowed and car_recognized and not self.CP.dashcamOnly:
            self.events.add(EventName.communityFeatureDisallowed, static=True)
        if not car_recognized:
            self.events.add(EventName.carUnrecognized, static=True)
        elif self.read_only:
            self.events.add(EventName.dashcamMode, static=True)
        elif self.joystick_mode:
            self.events.add(EventName.joystickDebug, static=True)
            self.startup_event = None

        # controlsd is driven by can recv, expected at 100Hz
        self.rk = Ratekeeper(100, print_delay_threshold=None)
        self.prof = Profiler(False)  # off by default
Ejemplo n.º 30
0
def set_params_enabled():
    from common.params import Params
    params = Params()
    params.put("HasAcceptedTerms", terms_version)
    params.put("HasCompletedSetup", "1")
    params.put("OpenpilotEnabledToggle", "1")
    params.put("CommunityFeaturesToggle", "1")
    params.put("Passive", "0")
    params.put("CompletedTrainingVersion", training_version)