Example #1
0
 def _setup_collector(self):
     self.sm_collector = SubMaster(['liveTracks'])
     self.log_auto_df = self.op_params.get('log_auto_df')
     if not isinstance(self.log_auto_df, bool):
         self.log_auto_df = False
     self.data_collector = DataCollector(file_path='/data/df_data',
                                         keys=[
                                             'v_ego', 'a_ego', 'a_lead',
                                             'v_lead', 'x_lead', 'profile',
                                             'time'
                                         ],
                                         log_data=self.log_auto_df)
def send_request(url, request):
    print('Size of request: ' + str(request.image.size))

    start_time = time.time()

    # Send full image to edge device for further processing
    pickle.dump(request.image, open(PICKLED_TEMP_LOC, 'wb'))

    resp = requests.post(url,
                         files={'file': open(PICKLED_TEMP_LOC, 'rb')},
                         verify=False)
    status_code = resp.status_code
    size_of_resp = len(resp.content)
    total_size = str(request.image.size + size_of_resp)
    resp = resp.json()

    print('Size of response: ' + str(size_of_resp))
    print('Total transfer size: ' + total_size)

    duration = str(time.time() - start_time)
    prediction = 'Count: ' + str(len(resp['prediction'])) + ', ' + str(
        resp['prediction'])
    print('Data Transfer Time: ' + duration)
    print('Results: ' + prediction)

    data_collector = DataCollector()
    data_collector.write(DATA_TYPE_TRANSFER_SIZE, total_size)
    data_collector.write(DATA_TYPE_DATA_TRANSFER_TIME, duration)
    data_collector.write(DATA_TYPE_DETECTION, prediction)

    return NodeResponse(cc.get_status(status_code),
                        cc.get_image(request.image, resp['prediction']),
                        resp['prediction'])
Example #3
0
def run_camera(camera_chain, video_file_loc):
    # buffers for demo in batch
    buffer_inp = list()

    # Loop through frames
    elapsed = 0
    start = timer()
    data_collector = DataCollector()

    print('Video file to open: ' + str(video_file_loc))

    while True:
        frame_num = 0
        while frame_num < FRAME_LIMIT:
            print('Press [ESC] to quit demo')
            camera = cv2.VideoCapture(video_file_loc)
            cam_num = UserParameters().get_cam_num()

            while camera.isOpened():
                elapsed += 1
                _, frame = camera.read()
                frame_num = frame_num + 1
                if frame is None:
                    print('\nEnd of Video')
                    break
                buffer_inp.append(frame)
                # Only process and imshow when queue is full
                if elapsed % QUEUE == 0:
                    for image in buffer_inp:
                        collector_start_time = timer()
                        process_image_response = process_img_request(
                            image, cam_num, frame_num,
                            camera_chain.get_processor())
                        cv2.imshow('', process_image_response.boxed_image)
                        #cv2.imshow('', image)
                        duration = str(timer() - collector_start_time)
                        print('Processing Time: ' + duration)
                        data_collector.write(DATA_TYPE_PROCESSING_TIME,
                                             duration)
                    # Clear Buffers
                    buffer_inp = list()

                if elapsed % 5 == 0:
                    sys.stdout.write('\r')
                    fps = elapsed / (timer() - start)
                    sys.stdout.write('{0:3.3f} FPS\n'.format(fps))
                    data_collector.write(DATA_TYPE_FPS, str(fps))
                    sys.stdout.flush()
                choice = cv2.waitKey(1)
                if choice == 27:
                    break

            sys.stdout.write('\n')
            camera.release()
            data_collector.close()
            cv2.destroyAllWindows()


#run_camera()
Example #4
0
 def predict(self, image):
     boxes = self.model.predict(image)
     image_annotated = draw_boxes(image, boxes, self.label_array)
     boxes_str = 'Count: ' + str(len(boxes)) + ', ' + str([create_box_resp_field(box) for box in boxes])
     print('Results: ' + boxes_str)
     DataCollector().write(DATA_TYPE_DETECTION, boxes_str)
     return image_annotated, boxes
def post_to_multi_view(request):
    data = {
        'cam':
        request.cam_num,
        'frame':
        request.frame_num,
        'prediction':
        [create_box_resp_field(pred) for pred in request.predicted_box_loc]
    }

    size_of_request = asizeof.asizeof(data)
    print('Size of request: ' + str(size_of_request))

    start_time = time.time()

    resp = requests.post(str(UserParameters().get_edge_ip()) +
                         MULTI_VIEW_RELATIVE_URL,
                         headers={'Content-Type': 'application/json'},
                         data=json.dumps(data),
                         verify=False)
    status_code = resp.status_code
    size_of_resp = asizeof.asizeof(resp.content)
    total_size = str(size_of_request + size_of_resp)
    resp = resp.json()
    print('Size of response: ' + str(size_of_resp))
    print('Total transfer size: ' + total_size)

    duration = str(time.time() - start_time)
    prediction = 'Count: ' + str(len(resp['prediction'])) + ', ' + str(
        resp['prediction'])
    print('Data Transfer Time: ' + duration)
    print('Results: ' + prediction)

    data_collector = DataCollector()
    data_collector.write(DATA_TYPE_TRANSFER_SIZE, total_size)
    data_collector.write(DATA_TYPE_DATA_TRANSFER_TIME, duration)
    data_collector.write(DATA_TYPE_DETECTION, prediction)

    return NodeResponse(cc.get_status(status_code),
                        cc.get_image(request.image, resp['prediction']),
                        resp['prediction'])
