parent
48303589e9
commit
187a70f760
70 changed files with 1934 additions and 579 deletions
@ -1,6 +1,9 @@ |
|||||||
.PHONY: all |
|
||||||
|
|
||||||
# TODO: Add a global build system to openpilot
|
code_dir := $(shell pwd)
|
||||||
|
|
||||||
|
# TODO: Add a global build system
|
||||||
|
|
||||||
|
.PHONY: all |
||||||
all: |
all: |
||||||
cd /data/openpilot/selfdrive && PYTHONPATH=/data/openpilot PREPAREONLY=1 /data/openpilot/selfdrive/manager.py
|
cd selfdrive && PYTHONPATH=$(code_dir) PREPAREONLY=1 ./manager.py
|
||||||
|
|
||||||
|
@ -1 +1 @@ |
|||||||
Subproject commit b8c0034c5d6ded3d85a4f0414b3509baae35a34b |
Subproject commit 835a9739d6721e351e1814439b55b6c4212f7b85 |
@ -1 +1 @@ |
|||||||
Subproject commit 5ea4df111b735ce9efb27ab2e0f87837210f6fc3 |
Subproject commit 849f68879d1ceacbf1f9d4174e16e1cd14527383 |
@ -0,0 +1,34 @@ |
|||||||
|
# Car button codes |
||||||
|
class CruiseButtons: |
||||||
|
RES_ACCEL = 4 |
||||||
|
DECEL_SET = 3 |
||||||
|
CANCEL = 2 |
||||||
|
MAIN = 1 |
||||||
|
|
||||||
|
|
||||||
|
#car chimes: enumeration from dbc file. Chimes are for alerts and warnings |
||||||
|
class CM: |
||||||
|
MUTE = 0 |
||||||
|
SINGLE = 3 |
||||||
|
DOUBLE = 4 |
||||||
|
REPEATED = 1 |
||||||
|
CONTINUOUS = 2 |
||||||
|
|
||||||
|
|
||||||
|
#car beepss: enumeration from dbc file. Beeps are for activ and deactiv |
||||||
|
class BP: |
||||||
|
MUTE = 0 |
||||||
|
SINGLE = 3 |
||||||
|
TRIPLE = 2 |
||||||
|
REPEATED = 1 |
||||||
|
|
||||||
|
class AH: |
||||||
|
#[alert_idx, value] |
||||||
|
# See dbc files for info on values" |
||||||
|
NONE = [0, 0] |
||||||
|
FCW = [1, 0x8] |
||||||
|
STEER = [2, 1] |
||||||
|
BRAKE_PRESSED = [3, 10] |
||||||
|
GEAR_NOT_D = [4, 6] |
||||||
|
SEATBELT = [5, 5] |
||||||
|
SPEED_TOO_HIGH = [6, 8] |
@ -0,0 +1,236 @@ |
|||||||
|
from common.numpy_fast import clip, interp |
||||||
|
from common.realtime import sec_since_boot |
||||||
|
from selfdrive.boardd.boardd import can_list_to_can_capnp |
||||||
|
from selfdrive.controls.lib.drive_helpers import rate_limit |
||||||
|
from selfdrive.car.toyota.toyotacan import make_can_msg, create_video_target,\ |
||||||
|
create_steer_command, create_ui_command, \ |
||||||
|
create_ipas_steer_command, create_accel_command |
||||||
|
|
||||||
|
|
||||||
|
ACCEL_HYST_GAP = 0.02 # don't change accel command for small oscilalitons within this value |
||||||
|
ACCEL_MAX = 1500 # 1.5 m/s2 |
||||||
|
ACCEL_MIN = -3000 # 3 m/s2 |
||||||
|
ACCEL_SCALE = max(ACCEL_MAX, -ACCEL_MIN) |
||||||
|
|
||||||
|
STEER_MAX = 1500 |
||||||
|
STEER_DELTA_UP = 10 # 1.5s time to peak torque |
||||||
|
STEER_DELTA_DOWN = 45 # lower than 50 otherwise the Rav4 faults (Prius seems ok though) |
||||||
|
STEER_ERROR_MAX = 500 # max delta between torque cmd and torque motor |
||||||
|
|
||||||
|
STEER_IPAS_MAX = 340 |
||||||
|
STEER_IPAS_DELTA_MAX = 3 |
||||||
|
|
||||||
|
class CAR: |
||||||
|
PRIUS = "TOYOTA PRIUS 2017" |
||||||
|
RAV4 = "TOYOTA RAV4 2017" |
||||||
|
|
||||||
|
class ECU: |
||||||
|
CAM = 0 # camera |
||||||
|
DSU = 1 # driving support unit |
||||||
|
APGS = 2 # advanced parking guidance system |
||||||
|
|
||||||
|
|
||||||
|
TARGET_IDS = [0x340, 0x341, 0x342, 0x343, 0x344, 0x345, |
||||||
|
0x363, 0x364, 0x365, 0x370, 0x371, 0x372, |
||||||
|
0x373, 0x374, 0x375, 0x380, 0x381, 0x382, |
||||||
|
0x383] |
||||||
|
|
||||||
|
# addr, [ecu, bus, 1/freq*100, vl] |
||||||
|
STATIC_MSGS = {0x141: (ECU.DSU, (CAR.PRIUS, CAR.RAV4), 1, 2, '\x00\x00\x00\x46'), |
||||||
|
0x128: (ECU.DSU, (CAR.PRIUS, CAR.RAV4), 1, 3, '\xf4\x01\x90\x83\x00\x37'), |
||||||
|
|
||||||
|
0x292: (ECU.APGS, (CAR.PRIUS, CAR.RAV4), 0, 3, '\x00\x00\x00\x00\x00\x00\x00\x9e'), |
||||||
|
0x283: (ECU.DSU, (CAR.PRIUS, CAR.RAV4), 0, 3, '\x00\x00\x00\x00\x00\x00\x8c'), |
||||||
|
0x2E6: (ECU.DSU, (CAR.PRIUS,), 0, 3, '\xff\xf8\x00\x08\x7f\xe0\x00\x4e'), |
||||||
|
0x2E7: (ECU.DSU, (CAR.PRIUS,), 0, 3, '\xa8\x9c\x31\x9c\x00\x00\x00\x02'), |
||||||
|
|
||||||
|
0x240: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 1, 5, '\x00\x10\x01\x00\x10\x01\x00'), |
||||||
|
0x241: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 1, 5, '\x00\x10\x01\x00\x10\x01\x00'), |
||||||
|
0x244: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 1, 5, '\x00\x10\x01\x00\x10\x01\x00'), |
||||||
|
0x245: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 1, 5, '\x00\x10\x01\x00\x10\x01\x00'), |
||||||
|
0x248: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 1, 5, '\x00\x00\x00\x00\x00\x00\x01'), |
||||||
|
0x344: (ECU.DSU, (CAR.PRIUS, CAR.RAV4), 0, 5, '\x00\x00\x01\x00\x00\x00\x00\x50'), |
||||||
|
|
||||||
|
0x160: (ECU.DSU, (CAR.PRIUS, CAR.RAV4), 1, 7, '\x00\x00\x08\x12\x01\x31\x9c\x51'), |
||||||
|
0x161: (ECU.DSU, (CAR.PRIUS, CAR.RAV4), 1, 7, '\x00\x1e\x00\x00\x00\x80\x07'), |
||||||
|
|
||||||
|
0x32E: (ECU.APGS, (CAR.PRIUS, CAR.RAV4), 0, 20, '\x00\x00\x00\x00\x00\x00\x00\x00'), |
||||||
|
0x33E: (ECU.DSU, (CAR.PRIUS,), 0, 20, '\x0f\xff\x26\x40\x00\x1f\x00'), |
||||||
|
0x365: (ECU.DSU, (CAR.PRIUS,), 0, 20, '\x00\x00\x00\x80\x03\x00\x08'), |
||||||
|
0x365: (ECU.DSU, (CAR.RAV4,), 0, 20, '\x00\x00\x00\x80\xfc\x00\x08'), |
||||||
|
0x366: (ECU.DSU, (CAR.PRIUS,), 0, 20, '\x00\x00\x4d\x82\x40\x02\x00'), |
||||||
|
0x366: (ECU.DSU, (CAR.RAV4,), 0, 20, '\x00\x72\x07\xff\x09\xfe\x00'), |
||||||
|
|
||||||
|
0x367: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 0, 40, '\x06\x00'), |
||||||
|
|
||||||
|
0x414: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 0, 100, '\x00\x00\x00\x00\x00\x00\x17\x00'), |
||||||
|
0x489: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 0, 100, '\x00\x00\x00\x00\x00\x00\x00'), |
||||||
|
0x48a: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 0, 100, '\x00\x00\x00\x00\x00\x00\x00'), |
||||||
|
0x48b: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 0, 100, '\x66\x06\x08\x0a\x02\x00\x00\x00'), |
||||||
|
0x4d3: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 0, 100, '\x1C\x00\x00\x01\x00\x00\x00\x00'), |
||||||
|
0x130: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 1, 100, '\x00\x00\x00\x00\x00\x00\x38'), |
||||||
|
0x466: (ECU.CAM, (CAR.PRIUS, CAR.RAV4), 1, 100, '\x20\x20\xAD'), |
||||||
|
0x396: (ECU.APGS, (CAR.PRIUS, CAR.RAV4), 0, 100, '\xBD\x00\x00\x00\x60\x0F\x02\x00'), |
||||||
|
0x43A: (ECU.APGS, (CAR.PRIUS, CAR.RAV4), 0, 100, '\x84\x00\x00\x00\x00\x00\x00\x00'), |
||||||
|
0x43B: (ECU.APGS, (CAR.PRIUS, CAR.RAV4), 0, 100, '\x00\x00\x00\x00\x00\x00\x00\x00'), |
||||||
|
0x497: (ECU.APGS, (CAR.PRIUS, CAR.RAV4), 0, 100, '\x00\x00\x00\x00\x00\x00\x00\x00'), |
||||||
|
0x4CC: (ECU.APGS, (CAR.PRIUS, CAR.RAV4), 0, 100, '\x0D\x00\x00\x00\x00\x00\x00\x00'), |
||||||
|
0x411: (ECU.DSU, (CAR.PRIUS, CAR.RAV4), 0, 100, '\x00\x20\x00\x00\x10\x00\x80\x00'), |
||||||
|
0x4CB: (ECU.DSU, (CAR.PRIUS, CAR.RAV4), 0, 100, '\x0c\x00\x00\x00\x00\x00\x00\x00'), |
||||||
|
0x470: (ECU.DSU, (CAR.PRIUS,), 1, 100, '\x00\x00\x02\x7a'), |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
def check_ecu_msgs(fingerprint, candidate, ecu): |
||||||
|
# return True if fingerprint contains messages normally sent by a given ecu |
||||||
|
ecu_msgs = [x for x in STATIC_MSGS if (ecu == STATIC_MSGS[x][0] and |
||||||
|
candidate in STATIC_MSGS[x][1] and |
||||||
|
STATIC_MSGS[x][2] == 0)] |
||||||
|
|
||||||
|
return any(msg for msg in fingerprint if msg in ecu_msgs) |
||||||
|
|
||||||
|
|
||||||
|
def accel_hysteresis(accel, accel_steady, enabled): |
||||||
|
|
||||||
|
# for small accel oscillations within ACCEL_HYST_GAP, don't change the accel command |
||||||
|
if not enabled: |
||||||
|
# send 0 when disabled, otherwise acc faults |
||||||
|
accel_steady = 0. |
||||||
|
elif accel > accel_steady + ACCEL_HYST_GAP: |
||||||
|
accel_steady = accel - ACCEL_HYST_GAP |
||||||
|
elif accel < accel_steady - ACCEL_HYST_GAP: |
||||||
|
accel_steady = accel + ACCEL_HYST_GAP |
||||||
|
accel = accel_steady |
||||||
|
|
||||||
|
return accel, accel_steady |
||||||
|
|
||||||
|
|
||||||
|
def process_hud_alert(hud_alert, audible_alert): |
||||||
|
# initialize to no alert |
||||||
|
hud1 = 0 |
||||||
|
hud2 = 0 |
||||||
|
if hud_alert in ['steerRequired', 'fcw']: |
||||||
|
if audible_alert == 'chimeRepeated': |
||||||
|
hud1 = 3 |
||||||
|
else: |
||||||
|
hud1 = 1 |
||||||
|
if audible_alert in ['beepSingle', 'chimeSingle', 'chimeDouble']: |
||||||
|
# TODO: find a way to send single chimes |
||||||
|
hud2 = 1 |
||||||
|
|
||||||
|
return hud1, hud2 |
||||||
|
|
||||||
|
|
||||||
|
class CarController(object): |
||||||
|
def __init__(self, car_fingerprint, enable_camera, enable_dsu, enable_apg): |
||||||
|
self.braking = False |
||||||
|
# redundant safety check with the board |
||||||
|
self.controls_allowed = True |
||||||
|
self.last_steer = 0. |
||||||
|
self.accel_steady = 0. |
||||||
|
self.car_fingerprint = car_fingerprint |
||||||
|
self.alert_active = False |
||||||
|
|
||||||
|
self.fake_ecus = set() |
||||||
|
if enable_camera: self.fake_ecus.add(ECU.CAM) |
||||||
|
if enable_dsu: self.fake_ecus.add(ECU.DSU) |
||||||
|
if enable_apg: self.fake_ecus.add(ECU.APGS) |
||||||
|
|
||||||
|
def update(self, sendcan, enabled, CS, frame, actuators, |
||||||
|
pcm_cancel_cmd, hud_alert, audible_alert): |
||||||
|
|
||||||
|
# *** compute control surfaces *** |
||||||
|
tt = sec_since_boot() |
||||||
|
|
||||||
|
# steer torque is converted back to CAN reference (positive when steering right) |
||||||
|
apply_accel = actuators.gas - actuators.brake |
||||||
|
apply_accel, self.accel_steady = accel_hysteresis(apply_accel, self.accel_steady, enabled) |
||||||
|
apply_accel = int(round(clip(apply_accel * ACCEL_SCALE, ACCEL_MIN, ACCEL_MAX))) |
||||||
|
|
||||||
|
# steer torque is converted back to CAN reference (positive when steering right) |
||||||
|
apply_steer = int(round(actuators.steer * STEER_MAX)) |
||||||
|
|
||||||
|
max_lim = min(max(CS.steer_torque_motor + STEER_ERROR_MAX, STEER_ERROR_MAX), STEER_MAX) |
||||||
|
min_lim = max(min(CS.steer_torque_motor - STEER_ERROR_MAX, -STEER_ERROR_MAX), -STEER_MAX) |
||||||
|
|
||||||
|
apply_steer = clip(apply_steer, min_lim, max_lim) |
||||||
|
|
||||||
|
# slow rate if steer torque increases in magnitude |
||||||
|
if self.last_steer > 0: |
||||||
|
apply_steer = clip(apply_steer, max(self.last_steer - STEER_DELTA_DOWN, - STEER_DELTA_UP), self.last_steer + STEER_DELTA_UP) |
||||||
|
else: |
||||||
|
apply_steer = clip(apply_steer, self.last_steer - STEER_DELTA_UP, min(self.last_steer + STEER_DELTA_DOWN, STEER_DELTA_UP)) |
||||||
|
|
||||||
|
if not enabled and CS.pcm_acc_status: |
||||||
|
# send pcm acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated |
||||||
|
pcm_cancel_cmd = 1 |
||||||
|
|
||||||
|
# dropping torque immediately might cause eps to temp fault. On the other hand, safety_toyota |
||||||
|
# cuts steer torque immediately anyway TODO: monitor if this is a real issue |
||||||
|
if not enabled or CS.steer_error: |
||||||
|
apply_steer = 0 |
||||||
|
|
||||||
|
self.last_steer = apply_steer |
||||||
|
self.last_accel = apply_accel |
||||||
|
|
||||||
|
can_sends = [] |
||||||
|
|
||||||
|
#*** control msgs *** |
||||||
|
#print "steer", apply_steer, min_lim, max_lim, CS.steer_torque_motor |
||||||
|
|
||||||
|
# toyota can trace shows this message at 42Hz, with counter adding alternatively 1 and 2; |
||||||
|
# sending it at 100Hz seem to allow a higher rate limit, as the rate limit seems imposed |
||||||
|
# on consecutive messages |
||||||
|
if ECU.CAM in self.fake_ecus: |
||||||
|
can_sends.append(create_steer_command(apply_steer, frame)) |
||||||
|
|
||||||
|
if ECU.APGS in self.fake_ecus: |
||||||
|
can_sends.append(create_ipas_steer_command(apply_steer)) |
||||||
|
|
||||||
|
# accel cmd comes from DSU, but we can spam can to cancel the system even if we are using lat only control |
||||||
|
if (frame % 3 == 0 and ECU.DSU in self.fake_ecus) or (pcm_cancel_cmd and ECU.CAM in self.fake_ecus): |
||||||
|
if ECU.DSU in self.fake_ecus: |
||||||
|
can_sends.append(create_accel_command(apply_accel, pcm_cancel_cmd)) |
||||||
|
else: |
||||||
|
can_sends.append(create_accel_command(0, pcm_cancel_cmd)) |
||||||
|
|
||||||
|
if frame % 10 == 0 and ECU.CAM in self.fake_ecus: |
||||||
|
for addr in TARGET_IDS: |
||||||
|
can_sends.append(create_video_target(frame/10, addr)) |
||||||
|
|
||||||
|
# ui mesg is at 100Hz but we send asap if: |
||||||
|
# - there is something to display |
||||||
|
# - there is something to stop displaying |
||||||
|
hud1, hud2 = process_hud_alert(hud_alert, audible_alert) |
||||||
|
if ((hud1 or hud2) and not self.alert_active) or \ |
||||||
|
(not (hud1 or hud2) and self.alert_active): |
||||||
|
send_ui = True |
||||||
|
self.alert_active = not self.alert_active |
||||||
|
else: |
||||||
|
send_ui = False |
||||||
|
|
||||||
|
if (frame % 100 == 0 or send_ui) and ECU.CAM in self.fake_ecus: |
||||||
|
can_sends.append(create_ui_command(hud1, hud2)) |
||||||
|
|
||||||
|
#*** static msgs *** |
||||||
|
|
||||||
|
for addr, (ecu, cars, bus, fr_step, vl) in STATIC_MSGS.iteritems(): |
||||||
|
if frame % fr_step == 0 and ecu in self.fake_ecus and self.car_fingerprint in cars: |
||||||
|
# send msg! |
||||||
|
# special cases |
||||||
|
|
||||||
|
if fr_step == 5 and ecu == ECU.CAM and bus == 1: |
||||||
|
cnt = (((frame / 5) % 7) + 1) << 5 |
||||||
|
vl = chr(cnt) + vl |
||||||
|
elif addr in (0x489, 0x48a) and bus == 0: |
||||||
|
# add counter for those 2 messages (last 4 bits) |
||||||
|
cnt = ((frame/100)%0xf) + 1 |
||||||
|
if addr == 0x48a: |
||||||
|
# 0x48a has a 8 preceding the counter |
||||||
|
cnt += 1 << 7 |
||||||
|
vl += chr(cnt) |
||||||
|
|
||||||
|
can_sends.append(make_can_msg(addr, vl, bus, False)) |
||||||
|
|
||||||
|
|
||||||
|
sendcan.send(can_list_to_can_capnp(can_sends, msgtype='sendcan').to_bytes()) |
@ -0,0 +1,187 @@ |
|||||||
|
import os |
||||||
|
import time |
||||||
|
from common.realtime import sec_since_boot |
||||||
|
import selfdrive.messaging as messaging |
||||||
|
from selfdrive.car.toyota.carcontroller import CAR |
||||||
|
from selfdrive.can.parser import CANParser |
||||||
|
from selfdrive.config import Conversions as CV |
||||||
|
import numpy as np |
||||||
|
|
||||||
|
def parse_gear_shifter(can_gear, car_fingerprint): |
||||||
|
|
||||||
|
if car_fingerprint == CAR.PRIUS: |
||||||
|
if can_gear == 0x0: |
||||||
|
return "park" |
||||||
|
elif can_gear == 0x1: |
||||||
|
return "reverse" |
||||||
|
elif can_gear == 0x2: |
||||||
|
return "neutral" |
||||||
|
elif can_gear == 0x3: |
||||||
|
return "drive" |
||||||
|
elif can_gear == 0x4: |
||||||
|
return "brake" |
||||||
|
elif car_fingerprint == CAR.RAV4: |
||||||
|
if can_gear == 0x20: |
||||||
|
return "park" |
||||||
|
elif can_gear == 0x10: |
||||||
|
return "reverse" |
||||||
|
elif can_gear == 0x8: |
||||||
|
return "neutral" |
||||||
|
elif can_gear == 0x0: |
||||||
|
return "drive" |
||||||
|
elif can_gear == 0x1: |
||||||
|
return "sport" |
||||||
|
|
||||||
|
return "unknown" |
||||||
|
|
||||||
|
|
||||||
|
def get_can_parser(CP): |
||||||
|
# this function generates lists for signal, messages and initial values |
||||||
|
if CP.carFingerprint == CAR.PRIUS: |
||||||
|
dbc_f = 'toyota_prius_2017_pt.dbc' |
||||||
|
signals = [ |
||||||
|
("GEAR", 295, 0), |
||||||
|
("BRAKE_PRESSED", 550, 0), |
||||||
|
("GAS_PEDAL", 581, 0), |
||||||
|
] |
||||||
|
checks = [ |
||||||
|
(550, 40), |
||||||
|
(581, 33) |
||||||
|
] |
||||||
|
elif CP.carFingerprint == CAR.RAV4: |
||||||
|
dbc_f = 'toyota_rav4_2017_pt.dbc' |
||||||
|
signals = [ |
||||||
|
("GEAR", 956, 0x20), |
||||||
|
("BRAKE_PRESSED", 548, 0), |
||||||
|
("GAS_PEDAL", 705, 0), |
||||||
|
] |
||||||
|
checks = [ |
||||||
|
(548, 40), |
||||||
|
(705, 33) |
||||||
|
] |
||||||
|
|
||||||
|
# TODO: DOORS, GAS_PEDAL, BRAKE_PRESSED for RAV4 |
||||||
|
signals += [ |
||||||
|
# sig_name, sig_address, default |
||||||
|
("WHEEL_SPEED_FL", 170, 0), |
||||||
|
("WHEEL_SPEED_FR", 170, 0), |
||||||
|
("WHEEL_SPEED_RL", 170, 0), |
||||||
|
("WHEEL_SPEED_RR", 170, 0), |
||||||
|
("DOOR_OPEN_FL", 1568, 1), |
||||||
|
("DOOR_OPEN_FR", 1568, 1), |
||||||
|
("DOOR_OPEN_RL", 1568, 1), |
||||||
|
("DOOR_OPEN_RR", 1568, 1), |
||||||
|
("SEATBELT_DRIVER_UNLATCHED", 1568, 1), |
||||||
|
("TC_DISABLED", 951, 1), |
||||||
|
("STEER_ANGLE", 37, 0), |
||||||
|
("STEER_FRACTION", 37, 0), |
||||||
|
("STEER_RATE", 37, 0), |
||||||
|
("GAS_RELEASED", 466, 0), |
||||||
|
("CRUISE_STATE", 466, 0), |
||||||
|
("MAIN_ON", 467, 0), |
||||||
|
("SET_SPEED", 467, 0), |
||||||
|
("LOW_SPEED_LOCKOUT", 467, 0), |
||||||
|
("STEER_TORQUE_DRIVER", 608, 0), |
||||||
|
("STEER_TORQUE_EPS", 608, 0), |
||||||
|
("TURN_SIGNALS", 1556, 3), # 3 is no blinkers |
||||||
|
("LKA_STATE", 610, 0), |
||||||
|
] |
||||||
|
|
||||||
|
checks += [ |
||||||
|
(170, 80), |
||||||
|
(37, 80), |
||||||
|
(466, 33), |
||||||
|
(467, 33), |
||||||
|
(608, 50), |
||||||
|
(610, 25), |
||||||
|
] |
||||||
|
|
||||||
|
return CANParser(os.path.splitext(dbc_f)[0], signals, checks, 0) |
||||||
|
|
||||||
|
|
||||||
|
class CarState(object): |
||||||
|
def __init__(self, CP, logcan): |
||||||
|
|
||||||
|
self.CP = CP |
||||||
|
self.left_blinker_on = 0 |
||||||
|
self.right_blinker_on = 0 |
||||||
|
|
||||||
|
# initialize can parser |
||||||
|
self.cp = get_can_parser(CP) |
||||||
|
self.car_fingerprint = CP.carFingerprint |
||||||
|
|
||||||
|
# vEgo kalman filter |
||||||
|
dt = 0.01 |
||||||
|
self.v_ego_x = np.matrix([[0.0], [0.0]]) |
||||||
|
self.v_ego_A = np.matrix([[1.0, dt], [0.0, 1.0]]) |
||||||
|
self.v_ego_C = np.matrix([1.0, 0.0]) |
||||||
|
self.v_ego_Q = np.matrix([[10.0, 0.0], [0.0, 100.0]]) |
||||||
|
self.v_ego_R = 1e3 |
||||||
|
# import control |
||||||
|
# (x, l, K) = control.dare(np.transpose(A), np.transpose(C), Q, R) |
||||||
|
# self.v_ego_K = np.transpose(K) |
||||||
|
self.v_ego_K = np.matrix([[0.12287673], [0.29666309]]) |
||||||
|
|
||||||
|
def update(self): |
||||||
|
cp = self.cp |
||||||
|
cp.update(int(sec_since_boot() * 1e9), False) |
||||||
|
|
||||||
|
# copy can_valid |
||||||
|
self.can_valid = cp.can_valid |
||||||
|
|
||||||
|
if self.car_fingerprint == CAR.PRIUS: |
||||||
|
can_gear = cp.vl[295]['GEAR'] |
||||||
|
self.brake_pressed = cp.vl[550]['BRAKE_PRESSED'] |
||||||
|
self.pedal_gas = cp.vl[581]['GAS_PEDAL'] |
||||||
|
elif self.car_fingerprint == CAR.RAV4: |
||||||
|
can_gear = cp.vl[956]['GEAR'] |
||||||
|
self.brake_pressed = cp.vl[548]['BRAKE_PRESSED'] |
||||||
|
self.pedal_gas = cp.vl[705]['GAS_PEDAL'] |
||||||
|
|
||||||
|
# update prevs, update must run once per loop |
||||||
|
self.prev_left_blinker_on = self.left_blinker_on |
||||||
|
self.prev_right_blinker_on = self.right_blinker_on |
||||||
|
|
||||||
|
# ******************* parse out can ******************* |
||||||
|
self.door_all_closed = not any([cp.vl[1568]['DOOR_OPEN_FL'], cp.vl[1568]['DOOR_OPEN_FR'], |
||||||
|
cp.vl[1568]['DOOR_OPEN_RL'], cp.vl[1568]['DOOR_OPEN_RR']]) |
||||||
|
self.seatbelt = not cp.vl[1568]['SEATBELT_DRIVER_UNLATCHED'] |
||||||
|
# whitelist instead of blacklist, safer at the expense of disengages |
||||||
|
self.steer_error = False |
||||||
|
self.brake_error = 0 |
||||||
|
self.esp_disabled = cp.vl[951]['TC_DISABLED'] |
||||||
|
# calc best v_ego estimate, by averaging two opposite corners |
||||||
|
self.v_wheel_fl = cp.vl[170]['WHEEL_SPEED_FL'] |
||||||
|
self.v_wheel_fr = cp.vl[170]['WHEEL_SPEED_FR'] |
||||||
|
self.v_wheel_rl = cp.vl[170]['WHEEL_SPEED_RL'] |
||||||
|
self.v_wheel_rr = cp.vl[170]['WHEEL_SPEED_RR'] |
||||||
|
self.v_wheel = ( |
||||||
|
cp.vl[170]['WHEEL_SPEED_FL'] + cp.vl[170]['WHEEL_SPEED_FR'] + |
||||||
|
cp.vl[170]['WHEEL_SPEED_RL'] + cp.vl[170]['WHEEL_SPEED_RR']) / 4. * CV.KPH_TO_MS |
||||||
|
|
||||||
|
# Kalman filter |
||||||
|
self.v_ego_x = np.dot((self.v_ego_A - np.dot(self.v_ego_K, self.v_ego_C)), self.v_ego_x) + np.dot(self.v_ego_K, self.v_wheel) |
||||||
|
self.v_ego_raw = self.v_wheel |
||||||
|
self.v_ego = float(self.v_ego_x[0]) |
||||||
|
self.a_ego = float(self.v_ego_x[1]) |
||||||
|
self.standstill = not self.v_wheel > 0.001 |
||||||
|
|
||||||
|
self.angle_steers = cp.vl[37]['STEER_ANGLE'] + cp.vl[37]['STEER_FRACTION'] |
||||||
|
self.angle_steers_rate = cp.vl[37]['STEER_RATE'] |
||||||
|
self.gear_shifter = parse_gear_shifter(can_gear, self.car_fingerprint) |
||||||
|
self.main_on = cp.vl[467]['MAIN_ON'] |
||||||
|
self.left_blinker_on = cp.vl[1556]['TURN_SIGNALS'] == 1 |
||||||
|
self.right_blinker_on = cp.vl[1556]['TURN_SIGNALS'] == 2 |
||||||
|
|
||||||
|
# we could use the override bit from dbc, but it's triggered at too high torque values |
||||||
|
self.steer_override = abs(cp.vl[608]['STEER_TORQUE_DRIVER']) > 100 |
||||||
|
self.steer_error = cp.vl[610]['LKA_STATE'] == 50 |
||||||
|
self.steer_torque_driver = cp.vl[608]['STEER_TORQUE_DRIVER'] |
||||||
|
self.steer_torque_motor = cp.vl[608]['STEER_TORQUE_EPS'] |
||||||
|
|
||||||
|
self.user_brake = 0 |
||||||
|
self.v_cruise_pcm = cp.vl[467]['SET_SPEED'] |
||||||
|
self.pcm_acc_status = cp.vl[466]['CRUISE_STATE'] |
||||||
|
self.car_gas = self.pedal_gas |
||||||
|
self.gas_pressed = not cp.vl[466]['GAS_RELEASED'] |
||||||
|
self.low_speed_lockout = cp.vl[467]['LOW_SPEED_LOCKOUT'] == 2 |
@ -0,0 +1,246 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
import os |
||||||
|
import time |
||||||
|
import common.numpy_fast as np |
||||||
|
from selfdrive.config import Conversions as CV |
||||||
|
from selfdrive.car.toyota.carstate import CarState, CAR |
||||||
|
from selfdrive.car.toyota.carcontroller import CarController, ECU, check_ecu_msgs |
||||||
|
from cereal import car |
||||||
|
from selfdrive.services import service_list |
||||||
|
import selfdrive.messaging as messaging |
||||||
|
from selfdrive.controls.lib.drive_helpers import EventTypes as ET, create_event |
||||||
|
|
||||||
|
|
||||||
|
class CarInterface(object): |
||||||
|
def __init__(self, CP, logcan, sendcan=None): |
||||||
|
self.logcan = logcan |
||||||
|
self.CP = CP |
||||||
|
|
||||||
|
self.frame = 0 |
||||||
|
self.can_invalid_count = 0 |
||||||
|
self.gas_pressed_prev = False |
||||||
|
self.brake_pressed_prev = False |
||||||
|
self.cruise_enabled_prev = False |
||||||
|
|
||||||
|
# *** init the major players *** |
||||||
|
self.CS = CarState(CP, self.logcan) |
||||||
|
|
||||||
|
# sending if read only is False |
||||||
|
if sendcan is not None: |
||||||
|
self.sendcan = sendcan |
||||||
|
self.CC = CarController(CP.carFingerprint, CP.enableCamera, CP.enableDsu, CP.enableApgs) |
||||||
|
|
||||||
|
@staticmethod |
||||||
|
def get_params(candidate, fingerprint): |
||||||
|
|
||||||
|
# kg of standard extra cargo to count for drive, gas, etc... |
||||||
|
std_cargo = 136 |
||||||
|
|
||||||
|
ret = car.CarParams.new_message() |
||||||
|
|
||||||
|
ret.carName = "toyota" |
||||||
|
ret.radarName = "toyota" |
||||||
|
ret.carFingerprint = candidate |
||||||
|
|
||||||
|
ret.safetyModel = car.CarParams.SafetyModels.toyota |
||||||
|
|
||||||
|
ret.enableSteer = True |
||||||
|
ret.enableBrake = True |
||||||
|
|
||||||
|
# pedal |
||||||
|
ret.enableCruise = True |
||||||
|
|
||||||
|
# FIXME: hardcoding honda civic 2016 touring params so they can be used to |
||||||
|
# scale unknown params for other cars |
||||||
|
m_civic = 2923./2.205 + std_cargo |
||||||
|
l_civic = 2.70 |
||||||
|
aF_civic = l_civic * 0.4 |
||||||
|
aR_civic = l_civic - aF_civic |
||||||
|
j_civic = 2500 |
||||||
|
cF_civic = 85400 |
||||||
|
cR_civic = 90000 |
||||||
|
|
||||||
|
stop_and_go = True |
||||||
|
ret.m = 3045./2.205 + std_cargo |
||||||
|
ret.l = 2.70 |
||||||
|
ret.aF = ret.l * 0.44 |
||||||
|
ret.sR = 14.5 #Rav4 2017, TODO: find exact value for Prius |
||||||
|
if candidate == CAR.PRIUS: |
||||||
|
ret.steerKp, ret.steerKi = 0.2, 0.01 |
||||||
|
elif candidate == CAR.RAV4: # rav4 control seem to be ok with integrators |
||||||
|
ret.steerKp, ret.steerKi = 0.2, 0.05 |
||||||
|
ret.steerKf = 0.00007818594 # full torque for 10 deg at 80mph |
||||||
|
|
||||||
|
# min speed to enable ACC. if car can do stop and go, then set enabling speed |
||||||
|
# to a negative value, so it won't matter. |
||||||
|
if candidate == CAR.PRIUS: |
||||||
|
ret.minEnableSpeed = -1. |
||||||
|
elif candidate == CAR.RAV4: # TODO: hack Rav4 to do stop and go |
||||||
|
ret.minEnableSpeed = 19. * CV.MPH_TO_MS |
||||||
|
|
||||||
|
ret.aR = ret.l - ret.aF |
||||||
|
# TODO: get actual value, for now starting with reasonable value for |
||||||
|
# civic and scaling by mass and wheelbase |
||||||
|
ret.j = j_civic * ret.m * ret.l**2 / (m_civic * l_civic**2) |
||||||
|
|
||||||
|
# TODO: start from empirically derived lateral slip stiffness for the civic and scale by |
||||||
|
# mass and CG position, so all cars will have approximately similar dyn behaviors |
||||||
|
ret.cF = cF_civic * ret.m / m_civic * (ret.aR / ret.l) / (aR_civic / l_civic) |
||||||
|
ret.cR = cR_civic * ret.m / m_civic * (ret.aF / ret.l) / (aF_civic / l_civic) |
||||||
|
|
||||||
|
# no rear steering, at least on the listed cars above |
||||||
|
ret.chi = 0. |
||||||
|
|
||||||
|
# steer, gas, brake limitations VS speed |
||||||
|
ret.steerMaxBP = [16. * CV.KPH_TO_MS, 45. * CV.KPH_TO_MS] # breakpoints at 1 and 40 kph |
||||||
|
ret.steerMaxV = [1., 1.] # 2/3rd torque allowed above 45 kph |
||||||
|
ret.gasMaxBP = [0.] |
||||||
|
ret.gasMaxV = [0.5] |
||||||
|
ret.brakeMaxBP = [5., 20.] |
||||||
|
ret.brakeMaxV = [1., 0.8] |
||||||
|
|
||||||
|
ret.enableCamera = not check_ecu_msgs(fingerprint, candidate, ECU.CAM) |
||||||
|
ret.enableDsu = not check_ecu_msgs(fingerprint, candidate, ECU.DSU) |
||||||
|
ret.enableApgs = False # not check_ecu_msgs(fingerprint, candidate, ECU.APGS) |
||||||
|
print "ECU Camera Simulated: ", ret.enableCamera |
||||||
|
print "ECU DSU Simulated: ", ret.enableDsu |
||||||
|
print "ECU APGS Simulated: ", ret.enableApgs |
||||||
|
ret.enableGas = True |
||||||
|
|
||||||
|
ret.steerLimitAlert = False |
||||||
|
|
||||||
|
return ret |
||||||
|
|
||||||
|
@staticmethod |
||||||
|
def compute_gb(accel, speed): |
||||||
|
# toyota interface is already in accelration cmd, so conversion to gas-brake it's a pass-through. |
||||||
|
return accel |
||||||
|
|
||||||
|
# returns a car.CarState |
||||||
|
def update(self, c): |
||||||
|
# ******************* do can recv ******************* |
||||||
|
can_pub_main = [] |
||||||
|
canMonoTimes = [] |
||||||
|
|
||||||
|
self.CS.update() |
||||||
|
|
||||||
|
# create message |
||||||
|
ret = car.CarState.new_message() |
||||||
|
|
||||||
|
# speeds |
||||||
|
ret.vEgo = self.CS.v_ego |
||||||
|
ret.vEgoRaw = self.CS.v_ego_raw |
||||||
|
ret.aEgo = self.CS.a_ego |
||||||
|
ret.standstill = self.CS.standstill |
||||||
|
ret.wheelSpeeds.fl = self.CS.v_wheel_fl |
||||||
|
ret.wheelSpeeds.fr = self.CS.v_wheel_fr |
||||||
|
ret.wheelSpeeds.rl = self.CS.v_wheel_rl |
||||||
|
ret.wheelSpeeds.rr = self.CS.v_wheel_rr |
||||||
|
|
||||||
|
# gear shifter |
||||||
|
ret.gearShifter = self.CS.gear_shifter |
||||||
|
|
||||||
|
# gas pedal |
||||||
|
ret.gas = self.CS.car_gas / 256.0 |
||||||
|
ret.gasPressed = self.CS.pedal_gas > 0 |
||||||
|
|
||||||
|
# brake pedal |
||||||
|
ret.brake = self.CS.user_brake |
||||||
|
ret.brakePressed = self.CS.brake_pressed != 0 |
||||||
|
|
||||||
|
# steering wheel |
||||||
|
ret.steeringAngle = self.CS.angle_steers |
||||||
|
ret.steeringRate = self.CS.angle_steers_rate |
||||||
|
|
||||||
|
ret.steeringTorque = 0 |
||||||
|
ret.steeringPressed = self.CS.steer_override |
||||||
|
|
||||||
|
# cruise state |
||||||
|
ret.cruiseState.enabled = self.CS.pcm_acc_status != 0 |
||||||
|
ret.cruiseState.speed = self.CS.v_cruise_pcm * CV.KPH_TO_MS |
||||||
|
ret.cruiseState.available = bool(self.CS.main_on) |
||||||
|
ret.cruiseState.speedOffset = 0. |
||||||
|
|
||||||
|
# TODO: button presses |
||||||
|
buttonEvents = [] |
||||||
|
|
||||||
|
if self.CS.left_blinker_on != self.CS.prev_left_blinker_on: |
||||||
|
be = car.CarState.ButtonEvent.new_message() |
||||||
|
be.type = 'leftBlinker' |
||||||
|
be.pressed = self.CS.left_blinker_on != 0 |
||||||
|
buttonEvents.append(be) |
||||||
|
|
||||||
|
if self.CS.right_blinker_on != self.CS.prev_right_blinker_on: |
||||||
|
be = car.CarState.ButtonEvent.new_message() |
||||||
|
be.type = 'rightBlinker' |
||||||
|
be.pressed = self.CS.right_blinker_on != 0 |
||||||
|
buttonEvents.append(be) |
||||||
|
|
||||||
|
ret.buttonEvents = buttonEvents |
||||||
|
|
||||||
|
# events |
||||||
|
events = [] |
||||||
|
if not self.CS.can_valid: |
||||||
|
self.can_invalid_count += 1 |
||||||
|
if self.can_invalid_count >= 5: |
||||||
|
events.append(create_event('commIssue', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE])) |
||||||
|
else: |
||||||
|
self.can_invalid_count = 0 |
||||||
|
if not ret.gearShifter == 'drive' and self.CP.enableDsu: |
||||||
|
events.append(create_event('wrongGear', [ET.NO_ENTRY, ET.SOFT_DISABLE])) |
||||||
|
if not self.CS.door_all_closed: |
||||||
|
events.append(create_event('doorOpen', [ET.NO_ENTRY, ET.SOFT_DISABLE])) |
||||||
|
if not self.CS.seatbelt: |
||||||
|
events.append(create_event('seatbeltNotLatched', [ET.NO_ENTRY, ET.SOFT_DISABLE])) |
||||||
|
if self.CS.esp_disabled and self.CP.enableDsu: |
||||||
|
events.append(create_event('espDisabled', [ET.NO_ENTRY, ET.SOFT_DISABLE])) |
||||||
|
if not self.CS.main_on and self.CP.enableDsu: |
||||||
|
events.append(create_event('wrongCarMode', [ET.NO_ENTRY, ET.USER_DISABLE])) |
||||||
|
if ret.gearShifter == 'reverse' and self.CP.enableDsu: |
||||||
|
events.append(create_event('reverseGear', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE])) |
||||||
|
if self.CS.steer_error: |
||||||
|
events.append(create_event('steerTempUnavailable', [ET.NO_ENTRY, ET.WARNING])) |
||||||
|
if self.CS.low_speed_lockout: |
||||||
|
events.append(create_event('lowSpeedLockout', [ET.NO_ENTRY])) |
||||||
|
if ret.vEgo < self.CP.minEnableSpeed and self.CP.enableDsu: |
||||||
|
events.append(create_event('speedTooLow', [ET.NO_ENTRY])) |
||||||
|
if c.actuators.gas > 0.1: |
||||||
|
# some margin on the actuator to not false trigger cancellation while stopping |
||||||
|
events.append(create_event('speedTooLow', [ET.IMMEDIATE_DISABLE])) |
||||||
|
if ret.vEgo < 0.001: |
||||||
|
# while in standstill, send a user alert |
||||||
|
events.append(create_event('manualRestart', [ET.WARNING])) |
||||||
|
|
||||||
|
# enable request in prius is simple, as we activate when Toyota is active (rising edge) |
||||||
|
if ret.cruiseState.enabled and not self.cruise_enabled_prev: |
||||||
|
events.append(create_event('pcmEnable', [ET.ENABLE])) |
||||||
|
elif not ret.cruiseState.enabled: |
||||||
|
events.append(create_event('pcmDisable', [ET.USER_DISABLE])) |
||||||
|
|
||||||
|
# disable on pedals rising edge or when brake is pressed and speed isn't zero |
||||||
|
if (ret.gasPressed and not self.gas_pressed_prev) or \ |
||||||
|
(ret.brakePressed and (not self.brake_pressed_prev or ret.vEgo > 0.001)): |
||||||
|
events.append(create_event('pedalPressed', [ET.NO_ENTRY, ET.USER_DISABLE])) |
||||||
|
|
||||||
|
if ret.gasPressed: |
||||||
|
events.append(create_event('pedalPressed', [ET.PRE_ENABLE])) |
||||||
|
|
||||||
|
ret.events = events |
||||||
|
ret.canMonoTimes = canMonoTimes |
||||||
|
|
||||||
|
self.gas_pressed_prev = ret.gasPressed |
||||||
|
self.brake_pressed_prev = ret.brakePressed |
||||||
|
self.cruise_enabled_prev = ret.cruiseState.enabled |
||||||
|
|
||||||
|
return ret.as_reader() |
||||||
|
|
||||||
|
# pass in a car.CarControl |
||||||
|
# to be called @ 100hz |
||||||
|
def apply(self, c): |
||||||
|
|
||||||
|
self.CC.update(self.sendcan, c.enabled, self.CS, self.frame, |
||||||
|
c.actuators, c.cruiseControl.cancel, c.hudControl.visualAlert, |
||||||
|
c.hudControl.audibleAlert) |
||||||
|
|
||||||
|
self.frame += 1 |
||||||
|
return False |
@ -0,0 +1,83 @@ |
|||||||
|
import struct |
||||||
|
import common.numpy_fast as np |
||||||
|
from selfdrive.config import Conversions as CV |
||||||
|
|
||||||
|
|
||||||
|
# *** Toyota specific *** |
||||||
|
|
||||||
|
def fix(msg, addr): |
||||||
|
checksum = 0 |
||||||
|
idh = (addr & 0xff00) >> 8 |
||||||
|
idl = (addr & 0xff) |
||||||
|
|
||||||
|
checksum = idh + idl + len(msg) + 1 |
||||||
|
for d_byte in msg: |
||||||
|
checksum += ord(d_byte) |
||||||
|
|
||||||
|
#return msg + chr(checksum & 0xFF) |
||||||
|
return msg + struct.pack("B", checksum & 0xFF) |
||||||
|
|
||||||
|
|
||||||
|
def make_can_msg(addr, dat, alt, cks=False): |
||||||
|
if cks: |
||||||
|
dat = fix(dat, addr) |
||||||
|
return [addr, 0, dat, alt] |
||||||
|
|
||||||
|
|
||||||
|
def create_video_target(frame, addr): |
||||||
|
counter = frame & 0xff |
||||||
|
msg = struct.pack("!BBBBBBB", counter, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00) |
||||||
|
return make_can_msg(addr, msg, 1, True) |
||||||
|
|
||||||
|
|
||||||
|
def create_ipas_steer_command(steer): |
||||||
|
|
||||||
|
"""Creates a CAN message for the Toyota Steer Command.""" |
||||||
|
if steer < 0: |
||||||
|
move = 0x60 |
||||||
|
steer = 0xfff + steer + 1 |
||||||
|
elif steer > 0: |
||||||
|
move = 0x20 |
||||||
|
else: |
||||||
|
move = 0x40 |
||||||
|
|
||||||
|
mode = 0x30 if steer else 0x10 |
||||||
|
|
||||||
|
steer_h = (steer & 0xF00) >> 8 |
||||||
|
steer_l = steer & 0xff |
||||||
|
|
||||||
|
msg = struct.pack("!BBBBBBB", mode | steer_h, steer_l, 0x10, 0x00, move, 0x40, 0x00) |
||||||
|
|
||||||
|
return make_can_msg(0x266, msg, 0, True) |
||||||
|
|
||||||
|
def create_steer_command(steer, raw_cnt): |
||||||
|
"""Creates a CAN message for the Toyota Steer Command.""" |
||||||
|
# from 0x80 to 0xff |
||||||
|
counter = ((raw_cnt & 0x3f) << 1) | 0x80 |
||||||
|
if steer != 0: |
||||||
|
counter |= 1 |
||||||
|
|
||||||
|
# hud |
||||||
|
# 00 => Regular |
||||||
|
# 40 => Actively Steering (with beep) |
||||||
|
# 80 => Actively Steering (without beep) |
||||||
|
hud = 0x00 |
||||||
|
|
||||||
|
msg = struct.pack("!BhB", counter, steer, hud) |
||||||
|
|
||||||
|
return make_can_msg(0x2e4, msg, 0, True) |
||||||
|
|
||||||
|
|
||||||
|
def create_accel_command(accel, pcm_cancel): |
||||||
|
# TODO: find the exact canceling bit |
||||||
|
state = 0xc0 + pcm_cancel # this allows automatic restart from hold without driver cmd |
||||||
|
|
||||||
|
msg = struct.pack("!hBBBBB", accel, 0x63, state, 0x00, 0x00, 0x00) |
||||||
|
|
||||||
|
return make_can_msg(0x343, msg, 0, True) |
||||||
|
|
||||||
|
|
||||||
|
def create_ui_command(hud1, hud2): |
||||||
|
msg = struct.pack('!BBBBBBBB', 0x54, 0x04 + hud1 + (hud2 << 4), 0x0C, |
||||||
|
0x00, 0x00, 0x2C, 0x38, 0x02) |
||||||
|
return make_can_msg(0x412, msg, 0, False) |
@ -1 +1 @@ |
|||||||
#define OPENPILOT_VERSION "0.3.7" |
#define COMMA_VERSION "0.3.8.2-openpilot" |
||||||
|
Binary file not shown.
@ -0,0 +1,13 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# simple boardd wrapper that updates the panda first |
||||||
|
import os |
||||||
|
from panda import ensure_st_up_to_date |
||||||
|
|
||||||
|
def main(gctx=None): |
||||||
|
ensure_st_up_to_date() |
||||||
|
|
||||||
|
os.chdir("boardd") |
||||||
|
os.execvp("./boardd", ["./boardd"]) |
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
main() |
@ -0,0 +1,81 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
import os |
||||||
|
import numpy as np |
||||||
|
from selfdrive.can.parser import CANParser |
||||||
|
from cereal import car |
||||||
|
from common.realtime import sec_since_boot |
||||||
|
import zmq |
||||||
|
from selfdrive.services import service_list |
||||||
|
import selfdrive.messaging as messaging |
||||||
|
|
||||||
|
def _create_radard_can_parser(): |
||||||
|
dbc_f = 'toyota_prius_2017_adas.dbc' |
||||||
|
radar_messages = range(0x210, 0x220) |
||||||
|
msg_n = len(radar_messages) |
||||||
|
msg_last = radar_messages[-1] |
||||||
|
signals = zip(['LONG_DIST'] * msg_n + ['NEW_TRACK'] * msg_n + ['LAT_DIST'] * msg_n + |
||||||
|
['REL_SPEED'] * msg_n + ['VALID'] * msg_n, |
||||||
|
radar_messages * 5, |
||||||
|
[255] * msg_n + [1] * msg_n + [0] * msg_n + [0] * msg_n + [0] * msg_n) |
||||||
|
checks = zip(radar_messages, [20]*msg_n) |
||||||
|
|
||||||
|
return CANParser(os.path.splitext(dbc_f)[0], signals, checks, 1) |
||||||
|
|
||||||
|
class RadarInterface(object): |
||||||
|
def __init__(self): |
||||||
|
# radar |
||||||
|
self.pts = {} |
||||||
|
self.track_id = 0 |
||||||
|
|
||||||
|
self.delay = 0.0 # Delay of radar |
||||||
|
|
||||||
|
# Nidec |
||||||
|
self.rcp = _create_radard_can_parser() |
||||||
|
|
||||||
|
context = zmq.Context() |
||||||
|
self.logcan = messaging.sub_sock(context, service_list['can'].port) |
||||||
|
|
||||||
|
def update(self): |
||||||
|
canMonoTimes = [] |
||||||
|
|
||||||
|
updated_messages = set() |
||||||
|
while 1: |
||||||
|
tm = int(sec_since_boot() * 1e9) |
||||||
|
updated_messages.update(self.rcp.update(tm, True)) |
||||||
|
# TODO: use msg_last |
||||||
|
if 0x21f in updated_messages: |
||||||
|
break |
||||||
|
|
||||||
|
ret = car.RadarState.new_message() |
||||||
|
errors = [] |
||||||
|
if not self.rcp.can_valid: |
||||||
|
errors.append("commIssue") |
||||||
|
ret.errors = errors |
||||||
|
ret.canMonoTimes = canMonoTimes |
||||||
|
#print "NEW TRACKS" |
||||||
|
for ii in updated_messages: |
||||||
|
cpt = self.rcp.vl[ii] |
||||||
|
if cpt['LONG_DIST'] < 255 and cpt['VALID']: |
||||||
|
#print "%5s %5s %5s" % (round(cpt['LONG_DIST'], 1), round(cpt['LAT_DIST'], 1), round(cpt['REL_SPEED'], 1)) |
||||||
|
if ii not in self.pts or cpt['NEW_TRACK']: |
||||||
|
self.pts[ii] = car.RadarState.RadarPoint.new_message() |
||||||
|
self.pts[ii].trackId = self.track_id |
||||||
|
self.track_id += 1 |
||||||
|
self.pts[ii].dRel = cpt['LONG_DIST'] # from front of car |
||||||
|
self.pts[ii].yRel = -cpt['LAT_DIST'] # in car frame's y axis, left is positive |
||||||
|
self.pts[ii].vRel = cpt['REL_SPEED'] |
||||||
|
self.pts[ii].aRel = float('nan') |
||||||
|
self.pts[ii].yvRel = float('nan') |
||||||
|
else: |
||||||
|
if ii in self.pts: |
||||||
|
del self.pts[ii] |
||||||
|
|
||||||
|
ret.points = self.pts.values() |
||||||
|
return ret |
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
RI = RadarInterface() |
||||||
|
while 1: |
||||||
|
ret = RI.update() |
||||||
|
print(chr(27) + "[2J") |
||||||
|
print ret |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,29 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
|
||||||
|
# simple service that waits for network access and tries to update every 3 hours |
||||||
|
|
||||||
|
import os |
||||||
|
import time |
||||||
|
import subprocess |
||||||
|
|
||||||
|
def main(gctx=None): |
||||||
|
if not os.getenv("CLEAN"): |
||||||
|
return |
||||||
|
|
||||||
|
while True: |
||||||
|
# try network |
||||||
|
r = subprocess.call(["ping", "-W", "4", "-c", "1", "8.8.8.8"]) |
||||||
|
if r: |
||||||
|
time.sleep(60) |
||||||
|
continue |
||||||
|
|
||||||
|
# try fetch |
||||||
|
r = subprocess.call(["nice", "-n", "19", "git", "fetch", "--depth=1"]) |
||||||
|
if r: |
||||||
|
time.sleep(60) |
||||||
|
continue |
||||||
|
|
||||||
|
time.sleep(60*60*3) |
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
main() |
Binary file not shown.
Loading…
Reference in new issue