Example #1
0
 def __init__(self, camera_type):
     super().__init__()
     if camera_type != self.TYPE_T265 and camera_type != self.TYPE_D435:
         raise Exception("Camera type invalid")
     self.camera_type = camera_type
     self.pipe = None
     self.metadata = {}
     self.threads = []
     self.exit_threads = False
     self.rb_i = RedisBridge(db=self.rd_cfg.databases['instruments'])
     self.rb_r = RedisBridge(db=self.rd_cfg.databases['robot'])
     self._init_frame_metadata_values()
     self._setup_parameters()
     self._setup_threads()
Example #2
0
    def run_main(self):
        rb = RedisBridge(db=self.rd_cfg.databases['robot'])
        self.conn = Connector(self.cfg.ap_to_redis,
                              self.cfg.connection_baudrate, 1, 0)
        params = self.rd_cfg.robot

        while not self.exit_threads:
            try:
                self.conn.send_heartbeat()
                m = self.conn.get_callbacks(params)
                if m is not None:
                    rb.add_key(m.to_json(), m.get_type(), to_json=False)
            except:
                pass
Example #3
0
        def __init__(self, **kwargs):
            super().__init__(**kwargs)

            self.rb = RedisBridge(db=self.rd_cfg.databases['instruments'])
            self.keys = self.rd_cfg.generate_flat_keys('instruments')
            self.conn = mavutil.mavlink_connection(
                self.cfg.redis_to_ap,
                autoreconnect = True,
                source_system = 1,
                source_component = 93,
                baud=self.cfg.connection_baudrate,
                force_connected=True
            )

            self.lock = threading.Lock()
            default_msg_hz = 30.0
            msg_hz = {
                'send_vision_position_estimate': 30.0,
                'send_obstacle_distance': 15.0
            }

            self.mavlink_thread = threading.Thread(target=self.mavlink_loop, args=[self.conn])
            self.mavlink_thread.start()
            self.sched = BackgroundScheduler()
            logging.getLogger('apscheduler').setLevel(logging.ERROR)

            self.data = {}
            for k, v in self.keys.items():
                try:
                    if v in msg_hz.keys():
                        seconds = 1.0/msg_hz[v]
                    else:
                        seconds = 1.0/default_msg_hz
                    
                    func = getattr(self, v)
                    self.sched.add_job(self.send_message, 
                        'interval', 
                        seconds=seconds, 
                        args=[func, k],
                        max_instances=1
                    )
                except:
                    utils.progress(traceback)
                else:
                    self.data[k] = None
Example #4
0
def get_redis_data(database, paginate, paginate_it):
    database = int(database)
    paginate = int(paginate)
    paginate_it = int(paginate_it)

    rb = RedisBridge(db=int(database))
    keys = rd_cfg.generate_flat_keys(database)
    if isinstance(keys, dict):
        keys = list(keys.keys())

    start = (paginate_it - 1) * paginate
    end = start + paginate
    keys = keys[start:end]

    data = {}
    for key in keys:
        data[key] = rb.get_key_by_string(key)

    return json.dumps(data)
Example #5
0
    def _setup_parameters(self):
        self.scale_factor = self.cfg.t265['scale_factor']
        self.jump_threshold = self.cfg.t265['jump_threshold']
        self.jump_speed_threshold = self.cfg.t265['jump_speed_threshold']
        self.compass_enabled = self.cfg.t265['compass_enabled']
        self.heading_north_yaw = None
        self.rb_0 = RedisBridge(db=self.rd_cfg.databases['robot'])

        if self.compass_enabled:
            att = self.rb_0.get_key('ATTITUDE')
            if att is not None:
                self.heading_north_yaw = att['yaw']
            else:
                self.compass_enabled = False
                self.logger.log_warn(
                    "Failed to enable compass, could not retrieve attitude yaw"
                )

        self._initialize_compute_vars()
        # body offset - see initial script

        self.metadata = ['enable_pose_stream']
