def __init__(self, speed): super().__init__(name='FollowCamera') self.drivetrain = self.getRobot().drivetrain self.requires(self.drivetrain) self.logger = self.getRobot().logger self.angle = 0.0 self.speed = -speed self.rotation = 0.0 self.pidOutput = 0.0 self.distance = 0 NetworkTables.addConnectionListener(self.connectionListener, immediateNotify=True) self.smartDashboard = NetworkTables.getTable('SmartDashboard') self.smartDashboard.addEntryListener(self.valueChanged) kP = robotmap.camera_kP kD = robotmap.camera_kD kI = robotmap.camera_kI self.pid = wpilib.PIDController(kP, kI, kD, lambda: self.getAngle(), lambda r: self.setRotation(r)) self.pid.setAbsoluteTolerance(0.01) self.pid.setInputRange(0, 640) self.pid.setSetpoint(320) self.pid.setOutputRange(-1.0, 1.0) self.pid.setContinuous(True)
def main(): wsclients = set() allKeys = dict() def updateClients(): data = json.dumps(allKeys) for ws in wsclients: asyncio.run(ws.send(data)) def connectionListener(connected, info): print(info, "; Connected=%s" % connected) def valueChanged(key, value, isNew): allKeys[key] = value updateClients() NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) NetworkTables.addEntryListener(valueChanged) async def wshandler(ws, path): wsclients.add(ws) await ws.wait_closed() wsclients.remove(ws) start_server = websockets.serve(wshandler, '127.0.0.1', 5678) asyncio.get_event_loop().run_until_complete(start_server) asyncio.get_event_loop().run_forever()
def networkTablesConnect(): NetworkTables.initialize(server='10.9.67.2') NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) with cond: print("Waiting for robot to connect") if not notified[0]: cond.wait()
def __init__(self, **kwargs): tableName = kwargs.get('tableName', 'SmartDashboard') server = kwargs.get('server', '10.55.49.2') cond = threading.Condition() notified = [False] self.Connected = False def connectionListener(connected, info): print(info, '; Connected=%s' % connected) with cond: notified[0] = True cond.notify() NetworkTables.initialize(server=server) NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) with cond: print("Waiting") if not notified[0]: cond.wait() self.Connected = True print("Connected!") self.table = NetworkTables.getTable(tableName)
def robotInit(self): #update channels self.frontR = wpi.Talon(1) self.frontL = wpi.Talon(2) self.rearR = wpi.Talon(0) self.rearL = wpi.Talon(3) self.gyro = wpi.AnalogGyro(0) self.joystick = wpi.Joystick(0) self.right = wpi.SpeedControllerGroup(self.frontR, self.rearR) self.left = wpi.SpeedControllerGroup(self.frontL, self.rearL) self.dTrain = wpi.drive.DifferentialDrive(self.right, self.left) self.xDeadZone = .05 self.yDeadZone = .05 self.xConstant = .55 self.yConstant = .85 logging.basicConfig(level=logging.DEBUG) NetworkTables.initialize(server='10.28.75.2') NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) with cond: print("Waiting") if not notified[0]: cond.wait() print("Connected") self.table = NetworkTables.getTable('SmartDashboard')
def connect(self): """ Connect to robot NetworkTables server """ NetworkTables.initialize() NetworkTables.addConnectionListener(self.connectionListener, immediateNotify=True)
def __init__(self, name: str): """ Create a networktables server, and create the vision table. :param name: The name of the target. """ self.name = name self.prefix = '/vision/' + self.name + '_' self.team_number = 5987 # The values file for the target, with a default value for when no such file exists self.file = File( self.name, '[NetworkTables Storage 3.0]\nstring "/vision/{}_name"={}', 'values', 'nt'.format(self.name, self.name)) # Server IP returned by get_nt_server() server = self.get_nt_server() # Set update rate as defined in constants.py NetworkTables.setUpdateRate(constants.NT_RATE) logging.info( 'Initiating network tables connection with {}'.format(server)) NetworkTables.initialize(server=server) NetworkTables.addConnectionListener(self.connection_listener, immediateNotify=True) # Create individual table instead of clogging SmartDashboard self.table = NetworkTables.getTable('vision')
def run(self): # Determine what IP to connect to try: server = sys.argv[1] # Save the robot ip if not os.path.exists(self.cache_file): with open(self.cache_file, 'w') as fp: fp.write(server) except IndexError: try: with open(self.cache_file) as fp: server = fp.read().strip() except IOError: print("Usage: logger.py [10.xx.yy.2]") return logger.info("NT server set to %s", server) NetworkTables.initialize(server=server) # Use listeners to receive the data NetworkTables.addConnectionListener(self.connectionListener, immediateNotify=True) NetworkTables.addEntryListener(self.valueChanged) # When new data is queued, write it to disk while True: name, data = self.queue.get() with open(name, 'w') as fp: json.dump(data, fp)
def connectToNetworkTables(address): cond = threading.Condition() notified = [False] def connectionListener(connected, info): if (connected): print("Connected to NetworkTables at ", str(info.remote_ip) + ":" + str(info.remote_port)) else: input("Could not connect to NetworkTables. Click enter to exit.") sys.exit() with cond: notified[0] = True cond.notify() NetworkTables.initialize(server=address) NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) with cond: print("Waiting for NetworkTable Connection...") if not notified[0]: cond.wait() return NetworkTables.getTable("SmartDashboard")
def main(): ''' Main method, runs when program is run. ''' #Resets the symlinks to vid source 50 and 51, connecting them to usb ports os.system("sudo rm -f /dev/video" + ` front_capture_source `) os.system("sudo rm -f /dev/video" + ` back_capture_source `) os.system( "sudo ln -s /dev/v4l/by-path/platform-3f980000.usb-usb-0:1.5:1.0-video-index0 /dev/video" + ` front_capture_source `) os.system( "sudo ln -s /dev/v4l/by-path/platform-3f980000.usb-usb-0:1.3:1.0-video-index0 /dev/video" + ` back_capture_source `) #Uncomment when saving images os.system("rm -rf output") os.system("mkdir output") #Initializes connection to RIO NetworkTables.initialize(server=ROBORIO_IP) NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) #Waits until RIO is connected before continuing with cond: if not notified[0]: print("waiting") cond.wait() table = NetworkTables.getTable(NETWORK_TABLE_NAME) table.addEntryListener(checkEnabled) #Video capture / resizing stuff global vs_front global vs_back vs_front = ThreadedVideo(screen_resize, front_capture_source) vs_back = ThreadedVideo(screen_resize, back_capture_source) # This may not need to be calculated, can use Andra's precalculated values global vert_focal_length global hor_focal_length vert_focal_length = find_vert_focal_length(vs_front.raw_read()[0], camera_fov_vertical) hor_focal_length = find_hor_focal_length(vs_front.raw_read()[0], camera_fov_horizontal) global frames frames = 0 # vs_front.reset_stream() # vs_back.reset_stream() # input_raw = vs_front.raw_read() # input_image = input_raw[0] # masked_image = find_colored_object(input_image) # cv2.imwrite("output/mask_%d.jpg"%frames, masked_image) # cv2.imwrite("output/frame_%d.jpg"%frames,input_image) while True: time.sleep(1)
def main(): """Run this file to process vision code. Please go to README.md to learn how to use this properly By Grant Perkins, 2018 """ # Initialize pipeline, image, camera server pipe = GripPipeline() img = np.zeros(shape=(480, 640, 3), dtype=np.uint8) cs = CameraServer.getInstance() camera = cs.startAutomaticCapture() camera.setResolution(640, 480) camera.setFPS(20) camera.setExposureManual(40) # Get a CvSink. This will capture images from the camera cvsink = cs.getVideo() # Wait on vision processing until connected to Network Tables cond = threading.Condition() notified = [False] def listener(connected, info): print(info, '; Connected=%s' % connected) with cond: notified[0] = True cond.notify() NetworkTables.initialize(server='roborio-1100-frc.local') NetworkTables.addConnectionListener(listener, immediateNotify=True) with cond: print("Waiting") if not notified[0]: # Wait until connected. cond.wait() is exited once listener is called by ConnectionListener cond.wait() print("Connected!") table = NetworkTablesInstance.getDefault().getTable("Pi") imagetaken = False last = -1 while True: time.sleep(.4) # Tell the CvSink to grab a frame from the camera and put it # in the source image. If there is an error notify the output. t, img = cvsink.grabFrame(img) if t == 0: continue pipe.process(img) cx, cy = pipe.get_centeroid() area = pipe.get_area() print(cx) if cx != last and cx != -1: print(cx) last = cx table.getEntry("centerx").setDouble(cx) table.getEntry("centery").setDouble(cy) table.getEntry("area").setDouble(area)
def __init__(self, update_callback): """ :param update_callback: A callable with signature ```callable(update)``` for processing outgoing updates formatted as strings. """ self.update_callback = update_callback NetworkTables.addGlobalListener(self._nt_on_change, immediateNotify=True) NetworkTables.addConnectionListener(self._nt_connected, immediateNotify=True)
def main(): NetworkTables.initialize(server=ip) NetworkTables.addConnectionListener(_connectionListener, immediateNotify=True) server_address = ("", 8080) httpd = HTTPServer(server_address, RequestHandler) try: httpd.serve_forever() except KeyboardInterrupt: pass httpd.server_close()
def __init__(self, serverIP): try: # IPAddress can be # - None: means run as fake server # - ip: "10.49.15.2" or # - name: "roboRIO-4915-FRC", "localhost" if serverIP != None: # we're a client self.asServer = False NetworkTables.initialize(server=serverIP) NetworkTables.setUpdateRate(.01) # default is .05 (50ms/20Hz), .01 (10ms/100Hz) else: # we're fake server self.asServer = True NetworkTables.initialize() theComm = self # for callback access # update the dashboard with our state, NB: this is a different table # that both the vision and control tables. self.sd = NetworkTables.getTable("SmartDashboard") self.sd.putString("Vision/Status", "OK") self.updateVisionState("Standby") # We communcate target to robot via Vision table, # current thinking is that this should not be a subtable of # SmartDashboard, since traffic is multiplied by the number # of clients. self.visionTable = NetworkTables.getTable("Vision") self.controlTable = NetworkTables.getTable("VisionControl") self.control = Control() self.target = Target() self.fpsHistory = [] self.lastUpdate = time.time() # Robot communicates to us via fields within the Vision/Control # SubTable we opt for a different table to ensure we # receive callbacks from our own writes. if self.asServer: # as server, we're interested in reporting connections NetworkTables.addConnectionListener(self.connectionListener, immediateNotify=True) else: # as vision controller, we're interested in acting upon # vision control events. self.controlTable.addEntryListener(self.visionControlEvent) except: xcpt = sys.exc_info() print("ERROR initializing network tables", xcpt[0]) traceback.print_tb(xcpt[2])
def __init__(self): NetworkTables.initialize(server='10.36.36.2') NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) with cond: print("Waiting") if not notified[0]: cond.wait() # Insert your processing code here print("Connected!") self.__sd = NetworkTables.getTable('SmartDashboard')
def startNetworkTables(): NetworkTables.startClientTeam(668) NetworkTables.initialize( server='10.6.68.2') #roborio must be on this static ip NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) with cond: print("Waiting") if not notified[0]: cond.wait() print("Connected!")
def __init__(self, serverIP): global theComm try: # IPAddress can be # - None: means run as fake server # - ip: "10.49.15.2" or # - name: "roboRIO-4915-FRC", "localhost" if serverIP != None: # we're a client self.asServer = False NetworkTables.initialize(server=serverIP) # don't override updaterate as it apparently causes # odd behavior. else: # we're fake server self.asServer = True NetworkTables.initialize() theComm = self # for callback access # update the dashboard with our state, NB: this is a different table # that both the vision and control tables. self.sd = NetworkTables.getTable("SmartDashboard") self.sd.putString("Vision/Status", "Connected") self.UpdateVisionState("Standby") # We communicate target to robot via Vision table. # TODO: Should be cut later self.controlTable = NetworkTables.getTable("/VisionControl") self.robotTable = NetworkTables.getTable( "/SmartDashboard/RobotState") self.control = Control() # Robot communicates to us via fields within the Vision/Control # SubTable we opt for a different table to ensure we # receive callbacks from our own writes. if self.asServer: # as server, we're interested in reporting connections NetworkTables.addConnectionListener(self.connectionListener, immediateNotify=True) else: # as vision controller, we're interested in acting upon # vision control events. self.controlTable.addEntryListener(self.visionControlEvent) except: xcpt = sys.exc_info() logging.info("ERROR initializing network tables", xcpt[0]) traceback.print_tb(xcpt[2])
def __init__(self): cond = threading.Condition() notified = [False] NetworkTables.initialize(server='10.25.77.2') NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) self.nt = NetworkTables.getTable("SmartDashboard") self.__hsv_threshold_hue = [ self.nt.getNumber("hueMin", defaults[0]), self.nt.getNumber("hueMax", defaults[1]) ] self.__hsv_threshold_saturation = [ self.nt.getNumber("satMin", defaults[2]), self.nt.getNumber("satMax", defaults[3]) ] self.__hsv_threshold_value = [ self.nt.getNumber("valMin", defaults[4]), self.nt.getNumber("valMax", defaults[5]) ] self.hsv_threshold_output = None self.__blur_input = self.hsv_threshold_output self.__blur_type = BlurType.Box_Blur #self.__blur_type = BlurType.Gaussian_Blur self.__blur_radius = 1 self.blur_output = None self.__find_contours_input = self.blur_output self.__find_contours_external_only = False self.find_contours_output = None self.__filter_contours_contours = self.find_contours_output self.__filter_contours_min_area = 50.0 self.__filter_contours_min_perimeter = 10.0 self.__filter_contours_min_width = 00.0 self.__filter_contours_max_width = 1000.0 self.__filter_contours_min_height = 10.0 self.__filter_contours_max_height = 1000.0 self.__filter_contours_solidity = [58.45323741007194, 100.0] self.__filter_contours_max_vertices = 1000000.0 self.__filter_contours_min_vertices = 0.0 self.__filter_contours_min_ratio = 0.0 self.__filter_contours_max_ratio = 1000.0 self.filter_contours_output = None
def connect(): if STATE.connect_handle: STATE.mainGUI.after_cancel(STATE.connect_handle) if STATE.team_number.get() != 0: NetworkTables.startClientTeam(STATE.team_number.get()) else: NetworkTables.initialize(server="localhost") NetworkTables.addConnectionListener(RUNNER.connectionListener, immediateNotify=True) NetworkTables.addEntryListener(RUNNER.valueChanged) STATE.connected.set("Connecting...") waitForConnection()
def setup(): global ip global table # if there was another argument sent, set the ip to it, otherwise use the default ip if len(sys.argv) == 2: ip = sys.argv[1] logging.basicConfig(level=logging.DEBUG) NetworkTables.initialize(server=ip) NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) table = NetworkTables.getTable("simulation") table.addEntryListener(listener=entryChanged, immediateNotify=True, key=None, localNotify=False)
def connect(): cond = threading.Condition() notified = [False] def connectionListener(connected, info): print(info, '; Connected=%s' % connected) with cond: notified[0] = True cond.notify() NetworkTables.initialize(server='roborio-2643-frc.local') NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) with cond: print("Waiting") if not notified[0]: cond.wait()
def connect(self, callback): if self.connected or self.connecting: self.logger.warn( "connect: connecting=%r, connected=%r", self.connecting, self.connected, ) return def connection_listener(is_connected, info): self.connecting = False self.connected = is_connected if not is_connected: self.logger.debug("disconnected from NT server") return root = NetworkTables.getGlobalTable() if not root.containsSubTable("Deadeye"): self.logger.fatal( "Deadeye subtable missing from Network Tables") NetworkTables.shutdown() callback(False) return if is_connected: self.logger.info("connected to NT server at %s", info.remote_ip) else: self.logger.error("connection to NT server failed: %s", info) callback(True) self.connecting = True self.logger.info("connecting to NT server at %s:%i", DEADEYE_NT_SERVER, DEADEYE_NT_PORT) # NetworkTables.initialize(server=DEADEYE_NT_SERVER) NetworkTables.startClient((DEADEYE_NT_SERVER, DEADEYE_NT_PORT)) NetworkTables.addConnectionListener(connection_listener, immediateNotify=True)
async def initialize(self): # cond = threading.Condition() # notified = [False] def connectionListener(connected, info): print(info, '; Connected=%s' % connected) # with cond: # notified[0] = True # cond.notify() NetworkTables.initialize(server='10.80.15.2') NetworkTables.addConnectionListener( connectionListener, immediateNotify=True) self.table_NANO_to_RIO = NetworkTables.getTable('NANO-TO-RIO') self.table_RIO_to_NANO = NetworkTables.getTable('RIO-TO-NANO') # self.sensorTable = return True
def run(self): # Determine what IP to connect to try: server = sys.argv[1] # Save the robot ip if not os.path.exists(self.cache_file): with open(self.cache_file, 'w') as fp: fp.write(server) except IndexError: try: with open(self.cache_file) as fp: server = fp.read().strip() except IOError: print("Usage: logger.py [10.xx.yy.2]") return logger.info("NT server set to %s", server) NetworkTables.initialize(server=server) # Use listeners to receive the data NetworkTables.addConnectionListener(self.connectionListener, immediateNotify=True) NetworkTables.addEntryListener(self.valueChanged) # When new data is queued, write it to disk while True: name, data = self.queue.get() with open(name, 'w') as fp: fp.write( "timestamp,robot_x,robot_y,robot_yaw,path_x,path_y,path_yaw,path_x_vel,path_y_vel,path_x_accel," "path_y_accel,robot_x_vel,robot_y_vel,x_error,y_error,yaw_error,x_power,y_power,yaw_power\n" ) for line in data: fp.write(",".join([str(f) for f in list(line)]) + "\n") name, data = self.queue_pref.get() with open(name, 'w') as fp: fp.write(json.dumps(data))
def networkTableSetup(): global table cond = threading.Condition() notified = [False] def connectionListener(connected, info): print(info, '; Connected=%s' % connected) with cond: notified[0] = True cond.notify() NetworkTables.initialize(server='10.55.15.2') NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) with cond: print("Waiting") if not notified[0]: cond.wait() print("Connected!") table = NetworkTables.getTable('datatable')
def connect(): cond=threading.Condition() notified=[False] def connectionListener(connected, info): print(info, '; Connected=%s' % connected) with cond: notified[0]=True cond.notify() NetworkTables.initialize(server = '10.26.43.2') NetworkTables.addConnectionListener( connectionListener, immediateNotify = True ) with cond: print("Waiting") if not notified[0]: cond.wait() return NetworkTables.getTable('Vision')
def __init__(self, name): """ This is a class for handling all networktables operations, mainly starting a server and sending to and receiving variables from it. :param name: The name of the target """ self.name = name self.prefix = '/vision/' + self.name + '_' # Prefix for working with files self.team_number = 5987 # Our team number, used for the server IP self.file = File( self.name, f'[NetworkTables Storage 3.0]\nstring "/vision/{self.name}_name"={self.name}', 'values', 'nt') # The values file for the target, with a default value for when no such file exists server = self.get_nt_server() logging.info(f'Initiating network tables connection with {server}') NetworkTables.initialize(server=server) NetworkTables.addConnectionListener(self.connection_listener, immediateNotify=True) self.table = NetworkTables.getTable( 'vision' ) # Create our own table instead of clogging SmartDashboard atexit.register(self.save_values)
print("valueChanged: key: '%s'; value: %s; isNew: %s" % (key, value, isNew)) if key == "Camera State": if value.lower() == "forward" and len(cameras) >= 2: cvSink = CameraServer.getInstance().getVideo(cameras[0]) dualServer.setSource(cameras[0]) elif value.lower() == "backward" and len(cameras) >= 2: cvSink = CameraServer.getInstance().getVideo(cameras[1]) dualServer.setSource(cameras[1]) def connectionListener(connected, info): print(info, "; Connected=%s" % connected) nt.addConnectionListener(connectionListener, immediateNotify=True) """Start running the camera.""" def startCamera(config): print("Starting camera '{}' on {}".format(config.name, config.path)) inst = CameraServer.getInstance() camera = UsbCamera(config.name, config.path) server = inst.startAutomaticCapture(camera=camera, return_server=True) camera.setConfigJson(json.dumps(config.config)) camera.setConnectionStrategy(VideoSource.ConnectionStrategy.kKeepOpen) if config.streamConfig is not None: server.setConfigJson(json.dumps(config.streamConfig)) return camera
def run(self): # Initialize networktables team = "" while team == "": team = input("Enter team number or 'sim': ") if team == "sim": NetworkTables.initialize(server="localhost") else: NetworkTables.startClientTeam(int(team)) # Use listeners to receive the data NetworkTables.addConnectionListener(self.connectionListener, immediateNotify=True) NetworkTables.addEntryListener(self.valueChanged) # Wait for a connection notification, then continue on the path print("Waiting for NT connection..") while True: if self.queue.get() == "connected": break print("Connected!") print() autonomous = [ # name, initial speed, ramp ("slow-forward", 0, 0.001), ("slow-backward", 0, -0.001), ("fast-forward", abs(ROBOT_FAST_SPEED), 0), ("fast-backward", -abs(ROBOT_FAST_SPEED), 0), ] stored_data = {} # # Wait for the user to cycle through the 4 autonomus modes # for i, (name, initial_speed, ramp) in enumerate(autonomous): # Initialize the robot commanded speed to 0 self.autospeed = 0 self.discard_data = True print() print("Autonomous %d/%d: %s" % (i + 1, len(autonomous), name)) print() print("Please enable the robot in autonomous mode.") print() print( "WARNING: It will not automatically stop moving, so disable the robot" ) print("before it hits something!") print("") # Wait for robot to signal that it entered autonomous mode with self.lock: self.lock.wait_for(lambda: self.mode == "auto") data = self.wait_for_stationary() if data is not None: if data in ("connected", "disconnected"): print( "ERROR: NT disconnected, results won't be reliable. Giving up." ) return else: print( "Robot exited autonomous mode before data could be sent?" ) break # Ramp the voltage at the specified rate data = self.ramp_voltage_in_auto(initial_speed, ramp) if data in ("connected", "disconnected"): print( "ERROR: NT disconnected, results won't be reliable. Giving up." ) return # output sanity check if len(data) < 3: print( "WARNING: There wasn't a lot of data received during that last run" ) else: left_distance = data[-1][L_ENCODER_P_COL] - data[0][ L_ENCODER_P_COL] right_distance = data[-1][R_ENCODER_P_COL] - data[0][ R_ENCODER_P_COL] print() print("The robot reported traveling the following distance:") print() print("Left: %.3f ft" % left_distance) print("Right: %.3f ft" % right_distance) print() print( "If that doesn't seem quite right... you should change the encoder calibration" ) print("in the robot program or fix your encoders!") stored_data[name] = data # In case the user decides to re-enable autonomous again.. self.autospeed = 0 # # We have data! Do something with it now # # Write it to disk first, in case the processing fails for some reason # -> Using JSON for simplicity, maybe add csv at a later date now = time.strftime("%Y%m%d-%H%M-%S") fname = "%s-data.json" % now print() print("Data collection complete! saving to %s..." % fname) with open(fname, "w") as fp: json.dump(stored_data, fp, indent=4, separators=(",", ": ")) analyze_data(stored_data)
MOTOR1 = 0 MOTOR2 = 1 SOLENOID = 13 def valueChanged(table, key, value, isNew): print("valueChanged: key: '%s'; value: %s; isNew: %s" % (key, value, isNew)) def connectionListener(connected, info): print(info, '; Connected=%s' % connected) NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) sd = NetworkTables.getTable("SmartDashboard") sd.addTableListener(valueChanged) class MyRobot(wpilib.IterativeRobot): def robotInit(self): """ This function is called upon program startup and should be used for any initialization code. """ #traceback.print_stack() m1 = wpilib.TalonSRX(MOTOR1) m2 = wpilib.TalonSRX(MOTOR2)
# To see messages from networktables, you must setup logging import logging logging.basicConfig(level=logging.DEBUG) if len(sys.argv) != 2: print("Error: specify an IP to connect to!") exit(0) ip = sys.argv[1] NetworkTables.initialize(server=ip) def valueChanged(table, key, value, isNew): print("valueChanged: key: '%s'; value: %s; isNew: %s" % (key, value, isNew)) def connectionListener(connected, info): print(info, "; Connected=%s" % connected) NetworkTables.addConnectionListener(connectionListener, immediateNotify=True) sd = NetworkTables.getTable("SmartDashboard") sd.addEntryListener(valueChanged) while True: time.sleep(1)