Example #6
0
    def predict(self, image):
        class_to_color = {self.class_mapping[v]: np.random.randint(0, 255, 3) for v in self.class_mapping}
        bbox_threshold = 0.8
        X, ratio = format_img(image, self.C)
        X = np.transpose(X, (0, 2, 3, 1))
        [Y1, Y2, F] = self.model_rpn.predict(X)
        R = roi_helpers.rpn_to_roi(Y1, Y2, K.image_dim_ordering(), overlap_thresh=0.7)
        R[:, 2] -= R[:, 0]
        R[:, 3] -= R[:, 1]

        # apply the spatial pyramid pooling to the proposed regions
        bboxes = {}
        probs = {}

        for jk in range(R.shape[0] // self.C.num_rois + 1):
            ROIs = np.expand_dims(R[self.C.num_rois * jk:self.C.num_rois * (jk + 1), :], axis=0)
            if ROIs.shape[1] == 0:
                break

            if jk == R.shape[0] // self.C.num_rois:
                # pad R
                curr_shape = ROIs.shape
                target_shape = (curr_shape[0], self.C.num_rois, curr_shape[2])
                ROIs_padded = np.zeros(target_shape).astype(ROIs.dtype)
                ROIs_padded[:, :curr_shape[1], :] = ROIs
                ROIs_padded[0, curr_shape[1]:, :] = ROIs[0, 0, :]
                ROIs = ROIs_padded

            [P_cls, P_regr] = self.model_classifier_only.predict([F, ROIs])

            for ii in range(P_cls.shape[1]):

                if np.max(P_cls[0, ii, :]) < bbox_threshold or np.argmax(P_cls[0, ii, :]) == (P_cls.shape[2] - 1):
                    continue

                cls_name = self.class_mapping[np.argmax(P_cls[0, ii, :])]

                if cls_name not in bboxes:
                    bboxes[cls_name] = []
                    probs[cls_name] = []

                (x, y, w, h) = ROIs[0, ii, :]

                cls_num = np.argmax(P_cls[0, ii, :])
                try:
                    (tx, ty, tw, th) = P_regr[0, ii, 4 * cls_num:4 * (cls_num + 1)]
                    tx /= self.C.classifier_regr_std[0]
                    ty /= self.C.classifier_regr_std[1]
                    tw /= self.C.classifier_regr_std[2]
                    th /= self.C.classifier_regr_std[3]
                    x, y, w, h = roi_helpers.apply_regr(x, y, w, h, tx, ty, tw, th)
                except:
                    pass
                bboxes[cls_name].append(
                    [self.C.rpn_stride * x, self.C.rpn_stride * y, self.C.rpn_stride * (x + w), self.C.rpn_stride * (y + h)])
                probs[cls_name].append(np.max(P_cls[0, ii, :]))

        all_dets = []

        for key in bboxes:
            bbox = np.array(bboxes[key])

            new_boxes, new_probs = roi_helpers.non_max_suppression_fast(bbox, np.array(probs[key]), overlap_thresh=0.5)
            for jk in range(new_boxes.shape[0]):
                (x1, y1, x2, y2) = new_boxes[jk, :]

                (real_x1, real_y1, real_x2, real_y2) = get_real_coordinates(ratio, x1, y1, x2, y2)

                cv2.rectangle(image, (real_x1, real_y1), (real_x2, real_y2),
                              (int(class_to_color[key][0]), int(class_to_color[key][1]), int(class_to_color[key][2])),
                              2)

                textLabel = '{}: {}'.format(key, int(100 * new_probs[jk]))
                all_dets.append(create_box_resp_field(self.class_mapping_rev[key], new_probs[jk], real_x2/255, real_x1/255, real_y2/255, real_y1/255))

                (retval, baseLine) = cv2.getTextSize(textLabel, cv2.FONT_HERSHEY_COMPLEX, 1, 1)
                textOrg = (real_x1, real_y1 - 0)

                cv2.rectangle(image, (textOrg[0] - 5, textOrg[1] + baseLine - 5),
                              (textOrg[0] + retval[0] + 5, textOrg[1] - retval[1] - 5), (0, 0, 0), 2)
                cv2.rectangle(image, (textOrg[0] - 5, textOrg[1] + baseLine - 5),
                              (textOrg[0] + retval[0] + 5, textOrg[1] - retval[1] - 5), (255, 255, 255), -1)
                cv2.putText(image, textLabel, textOrg, cv2.FONT_HERSHEY_DUPLEX, 1, (0, 0, 0), 1)

        boxes_str = 'Count: ' + str(len(all_dets)) + ', ' + str(all_dets)
        print('Results: ' + boxes_str)
        DataCollector().write(DATA_TYPE_DETECTION, boxes_str)
        return image, all_dets
Example #7
0
class DynamicFollow:
    def __init__(self, mpc_id):
        self.mpc_id = mpc_id
        self.op_params = opParams()
        self.df_profiles = dfProfiles()
        self.df_manager = dfManager(self.op_params)

        if not travis and mpc_id == 1:
            self.pm = messaging.PubMaster(['dynamicFollowData'])
        else:
            self.pm = None

        # Model variables
        mpc_rate = 1 / 20.
        self.model_scales = {
            'v_ego': [-0.06112159043550491, 37.96522521972656],
            'a_lead': [-3.109330892562866, 3.3612186908721924],
            'v_lead': [0.0, 35.27671432495117],
            'x_lead': [2.4600000381469727, 141.44000244140625]
        }
        self.predict_rate = 1 / 4.
        self.skip_every = round(0.25 / mpc_rate)
        self.model_input_len = round(45 / mpc_rate)

        # Dynamic follow variables
        self.default_TR = 1.8
        self.TR = 1.8
        self.v_ego_retention = 2.5
        self.v_rel_retention = 1.75

        self.sng_TR = 1.8  # reacceleration stop and go TR
        self.sng_speed = 18.0 * CV.MPH_TO_MS

        self._setup_collector()
        self._setup_changing_variables()

    def _setup_collector(self):
        self.sm_collector = SubMaster(['liveTracks', 'laneSpeed'])
        self.log_auto_df = self.op_params.get('log_auto_df')
        if not isinstance(self.log_auto_df, bool):
            self.log_auto_df = False
        self.data_collector = DataCollector(
            file_path='/data/df_data',
            keys=[
                'v_ego', 'a_ego', 'a_lead', 'v_lead', 'x_lead',
                'left_lane_speeds', 'middle_lane_speeds', 'right_lane_speeds',
                'left_lane_distances', 'middle_lane_distances',
                'right_lane_distances', 'profile', 'time'
            ],
            log_data=self.log_auto_df)

    def _setup_changing_variables(self):
        self.TR = self.default_TR
        self.user_profile = self.df_profiles.relaxed  # just a starting point
        self.model_profile = self.df_profiles.relaxed

        self.last_effective_profile = self.user_profile
        self.profile_change_time = 0

        self.sng = False
        self.car_data = CarData()
        self.lead_data = LeadData()
        self.df_data = dfData()  # dynamic follow data

        self.last_cost = 0.0
        self.last_predict_time = 0.0
        self.auto_df_model_data = []
        self._get_live_params()  # so they're defined just in case

    def update(self, CS, libmpc):
        self._get_live_params()
        self._update_car(CS)
        self._get_profiles()

        if self.mpc_id == 1 and self.log_auto_df:
            self._gather_data()

        if not self.lead_data.status:
            self.TR = self.default_TR
        else:
            self._store_df_data()
            self.TR = self._get_TR()

        if not travis:
            self._change_cost(libmpc)
            self._send_cur_state()

        return self.TR

    def _get_profiles(self):
        """This receives profile change updates from dfManager and runs the auto-df prediction if auto mode"""
        df_out = self.df_manager.update()
        self.user_profile = df_out.user_profile
        if df_out.is_auto:  # todo: find some way to share prediction between the two mpcs to reduce processing overhead
            self._get_pred(
            )  # sets self.model_profile, all other checks are inside function

    def _gather_data(self):
        self.sm_collector.update(0)
        # live_tracks = [[i.dRel, i.vRel, i.aRel, i.yRel] for i in self.sm_collector['liveTracks']]
        if self.car_data.cruise_enabled:
            self.data_collector.update([
                self.car_data.v_ego, self.car_data.a_ego,
                self.lead_data.a_lead, self.lead_data.v_lead,
                self.lead_data.x_lead,
                list(self.sm_collector['laneSpeed'].leftLaneSpeeds),
                list(self.sm_collector['laneSpeed'].middleLaneSpeeds),
                list(self.sm_collector['laneSpeed'].rightLaneSpeeds),
                list(self.sm_collector['laneSpeed'].leftLaneDistances),
                list(self.sm_collector['laneSpeed'].middleLaneDistances),
                list(self.sm_collector['laneSpeed'].rightLaneDistances),
                self.user_profile,
                sec_since_boot()
            ])

    def _norm(self, x, name):
        self.x = x
        return interp(x, self.model_scales[name], [0, 1])

    def _send_cur_state(self):
        if self.mpc_id == 1 and self.pm is not None:
            dat = messaging.new_message()
            dat.init('dynamicFollowData')
            dat.dynamicFollowData.mpcTR = self.TR
            dat.dynamicFollowData.profilePred = self.model_profile
            self.pm.send('dynamicFollowData', dat)

    def _change_cost(self, libmpc):
        TRs = [0.9, 1.8, 2.7]
        costs = [1.15, 0.15, 0.05]
        cost = interp(self.TR, TRs, costs)

        change_time = sec_since_boot() - self.profile_change_time
        change_time_x = [
            0, 0.5, 4
        ]  # for three seconds after effective profile has changed
        change_mod_y = [
            3, 6, 1
        ]  # multiply cost by multiplier to quickly change distance
        if change_time < change_time_x[
                -1]:  # if profile changed in last 3 seconds
            cost_mod = interp(change_time, change_time_x, change_mod_y)
            cost_mod_speeds = [0, 20 * CV.MPH_TO_MS
                               ]  # don't change cost too much under 20 mph
            cost_mods = [cost_mod * 0.01, cost_mod]
            cost *= interp(cost_mod, cost_mod_speeds, cost_mods)

        if self.last_cost != cost:
            libmpc.change_costs(
                MPC_COST_LONG.TTC, cost, MPC_COST_LONG.ACCELERATION,
                MPC_COST_LONG.JERK
            )  # todo: jerk is the derivative of acceleration, could tune that
            self.last_cost = cost

    def _store_df_data(self):
        cur_time = sec_since_boot()
        # Store custom relative accel over time
        if self.lead_data.status:
            if self.lead_data.new_lead:
                self.df_data.v_rels = []  # reset when new lead
            else:
                self.df_data.v_rels = self._remove_old_entries(
                    self.df_data.v_rels, cur_time, self.v_rel_retention)
            self.df_data.v_rels.append({
                'v_ego': self.car_data.v_ego,
                'v_lead': self.lead_data.v_lead,
                'time': cur_time
            })

        # Store our velocity for better sng
        self.df_data.v_egos = self._remove_old_entries(self.df_data.v_egos,
                                                       cur_time,
                                                       self.v_ego_retention)
        self.df_data.v_egos.append({
            'v_ego': self.car_data.v_ego,
            'time': cur_time
        })

        # Store data for auto-df model
        self.auto_df_model_data.append([
            self._norm(self.car_data.v_ego, 'v_ego'),
            self._norm(self.lead_data.v_lead, 'v_lead'),
            self._norm(self.lead_data.a_lead, 'a_lead'),
            self._norm(self.lead_data.x_lead, 'x_lead')
        ])
        while len(self.auto_df_model_data) > self.model_input_len:
            del self.auto_df_model_data[0]

    def _get_pred(self):
        cur_time = sec_since_boot()
        if self.car_data.cruise_enabled and self.lead_data.status:
            if cur_time - self.last_predict_time > self.predict_rate:
                if len(self.auto_df_model_data) == self.model_input_len:
                    pred = predict(
                        np.array(self.auto_df_model_data[::self.skip_every],
                                 dtype=np.float32).flatten())
                    self.last_predict_time = cur_time
                    self.model_profile = int(np.argmax(pred))

    def _remove_old_entries(self, lst, cur_time, retention):
        return [
            sample for sample in lst if cur_time - sample['time'] <= retention
        ]

    def _relative_accel_mod(self):
        """
    Returns relative acceleration mod calculated from list of lead and ego velocities over time (longer than 1s)
    If min_consider_time has not been reached, uses lead accel and ego accel from openpilot (kalman filtered)
    """
        a_ego = self.car_data.a_ego
        a_lead = self.lead_data.a_lead
        min_consider_time = 0.75  # minimum amount of time required to consider calculation
        if len(self.df_data.v_rels) > 0:  # if not empty
            elapsed_time = self.df_data.v_rels[-1][
                'time'] - self.df_data.v_rels[0]['time']
            if elapsed_time > min_consider_time:
                a_ego = (self.df_data.v_rels[-1]['v_ego'] -
                         self.df_data.v_rels[0]['v_ego']) / elapsed_time
                a_lead = (self.df_data.v_rels[-1]['v_lead'] -
                          self.df_data.v_rels[0]['v_lead']) / elapsed_time

        mods_x = [-1.5, -.75, 0]
        mods_y = [1, 1.25, 1.3]
        if a_lead < 0:  # more weight to slight lead decel
            a_lead *= interp(a_lead, mods_x, mods_y)

        if a_lead - a_ego > 0:  # return only if adding distance
            return 0

        rel_x = [
            -2.6822, -1.7882, -0.8941, -0.447, -0.2235, 0.0, 0.2235, 0.447,
            0.8941, 1.7882, 2.6822
        ]
        mod_y = [
            0.3245 * 1.1, 0.277 * 1.08, 0.11075 * 1.06, 0.08106 * 1.045,
            0.06325 * 1.035, 0.0, -0.09, -0.09375, -0.125, -0.3, -0.35
        ]
        return interp(a_lead - a_ego, rel_x, mod_y)

    def global_profile_mod(self, profile_mod_x, profile_mod_pos,
                           profile_mod_neg, x_vel, y_dist):
        """
    This function modifies the y_dist list used by dynamic follow in accordance with global_df_mod
    It also intelligently adjusts the profile mods at each breakpoint based on the change in TR
    """
        if self.global_df_mod == 1.:
            return profile_mod_pos, profile_mod_neg, y_dist
        global_df_mod = 1 - self.global_df_mod

        # Calculate new TRs
        speeds = [
            0, self.sng_speed, 18, x_vel[-1]
        ]  # [0, 18 mph, ~40 mph, highest profile mod speed (~78 mph)]
        mods = [
            0, 0.1, 0.7, 1
        ]  # how much to limit global_df_mod at each speed, 1 is full effect
        y_dist_new = [
            y - (y * global_df_mod * interp(x, speeds, mods))
            for x, y in zip(x_vel, y_dist)
        ]

        # Calculate how to change profile mods based on change in TR
        # eg. if df mod is 0.7, then increase positive mod and decrease negative mod
        calc_profile_mods = [(interp(mod_x, x_vel, y_dist) -
                              interp(mod_x, x_vel, y_dist_new) + 1)
                             for mod_x in profile_mod_x]
        profile_mod_pos = [
            mod_pos * mod
            for mod_pos, mod in zip(profile_mod_pos, calc_profile_mods)
        ]
        profile_mod_neg = [
            mod_neg * ((1 - mod) + 1)
            for mod_neg, mod in zip(profile_mod_neg, calc_profile_mods)
        ]

        return profile_mod_pos, profile_mod_neg, y_dist_new

    def _get_TR(self):
        x_vel = [
            0.0, 1.8627, 3.7253, 5.588, 7.4507, 9.3133, 11.5598, 13.645,
            22.352, 31.2928, 33.528, 35.7632, 40.2336
        ]  # velocities
        profile_mod_x = [
            5 * CV.MPH_TO_MS, 30 * CV.MPH_TO_MS, 55 * CV.MPH_TO_MS,
            80 * CV.MPH_TO_MS
        ]  # profile mod speeds

        if self.df_manager.is_auto:  # decide which profile to use, model profile will be updated before this
            df_profile = self.model_profile
        else:
            df_profile = self.user_profile

        if df_profile != self.last_effective_profile:
            self.profile_change_time = sec_since_boot()
        self.last_effective_profile = df_profile

        if df_profile == self.df_profiles.roadtrip:
            y_dist = [
                1.5486, 1.556, 1.5655, 1.5773, 1.5964, 1.6246, 1.6715, 1.7057,
                1.7859, 1.8542, 1.8697, 1.8833, 1.8961
            ]  # TRs
            profile_mod_pos = [0.5, 0.35, 0.1, 0.03]
            profile_mod_neg = [1.3, 1.4, 1.8, 2.0]
        elif df_profile == self.df_profiles.traffic:  # for in congested traffic
            x_vel = [
                0.0, 1.892, 3.7432, 5.8632, 8.0727, 10.7301, 14.343, 17.6275,
                22.4049, 28.6752, 34.8858, 40.35
            ]
            y_dist = [
                1.3781, 1.3791, 1.3457, 1.3134, 1.3145, 1.318, 1.3485, 1.257,
                1.144, 0.979, 0.9461, 0.9156
            ]
            profile_mod_pos = [1.075, 1.55, 2.6, 3.75]
            profile_mod_neg = [0.95, .275, 0.1, 0.05]
        elif df_profile == self.df_profiles.relaxed:  # default to relaxed/stock
            y_dist = [
                1.385, 1.394, 1.406, 1.421, 1.444, 1.474, 1.521, 1.544, 1.568,
                1.588, 1.599, 1.613, 1.634
            ]
            profile_mod_pos = [1.0, 0.955, 0.898, 0.905]
            profile_mod_neg = [1.0, 1.0825, 1.1877, 1.174]
        else:
            raise Exception('Unknown profile type: {}'.format(df_profile))

        # Global df mod
        profile_mod_pos, profile_mod_neg, y_dist = self.global_profile_mod(
            profile_mod_x, profile_mod_pos, profile_mod_neg, x_vel, y_dist)

        # Profile modifications - Designed so that each profile reacts similarly to changing lead dynamics
        profile_mod_pos = interp(self.car_data.v_ego, profile_mod_x,
                                 profile_mod_pos)
        profile_mod_neg = interp(self.car_data.v_ego, profile_mod_x,
                                 profile_mod_neg)

        if self.car_data.v_ego > self.sng_speed:  # keep sng distance until we're above sng speed again
            self.sng = False

        if (self.car_data.v_ego >= self.sng_speed
                or self.df_data.v_egos[0]['v_ego'] >= self.car_data.v_ego
            ) and not self.sng:
            # if above 15 mph OR we're decelerating to a stop, keep shorter TR. when we reaccelerate, use sng_TR and slowly decrease
            TR = interp(self.car_data.v_ego, x_vel, y_dist)
        else:  # this allows us to get closer to the lead car when stopping, while being able to have smooth stop and go when reaccelerating
            self.sng = True
            x = [
                self.sng_speed * 0.7, self.sng_speed
            ]  # decrease TR between 12.6 and 18 mph from 1.8s to defined TR above at 18mph while accelerating
            y = [self.sng_TR, interp(self.sng_speed, x_vel, y_dist)]
            TR = interp(self.car_data.v_ego, x, y)

        TR_mods = []
        # Dynamic follow modifications (the secret sauce)
        x = [
            -26.8224, -20.0288, -15.6871, -11.1965, -7.8645, -4.9472, -3.0541,
            -2.2244, -1.5045, -0.7908, -0.3196, 0.0, 0.5588, 1.3682, 1.898,
            2.7316, 4.4704
        ]  # relative velocity values
        y = [
            .76, 0.62323, 0.49488, 0.40656, 0.32227, 0.23914 * 1.025,
            0.12269 * 1.05, 0.10483 * 1.075, 0.08074 * 1.15, 0.04886 * 1.25,
            0.0072 * 1.075, 0.0, -0.05648, -0.0792, -0.15675, -0.23289, -0.315
        ]  # modification values
        TR_mods.append(
            interp(self.lead_data.v_lead - self.car_data.v_ego, x, y))

        x = [
            -4.4795, -2.8122, -1.5727, -1.1129, -0.6611, -0.2692, 0.0, 0.1466,
            0.5144, 0.6903, 0.9302
        ]  # lead acceleration values
        y = [
            0.24, 0.16, 0.092, 0.0515, 0.0305, 0.022, 0.0, -0.0153, -0.042,
            -0.053, -0.059
        ]  # modification values
        TR_mods.append(interp(self.lead_data.a_lead, x, y))

        # deadzone = self.car_data.v_ego / 3  # 10 mph at 30 mph  # todo: tune pedal to react similarly to without before adding/testing this
        # if self.lead_data.v_lead - deadzone > self.car_data.v_ego:
        #   TR_mods.append(self._relative_accel_mod())

        x = [self.sng_speed,
             self.sng_speed / 5.0]  # as we approach 0, apply x% more distance
        y = [1.0, 1.05]
        profile_mod_pos *= interp(self.car_data.v_ego, x,
                                  y)  # but only for currently positive mods

        TR_mod = sum([
            mod * profile_mod_neg if mod < 0 else mod * profile_mod_pos
            for mod in TR_mods
        ])  # alter TR modification according to profile
        TR += TR_mod

        if (self.car_data.left_blinker or self.car_data.right_blinker
            ) and df_profile != self.df_profiles.traffic:
            x = [8.9408, 22.352, 31.2928]  # 20, 50, 70 mph
            y = [1.0, .75, .65]
            TR *= interp(self.car_data.v_ego, x,
                         y)  # reduce TR when changing lanes

        return float(clip(TR, self.min_TR, 2.7))

    def update_lead(self,
                    v_lead=None,
                    a_lead=None,
                    x_lead=None,
                    status=False,
                    new_lead=False):
        self.lead_data.v_lead = v_lead
        self.lead_data.a_lead = a_lead
        self.lead_data.x_lead = x_lead

        self.lead_data.status = status
        self.lead_data.new_lead = new_lead

    def _update_car(self, CS):
        self.car_data.v_ego = CS.vEgo
        self.car_data.a_ego = CS.aEgo

        self.car_data.left_blinker = CS.leftBlinker
        self.car_data.right_blinker = CS.rightBlinker
        self.car_data.cruise_enabled = CS.cruiseState.enabled

    def _get_live_params(self):
        self.global_df_mod = self.op_params.get('global_df_mod')
        if self.global_df_mod != 1.:
            self.global_df_mod = clip(self.global_df_mod, 0.85, 1.2)

        self.min_TR = self.op_params.get('min_TR')
        if self.min_TR != 1.:
            self.min_TR = clip(self.min_TR, 0.85, 1.6)
Example #8
0
    # hidden-layer. To train the network:
    # - Use the training dataset of MNIST digits
    # - Corrupt the input data using a binomial distribution at 10% corruption level.
    # - Use cross-entropy as the cost function
    #
    # Plot
    #
    # - a. learning curves for training each layer
    # - b. Plot 100 samples of weights (as images) learned at each layer
    # - c. For 100 representative test images plot:
    #     - reconstructed images by the network.
    #     - Hidden layer activation

    # a. Learning curve for training each layer.

    data_collector = DataCollector("../mnist.pkl")

    train_x, train_y = data_collector.get_train_data()
    test_x, test_y = data_collector.get_test_data()
    validate_x, validate_y = data_collector.get_validation_data()

    num_feature = len(train_x[0])
    list_hidden_layer = [900, 625, 400]
    epochs = 3
    batch_size = 128
    num_output = 10

    softmax = SoftmaxAutoEncoder(num_features=num_feature,
                                 num_outputs=num_output,
                                 list_hidden_layer=list_hidden_layer,
                                 learning_rate=0.1)
Example #9
0
class DynamicFollow:
    def __init__(self, mpc_id):
        self.mpc_id = mpc_id
        self.op_params = opParams()
        self.df_profiles = dfProfiles()
        self.df_manager = dfManager()
        self.dmc_v_rel = DistanceModController(k_i=0.042,
                                               k_d=0.08,
                                               x_clip=[-1, 0, 0.66],
                                               mods=[1.15, 1., 0.95])
        self.dmc_a_rel = DistanceModController(
            k_i=0.042 * 1.05,
            k_d=0.08,
            x_clip=[-1, 0, 0.33],
            mods=[1.15, 1., 0.98])  # a_lead loop is 5% faster

        if not travis and mpc_id == 1:
            self.pm = messaging.PubMaster(['dynamicFollowData'])
        else:
            self.pm = None

        # Model variables
        mpc_rate = 1 / 20.
        self.model_scales = {
            'v_ego': [-0.06112159043550491, 37.96522521972656],
            'a_lead': [-3.109330892562866, 3.3612186908721924],
            'v_lead': [0.0, 35.27671432495117],
            'x_lead': [2.4600000381469727, 141.44000244140625]
        }
        self.predict_rate = 1 / 4.
        self.skip_every = round(0.25 / mpc_rate)
        self.model_input_len = round(45 / mpc_rate)

        # Dynamic follow variables
        self.default_TR = 1.8
        self.TR = 1.8
        self.v_ego_retention = 2.5
        self.v_rel_retention = 1.75

        #self.sng_TR = 1.8  # reacceleration stop and go TR   #Orig
        #self.sng_TR = 2.3  # Last value
        #self.sng_TR = 1.5   # Try to decrease stop and start TR so would start move faster from stop
        self.sng_TR = 1.  # Try to decrease stop and start TR so would start move faster from stop
        self.sng_TR = 2.5  # Maybe I thought this wrong
        self.sng_speed = 18.0 * CV.MPH_TO_MS  #Orig
        #self.sng_speed = 12.0 * CV.MPH_TO_MS

        self._setup_collector()
        self._setup_changing_variables()

    def _setup_collector(self):
        self.sm_collector = SubMaster(['liveTracks', 'laneSpeed'])
        self.log_auto_df = self.op_params.get('log_auto_df')
        if not isinstance(self.log_auto_df, bool):
            self.log_auto_df = False
        self.data_collector = DataCollector(
            file_path='/data/df_data',
            keys=[
                'v_ego', 'a_ego', 'a_lead', 'v_lead', 'x_lead',
                'left_lane_speeds', 'middle_lane_speeds', 'right_lane_speeds',
                'left_lane_distances', 'middle_lane_distances',
                'right_lane_distances', 'profile', 'time'
            ],
            log_data=self.log_auto_df)

    def _setup_changing_variables(self):
        self.TR = self.default_TR
        self.user_profile = self.df_profiles.relaxed  # just a starting point
        self.model_profile = self.df_profiles.relaxed

        self.last_effective_profile = self.user_profile
        self.profile_change_time = 0

        self.sng = False
        self.car_data = CarData()
        self.lead_data = LeadData()
        self.df_data = dfData()  # dynamic follow data

        self.last_cost = 0.0
        self.last_predict_time = 0.0
        self.auto_df_model_data = []
        self._get_live_params()  # so they're defined just in case

    def update(self, CS, libmpc):
        self._get_live_params()
        self._update_car(CS)
        self._get_profiles()

        if self.mpc_id == 1 and self.log_auto_df:
            self._gather_data()

        if not self.lead_data.status:
            self.TR = self.default_TR
        else:
            self._store_df_data()
            self.TR = self._get_TR()

        if not travis:
            self._change_cost(libmpc)
            self._send_cur_state()

        return self.TR

    def _get_profiles(self):
        """This receives profile change updates from dfManager and runs the auto-df prediction if auto mode"""
        df_out = self.df_manager.update()
        self.user_profile = df_out.user_profile
        if df_out.is_auto:  # todo: find some way to share prediction between the two mpcs to reduce processing overhead
            self._get_pred(
            )  # sets self.model_profile, all other checks are inside function

    def _gather_data(self):
        self.sm_collector.update(0)
        # live_tracks = [[i.dRel, i.vRel, i.aRel, i.yRel] for i in self.sm_collector['liveTracks']]
        if self.car_data.cruise_enabled:
            self.data_collector.update([
                self.car_data.v_ego, self.car_data.a_ego,
                self.lead_data.a_lead, self.lead_data.v_lead,
                self.lead_data.x_lead,
                list(self.sm_collector['laneSpeed'].leftLaneSpeeds),
                list(self.sm_collector['laneSpeed'].middleLaneSpeeds),
                list(self.sm_collector['laneSpeed'].rightLaneSpeeds),
                list(self.sm_collector['laneSpeed'].leftLaneDistances),
                list(self.sm_collector['laneSpeed'].middleLaneDistances),
                list(self.sm_collector['laneSpeed'].rightLaneDistances),
                self.user_profile,
                sec_since_boot()
            ])

    def _norm(self, x, name):
        self.x = x
        return interp(x, self.model_scales[name], [0, 1])

    def _send_cur_state(self):
        if self.mpc_id == 1 and self.pm is not None:
            dat = messaging.new_message('dynamicFollowData')
            dat.dynamicFollowData.mpcTR = self.TR
            dat.dynamicFollowData.profilePred = self.model_profile
            self.pm.send('dynamicFollowData', dat)

    def _change_cost(self, libmpc):
        TRs = [0.9, 1.8, 2.7]
        #costs = [1., 0.1, 0.01]     #Original values
        #costs = [1., 0.5, 0.1]      # Last values
        costs = [1., 0.75, 0.5]
        cost = interp(self.TR, TRs, costs)

        # change_time = sec_since_boot() - self.profile_change_time
        # change_time_x = [0, 0.5, 4]  # for three seconds after effective profile has changed
        # change_mod_y = [3, 6, 1]  # multiply cost by multiplier to quickly change distance
        # if change_time < change_time_x[-1]:  # if profile changed in last 3 seconds
        #   cost_mod = interp(change_time, change_time_x, change_mod_y)
        #   cost_mod_speeds = [0, 20 * CV.MPH_TO_MS]  # don't change cost too much under 20 mph
        #   cost_mods = [cost_mod * 0.01, cost_mod]
        #   cost *= interp(cost_mod, cost_mod_speeds, cost_mods)

        if self.last_cost != cost:
            libmpc.change_costs(
                MPC_COST_LONG.TTC, cost, MPC_COST_LONG.ACCELERATION,
                MPC_COST_LONG.JERK
            )  # todo: jerk is the derivative of acceleration, could tune that
            self.last_cost = cost

    def _store_df_data(self):
        cur_time = sec_since_boot()
        # Store custom relative accel over time
        if self.lead_data.status:
            if self.lead_data.new_lead:
                self.df_data.v_rels = []  # reset when new lead
            else:
                self.df_data.v_rels = self._remove_old_entries(
                    self.df_data.v_rels, cur_time, self.v_rel_retention)
            self.df_data.v_rels.append({
                'v_ego': self.car_data.v_ego,
                'v_lead': self.lead_data.v_lead,
                'time': cur_time
            })

        # Store our velocity for better sng
        self.df_data.v_egos = self._remove_old_entries(self.df_data.v_egos,
                                                       cur_time,
                                                       self.v_ego_retention)
        self.df_data.v_egos.append({
            'v_ego': self.car_data.v_ego,
            'time': cur_time
        })

        # Store data for auto-df model
        self.auto_df_model_data.append([
            self._norm(self.car_data.v_ego, 'v_ego'),
            self._norm(self.lead_data.v_lead, 'v_lead'),
            self._norm(self.lead_data.a_lead, 'a_lead'),
            self._norm(self.lead_data.x_lead, 'x_lead')
        ])
        while len(self.auto_df_model_data) > self.model_input_len:
            del self.auto_df_model_data[0]

    def _get_pred(self):
        cur_time = sec_since_boot()
        if self.car_data.cruise_enabled and self.lead_data.status:
            if cur_time - self.last_predict_time > self.predict_rate:
                if len(self.auto_df_model_data) == self.model_input_len:
                    pred = predict(
                        np.array(self.auto_df_model_data[::self.skip_every],
                                 dtype=np.float32).flatten())
                    self.last_predict_time = cur_time
                    self.model_profile = int(np.argmax(pred))

    @staticmethod
    def _remove_old_entries(lst, cur_time, retention):
        return [
            sample for sample in lst if cur_time - sample['time'] <= retention
        ]

    def _relative_accel_mod(self):
        """
    Returns relative acceleration mod calculated from list of lead and ego velocities over time (longer than 1s)
    If min_consider_time has not been reached, uses lead accel and ego accel from openpilot (kalman filtered)
    """
        a_ego = self.car_data.a_ego
        a_lead = self.lead_data.a_lead
        min_consider_time = 0.75  # minimum amount of time required to consider calculation
        if len(self.df_data.v_rels) > 0:  # if not empty
            elapsed_time = self.df_data.v_rels[-1][
                'time'] - self.df_data.v_rels[0]['time']
            if elapsed_time > min_consider_time:
                a_ego = (self.df_data.v_rels[-1]['v_ego'] -
                         self.df_data.v_rels[0]['v_ego']) / elapsed_time
                a_lead = (self.df_data.v_rels[-1]['v_lead'] -
                          self.df_data.v_rels[0]['v_lead']) / elapsed_time

        mods_x = [-1.5, -.75, 0]
        mods_y = [1, 1.25, 1.3]
        if a_lead < 0:  # more weight to slight lead decel
            a_lead *= interp(a_lead, mods_x, mods_y)

        if a_lead - a_ego > 0:  # return only if adding distance
            return 0

        rel_x = [
            -2.6822, -1.7882, -0.8941, -0.447, -0.2235, 0.0, 0.2235, 0.447,
            0.8941, 1.7882, 2.6822
        ]
        mod_y = [
            0.3245 * 1.1, 0.277 * 1.08, 0.11075 * 1.06, 0.08106 * 1.045,
            0.06325 * 1.035, 0.0, -0.09, -0.09375, -0.125, -0.3, -0.35
        ]
        return interp(a_lead - a_ego, rel_x, mod_y)

    def global_profile_mod(self, x_vel, y_dist):
        """
    This function modifies the y_dist list used by dynamic follow in accordance with global_df_mod
    """
        if self.global_df_mod == 1.:
            return y_dist
        global_df_mod = 1 - self.global_df_mod

        # Calculate new TRs
        speeds, mods = [0.], [1.]  # if increasing don't limit
        if self.global_df_mod < 1:  # if reducing distance
            speeds = [
                0, self.sng_speed, 18, x_vel[-1]
            ]  # [0, 18 mph, ~40 mph, highest profile mod speed (~78 mph)]
            mods = [
                0, 0.25, 0.75, 1
            ]  # how much to limit global_df_mod at each speed, 1 is full effect

        return [
            y - (y * global_df_mod * interp(x, speeds, mods))
            for x, y in zip(x_vel, y_dist)
        ]

    def _get_TR(self):
        if self.df_manager.is_auto:  # decide which profile to use, model profile will be updated before this
            df_profile = self.model_profile
        else:
            df_profile = self.user_profile

        if df_profile != self.last_effective_profile:
            self.profile_change_time = sec_since_boot()
        self.last_effective_profile = df_profile

        x_vel = [
            0.0, 1.8627, 3.7253, 5.588, 7.4507, 9.3133, 11.5598, 13.645,
            22.352, 31.2928, 33.528, 35.7632, 40.2336
        ]  # velocities
        if df_profile == self.df_profiles.stock:
            return 1.8
        elif df_profile == self.df_profiles.traffic:  # for in congested traffic
            x_vel = [
                0.0, 1.892, 3.7432, 5.8632, 8.0727, 10.7301, 14.343, 17.6275,
                22.4049, 28.6752, 34.8858, 40.35
            ]
            y_dist = [
                1.3781, 1.3791, 1.3457, 1.3134, 1.3145, 1.318, 1.3485, 1.257,
                1.144, 0.979, 0.9461, 0.9156
            ]
        elif df_profile == self.df_profiles.relaxed:  # default to relaxed/stock
            #y_dist = [1.411, 1.418, 1.428, 1.441, 1.461, 1.49, 1.535, 1.561, 1.589, 1.612, 1.621, 1.632, 1.648]       # Original values
            #y_dist = [1.6, 1.6, 1.6, 1.6, 1.6, 1.6, 1.6, 1.6, 1.6, 1.612, 1.621, 1.632, 1.648]
            #y_dist = [1.411, 1.418, 1.8, 1.9, 2.1, 2.0, 1.8, 1.6, 1.6, 1.612, 1.621, 1.632, 1.648]
            #y_dist = [1.8, 1.8, 1.8, 1.9, 2.1, 2.0, 1.8, 1.6, 1.6, 1.55, 1.5, 1.45, 1.4]      # Last used
            #y_dist = [3., 2.6, 2.2, 2.1, 2.1, 2.0, 1.8, 1.6, 1.6, 1.55, 1.5, 1.45, 1.4]
            y_dist = [
                3., 2.6, 2.2, 2.1, 2.1, 2.0, 1.8, 1.7, 1.7, 1.65, 1.55, 1.45,
                1.4
            ]
        else:
            raise Exception('Unknown profile type: {}'.format(df_profile))

        # Global df mod
        y_dist = self.global_profile_mod(x_vel, y_dist)

        v_rel_dist_factor = self.dmc_v_rel.update(self.lead_data.v_lead -
                                                  self.car_data.v_ego)
        a_lead_dist_factor = self.dmc_a_rel.update(self.lead_data.a_lead -
                                                   self.car_data.a_ego)

        TR = interp(self.car_data.v_ego, x_vel, y_dist)
        TR *= v_rel_dist_factor
        TR *= a_lead_dist_factor

        if self.car_data.v_ego > self.sng_speed:  # keep sng distance until we're above sng speed again
            self.sng = False

        if (self.car_data.v_ego >= self.sng_speed
                or self.df_data.v_egos[0]['v_ego'] >= self.car_data.v_ego
            ) and not self.sng:
            # if above 15 mph OR we're decelerating to a stop, keep shorter TR. when we reaccelerate, use sng_TR and slowly decrease
            TR = interp(self.car_data.v_ego, x_vel, y_dist)
            #TR = TR
        else:  # this allows us to get closer to the lead car when stopping, while being able to have smooth stop and go when reaccelerating
            self.sng = True
            x = [
                self.sng_speed * 0.7, self.sng_speed
            ]  # decrease TR between 12.6 and 18 mph from 1.8s to defined TR above at 18mph while accelerating
            #x = [self.sng_speed * 0.55, self.sng_speed]
            y = [self.sng_TR, interp(self.sng_speed, x_vel, y_dist)]
            TR = interp(self.car_data.v_ego, x, y)

        return float(clip(TR, self.min_TR, 2.7))

        TR_mods = []
        # Dynamic follow modifications (the secret sauce)
        x = [
            -26, -15.6464, -9.8422, -6.0, -4.0, -2.68, -2.3, -1.8, -1.26,
            -0.61, 0, 0.61, 1.26, 2.1, 2.68, 4.4704
        ]  # relative velocity values
        y = [
            1.76, 1.504, 1.34, 1.29, 1.25, 1.22, 1.19, 1.13, 1.053, 1.017, 1.0,
            0.985, 0.958, 0.87, 0.81, 0.685
        ]  # multiplier values
        y = np.array(y) - 1  # converts back to original abs mod
        y *= 1.1  # multiplier for how much to mod
        y = y / TR + 1  # converts back to multipliers
        TR_mods.append(
            interp(self.lead_data.v_lead - self.car_data.v_ego, x, y))

        x = [
            -4.4795, -2.8122, -1.5727, -1.1129, -0.6611, -0.2692, 0.0, 0.1466,
            0.5144, 0.6903, 0.9302
        ]  # lead acceleration values
        y = [
            1.16, 1.1067, 1.0613, 1.0343, 1.0203, 1.0147, 1.0, 0.9898, 0.972,
            0.9647, 0.9607
        ]  # multiplier values
        converted_with_TR = 1.5  # todo: do without numpy and simplify by converting with TR of 1, so only subtract
        absolute_y_TR_mod = np.array(
            y
        ) * converted_with_TR - converted_with_TR  # converts back to original abs mod
        absolute_y_TR_mod *= 1.2  # multiplier for how much to mod
        y = absolute_y_TR_mod / TR + 1  # converts back to multipliers with accel mod of 1.4 taking current TR into account
        TR_mods.append(interp(self.get_rel_accel(), x,
                              y))  # todo: make this over more than 1 sec

        # deadzone = self.car_data.v_ego / 3  # 10 mph at 30 mph  # todo: tune pedal to react similarly to without before adding/testing this
        # if self.lead_data.v_lead - deadzone > self.car_data.v_ego:
        #   TR_mods.append(self._relative_accel_mod())

        # x = [self.sng_speed, self.sng_speed / 5.0]  # as we approach 0, apply x% more distance
        # y = [1.0, 1.05]

        TR *= mean(
            TR_mods
        )  # with mods as multipliers, profile mods shouldn't be needed

        # if (self.car_data.left_blinker or self.car_data.right_blinker) and df_profile != self.df_profiles.traffic:
        #   x = [8.9408, 22.352, 31.2928]  # 20, 50, 70 mph
        #   y = [1.0, .75, .65]
        #   TR *= interp(self.car_data.v_ego, x, y)  # reduce TR when changing lanes

        return float(clip(TR, self.min_TR, 2.7))

    def update_lead(self,
                    v_lead=None,
                    a_lead=None,
                    x_lead=None,
                    status=False,
                    new_lead=False):
        self.lead_data.v_lead = v_lead
        self.lead_data.a_lead = a_lead
        self.lead_data.x_lead = x_lead

        self.lead_data.status = status
        self.lead_data.new_lead = new_lead

    def _update_car(self, CS):
        self.car_data.v_ego = CS.vEgo
        self.car_data.a_ego = CS.aEgo

        self.car_data.left_blinker = CS.leftBlinker
        self.car_data.right_blinker = CS.rightBlinker
        self.car_data.cruise_enabled = CS.cruiseState.enabled

    def _get_live_params(self):
        self.global_df_mod = self.op_params.get('global_df_mod')
        if self.global_df_mod != 1.:
            self.global_df_mod = clip(self.global_df_mod, 0.85, 2.5)

        self.min_TR = self.op_params.get('min_TR')
        if self.min_TR != 1.:
            self.min_TR = clip(self.min_TR, 0.85, 2.7)