Example #6
0
class Camera(Base):

    TYPE_T265 = 't265'
    TYPE_D435 = 'd435'

    ALIVE_FLAG = 'alive'

    def __init__(self, camera_type):
        super().__init__()
        if camera_type != self.TYPE_T265 and camera_type != self.TYPE_D435:
            raise Exception("Camera type invalid")
        self.camera_type = camera_type
        self.pipe = None
        self.metadata = {}
        self.threads = []
        self.exit_threads = False
        self.rb_i = RedisBridge(db=self.rd_cfg.databases['instruments'])
        self.rb_r = RedisBridge(db=self.rd_cfg.databases['robot'])
        self._init_frame_metadata_values()
        self._setup_parameters()
        self._setup_threads()

    def start(self):
        for t in self.threads:
            t.start()
            
        self._open_pipe()
        while not self.exit_threads:
            self._process_frames()

    def stop(self):
        self.exit_threads = True
        try:
            self.pipe.stop()
        except:
            self.logger.log_error("Pipe closing")

        for t in self.threads:
            try:
                t.join()
            except:
                self.logger.log_warn("Thread failed to join")
                
    def __enter__(self):
        return self

    def __exit__(self):
        self.stop()

    def _setup_parameters(self):
        # Setup sensor-specific parameters
        raise NotImplementedError

    def _setup_threads(self):
        self.threads = [Thread(target=self._send_metadata)]

    def _send_metadata(self):
        while not self.exit_threads:
            try:
                for key in self.metadata:
                    value = getattr(self, key)
                    self.rb_i.add_key(value, self.camera_type, key, expiry=5)
            except Exception as e:
                self.logger.log_error("Invalid redis metadata: %s" % str(e))

    def _setup_save_dir(self):
        try:
            dir_path = dirname(dirname(dirname(realpath(__file__))))
            datestamp = datetime.datetime.now().strftime("%Y_%m_%d")
            self.save_data_dir = dir_path + "/" + self.cfg.save_data_dir + "/" + datestamp + "/"
            if not os.path.exists(self.save_data_dir):
                os.makedirs(self.save_data_dir)
        except:
            self.logger.log_error("Could not create directory: %s" % self.save_data_dir)

    def _open_pipe(self):    
        raise NotImplementedError

    def _process_frames(self):
        # Process frames from pipe
        raise NotImplementedError

    def _init_frame_metadata_values(self):
        self.frame_metadata_values = []
        for k,v in rs.frame_metadata_value.__dict__.items():
            if k.startswith('__') or k == 'name':
                continue
            self.frame_metadata_values.append(v)

    def _get_gps_data(self):
        gps_data_1 = self.rb_0.get_key('GPS_RAW_INT')
        gps_data_2 = self.rb_0.get_key('GPS2_RAW')
        gps = [None, None, None, None, None, None]

        if gps_data_1 is not None:
            # Use 1
            gps[0] = gps_data_1['lat']
            gps[1] = gps_data_1['lon']
            gps[2] = gps_data_1['fix_type']

        if gps_data_2 is not None:
            # Use 2
            gps[3] = gps_data_2['lat']
            gps[4] = gps_data_2['lon']
            gps[5] = gps_data_2['fix_type']

        return gps
