Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Synchronize controls with the CAN bus #547

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
845508b
fixed max torque, for more actual torque
Gernby Jan 10, 2019
5443792
Delete visiond
Gernby Jan 10, 2019
504f750
0.5.6 visiond
Gernby Jan 10, 2019
baa7b73
Merge branch 'devel' of https://github.com/Gernby/openpilot into devel
Gernby Jan 16, 2019
6d737ca
Merge branch 'devel' of https://github.com/commaa/openpilot into
Gernby Feb 5, 2019
167ef82
Merge fix
Gernby Feb 5, 2019
4ed0725
another merge fix
Gernby Feb 5, 2019
17a5c7b
Update README.md
Gernby Feb 16, 2019
4f8dd77
Update README.md
Gernby Feb 16, 2019
3a49dac
added sftp
Gernby Feb 22, 2019
73c8877
Merge branch 'devel' of https://github.com/commaai/openpilot into devel
Gernby Feb 22, 2019
e57a9ac
configuring git
Gernby Feb 22, 2019
4712458
Merge branch 'devel' of https://github.com/Gernby/openpilot into deve
Gernby Feb 22, 2019
5a0aae3
git config
Gernby Feb 22, 2019
9e28ef9
git config
Gernby Feb 22, 2019
4101ddc
Update README.md
Gernby Feb 22, 2019
a1819ea
git config
Gernby Feb 22, 2019
2ea0602
Merge branch 'devel' of https://github.com/gernby/openpilot into devel
Gernby Feb 22, 2019
eef45dc
Merge branch 'devel' of https://github.com/Gernby/openpilot into devel
Gernby Feb 22, 2019
2629080
git config
Gernby Feb 22, 2019
e7c52d5
Merge branch 'devel' of https://github.com/gernby/openpilot into devel
Gernby Feb 22, 2019
031996f
git cleanup
Gernby Feb 22, 2019
64cd45f
gitignore
Gernby Feb 22, 2019
db34d8c
ignore visiond
Gernby Mar 1, 2019
da84d41
preparing for PRpreparing for PR
Gernby Mar 4, 2019
dbe8a75
added syncID for Accord
Gernby Mar 4, 2019
ffd8c3a
more refinements for PR
Gernby Mar 4, 2019
1412a60
fixed a couple cleanup mistakes
Gernby Mar 4, 2019
36de288
another cleanup fixanother cleanup fix
Gernby Mar 4, 2019
104c4a8
fixed some cleanup mistakes.
Gernby Mar 4, 2019
3c96b40
Fixed issue with thermald between drives
Gernby Mar 5, 2019
52ae8fe
fixed sync issue with extended drives
Gernby Mar 21, 2019
4017b1d
merge fixes
Gernby Mar 21, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cereal/car.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ struct CarParams {
steerRateCost @40 :Float32; # Lateral MPC cost on steering rate
steerControlType @46 :SteerControlType;
radarOffCan @47 :Bool; # True when radar objects aren't visible on CAN
syncID @51 :Int16; # SyncID is optional

steerActuatorDelay @48 :Float32; # Steering wheel actuator delay in seconds
openpilotLongitudinalControl @50 :Bool; # is openpilot doing the longitudinal control?
Expand Down
176 changes: 145 additions & 31 deletions selfdrive/boardd/boardd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ pthread_t safety_setter_thread_handle = -1;
pthread_t pigeon_thread_handle = -1;
bool pigeon_needs_init;

int big_recv;
uint32_t big_data[RECV_SIZE*2];
uint16_t sync_id;

void pigeon_init();
void *pigeon_thread(void *crap);

Expand All @@ -90,7 +94,8 @@ void *safety_setter_thread(void *s) {

auto safety_model = car_params.getSafetyModel();
auto safety_param = car_params.getSafetyParam();
LOGW("setting safety model: %d with param %d", safety_model, safety_param);
sync_id = car_params.getSyncID();
LOGW("setting safety model: %d with param %d and sync id %d", safety_model, safety_param, sync_id);

int safety_setting = 0;
switch (safety_model) {
Expand Down Expand Up @@ -212,15 +217,23 @@ void handle_usb_issue(int err, const char func[]) {
// TODO: check other errors, is simply retrying okay?
}

void can_recv(void *s) {
bool can_recv(void *s, uint64_t locked_wake_time, bool force_send) {
int err;
uint32_t data[RECV_SIZE/4];
int recv;
uint32_t f1, f2;
int recv, big_index;
uint32_t f1, f2, address;
bool frame_sent;
uint64_t cur_time;
frame_sent = false;

// do recv
pthread_mutex_lock(&usb_lock);

cur_time = 1e-3 * nanos_since_boot();
if (locked_wake_time > cur_time) {
// Short sleep occurs after usb_lock to ensure sync timing
usleep(locked_wake_time - cur_time);
}
do {
err = libusb_bulk_transfer(dev_handle, 0x81, (uint8_t*)data, RECV_SIZE, &recv, TIMEOUT);
if (err != 0) { handle_usb_issue(err, __func__); }
Expand All @@ -232,38 +245,61 @@ void can_recv(void *s) {

pthread_mutex_unlock(&usb_lock);

// return if length is 0
if (recv <= 0) {
return;
// return if both buffers are empty
if ((big_recv <= 0) && (recv <= 0)) {
return true;
}

// create message
capnp::MallocMessageBuilder msg;
cereal::Event::Builder event = msg.initRoot<cereal::Event>();
event.setLogMonoTime(nanos_since_boot());

auto canData = event.initCan(recv/0x10);

// populate message
big_index = big_recv/0x10;
for (int i = 0; i<(recv/0x10); i++) {
big_data[(big_index + i)*4] = data[i*4];
big_data[(big_index + i)*4+1] = data[i*4+1];
big_data[(big_index + i)*4+2] = data[i*4+2];
big_data[(big_index + i)*4+3] = data[i*4+3];
big_recv += 0x10;
if (data[i*4] & 4) {
// extended
canData[i].setAddress(data[i*4] >> 3);
//printf("got extended: %x\n", data[i*4] >> 3);
address = data[i*4] >> 3;
//printf("got extended: %x\n", big_data[i*4] >> 3);
} else {
// normal
canData[i].setAddress(data[i*4] >> 21);
address = data[i*4] >> 21;
}
canData[i].setBusTime(data[i*4+1] >> 16);
int len = data[i*4+1]&0xF;
canData[i].setDat(kj::arrayPtr((uint8_t*)&data[i*4+2], len));
canData[i].setSrc((data[i*4+1] >> 4) & 0xff);
if (address == sync_id) force_send = true;
}
if (force_send) {
frame_sent = true;

// send to can
auto words = capnp::messageToFlatArray(msg);
auto bytes = words.asBytes();
zmq_send(s, bytes.begin(), bytes.size(), 0);
capnp::MallocMessageBuilder msg;
cereal::Event::Builder event = msg.initRoot<cereal::Event>();
event.setLogMonoTime(nanos_since_boot());

auto can_data = event.initCan(big_recv/0x10);

// populate message
for (int i = 0; i<(big_recv/0x10); i++) {
if (big_data[i*4] & 4) {
// extended
can_data[i].setAddress(big_data[i*4] >> 3);
//printf("got extended: %x\n", big_data[i*4] >> 3);
} else {
// normal
can_data[i].setAddress(big_data[i*4] >> 21);
}
can_data[i].setBusTime(big_data[i*4+1] >> 16);
int len = big_data[i*4+1]&0xF;
can_data[i].setDat(kj::arrayPtr((uint8_t*)&big_data[i*4+2], len));
can_data[i].setSrc((big_data[i*4+1] >> 4) & 0xff);
}

// send to can
auto words = capnp::messageToFlatArray(msg);
auto bytes = words.asBytes();
zmq_send(s, bytes.begin(), bytes.size(), 0);
big_recv = 0;
}

return frame_sent;
}

void can_health(void *s) {
Expand Down Expand Up @@ -447,11 +483,89 @@ void *can_recv_thread(void *crap) {
void *publisher = zmq_socket(context, ZMQ_PUB);
zmq_bind(publisher, "tcp://*:8006");

// run at ~200hz
bool frame_sent, skip_once, force_send;
uint64_t wake_time, locked_wake_time, last_long_sleep;
int recv_state = 0;
force_send = true;
last_long_sleep = 1e-3 * nanos_since_boot();
wake_time = last_long_sleep;
locked_wake_time = wake_time;

while (!do_exit) {
can_recv(publisher);
// 5ms
usleep(5*1000);
while (sync_id > 0 && !do_exit) {
frame_sent = can_recv(publisher, locked_wake_time, force_send);

// drain the Panda twice at 4.5ms intervals, then once at 1.0ms interval (twice max if sync_id is set)
if (frame_sent == true || skip_once == true) {
last_long_sleep = 1e-3 * nanos_since_boot();
skip_once = frame_sent;
wake_time += 4500;
force_send = false;
if (last_long_sleep < wake_time) {
usleep(wake_time - last_long_sleep);
}
else {
if ((last_long_sleep - wake_time) > 5e5) {
// probably a new drive
wake_time = last_long_sleep;
}
else {
if (skip_once) {
wake_time += 4500;
skip_once = false;
if (last_long_sleep < wake_time) {
usleep(wake_time - last_long_sleep);
}
else {
printf(" lagging sync %d \n", sync_id);
}
}
}
}
}
else {
//force_send = (locked_wake_time > last_long_sleep);
wake_time += 1000;
locked_wake_time = wake_time;
}
}
while (sync_id == 0 && !do_exit) {
frame_sent = can_recv(publisher, locked_wake_time, force_send);

// drain the Panda twice at 4.5ms intervals, then once at 1.0ms interval (twice max if sync_id is set)
if (recv_state++ < 2) {
last_long_sleep = 1e-3 * nanos_since_boot();
wake_time += 4500;
force_send = false;
if (last_long_sleep < wake_time) {
usleep(wake_time - last_long_sleep);
}
else {
if ((last_long_sleep - wake_time) > 5e5) {
// probably a new drive
wake_time = last_long_sleep;
}
else {
if (recv_state < 2) {
wake_time += 4500;
recv_state++;
if (last_long_sleep < wake_time) {
usleep(wake_time - last_long_sleep);
}
else {
printf(" lagging!\n");
}
}
}
}
}
else {
force_send = true;
recv_state = 0;
wake_time += 1000;
locked_wake_time = wake_time;
}
}
}
return NULL;
}
Expand Down Expand Up @@ -635,7 +749,7 @@ int main() {
LOGW("starting boardd");

// set process priority
err = set_realtime_priority(4);
err = set_realtime_priority(3);
LOG("setpriority returns %d", err);

// check the environment
Expand Down
11 changes: 8 additions & 3 deletions selfdrive/can/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -303,15 +303,19 @@ class CANParser {

// multiple recv is fine
bool first = wait;
while (1) {
while (first || drain) {
if (first) {
err = zmq_msg_recv(&msg, subscriber, 0);
first = false;
} else {
// Drain the queue at startup
usleep(500);
err = zmq_msg_recv(&msg, subscriber, ZMQ_DONTWAIT);
}
if (err < 0) break;

if (err < 0) {
drain = false;
break;
}
// format for board, make copy due to alignment issues, will be freed on out of scope
auto amsg = kj::heapArray<capnp::word>((zmq_msg_size(&msg) / sizeof(capnp::word)) + 1);
memcpy(amsg.begin(), zmq_msg_data(&msg), zmq_msg_size(&msg));
Expand Down Expand Up @@ -355,6 +359,7 @@ class CANParser {

private:
const int bus;
bool drain = true;
// zmq vars
void *context = NULL;
void *subscriber = NULL;
Expand Down
2 changes: 1 addition & 1 deletion selfdrive/car/chrysler/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def update(self, c):
# ******************* do can recv *******************
canMonoTimes = []

self.cp.update(int(sec_since_boot() * 1e9), False)
self.cp.update(int(sec_since_boot() * 1e9), True)

self.CS.update(self.cp)

Expand Down
2 changes: 1 addition & 1 deletion selfdrive/car/ford/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def update(self, c):
# ******************* do can recv *******************
canMonoTimes = []

self.cp.update(int(sec_since_boot() * 1e9), False)
self.cp.update(int(sec_since_boot() * 1e9), True)

self.CS.update(self.cp)

Expand Down
2 changes: 1 addition & 1 deletion selfdrive/car/gm/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def get_params(candidate, fingerprint):
# returns a car.CarState
def update(self, c):

self.pt_cp.update(int(sec_since_boot() * 1e9), False)
self.pt_cp.update(int(sec_since_boot() * 1e9), True)
self.CS.update(self.pt_cp)

# create message
Expand Down
11 changes: 10 additions & 1 deletion selfdrive/car/honda/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ def get_params(candidate, fingerprint):
ret.centerToFront = centerToFront_civic
ret.steerRatio = 14.63 # 10.93 is end-to-end spec
tire_stiffness_factor = 1.
ret.syncID = 330
# Civic at comma has modified steering FW, so different tuning for the Neo in that car
is_fw_modified = os.getenv("DONGLE_ID") in ['99c94dc769b5d96e']
ret.steerKpV, ret.steerKiV = [[0.4], [0.12]] if is_fw_modified else [[0.8], [0.24]]
Expand All @@ -214,6 +215,7 @@ def get_params(candidate, fingerprint):
ret.centerToFront = ret.wheelbase * 0.39
ret.steerRatio = 15.96 # 11.82 is spec end-to-end
tire_stiffness_factor = 0.8467
ret.syncID = 330
ret.steerKpV, ret.steerKiV = [[0.6], [0.18]]
ret.longitudinalKpBP = [0., 5., 35.]
ret.longitudinalKpV = [1.2, 0.8, 0.5]
Expand All @@ -224,6 +226,7 @@ def get_params(candidate, fingerprint):
stop_and_go = False
ret.mass = 3095 * CV.LB_TO_KG + std_cargo
ret.wheelbase = 2.67
ret.syncID = 342
ret.centerToFront = ret.wheelbase * 0.37
ret.steerRatio = 18.61 # 15.3 is spec end-to-end
tire_stiffness_factor = 0.72
Expand All @@ -237,6 +240,7 @@ def get_params(candidate, fingerprint):
stop_and_go = False
ret.mass = 3572 * CV.LB_TO_KG + std_cargo
ret.wheelbase = 2.62
ret.syncID = 330
ret.centerToFront = ret.wheelbase * 0.41
ret.steerRatio = 15.3 # as spec
tire_stiffness_factor = 0.444 # not optimized yet
Expand All @@ -248,6 +252,7 @@ def get_params(candidate, fingerprint):

elif candidate == CAR.CRV_5G:
stop_and_go = True
ret.syncID = 342
ret.safetyParam = 1 # Accord and CRV 5G use an alternate user brake msg
ret.mass = 3410. * CV.LB_TO_KG + std_cargo
ret.wheelbase = 2.66
Expand All @@ -264,6 +269,7 @@ def get_params(candidate, fingerprint):
stop_and_go = False
ret.mass = 3935 * CV.LB_TO_KG + std_cargo
ret.wheelbase = 2.68
ret.syncID = 342
ret.centerToFront = ret.wheelbase * 0.38
ret.steerRatio = 15.0 # as spec
tire_stiffness_factor = 0.444 # not optimized yet
Expand All @@ -277,6 +283,7 @@ def get_params(candidate, fingerprint):
stop_and_go = False
ret.mass = 4471 * CV.LB_TO_KG + std_cargo
ret.wheelbase = 3.00
ret.syncID = 342
ret.centerToFront = ret.wheelbase * 0.41
ret.steerRatio = 14.35 # as spec
tire_stiffness_factor = 0.82
Expand All @@ -290,6 +297,7 @@ def get_params(candidate, fingerprint):
stop_and_go = False
ret.mass = 4303 * CV.LB_TO_KG + std_cargo
ret.wheelbase = 2.81
ret.syncID = 342
ret.centerToFront = ret.wheelbase * 0.41
ret.steerRatio = 16.0 # as spec
tire_stiffness_factor = 0.444 # not optimized yet
Expand All @@ -302,6 +310,7 @@ def get_params(candidate, fingerprint):
elif candidate == CAR.RIDGELINE:
stop_and_go = False
ret.mass = 4515 * CV.LB_TO_KG + std_cargo
ret.syncID = 342
ret.wheelbase = 3.18
ret.centerToFront = ret.wheelbase * 0.41
ret.steerRatio = 15.59 # as spec
Expand Down Expand Up @@ -366,7 +375,7 @@ def update(self, c):
# ******************* do can recv *******************
canMonoTimes = []

self.cp.update(int(sec_since_boot() * 1e9), False)
self.cp.update(int(sec_since_boot() * 1e9), True)
self.cp_cam.update(int(sec_since_boot() * 1e9), False)

self.CS.update(self.cp, self.cp_cam)
Expand Down
2 changes: 1 addition & 1 deletion selfdrive/car/hyundai/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def get_params(candidate, fingerprint):
def update(self, c):
# ******************* do can recv *******************
canMonoTimes = []
self.cp.update(int(sec_since_boot() * 1e9), False)
self.cp.update(int(sec_since_boot() * 1e9), True)
self.cp_cam.update(int(sec_since_boot() * 1e9), False)
self.CS.update(self.cp, self.cp_cam)
# create message
Expand Down
2 changes: 1 addition & 1 deletion selfdrive/car/toyota/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def update(self, c):
# ******************* do can recv *******************
canMonoTimes = []

self.cp.update(int(sec_since_boot() * 1e9), False)
self.cp.update(int(sec_since_boot() * 1e9), True)

# run the cam can update for 10s as we just need to know if the camera is alive
if self.frame < 1000:
Expand Down
Loading