Skip to content

Commit

Permalink
Merge remote-tracking branch 'commaai/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Len Budney authored and Len Budney committed Dec 15, 2021
2 parents bc88631 + a112599 commit 17d2e19
Show file tree
Hide file tree
Showing 62 changed files with 508 additions and 435 deletions.
5 changes: 5 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
Version 0.8.13 (2022-XX-XX)
========================

Version 0.8.12 (2021-12-15)
========================
* New driving model
* Improved behavior around exits
* Better pose accuracy at high speeds, allowing max speed of 90mph
* Fully incorporated comma three data into all parts of training stack
* Improved follow distance
* Better longitudinal policy, especially in low speed traffic
* New alert sounds
Expand Down
49 changes: 22 additions & 27 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,41 @@
# How to contribute

Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use.
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use. Check out our [post about externalization](https://blog.comma.ai/a-2020-theme-externalization/).

Most open source development activity is coordinated through our [GitHub Discussions](https://github.com/commaai/openpilot/discussions) and [Discord](https://discord.comma.ai). A lot of documentation is available on our [blog](https://blog.comma.ai/).
Most open source development activity is coordinated through our [GitHub Discussions](https://github.com/commaai/openpilot/discussions) and [Discord](https://discord.comma.ai). A lot of documentation is available at https://docs.comma.ai and on our [blog](https://blog.comma.ai/).

## Getting Started
### Getting Started

* Setup your [development environment](../tools/)
* Join our [Discord](https://discord.comma.ai)
* Make sure you have a [GitHub account](https://github.com/signup/free)
* Fork [our repositories](https://github.com/commaai) on GitHub

## Testing

### Automated Testing

All PRs and commits are automatically checked by GitHub Actions. Check out `.github/workflows/` for what GitHub Actions runs. Any new tests should be added to GitHub Actions.
## Pull Requests

### Code Style and Linting
Pull requests should be against the master branch. Welcomed contributions include bug reports, car ports, and any [open issue](https://github.com/commaai/openpilot/issues). If you're unsure about a contribution, feel free to open a discussion, issue, or draft PR to discuss the problem you're trying to solve.

Code is automatically checked for style by GitHub Actions as part of the automated tests. You can also run these tests yourself by running `pre-commit run --all`.
A good pull request has all of the following:
* a clearly stated purpose
* every line changed directly contributes to the stated purpose
* verification, i.e. how did you test your PR?
* justification
* if you've optimized something, post benchmarks to prove it's better
* if you've improved your car's tuning, post before and after plots
* passes the CI tests

## Car Ports
### Car Ports

We've released a [Model Port guide](https://blog.comma.ai/openpilot-port-guide-for-toyota-models/) for porting to Toyota/Lexus models.

If you port openpilot to a substantially new car brand, see this more generic [Brand Port guide](https://blog.comma.ai/how-to-write-a-car-port-for-openpilot/).

## Pull Requests
## Testing

### Automated Testing

All PRs and commits are automatically checked by GitHub Actions. Check out `.github/workflows/` for what GitHub Actions runs. Any new tests should be added to GitHub Actions.

### Code Style and Linting

Pull requests should be against the master branch. Before running master on in-car hardware, you'll need to clone the submodules too. That can be done by recursively cloning the repository:
```
git clone https://github.com/commaai/openpilot.git --recursive
```
Or alternatively, when on the master branch:
```
git submodule update --init
```
The reasons for having submodules on a dedicated repository and our new development philosophy can be found in our [post about externalization](https://blog.comma.ai/a-2020-theme-externalization/).
Modules that are in seperate repositories include:
* cereal
* laika
* opendbc
* panda
* rednose
Code is automatically checked for style by GitHub Actions as part of the automated tests. You can also run these tests yourself by running `pre-commit run --all`.
31 changes: 29 additions & 2 deletions selfdrive/athena/athenad.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,28 @@
cur_upload_items = {}


class UploadQueueCache():
params = Params()

@staticmethod
def initialize(upload_queue):
try:
upload_queue_json = UploadQueueCache.params.get("AthenadUploadQueue")
if upload_queue_json is not None:
for item in json.loads(upload_queue_json):
upload_queue.put(UploadItem(**item))
except Exception:
cloudlog.exception("athena.UploadQueueCache.initialize.exception")

@staticmethod
def cache(upload_queue):
try:
items = [i._asdict() for i in upload_queue.queue if i.id not in cancelled_uploads]
UploadQueueCache.params.put("AthenadUploadQueue", json.dumps(items))
except Exception:
cloudlog.exception("athena.UploadQueueCache.cache.exception")


def handle_long_poll(ws):
end_event = threading.Event()

Expand Down Expand Up @@ -111,6 +133,7 @@ def upload_handler(end_event):

try:
cur_upload_items[tid] = upload_queue.get(timeout=1)._replace(current=True)

if cur_upload_items[tid].id in cancelled_uploads:
cancelled_uploads.remove(cur_upload_items[tid].id)
continue
Expand All @@ -120,6 +143,7 @@ def cb(sz, cur):
cur_upload_items[tid] = cur_upload_items[tid]._replace(progress=cur / sz if sz else 1)

_do_upload(cur_upload_items[tid], cb)
UploadQueueCache.cache(upload_queue)
except (requests.exceptions.Timeout, requests.exceptions.ConnectionError, requests.exceptions.SSLError) as e:
cloudlog.warning(f"athena.upload_handler.retry {e} {cur_upload_items[tid]}")

Expand All @@ -131,6 +155,8 @@ def cb(sz, cur):
current=False
)
upload_queue.put_nowait(item)
UploadQueueCache.cache(upload_queue)

cur_upload_items[tid] = None

for _ in range(RETRY_DELAY):
Expand Down Expand Up @@ -248,6 +274,7 @@ def uploadFileToUrl(fn, url, headers):
item = item._replace(id=upload_id)

upload_queue.put_nowait(item)
UploadQueueCache.cache(upload_queue)

return {"enqueued": 1, "item": item._asdict()}

Expand Down Expand Up @@ -280,8 +307,7 @@ def startLocalProxy(global_end_event, remote_ws_uri, local_port):

cloudlog.debug("athena.startLocalProxy.starting")

params = Params()
dongle_id = params.get("DongleId").decode('utf8')
dongle_id = Params().get("DongleId").decode('utf8')
identity_token = Api(dongle_id).get_token()
ws = create_connection(remote_ws_uri,
cookie="jwt=" + identity_token,
Expand Down Expand Up @@ -525,6 +551,7 @@ def backoff(retries):
def main():
params = Params()
dongle_id = params.get("DongleId", encoding='utf-8')
UploadQueueCache.initialize(upload_queue)

ws_uri = ATHENA_HOST + "/ws/v2/" + dongle_id
api = Api(dongle_id)
Expand Down
6 changes: 3 additions & 3 deletions selfdrive/athena/manage_athenad.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@
from common.params import Params
from selfdrive.manager.process import launcher
from selfdrive.swaglog import cloudlog
from selfdrive.version import get_version, get_dirty
from selfdrive.version import get_version, is_dirty

ATHENA_MGR_PID_PARAM = "AthenadPid"


def main():
params = Params()
dongle_id = params.get("DongleId").decode('utf-8')
cloudlog.bind_global(dongle_id=dongle_id, version=get_version(), dirty=get_dirty())
cloudlog.bind_global(dongle_id=dongle_id, version=get_version(), dirty=is_dirty())

try:
while 1:
cloudlog.info("starting athena daemon")
proc = Process(name='athenad', target=launcher, args=('selfdrive.athena.athenad',))
proc = Process(name='athenad', target=launcher, args=('selfdrive.athena.athenad', 'athenad'))
proc.start()
proc.join()
cloudlog.event("athenad exited", exitcode=proc.exitcode)
Expand Down
22 changes: 16 additions & 6 deletions selfdrive/athena/tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,28 @@ def get_token(self):


class MockParams():
def __init__(self):
self.params = {
"DongleId": b"0000000000000000",
"GithubSshKeys": b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC307aE+nuHzTAgaJhzSf5v7ZZQW9gaperjhCmyPyl4PzY7T1mDGenTlVTN7yoVFZ9UfO9oMQqo0n1OwDIiqbIFxqnhrHU0cYfj88rI85m5BEKlNu5RdaVTj1tcbaPpQc5kZEolaI1nDDjzV0lwS7jo5VYDHseiJHlik3HH1SgtdtsuamGR2T80q1SyW+5rHoMOJG73IH2553NnWuikKiuikGHUYBd00K1ilVAK2xSiMWJp55tQfZ0ecr9QjEsJ+J/efL4HqGNXhffxvypCXvbUYAFSddOwXUPo5BTKevpxMtH+2YrkpSjocWA04VnTYFiPG6U4ItKmbLOTFZtPzoez private" # noqa: E501
}
default_params = {
"DongleId": b"0000000000000000",
"GithubSshKeys": b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC307aE+nuHzTAgaJhzSf5v7ZZQW9gaperjhCmyPyl4PzY7T1mDGenTlVTN7yoVFZ9UfO9oMQqo0n1OwDIiqbIFxqnhrHU0cYfj88rI85m5BEKlNu5RdaVTj1tcbaPpQc5kZEolaI1nDDjzV0lwS7jo5VYDHseiJHlik3HH1SgtdtsuamGR2T80q1SyW+5rHoMOJG73IH2553NnWuikKiuikGHUYBd00K1ilVAK2xSiMWJp55tQfZ0ecr9QjEsJ+J/efL4HqGNXhffxvypCXvbUYAFSddOwXUPo5BTKevpxMtH+2YrkpSjocWA04VnTYFiPG6U4ItKmbLOTFZtPzoez private", # noqa: E501
"AthenadUploadQueue": '[]'
}
params = default_params.copy()

@staticmethod
def restore_defaults():
MockParams.params = MockParams.default_params.copy()

def get(self, k, encoding=None):
ret = self.params.get(k)
ret = MockParams.params.get(k)
if ret is not None and encoding is not None:
ret = ret.decode(encoding)
return ret

def put(self, k, v):
if k not in MockParams.params:
raise KeyError(f"key: {k} not in MockParams")
MockParams.params[k] = v


class MockWebsocket():
def __init__(self, recv_queue, send_queue):
Expand Down
25 changes: 24 additions & 1 deletion selfdrive/athena/tests/test_athenad.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,22 @@
from selfdrive.athena.tests.helpers import MockWebsocket, MockParams, MockApi, EchoSocket, with_http_server
from cereal import messaging


class TestAthenadMethods(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.SOCKET_PORT = 45454
athenad.Params = MockParams
athenad.ROOT = tempfile.mkdtemp()
athenad.SWAGLOG_DIR = swaglog.SWAGLOG_DIR = tempfile.mkdtemp()
athenad.Params = MockParams
athenad.Api = MockApi
athenad.LOCAL_PORT_WHITELIST = set([cls.SOCKET_PORT])

def setUp(self):
MockParams.restore_defaults()
athenad.upload_queue = queue.Queue()
athenad.cur_upload_items.clear()
athenad.cancelled_uploads.clear()

for i in os.listdir(athenad.ROOT):
p = os.path.join(athenad.ROOT, i)
Expand Down Expand Up @@ -249,6 +252,26 @@ def test_listUploadQueue(self):
items = dispatcher["listUploadQueue"]()
self.assertEqual(len(items), 0)

def test_upload_queue_persistence(self):
item1 = athenad.UploadItem(path="_", url="_", headers={}, created_at=int(time.time()), id='id1')
item2 = athenad.UploadItem(path="_", url="_", headers={}, created_at=int(time.time()), id='id2')

athenad.upload_queue.put_nowait(item1)
athenad.upload_queue.put_nowait(item2)

# Ensure cancelled items are not persisted
athenad.cancelled_uploads.add(item2.id)

# serialize item
athenad.UploadQueueCache.cache(athenad.upload_queue)

# deserialize item
athenad.upload_queue.queue.clear()
athenad.UploadQueueCache.initialize(athenad.upload_queue)

self.assertEqual(athenad.upload_queue.qsize(), 1)
self.assertDictEqual(athenad.upload_queue.queue[-1]._asdict(), item1._asdict())

@mock.patch('selfdrive.athena.athenad.create_connection')
def test_startLocalProxy(self, mock_create_connection):
end_event = threading.Event()
Expand Down
1 change: 0 additions & 1 deletion selfdrive/camerad/cameras/camera_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,6 @@ void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &fr
framed.setMeasuredGreyFraction(frame_data.measured_grey_fraction);
framed.setTargetGreyFraction(frame_data.target_grey_fraction);
framed.setLensPos(frame_data.lens_pos);
framed.setLensSag(frame_data.lens_sag);
framed.setLensErr(frame_data.lens_err);
framed.setLensTruePos(frame_data.lens_true_pos);
}
Expand Down
1 change: 0 additions & 1 deletion selfdrive/camerad/cameras/camera_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ typedef struct FrameMetadata {

// Focus
unsigned int lens_pos;
float lens_sag;
float lens_err;
float lens_true_pos;
} FrameMetadata;
Expand Down
35 changes: 3 additions & 32 deletions selfdrive/camerad/cameras/camera_qcom.cc
Original file line number Diff line number Diff line change
Expand Up @@ -852,45 +852,18 @@ static void parse_autofocus(CameraState *s, uint8_t *d) {
s->focus_err = max_focus*1.0;
}

static std::optional<float> get_accel_z(SubMaster *sm) {
sm->update(0);
if(sm->updated("sensorEvents")) {
for (auto event : (*sm)["sensorEvents"].getSensorEvents()) {
if (event.which() == cereal::SensorEventData::ACCELERATION) {
if (auto v = event.getAcceleration().getV(); v.size() >= 3)
return -v[2];
break;
}
}
}
return std::nullopt;
}

static void do_autofocus(CameraState *s, SubMaster *sm) {
static void do_autofocus(CameraState *s) {
float lens_true_pos = s->lens_true_pos.load();
if (!isnan(s->focus_err)) {
// learn lens_true_pos
const float focus_kp = 0.005;
lens_true_pos -= s->focus_err*focus_kp;
}

if (auto accel_z = get_accel_z(sm)) {
s->last_sag_acc_z = *accel_z;
}
const float sag = (s->last_sag_acc_z / 9.8) * 128;
// stay off the walls
lens_true_pos = std::clamp(lens_true_pos, float(LP3_AF_DAC_DOWN), float(LP3_AF_DAC_UP));
int target = std::clamp(lens_true_pos - sag, float(LP3_AF_DAC_DOWN), float(LP3_AF_DAC_UP));
s->lens_true_pos.store(lens_true_pos);

/*char debug[4096];
char *pdebug = debug;
pdebug += sprintf(pdebug, "focus ");
for (int i = 0; i < NUM_FOCUS; i++) pdebug += sprintf(pdebug, "%2x(%4d) ", s->confidence[i], s->focus[i]);
pdebug += sprintf(pdebug, " err: %7.2f offset: %6.2f sag: %6.2f lens_true_pos: %6.2f cur_lens_pos: %4d->%4d", err * focus_kp, offset, sag, s->lens_true_pos, s->cur_lens_pos, target);
LOGD(debug);*/

actuator_move(s, target);
actuator_move(s, lens_true_pos);
}

void camera_autoexposure(CameraState *s, float grey_frac) {
Expand Down Expand Up @@ -1046,12 +1019,11 @@ static void ops_thread(MultiCameraState *s) {
CameraExpInfo driver_cam_op;

util::set_thread_name("camera_settings");
SubMaster sm({"sensorEvents"});
while(!do_exit) {
road_cam_op = road_cam_exp.load();
if (road_cam_op.op_id != last_road_cam_op_id) {
do_autoexposure(&s->road_cam, road_cam_op.grey_frac);
do_autofocus(&s->road_cam, &sm);
do_autofocus(&s->road_cam);
last_road_cam_op_id = road_cam_op.op_id;
}

Expand Down Expand Up @@ -1165,7 +1137,6 @@ void cameras_run(MultiCameraState *s) {
.frame_length = (uint32_t)c->frame_length,
.integ_lines = (uint32_t)c->cur_integ_lines,
.lens_pos = c->cur_lens_pos,
.lens_sag = c->last_sag_acc_z,
.lens_err = c->focus_err,
.lens_true_pos = c->lens_true_pos,
.gain = c->cur_gain_frac,
Expand Down
1 change: 0 additions & 1 deletion selfdrive/camerad/cameras/camera_qcom.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ typedef struct CameraState {
// rear camera only,used for focusing
unique_fd actuator_fd;
std::atomic<float> focus_err;
std::atomic<float> last_sag_acc_z;
std::atomic<float> lens_true_pos;
std::atomic<int> self_recover; // af recovery counter, neg is patience, pos is active
uint16_t cur_step_pos;
Expand Down
4 changes: 2 additions & 2 deletions selfdrive/car/car_helpers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
from common.params import Params
from common.basedir import BASEDIR
from selfdrive.version import get_comma_remote, get_tested_branch
from selfdrive.version import is_comma_remote, is_tested_branch
from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars
from selfdrive.car.vin import get_vin, VIN_UNKNOWN
from selfdrive.car.fw_versions import get_fw_versions, match_fw_to_car
Expand All @@ -14,7 +14,7 @@


def get_startup_event(car_recognized, controller_available, fw_seen):
if get_comma_remote() and get_tested_branch():
if is_comma_remote() and is_tested_branch():
event = EventName.startup
else:
event = EventName.startupMaster
Expand Down
1 change: 0 additions & 1 deletion selfdrive/car/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ def get_std_params(candidate, fingerprint):
ret.minEnableSpeed = -1. # enable is done by stock ACC, so ignore this
ret.steerRatioRear = 0. # no rear steering, at least on the listed cars aboveA
ret.openpilotLongitudinalControl = False
ret.minSpeedCan = 0.3
ret.startAccel = -0.8
ret.stopAccel = -2.0
ret.startingAccelRate = 3.2 # brake_travel/s while releasing on restart
Expand Down
Loading

0 comments on commit 17d2e19

Please sign in to comment.