Example #7
0
class CameraT265(Camera):
    def __init__(self):
        self.enable_pose_stream = False
        super().__init__(Camera.TYPE_T265)
        self._setup_save_dir()

    def _setup_parameters(self):
        self.scale_factor = self.cfg.t265['scale_factor']
        self.jump_threshold = self.cfg.t265['jump_threshold']
        self.jump_speed_threshold = self.cfg.t265['jump_speed_threshold']
        self.compass_enabled = self.cfg.t265['compass_enabled']
        self.heading_north_yaw = None
        self.rb_0 = RedisBridge(db=self.rd_cfg.databases['robot'])

        if self.compass_enabled:
            att = self.rb_0.get_key('ATTITUDE')
            if att is not None:
                self.heading_north_yaw = att['yaw']
            else:
                self.compass_enabled = False
                self.logger.log_warn(
                    "Failed to enable compass, could not retrieve attitude yaw"
                )

        self._initialize_compute_vars()
        # body offset - see initial script

        self.metadata = ['enable_pose_stream']

    def _initialize_compute_vars(self):
        self.prev_data = None
        self.reset_counter = 1
        self.current_confidence_level = None

        # Initialize with camera orientation
        self.H_aeroRef_T265Ref = np.array([[0, 0, -1, 0], [1, 0, 0, 0],
                                           [0, -1, 0, 0], [0, 0, 0, 1]])
        xr = m.radians(self.cfg.t265['camera_rot_x'])
        yr = m.radians(self.cfg.t265['camera_rot_y'])
        zr = m.radians(self.cfg.t265['camera_rot_z'])
        self.H_T265body_aeroBody = (tf.euler_matrix(xr, yr, zr)).dot(
            np.linalg.inv(self.H_aeroRef_T265Ref))
        self.H_aeroRef_aeroBody = None

        # V_aeroRef_aeroBody # vision speed estimate message
        # H_aeroRef_PrevAeroBody # vision position delta message

        self.frames = None
        self.pose_estimate_data = None

    def _setup_threads(self):
        super()._setup_threads()
        self.threads.append(Thread(target=self._save_pos_estimate))

    def _save_pos_estimate(self):
        csv_file = self.save_data_dir + 't265_pos_estimate.csv'
        file_exists = os.path.exists(csv_file)
        with open(csv_file, 'a+', newline='') as csvfile:
            csvwriter = csv.writer(csvfile, delimiter=',')
            if not file_exists:
                header = [
                    'current_time_us', 'local_x_pos', 'local_y_pos',
                    'local_z_pos', 'roll_angle', 'pitch_angle', 'yaw_angle',
                    'covariance', 'reset_counter', 'gps_1_lat', 'gps_1_lon',
                    'gps_1_fix_type', 'gps_2_lat', 'gps_2_lon',
                    'gps_2_fix_type'
                ]
                csvwriter.writerow(header)

            while not self.exit_threads:
                self.rb_i.add_key(self.pose_estimate_data,
                                  self.camera_type,
                                  'vision_position_estimate',
                                  expiry=self.cfg.t265['save_redis_expiry'])
                self._save_csv(csvwriter, self.pose_estimate_data)

    def _save_csv(self, csvwriter, data):
        if data:
            try:
                data += self._get_gps_data()
                csvwriter.writerow(data)
            except Exception as e:
                self.logger.log_warn("Could not write pose data to csv: %s" %
                                     e)

    def _realsense_notification_callback(notif):
        self.logger.log_info(notif)

    def _open_pipe(self):
        self.pipe = rs.pipeline()
        config = rs.config()
        config.enable_stream(rs.stream.pose)
        device = config.resolve(self.pipe).get_device()
        pose_sensor = device.first_pose_sensor()
        pose_sensor.set_notifications_callback(
            self._realsense_notification_callback)
        self.enable_pose_stream = True
        self.pipe.start(config)

    def _process_frames(self):
        self.frames = self.pipe.wait_for_frames()
        pose = self.frames.get_pose_frame()
        if pose:
            # Pose data consists of translation and rotation
            data = pose.get_pose_data()

            # Confidence level value from T265: 0-3, remapped to 0 - 100: 0% - Failed / 33.3% - Low / 66.6% - Medium / 100% - High
            self.current_confidence_level = float(data.tracker_confidence *
                                                  100 / 3)

            # In transformations, Quaternions w+ix+jy+kz are represented as [w, x, y, z]!
            H_T265Ref_T265body = tf.quaternion_matrix([
                data.rotation.w, data.rotation.x, data.rotation.y,
                data.rotation.z
            ])
            H_T265Ref_T265body[0][3] = data.translation.x * self.scale_factor
            H_T265Ref_T265body[1][3] = data.translation.y * self.scale_factor
            H_T265Ref_T265body[2][3] = data.translation.z * self.scale_factor

            # Transform to aeronautic coordinates (body AND reference frame!)
            self.H_aeroRef_aeroBody = self.H_aeroRef_T265Ref.dot(
                H_T265Ref_T265body.dot(self.H_T265body_aeroBody))

            # vision_speed_estimate_message
            # Calculate GLOBAL XYZ speed (speed from T265 is already GLOBAL)
            # V_aeroRef_aeroBody = tf.quaternion_matrix([1,0,0,0])
            # V_aeroRef_aeroBody[0][3] = data.velocity.x
            # V_aeroRef_aeroBody[1][3] = data.velocity.y
            # V_aeroRef_aeroBody[2][3] = data.velocity.z
            # V_aeroRef_aeroBody = H_aeroRef_T265Ref.dot(V_aeroRef_aeroBody)

            # Check for pose jump and increment reset_counter
            if self.prev_data is not None:
                delta_translation = [
                    data.translation.x - self.prev_data.translation.x,
                    data.translation.y - self.prev_data.translation.y,
                    data.translation.z - self.prev_data.translation.z
                ]
                delta_velocity = [
                    data.velocity.x - self.prev_data.velocity.x,
                    data.velocity.y - self.prev_data.velocity.y,
                    data.velocity.z - self.prev_data.velocity.z
                ]
                position_displacement = np.linalg.norm(delta_translation)
                speed_delta = np.linalg.norm(delta_velocity)

                if (position_displacement > self.jump_threshold) or (
                        speed_delta > self.jump_speed_threshold):
                    if position_displacement > self.jump_threshold:
                        self.logger.log_warn("Position jumped by: %s" %
                                             position_displacement)
                    elif speed_delta > self.jump_speed_threshold:
                        self.logger.log_warn("Speed jumped by: %s" %
                                             speed_delta)
                    self._increment_reset_counter()

            self.prev_data = data

            # Take offsets from body's center of gravity (or IMU) to camera's origin into account
            # if self.body_offset_enabled == 1:
            #     H_body_camera = tf.euler_matrix(0, 0, 0, 'sxyz')
            #     H_body_camera[0][3] = body_offset_x
            #     H_body_camera[1][3] = body_offset_y
            #     H_body_camera[2][3] = body_offset_z
            #     H_camera_body = np.linalg.inv(H_body_camera)
            #     H_aeroRef_aeroBody = H_body_camera.dot(H_aeroRef_aeroBody.dot(H_camera_body))

            # Realign heading to face north using initial compass data
            if self.compass_enabled:
                self.H_aeroRef_aeroBody = self.H_aeroRef_aeroBody.dot(
                    tf.euler_matrix(0, 0, self.heading_north_yaw, 'sxyz'))

            self._compute_pose_estimate(data)

    def _increment_reset_counter(self):
        if self.reset_counter >= 255:
            self.reset_counter = 1
        self.reset_counter += 1

    def _compute_pose_estimate(self, data):
        if self.H_aeroRef_aeroBody is not None:
            current_time_us = int(round(time.time() * 1000000))

            # Setup angle data
            rpy_rad = np.array(
                tf.euler_from_matrix(self.H_aeroRef_aeroBody, 'sxyz'))

            # Setup covariance data, which is the upper right triangle of the covariance matrix, see here: https://files.gitter.im/ArduPilot/VisionProjects/1DpU/image.png
            # Attemp #01: following this formula https://github.com/IntelRealSense/realsense-ros/blob/development/realsense2_camera/src/base_realsense_node.cpp#L1406-L1411
            cov_pose = self.cfg.t265['linear_accel_cov'] * pow(
                10, 3 - int(data.tracker_confidence))
            cov_twist = self.cfg.t265['angular_vel_cov'] * pow(
                10, 1 - int(data.tracker_confidence))
            covariance = [
                cov_pose, 0, 0, 0, 0, 0, cov_pose, 0, 0, 0, 0, cov_pose, 0, 0,
                0, cov_twist, 0, 0, cov_twist, 0, cov_twist
            ]

            self.pose_estimate_data = [
                current_time_us,
                self.H_aeroRef_aeroBody[0][3],  # Local X position
                self.H_aeroRef_aeroBody[1][3],  # Local Y position
                self.H_aeroRef_aeroBody[2][3],  # Local Z position
                rpy_rad[0],  # Roll angle
                rpy_rad[1],  # Pitch angle
                rpy_rad[2],  # Yaw angle
                covariance,  # Row-major representation of pose 6x6 cross-covariance matrix
                self.
                reset_counter  # Estimate reset counter. Increment every time pose estimate jumps.
            ]
            self.logger.log_debug("Captured pose estimate data: %s" %
                                  str(self.pose_estimate_data))
Example #8
0
    class __RedisToAPScripterExt(Scripter):

        def __init__(self, **kwargs):
            super().__init__(**kwargs)

            self.rb = RedisBridge(db=self.rd_cfg.databases['instruments'])
            self.keys = self.rd_cfg.generate_flat_keys('instruments')
            self.conn = mavutil.mavlink_connection(
                self.cfg.redis_to_ap,
                autoreconnect = True,
                source_system = 1,
                source_component = 93,
                baud=self.cfg.connection_baudrate,
                force_connected=True
            )

            self.lock = threading.Lock()
            default_msg_hz = 30.0
            msg_hz = {
                'send_vision_position_estimate': 30.0,
                'send_obstacle_distance': 15.0
            }

            self.mavlink_thread = threading.Thread(target=self.mavlink_loop, args=[self.conn])
            self.mavlink_thread.start()
            self.sched = BackgroundScheduler()
            logging.getLogger('apscheduler').setLevel(logging.ERROR)

            self.data = {}
            for k, v in self.keys.items():
                try:
                    if v in msg_hz.keys():
                        seconds = 1.0/msg_hz[v]
                    else:
                        seconds = 1.0/default_msg_hz
                    
                    func = getattr(self, v)
                    self.sched.add_job(self.send_message, 
                        'interval', 
                        seconds=seconds, 
                        args=[func, k],
                        max_instances=1
                    )
                except:
                    utils.progress(traceback)
                else:
                    self.data[k] = None

        # https://mavlink.io/en/messages/common.html#VISION_POSITION_ESTIMATE
        def send_vision_position_estimate(self, current_time_us, x, y, z, 
            roll, pitch, yaw, covariance, reset_counter):
            # self.connect(self.connection_string, self.connection_baudrate, self.source_system, self.source_component)
            self.conn.mav.vision_position_estimate_send(
                current_time_us,        # us Timestamp (UNIX time or time since system boot)
                x,                      # Local X position
                y,                      # Local Y position
                z,                      # Local Z position
                roll,	                # Roll angle
                pitch,	                # Pitch angle
                yaw,	                # Yaw angle
                covariance,             # Row-major representation of pose 6x6 cross-covariance matrix
                reset_counter           # Estimate reset counter. Increment every time pose estimate jumps.
            )

    # def send_vision_position_delta_message(self, current_time_us, delta_time_us, delta_angle_rad, delta_position_m, current_confidence_level):
    #     conn.mav.vision_position_delta_send(
    #             current_time_us,    # us: Timestamp (UNIX time or time since system boot)
    #             delta_time_us,	    # us: Time since last reported camera frame
    #             delta_angle_rad,    # float[3] in radian: Defines a rotation vector in body frame that rotates the vehicle from the previous to the current orientation
    #             delta_position_m,   # float[3] in m: Change in position from previous to current frame rotated into body frame (0=forward, 1=right, 2=down)
    #             current_confidence_level # Normalized confidence value from 0 to 100. 
    #         )

    # def send_vision_speed_estimate(self, current):
    #     self.conn.mav.vision_speed_estimate_send(
    #         current_time_us,            # us Timestamp (UNIX time or time since system boot)
    #         V_aeroRef_aeroBody[0][3],   # Global X speed
    #         V_aeroRef_aeroBody[1][3],   # Global Y speed
    #         V_aeroRef_aeroBody[2][3],   # Global Z speed
    #         covariance,                 # covariance
    #         reset_counter               # Estimate reset counter. Increment every time pose estimate jumps.
    #     )
    
        # https://mavlink.io/en/messages/common.html#OBSTACLE_DISTANCE
        def send_obstacle_distance(self, current_time_us, sensor_type, distances, increment,
            min_distance, max_distance, increment_f, angle_offset, mav_frame):
            # self.connect(self.connection_string, self.connection_baudrate, self.source_system, self.source_component)
            self.conn.mav.obstacle_distance_send(
                current_time_us,    # us Timestamp (UNIX time or time since system boot)
                sensor_type,        # sensor_type, defined here: https://mavlink.io/en/messages/common.html#MAV_DISTANCE_SENSOR
                distances,          # distances,    uint16_t[72],   cm
                increment,          # increment,    uint8_t,        deg
                min_distance,	    # min_distance, uint16_t,       cm
                max_distance,       # max_distance, uint16_t,       cm
                increment_f,	    # increment_f,  float,          deg
                angle_offset,       # angle_offset, float,          deg
                mav_frame           # MAV_FRAME, vehicle-front aligned: https://mavlink.io/en/messages/common.html#MAV_FRAME_BODY_FRD    
            )

        def run_main(self):
            self.sched.start()
            while not self.exit_threads:
                with self.lock:
                    for k, _ in self.keys.items():
                        self.data[k] = self.rb.get_key_by_string(k)
                    # time.sleep(0.3)
                    
                # self.conn.send_heartbeat()
                # m = self.conn.get_callbacks(['HEARTBEAT'])
                # if m is None:
                #     continue
                # self.logger.log_debug("Received callback: %s" % m)
                # # utils.progress(m)

        def mavlink_loop(self, conn, callbacks=['HEARTBEAT']):
            while not self.exit_threads:
                self.conn.mav.heartbeat_send(mavutil.mavlink.MAV_TYPE_ONBOARD_CONTROLLER,
                                    mavutil.mavlink.MAV_AUTOPILOT_GENERIC,
                                    0,
                                    0,
                                    0)
                m = self.conn.recv_match(type=callbacks, timeout=1, blocking=True)
                if m is None:
                    continue
                self.logger.log_debug("Received callback: %s" % m)

        def send_message(self, func, key):
            while not self.exit_threads:
                with self.lock:
                    try:
                        value = self.data[key]
                        if value is not None:
                            func(*value)
                    except Exception as e:
                        self.logger.log_error("Could not send %s"%e)

        def close_script(self):
            try:
                self.sched.shutdown()
                self.mavlink_thread.join()
                self.conn.close()
            except:
                pass
Example #9
0
    class __RedisToAPScripterExt(Scripter):
        def __init__(self, connection, **kwargs):
            super().__init__(**kwargs)
            self.rb = RedisBridge(db=self.rd_cfg.databases['instruments'])
            self.keys = self.rd_cfg.generate_flat_keys('instruments')
            self.conn = connection
            self.lock = threading.Lock()
            default_msg_hz = 30.0
            msg_hz = {
                'send_vision_position_estimate': 30.0,
                'send_obstacle_distance': 15.0
            }

            self.mavlink_thread = threading.Thread(target=self.mavlink_loop,
                                                   args=[self.conn])
            self.mavlink_thread.start()
            self.sched = BackgroundScheduler()
            logging.getLogger('apscheduler').setLevel(logging.ERROR)

            self.data = {}
            for k, v in self.keys.items():
                try:
                    if v in msg_hz.keys():
                        seconds = 1.0 / msg_hz[v]
                    else:
                        seconds = 1.0 / default_msg_hz

                    func = getattr(self.conn, v)
                    self.sched.add_job(self.send_message,
                                       'interval',
                                       seconds=seconds,
                                       args=[func, k],
                                       max_instances=1)
                except:
                    utils.progress(traceback)
                else:
                    self.data[k] = None

        def run_main(self):
            self.sched.start()
            while not self.exit_threads:
                with self.lock:
                    for k, _ in self.keys.items():
                        self.data[k] = self.rb.get_key_by_string(k)
                    time.sleep(0.3)

                # self.conn.send_heartbeat()
                # m = self.conn.get_callbacks(['HEARTBEAT'])
                # if m is None:
                #     continue
                # self.logger.log_debug("Received callback: %s" % m)
                # # utils.progress(m)

        def mavlink_loop(self, conn, callbacks=['HEARTBEAT']):
            while not self.exit_threads:
                self.conn.send_heartbeat()
                m = self.conn.get_callbacks(callbacks)
                if m is None:
                    continue
                self.logger.log_debug("Received callback: %s" % m)

        def send_message(self, func, key):
            while not self.exit_threads:
                with self.lock:
                    try:
                        value = self.data[key]
                        if value is not None:
                            func(*value)
                    except Exception as e:
                        self.logger.log_error("Could not send %s" % e)

        def close_script(self):
            try:
                self.sched.shutdown()
                self.mavlink_thread.join()
                self.conn.disconnect()
            except:
                pass
Example #10
0
def controls_tab():
    rgb_status = get_switch_status(controls['rgb_capture'], False)
    depth_status = get_switch_status(controls['depth_capture'], False)
    infrared_status = get_switch_status(controls['infrared_capture'], False)

    return render_template('main.html',
                           tab="controls",
                           tab_html="controls_tab.html",
                           controls=controls,
                           rgb_status=rgb_status,
                           depth_status=depth_status,
                           infrared_status=infrared_status)


rd_cfg = RedisConfig()
rb = RedisBridge(db=rd_cfg.databases['instruments'])


@app.route('/controls/set/<switch>/<value>')
def set_switch(switch, value):
    msg = "Setting switch "
    switch = int(switch)
    value = int(value)
    if switch == controls['ekf_source']:
        msg += "EKF source to "
        try:
            switch = EKFSwitch()
            switch.set_ekf_source(value)
        except:
            pass