From 39c6202caa22009bdcb99fe71c03a96dcff271dd Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Wed, 28 Jan 2026 17:20:25 +0000 Subject: [PATCH 001/139] Add try/catch to dat_to_csv, formatting --- kamera/postflight/dat_to_csv.py | 7 +- .../src/view_server/image_view_server.py | 357 +++++++++++------- 2 files changed, 227 insertions(+), 137 deletions(-) diff --git a/kamera/postflight/dat_to_csv.py b/kamera/postflight/dat_to_csv.py index 09ea121..b3c9e96 100644 --- a/kamera/postflight/dat_to_csv.py +++ b/kamera/postflight/dat_to_csv.py @@ -417,8 +417,11 @@ def parse_gsof_stream(buf): def maybe_gsof(buf): # type: (bytes) -> bool - if struct.unpack("B", buf[0:1])[0] == START_TX: - return True + try: + if struct.unpack('B', buf[0:1])[0] == START_TX: + return True + except: + pass return False diff --git a/src/process/view_server/src/view_server/image_view_server.py b/src/process/view_server/src/view_server/image_view_server.py index 70d546b..d3dcc4b 100755 --- a/src/process/view_server/src/view_server/image_view_server.py +++ b/src/process/view_server/src/view_server/image_view_server.py @@ -56,27 +56,35 @@ # Kamera Imports from custom_msgs.msg import SynchronizedImages, SyncedPathImages -from custom_msgs.srv import RequestImageMetadata, RequestCompressedImageView, \ - RequestImageView -from nexus.pathimg_bridge import PathImgBridge, ExtendedBridge, coerce_message, InMemBridge +from custom_msgs.srv import ( + RequestImageMetadata, + RequestCompressedImageView, + RequestImageView, +) +from nexus.pathimg_bridge import ( + PathImgBridge, + ExtendedBridge, + coerce_message, + InMemBridge, +) from view_server.img_nexus import Nexus -MEM_TRANSPORT_DIR = os.environ.get('MEM_TRANSPORT_DIR', False) -MEM_TRANSPORT_NS = os.environ.get('MEM_TRANSPORT_NS', False) +MEM_TRANSPORT_DIR = os.environ.get("MEM_TRANSPORT_DIR", False) +MEM_TRANSPORT_NS = os.environ.get("MEM_TRANSPORT_NS", False) if MEM_TRANSPORT_DIR: - print('MEM_TRANSPORT_DIR', MEM_TRANSPORT_DIR) - membridge = PathImgBridge(name='VS') + print("MEM_TRANSPORT_DIR", MEM_TRANSPORT_DIR) + membridge = PathImgBridge(name="VS") membridge.dirname = MEM_TRANSPORT_DIR SyncedImageMsg = SyncedPathImages elif MEM_TRANSPORT_NS: - print('MEM_TRANSPORT_NS', MEM_TRANSPORT_NS) - membridge = InMemBridge(name='VS') + print("MEM_TRANSPORT_NS", MEM_TRANSPORT_NS) + membridge = InMemBridge(name="VS") membridge.dirname = MEM_TRANSPORT_NS SyncedImageMsg = SyncedPathImages else: - membridge = ExtendedBridge(name='VS') + membridge = ExtendedBridge(name="VS") SyncedImageMsg = SynchronizedImages bridge = CvBridge() @@ -88,6 +96,7 @@ import threading from contextlib import contextmanager + class NopContext(object): @property @@ -119,7 +128,6 @@ def release(self): self._lock.release() - def get_interpolation(interpolation): if interpolation == 4: flags = cv2.INTER_LANCZOS4 | cv2.WARP_INVERSE_MAP @@ -141,10 +149,18 @@ class ImageViewServer(object): received by this node. """ - def __init__(self, sync_image_topic, rgb_service_topic=None, - rgb_metadata_service_topic=None, ir_service_topic=None, - ir_metadata_service_topic=None, uv_service_topic=None, - uv_metadata_service_topic=None, rgb_queue=None): + + def __init__( + self, + sync_image_topic, + rgb_service_topic=None, + rgb_metadata_service_topic=None, + ir_service_topic=None, + ir_metadata_service_topic=None, + uv_service_topic=None, + uv_metadata_service_topic=None, + rgb_queue=None, + ): """ :param sync_image_topic: Topic providing SynchronizedImages messages. :type sync_image_topic: str @@ -163,74 +179,104 @@ def __init__(self, sync_image_topic, rgb_service_topic=None, self.ir_msg = None self.uv_msg = None - self.frame2newimg = {"rgb_msg":dict(), "ir_msg":dict(), "uv_msg":dict()} - self.frame2hash = {"rgb_msg":dict(), "ir_msg":dict(), "uv_msg":dict()} + self.frame2newimg = {"rgb_msg": dict(), "ir_msg": dict(), "uv_msg": dict()} + self.frame2hash = {"rgb_msg": dict(), "ir_msg": dict(), "uv_msg": dict()} if rgb_queue is None: raise ValueError("You must provide a rgb_queue parameter") self.rgb_queue = rgb_queue # type: queue.dequeue - self.queue = {"rgb_msg": Queue(1), "ir_msg": Queue(1), "uv_msg": Queue(1), } - self.img_stamp_blocks = {"rgb_msg": ConditionalRendezvous(1), "ir_msg": ConditionalRendezvous(1), "uv_msg": ConditionalRendezvous(1), } - self.req_hash_blocks = {"rgb_msg": ConditionalRendezvous(1), "ir_msg": ConditionalRendezvous(1), "uv_msg": ConditionalRendezvous(1), } - + self.queue = { + "rgb_msg": Queue(1), + "ir_msg": Queue(1), + "uv_msg": Queue(1), + } + self.img_stamp_blocks = { + "rgb_msg": ConditionalRendezvous(1), + "ir_msg": ConditionalRendezvous(1), + "uv_msg": ConditionalRendezvous(1), + } + self.req_hash_blocks = { + "rgb_msg": ConditionalRendezvous(1), + "ir_msg": ConditionalRendezvous(1), + "uv_msg": ConditionalRendezvous(1), + } if isinstance(SyncedImageMsg(), SyncedPathImages): - sync_image_topic += '_shm' + sync_image_topic += "_shm" - hostname_ns = '/' + socket.gethostname() + hostname_ns = "/" + socket.gethostname() # rospy.loginfo('Subscribing to SynchronizedImages topic \'{}\''.format(sync_image_topic)) # rospy.Subscriber(sync_image_topic, SyncedImageMsg, self.sync_images_callback, queue_size=1) - self.enabled = {'rgb': True, 'uv': True, 'ir': True} + self.enabled = {"rgb": True, "uv": True, "ir": True} # todo: deal with channel enable config - def subscribe_to_single_image(modality='rgb'): + def subscribe_to_single_image(modality="rgb"): if self.enabled[modality]: - topic = rospy.get_param('_topic'.format(modality), - hostname_ns + '/{}/image_raw'.format(modality)) - - rospy.loginfo('Subscribing to Images topic \'{}\''.format(topic)) - rospy.Subscriber(topic, Image, self.any_queue_callback, - callback_args=modality, queue_size=1) - - def subscribe_to_image_service(service_topic, metadata_service_topic, - key): + topic = rospy.get_param( + "_topic".format(modality), + hostname_ns + "/{}/image_raw".format(modality), + ) + + rospy.loginfo("Subscribing to Images topic '{}'".format(topic)) + rospy.Subscriber( + topic, + Image, + self.any_queue_callback, + callback_args=modality, + queue_size=1, + ) + + def subscribe_to_image_service(service_topic, metadata_service_topic, key): if service_topic is not None: - rospy.loginfo('Creating RequestImageView service to provide ' - '\'%s\' image views on topic \'%s\'' % - (key,service_topic)) - rospy.Service(service_topic, RequestImageView, - lambda req: self.image_patch_service_request(req, - key, - False)) + rospy.loginfo( + "Creating RequestImageView service to provide " + "'%s' image views on topic '%s'" % (key, service_topic) + ) + rospy.Service( + service_topic, + RequestImageView, + lambda req: self.image_patch_service_request(req, key, False), + ) if service_topic is not None: - compressed_service_topic = '%s/compressed' % service_topic - rospy.loginfo('Creating RequestCompressedImageView service to ' - 'provide \'%s\' image views on topic \'%s\'' % - (key,compressed_service_topic)) - rospy.Service(compressed_service_topic, - RequestCompressedImageView, - lambda req: self.image_patch_service_request(req, - key, - True)) + compressed_service_topic = "%s/compressed" % service_topic + rospy.loginfo( + "Creating RequestCompressedImageView service to " + "provide '%s' image views on topic '%s'" + % (key, compressed_service_topic) + ) + rospy.Service( + compressed_service_topic, + RequestCompressedImageView, + lambda req: self.image_patch_service_request(req, key, True), + ) if metadata_service_topic is not None: - rospy.loginfo('Creating RequestImageMetadata service to ' - 'provide \'%s\' image metadata via ' - 'RequestImageMetadata on topic \'%s\'' % - (key,metadata_service_topic)) - rospy.Service(metadata_service_topic, RequestImageMetadata, - lambda req: self.metadata_service_topic_request(req, - key)) + rospy.loginfo( + "Creating RequestImageMetadata service to " + "provide '%s' image metadata via " + "RequestImageMetadata on topic '%s'" % (key, metadata_service_topic) + ) + rospy.Service( + metadata_service_topic, + RequestImageMetadata, + lambda req: self.metadata_service_topic_request(req, key), + ) for modality in self.enabled: subscribe_to_single_image(modality) - subscribe_to_image_service(rgb_service_topic, rgb_metadata_service_topic, 'rgb_msg') - subscribe_to_image_service(ir_service_topic, ir_metadata_service_topic, 'ir_msg') - subscribe_to_image_service(uv_service_topic, uv_metadata_service_topic, 'uv_msg') + subscribe_to_image_service( + rgb_service_topic, rgb_metadata_service_topic, "rgb_msg" + ) + subscribe_to_image_service( + ir_service_topic, ir_metadata_service_topic, "ir_msg" + ) + subscribe_to_image_service( + uv_service_topic, uv_metadata_service_topic, "uv_msg" + ) @property def nop_lock(self): @@ -241,8 +287,8 @@ def nop_lock(self): def nopContext(self): yield True - def any_queue_callback(self, msg, modality='rgb'): - modality = modality.lower() + '_msg' + def any_queue_callback(self, msg, modality="rgb"): + modality = modality.lower() + "_msg" rospy.loginfo("image callback {}".format(modality)) for frame in self.frame2newimg[modality]: try: @@ -256,44 +302,50 @@ def sync_images_callback(self, msg): rospy.loginfo("sync images callback") with self.nop_lock: try: - rgb_str = ('RGB=%ix%i %s' % (msg.image_rgb.width, - msg.image_rgb.height, - msg.image_rgb.encoding)) + rgb_str = "RGB=%ix%i %s" % ( + msg.image_rgb.width, + msg.image_rgb.height, + msg.image_rgb.encoding, + ) modality = "rgb_msg" img_rendezvous = self.img_stamp_blocks[modality] img_rendezvous.put(msg.header.stamp) # queue = self.queue[modality] # if queue.empty(): # rospy.loginfo("Enqueued: {}".format(modality)) - # queue.put(True) + # queue.put(True) # else: # rospy.loginfo("Full or something: {}".format(modality)) except Exception as exc: - rospy.logerr('RGB fail: {}: {}'.format(exc.__class__.__name__, exc)) - rgb_str = 'No RGB' + rospy.logerr("RGB fail: {}: {}".format(exc.__class__.__name__, exc)) + rgb_str = "No RGB" try: - ir_str = ('IR=%ix%i %s' % (msg.image_ir.width, - msg.image_ir.height, - msg.image_ir.encoding)) + ir_str = "IR=%ix%i %s" % ( + msg.image_ir.width, + msg.image_ir.height, + msg.image_ir.encoding, + ) modality = "ir_msg" img_rendezvous = self.img_stamp_blocks[modality] img_rendezvous.put(msg.header.stamp) # queue = self.queue[modality] # if queue.empty(): - # rospy.loginfo("Enqueued: {}".format(modality)) - # queue.put(True) + # rospy.loginfo("Enqueued: {}".format(modality)) + # queue.put(True) # else: # rospy.loginfo("Full or something: {}".format(modality)) except Exception as exc: - rospy.logerr('IR fail {}: {}'.format(exc.__class__.__name__, exc)) - ir_str = 'No IR' + rospy.logerr("IR fail {}: {}".format(exc.__class__.__name__, exc)) + ir_str = "No IR" try: - uv_str = ('UV=%ix%i %s' % (msg.image_uv.width, - msg.image_uv.height, - msg.image_uv.encoding)) + uv_str = "UV=%ix%i %s" % ( + msg.image_uv.width, + msg.image_uv.height, + msg.image_uv.encoding, + ) modality = "uv_msg" img_rendezvous = self.img_stamp_blocks[modality] @@ -305,11 +357,13 @@ def sync_images_callback(self, msg): # else: # rospy.loginfo("Full or something: {}".format(modality)) except Exception as exc: - rospy.logerr('UV fail {}: {}'.format(exc.__class__.__name__, exc)) - uv_str = 'No UV' + rospy.logerr("UV fail {}: {}".format(exc.__class__.__name__, exc)) + uv_str = "No UV" - rospy.loginfo('Received SynchronizedImages message with [%s] [%s] ' - '[%s]' % (rgb_str,ir_str,uv_str)) + rospy.loginfo( + "Received SynchronizedImages message with [%s] [%s] " + "[%s]" % (rgb_str, ir_str, uv_str) + ) self.rgb_msg = msg.image_rgb self.ir_msg = msg.image_ir self.uv_msg = msg.image_uv @@ -324,13 +378,13 @@ def image_patch_service_request(self, req, modality, compress): """ tic = time.time() req_hash = hash_genpy_msg(req) - #rospy.loginfo('Requesting {} \'{}\' image view of size {} x {}: {}'.format( + # rospy.loginfo('Requesting {} \'{}\' image view of size {} x {}: {}'.format( # 'compressed' if compress else '', modality, # req.output_width, req.output_height, req_hash)) with self.nop_lock: # rospy.logwarn('pre lock') - if modality == 'rgb_msg': + if modality == "rgb_msg": try: img_msg = self.rgb_queue[0] except IndexError as exc: @@ -343,7 +397,7 @@ def image_patch_service_request(self, req, modality, compress): # rospy.logwarn('post lock') if img_msg is None: - #rospy.logerr('exit early due to lack of encoding') + # rospy.logerr('exit early due to lack of encoding') return False, Image() try: @@ -357,9 +411,9 @@ def image_patch_service_request(self, req, modality, compress): if newimg or not stale_hash: try: - image = membridge.imgmsg_to_cv2(img_msg, 'passthrough') + image = membridge.imgmsg_to_cv2(img_msg, "passthrough") except Exception as exc: - rospy.logerr('{}: {}'.format(exc.__class__.__name__, exc)) + rospy.logerr("{}: {}".format(exc.__class__.__name__, exc)) return False, Image() else: return True, Image() @@ -377,22 +431,23 @@ def image_patch_service_request(self, req, modality, compress): dsize = (req.output_width, req.output_height) if modality == "ir_msg": if req.apply_clahe: - bright_px = 5 + bright_px = 20 h, w = image.shape pxs = h * w - top_percentile = ((pxs - bright_px) / pxs) * 100 + #top_percentile = ((pxs - bright_px) / pxs) * 100 + top_percentile = 100 stretch_percentiles = [1, top_percentile] - img = image.astype("float32") - mi = np.percentile( img, stretch_percentiles[0] ) - ma = np.percentile( img, stretch_percentiles[1] ) - normalized = ( img - mi ) / ( ma - mi) - normalized = np.clip(normalized, 0, 1) + img = image.astype("uint16") + mi = np.percentile(img, stretch_percentiles[0]) + ma = np.percentile(img, stretch_percentiles[1]) + normalized = (img - mi) / (ma - mi) + #normalized = np.clip(normalized, 0, 1) normalized = normalized * 255 + normalized[normalized < 0] = 0 image = np.round(normalized).astype("uint8") - homography = np.reshape(req.homography, (3,3)).astype(np.float32) - raw_image = cv2.warpPerspective(image, homography, dsize=dsize, - flags=flags) + homography = np.reshape(req.homography, (3, 3)).astype(np.float32) + raw_image = cv2.warpPerspective(image, homography, dsize=dsize, flags=flags) if modality == "ir_msg": # Don't need mono16 for display @@ -425,7 +480,7 @@ def image_patch_service_request(self, req, modality, compress): # raise NotImplementedError('disabled for now') out_msg = CompressedImage() out_msg.format = "jpeg" - out_msg.data = np.array(cv2.imencode('.jpg', image2)[1]).tostring() + out_msg.data = np.array(cv2.imencode(".jpg", image2)[1]).tostring() out_msg.header = img_msg.header # rospy.logwarn("Compressed") else: @@ -435,7 +490,11 @@ def image_patch_service_request(self, req, modality, compress): # Cache the request hash so we can block the next time around toc = time.time() - rospy.loginfo("{:.2f} Releasing {: >3}".format(img_msg.header.stamp.to_sec(), modality[:3])) + rospy.loginfo( + "{:.2f} Releasing {: >3}".format( + img_msg.header.stamp.to_sec(), modality[:3] + ) + ) print("Time to process request was %0.3fs" % (toc - tic)) return True, out_msg @@ -453,9 +512,9 @@ def metadata_service_topic_request(self, req, modality): img_msg0 = getattr(self, modality) if img_msg0 is None: - msg = (False,0,0,'') + msg = (False, 0, 0, "") else: - msg = (True,img_msg0.height,img_msg0.width,img_msg0.encoding) + msg = (True, img_msg0.height, img_msg0.width, img_msg0.encoding) # print('metadata: {}'.format(msg)) # invalidate cache lanes @@ -468,9 +527,10 @@ def metadata_service_topic_request(self, req, modality): def set_up_nexus(rgb_queue): import socket + # node = 'img_nexus' # rospy.init_node(node) - print('Parent', rospy.get_namespace()) + print("Parent", rospy.get_namespace()) node_name = rospy.get_name() # for param in rospy.get_param_names(): # print(param) @@ -479,20 +539,29 @@ def set_up_nexus(rgb_queue): root@nuvo0:~/kamera_ws# rosparam get /nuvo0/img_nexus {ir_topic: ir/image_raw, max_wait: 0.9, out_topic: synched, rgb_topic: rgb/image_raw, uv_topic: uv/image_raw, verbosity: 9}""" - hostname_ns = '/' + socket.gethostname() - sys_prefix = hostname_ns + '/img_nexus' - verbosity = rospy.get_param('verbosity', 9) - rgb_topic = rospy.get_param('rgb_topic', hostname_ns + '/rgb/image_raw') - ir_topic = rospy.get_param('ir_topic', hostname_ns + '/ir/image_raw') - uv_topic = rospy.get_param('uv_topic', hostname_ns + '/uv/image_raw') + hostname_ns = "/" + socket.gethostname() + sys_prefix = hostname_ns + "/img_nexus" + verbosity = rospy.get_param("verbosity", 9) + rgb_topic = rospy.get_param("rgb_topic", hostname_ns + "/rgb/image_raw") + ir_topic = rospy.get_param("ir_topic", hostname_ns + "/ir/image_raw") + uv_topic = rospy.get_param("uv_topic", hostname_ns + "/uv/image_raw") # out_topic = rospy.get_param('out_topic', sys_prefix + 'synced') - out_topic = hostname_ns + '/synched' - max_wait = rospy.get_param('/max_frame_period', 444) / 1000.0 - send_image_data = rospy.get_param('~send_image_data') - compress_imagery = rospy.get_param('~compress_imagery') - - nexus = Nexus(rgb_topic, ir_topic, uv_topic, out_topic, compress_imagery, - send_image_data, max_wait, rgb_queue=rgb_queue, verbosity=verbosity) + out_topic = hostname_ns + "/synched" + max_wait = rospy.get_param("/max_frame_period", 444) / 1000.0 + send_image_data = rospy.get_param("~send_image_data") + compress_imagery = rospy.get_param("~compress_imagery") + + nexus = Nexus( + rgb_topic, + ir_topic, + uv_topic, + out_topic, + compress_imagery, + send_image_data, + max_wait, + rgb_queue=rgb_queue, + verbosity=verbosity, + ) return nexus @@ -503,51 +572,69 @@ def rospy_spin(delay=1.0): """ if not rospy.core.is_initialized(): - raise rospy.exceptions.ROSInitException("client code must call rospy.init_node() first") - rospy.logdebug("node[%s, %s] entering spin(), pid[%s]", rospy.core.get_caller_id(), rospy.core.get_node_uri(), - os.getpid()) + raise rospy.exceptions.ROSInitException( + "client code must call rospy.init_node() first" + ) + rospy.logdebug( + "node[%s, %s] entering spin(), pid[%s]", + rospy.core.get_caller_id(), + rospy.core.get_node_uri(), + os.getpid(), + ) try: while not rospy.core.is_shutdown(): rospy.rostime.wallsleep(delay) - rospy.loginfo('spin') + rospy.loginfo("spin") # print('.', end='') except KeyboardInterrupt: rospy.logdebug("keyboard interrupt, shutting down") - rospy.core.signal_shutdown('keyboard interrupt') + rospy.core.signal_shutdown("keyboard interrupt") def main(): # Launch the node. - node = 'image_view_server' + node = "image_view_server" rospy.init_node(node, anonymous=False) node_name = rospy.get_name() # -------------------------- Read Parameters ----------------------------- - sync_image_topic = rospy.get_param('%s/sync_image_topic' % node_name) - rgb_service_topic = rospy.get_param('%s/rgb_service_topic' % node_name) - ir_service_topic = rospy.get_param('%s/ir_service_topic' % node_name) - uv_service_topic = rospy.get_param('%s/uv_service_topic' % node_name) - - rgb_metadata_service_topic = rospy.get_param('%s/rgb_metadata_service_topic' % node_name) - ir_metadata_service_topic = rospy.get_param('%s/ir_metadata_service_topic' % node_name) - uv_metadata_service_topic = rospy.get_param('%s/uv_metadata_service_topic' % node_name) + sync_image_topic = rospy.get_param("%s/sync_image_topic" % node_name) + rgb_service_topic = rospy.get_param("%s/rgb_service_topic" % node_name) + ir_service_topic = rospy.get_param("%s/ir_service_topic" % node_name) + uv_service_topic = rospy.get_param("%s/uv_service_topic" % node_name) + + rgb_metadata_service_topic = rospy.get_param( + "%s/rgb_metadata_service_topic" % node_name + ) + ir_metadata_service_topic = rospy.get_param( + "%s/ir_metadata_service_topic" % node_name + ) + uv_metadata_service_topic = rospy.get_param( + "%s/uv_metadata_service_topic" % node_name + ) # ------------------------------------------------------------------------ # Share debayered RGB images between nexus and image view rgb_queue = deque(maxlen=1) nexus = set_up_nexus(rgb_queue) - ImageViewServer(sync_image_topic, rgb_service_topic, - rgb_metadata_service_topic, ir_service_topic, - ir_metadata_service_topic, uv_service_topic, - uv_metadata_service_topic, rgb_queue=rgb_queue) + ImageViewServer( + sync_image_topic, + rgb_service_topic, + rgb_metadata_service_topic, + ir_service_topic, + ir_metadata_service_topic, + uv_service_topic, + uv_metadata_service_topic, + rgb_queue=rgb_queue, + ) rospy_spin() -if __name__ == '__main__': +if __name__ == "__main__": try: main() except rospy.ROSInterruptException: - print('Interrupt') + print("Interrupt") pass From a2bb96d02f32358242ab667cb8b5d164d4cd655d Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 12 Jan 2026 10:46:34 -0500 Subject: [PATCH 002/139] Add function to compress jpegs with nvJPEG, and an optional flag to turn it on with /sys/arch/use_nvjpeg. --- src/cams/phase_one/CMakeLists.txt | 67 ++++ .../phase_one/include/phase_one/phase_one.h | 5 + .../phase_one/src/phase_one_standalone.cpp | 297 +++++++++++++++++- 3 files changed, 362 insertions(+), 7 deletions(-) diff --git a/src/cams/phase_one/CMakeLists.txt b/src/cams/phase_one/CMakeLists.txt index de5db34..6405375 100644 --- a/src/cams/phase_one/CMakeLists.txt +++ b/src/cams/phase_one/CMakeLists.txt @@ -71,6 +71,56 @@ find_package(catkin REQUIRED COMPONENTS ## System dependencies are found with CMake's conventions find_package(Boost REQUIRED COMPONENTS system) +## Find CUDA +find_package(CUDA QUIET) +if(CUDA_FOUND) + enable_language(CUDA) + message(STATUS "CUDA found: ${CUDA_VERSION}") + message(STATUS "CUDA libraries: ${CUDA_LIBRARIES}") +else() + message(WARNING "CUDA not found - nvjpeg will not be available") +endif() + +## Find nvjpeg (part of CUDA Toolkit) +if(CUDA_FOUND) + find_library(NVJPEG_LIBRARY + NAMES nvjpeg + PATHS + ${CUDA_TOOLKIT_ROOT_DIR}/lib64 + ${CUDA_TOOLKIT_ROOT_DIR}/lib + /usr/local/cuda/lib64 + /usr/local/cuda/lib + NO_DEFAULT_PATH + ) + + if(NVJPEG_LIBRARY) + message(STATUS "nvjpeg library found: ${NVJPEG_LIBRARY}") + set(NVJPEG_FOUND TRUE) + else() + message(WARNING "nvjpeg library not found - nvjpeg encoding will not be available") + set(NVJPEG_FOUND FALSE) + endif() + + # Find nvjpeg header + find_path(NVJPEG_INCLUDE_DIR + NAMES nvjpeg.h + PATHS + ${CUDA_TOOLKIT_ROOT_DIR}/include + /usr/local/cuda/include + NO_DEFAULT_PATH + ) + + if(NVJPEG_INCLUDE_DIR) + message(STATUS "nvjpeg headers found: ${NVJPEG_INCLUDE_DIR}") + add_definitions(-DHAVE_NVJPEG) + else() + message(WARNING "nvjpeg headers not found") + set(NVJPEG_FOUND FALSE) + endif() +else() + set(NVJPEG_FOUND FALSE) +endif() + ## Uncomment this if the package has a setup.py. This macro ensures ## modules and global scripts declared therein get installed @@ -174,6 +224,9 @@ catkin_package( ## Specify additional locations of header files ## Your package locations should be listed before other locations include_directories(include ${Boost_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS}) +if(NVJPEG_FOUND AND NVJPEG_INCLUDE_DIR) + include_directories(${NVJPEG_INCLUDE_DIR} ${CUDA_INCLUDE_DIRS}) +endif() ## Declare a C++ library # add_library(${PROJECT_NAME} @@ -201,6 +254,13 @@ target_link_libraries(phase_one PRIVATE CameraSDK::CameraSdkCpp ImageSDK::ImageSdkCpp ) +if(NVJPEG_FOUND) + target_link_libraries(phase_one PRIVATE + ${NVJPEG_LIBRARY} + ${CUDA_LIBRARIES} + ${CUDA_CUDART_LIBRARY} + ) +endif() ## Declare a C++ executable ## With catkin_make all packages are built within a single CMake context @@ -218,6 +278,13 @@ target_link_libraries(phase_one_standalone PRIVATE CameraSDK::CameraSdkCpp ImageSDK::ImageSdkCpp ) +if(NVJPEG_FOUND) + target_link_libraries(phase_one_standalone PRIVATE + ${NVJPEG_LIBRARY} + ${CUDA_LIBRARIES} + ${CUDA_CUDART_LIBRARY} + ) +endif() ## Rename C++ executable without prefix ## The above recommended prefix causes long target names, the following renames the diff --git a/src/cams/phase_one/include/phase_one/phase_one.h b/src/cams/phase_one/include/phase_one/phase_one.h index 7c3669a..8195f27 100644 --- a/src/cams/phase_one/include/phase_one/phase_one.h +++ b/src/cams/phase_one/include/phase_one/phase_one.h @@ -74,6 +74,11 @@ namespace phase_one const std::string &filename, std::string format); + // Compress JPEG using nvjpeg (GPU-accelerated) + bool compressJpegNvjpeg(const cv::Mat& bgr_image, + std::vector& output, + int quality = 90); + // Fill in the entries of the maps 'property_to_id_' and 'property_to_type_' given // a 'camera' handle. These maps define the values used for setting/getting the // parameters in the ROS service calls diff --git a/src/cams/phase_one/src/phase_one_standalone.cpp b/src/cams/phase_one/src/phase_one_standalone.cpp index 8724bd1..8fd9daa 100755 --- a/src/cams/phase_one/src/phase_one_standalone.cpp +++ b/src/cams/phase_one/src/phase_one_standalone.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,197 @@ #include #include +#ifdef HAVE_NVJPEG +#include +#include +#include +#endif + +#ifdef HAVE_NVJPEG +namespace phase_one +{ + // Helper function to convert nvjpeg status to string + const char* nvjpeg_error_string(nvjpegStatus_t s) { + switch (s) { + case NVJPEG_STATUS_SUCCESS: return "NVJPEG_STATUS_SUCCESS"; + case NVJPEG_STATUS_NOT_INITIALIZED: return "NVJPEG_STATUS_NOT_INITIALIZED"; + case NVJPEG_STATUS_INVALID_PARAMETER: return "NVJPEG_STATUS_INVALID_PARAMETER"; + case NVJPEG_STATUS_BAD_JPEG: return "NVJPEG_STATUS_BAD_JPEG"; + case NVJPEG_STATUS_JPEG_NOT_SUPPORTED: return "NVJPEG_STATUS_JPEG_NOT_SUPPORTED"; + case NVJPEG_STATUS_ALLOCATOR_FAILURE: return "NVJPEG_STATUS_ALLOCATOR_FAILURE"; + case NVJPEG_STATUS_EXECUTION_FAILED: return "NVJPEG_STATUS_EXECUTION_FAILED"; + case NVJPEG_STATUS_ARCH_MISMATCH: return "NVJPEG_STATUS_ARCH_MISMATCH"; + case NVJPEG_STATUS_INTERNAL_ERROR: return "NVJPEG_STATUS_INTERNAL_ERROR"; + default: return "NVJPEG_STATUS_UNKNOWN"; + } + } + + // Helper class for nvjpeg encoding + class NvJpegEncoder { + public: + NvJpegEncoder(int width, int height, int quality = 90) + : width_(width), height_(height), quality_(quality) + { + // Create nvJPEG handle (try hardware backend first, fall back to default) + nvjpegStatus_t st = nvjpegCreateEx( + NVJPEG_BACKEND_HARDWARE, + nullptr, nullptr, 0, &handle_); + if (st == NVJPEG_STATUS_ARCH_MISMATCH) { + st = nvjpegCreateEx( + NVJPEG_BACKEND_DEFAULT, + nullptr, nullptr, 0, &handle_); + } + if (st != NVJPEG_STATUS_SUCCESS) { + ROS_ERROR("Failed to create nvJPEG handle: %s", nvjpeg_error_string(st)); + handle_ = nullptr; + return; + } + + nvjpegStatus_t enc_st = nvjpegEncoderStateCreate(handle_, &encState_, nullptr); + if (enc_st != NVJPEG_STATUS_SUCCESS) { + ROS_ERROR("Failed to create encoder state: %s", nvjpeg_error_string(enc_st)); + nvjpegDestroy(handle_); + handle_ = nullptr; + return; + } + + enc_st = nvjpegEncoderParamsCreate(handle_, &encParams_, nullptr); + if (enc_st != NVJPEG_STATUS_SUCCESS) { + ROS_ERROR("Failed to create encoder params: %s", nvjpeg_error_string(enc_st)); + nvjpegEncoderStateDestroy(encState_); + nvjpegDestroy(handle_); + handle_ = nullptr; + return; + } + + nvjpegEncoderParamsSetQuality(encParams_, quality_, nullptr); + nvjpegEncoderParamsSetOptimizedHuffman(encParams_, 1, nullptr); + nvjpegEncoderParamsSetSamplingFactors( + encParams_, NVJPEG_CSS_420, nullptr); + nvjpegEncoderParamsSetEncoding( + encParams_, NVJPEG_ENCODING_BASELINE_DCT, nullptr); + + // Allocate a single GPU buffer large enough for interleaved BGR + cudaError_t cuda_st = cudaMallocPitch( + (void**)&d_img_, &pitch_, + width_ * 3 * sizeof(unsigned char), + height_); + if (cuda_st != cudaSuccess) { + ROS_ERROR("Failed to allocate CUDA memory: %s", cudaGetErrorString(cuda_st)); + nvjpegEncoderParamsDestroy(encParams_); + nvjpegEncoderStateDestroy(encState_); + nvjpegDestroy(handle_); + handle_ = nullptr; + return; + } + + std::memset(&nvImage_, 0, sizeof(nvImage_)); + nvImage_.channel[0] = d_img_; + nvImage_.pitch[0] = static_cast(pitch_); + + input_format_ = NVJPEG_INPUT_BGRI; + + cuda_st = cudaStreamCreate(&stream_); + if (cuda_st != cudaSuccess) { + ROS_ERROR("Failed to create CUDA stream: %s", cudaGetErrorString(cuda_st)); + cudaFree(d_img_); + nvjpegEncoderParamsDestroy(encParams_); + nvjpegEncoderStateDestroy(encState_); + nvjpegDestroy(handle_); + handle_ = nullptr; + return; + } + } + + ~NvJpegEncoder() + { + if (d_img_) cudaFree(d_img_); + if (stream_) cudaStreamDestroy(stream_); + if (encParams_) nvjpegEncoderParamsDestroy(encParams_); + if (encState_) nvjpegEncoderStateDestroy(encState_); + if (handle_) nvjpegDestroy(handle_); + } + + bool encode(const cv::Mat& bgr, std::vector& output) + { + if (!handle_) { + ROS_ERROR("NvJpegEncoder: handle not initialized"); + return false; + } + + if (bgr.cols != width_ || bgr.rows != height_ || bgr.type() != CV_8UC3) { + ROS_ERROR("NvJpegEncoder: input size/type mismatch. Expected %dx%d CV_8UC3, got %dx%d type %d", + width_, height_, bgr.cols, bgr.rows, bgr.type()); + return false; + } + + const unsigned char* h_bgr = bgr.ptr(0); + + // Upload + cudaError_t cuda_st = cudaMemcpy2DAsync( + d_img_, pitch_, + h_bgr, width_ * 3 * sizeof(unsigned char), + width_ * 3 * sizeof(unsigned char), + height_, + cudaMemcpyHostToDevice, + stream_); + if (cuda_st != cudaSuccess) { + ROS_ERROR("Failed to copy to device: %s", cudaGetErrorString(cuda_st)); + return false; + } + + // Encode + nvjpegStatus_t st = nvjpegEncodeImage( + handle_, encState_, encParams_, + &nvImage_, input_format_, + width_, height_, stream_); + if (st != NVJPEG_STATUS_SUCCESS) { + ROS_ERROR("Failed to encode image: %s", nvjpeg_error_string(st)); + return false; + } + + cudaStreamSynchronize(stream_); + + // Retrieve bitstream + size_t jpegSize = 0; + st = nvjpegEncodeRetrieveBitstream( + handle_, encState_, nullptr, &jpegSize, stream_); + if (st != NVJPEG_STATUS_SUCCESS) { + ROS_ERROR("Failed to retrieve bitstream size: %s", nvjpeg_error_string(st)); + return false; + } + cudaStreamSynchronize(stream_); + + output.resize(jpegSize); + st = nvjpegEncodeRetrieveBitstream( + handle_, encState_, output.data(), &jpegSize, stream_); + if (st != NVJPEG_STATUS_SUCCESS) { + ROS_ERROR("Failed to retrieve bitstream: %s", nvjpeg_error_string(st)); + return false; + } + cudaStreamSynchronize(stream_); + + return true; + } + + bool isValid() const { return handle_ != nullptr; } + + private: + int width_; + int height_; + int quality_; + + nvjpegHandle_t handle_ = nullptr; + nvjpegEncoderState_t encState_ = nullptr; + nvjpegEncoderParams_t encParams_ = nullptr; + nvjpegImage_t nvImage_{}; + + unsigned char* d_img_ = nullptr; + size_t pitch_ = 0; + nvjpegInputFormat_t input_format_; + cudaStream_t stream_ = nullptr; + }; +#endif // HAVE_NVJPEG namespace phase_one { @@ -547,6 +739,44 @@ namespace phase_one return 0; }; + bool PhaseOne::compressJpegNvjpeg(const cv::Mat& bgr_image, + std::vector& output, + int quality) + { +#ifdef HAVE_NVJPEG + try { + if (bgr_image.empty() || bgr_image.type() != CV_8UC3) { + ROS_ERROR("compressJpegNvjpeg: Invalid input image (empty or wrong type)"); + return false; + } + + // Create encoder for this image size + NvJpegEncoder encoder(bgr_image.cols, bgr_image.rows, quality); + if (!encoder.isValid()) { + ROS_ERROR("compressJpegNvjpeg: Failed to create nvjpeg encoder"); + return false; + } + + // Encode the image + if (!encoder.encode(bgr_image, output)) { + ROS_ERROR("compressJpegNvjpeg: Failed to encode image"); + return false; + } + + return true; + } catch (const std::exception& e) { + ROS_ERROR_STREAM("compressJpegNvjpeg: Exception: " << e.what()); + return false; + } catch (...) { + ROS_ERROR("compressJpegNvjpeg: Unknown exception"); + return false; + } +#else + ROS_ERROR("compressJpegNvjpeg: nvjpeg not available (compiled without HAVE_NVJPEG)"); + return false; +#endif + } + bool PhaseOne::dumpImage(P1::ImageSdk::RawImage rawImage, P1::ImageSdk::BitmapImage bitmap, const std::string &filename, @@ -561,9 +791,40 @@ namespace phase_one jpegConfig.quality = quality; auto ticj = std::chrono::high_resolution_clock::now(); int use_p1 = std::stoi(envoy_->get("/sys/arch/use_p1jpeg")); + int use_nvjpeg = std::stoi(envoy_->get("/sys/arch/use_nvjpeg")); + // This function for some reason takes ~5x as long if ( use_p1 == 1 ) { P1::ImageSdk::JpegWriter(filename, bitmap, rawImage, jpegConfig); + } else if ( use_nvjpeg == 1 ) { + // Use nvjpeg for GPU-accelerated encoding + cv::Mat cvImage_raw = cv::Mat(cv::Size( + bitmap.Width(), bitmap.Height()), CV_8UC3); + cvImage_raw.data = bitmap.Data().get(); + cv::Mat cvImage = cv::Mat(cv::Size( + bitmap.Width(), bitmap.Height()), CV_8UC3); + cv::cvtColor(cvImage_raw, cvImage, cv::COLOR_BGR2RGB); + + std::vector jpeg_buffer; + if (compressJpegNvjpeg(cvImage, jpeg_buffer, quality)) { + // Write the compressed JPEG to file + std::ofstream out_file(filename, std::ios::binary); + if (out_file.is_open()) { + out_file.write(reinterpret_cast(jpeg_buffer.data()), + jpeg_buffer.size()); + out_file.close(); + } else { + ROS_ERROR("|DUMP| Failed to open file for writing: %s", filename.c_str()); + return false; + } + } else { + ROS_ERROR("|DUMP| nvjpeg compression failed, falling back to OpenCV"); + // Fallback to OpenCV + std::vector compression_params; + compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); + compression_params.push_back(quality); + cv::imwrite(filename, cvImage, compression_params); + } } else { cv::Mat cvImage_raw = cv::Mat(cv::Size( bitmap.Width(), bitmap.Height()), CV_8UC3); @@ -785,14 +1046,36 @@ namespace phase_one output_msg.format = "jpg"; output_msg.header = header; int quality = std::stoi(envoy_->get("/sys/arch/jpg/quality")); - std::vector compression_params; - compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); - compression_params.push_back(quality); + int use_nvjpeg = std::stoi(envoy_->get("/sys/arch/use_nvjpeg")); + std::vector buffer; - int MB = 1024 * 1024; - buffer.resize(100 * MB); - ROS_INFO("Calling imencode"); - cv::imencode(".jpg", cvImage_raw, buffer, compression_params); + if (use_nvjpeg == 1) { + // Use nvjpeg for GPU-accelerated encoding + ROS_INFO("Calling nvjpeg encode"); + std::vector nvjpeg_buffer; + if (compressJpegNvjpeg(cvImage_raw, nvjpeg_buffer, quality)) { + buffer.assign(nvjpeg_buffer.begin(), nvjpeg_buffer.end()); + ROS_INFO("nvjpeg encode successful, size: %zu bytes", buffer.size()); + } else { + ROS_WARN("nvjpeg encode failed, falling back to OpenCV"); + // Fallback to OpenCV + int MB = 1024 * 1024; + buffer.resize(100 * MB); + std::vector compression_params; + compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); + compression_params.push_back(quality); + cv::imencode(".jpg", cvImage_raw, buffer, compression_params); + } + } else { + // Use OpenCV imencode + int MB = 1024 * 1024; + buffer.resize(100 * MB); + std::vector compression_params; + compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); + compression_params.push_back(quality); + ROS_INFO("Calling imencode"); + cv::imencode(".jpg", cvImage_raw, buffer, compression_params); + } ROS_INFO("Calling tocompressimage"); output_msg.data = buffer; img_bridge.toCompressedImageMsg(output_msg); From f8e6fa5859bc365632930c7f0afd467c212ff201 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 12 Jan 2026 11:11:06 -0500 Subject: [PATCH 003/139] Pull in updated PhaseOne image and camera SDK versions that support GPU. Make SensorProfiles location relative, not hardcoded. --- src/cams/phase_one/CMakeLists.txt | 47 ++++++++++++------- .../phase_one/src/phase_one_standalone.cpp | 30 +++++++++++- 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/cams/phase_one/CMakeLists.txt b/src/cams/phase_one/CMakeLists.txt index 6405375..0597e65 100644 --- a/src/cams/phase_one/CMakeLists.txt +++ b/src/cams/phase_one/CMakeLists.txt @@ -5,8 +5,9 @@ include(FetchContent) string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME_LC) set(SDK_PACKAGE_EXT ".tgz") -set(SDK_MAJOR_VERSION "3") -set(SDK_MINOR_VERSION "1") +set(CAMERA_SDK_MAJOR_VERSION "3") +# CUDA is supported 4+ +set(IMAGE_SDK_MAJOR_VERSION "4") if(NOT APPLE AND UNIX AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") set(LINUX_ARCH "-arm64") @@ -14,31 +15,35 @@ else() set(LINUX_ARCH "") endif() -# refs -# https://developer.phaseone.com/sdk/3.1/releases/imagesdk/3/p1imagesdk-linux.tgz -# https://developer.phaseone.com/sdk/3.1/releases/camerasdk/3/p1camerasdk-linux.tgz - +# ref path: https://developer.phaseone.com/sdk/releases/camerasdk/3/p1camerasdk-linux.tgz FetchContent_Declare(CameraSDK - URL https://developer.phaseone.com/sdk/${SDK_MAJOR_VERSION}.${SDK_MINOR_VERSION}/releases/camerasdk/${SDK_MAJOR_VERSION}/p1camerasdk-${SYSTEM_NAME_LC}${LINUX_ARCH}${SDK_PACKAGE_EXT} + URL https://developer.phaseone.com/sdk/releases/camerasdk/${CAMERA_SDK_MAJOR_VERSION}/p1camerasdk-${SYSTEM_NAME_LC}${LINUX_ARCH}${SDK_PACKAGE_EXT} SOURCE_DIR CameraSDK + DOWNLOAD_EXTRACT_TIMESTAMP TRUE ) message(STATUS "Downloading CameraSDK...") -FetchContent_Populate(CameraSDK) +FetchContent_MakeAvailable(CameraSDK) find_package(CameraSDK CONFIG REQUIRED HINTS ${CMAKE_CURRENT_BINARY_DIR}/CameraSDK) -# Leave it to a copy for the GPU version, rather than fetching -#FetchContent_Declare(ImageSDK -# URL https://developer.phaseone.com/sdk/${SDK_MAJOR_VERSION}.${SDK_MINOR_VERSION}/releases/imagesdk/${SDK_MAJOR_VERSION}/p1imagesdk-${SYSTEM_NAME_LC}${LINUX_ARCH}${SDK_PACKAGE_EXT} -# SOURCE_DIR ImageSDK -#) -# -#message(STATUS "Downloading ImageSDK...") -# -#FetchContent_Populate(ImageSDK) +# ref path: https://developer.phaseone.com/sdk/releases/imagesdk/4/p1imagesdk-linux.tgz +FetchContent_Declare(ImageSDK + URL https://developer.phaseone.com/sdk/releases/imagesdk/${IMAGE_SDK_MAJOR_VERSION}/p1imagesdk-${SYSTEM_NAME_LC}${LINUX_ARCH}${SDK_PACKAGE_EXT} + SOURCE_DIR ImageSDK + DOWNLOAD_EXTRACT_TIMESTAMP TRUE +) + +message(STATUS "Downloading ImageSDK...") + +FetchContent_MakeAvailable(ImageSDK) -find_package(ImageSDK CONFIG REQUIRED HINTS lib/ImageSDKCuda) +find_package(CameraSDK CONFIG REQUIRED HINTS ${CMAKE_CURRENT_BINARY_DIR}/ImageSDK) +#find_package(ImageSDK CONFIG REQUIRED HINTS lib/ImageSDKCuda) + +# Define SensorProfiles path relative to build directory +set(SENSOR_PROFILES_PATH "${CMAKE_CURRENT_BINARY_DIR}/ImageSDK/SensorProfiles") +message(STATUS "SensorProfiles path: ${SENSOR_PROFILES_PATH}") ## Compile as C++17, supported in ROS Noetic and newer add_compile_options(-std=c++17) @@ -247,6 +252,9 @@ set(SRC add_library(phase_one ${SRC}) +# Add SensorProfiles path as compile definition +target_compile_definitions(phase_one PRIVATE SENSOR_PROFILES_PATH="${SENSOR_PROFILES_PATH}") + ## Specify libraries to link a library or executable target against target_link_libraries(phase_one PRIVATE ${OpenCV_LIBS} @@ -268,6 +276,9 @@ endif() add_executable(${PROJECT_NAME}_node src/phase_one_node.cpp) add_executable(${PROJECT_NAME}_standalone src/phase_one_standalone.cpp src/phase_one_utils.cpp) +# Add SensorProfiles path as compile definition for standalone executable +target_compile_definitions(${PROJECT_NAME}_standalone PRIVATE SENSOR_PROFILES_PATH="${SENSOR_PROFILES_PATH}") + target_link_libraries(phase_one_node PRIVATE ${catkin_LIBRARIES} ) diff --git a/src/cams/phase_one/src/phase_one_standalone.cpp b/src/cams/phase_one/src/phase_one_standalone.cpp index 8fd9daa..673dacd 100755 --- a/src/cams/phase_one/src/phase_one_standalone.cpp +++ b/src/cams/phase_one/src/phase_one_standalone.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include +#include #include #include #include @@ -302,8 +304,32 @@ namespace phase_one } else { P1::ImageSdk::SetArchitecture(P1::ImageSdk::Architecture::Cuda); } - P1::ImageSdk::SetSensorProfilesLocation( - "/root/kamera/artifacts/ImageSDKCuda/SensorProfiles"); + + // Get SensorProfiles path - allow override via environment variable + std::string sensor_profiles_path; + const char* env_path = std::getenv("PHASE_ONE_SENSOR_PROFILES_PATH"); + if (env_path != nullptr) { + sensor_profiles_path = env_path; + ROS_INFO("Using SensorProfiles path from environment: %s", sensor_profiles_path.c_str()); + } else { + // Use compile-time path if available, otherwise try common locations + #ifdef SENSOR_PROFILES_PATH + sensor_profiles_path = SENSOR_PROFILES_PATH; + #else + // Fallback: try to find relative to package path + std::string package_path = ros::package::getPath("phase_one"); + if (!package_path.empty()) { + // Try build directory relative to package + sensor_profiles_path = package_path + "/../../build/phase_one/ImageSDK/SensorProfiles"; + } else { + ROS_WARN("Could not determine SensorProfiles path. Set PHASE_ONE_SENSOR_PROFILES_PATH environment variable."); + sensor_profiles_path = "/opt/phaseone/ImageSDK/SensorProfiles"; // Last resort default + } + #endif + } + + ROS_INFO("Setting SensorProfiles location to: %s", sensor_profiles_path.c_str()); + P1::ImageSdk::SetSensorProfilesLocation(sensor_profiles_path); connectToIPCamera(ip_address_); auto list = camera.AllPropertyIds(); From da0de11d4fa06f2590c2ac2547ae7e4a709fea43 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 26 Jan 2026 09:52:07 -0500 Subject: [PATCH 004/139] Revert "Pull in updated PhaseOne image and camera SDK versions that support GPU. Make SensorProfiles location relative, not hardcoded." This reverts commit 043f2335537c46e168fdab8a0bd433e75dd5fd5a. Move phase one SDK changes to separate branch. --- src/cams/phase_one/CMakeLists.txt | 47 +++++++------------ .../phase_one/src/phase_one_standalone.cpp | 30 +----------- 2 files changed, 20 insertions(+), 57 deletions(-) diff --git a/src/cams/phase_one/CMakeLists.txt b/src/cams/phase_one/CMakeLists.txt index 0597e65..6405375 100644 --- a/src/cams/phase_one/CMakeLists.txt +++ b/src/cams/phase_one/CMakeLists.txt @@ -5,9 +5,8 @@ include(FetchContent) string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSTEM_NAME_LC) set(SDK_PACKAGE_EXT ".tgz") -set(CAMERA_SDK_MAJOR_VERSION "3") -# CUDA is supported 4+ -set(IMAGE_SDK_MAJOR_VERSION "4") +set(SDK_MAJOR_VERSION "3") +set(SDK_MINOR_VERSION "1") if(NOT APPLE AND UNIX AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") set(LINUX_ARCH "-arm64") @@ -15,35 +14,31 @@ else() set(LINUX_ARCH "") endif() -# ref path: https://developer.phaseone.com/sdk/releases/camerasdk/3/p1camerasdk-linux.tgz +# refs +# https://developer.phaseone.com/sdk/3.1/releases/imagesdk/3/p1imagesdk-linux.tgz +# https://developer.phaseone.com/sdk/3.1/releases/camerasdk/3/p1camerasdk-linux.tgz + FetchContent_Declare(CameraSDK - URL https://developer.phaseone.com/sdk/releases/camerasdk/${CAMERA_SDK_MAJOR_VERSION}/p1camerasdk-${SYSTEM_NAME_LC}${LINUX_ARCH}${SDK_PACKAGE_EXT} + URL https://developer.phaseone.com/sdk/${SDK_MAJOR_VERSION}.${SDK_MINOR_VERSION}/releases/camerasdk/${SDK_MAJOR_VERSION}/p1camerasdk-${SYSTEM_NAME_LC}${LINUX_ARCH}${SDK_PACKAGE_EXT} SOURCE_DIR CameraSDK - DOWNLOAD_EXTRACT_TIMESTAMP TRUE ) message(STATUS "Downloading CameraSDK...") -FetchContent_MakeAvailable(CameraSDK) +FetchContent_Populate(CameraSDK) find_package(CameraSDK CONFIG REQUIRED HINTS ${CMAKE_CURRENT_BINARY_DIR}/CameraSDK) -# ref path: https://developer.phaseone.com/sdk/releases/imagesdk/4/p1imagesdk-linux.tgz -FetchContent_Declare(ImageSDK - URL https://developer.phaseone.com/sdk/releases/imagesdk/${IMAGE_SDK_MAJOR_VERSION}/p1imagesdk-${SYSTEM_NAME_LC}${LINUX_ARCH}${SDK_PACKAGE_EXT} - SOURCE_DIR ImageSDK - DOWNLOAD_EXTRACT_TIMESTAMP TRUE -) - -message(STATUS "Downloading ImageSDK...") - -FetchContent_MakeAvailable(ImageSDK) +# Leave it to a copy for the GPU version, rather than fetching +#FetchContent_Declare(ImageSDK +# URL https://developer.phaseone.com/sdk/${SDK_MAJOR_VERSION}.${SDK_MINOR_VERSION}/releases/imagesdk/${SDK_MAJOR_VERSION}/p1imagesdk-${SYSTEM_NAME_LC}${LINUX_ARCH}${SDK_PACKAGE_EXT} +# SOURCE_DIR ImageSDK +#) +# +#message(STATUS "Downloading ImageSDK...") +# +#FetchContent_Populate(ImageSDK) -find_package(CameraSDK CONFIG REQUIRED HINTS ${CMAKE_CURRENT_BINARY_DIR}/ImageSDK) -#find_package(ImageSDK CONFIG REQUIRED HINTS lib/ImageSDKCuda) - -# Define SensorProfiles path relative to build directory -set(SENSOR_PROFILES_PATH "${CMAKE_CURRENT_BINARY_DIR}/ImageSDK/SensorProfiles") -message(STATUS "SensorProfiles path: ${SENSOR_PROFILES_PATH}") +find_package(ImageSDK CONFIG REQUIRED HINTS lib/ImageSDKCuda) ## Compile as C++17, supported in ROS Noetic and newer add_compile_options(-std=c++17) @@ -252,9 +247,6 @@ set(SRC add_library(phase_one ${SRC}) -# Add SensorProfiles path as compile definition -target_compile_definitions(phase_one PRIVATE SENSOR_PROFILES_PATH="${SENSOR_PROFILES_PATH}") - ## Specify libraries to link a library or executable target against target_link_libraries(phase_one PRIVATE ${OpenCV_LIBS} @@ -276,9 +268,6 @@ endif() add_executable(${PROJECT_NAME}_node src/phase_one_node.cpp) add_executable(${PROJECT_NAME}_standalone src/phase_one_standalone.cpp src/phase_one_utils.cpp) -# Add SensorProfiles path as compile definition for standalone executable -target_compile_definitions(${PROJECT_NAME}_standalone PRIVATE SENSOR_PROFILES_PATH="${SENSOR_PROFILES_PATH}") - target_link_libraries(phase_one_node PRIVATE ${catkin_LIBRARIES} ) diff --git a/src/cams/phase_one/src/phase_one_standalone.cpp b/src/cams/phase_one/src/phase_one_standalone.cpp index 673dacd..8fd9daa 100755 --- a/src/cams/phase_one/src/phase_one_standalone.cpp +++ b/src/cams/phase_one/src/phase_one_standalone.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -19,7 +18,6 @@ #include #include -#include #include #include #include @@ -304,32 +302,8 @@ namespace phase_one } else { P1::ImageSdk::SetArchitecture(P1::ImageSdk::Architecture::Cuda); } - - // Get SensorProfiles path - allow override via environment variable - std::string sensor_profiles_path; - const char* env_path = std::getenv("PHASE_ONE_SENSOR_PROFILES_PATH"); - if (env_path != nullptr) { - sensor_profiles_path = env_path; - ROS_INFO("Using SensorProfiles path from environment: %s", sensor_profiles_path.c_str()); - } else { - // Use compile-time path if available, otherwise try common locations - #ifdef SENSOR_PROFILES_PATH - sensor_profiles_path = SENSOR_PROFILES_PATH; - #else - // Fallback: try to find relative to package path - std::string package_path = ros::package::getPath("phase_one"); - if (!package_path.empty()) { - // Try build directory relative to package - sensor_profiles_path = package_path + "/../../build/phase_one/ImageSDK/SensorProfiles"; - } else { - ROS_WARN("Could not determine SensorProfiles path. Set PHASE_ONE_SENSOR_PROFILES_PATH environment variable."); - sensor_profiles_path = "/opt/phaseone/ImageSDK/SensorProfiles"; // Last resort default - } - #endif - } - - ROS_INFO("Setting SensorProfiles location to: %s", sensor_profiles_path.c_str()); - P1::ImageSdk::SetSensorProfilesLocation(sensor_profiles_path); + P1::ImageSdk::SetSensorProfilesLocation( + "/root/kamera/artifacts/ImageSDKCuda/SensorProfiles"); connectToIPCamera(ip_address_); auto list = camera.AllPropertyIds(); From ef10596132762d5cc3d8b3fdedc01dbe6a4a73d8 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Wed, 28 Jan 2026 17:54:50 +0000 Subject: [PATCH 005/139] Fix namespace --- .../phase_one/src/phase_one_standalone.cpp | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/cams/phase_one/src/phase_one_standalone.cpp b/src/cams/phase_one/src/phase_one_standalone.cpp index 8fd9daa..1155eab 100755 --- a/src/cams/phase_one/src/phase_one_standalone.cpp +++ b/src/cams/phase_one/src/phase_one_standalone.cpp @@ -234,8 +234,6 @@ namespace phase_one }; #endif // HAVE_NVJPEG -namespace phase_one -{ PhaseOne::PhaseOne() { } @@ -543,11 +541,11 @@ namespace phase_one } catch (...) { ROS_ERROR("|CAPTURE| Failed to convert preview."); }; - - // grab all tags for image, and shove into frame ID. faster + + // grab all tags for image, and shove into frame ID. faster // than adding to EXIF, can do that later auto ticid = std::chrono::high_resolution_clock::now(); - + P1::ImageSdk::ImageTag tag; std::stringstream frame_id; tag = raw_img.GetTag(ids.Make); @@ -577,7 +575,7 @@ namespace phase_one auto tocid = std::chrono::high_resolution_clock::now(); auto dtid = tocid - ticid; ROS_INFO_STREAM("|CAPTURE| adding tags time: " << dtid.count() / 1e9 << "s"); - + output_msg.header.frame_id = frame_id.str(); image_pub.publish(output_msg); stat_pub_.publish(stat_msg); @@ -739,7 +737,7 @@ namespace phase_one return 0; }; - bool PhaseOne::compressJpegNvjpeg(const cv::Mat& bgr_image, + bool PhaseOne::compressJpegNvjpeg(const cv::Mat& bgr_image, std::vector& output, int quality) { @@ -792,7 +790,7 @@ namespace phase_one auto ticj = std::chrono::high_resolution_clock::now(); int use_p1 = std::stoi(envoy_->get("/sys/arch/use_p1jpeg")); int use_nvjpeg = std::stoi(envoy_->get("/sys/arch/use_nvjpeg")); - + // This function for some reason takes ~5x as long if ( use_p1 == 1 ) { P1::ImageSdk::JpegWriter(filename, bitmap, rawImage, jpegConfig); @@ -804,13 +802,13 @@ namespace phase_one cv::Mat cvImage = cv::Mat(cv::Size( bitmap.Width(), bitmap.Height()), CV_8UC3); cv::cvtColor(cvImage_raw, cvImage, cv::COLOR_BGR2RGB); - + std::vector jpeg_buffer; if (compressJpegNvjpeg(cvImage, jpeg_buffer, quality)) { // Write the compressed JPEG to file std::ofstream out_file(filename, std::ios::binary); if (out_file.is_open()) { - out_file.write(reinterpret_cast(jpeg_buffer.data()), + out_file.write(reinterpret_cast(jpeg_buffer.data()), jpeg_buffer.size()); out_file.close(); } else { @@ -1047,7 +1045,7 @@ namespace phase_one output_msg.header = header; int quality = std::stoi(envoy_->get("/sys/arch/jpg/quality")); int use_nvjpeg = std::stoi(envoy_->get("/sys/arch/use_nvjpeg")); - + std::vector buffer; if (use_nvjpeg == 1) { // Use nvjpeg for GPU-accelerated encoding @@ -1314,7 +1312,7 @@ namespace phase_one } else { ROS_WARN("Detections were found on an image that does not exist locally."); } - } + } lock.unlock(); // "touch" jpeg file, so timestamp still exists std::ofstream output(fname); From 81e77d37f97dd4f613bb9efb815de9ebde9efe80 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Wed, 28 Jan 2026 18:52:05 +0000 Subject: [PATCH 006/139] Build in one-step now --- src/cams/phase_one/CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cams/phase_one/CMakeLists.txt b/src/cams/phase_one/CMakeLists.txt index 6405375..96e2189 100644 --- a/src/cams/phase_one/CMakeLists.txt +++ b/src/cams/phase_one/CMakeLists.txt @@ -92,7 +92,7 @@ if(CUDA_FOUND) /usr/local/cuda/lib NO_DEFAULT_PATH ) - + if(NVJPEG_LIBRARY) message(STATUS "nvjpeg library found: ${NVJPEG_LIBRARY}") set(NVJPEG_FOUND TRUE) @@ -100,7 +100,7 @@ if(CUDA_FOUND) message(WARNING "nvjpeg library not found - nvjpeg encoding will not be available") set(NVJPEG_FOUND FALSE) endif() - + # Find nvjpeg header find_path(NVJPEG_INCLUDE_DIR NAMES nvjpeg.h @@ -109,7 +109,7 @@ if(CUDA_FOUND) /usr/local/cuda/include NO_DEFAULT_PATH ) - + if(NVJPEG_INCLUDE_DIR) message(STATUS "nvjpeg headers found: ${NVJPEG_INCLUDE_DIR}") add_definitions(-DHAVE_NVJPEG) @@ -245,7 +245,8 @@ set(SRC # build and install the nodelet -add_library(phase_one ${SRC}) +add_library(${PROJECT_NAME} ${SRC}) +add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) ## Specify libraries to link a library or executable target against target_link_libraries(phase_one PRIVATE From e5fc08955887dd61d8601c861070bd6d99fc4e70 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 26 Jan 2026 09:57:34 -0500 Subject: [PATCH 007/139] Add more error handling around phase one debayering queues, since they are failing to write to disk. Remove hardcoded path, move into header file. --- .gitignore | 2 + .../phase_one/include/phase_one/phase_one.h | 2 + .../phase_one/src/phase_one_standalone.cpp | 111 ++++++++++++++---- 3 files changed, 95 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 82b8e5c..1797505 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ **__pycache__ **.swp **.pyc +**.DS_Store +uv.lock artifacts build devel diff --git a/src/cams/phase_one/include/phase_one/phase_one.h b/src/cams/phase_one/include/phase_one/phase_one.h index 8195f27..392ccab 100644 --- a/src/cams/phase_one/include/phase_one/phase_one.h +++ b/src/cams/phase_one/include/phase_one/phase_one.h @@ -140,6 +140,8 @@ namespace phase_one std::string effort; std::string project; std::string base_dir; + std::string to_process_filename_; + std::string processed_filename_; double auto_trigger_rate_; int num_threads_; // Internal data structures / sync structures diff --git a/src/cams/phase_one/src/phase_one_standalone.cpp b/src/cams/phase_one/src/phase_one_standalone.cpp index 1155eab..44d1060 100755 --- a/src/cams/phase_one/src/phase_one_standalone.cpp +++ b/src/cams/phase_one/src/phase_one_standalone.cpp @@ -317,29 +317,47 @@ namespace phase_one static double min_image_delay = 0.95; // should depend on exposure time event_cache.set_delay(min_image_delay); event_cache.set_tolerance(ros::Duration(0.49)); - std::string to_process_filename = "/mnt/data/to_process.txt"; - std::string processed_filename = "/mnt/data/processed.txt"; - std::vector to_process_images = loadFile(to_process_filename); - std::vector processed_images = loadFile(processed_filename); + to_process_filename_ = base_dir + "/to_process.txt"; + processed_filename_ = base_dir + "/processed.txt"; + std::vector to_process_images = loadFile(to_process_filename_); + std::vector processed_images = loadFile(processed_filename_); // write out any files that are left, as well as add to queue std::ofstream write_intersection; - write_intersection.open(to_process_filename); - for (auto& toProcess : to_process_images) { - if (std::find(processed_images.begin(), processed_images.end(), - toProcess) != processed_images.end()) { - } else { - write_intersection << toProcess << std::endl; - // sequence doesn't matter if we've cycled, just set to 0 - filename_to_seq_map_[toProcess] = 0; - total_counter++; + write_intersection.open(to_process_filename_); + if (!write_intersection.is_open()) { + ROS_ERROR("Failed to open %s for writing. Check disk space and permissions.", to_process_filename_.c_str()); + } else { + for (auto& toProcess : to_process_images) { + if (std::find(processed_images.begin(), processed_images.end(), + toProcess) != processed_images.end()) { + } else { + write_intersection << toProcess << std::endl; + if (write_intersection.fail()) { + ROS_ERROR("Failed to write to %s. Check disk space.", to_process_filename_.c_str()); + break; + } + // sequence doesn't matter if we've cycled, just set to 0 + filename_to_seq_map_[toProcess] = 0; + total_counter++; + } } + write_intersection.flush(); + if (write_intersection.fail()) { + ROS_ERROR("Failed to flush %s. Data may not be written to disk.", to_process_filename_.c_str()); + } + write_intersection.close(); } - write_intersection.close(); // Just delete processed image file - remove(processed_filename.c_str()); + remove(processed_filename_.c_str()); // Append new entries to cache - to_process_out.open(to_process_filename, std::ios_base::app); - processed_out.open(processed_filename, std::ios_base::app); + to_process_out.open(to_process_filename_, std::ios_base::app); + if (!to_process_out.is_open()) { + ROS_ERROR("Failed to open %s in append mode. Check disk space and permissions.", to_process_filename_.c_str()); + } + processed_out.open(processed_filename_, std::ios_base::app); + if (!processed_out.is_open()) { + ROS_ERROR("Failed to open %s in append mode. Check disk space and permissions.", processed_filename_.c_str()); + } // Throw results into redis for access std::string base = "/sys/" + hostname + "/p1debayerq/"; @@ -513,10 +531,29 @@ namespace phase_one std::lock_guard lock(mtx); filename_to_seq_map_[fname] = seq; // write out every file received here, reduce set size with processed_out - to_process_out << fname << std::endl; + if (!to_process_out.is_open()) { + ROS_ERROR("|CAPTURE| to_process_out stream is not open. Attempting to reopen."); + to_process_out.open(to_process_filename_, std::ios_base::app); + if (!to_process_out.is_open()) { + ROS_ERROR("|CAPTURE| Failed to reopen %s. Check disk space and mount.", to_process_filename_.c_str()); + } + } + if (to_process_out.is_open()) { + to_process_out << fname << std::endl; + if (to_process_out.fail()) { + ROS_ERROR("|CAPTURE| Failed to write to %s. Check disk space.", to_process_filename_.c_str()); + } else { + to_process_out.flush(); + if (to_process_out.fail()) { + ROS_ERROR("|CAPTURE| Failed to flush %s. Data may not be written to disk.", to_process_filename_.c_str()); + } + } + } total_counter++; } catch (boost::filesystem::filesystem_error &e) { ROS_ERROR("|CAPTURE| Archive Failed [%d]: %s", e.code().value(), e.what()); + } catch (const std::ios_base::failure& e) { + ROS_ERROR("|CAPTURE| I/O error writing IIQ file: %s", e.what()); } } @@ -717,7 +754,24 @@ namespace phase_one if ( success ) { // delete IIQ file that's been processed remove(filename_iiq.c_str()); - processed_out << filename_iiq << std::endl; + if (!processed_out.is_open()) { + ROS_ERROR("|DEMOSAIC| processed_out stream is not open. Attempting to reopen."); + processed_out.open(processed_filename_, std::ios_base::app); + if (!processed_out.is_open()) { + ROS_ERROR("|DEMOSAIC| Failed to reopen %s. Check disk space and mount.", processed_filename_.c_str()); + } + } + if (processed_out.is_open()) { + processed_out << filename_iiq << std::endl; + if (processed_out.fail()) { + ROS_ERROR("|DEMOSAIC| Failed to write to %s. Check disk space.", processed_filename_.c_str()); + } else { + processed_out.flush(); + if (processed_out.fail()) { + ROS_ERROR("|DEMOSAIC| Failed to flush %s. Data may not be written to disk.", processed_filename_.c_str()); + } + } + } processed_counter++; } else { ROS_ERROR_STREAM("IIQ File: " << filename_iiq << " failed to save to disk as jpg."); @@ -1297,7 +1351,24 @@ namespace phase_one if ( count > 0 ) { // add to 'processed' file so that it won't attempt to be processed // after a reboot - processed_out << filename_iiq << std::endl; + if (!processed_out.is_open()) { + ROS_ERROR("|DETECTION| processed_out stream is not open. Attempting to reopen."); + processed_out.open(processed_filename_, std::ios_base::app); + if (!processed_out.is_open()) { + ROS_ERROR("|DETECTION| Failed to reopen %s. Check disk space and mount.", processed_filename_.c_str()); + } + } + if (processed_out.is_open()) { + processed_out << filename_iiq << std::endl; + if (processed_out.fail()) { + ROS_ERROR("|DETECTION| Failed to write to %s. Check disk space.", processed_filename_.c_str()); + } else { + processed_out.flush(); + if (processed_out.fail()) { + ROS_ERROR("|DETECTION| Failed to flush %s. Data may not be written to disk.", processed_filename_.c_str()); + } + } + } processed_counter++; // then remove IIQ file remove(filename_iiq.c_str()); From 6933ebe66b35cc08e9bb4aa4c513d90377d326f6 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Wed, 28 Jan 2026 19:43:40 +0000 Subject: [PATCH 008/139] Recreate the to_process file each time, guaranteeing all files will be processed. --- src/run_scripts/entry/cam_phaseone.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/run_scripts/entry/cam_phaseone.sh b/src/run_scripts/entry/cam_phaseone.sh index d955267..3c1ed22 100755 --- a/src/run_scripts/entry/cam_phaseone.sh +++ b/src/run_scripts/entry/cam_phaseone.sh @@ -104,6 +104,10 @@ if [[ $(redis-cli --raw -h $REDIS_HOST get /debug/rebuild ) == "true" ]]; then fi fi +echo "Building to_process.txt" +rm -f /mnt/data/to_process.txt +find /mnt/data/iiq_buffer -name "*.IIQ" > /mnt/data/to_process.txt + export ROS_NAMESPACE="/${NODE_HOSTNAME}/${CAM_MODE}" exec roslaunch "${ROSWAIT}" phase_one phase_one_standalone.launch \ ip_address:=${CAM_IP} \ From d310544e1a7829c9e85778dea7a2bbe6a91248cb Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Thu, 30 Apr 2026 13:26:58 -0400 Subject: [PATCH 009/139] Add defaults for use_nvjpeg --- src/cfg/redis/nayak_system_config.txt | 1 + src/cfg/redis/taiga_system_config.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/src/cfg/redis/nayak_system_config.txt b/src/cfg/redis/nayak_system_config.txt index aa6236d..5fe470e 100644 --- a/src/cfg/redis/nayak_system_config.txt +++ b/src/cfg/redis/nayak_system_config.txt @@ -16,3 +16,4 @@ /sys/arch/hosts/cas2/fov right /sys/arch/jpg/quality 90 /sys/arch/load_shapefile 0 +/sys/arch/use_nvjpeg 1 diff --git a/src/cfg/redis/taiga_system_config.txt b/src/cfg/redis/taiga_system_config.txt index aa6236d..5fe470e 100644 --- a/src/cfg/redis/taiga_system_config.txt +++ b/src/cfg/redis/taiga_system_config.txt @@ -16,3 +16,4 @@ /sys/arch/hosts/cas2/fov right /sys/arch/jpg/quality 90 /sys/arch/load_shapefile 0 +/sys/arch/use_nvjpeg 1 From e5b3af41b0d9f60e6e297b4b2c8373ddad889534 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Thu, 30 Apr 2026 15:38:24 -0400 Subject: [PATCH 010/139] Provisioning updates --- provision/ansible/hosts.yml | 4 +- provision/ansible/playbooks/cas/build.yml | 9 +- provision/ansible/playbooks/cas/configure.yml | 38 +++----- provision/ansible/playbooks/cas/provision.yml | 92 ++++++++----------- 4 files changed, 61 insertions(+), 82 deletions(-) diff --git a/provision/ansible/hosts.yml b/provision/ansible/hosts.yml index ceefd1c..763e39c 100644 --- a/provision/ansible/hosts.yml +++ b/provision/ansible/hosts.yml @@ -92,12 +92,12 @@ all: follower: True ssd_id: "1b5b6c41-48f2-43fe-82db-fdc598387ea3" cas3: - redis_host: False + redis_host: True supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/leader/supervisor.conf" leader: True follower: False ssd_id: "TODO" vars: gui: False - config_dir: "taiga" + config_dir: "nayak" nvidia_cuda: True diff --git a/provision/ansible/playbooks/cas/build.yml b/provision/ansible/playbooks/cas/build.yml index e07bb09..85ed2c8 100644 --- a/provision/ansible/playbooks/cas/build.yml +++ b/provision/ansible/playbooks/cas/build.yml @@ -4,12 +4,17 @@ - name: Make nuvo images command: chdir: "{{ kamera_dir }}" - cmd: make build-nuvo + cmd: make nuvo - name: Make viame images command: chdir: "{{ kamera_dir }}" - cmd: make build-viame + cmd: make viame + + - name: Make postflight images + command: + chdir: "{{ kamera_dir }}" + cmd: make postflight - name: Clean dangling images command: diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index 90d277f..adc33d0 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -15,11 +15,11 @@ update: True force: True - - name: Set redis configuration + - name: "Set redis configuration to {{ kamera_dir }}/src/cfg/redis.conf" become: True when: redis_host copy: - src: "{{ kamera_dir }}/src/cfg/{{ config_dir }}/redis.conf" + src: "{{ kamera_dir }}/src/cfg/redis.conf" remote_src: true dest: /etc/redis/redis.conf owner: root @@ -69,6 +69,18 @@ state: directory mode: '0755' + - name: Create ~/kw/SYSTEM_NAME if it does not exist + file: + path: ~/kw/SYSTEM_NAME + state: touch + mode: '0755' + + - name: Insert system name into ~/kw/SYSTEM_NAME + copy: + dest: ~/kw/SYSTEM_NAME + content: | + {{ config_dir }} + - name: Create repo dir symlink file: src: "{{ kamera_dir }}/.dir" @@ -181,34 +193,12 @@ when: follower or leader or gui shell: sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target - - name: Create ~/.local/bin if it does not exist - when: gui - file: - path: ~/.local/bin - state: directory - mode: '0755' - - name: Create ~/.tmuxinator if it does not exist file: path: ~/.tmuxinator state: directory mode: '0755' - - name: Create bootstrap symlink - file: - src: "{{ kamera_dir }}/src/run_scripts/bootstrap_app.sh" - dest: ~/.config/kamera/repo_dir.bash - owner: "{{ ansible_user }}" - state: link - - - name: Create kamera_run symlink - when: gui - file: - src: "{{ kamera_dir }}/src/run_scripts/newstartup/kamera_run.sh" - dest: ~/.local/bin/kamera_run - owner: "{{ ansible_user }}" - state: link - - name: Create udev rule for mcc_daq become: True when: leader diff --git a/provision/ansible/playbooks/cas/provision.yml b/provision/ansible/playbooks/cas/provision.yml index 8cf81b9..9effa03 100644 --- a/provision/ansible/playbooks/cas/provision.yml +++ b/provision/ansible/playbooks/cas/provision.yml @@ -3,10 +3,8 @@ - hosts: all vars: - nvidia_driver_version: 560 - linux_distro: ubuntu20.04 - ros_distro: noetic - ros_package: perception + nvidia_driver_version: 590 + linux_distro: ubuntu22.04 ansible_user: user sys_packages: [ 'apt-transport-https', 'gnupg-agent', # secure socket / signing @@ -18,8 +16,8 @@ 'mosh', # SSH tools 'git', # vcs 'vim', # editor - 'rubygems', # tmuxinator 'supervisor', # startup tools + 'tmuxinator', # tmux orchestration 'curl', 'wget', # http / download 'htop', # process monitor 'tree', 'mc', # explore filesystem @@ -36,16 +34,9 @@ 'ubuntu-drivers-common', # For hardware drivers 'python3-pip' # Pip goodness ] - ros_packages: [ - 'ros-noetic-rc-genicam-driver', - 'ros-noetic-rc-genicam-camera', - 'ros-noetic-rqt-image-view', - 'python3-catkin-tools' - ] pip_packages: [ "ansible", "ruff", - "black" ] pre_tasks: @@ -83,35 +74,15 @@ tags: - nuvo - - name: Add ROS repository apt-key - become: True - apt_key: - url: "https://raw.githubusercontent.com/ros/rosdistro/master/ros.key" - state: present - - - name: Add ROS repository - become: True - apt_repository: - repo: "deb http://packages.ros.org/ros/ubuntu {{ ansible_lsb.codename }} main" - state: present - - - name: Install ROS - become: True - apt: - pkg: "ros-{{ ros_distro }}-{{ ros_package }}" - state: present - - - name: Add ros setup sourcing to .bashrc - become: True - lineinfile: - path: /home/{{ ansible_user }}/.bashrc - state: present - line: "source /opt/ros/{{ ros_distro }}/setup.bash" - - name: Install required system packages become: True apt: name={{ sys_packages }} + - name: Install redis on redis host + become: True + apt: name=redis-server + when: redis_host + - name: Install docker and enable service become: True shell: curl https://get.docker.com | sh && systemctl --now enable docker @@ -129,17 +100,38 @@ tags: - nuvo - - name: Update apt and install nvidia-docker2 + - name: Add NVIDIA GPG key become: True - apt: update_cache=yes name=nvidia-docker2 state=latest - tags: - - nuvo + shell: + cmd: > + curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | + gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg + creates: /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg - - name: Install Docker Module for Python (for Ansible) - pip: - name: docker - executable: pip3 - extra_args: --user + - name: Add NVIDIA Container Toolkit apt repo + become: True + shell: + cmd: > + curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | + sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | + tee /etc/apt/sources.list.d/nvidia-container-toolkit.list + creates: /etc/apt/sources.list.d/nvidia-container-toolkit.list + + - name: Update apt cache + become: True + apt: + update_cache: true + + - name: Install nvidia-container-toolkit + become: True + apt: + name: nvidia-container-toolkit + state: present + + - name: Configure Docker runtime + become: True + command: + cmd: nvidia-ctk runtime configure --runtime=docker - name: Restart Docker Service become: True @@ -170,14 +162,6 @@ groups: ['user', 'docker', 'dialout', 'sudo'] tasks: - - name: Install required ros packages - become: True - apt: name={{ ros_packages }} - - - name: Install tmuxinator - become: True - shell: gem install tmuxinator -v 1.1.5 - - name: Install yq become: True get_url: From 25e3b941e40bf3b4f52a006cf13b780ca80b1e2f Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Fri, 1 May 2026 10:50:08 -0400 Subject: [PATCH 011/139] Add script to seed redis config, update provisioning to use it. --- provision/ansible/playbooks/cas/configure.yml | 7 +- provision/ansible/playbooks/cas/provision.yml | 2 + scripts/seed_redis.py | 126 ++++++++++++++++++ 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100755 scripts/seed_redis.py diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index adc33d0..cb0995b 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -30,9 +30,12 @@ service: name=redis-server state=restarted enabled=yes # Sets all system-wide parameters (except for REDIS_HOST) - - name: Set Redis defaults + - name: Seed Redis defaults when: redis_host - shell: cat "{{ kamera_dir }}/src/cfg/redis/{{ config_dir }}_system_config.conf" | xargs -n 2 bash -c 'redis-cli -h {{ inventory_hostname }} set $0 $1' + command: > + python3 {{ kamera_dir }}/scripts/seed_redis.py + --redis-host {{ inventory_hostname }} + --config {{ kamera_dir }}/src/cfg/{{ config_dir }}/default_system_state.json - name: Set up supervisor trampoline become: True diff --git a/provision/ansible/playbooks/cas/provision.yml b/provision/ansible/playbooks/cas/provision.yml index 9effa03..6de127c 100644 --- a/provision/ansible/playbooks/cas/provision.yml +++ b/provision/ansible/playbooks/cas/provision.yml @@ -37,6 +37,8 @@ pip_packages: [ "ansible", "ruff", + "redis", # seed_redis.py: Redis client for provisioning + "pyyaml", # seed_redis.py: YAML config loading ] pre_tasks: diff --git a/scripts/seed_redis.py b/scripts/seed_redis.py new file mode 100755 index 0000000..5b17f74 --- /dev/null +++ b/scripts/seed_redis.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 +"""Seed Redis with system configuration. + +Safe to re-run: existing keys are not overwritten unless --overwrite is passed. +Intended for use in Ansible provisioning. Requires only: redis-py, PyYAML. + + pip install redis pyyaml + +Each --config file is loaded and its contents seeded under --prefix (default /sys). +Multiple --config files are merged in order; later files do not overwrite earlier ones +unless --overwrite is set. + +Reimplements some logic in roskv to avoid building and importing. + +Example: + seed_redis.py --redis-host nuvo0 \\ + --config src/cfg/taiga/default_system_state.json +""" +from __future__ import print_function +import argparse +import json +import os +from collections.abc import Mapping + +import redis +import yaml + + +def _flatten(d, prefix="", sep="/"): + """Recursively flatten a nested dict into {keypath: leaf_value} pairs.""" + items = {} + for k, v in d.items(): + new_key = prefix + sep + k if prefix else k + if isinstance(v, Mapping): + items.update(_flatten(v, new_key, sep)) + else: + items[new_key] = v + return items + + +def seed(client, prefix, val, overwrite=False): + """Write a nested dict into Redis under prefix, skipping existing keys.""" + if isinstance(val, Mapping): + flat = _flatten(val, prefix=prefix) + else: + flat = {prefix: val} + + written = skipped = 0 + for k, v in flat.items(): + encoded = json.dumps(v) if not isinstance(v, str) else v + if overwrite: + client.set(k, encoded) + written += 1 + else: + if client.setnx(k, encoded): + written += 1 + else: + skipped += 1 + return written, skipped + + +def load_file(path): + ext = os.path.splitext(path)[1].lower() + with open(path) as f: + if ext in (".yml", ".yaml"): + return yaml.safe_load(f) + elif ext == ".json": + return json.load(f) + else: + raise ValueError("Unsupported file type: {}".format(path)) + + +def main(): + parser = argparse.ArgumentParser( + description="Seed Redis with system configuration (idempotent)." + ) + parser.add_argument( + "--redis-host", + default=os.environ.get("REDIS_HOST", "localhost"), + help="Redis hostname (default: $REDIS_HOST or localhost)", + ) + parser.add_argument( + "--redis-port", + type=int, + default=int(os.environ.get("REDIS_PORT", 6379)), + help="Redis port (default: $REDIS_PORT or 6379)", + ) + parser.add_argument( + "--config", + action="append", + dest="configs", + metavar="FILE", + required=True, + help="Config file to seed (.json or .yaml). May be specified multiple times.", + ) + parser.add_argument( + "--prefix", + default="/sys", + help="Redis key prefix to seed under (default: /sys)", + ) + parser.add_argument( + "--overwrite", + action="store_true", + help="Overwrite existing Redis keys (use only for fresh provision)", + ) + args = parser.parse_args() + + client = redis.Redis( + host=args.redis_host, port=args.redis_port, client_name="provisioner" + ) + + total_written = total_skipped = 0 + for path in args.configs: + data = load_file(path) + written, skipped = seed(client, args.prefix, data, args.overwrite) + print(" {}: {} written, {} skipped".format(path, written, skipped)) + total_written += written + total_skipped += skipped + + print("Done. {} keys written, {} skipped (already set) on {}:{}".format( + total_written, total_skipped, args.redis_host, args.redis_port + )) + + +if __name__ == "__main__": + main() From 9f53c692e8061b9a98ff8ee3cb24b334a1bf1990 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 4 May 2026 15:10:01 -0400 Subject: [PATCH 012/139] Update defaults --- src/cfg/nayak/default_system_state.json | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/cfg/nayak/default_system_state.json b/src/cfg/nayak/default_system_state.json index a1d1d26..9ab12cd 100644 --- a/src/cfg/nayak/default_system_state.json +++ b/src/cfg/nayak/default_system_state.json @@ -81,7 +81,7 @@ "archive_all_ir_images": 0, "base": "/mnt/data", "base_template": "{base}/{project}/fl{flight}/{sys_cfg}/", - "effort": "OFF", + "effort": "default_effort", "ext_evt": "json", "ext_ins": "json", "ext_ir": "tif", @@ -491,6 +491,16 @@ "wait_time_sec": 1 } }, + "effort_metadata_dict": { + "default_effort": { + "aircraft": "N94S", + "delete_old_images_sec": 60, + "field_notes": "Default effort, this should be edited", + "project_name": "default_effort", + "save_every_x_image": 5, + "wait_time_sec": 60 + } + }, "enabled": { "center": { "ir": true, @@ -821,4 +831,4 @@ "cam_fov": "left" }, "verbosity": 9 -} \ No newline at end of file +} From 2c74ad813db45951dd37cc8a664a0eb7976502f6 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 4 May 2026 15:20:50 -0400 Subject: [PATCH 013/139] Have safe default --- src/core/ins_driver/scripts/ins_socket_driver | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/core/ins_driver/scripts/ins_socket_driver b/src/core/ins_driver/scripts/ins_socket_driver index 1ddf16e..768e27d 100755 --- a/src/core/ins_driver/scripts/ins_socket_driver +++ b/src/core/ins_driver/scripts/ins_socket_driver @@ -205,7 +205,11 @@ class AvxClient(object): # GsofSpoofEventDispatch.add_publisher('event') # todo # recv-loop: When we're connected, keep receiving stuff until that fails counter = 0 - spoof_events = bool(int(rc.get("/debug/spoof_events"))) + spoof_events = rc.get("/debug/spoof_events") + if spoof_events is not None: + spoof_events = int(spoof_events) + else: + spoof_events = 0 for rawdata in gen_packets(host, port): event_arrived = rospy.Time.now() if rospy.is_shutdown(): @@ -214,7 +218,11 @@ class AvxClient(object): raw_ins_path = self.archiver.get_raw_ins_path() if not (counter % 100): rospy.loginfo('Ins path: {}'.format(raw_ins_path)) - spoof_events = bool(int(rc.get("/debug/spoof_events"))) + spoof_events = rc.get("/debug/spoof_events") + if spoof_events is not None: + spoof_events = int(spoof_events) + else: + spoof_events = 0 counter += 1 # todo: optionally archive stream @@ -237,7 +245,6 @@ class AvxClient(object): rospy.logerr("Some other exception in parsing: {}".format(err)) #aprint(dispatch.msg) for d in dispatches: - # print(d) d.msg.sys_time = event_arrived if isinstance(d, GsofEventDispatch) and spoof_events: rospy.logwarn("WARNING: Not publishing events because /debug/spoof_events is true.") From eae8cd96ad1c05055253428cea80149cd92bd535 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 4 May 2026 15:21:08 -0400 Subject: [PATCH 014/139] Remove local ROS calls in startup --- tmux/nayak/startup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmux/nayak/startup.sh b/tmux/nayak/startup.sh index e029c97..10cbb25 100755 --- a/tmux/nayak/startup.sh +++ b/tmux/nayak/startup.sh @@ -1,8 +1,8 @@ #!/bin/sh #DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -. /opt/ros/noetic/setup.sh +# . /opt/ros/noetic/setup.sh -rosclean purge -y +# rosclean purge -y mkdir -p ~/.tmuxinator mkdir -p ~/.config/kamera/gui From 2675b42bf6bc0b3d9ca3d50ec7a13f8bc5b12141 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 4 May 2026 15:23:34 -0400 Subject: [PATCH 015/139] Update redis default bind --- src/cfg/redis.conf | 1319 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1319 insertions(+) create mode 100755 src/cfg/redis.conf diff --git a/src/cfg/redis.conf b/src/cfg/redis.conf new file mode 100755 index 0000000..033bfb5 --- /dev/null +++ b/src/cfg/redis.conf @@ -0,0 +1,1319 @@ +# Redis configuration file example. +# +# Note that in order to read the configuration file, Redis must be +# started with the file path as first argument: +# +# ./redis-server /path/to/redis.conf + +# Note on units: when memory size is needed, it is possible to specify +# it in the usual form of 1k 5GB 4M and so forth: +# +# 1k => 1000 bytes +# 1kb => 1024 bytes +# 1m => 1000000 bytes +# 1mb => 1024*1024 bytes +# 1g => 1000000000 bytes +# 1gb => 1024*1024*1024 bytes +# +# units are case insensitive so 1GB 1Gb 1gB are all the same. + +################################## INCLUDES ################################### + +# Include one or more other config files here. This is useful if you +# have a standard template that goes to all Redis servers but also need +# to customize a few per-server settings. Include files can include +# other files, so use this wisely. +# +# Notice option "include" won't be rewritten by command "CONFIG REWRITE" +# from admin or Redis Sentinel. Since Redis always uses the last processed +# line as value of a configuration directive, you'd better put includes +# at the beginning of this file to avoid overwriting config change at runtime. +# +# If instead you are interested in using includes to override configuration +# options, it is better to use include as the last line. +# +# include /path/to/local.conf +# include /path/to/other.conf + +################################## MODULES ##################################### + +# Load modules at startup. If the server is not able to load modules +# it will abort. It is possible to use multiple loadmodule directives. +# +# loadmodule /path/to/my_module.so +# loadmodule /path/to/other_module.so + +################################## NETWORK ##################################### + +# By default, if no "bind" configuration directive is specified, Redis listens +# for connections from all the network interfaces available on the server. +# It is possible to listen to just one or multiple selected interfaces using +# the "bind" configuration directive, followed by one or more IP addresses. +# +# Examples: +# +# bind 192.168.1.100 10.0.0.1 +# bind 127.0.0.1 ::1 +# +# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the +# internet, binding to all the interfaces is dangerous and will expose the +# instance to everybody on the internet. So by default we uncomment the +# following bind directive, that will force Redis to listen only into +# the IPv4 lookback interface address (this means Redis will be able to +# accept connections only from clients running into the same computer it +# is running). +# +# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES +# JUST COMMENT THE FOLLOWING LINE. +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +bind 127.0.0.1 ::1 +bind ::1 +bind 0.0.0.0 + +# Protected mode is a layer of security protection, in order to avoid that +# Redis instances left open on the internet are accessed and exploited. +# +# When protected mode is on and if: +# +# 1) The server is not binding explicitly to a set of addresses using the +# "bind" directive. +# 2) No password is configured. +# +# The server only accepts connections from clients connecting from the +# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain +# sockets. +# +# By default protected mode is enabled. You should disable it only if +# you are sure you want clients from other hosts to connect to Redis +# even if no authentication is configured, nor a specific set of interfaces +# are explicitly listed using the "bind" directive. +protected-mode yes + +# Accept connections on the specified port, default is 6379 (IANA #815344). +# If port 0 is specified Redis will not listen on a TCP socket. +port 6379 + +# TCP listen() backlog. +# +# In high requests-per-second environments you need an high backlog in order +# to avoid slow clients connections issues. Note that the Linux kernel +# will silently truncate it to the value of /proc/sys/net/core/somaxconn so +# make sure to raise both the value of somaxconn and tcp_max_syn_backlog +# in order to get the desired effect. +tcp-backlog 511 + +# Unix socket. +# +# Specify the path for the Unix socket that will be used to listen for +# incoming connections. There is no default, so Redis will not listen +# on a unix socket when not specified. +# +# unixsocket /var/run/redis/redis-server.sock +# unixsocketperm 700 + +# Close the connection after a client is idle for N seconds (0 to disable) +timeout 0 + +# TCP keepalive. +# +# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence +# of communication. This is useful for two reasons: +# +# 1) Detect dead peers. +# 2) Take the connection alive from the point of view of network +# equipment in the middle. +# +# On Linux, the specified value (in seconds) is the period used to send ACKs. +# Note that to close the connection the double of the time is needed. +# On other kernels the period depends on the kernel configuration. +# +# A reasonable value for this option is 300 seconds, which is the new +# Redis default starting with Redis 3.2.1. +tcp-keepalive 300 + +################################# GENERAL ##################################### + +# By default Redis does not run as a daemon. Use 'yes' if you need it. +# Note that Redis will write a pid file in /var/run/redis.pid when daemonized. +daemonize yes + +# If you run Redis from upstart or systemd, Redis can interact with your +# supervision tree. Options: +# supervised no - no supervision interaction +# supervised upstart - signal upstart by putting Redis into SIGSTOP mode +# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET +# supervised auto - detect upstart or systemd method based on +# UPSTART_JOB or NOTIFY_SOCKET environment variables +# Note: these supervision methods only signal "process is ready." +# They do not enable continuous liveness pings back to your supervisor. +supervised no + +# If a pid file is specified, Redis writes it where specified at startup +# and removes it at exit. +# +# When the server runs non daemonized, no pid file is created if none is +# specified in the configuration. When the server is daemonized, the pid file +# is used even if not specified, defaulting to "/var/run/redis.pid". +# +# Creating a pid file is best effort: if Redis is not able to create it +# nothing bad happens, the server will start and run normally. +pidfile /var/run/redis/redis-server.pid + +# Specify the server verbosity level. +# This can be one of: +# debug (a lot of information, useful for development/testing) +# verbose (many rarely useful info, but not a mess like the debug level) +# notice (moderately verbose, what you want in production probably) +# warning (only very important / critical messages are logged) +loglevel notice + +# Specify the log file name. Also the empty string can be used to force +# Redis to log on the standard output. Note that if you use standard +# output for logging but daemonize, logs will be sent to /dev/null +logfile /var/log/redis/redis-server.log + +# To enable logging to the system logger, just set 'syslog-enabled' to yes, +# and optionally update the other syslog parameters to suit your needs. +# syslog-enabled no + +# Specify the syslog identity. +# syslog-ident redis + +# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7. +# syslog-facility local0 + +# Set the number of databases. The default database is DB 0, you can select +# a different one on a per-connection basis using SELECT where +# dbid is a number between 0 and 'databases'-1 +databases 16 + +# By default Redis shows an ASCII art logo only when started to log to the +# standard output and if the standard output is a TTY. Basically this means +# that normally a logo is displayed only in interactive sessions. +# +# However it is possible to force the pre-4.0 behavior and always show a +# ASCII art logo in startup logs by setting the following option to yes. +always-show-logo yes + +################################ SNAPSHOTTING ################################ +# +# Save the DB on disk: +# +# save +# +# Will save the DB if both the given number of seconds and the given +# number of write operations against the DB occurred. +# +# In the example below the behaviour will be to save: +# after 900 sec (15 min) if at least 1 key changed +# after 300 sec (5 min) if at least 10 keys changed +# after 60 sec if at least 10000 keys changed +# +# Note: you can disable saving completely by commenting out all "save" lines. +# +# It is also possible to remove all the previously configured save +# points by adding a save directive with a single empty string argument +# like in the following example: +# +# save "" + +save 900 1 +save 300 10 +save 60 10000 + +# By default Redis will stop accepting writes if RDB snapshots are enabled +# (at least one save point) and the latest background save failed. +# This will make the user aware (in a hard way) that data is not persisting +# on disk properly, otherwise chances are that no one will notice and some +# disaster will happen. +# +# If the background saving process will start working again Redis will +# automatically allow writes again. +# +# However if you have setup your proper monitoring of the Redis server +# and persistence, you may want to disable this feature so that Redis will +# continue to work as usual even if there are problems with disk, +# permissions, and so forth. +stop-writes-on-bgsave-error yes + +# Compress string objects using LZF when dump .rdb databases? +# For default that's set to 'yes' as it's almost always a win. +# If you want to save some CPU in the saving child set it to 'no' but +# the dataset will likely be bigger if you have compressible values or keys. +rdbcompression yes + +# Since version 5 of RDB a CRC64 checksum is placed at the end of the file. +# This makes the format more resistant to corruption but there is a performance +# hit to pay (around 10%) when saving and loading RDB files, so you can disable it +# for maximum performances. +# +# RDB files created with checksum disabled have a checksum of zero that will +# tell the loading code to skip the check. +rdbchecksum yes + +# The filename where to dump the DB +dbfilename dump.rdb + +# The working directory. +# +# The DB will be written inside this directory, with the filename specified +# above using the 'dbfilename' configuration directive. +# +# The Append Only File will also be created inside this directory. +# +# Note that you must specify a directory here, not a file name. +dir /var/lib/redis + +################################# REPLICATION ################################# + +# Master-Slave replication. Use slaveof to make a Redis instance a copy of +# another Redis server. A few things to understand ASAP about Redis replication. +# +# 1) Redis replication is asynchronous, but you can configure a master to +# stop accepting writes if it appears to be not connected with at least +# a given number of slaves. +# 2) Redis slaves are able to perform a partial resynchronization with the +# master if the replication link is lost for a relatively small amount of +# time. You may want to configure the replication backlog size (see the next +# sections of this file) with a sensible value depending on your needs. +# 3) Replication is automatic and does not need user intervention. After a +# network partition slaves automatically try to reconnect to masters +# and resynchronize with them. +# +# replicaof 192.168.88.10 6379 + +# If the master is password protected (using the "requirepass" configuration +# directive below) it is possible to tell the slave to authenticate before +# starting the replication synchronization process, otherwise the master will +# refuse the slave request. +# +# masterauth + +# When a slave loses its connection with the master, or when the replication +# is still in progress, the slave can act in two different ways: +# +# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will +# still reply to client requests, possibly with out of date data, or the +# data set may just be empty if this is the first synchronization. +# +# 2) if slave-serve-stale-data is set to 'no' the slave will reply with +# an error "SYNC with master in progress" to all the kind of commands +# but to INFO and SLAVEOF. +# +slave-serve-stale-data yes + +# You can configure a slave instance to accept writes or not. Writing against +# a slave instance may be useful to store some ephemeral data (because data +# written on a slave will be easily deleted after resync with the master) but +# may also cause problems if clients are writing to it because of a +# misconfiguration. +# +# Since Redis 2.6 by default slaves are read-only. +# +# Note: read only slaves are not designed to be exposed to untrusted clients +# on the internet. It's just a protection layer against misuse of the instance. +# Still a read only slave exports by default all the administrative commands +# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve +# security of read only slaves using 'rename-command' to shadow all the +# administrative / dangerous commands. +slave-read-only no + +# Replication SYNC strategy: disk or socket. +# +# ------------------------------------------------------- +# WARNING: DISKLESS REPLICATION IS EXPERIMENTAL CURRENTLY +# ------------------------------------------------------- +# +# New slaves and reconnecting slaves that are not able to continue the replication +# process just receiving differences, need to do what is called a "full +# synchronization". An RDB file is transmitted from the master to the slaves. +# The transmission can happen in two different ways: +# +# 1) Disk-backed: The Redis master creates a new process that writes the RDB +# file on disk. Later the file is transferred by the parent +# process to the slaves incrementally. +# 2) Diskless: The Redis master creates a new process that directly writes the +# RDB file to slave sockets, without touching the disk at all. +# +# With disk-backed replication, while the RDB file is generated, more slaves +# can be queued and served with the RDB file as soon as the current child producing +# the RDB file finishes its work. With diskless replication instead once +# the transfer starts, new slaves arriving will be queued and a new transfer +# will start when the current one terminates. +# +# When diskless replication is used, the master waits a configurable amount of +# time (in seconds) before starting the transfer in the hope that multiple slaves +# will arrive and the transfer can be parallelized. +# +# With slow disks and fast (large bandwidth) networks, diskless replication +# works better. +repl-diskless-sync no + +# When diskless replication is enabled, it is possible to configure the delay +# the server waits in order to spawn the child that transfers the RDB via socket +# to the slaves. +# +# This is important since once the transfer starts, it is not possible to serve +# new slaves arriving, that will be queued for the next RDB transfer, so the server +# waits a delay in order to let more slaves arrive. +# +# The delay is specified in seconds, and by default is 5 seconds. To disable +# it entirely just set it to 0 seconds and the transfer will start ASAP. +repl-diskless-sync-delay 5 + +# Slaves send PINGs to server in a predefined interval. It's possible to change +# this interval with the repl_ping_slave_period option. The default value is 10 +# seconds. +# +# repl-ping-slave-period 10 + +# The following option sets the replication timeout for: +# +# 1) Bulk transfer I/O during SYNC, from the point of view of slave. +# 2) Master timeout from the point of view of slaves (data, pings). +# 3) Slave timeout from the point of view of masters (REPLCONF ACK pings). +# +# It is important to make sure that this value is greater than the value +# specified for repl-ping-slave-period otherwise a timeout will be detected +# every time there is low traffic between the master and the slave. +# +# repl-timeout 60 + +# Disable TCP_NODELAY on the slave socket after SYNC? +# +# If you select "yes" Redis will use a smaller number of TCP packets and +# less bandwidth to send data to slaves. But this can add a delay for +# the data to appear on the slave side, up to 40 milliseconds with +# Linux kernels using a default configuration. +# +# If you select "no" the delay for data to appear on the slave side will +# be reduced but more bandwidth will be used for replication. +# +# By default we optimize for low latency, but in very high traffic conditions +# or when the master and slaves are many hops away, turning this to "yes" may +# be a good idea. +repl-disable-tcp-nodelay no + +# Set the replication backlog size. The backlog is a buffer that accumulates +# slave data when slaves are disconnected for some time, so that when a slave +# wants to reconnect again, often a full resync is not needed, but a partial +# resync is enough, just passing the portion of data the slave missed while +# disconnected. +# +# The bigger the replication backlog, the longer the time the slave can be +# disconnected and later be able to perform a partial resynchronization. +# +# The backlog is only allocated once there is at least a slave connected. +# +# repl-backlog-size 1mb + +# After a master has no longer connected slaves for some time, the backlog +# will be freed. The following option configures the amount of seconds that +# need to elapse, starting from the time the last slave disconnected, for +# the backlog buffer to be freed. +# +# Note that slaves never free the backlog for timeout, since they may be +# promoted to masters later, and should be able to correctly "partially +# resynchronize" with the slaves: hence they should always accumulate backlog. +# +# A value of 0 means to never release the backlog. +# +# repl-backlog-ttl 3600 + +# The slave priority is an integer number published by Redis in the INFO output. +# It is used by Redis Sentinel in order to select a slave to promote into a +# master if the master is no longer working correctly. +# +# A slave with a low priority number is considered better for promotion, so +# for instance if there are three slaves with priority 10, 100, 25 Sentinel will +# pick the one with priority 10, that is the lowest. +# +# However a special priority of 0 marks the slave as not able to perform the +# role of master, so a slave with priority of 0 will never be selected by +# Redis Sentinel for promotion. +# +# By default the priority is 100. +slave-priority 100 + +# It is possible for a master to stop accepting writes if there are less than +# N slaves connected, having a lag less or equal than M seconds. +# +# The N slaves need to be in "online" state. +# +# The lag in seconds, that must be <= the specified value, is calculated from +# the last ping received from the slave, that is usually sent every second. +# +# This option does not GUARANTEE that N replicas will accept the write, but +# will limit the window of exposure for lost writes in case not enough slaves +# are available, to the specified number of seconds. +# +# For example to require at least 3 slaves with a lag <= 10 seconds use: +# +# min-slaves-to-write 3 +# min-slaves-max-lag 10 +# +# Setting one or the other to 0 disables the feature. +# +# By default min-slaves-to-write is set to 0 (feature disabled) and +# min-slaves-max-lag is set to 10. + +# A Redis master is able to list the address and port of the attached +# slaves in different ways. For example the "INFO replication" section +# offers this information, which is used, among other tools, by +# Redis Sentinel in order to discover slave instances. +# Another place where this info is available is in the output of the +# "ROLE" command of a master. +# +# The listed IP and address normally reported by a slave is obtained +# in the following way: +# +# IP: The address is auto detected by checking the peer address +# of the socket used by the slave to connect with the master. +# +# Port: The port is communicated by the slave during the replication +# handshake, and is normally the port that the slave is using to +# list for connections. +# +# However when port forwarding or Network Address Translation (NAT) is +# used, the slave may be actually reachable via different IP and port +# pairs. The following two options can be used by a slave in order to +# report to its master a specific set of IP and port, so that both INFO +# and ROLE will report those values. +# +# There is no need to use both the options if you need to override just +# the port or the IP address. +# +# slave-announce-ip 5.5.5.5 +# slave-announce-port 1234 + +################################## SECURITY ################################### + +# Require clients to issue AUTH before processing any other +# commands. This might be useful in environments in which you do not trust +# others with access to the host running redis-server. +# +# This should stay commented out for backward compatibility and because most +# people do not need auth (e.g. they run their own servers). +# +# Warning: since Redis is pretty fast an outside user can try up to +# 150k passwords per second against a good box. This means that you should +# use a very strong password otherwise it will be very easy to break. +# +# requirepass foobared + +# Command renaming. +# +# It is possible to change the name of dangerous commands in a shared +# environment. For instance the CONFIG command may be renamed into something +# hard to guess so that it will still be available for internal-use tools +# but not available for general clients. +# +# Example: +# +# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 +# +# It is also possible to completely kill a command by renaming it into +# an empty string: +# +# rename-command CONFIG "" +# +# Please note that changing the name of commands that are logged into the +# AOF file or transmitted to slaves may cause problems. + +################################### CLIENTS #################################### + +# Set the max number of connected clients at the same time. By default +# this limit is set to 10000 clients, however if the Redis server is not +# able to configure the process file limit to allow for the specified limit +# the max number of allowed clients is set to the current file limit +# minus 32 (as Redis reserves a few file descriptors for internal uses). +# +# Once the limit is reached Redis will close all the new connections sending +# an error 'max number of clients reached'. +# +# maxclients 10000 + +############################## MEMORY MANAGEMENT ################################ + +# Set a memory usage limit to the specified amount of bytes. +# When the memory limit is reached Redis will try to remove keys +# according to the eviction policy selected (see maxmemory-policy). +# +# If Redis can't remove keys according to the policy, or if the policy is +# set to 'noeviction', Redis will start to reply with errors to commands +# that would use more memory, like SET, LPUSH, and so on, and will continue +# to reply to read-only commands like GET. +# +# This option is usually useful when using Redis as an LRU or LFU cache, or to +# set a hard memory limit for an instance (using the 'noeviction' policy). +# +# WARNING: If you have slaves attached to an instance with maxmemory on, +# the size of the output buffers needed to feed the slaves are subtracted +# from the used memory count, so that network problems / resyncs will +# not trigger a loop where keys are evicted, and in turn the output +# buffer of slaves is full with DELs of keys evicted triggering the deletion +# of more keys, and so forth until the database is completely emptied. +# +# In short... if you have slaves attached it is suggested that you set a lower +# limit for maxmemory so that there is some free RAM on the system for slave +# output buffers (but this is not needed if the policy is 'noeviction'). +# +# maxmemory + +# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory +# is reached. You can select among five behaviors: +# +# volatile-lru -> Evict using approximated LRU among the keys with an expire set. +# allkeys-lru -> Evict any key using approximated LRU. +# volatile-lfu -> Evict using approximated LFU among the keys with an expire set. +# allkeys-lfu -> Evict any key using approximated LFU. +# volatile-random -> Remove a random key among the ones with an expire set. +# allkeys-random -> Remove a random key, any key. +# volatile-ttl -> Remove the key with the nearest expire time (minor TTL) +# noeviction -> Don't evict anything, just return an error on write operations. +# +# LRU means Least Recently Used +# LFU means Least Frequently Used +# +# Both LRU, LFU and volatile-ttl are implemented using approximated +# randomized algorithms. +# +# Note: with any of the above policies, Redis will return an error on write +# operations, when there are no suitable keys for eviction. +# +# At the date of writing these commands are: set setnx setex append +# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd +# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby +# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby +# getset mset msetnx exec sort +# +# The default is: +# +# maxmemory-policy noeviction + +# LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated +# algorithms (in order to save memory), so you can tune it for speed or +# accuracy. For default Redis will check five keys and pick the one that was +# used less recently, you can change the sample size using the following +# configuration directive. +# +# The default of 5 produces good enough results. 10 Approximates very closely +# true LRU but costs more CPU. 3 is faster but not very accurate. +# +# maxmemory-samples 5 + +############################# LAZY FREEING #################################### + +# Redis has two primitives to delete keys. One is called DEL and is a blocking +# deletion of the object. It means that the server stops processing new commands +# in order to reclaim all the memory associated with an object in a synchronous +# way. If the key deleted is associated with a small object, the time needed +# in order to execute the DEL command is very small and comparable to most other +# O(1) or O(log_N) commands in Redis. However if the key is associated with an +# aggregated value containing millions of elements, the server can block for +# a long time (even seconds) in order to complete the operation. +# +# For the above reasons Redis also offers non blocking deletion primitives +# such as UNLINK (non blocking DEL) and the ASYNC option of FLUSHALL and +# FLUSHDB commands, in order to reclaim memory in background. Those commands +# are executed in constant time. Another thread will incrementally free the +# object in the background as fast as possible. +# +# DEL, UNLINK and ASYNC option of FLUSHALL and FLUSHDB are user-controlled. +# It's up to the design of the application to understand when it is a good +# idea to use one or the other. However the Redis server sometimes has to +# delete keys or flush the whole database as a side effect of other operations. +# Specifically Redis deletes objects independently of a user call in the +# following scenarios: +# +# 1) On eviction, because of the maxmemory and maxmemory policy configurations, +# in order to make room for new data, without going over the specified +# memory limit. +# 2) Because of expire: when a key with an associated time to live (see the +# EXPIRE command) must be deleted from memory. +# 3) Because of a side effect of a command that stores data on a key that may +# already exist. For example the RENAME command may delete the old key +# content when it is replaced with another one. Similarly SUNIONSTORE +# or SORT with STORE option may delete existing keys. The SET command +# itself removes any old content of the specified key in order to replace +# it with the specified string. +# 4) During replication, when a slave performs a full resynchronization with +# its master, the content of the whole database is removed in order to +# load the RDB file just transfered. +# +# In all the above cases the default is to delete objects in a blocking way, +# like if DEL was called. However you can configure each case specifically +# in order to instead release memory in a non-blocking way like if UNLINK +# was called, using the following configuration directives: + +lazyfree-lazy-eviction no +lazyfree-lazy-expire no +lazyfree-lazy-server-del no +slave-lazy-flush no + +############################## APPEND ONLY MODE ############################### + +# By default Redis asynchronously dumps the dataset on disk. This mode is +# good enough in many applications, but an issue with the Redis process or +# a power outage may result into a few minutes of writes lost (depending on +# the configured save points). +# +# The Append Only File is an alternative persistence mode that provides +# much better durability. For instance using the default data fsync policy +# (see later in the config file) Redis can lose just one second of writes in a +# dramatic event like a server power outage, or a single write if something +# wrong with the Redis process itself happens, but the operating system is +# still running correctly. +# +# AOF and RDB persistence can be enabled at the same time without problems. +# If the AOF is enabled on startup Redis will load the AOF, that is the file +# with the better durability guarantees. +# +# Please check http://redis.io/topics/persistence for more information. + +appendonly no + +# The name of the append only file (default: "appendonly.aof") + +appendfilename "appendonly.aof" + +# The fsync() call tells the Operating System to actually write data on disk +# instead of waiting for more data in the output buffer. Some OS will really flush +# data on disk, some other OS will just try to do it ASAP. +# +# Redis supports three different modes: +# +# no: don't fsync, just let the OS flush the data when it wants. Faster. +# always: fsync after every write to the append only log. Slow, Safest. +# everysec: fsync only one time every second. Compromise. +# +# The default is "everysec", as that's usually the right compromise between +# speed and data safety. It's up to you to understand if you can relax this to +# "no" that will let the operating system flush the output buffer when +# it wants, for better performances (but if you can live with the idea of +# some data loss consider the default persistence mode that's snapshotting), +# or on the contrary, use "always" that's very slow but a bit safer than +# everysec. +# +# More details please check the following article: +# http://antirez.com/post/redis-persistence-demystified.html +# +# If unsure, use "everysec". + +# appendfsync always +appendfsync everysec +# appendfsync no + +# When the AOF fsync policy is set to always or everysec, and a background +# saving process (a background save or AOF log background rewriting) is +# performing a lot of I/O against the disk, in some Linux configurations +# Redis may block too long on the fsync() call. Note that there is no fix for +# this currently, as even performing fsync in a different thread will block +# our synchronous write(2) call. +# +# In order to mitigate this problem it's possible to use the following option +# that will prevent fsync() from being called in the main process while a +# BGSAVE or BGREWRITEAOF is in progress. +# +# This means that while another child is saving, the durability of Redis is +# the same as "appendfsync none". In practical terms, this means that it is +# possible to lose up to 30 seconds of log in the worst scenario (with the +# default Linux settings). +# +# If you have latency problems turn this to "yes". Otherwise leave it as +# "no" that is the safest pick from the point of view of durability. + +no-appendfsync-on-rewrite no + +# Automatic rewrite of the append only file. +# Redis is able to automatically rewrite the log file implicitly calling +# BGREWRITEAOF when the AOF log size grows by the specified percentage. +# +# This is how it works: Redis remembers the size of the AOF file after the +# latest rewrite (if no rewrite has happened since the restart, the size of +# the AOF at startup is used). +# +# This base size is compared to the current size. If the current size is +# bigger than the specified percentage, the rewrite is triggered. Also +# you need to specify a minimal size for the AOF file to be rewritten, this +# is useful to avoid rewriting the AOF file even if the percentage increase +# is reached but it is still pretty small. +# +# Specify a percentage of zero in order to disable the automatic AOF +# rewrite feature. + +auto-aof-rewrite-percentage 100 +auto-aof-rewrite-min-size 64mb + +# An AOF file may be found to be truncated at the end during the Redis +# startup process, when the AOF data gets loaded back into memory. +# This may happen when the system where Redis is running +# crashes, especially when an ext4 filesystem is mounted without the +# data=ordered option (however this can't happen when Redis itself +# crashes or aborts but the operating system still works correctly). +# +# Redis can either exit with an error when this happens, or load as much +# data as possible (the default now) and start if the AOF file is found +# to be truncated at the end. The following option controls this behavior. +# +# If aof-load-truncated is set to yes, a truncated AOF file is loaded and +# the Redis server starts emitting a log to inform the user of the event. +# Otherwise if the option is set to no, the server aborts with an error +# and refuses to start. When the option is set to no, the user requires +# to fix the AOF file using the "redis-check-aof" utility before to restart +# the server. +# +# Note that if the AOF file will be found to be corrupted in the middle +# the server will still exit with an error. This option only applies when +# Redis will try to read more data from the AOF file but not enough bytes +# will be found. +aof-load-truncated yes + +# When rewriting the AOF file, Redis is able to use an RDB preamble in the +# AOF file for faster rewrites and recoveries. When this option is turned +# on the rewritten AOF file is composed of two different stanzas: +# +# [RDB file][AOF tail] +# +# When loading Redis recognizes that the AOF file starts with the "REDIS" +# string and loads the prefixed RDB file, and continues loading the AOF +# tail. +# +# This is currently turned off by default in order to avoid the surprise +# of a format change, but will at some point be used as the default. +aof-use-rdb-preamble no + +################################ LUA SCRIPTING ############################### + +# Max execution time of a Lua script in milliseconds. +# +# If the maximum execution time is reached Redis will log that a script is +# still in execution after the maximum allowed time and will start to +# reply to queries with an error. +# +# When a long running script exceeds the maximum execution time only the +# SCRIPT KILL and SHUTDOWN NOSAVE commands are available. The first can be +# used to stop a script that did not yet called write commands. The second +# is the only way to shut down the server in the case a write command was +# already issued by the script but the user doesn't want to wait for the natural +# termination of the script. +# +# Set it to 0 or a negative value for unlimited execution without warnings. +lua-time-limit 5000 + +################################ REDIS CLUSTER ############################### +# +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# WARNING EXPERIMENTAL: Redis Cluster is considered to be stable code, however +# in order to mark it as "mature" we need to wait for a non trivial percentage +# of users to deploy it in production. +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +# Normal Redis instances can't be part of a Redis Cluster; only nodes that are +# started as cluster nodes can. In order to start a Redis instance as a +# cluster node enable the cluster support uncommenting the following: +# +# cluster-enabled yes + +# Every cluster node has a cluster configuration file. This file is not +# intended to be edited by hand. It is created and updated by Redis nodes. +# Every Redis Cluster node requires a different cluster configuration file. +# Make sure that instances running in the same system do not have +# overlapping cluster configuration file names. +# +# cluster-config-file nodes-6379.conf + +# Cluster node timeout is the amount of milliseconds a node must be unreachable +# for it to be considered in failure state. +# Most other internal time limits are multiple of the node timeout. +# +# cluster-node-timeout 15000 + +# A slave of a failing master will avoid to start a failover if its data +# looks too old. +# +# There is no simple way for a slave to actually have an exact measure of +# its "data age", so the following two checks are performed: +# +# 1) If there are multiple slaves able to failover, they exchange messages +# in order to try to give an advantage to the slave with the best +# replication offset (more data from the master processed). +# Slaves will try to get their rank by offset, and apply to the start +# of the failover a delay proportional to their rank. +# +# 2) Every single slave computes the time of the last interaction with +# its master. This can be the last ping or command received (if the master +# is still in the "connected" state), or the time that elapsed since the +# disconnection with the master (if the replication link is currently down). +# If the last interaction is too old, the slave will not try to failover +# at all. +# +# The point "2" can be tuned by user. Specifically a slave will not perform +# the failover if, since the last interaction with the master, the time +# elapsed is greater than: +# +# (node-timeout * slave-validity-factor) + repl-ping-slave-period +# +# So for example if node-timeout is 30 seconds, and the slave-validity-factor +# is 10, and assuming a default repl-ping-slave-period of 10 seconds, the +# slave will not try to failover if it was not able to talk with the master +# for longer than 310 seconds. +# +# A large slave-validity-factor may allow slaves with too old data to failover +# a master, while a too small value may prevent the cluster from being able to +# elect a slave at all. +# +# For maximum availability, it is possible to set the slave-validity-factor +# to a value of 0, which means, that slaves will always try to failover the +# master regardless of the last time they interacted with the master. +# (However they'll always try to apply a delay proportional to their +# offset rank). +# +# Zero is the only value able to guarantee that when all the partitions heal +# the cluster will always be able to continue. +# +# cluster-slave-validity-factor 10 + +# Cluster slaves are able to migrate to orphaned masters, that are masters +# that are left without working slaves. This improves the cluster ability +# to resist to failures as otherwise an orphaned master can't be failed over +# in case of failure if it has no working slaves. +# +# Slaves migrate to orphaned masters only if there are still at least a +# given number of other working slaves for their old master. This number +# is the "migration barrier". A migration barrier of 1 means that a slave +# will migrate only if there is at least 1 other working slave for its master +# and so forth. It usually reflects the number of slaves you want for every +# master in your cluster. +# +# Default is 1 (slaves migrate only if their masters remain with at least +# one slave). To disable migration just set it to a very large value. +# A value of 0 can be set but is useful only for debugging and dangerous +# in production. +# +# cluster-migration-barrier 1 + +# By default Redis Cluster nodes stop accepting queries if they detect there +# is at least an hash slot uncovered (no available node is serving it). +# This way if the cluster is partially down (for example a range of hash slots +# are no longer covered) all the cluster becomes, eventually, unavailable. +# It automatically returns available as soon as all the slots are covered again. +# +# However sometimes you want the subset of the cluster which is working, +# to continue to accept queries for the part of the key space that is still +# covered. In order to do so, just set the cluster-require-full-coverage +# option to no. +# +# cluster-require-full-coverage yes + +# This option, when set to yes, prevents slaves from trying to failover its +# master during master failures. However the master can still perform a +# manual failover, if forced to do so. +# +# This is useful in different scenarios, especially in the case of multiple +# data center operations, where we want one side to never be promoted if not +# in the case of a total DC failure. +# +# cluster-slave-no-failover no + +# In order to setup your cluster make sure to read the documentation +# available at http://redis.io web site. + +########################## CLUSTER DOCKER/NAT support ######################## + +# In certain deployments, Redis Cluster nodes address discovery fails, because +# addresses are NAT-ted or because ports are forwarded (the typical case is +# Docker and other containers). +# +# In order to make Redis Cluster working in such environments, a static +# configuration where each node knows its public address is needed. The +# following two options are used for this scope, and are: +# +# * cluster-announce-ip +# * cluster-announce-port +# * cluster-announce-bus-port +# +# Each instruct the node about its address, client port, and cluster message +# bus port. The information is then published in the header of the bus packets +# so that other nodes will be able to correctly map the address of the node +# publishing the information. +# +# If the above options are not used, the normal Redis Cluster auto-detection +# will be used instead. +# +# Note that when remapped, the bus port may not be at the fixed offset of +# clients port + 10000, so you can specify any port and bus-port depending +# on how they get remapped. If the bus-port is not set, a fixed offset of +# 10000 will be used as usually. +# +# Example: +# +# cluster-announce-ip 10.1.1.5 +# cluster-announce-port 6379 +# cluster-announce-bus-port 6380 + +################################## SLOW LOG ################################### + +# The Redis Slow Log is a system to log queries that exceeded a specified +# execution time. The execution time does not include the I/O operations +# like talking with the client, sending the reply and so forth, +# but just the time needed to actually execute the command (this is the only +# stage of command execution where the thread is blocked and can not serve +# other requests in the meantime). +# +# You can configure the slow log with two parameters: one tells Redis +# what is the execution time, in microseconds, to exceed in order for the +# command to get logged, and the other parameter is the length of the +# slow log. When a new command is logged the oldest one is removed from the +# queue of logged commands. + +# The following time is expressed in microseconds, so 1000000 is equivalent +# to one second. Note that a negative number disables the slow log, while +# a value of zero forces the logging of every command. +slowlog-log-slower-than 10000 + +# There is no limit to this length. Just be aware that it will consume memory. +# You can reclaim memory used by the slow log with SLOWLOG RESET. +slowlog-max-len 128 + +################################ LATENCY MONITOR ############################## + +# The Redis latency monitoring subsystem samples different operations +# at runtime in order to collect data related to possible sources of +# latency of a Redis instance. +# +# Via the LATENCY command this information is available to the user that can +# print graphs and obtain reports. +# +# The system only logs operations that were performed in a time equal or +# greater than the amount of milliseconds specified via the +# latency-monitor-threshold configuration directive. When its value is set +# to zero, the latency monitor is turned off. +# +# By default latency monitoring is disabled since it is mostly not needed +# if you don't have latency issues, and collecting data has a performance +# impact, that while very small, can be measured under big load. Latency +# monitoring can easily be enabled at runtime using the command +# "CONFIG SET latency-monitor-threshold " if needed. +latency-monitor-threshold 0 + +############################# EVENT NOTIFICATION ############################## + +# Redis can notify Pub/Sub clients about events happening in the key space. +# This feature is documented at http://redis.io/topics/notifications +# +# For instance if keyspace events notification is enabled, and a client +# performs a DEL operation on key "foo" stored in the Database 0, two +# messages will be published via Pub/Sub: +# +# PUBLISH __keyspace@0__:foo del +# PUBLISH __keyevent@0__:del foo +# +# It is possible to select the events that Redis will notify among a set +# of classes. Every class is identified by a single character: +# +# K Keyspace events, published with __keyspace@__ prefix. +# E Keyevent events, published with __keyevent@__ prefix. +# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ... +# $ String commands +# l List commands +# s Set commands +# h Hash commands +# z Sorted set commands +# x Expired events (events generated every time a key expires) +# e Evicted events (events generated when a key is evicted for maxmemory) +# A Alias for g$lshzxe, so that the "AKE" string means all the events. +# +# The "notify-keyspace-events" takes as argument a string that is composed +# of zero or multiple characters. The empty string means that notifications +# are disabled. +# +# Example: to enable list and generic events, from the point of view of the +# event name, use: +# +# notify-keyspace-events Elg +# +# Example 2: to get the stream of the expired keys subscribing to channel +# name __keyevent@0__:expired use: +# +# notify-keyspace-events Ex +# +# By default all notifications are disabled because most users don't need +# this feature and the feature has some overhead. Note that if you don't +# specify at least one of K or E, no events will be delivered. +notify-keyspace-events "" + +############################### ADVANCED CONFIG ############################### + +# Hashes are encoded using a memory efficient data structure when they have a +# small number of entries, and the biggest entry does not exceed a given +# threshold. These thresholds can be configured using the following directives. +hash-max-ziplist-entries 512 +hash-max-ziplist-value 64 + +# Lists are also encoded in a special way to save a lot of space. +# The number of entries allowed per internal list node can be specified +# as a fixed maximum size or a maximum number of elements. +# For a fixed maximum size, use -5 through -1, meaning: +# -5: max size: 64 Kb <-- not recommended for normal workloads +# -4: max size: 32 Kb <-- not recommended +# -3: max size: 16 Kb <-- probably not recommended +# -2: max size: 8 Kb <-- good +# -1: max size: 4 Kb <-- good +# Positive numbers mean store up to _exactly_ that number of elements +# per list node. +# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size), +# but if your use case is unique, adjust the settings as necessary. +list-max-ziplist-size -2 + +# Lists may also be compressed. +# Compress depth is the number of quicklist ziplist nodes from *each* side of +# the list to *exclude* from compression. The head and tail of the list +# are always uncompressed for fast push/pop operations. Settings are: +# 0: disable all list compression +# 1: depth 1 means "don't start compressing until after 1 node into the list, +# going from either the head or tail" +# So: [head]->node->node->...->node->[tail] +# [head], [tail] will always be uncompressed; inner nodes will compress. +# 2: [head]->[next]->node->node->...->node->[prev]->[tail] +# 2 here means: don't compress head or head->next or tail->prev or tail, +# but compress all nodes between them. +# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail] +# etc. +list-compress-depth 0 + +# Sets have a special encoding in just one case: when a set is composed +# of just strings that happen to be integers in radix 10 in the range +# of 64 bit signed integers. +# The following configuration setting sets the limit in the size of the +# set in order to use this special memory saving encoding. +set-max-intset-entries 512 + +# Similarly to hashes and lists, sorted sets are also specially encoded in +# order to save a lot of space. This encoding is only used when the length and +# elements of a sorted set are below the following limits: +zset-max-ziplist-entries 128 +zset-max-ziplist-value 64 + +# HyperLogLog sparse representation bytes limit. The limit includes the +# 16 bytes header. When an HyperLogLog using the sparse representation crosses +# this limit, it is converted into the dense representation. +# +# A value greater than 16000 is totally useless, since at that point the +# dense representation is more memory efficient. +# +# The suggested value is ~ 3000 in order to have the benefits of +# the space efficient encoding without slowing down too much PFADD, +# which is O(N) with the sparse encoding. The value can be raised to +# ~ 10000 when CPU is not a concern, but space is, and the data set is +# composed of many HyperLogLogs with cardinality in the 0 - 15000 range. +hll-sparse-max-bytes 3000 + +# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in +# order to help rehashing the main Redis hash table (the one mapping top-level +# keys to values). The hash table implementation Redis uses (see dict.c) +# performs a lazy rehashing: the more operation you run into a hash table +# that is rehashing, the more rehashing "steps" are performed, so if the +# server is idle the rehashing is never complete and some more memory is used +# by the hash table. +# +# The default is to use this millisecond 10 times every second in order to +# actively rehash the main dictionaries, freeing memory when possible. +# +# If unsure: +# use "activerehashing no" if you have hard latency requirements and it is +# not a good thing in your environment that Redis can reply from time to time +# to queries with 2 milliseconds delay. +# +# use "activerehashing yes" if you don't have such hard requirements but +# want to free memory asap when possible. +activerehashing yes + +# The client output buffer limits can be used to force disconnection of clients +# that are not reading data from the server fast enough for some reason (a +# common reason is that a Pub/Sub client can't consume messages as fast as the +# publisher can produce them). +# +# The limit can be set differently for the three different classes of clients: +# +# normal -> normal clients including MONITOR clients +# slave -> slave clients +# pubsub -> clients subscribed to at least one pubsub channel or pattern +# +# The syntax of every client-output-buffer-limit directive is the following: +# +# client-output-buffer-limit +# +# A client is immediately disconnected once the hard limit is reached, or if +# the soft limit is reached and remains reached for the specified number of +# seconds (continuously). +# So for instance if the hard limit is 32 megabytes and the soft limit is +# 16 megabytes / 10 seconds, the client will get disconnected immediately +# if the size of the output buffers reach 32 megabytes, but will also get +# disconnected if the client reaches 16 megabytes and continuously overcomes +# the limit for 10 seconds. +# +# By default normal clients are not limited because they don't receive data +# without asking (in a push way), but just after a request, so only +# asynchronous clients may create a scenario where data is requested faster +# than it can read. +# +# Instead there is a default limit for pubsub and slave clients, since +# subscribers and slaves receive data in a push fashion. +# +# Both the hard or the soft limit can be disabled by setting them to zero. +client-output-buffer-limit normal 0 0 0 +client-output-buffer-limit slave 256mb 64mb 60 +client-output-buffer-limit pubsub 32mb 8mb 60 + +# Client query buffers accumulate new commands. They are limited to a fixed +# amount by default in order to avoid that a protocol desynchronization (for +# instance due to a bug in the client) will lead to unbound memory usage in +# the query buffer. However you can configure it here if you have very special +# needs, such us huge multi/exec requests or alike. +# +# client-query-buffer-limit 1gb + +# In the Redis protocol, bulk requests, that are, elements representing single +# strings, are normally limited ot 512 mb. However you can change this limit +# here. +# +# proto-max-bulk-len 512mb + +# Redis calls an internal function to perform many background tasks, like +# closing connections of clients in timeout, purging expired keys that are +# never requested, and so forth. +# +# Not all tasks are performed with the same frequency, but Redis checks for +# tasks to perform according to the specified "hz" value. +# +# By default "hz" is set to 10. Raising the value will use more CPU when +# Redis is idle, but at the same time will make Redis more responsive when +# there are many keys expiring at the same time, and timeouts may be +# handled with more precision. +# +# The range is between 1 and 500, however a value over 100 is usually not +# a good idea. Most users should use the default of 10 and raise this up to +# 100 only in environments where very low latency is required. +hz 10 + +# When a child rewrites the AOF file, if the following option is enabled +# the file will be fsync-ed every 32 MB of data generated. This is useful +# in order to commit the file to the disk more incrementally and avoid +# big latency spikes. +aof-rewrite-incremental-fsync yes + +# Redis LFU eviction (see maxmemory setting) can be tuned. However it is a good +# idea to start with the default settings and only change them after investigating +# how to improve the performances and how the keys LFU change over time, which +# is possible to inspect via the OBJECT FREQ command. +# +# There are two tunable parameters in the Redis LFU implementation: the +# counter logarithm factor and the counter decay time. It is important to +# understand what the two parameters mean before changing them. +# +# The LFU counter is just 8 bits per key, it's maximum value is 255, so Redis +# uses a probabilistic increment with logarithmic behavior. Given the value +# of the old counter, when a key is accessed, the counter is incremented in +# this way: +# +# 1. A random number R between 0 and 1 is extracted. +# 2. A probability P is calculated as 1/(old_value*lfu_log_factor+1). +# 3. The counter is incremented only if R < P. +# +# The default lfu-log-factor is 10. This is a table of how the frequency +# counter changes with a different number of accesses with different +# logarithmic factors: +# +# +--------+------------+------------+------------+------------+------------+ +# | factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits | +# +--------+------------+------------+------------+------------+------------+ +# | 0 | 104 | 255 | 255 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 1 | 18 | 49 | 255 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 10 | 10 | 18 | 142 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 100 | 8 | 11 | 49 | 143 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# +# NOTE: The above table was obtained by running the following commands: +# +# redis-benchmark -n 1000000 incr foo +# redis-cli object freq foo +# +# NOTE 2: The counter initial value is 5 in order to give new objects a chance +# to accumulate hits. +# +# The counter decay time is the time, in minutes, that must elapse in order +# for the key counter to be divided by two (or decremented if it has a value +# less <= 10). +# +# The default value for the lfu-decay-time is 1. A Special value of 0 means to +# decay the counter every time it happens to be scanned. +# +# lfu-log-factor 10 +# lfu-decay-time 1 + +########################### ACTIVE DEFRAGMENTATION ####################### +# +# WARNING THIS FEATURE IS EXPERIMENTAL. However it was stress tested +# even in production and manually tested by multiple engineers for some +# time. +# +# What is active defragmentation? +# ------------------------------- +# +# Active (online) defragmentation allows a Redis server to compact the +# spaces left between small allocations and deallocations of data in memory, +# thus allowing to reclaim back memory. +# +# Fragmentation is a natural process that happens with every allocator (but +# less so with Jemalloc, fortunately) and certain workloads. Normally a server +# restart is needed in order to lower the fragmentation, or at least to flush +# away all the data and create it again. However thanks to this feature +# implemented by Oran Agra for Redis 4.0 this process can happen at runtime +# in an "hot" way, while the server is running. +# +# Basically when the fragmentation is over a certain level (see the +# configuration options below) Redis will start to create new copies of the +# values in contiguous memory regions by exploiting certain specific Jemalloc +# features (in order to understand if an allocation is causing fragmentation +# and to allocate it in a better place), and at the same time, will release the +# old copies of the data. This process, repeated incrementally for all the keys +# will cause the fragmentation to drop back to normal values. +# +# Important things to understand: +# +# 1. This feature is disabled by default, and only works if you compiled Redis +# to use the copy of Jemalloc we ship with the source code of Redis. +# This is the default with Linux builds. +# +# 2. You never need to enable this feature if you don't have fragmentation +# issues. +# +# 3. Once you experience fragmentation, you can enable this feature when +# needed with the command "CONFIG SET activedefrag yes". +# +# The configuration parameters are able to fine tune the behavior of the +# defragmentation process. If you are not sure about what they mean it is +# a good idea to leave the defaults untouched. + +# Enabled active defragmentation +# activedefrag yes + +# Minimum amount of fragmentation waste to start active defrag +# active-defrag-ignore-bytes 100mb + +# Minimum percentage of fragmentation to start active defrag +# active-defrag-threshold-lower 10 + +# Maximum percentage of fragmentation at which we use maximum effort +# active-defrag-threshold-upper 100 + +# Minimal effort for defrag in CPU percentage +# active-defrag-cycle-min 25 + +# Maximal effort for defrag in CPU percentage +# active-defrag-cycle-max 75 + From 1849c47134592d4ca2209dd3f46565703241a4e9 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 4 May 2026 15:25:18 -0400 Subject: [PATCH 016/139] Move order of aptitude install so only one cache update is required --- provision/ansible/playbooks/cas/provision.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/provision/ansible/playbooks/cas/provision.yml b/provision/ansible/playbooks/cas/provision.yml index 6de127c..a4b8621 100644 --- a/provision/ansible/playbooks/cas/provision.yml +++ b/provision/ansible/playbooks/cas/provision.yml @@ -50,15 +50,15 @@ ignore_errors: yes register: uname_m - - name: Install aptitude - become: True - apt: name=aptitude state=present - - name: Fully Update System become: True become_user: root apt: update_cache=True upgrade=full + - name: Install aptitude + become: True + apt: name=aptitude state=present + - name: Add nvidia-drivers apt repository become: True apt_repository: From 5cdaa698f11b69c4297dca22cf2bcc276919e1d8 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Wed, 6 May 2026 11:05:30 -0400 Subject: [PATCH 017/139] Move the KAMERA_DIR env variable into the supervisor conf, so only one location needs modification for startup scripts. --- src/cfg/nayak/supervisord.conf | 1 + src/cfg/taiga/supervisord.conf | 1 + src/cfg/uas/supervisord.conf | 27 ++++++++++++++++++++ tmux/nayak/follower/supervisor.conf | 26 ++++++++++---------- tmux/nayak/leader/supervisor.conf | 38 ++++++++++++++--------------- tmux/taiga/follower/supervisor.conf | 26 ++++++++++---------- tmux/taiga/leader/supervisor.conf | 38 ++++++++++++++--------------- tmux/uas/follower/supervisor.conf | 12 ++++----- tmux/uas/guibox/supervisor.conf | 2 +- tmux/uas/leader/supervisor.conf | 10 ++++---- 10 files changed, 105 insertions(+), 76 deletions(-) create mode 100644 src/cfg/uas/supervisord.conf diff --git a/src/cfg/nayak/supervisord.conf b/src/cfg/nayak/supervisord.conf index 48e4054..5ecaa71 100644 --- a/src/cfg/nayak/supervisord.conf +++ b/src/cfg/nayak/supervisord.conf @@ -12,6 +12,7 @@ port=0.0.0.0:9001 logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) +environment=KAMERA_DIR="/home/user/kw/kamera" ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be diff --git a/src/cfg/taiga/supervisord.conf b/src/cfg/taiga/supervisord.conf index 48e4054..5ecaa71 100644 --- a/src/cfg/taiga/supervisord.conf +++ b/src/cfg/taiga/supervisord.conf @@ -12,6 +12,7 @@ port=0.0.0.0:9001 logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) +environment=KAMERA_DIR="/home/user/kw/kamera" ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be diff --git a/src/cfg/uas/supervisord.conf b/src/cfg/uas/supervisord.conf new file mode 100644 index 0000000..2028122 --- /dev/null +++ b/src/cfg/uas/supervisord.conf @@ -0,0 +1,27 @@ +; supervisor config file + +[unix_http_server] +file=/var/run/supervisor.sock ; (the path to the socket file) +chmod=0700 ; sockef file mode (default 0700) +chown=user:user + +[inet_http_server] +port=0.0.0.0:9001 + +[supervisord] +logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) +pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) +childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) +environment=KAMERA_DIR="/home/user/kw/kamera" + +; the below section must remain in the config file for RPC +; (supervisorctl/web interface) to work, additional interfaces may be +; added by defining them in separate rpcinterface: sections +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket + +[include] +files = /etc/supervisor/conf.d/*.conf diff --git a/tmux/nayak/follower/supervisor.conf b/tmux/nayak/follower/supervisor.conf index c694775..539b71a 100644 --- a/tmux/nayak/follower/supervisor.conf +++ b/tmux/nayak/follower/supervisor.conf @@ -1,79 +1,79 @@ [program:kamerad] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh kamerad +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh kamerad user=user environment=HOME="/home/user",USER="user" autostart=false [program:image_manager] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh image_manager +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh image_manager user=user environment=HOME="/home/user",USER="user" autostart=false [program:mount_nas] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/mount_nas.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/mount_nas.sh startsecs=0 user=root environment=HOME="/home/user",USER="root" autostart=true [program:set_eth_speed_max] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/set_eth_speed_max.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/set_eth_speed_max.sh startsecs=0 user=root environment=HOME="/home/user",USER="root" autostart=true [program:cam_ir] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh cam_ir +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh cam_ir user=user environment=HOME="/home/user",USER="user" autostart=false [program:cam_uv] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh cam_uv +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh cam_uv user=user environment=HOME="/home/user",USER="user" autostart=false [program:cam_rgb] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh cam_rgb +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh cam_rgb user=user environment=HOME="/home/user",USER="user" autostart=false [program:imageview] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh imageview +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh imageview user=user environment=HOME="/home/user",USER="user" autostart=false [program:fps_monitor] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh fps_monitor +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh fps_monitor user=user environment=HOME="/home/user",USER="user" autostart=false [program:detector] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh detector +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh detector user=user environment=HOME="/home/user",USER="user" autostart=false [program:flight_summary] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh flight_summary +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh flight_summary user=user environment=HOME="/home/user",USER="user" autostart=false [program:homography] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh homography +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh homography user=user environment=HOME="/home/user",USER="user" autostart=false [program:detections] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh detections +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh detections user=user environment=HOME="/home/user",USER="user" autostart=false diff --git a/tmux/nayak/leader/supervisor.conf b/tmux/nayak/leader/supervisor.conf index 359aaf6..3d2b56f 100644 --- a/tmux/nayak/leader/supervisor.conf +++ b/tmux/nayak/leader/supervisor.conf @@ -1,116 +1,116 @@ [program:kamerad] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh kamerad +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh kamerad user=user environment=HOME="/home/user",USER="user" autostart=false [program:image_manager] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh image_manager +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh image_manager user=user environment=HOME="/home/user",USER="user" autostart=false [program:restart_redis] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/restart_redis.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/restart_redis.sh startsecs=0 user=root environment=HOME="/home/user",USER="root" autostart=true [program:mount_nas] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/mount_nas.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/mount_nas.sh startsecs=0 user=root environment=HOME="/home/user",USER="root" autostart=true [program:set_eth_speed_max] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/set_eth_speed_max.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/set_eth_speed_max.sh startsecs=0 user=root environment=HOME="/home/user",USER="root" autostart=true [program:roscore] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh roscore +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh roscore user=user environment=HOME="/home/user",USER="user" autostart=false [program:cam_param_monitor] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh cam_param_monitor +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh cam_param_monitor user=user environment=HOME="/home/user",USER="user" autostart=false [program:fps_monitor] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh fps_monitor +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh fps_monitor user=user environment=HOME="/home/user",USER="user" autostart=false [program:shapefile_monitor] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh shapefile_monitor +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh shapefile_monitor user=user environment=HOME="/home/user",USER="user" autostart=false [program:cam_ir] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh cam_ir +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh cam_ir user=user environment=HOME="/home/user",USER="user" autostart=false [program:cam_uv] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh cam_uv +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh cam_uv user=user environment=HOME="/home/user",USER="user" autostart=false [program:cam_rgb] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh cam_rgb +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh cam_rgb user=user environment=HOME="/home/user",USER="user" autostart=false [program:ins] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh ins +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh ins user=user environment=HOME="/home/user",USER="user" autostart=false [program:daq] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh daq +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh daq user=user environment=HOME="/home/user",USER="user" autostart=false [program:imageview] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh imageview +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh imageview user=user environment=HOME="/home/user",USER="user" autostart=false [program:detector] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh detector +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh detector user=user environment=HOME="/home/user",USER="user" autostart=false [program:flight_summary] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh flight_summary +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh flight_summary user=user environment=HOME="/home/user",USER="user" autostart=false [program:homography] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh homography +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh homography user=user environment=HOME="/home/user",USER="user" autostart=false [program:detections] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh detections +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh detections user=user environment=HOME="/home/user",USER="user" autostart=false diff --git a/tmux/taiga/follower/supervisor.conf b/tmux/taiga/follower/supervisor.conf index 8d09a86..6e29146 100644 --- a/tmux/taiga/follower/supervisor.conf +++ b/tmux/taiga/follower/supervisor.conf @@ -1,79 +1,79 @@ [program:kamerad] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh kamerad +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh kamerad user=user environment=HOME="/home/user",USER="user" autostart=false [program:image_manager] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh image_manager +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh image_manager user=user environment=HOME="/home/user",USER="user" autostart=false [program:mount_nas] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/mount_nas.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/mount_nas.sh startsecs=0 user=root environment=HOME="/home/user",USER="root" autostart=true [program:set_eth_speed_max] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/set_eth_speed_max.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/set_eth_speed_max.sh startsecs=0 user=root environment=HOME="/home/user",USER="root" autostart=true [program:cam_ir] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh cam_ir +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh cam_ir user=user environment=HOME="/home/user",USER="user" autostart=false [program:cam_uv] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh cam_uv +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh cam_uv user=user environment=HOME="/home/user",USER="user" autostart=false [program:cam_rgb] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh cam_rgb +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh cam_rgb user=user environment=HOME="/home/user",USER="user" autostart=false [program:imageview] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh imageview +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh imageview user=user environment=HOME="/home/user",USER="user" autostart=false [program:fps_monitor] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh fps_monitor +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh fps_monitor user=user environment=HOME="/home/user",USER="user" autostart=false [program:detector] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh detector +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh detector user=user environment=HOME="/home/user",USER="user" autostart=false [program:flight_summary] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh flight_summary +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh flight_summary user=user environment=HOME="/home/user",USER="user" autostart=false [program:homography] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh homography +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh homography user=user environment=HOME="/home/user",USER="user" autostart=false [program:detections] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh detections +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh detections user=user environment=HOME="/home/user",USER="user" autostart=false diff --git a/tmux/taiga/leader/supervisor.conf b/tmux/taiga/leader/supervisor.conf index 5986197..0f49c83 100644 --- a/tmux/taiga/leader/supervisor.conf +++ b/tmux/taiga/leader/supervisor.conf @@ -1,116 +1,116 @@ [program:kamerad] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh kamerad +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh kamerad user=user environment=HOME="/home/user",USER="user" autostart=false [program:image_manager] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh image_manager +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh image_manager user=user environment=HOME="/home/user",USER="user" autostart=false [program:restart_redis] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/restart_redis.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/restart_redis.sh startsecs=0 user=root environment=HOME="/home/user",USER="root" autostart=true [program:mount_nas] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/mount_nas.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/mount_nas.sh startsecs=0 user=root environment=HOME="/home/user",USER="root" autostart=true [program:set_eth_speed_max] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/set_eth_speed_max.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/set_eth_speed_max.sh startsecs=0 user=root environment=HOME="/home/user",USER="root" autostart=true [program:roscore] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh roscore +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh roscore user=user environment=HOME="/home/user",USER="user" autostart=false [program:cam_param_monitor] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh cam_param_monitor +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh cam_param_monitor user=user environment=HOME="/home/user",USER="user" autostart=false [program:fps_monitor] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh fps_monitor +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh fps_monitor user=user environment=HOME="/home/user",USER="user" autostart=false [program:shapefile_monitor] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh shapefile_monitor +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh shapefile_monitor user=user environment=HOME="/home/user",USER="user" autostart=false [program:cam_ir] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh cam_ir +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh cam_ir user=user environment=HOME="/home/user",USER="user" autostart=false [program:cam_uv] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh cam_uv +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh cam_uv user=user environment=HOME="/home/user",USER="user" autostart=false [program:cam_rgb] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh cam_rgb +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh cam_rgb user=user environment=HOME="/home/user",USER="user" autostart=false [program:ins] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh ins +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh ins user=user environment=HOME="/home/user",USER="user" autostart=false [program:daq] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh daq +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh daq user=user environment=HOME="/home/user",USER="user" autostart=false [program:imageview] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh imageview +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh imageview user=user environment=HOME="/home/user",USER="user" autostart=false [program:detector] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh detector +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh detector user=user environment=HOME="/home/user",USER="user" autostart=false [program:flight_summary] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh flight_summary +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh flight_summary user=user environment=HOME="/home/user",USER="user" autostart=false [program:homography] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh homography +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh homography user=user environment=HOME="/home/user",USER="user" autostart=false [program:detections] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh detections +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh detections user=user environment=HOME="/home/user",USER="user" autostart=false diff --git a/tmux/uas/follower/supervisor.conf b/tmux/uas/follower/supervisor.conf index 4e13125..745a013 100644 --- a/tmux/uas/follower/supervisor.conf +++ b/tmux/uas/follower/supervisor.conf @@ -1,35 +1,35 @@ [program:core] -command=/bin/bash /home/user/kw/kamera/tmux/uas/follower/00_start_core.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/00_start_core.sh user=user environment=HOME="/home/user",USER="user" autostart=true [program:sensors] -command=/bin/bash /home/user/kw/kamera/tmux/uas/follower/01_start_sensors.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/01_start_sensors.sh user=user environment=HOME="/home/user",USER="user" autostart=true [program:processing] -command=/bin/bash /home/user/kw/kamera/tmux/uas/follower/02_start_processing.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/02_start_processing.sh user=user environment=HOME="/home/user",USER="user" autostart=true [program:timesync] -command=/bin/bash /home/user/kw/kamera/tmux/uas/follower/03_run_clock_sync.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/03_run_clock_sync.sh user=root environment=HOME="/home/user",USER="root" autostart=true [program:camptp] -command=/bin/bash /home/user/kw/kamera/tmux/uas/follower/04_run_cam_ptp.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/04_run_cam_ptp.sh user=root environment=HOME="/home/user",USER="root" autostart=true [program:docker] -command=/bin/bash /home/user/kw/kamera/tmux/uas/follower/05_start_docker.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/05_start_docker.sh user=root environment=HOME="/home/user",USER="root" autostart=true diff --git a/tmux/uas/guibox/supervisor.conf b/tmux/uas/guibox/supervisor.conf index 8dcb6d9..0e3217d 100644 --- a/tmux/uas/guibox/supervisor.conf +++ b/tmux/uas/guibox/supervisor.conf @@ -1,5 +1,5 @@ [program:flight_summary] -command=/bin/bash /home/user/kw/kamera/tmux/uas/guibox/00_flight_summary.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/guibox/00_flight_summary.sh user=root environment=HOME="/home/user",USER="root" autostart=true diff --git a/tmux/uas/leader/supervisor.conf b/tmux/uas/leader/supervisor.conf index f5f2cf7..e34f471 100644 --- a/tmux/uas/leader/supervisor.conf +++ b/tmux/uas/leader/supervisor.conf @@ -1,29 +1,29 @@ [program:core] -command=/bin/bash /home/user/kw/kamera/tmux/uas/leader/00_start_core.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/00_start_core.sh user=user environment=HOME="/home/user",USER="user" autostart=true [program:sensors] -command=/bin/bash /home/user/kw/kamera/tmux/uas/leader/01_start_sensors.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/01_start_sensors.sh user=user environment=HOME="/home/user",USER="user" autostart=true [program:processing] -command=/bin/bash /home/user/kw/kamera/tmux/uas/leader/02_start_processing.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/02_start_processing.sh user=user environment=HOME="/home/user",USER="user" autostart=true [program:timesync] -command=/bin/bash /home/user/kw/kamera/tmux/uas/leader/03_run_clock_sync.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/03_run_clock_sync.sh user=root environment=HOME="/home/user",USER="root" autostart=true [program:docker] -command=/bin/bash /home/user/kw/kamera/tmux/uas/leader/05_start_docker.sh +command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/05_start_docker.sh user=root environment=HOME="/home/user",USER="root" autostart=true From cd573ed96f8262cef6631dbc3386e29097d4bb0f Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Thu, 7 May 2026 14:51:38 -0400 Subject: [PATCH 018/139] Create global variables at the supervisord level, consolidating configuration --- src/cfg/nayak/supervisord.conf | 2 +- src/cfg/taiga/supervisord.conf | 2 +- src/cfg/uas/supervisord.conf | 2 +- tmux/nayak/follower/supervisor.conf | 13 ------------- tmux/nayak/leader/supervisor.conf | 19 ------------------- tmux/taiga/follower/supervisor.conf | 13 ------------- tmux/taiga/leader/supervisor.conf | 19 ------------------- tmux/uas/follower/supervisor.conf | 6 ------ tmux/uas/guibox/supervisor.conf | 1 - tmux/uas/leader/supervisor.conf | 5 ----- 10 files changed, 3 insertions(+), 79 deletions(-) diff --git a/src/cfg/nayak/supervisord.conf b/src/cfg/nayak/supervisord.conf index 5ecaa71..39ab6d8 100644 --- a/src/cfg/nayak/supervisord.conf +++ b/src/cfg/nayak/supervisord.conf @@ -12,7 +12,7 @@ port=0.0.0.0:9001 logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) -environment=KAMERA_DIR="/home/user/kw/kamera" +environment=HOME="/home/user",KAMERA_DIR="/home/user/kw/kamera" ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be diff --git a/src/cfg/taiga/supervisord.conf b/src/cfg/taiga/supervisord.conf index 5ecaa71..39ab6d8 100644 --- a/src/cfg/taiga/supervisord.conf +++ b/src/cfg/taiga/supervisord.conf @@ -12,7 +12,7 @@ port=0.0.0.0:9001 logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) -environment=KAMERA_DIR="/home/user/kw/kamera" +environment=HOME="/home/user",KAMERA_DIR="/home/user/kw/kamera" ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be diff --git a/src/cfg/uas/supervisord.conf b/src/cfg/uas/supervisord.conf index 2028122..913fe0b 100644 --- a/src/cfg/uas/supervisord.conf +++ b/src/cfg/uas/supervisord.conf @@ -12,7 +12,7 @@ port=0.0.0.0:9001 logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) -environment=KAMERA_DIR="/home/user/kw/kamera" +environment=HOME="/home/user",KAMERA_DIR="/home/user/kw/kamera" ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be diff --git a/tmux/nayak/follower/supervisor.conf b/tmux/nayak/follower/supervisor.conf index 539b71a..ebea601 100644 --- a/tmux/nayak/follower/supervisor.conf +++ b/tmux/nayak/follower/supervisor.conf @@ -1,81 +1,68 @@ [program:kamerad] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh kamerad user=user -environment=HOME="/home/user",USER="user" autostart=false [program:image_manager] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh image_manager user=user -environment=HOME="/home/user",USER="user" autostart=false [program:mount_nas] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/mount_nas.sh startsecs=0 user=root -environment=HOME="/home/user",USER="root" autostart=true [program:set_eth_speed_max] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/set_eth_speed_max.sh startsecs=0 user=root -environment=HOME="/home/user",USER="root" autostart=true [program:cam_ir] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh cam_ir user=user -environment=HOME="/home/user",USER="user" autostart=false [program:cam_uv] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh cam_uv user=user -environment=HOME="/home/user",USER="user" autostart=false [program:cam_rgb] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh cam_rgb user=user -environment=HOME="/home/user",USER="user" autostart=false [program:imageview] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh imageview user=user -environment=HOME="/home/user",USER="user" autostart=false [program:fps_monitor] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh fps_monitor user=user -environment=HOME="/home/user",USER="user" autostart=false [program:detector] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh detector user=user -environment=HOME="/home/user",USER="user" autostart=false [program:flight_summary] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh flight_summary user=user -environment=HOME="/home/user",USER="user" autostart=false [program:homography] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh homography user=user -environment=HOME="/home/user",USER="user" autostart=false [program:detections] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh detections user=user -environment=HOME="/home/user",USER="user" autostart=false [group:nayak] diff --git a/tmux/nayak/leader/supervisor.conf b/tmux/nayak/leader/supervisor.conf index 3d2b56f..7da34c0 100644 --- a/tmux/nayak/leader/supervisor.conf +++ b/tmux/nayak/leader/supervisor.conf @@ -1,118 +1,99 @@ [program:kamerad] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh kamerad user=user -environment=HOME="/home/user",USER="user" autostart=false [program:image_manager] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh image_manager user=user -environment=HOME="/home/user",USER="user" autostart=false [program:restart_redis] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/restart_redis.sh startsecs=0 user=root -environment=HOME="/home/user",USER="root" autostart=true [program:mount_nas] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/mount_nas.sh startsecs=0 user=root -environment=HOME="/home/user",USER="root" autostart=true [program:set_eth_speed_max] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/set_eth_speed_max.sh startsecs=0 user=root -environment=HOME="/home/user",USER="root" autostart=true [program:roscore] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh roscore user=user -environment=HOME="/home/user",USER="user" autostart=false [program:cam_param_monitor] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh cam_param_monitor user=user -environment=HOME="/home/user",USER="user" autostart=false [program:fps_monitor] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh fps_monitor user=user -environment=HOME="/home/user",USER="user" autostart=false [program:shapefile_monitor] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh shapefile_monitor user=user -environment=HOME="/home/user",USER="user" autostart=false [program:cam_ir] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh cam_ir user=user -environment=HOME="/home/user",USER="user" autostart=false [program:cam_uv] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh cam_uv user=user -environment=HOME="/home/user",USER="user" autostart=false [program:cam_rgb] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh cam_rgb user=user -environment=HOME="/home/user",USER="user" autostart=false [program:ins] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh ins user=user -environment=HOME="/home/user",USER="user" autostart=false [program:daq] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh daq user=user -environment=HOME="/home/user",USER="user" autostart=false [program:imageview] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh imageview user=user -environment=HOME="/home/user",USER="user" autostart=false [program:detector] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh detector user=user -environment=HOME="/home/user",USER="user" autostart=false [program:flight_summary] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh flight_summary user=user -environment=HOME="/home/user",USER="user" autostart=false [program:homography] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh homography user=user -environment=HOME="/home/user",USER="user" autostart=false [program:detections] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh detections user=user -environment=HOME="/home/user",USER="user" autostart=false [group:nayak] diff --git a/tmux/taiga/follower/supervisor.conf b/tmux/taiga/follower/supervisor.conf index 6e29146..9ce5067 100644 --- a/tmux/taiga/follower/supervisor.conf +++ b/tmux/taiga/follower/supervisor.conf @@ -1,81 +1,68 @@ [program:kamerad] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh kamerad user=user -environment=HOME="/home/user",USER="user" autostart=false [program:image_manager] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh image_manager user=user -environment=HOME="/home/user",USER="user" autostart=false [program:mount_nas] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/mount_nas.sh startsecs=0 user=root -environment=HOME="/home/user",USER="root" autostart=true [program:set_eth_speed_max] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/set_eth_speed_max.sh startsecs=0 user=root -environment=HOME="/home/user",USER="root" autostart=true [program:cam_ir] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh cam_ir user=user -environment=HOME="/home/user",USER="user" autostart=false [program:cam_uv] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh cam_uv user=user -environment=HOME="/home/user",USER="user" autostart=false [program:cam_rgb] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh cam_rgb user=user -environment=HOME="/home/user",USER="user" autostart=false [program:imageview] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh imageview user=user -environment=HOME="/home/user",USER="user" autostart=false [program:fps_monitor] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh fps_monitor user=user -environment=HOME="/home/user",USER="user" autostart=false [program:detector] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh detector user=user -environment=HOME="/home/user",USER="user" autostart=false [program:flight_summary] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh flight_summary user=user -environment=HOME="/home/user",USER="user" autostart=false [program:homography] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh homography user=user -environment=HOME="/home/user",USER="user" autostart=false [program:detections] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh detections user=user -environment=HOME="/home/user",USER="user" autostart=false [group:taiga] diff --git a/tmux/taiga/leader/supervisor.conf b/tmux/taiga/leader/supervisor.conf index 0f49c83..271c061 100644 --- a/tmux/taiga/leader/supervisor.conf +++ b/tmux/taiga/leader/supervisor.conf @@ -1,118 +1,99 @@ [program:kamerad] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh kamerad user=user -environment=HOME="/home/user",USER="user" autostart=false [program:image_manager] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh image_manager user=user -environment=HOME="/home/user",USER="user" autostart=false [program:restart_redis] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/restart_redis.sh startsecs=0 user=root -environment=HOME="/home/user",USER="root" autostart=true [program:mount_nas] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/mount_nas.sh startsecs=0 user=root -environment=HOME="/home/user",USER="root" autostart=true [program:set_eth_speed_max] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/set_eth_speed_max.sh startsecs=0 user=root -environment=HOME="/home/user",USER="root" autostart=true [program:roscore] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh roscore user=user -environment=HOME="/home/user",USER="user" autostart=false [program:cam_param_monitor] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh cam_param_monitor user=user -environment=HOME="/home/user",USER="user" autostart=false [program:fps_monitor] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh fps_monitor user=user -environment=HOME="/home/user",USER="user" autostart=false [program:shapefile_monitor] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh shapefile_monitor user=user -environment=HOME="/home/user",USER="user" autostart=false [program:cam_ir] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh cam_ir user=user -environment=HOME="/home/user",USER="user" autostart=false [program:cam_uv] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh cam_uv user=user -environment=HOME="/home/user",USER="user" autostart=false [program:cam_rgb] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh cam_rgb user=user -environment=HOME="/home/user",USER="user" autostart=false [program:ins] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh ins user=user -environment=HOME="/home/user",USER="user" autostart=false [program:daq] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh daq user=user -environment=HOME="/home/user",USER="user" autostart=false [program:imageview] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh imageview user=user -environment=HOME="/home/user",USER="user" autostart=false [program:detector] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh detector user=user -environment=HOME="/home/user",USER="user" autostart=false [program:flight_summary] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh flight_summary user=user -environment=HOME="/home/user",USER="user" autostart=false [program:homography] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh homography user=user -environment=HOME="/home/user",USER="user" autostart=false [program:detections] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh detections user=user -environment=HOME="/home/user",USER="user" autostart=false [group:taiga] diff --git a/tmux/uas/follower/supervisor.conf b/tmux/uas/follower/supervisor.conf index 745a013..8aa16a4 100644 --- a/tmux/uas/follower/supervisor.conf +++ b/tmux/uas/follower/supervisor.conf @@ -1,37 +1,31 @@ [program:core] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/00_start_core.sh user=user -environment=HOME="/home/user",USER="user" autostart=true [program:sensors] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/01_start_sensors.sh user=user -environment=HOME="/home/user",USER="user" autostart=true [program:processing] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/02_start_processing.sh user=user -environment=HOME="/home/user",USER="user" autostart=true [program:timesync] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/03_run_clock_sync.sh user=root -environment=HOME="/home/user",USER="root" autostart=true [program:camptp] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/04_run_cam_ptp.sh user=root -environment=HOME="/home/user",USER="root" autostart=true [program:docker] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/05_start_docker.sh user=root -environment=HOME="/home/user",USER="root" autostart=true [group:uas] diff --git a/tmux/uas/guibox/supervisor.conf b/tmux/uas/guibox/supervisor.conf index 0e3217d..7a1cad8 100644 --- a/tmux/uas/guibox/supervisor.conf +++ b/tmux/uas/guibox/supervisor.conf @@ -1,5 +1,4 @@ [program:flight_summary] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/guibox/00_flight_summary.sh user=root -environment=HOME="/home/user",USER="root" autostart=true diff --git a/tmux/uas/leader/supervisor.conf b/tmux/uas/leader/supervisor.conf index e34f471..13950fe 100644 --- a/tmux/uas/leader/supervisor.conf +++ b/tmux/uas/leader/supervisor.conf @@ -1,31 +1,26 @@ [program:core] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/00_start_core.sh user=user -environment=HOME="/home/user",USER="user" autostart=true [program:sensors] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/01_start_sensors.sh user=user -environment=HOME="/home/user",USER="user" autostart=true [program:processing] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/02_start_processing.sh user=user -environment=HOME="/home/user",USER="user" autostart=true [program:timesync] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/03_run_clock_sync.sh user=root -environment=HOME="/home/user",USER="root" autostart=true [program:docker] command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/05_start_docker.sh user=root -environment=HOME="/home/user",USER="root" autostart=true [group:uas] From 76a6cd93902733c72af5e6b61d64c5f457d19046 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Thu, 7 May 2026 14:52:29 -0400 Subject: [PATCH 019/139] Store image tags in a .env variable, less name duplication --- compose/.env | 5 +++++ compose/cam_ir.yml | 2 +- compose/cam_param_monitor.yml | 2 +- compose/cam_rgb.yml | 2 +- compose/cam_uv.yml | 2 +- compose/daq.yml | 2 +- compose/detections.yml | 2 +- compose/detector.yml | 2 +- compose/flight_summary.yml | 2 +- compose/fps_monitor.yml | 2 +- compose/gui.yml | 2 +- compose/homography.yml | 2 +- compose/image_manager.yml | 2 +- compose/imageview.yml | 2 +- compose/ins.yml | 2 +- compose/kamerad.yml | 2 +- compose/nodelist.yml | 2 +- compose/postproc.yml | 2 +- compose/roscore.yml | 2 +- compose/shapefile_monitor.yml | 2 +- compose/spoof_events.yml | 2 +- compose/sync_msg_publisher.yml | 2 +- 22 files changed, 26 insertions(+), 21 deletions(-) create mode 100644 compose/.env diff --git a/compose/.env b/compose/.env new file mode 100644 index 0000000..cc98b32 --- /dev/null +++ b/compose/.env @@ -0,0 +1,5 @@ +KAMERA_CORE_IMAGE=kitware/kamera:core +KAMERA_KAMERAD_IMAGE=kitware/kamera:kamerad +KAMERA_VIAME_IMAGE=kitware/kamera:viame +KAMERA_POSTPROC_IMAGE=kitware/kamera:postproc +KAMERA_GUI_IMAGE=kitware/kamera:gui diff --git a/compose/cam_ir.yml b/compose/cam_ir.yml index 83ce7f1..caed582 100644 --- a/compose/cam_ir.yml +++ b/compose/cam_ir.yml @@ -4,7 +4,7 @@ version: '3.7' services: cam_ir: container_name: "cam-ir-${CAM_FOV}" - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true environment: ROS_MASTER_URI: "${ROS_MASTER_URI}" diff --git a/compose/cam_param_monitor.yml b/compose/cam_param_monitor.yml index ddb60f5..e227336 100644 --- a/compose/cam_param_monitor.yml +++ b/compose/cam_param_monitor.yml @@ -4,7 +4,7 @@ version: '3.7' services: cam_param_monitor: container_name: cam_param_monitor - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true environment: ROS_MASTER_URI: "${ROS_MASTER_URI}" diff --git a/compose/cam_rgb.yml b/compose/cam_rgb.yml index 83f9a69..d0c8b74 100644 --- a/compose/cam_rgb.yml +++ b/compose/cam_rgb.yml @@ -5,7 +5,7 @@ services: ## =========================== headless nodes ============================= cam_rgb: container_name: "cam-rgb-${CAM_FOV}" - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true environment: ROS_MASTER_URI: "${ROS_MASTER_URI}" diff --git a/compose/cam_uv.yml b/compose/cam_uv.yml index 18732cc..799d892 100644 --- a/compose/cam_uv.yml +++ b/compose/cam_uv.yml @@ -5,7 +5,7 @@ services: ## =========================== headless nodes ============================= cam_uv: container_name: "cam-uv-${CAM_FOV}" - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true environment: ROS_MASTER_URI: "${ROS_MASTER_URI}" diff --git a/compose/daq.yml b/compose/daq.yml index 3dc3fee..92b95b2 100644 --- a/compose/daq.yml +++ b/compose/daq.yml @@ -4,7 +4,7 @@ version: '3.7' services: daq: container_name: daq - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true devices: - "${MCC_DAQ}:${MCC_DAQ}" diff --git a/compose/detections.yml b/compose/detections.yml index a8e1fb1..8d3ab1a 100644 --- a/compose/detections.yml +++ b/compose/detections.yml @@ -4,7 +4,7 @@ version: '3.7' services: ## =========================== headless nodes ============================= detections: - image: kitware/kamera:postproc + image: ${KAMERA_POSTPROC_IMAGE} network_mode: host environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/detector.yml b/compose/detector.yml index af61eab..7733d60 100644 --- a/compose/detector.yml +++ b/compose/detector.yml @@ -7,7 +7,7 @@ services: ## ========================== viame ============================= detector: container_name: "viame-${CAM_FOV}" - image: kitware/kamera:viame + image: ${KAMERA_VIAME_IMAGE} tty: true environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/flight_summary.yml b/compose/flight_summary.yml index d86d0ae..4952a1c 100644 --- a/compose/flight_summary.yml +++ b/compose/flight_summary.yml @@ -4,7 +4,7 @@ version: '3.7' services: ## =========================== headless nodes ============================= flight_summary: - image: kitware/kamera:postproc + image: ${KAMERA_POSTPROC_IMAGE} network_mode: host environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/fps_monitor.yml b/compose/fps_monitor.yml index 74e7aa3..beca892 100644 --- a/compose/fps_monitor.yml +++ b/compose/fps_monitor.yml @@ -4,7 +4,7 @@ version: '3.7' services: fps_monitor: container_name: fps_monitor - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true environment: ROS_MASTER_URI: "${ROS_MASTER_URI}" diff --git a/compose/gui.yml b/compose/gui.yml index 8f37ae6..72abb11 100644 --- a/compose/gui.yml +++ b/compose/gui.yml @@ -5,7 +5,7 @@ services: ## =========================== gui ============================= gui: container_name: gui - image: kitware/kamera:gui + image: ${KAMERA_GUI_IMAGE} tty: true environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/homography.yml b/compose/homography.yml index a10da6a..991ca33 100644 --- a/compose/homography.yml +++ b/compose/homography.yml @@ -4,7 +4,7 @@ version: '3.7' services: ## =========================== headless nodes ============================= homography: - image: kitware/kamera:postproc + image: ${KAMERA_POSTPROC_IMAGE} network_mode: host environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/image_manager.yml b/compose/image_manager.yml index 23b156f..2b7cede 100644 --- a/compose/image_manager.yml +++ b/compose/image_manager.yml @@ -5,7 +5,7 @@ services: ## =========================== headless nodes ============================= image_manager: container_name: "image_manager" - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/imageview.yml b/compose/imageview.yml index e4d5246..69230a6 100644 --- a/compose/imageview.yml +++ b/compose/imageview.yml @@ -3,7 +3,7 @@ version: '3.7' services: imageview: container_name: "imageview-${CAM_FOV}" - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/ins.yml b/compose/ins.yml index 5d01c04..89ddbcc 100644 --- a/compose/ins.yml +++ b/compose/ins.yml @@ -4,7 +4,7 @@ version: '3.7' services: ins: container_name: ins - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true devices: - "${PULSE_TTY}:${PULSE_TTY}" diff --git a/compose/kamerad.yml b/compose/kamerad.yml index 56cde0d..ddcd68d 100644 --- a/compose/kamerad.yml +++ b/compose/kamerad.yml @@ -4,7 +4,7 @@ version: '3.7' services: ## =========================== headless nodes ============================= kamerad: - image: kitware/kamera:kamerad + image: ${KAMERA_KAMERAD_IMAGE} network_mode: host build: ../src/core/kamerad tty: true diff --git a/compose/nodelist.yml b/compose/nodelist.yml index 36f71b4..79c3b74 100644 --- a/compose/nodelist.yml +++ b/compose/nodelist.yml @@ -4,7 +4,7 @@ services: ## =========================== headless nodes ============================= nodelist: container_name: nodelist - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true network_mode: host environment: diff --git a/compose/postproc.yml b/compose/postproc.yml index 9cfe2e7..e26d9d2 100644 --- a/compose/postproc.yml +++ b/compose/postproc.yml @@ -4,7 +4,7 @@ version: '3.7' services: ## =========================== headless nodes ============================= postproc: - image: kitware/kamera:postproc + image: ${KAMERA_POSTPROC_IMAGE} network_mode: host environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/roscore.yml b/compose/roscore.yml index b427a95..36fc934 100644 --- a/compose/roscore.yml +++ b/compose/roscore.yml @@ -5,7 +5,7 @@ services: ## =========================== headless nodes ============================= roscore: container_name: roscore - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true network_mode: host environment: diff --git a/compose/shapefile_monitor.yml b/compose/shapefile_monitor.yml index 2814580..ddfdd2e 100644 --- a/compose/shapefile_monitor.yml +++ b/compose/shapefile_monitor.yml @@ -4,7 +4,7 @@ version: '3.7' services: shapefile_monitor: container_name: shapefile_monitor - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/spoof_events.yml b/compose/spoof_events.yml index 831d424..c7c3e33 100644 --- a/compose/spoof_events.yml +++ b/compose/spoof_events.yml @@ -4,7 +4,7 @@ version: '3.7' services: spoof_events: container_name: spoof_events - image: kitware/kamera:core + image: ${KAMERA_CORE_IMAGE} tty: true devices: - "${PULSE_TTY}:${PULSE_TTY}" diff --git a/compose/sync_msg_publisher.yml b/compose/sync_msg_publisher.yml index 4f6124a..b83a813 100644 --- a/compose/sync_msg_publisher.yml +++ b/compose/sync_msg_publisher.yml @@ -4,7 +4,7 @@ version: "3.7" services: sync-publisher: container_name: "sync-publisher-${CAM_FOV}" - image: kitware/kamera:viame + image: ${KAMERA_VIAME_IMAGE} tty: true environment: ROS_MASTER_URI: "${ROS_MASTER_URI}" From b2f020da52705763f96226b5f49d671a908a4b10 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Thu, 7 May 2026 14:52:56 -0400 Subject: [PATCH 020/139] Eliminate the tmuxinator dependency, just call tmux directly. --- provision/ansible/playbooks/cas/configure.yml | 38 ++++++++--------- tmux/nayak/env.sh | 19 +++++---- tmux/nayak/follower/config/generic.yml | 35 ---------------- tmux/nayak/follower/start_tmux_session.sh | 24 ++++++----- tmux/nayak/leader/config/generic.yml | 34 --------------- tmux/nayak/leader/start_tmux_session.sh | 24 ++++++----- tmux/nayak/startup.sh | 1 - tmux/taiga/env.sh | 19 +++++---- tmux/taiga/follower/config/generic.yml | 35 ---------------- tmux/taiga/follower/start_tmux_session.sh | 24 ++++++----- tmux/taiga/leader/config/generic.yml | 34 --------------- tmux/taiga/leader/start_tmux_session.sh | 24 ++++++----- tmux/taiga/startup.sh | 1 - tmux/uas/env.sh | 19 +++++---- tmux/uas/follower/00_start_core.sh | 17 ++++---- tmux/uas/follower/01_start_sensors.sh | 19 +++++---- tmux/uas/follower/02_start_processing.sh | 21 ++++++---- tmux/uas/follower/config/core.yml | 36 ---------------- tmux/uas/follower/config/processing.yml | 38 ----------------- tmux/uas/follower/config/sensors.yml | 37 ----------------- tmux/uas/leader/00_start_core.sh | 27 ++++++++---- tmux/uas/leader/01_start_sensors.sh | 21 ++++++---- tmux/uas/leader/02_start_processing.sh | 23 +++++++---- tmux/uas/leader/config/core.yml | 41 ------------------- tmux/uas/leader/config/processing.yml | 39 ------------------ tmux/uas/leader/config/sensors.yml | 38 ----------------- tmux/uas/startup.sh | 1 - 27 files changed, 187 insertions(+), 502 deletions(-) delete mode 100644 tmux/nayak/follower/config/generic.yml delete mode 100644 tmux/nayak/leader/config/generic.yml delete mode 100644 tmux/taiga/follower/config/generic.yml delete mode 100644 tmux/taiga/leader/config/generic.yml delete mode 100644 tmux/uas/follower/config/core.yml delete mode 100644 tmux/uas/follower/config/processing.yml delete mode 100644 tmux/uas/follower/config/sensors.yml delete mode 100644 tmux/uas/leader/config/core.yml delete mode 100644 tmux/uas/leader/config/processing.yml delete mode 100644 tmux/uas/leader/config/sensors.yml diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index cb0995b..cba3785 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -5,15 +5,15 @@ - name: Crewed system tasks block: - - name: Clone kamera repo - git: - repo: "git@github.com:Kitware/kamera.git" - dest: "{{ kamera_dir }}" - version: main - recursive: True - accept_hostkey: True - update: True - force: True + # - name: Clone kamera repo + # git: + # repo: "git@github.com:Kitware/kamera.git" + # dest: "{{ kamera_dir }}" + # version: main + # recursive: True + # accept_hostkey: True + # update: True + # force: True - name: "Set redis configuration to {{ kamera_dir }}/src/cfg/redis.conf" become: True @@ -100,13 +100,13 @@ dest: /etc/netplan/{{ inventory_hostname }}-netplan.yaml owner: root - - name: Add mappings to /etc/hosts - become: True - copy: - src: "{{ kamera_dir }}/src/cfg/{{ config_dir }}/{{ inventory_hostname }}/hosts" - remote_src: true - dest: /etc/hosts - owner: root + # - name: Add mappings to /etc/hosts + # become: True + # copy: + # src: "{{ kamera_dir }}/src/cfg/{{ config_dir }}/{{ inventory_hostname }}/hosts" + # remote_src: true + # dest: /etc/hosts + # owner: root # Overwrite default, this is for our 10G cameras - name: Add sysctl rmem params. @@ -196,12 +196,6 @@ when: follower or leader or gui shell: sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target - - name: Create ~/.tmuxinator if it does not exist - file: - path: ~/.tmuxinator - state: directory - mode: '0755' - - name: Create udev rule for mcc_daq become: True when: leader diff --git a/tmux/nayak/env.sh b/tmux/nayak/env.sh index 3c78721..0a5ab02 100644 --- a/tmux/nayak/env.sh +++ b/tmux/nayak/env.sh @@ -15,16 +15,19 @@ export REDIS_HOST=$(cq ".redis_host") # (without nuvo0, 1, etc. hooked up) # export REDIS_HOST="localhost" -RESP=$(redis-cli -h ${REDIS_HOST} ping) -while [ "$RESP" != "PONG" ] -do - echo "Got '$RESP', wanted 'PONG'." - echo "Waiting for redis host $REDIS_HOST to come online..." - RESP=$(redis-cli -h ${REDIS_HOST} ping) - sleep 1; +_redis_elapsed=0 +RESP=$(redis-cli -h "${REDIS_HOST}" ping 2>/dev/null) +while [ "$RESP" != "PONG" ]; do + if [ $((_redis_elapsed % 30)) -eq 0 ]; then + echo "Waiting for Redis at ${REDIS_HOST} (${_redis_elapsed}s elapsed, got '${RESP}')..." + fi + sleep 1 + _redis_elapsed=$((_redis_elapsed + 1)) + RESP=$(redis-cli -h "${REDIS_HOST}" ping 2>/dev/null) done +unset _redis_elapsed -echo "Redis successfully connected at $REDIS_HOST, starting." +echo "Redis successfully connected at ${REDIS_HOST}, starting." export ROS_MASTER="$(cq .master_host)" export NODE_HOSTNAME=$(hostname) diff --git a/tmux/nayak/follower/config/generic.yml b/tmux/nayak/follower/config/generic.yml deleted file mode 100644 index 0382f47..0000000 --- a/tmux/nayak/follower/config/generic.yml +++ /dev/null @@ -1,35 +0,0 @@ -# tmuxinator configuration file -name: <%= ENV["SESSION"] %> -root: <%= ENV["KAMERA_DIR"] %> - -# Optional tmux socket -# socket_name: foo - -# Runs before everything. Use it to start daemons etc. -on_project_start: . <%= ENV["KAMERA_DIR"] %>/tmux/nayak/startup.sh - -# Runs in each window and pane before window/pane specific commands. Useful for setting up interpreter versions. -pre_window: source <%= ENV["KAMERA_DIR"] %>/tmux/nayak/env.sh - -# Pass command line options to tmux. Useful for specifying a different tmux.conf. -# tmux_options: -f ~/.tmux.mac.conf - -# Change the command to call tmux. This can be used by derivatives/wrappers like byobu. -# tmux_command: byobu - -# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used. -# startup_window: editor - -# Specitifes (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used. -# startup_pane: 1 - -# Controls whether the tmux session should be attached to automatically. Defaults to true. -attach: false - -# Runs after everything. Use it to attach to tmux with custom options etc. -# post: tmux -CC attach -t docker - -on_project_stop: echo "Stopping tmux" && docker compose -f compose/<%= ENV["SESSION"] %>.yml down - -windows: - - <%= ENV["SESSION"] %>: docker compose -f compose/<%= ENV["SESSION"] %>.yml up <%= ENV["SESSION"] %> diff --git a/tmux/nayak/follower/start_tmux_session.sh b/tmux/nayak/follower/start_tmux_session.sh index 8eea80c..9b20c26 100755 --- a/tmux/nayak/follower/start_tmux_session.sh +++ b/tmux/nayak/follower/start_tmux_session.sh @@ -1,22 +1,24 @@ #!/bin/bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -if [ $# != 1 ] -then - echo "Must enter session name." - exit 1 +if [ $# != 1 ]; then + echo "Must enter session name." >&2 + exit 1 fi export SESSION="$1" -# Kills running containers and processes -trap "{ echo Stopping session ${SESSION}; tmuxinator stop ${SESSION}; exit 0; }" EXIT +cleanup() { + echo "Stopping session ${SESSION}" + docker compose -f "${KAMERA_DIR}/compose/${SESSION}.yml" down + tmux kill-session -t "${SESSION}" 2>/dev/null +} +trap cleanup EXIT -source $DIR/../env.sh +. "${DIR}/../startup.sh" +source "${DIR}/../env.sh" echo "Starting session '${SESSION}'." -ln -sf $DIR/config/generic.yml ~/.tmuxinator/${SESSION}.yml +tmux new-session -d -s "${SESSION}" -c "${KAMERA_DIR}" \ + "docker compose -f compose/${SESSION}.yml up ${SESSION}" -tmuxinator start -n ${SESSION} -p ~/.tmuxinator/${SESSION}.yml - -# Keep process alive for supervisor sleep infinity diff --git a/tmux/nayak/leader/config/generic.yml b/tmux/nayak/leader/config/generic.yml deleted file mode 100644 index e141067..0000000 --- a/tmux/nayak/leader/config/generic.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: <%= ENV["SESSION"] %> -root: <%= ENV["KAMERA_DIR"] %> - -# Optional tmux socket -# socket_name: foo - -# Runs before everything. Use it to start daemons etc. -on_project_start: . <%= ENV["KAMERA_DIR"] %>/tmux/nayak/startup.sh - -# Runs in each window and pane before window/pane specific commands. Useful for setting up interpreter versions. -pre_window: source <%= ENV["KAMERA_DIR"] %>/tmux/nayak/env.sh - -# Pass command line options to tmux. Useful for specifying a different tmux.conf. -# tmux_options: -f ~/.tmux.mac.conf - -# Change the command to call tmux. This can be used by derivatives/wrappers like byobu. -# tmux_command: byobu - -# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used. -# startup_window: editor - -# Specitifes (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used. -# startup_pane: 1 - -# Controls whether the tmux session should be attached to automatically. Defaults to true. -attach: false - -# Runs after everything. Use it to attach to tmux with custom options etc. -# post: tmux -CC attach -t docker - -on_project_stop: echo "Stopping tmux" && docker compose -f compose/<%= ENV["SESSION"] %>.yml down - -windows: - - <%= ENV["SESSION"] %>: docker compose -f compose/<%= ENV["SESSION"] %>.yml up <%= ENV["SESSION"] %> diff --git a/tmux/nayak/leader/start_tmux_session.sh b/tmux/nayak/leader/start_tmux_session.sh index 8eea80c..9b20c26 100755 --- a/tmux/nayak/leader/start_tmux_session.sh +++ b/tmux/nayak/leader/start_tmux_session.sh @@ -1,22 +1,24 @@ #!/bin/bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -if [ $# != 1 ] -then - echo "Must enter session name." - exit 1 +if [ $# != 1 ]; then + echo "Must enter session name." >&2 + exit 1 fi export SESSION="$1" -# Kills running containers and processes -trap "{ echo Stopping session ${SESSION}; tmuxinator stop ${SESSION}; exit 0; }" EXIT +cleanup() { + echo "Stopping session ${SESSION}" + docker compose -f "${KAMERA_DIR}/compose/${SESSION}.yml" down + tmux kill-session -t "${SESSION}" 2>/dev/null +} +trap cleanup EXIT -source $DIR/../env.sh +. "${DIR}/../startup.sh" +source "${DIR}/../env.sh" echo "Starting session '${SESSION}'." -ln -sf $DIR/config/generic.yml ~/.tmuxinator/${SESSION}.yml +tmux new-session -d -s "${SESSION}" -c "${KAMERA_DIR}" \ + "docker compose -f compose/${SESSION}.yml up ${SESSION}" -tmuxinator start -n ${SESSION} -p ~/.tmuxinator/${SESSION}.yml - -# Keep process alive for supervisor sleep infinity diff --git a/tmux/nayak/startup.sh b/tmux/nayak/startup.sh index 10cbb25..66b9d9b 100755 --- a/tmux/nayak/startup.sh +++ b/tmux/nayak/startup.sh @@ -4,5 +4,4 @@ # . /opt/ros/noetic/setup.sh # rosclean purge -y -mkdir -p ~/.tmuxinator mkdir -p ~/.config/kamera/gui diff --git a/tmux/taiga/env.sh b/tmux/taiga/env.sh index eafb76b..77f2a6f 100644 --- a/tmux/taiga/env.sh +++ b/tmux/taiga/env.sh @@ -14,16 +14,19 @@ export REDIS_HOST=$(cq ".redis_host") # (without nuvo0, 1, etc. hooked up) # export REDIS_HOST="localhost" -RESP=$(redis-cli -h ${REDIS_HOST} ping) -while [ "$RESP" != "PONG" ] -do - echo "Got '$RESP', wanted 'PONG'." - echo "Waiting for redis host $REDIS_HOST to come online..." - RESP=$(redis-cli -h ${REDIS_HOST} ping) - sleep 1; +_redis_elapsed=0 +RESP=$(redis-cli -h "${REDIS_HOST}" ping 2>/dev/null) +while [ "$RESP" != "PONG" ]; do + if [ $((_redis_elapsed % 30)) -eq 0 ]; then + echo "Waiting for Redis at ${REDIS_HOST} (${_redis_elapsed}s elapsed, got '${RESP}')..." + fi + sleep 1 + _redis_elapsed=$((_redis_elapsed + 1)) + RESP=$(redis-cli -h "${REDIS_HOST}" ping 2>/dev/null) done +unset _redis_elapsed -echo "Redis successfully connected at $REDIS_HOST, starting." +echo "Redis successfully connected at ${REDIS_HOST}, starting." export ROS_HOSTNAME=$(cq ".master_host") export NODE_HOSTNAME=$(hostname) diff --git a/tmux/taiga/follower/config/generic.yml b/tmux/taiga/follower/config/generic.yml deleted file mode 100644 index 8286e3e..0000000 --- a/tmux/taiga/follower/config/generic.yml +++ /dev/null @@ -1,35 +0,0 @@ -# tmuxinator configuration file -name: <%= ENV["SESSION"] %> -root: <%= ENV["KAMERA_DIR"] %> - -# Optional tmux socket -# socket_name: foo - -# Runs before everything. Use it to start daemons etc. -on_project_start: . <%= ENV["KAMERA_DIR"] %>/tmux/taiga/startup.sh - -# Runs in each window and pane before window/pane specific commands. Useful for setting up interpreter versions. -pre_window: source <%= ENV["KAMERA_DIR"] %>/tmux/taiga/env.sh - -# Pass command line options to tmux. Useful for specifying a different tmux.conf. -# tmux_options: -f ~/.tmux.mac.conf - -# Change the command to call tmux. This can be used by derivatives/wrappers like byobu. -# tmux_command: byobu - -# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used. -# startup_window: editor - -# Specitifes (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used. -# startup_pane: 1 - -# Controls whether the tmux session should be attached to automatically. Defaults to true. -attach: false - -# Runs after everything. Use it to attach to tmux with custom options etc. -# post: tmux -CC attach -t docker - -on_project_stop: echo "Stopping tmux" && docker compose -f compose/<%= ENV["SESSION"] %>.yml down - -windows: - - <%= ENV["SESSION"] %>: docker compose -f compose/<%= ENV["SESSION"] %>.yml up <%= ENV["SESSION"] %> diff --git a/tmux/taiga/follower/start_tmux_session.sh b/tmux/taiga/follower/start_tmux_session.sh index 8eea80c..9b20c26 100755 --- a/tmux/taiga/follower/start_tmux_session.sh +++ b/tmux/taiga/follower/start_tmux_session.sh @@ -1,22 +1,24 @@ #!/bin/bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -if [ $# != 1 ] -then - echo "Must enter session name." - exit 1 +if [ $# != 1 ]; then + echo "Must enter session name." >&2 + exit 1 fi export SESSION="$1" -# Kills running containers and processes -trap "{ echo Stopping session ${SESSION}; tmuxinator stop ${SESSION}; exit 0; }" EXIT +cleanup() { + echo "Stopping session ${SESSION}" + docker compose -f "${KAMERA_DIR}/compose/${SESSION}.yml" down + tmux kill-session -t "${SESSION}" 2>/dev/null +} +trap cleanup EXIT -source $DIR/../env.sh +. "${DIR}/../startup.sh" +source "${DIR}/../env.sh" echo "Starting session '${SESSION}'." -ln -sf $DIR/config/generic.yml ~/.tmuxinator/${SESSION}.yml +tmux new-session -d -s "${SESSION}" -c "${KAMERA_DIR}" \ + "docker compose -f compose/${SESSION}.yml up ${SESSION}" -tmuxinator start -n ${SESSION} -p ~/.tmuxinator/${SESSION}.yml - -# Keep process alive for supervisor sleep infinity diff --git a/tmux/taiga/leader/config/generic.yml b/tmux/taiga/leader/config/generic.yml deleted file mode 100644 index 7f8f86d..0000000 --- a/tmux/taiga/leader/config/generic.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: <%= ENV["SESSION"] %> -root: <%= ENV["KAMERA_DIR"] %> - -# Optional tmux socket -# socket_name: foo - -# Runs before everything. Use it to start daemons etc. -on_project_start: . <%= ENV["KAMERA_DIR"] %>/tmux/taiga/startup.sh - -# Runs in each window and pane before window/pane specific commands. Useful for setting up interpreter versions. -pre_window: source <%= ENV["KAMERA_DIR"] %>/tmux/taiga/env.sh - -# Pass command line options to tmux. Useful for specifying a different tmux.conf. -# tmux_options: -f ~/.tmux.mac.conf - -# Change the command to call tmux. This can be used by derivatives/wrappers like byobu. -# tmux_command: byobu - -# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used. -# startup_window: editor - -# Specitifes (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used. -# startup_pane: 1 - -# Controls whether the tmux session should be attached to automatically. Defaults to true. -attach: false - -# Runs after everything. Use it to attach to tmux with custom options etc. -# post: tmux -CC attach -t docker - -on_project_stop: echo "Stopping tmux" && docker compose -f compose/<%= ENV["SESSION"] %>.yml down - -windows: - - <%= ENV["SESSION"] %>: docker compose -f compose/<%= ENV["SESSION"] %>.yml up <%= ENV["SESSION"] %> diff --git a/tmux/taiga/leader/start_tmux_session.sh b/tmux/taiga/leader/start_tmux_session.sh index 8eea80c..9b20c26 100755 --- a/tmux/taiga/leader/start_tmux_session.sh +++ b/tmux/taiga/leader/start_tmux_session.sh @@ -1,22 +1,24 @@ #!/bin/bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -if [ $# != 1 ] -then - echo "Must enter session name." - exit 1 +if [ $# != 1 ]; then + echo "Must enter session name." >&2 + exit 1 fi export SESSION="$1" -# Kills running containers and processes -trap "{ echo Stopping session ${SESSION}; tmuxinator stop ${SESSION}; exit 0; }" EXIT +cleanup() { + echo "Stopping session ${SESSION}" + docker compose -f "${KAMERA_DIR}/compose/${SESSION}.yml" down + tmux kill-session -t "${SESSION}" 2>/dev/null +} +trap cleanup EXIT -source $DIR/../env.sh +. "${DIR}/../startup.sh" +source "${DIR}/../env.sh" echo "Starting session '${SESSION}'." -ln -sf $DIR/config/generic.yml ~/.tmuxinator/${SESSION}.yml +tmux new-session -d -s "${SESSION}" -c "${KAMERA_DIR}" \ + "docker compose -f compose/${SESSION}.yml up ${SESSION}" -tmuxinator start -n ${SESSION} -p ~/.tmuxinator/${SESSION}.yml - -# Keep process alive for supervisor sleep infinity diff --git a/tmux/taiga/startup.sh b/tmux/taiga/startup.sh index e029c97..de83212 100644 --- a/tmux/taiga/startup.sh +++ b/tmux/taiga/startup.sh @@ -4,5 +4,4 @@ . /opt/ros/noetic/setup.sh rosclean purge -y -mkdir -p ~/.tmuxinator mkdir -p ~/.config/kamera/gui diff --git a/tmux/uas/env.sh b/tmux/uas/env.sh index 49e8e04..cfbf7a6 100644 --- a/tmux/uas/env.sh +++ b/tmux/uas/env.sh @@ -6,16 +6,19 @@ export REDIS_HOST="uas0" # (without uas0, 1, etc. hooked up) # export REDIS_HOST="localhost" -RESP=$(redis-cli -h ${REDIS_HOST} ping) -while [ "$RESP" != "PONG" ] -do - echo "Got '$RESP', wanted 'PONG'." - echo "Waiting for redis host $REDIS_HOST to come online..." - RESP=$(redis-cli -h ${REDIS_HOST} ping) - sleep 1; +_redis_elapsed=0 +RESP=$(redis-cli -h "${REDIS_HOST}" ping 2>/dev/null) +while [ "$RESP" != "PONG" ]; do + if [ $((_redis_elapsed % 30)) -eq 0 ]; then + echo "Waiting for Redis at ${REDIS_HOST} (${_redis_elapsed}s elapsed, got '${RESP}')..." + fi + sleep 1 + _redis_elapsed=$((_redis_elapsed + 1)) + RESP=$(redis-cli -h "${REDIS_HOST}" ping 2>/dev/null) done +unset _redis_elapsed -echo "Redis successfully connected at $REDIS_HOST, starting." +echo "Redis successfully connected at ${REDIS_HOST}, starting." export NODE_HOSTNAME=$(hostname) export ROS_MASTER_URI="http://${REDIS_HOST}:11311" diff --git a/tmux/uas/follower/00_start_core.sh b/tmux/uas/follower/00_start_core.sh index 0df1a75..eeed19f 100755 --- a/tmux/uas/follower/00_start_core.sh +++ b/tmux/uas/follower/00_start_core.sh @@ -2,15 +2,18 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -# Kills running containers and processes -trap "{ echo Stopping session 'core'.; tmuxinator stop core; exit 0; }" EXIT +cleanup() { + echo "Stopping session 'core'." + docker-compose -f "${KAMERA_DIR}/compose/core.yml" down + tmux kill-session -t core 2>/dev/null +} +trap cleanup EXIT -source $DIR/../env.sh +. "${DIR}/../startup.sh" +source "${DIR}/../env.sh" echo "Start session 'core'." -ln -sf $DIR/config/core.yml ~/.tmuxinator/core.yml +tmux new-session -d -s core -n webvideo -c "${KAMERA_DIR}" \ + "docker-compose -f compose/core.yml up webvideo" -tmuxinator start -p $DIR/config/core.yml - -# Keep process alive for supervisor sleep infinity diff --git a/tmux/uas/follower/01_start_sensors.sh b/tmux/uas/follower/01_start_sensors.sh index 37d30f2..03d74d4 100755 --- a/tmux/uas/follower/01_start_sensors.sh +++ b/tmux/uas/follower/01_start_sensors.sh @@ -2,15 +2,20 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -# Kills running containers and processes -trap "{ echo Stopping session 'sensors'; tmuxinator stop sensors; exit 0; }" EXIT +cleanup() { + echo "Stopping session 'sensors'." + docker-compose -f "${KAMERA_DIR}/compose/sensors.yml" down + tmux kill-session -t sensors 2>/dev/null +} +trap cleanup EXIT -source $DIR/../env.sh +. "${DIR}/../startup.sh" +source "${DIR}/../env.sh" echo "Starting session 'sensors'." -ln -sf $DIR/config/sensors.yml ~/.tmuxinator/sensors.yml +tmux new-session -d -s sensors -n rgb_cam -c "${KAMERA_DIR}" \ + "docker-compose -f compose/sensors.yml up cam_rgb" +tmux new-window -t sensors: -n ir_cam -c "${KAMERA_DIR}" \ + "docker-compose -f compose/sensors.yml up cam_ir" -tmuxinator start -n sensors -p $DIR/config/sensors.yml - -# Keep process alive for supervisor sleep infinity diff --git a/tmux/uas/follower/02_start_processing.sh b/tmux/uas/follower/02_start_processing.sh index 63f8887..080d062 100755 --- a/tmux/uas/follower/02_start_processing.sh +++ b/tmux/uas/follower/02_start_processing.sh @@ -2,15 +2,22 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -# Kills running containers and processes -trap "{ echo Stopping session 'processing'; tmuxinator stop processing; exit 0; }" EXIT +cleanup() { + echo "Stopping session 'processing'." + docker-compose -f "${KAMERA_DIR}/compose/processing.yml" down + tmux kill-session -t processing 2>/dev/null +} +trap cleanup EXIT -source $DIR/../env.sh +. "${DIR}/../startup.sh" +source "${DIR}/../env.sh" echo "Starting session 'processing'." -ln -sf $DIR/config/processing.yml ~/.tmuxinator/processing.yml +tmux new-session -d -s processing -n viewport_rgb -c "${KAMERA_DIR}" \ + "docker-compose -f compose/processing.yml up viewport_rgb" +tmux new-window -t processing: -n viewport_ir -c "${KAMERA_DIR}" \ + "docker-compose -f compose/processing.yml up viewport_ir" +tmux new-window -t processing: -n nexus -c "${KAMERA_DIR}" \ + "docker-compose -f compose/processing.yml up nexus" -tmuxinator start -n processing -p $DIR/config/processing.yml - -# Keep process alive for supervisor sleep infinity diff --git a/tmux/uas/follower/config/core.yml b/tmux/uas/follower/config/core.yml deleted file mode 100644 index 9ebd770..0000000 --- a/tmux/uas/follower/config/core.yml +++ /dev/null @@ -1,36 +0,0 @@ -# ~/.tmuxinator/docker.yml - -name: core -root: <%= ENV["KAMERA_DIR"] %> - -# Optional tmux socket -# socket_name: foo - -# Runs before everything. Use it to start daemons etc. -on_project_start: . <%= ENV["KAMERA_DIR"] %>/tmux/uas/startup.sh - -# Runs in each window and pane before window/pane specific commands. Useful for setting up interpreter versions. -pre_window: source <%= ENV["KAMERA_DIR"] %>/tmux/uas/env.sh - -# Pass command line options to tmux. Useful for specifying a different tmux.conf. -# tmux_options: -f ~/.tmux.mac.conf - -# Change the command to call tmux. This can be used by derivatives/wrappers like byobu. -# tmux_command: byobu - -# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used. -# startup_window: editor - -# Specitifes (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used. -# startup_pane: 1 - -# Controls whether the tmux session should be attached to automatically. Defaults to true. -attach: false - -# Runs after everything. Use it to attach to tmux with custom options etc. -# post: tmux -CC attach -t docker - -on_project_stop: echo "Stopping tmux" && docker-compose -f compose/core.yml down - -windows: - - webvideo: docker-compose -f compose/core.yml up webvideo diff --git a/tmux/uas/follower/config/processing.yml b/tmux/uas/follower/config/processing.yml deleted file mode 100644 index 22718a4..0000000 --- a/tmux/uas/follower/config/processing.yml +++ /dev/null @@ -1,38 +0,0 @@ -# ~/.tmuxinator/docker.yml - -name: processing -root: <%= ENV["KAMERA_DIR"] %> - -# Optional tmux socket -# socket_name: foo - -# Runs before everything. Use it to start daemons etc. -on_project_start: . <%= ENV["KAMERA_DIR"] %>/tmux/uas/startup.sh - -# Runs in each window and pane before window/pane specific commands. Useful for setting up interpreter versions. -pre_window: source <%= ENV["KAMERA_DIR"] %>/tmux/uas/env.sh - -# Pass command line options to tmux. Useful for specifying a different tmux.conf. -# tmux_options: -f ~/.tmux.mac.conf - -# Change the command to call tmux. This can be used by derivatives/wrappers like byobu. -# tmux_command: byobu - -# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used. -# startup_window: editor - -# Specitifes (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used. -# startup_pane: 1 - -# Controls whether the tmux session should be attached to automatically. Defaults to true. -attach: false - -# Runs after everything. Use it to attach to tmux with custom options etc. -# post: tmux -CC attach -t docker - -on_project_stop: echo "Stopping tmux" && docker-compose -f compose/processing.yml down - -windows: - - viewport_rgb: docker-compose -f compose/processing.yml up viewport_rgb - - viewport_ir: docker-compose -f compose/processing.yml up viewport_ir - - nexus: docker-compose -f compose/processing.yml up nexus diff --git a/tmux/uas/follower/config/sensors.yml b/tmux/uas/follower/config/sensors.yml deleted file mode 100644 index 03bc085..0000000 --- a/tmux/uas/follower/config/sensors.yml +++ /dev/null @@ -1,37 +0,0 @@ -# ~/.tmuxinator/docker.yml - -name: sensors -root: <%= ENV["KAMERA_DIR"] %> - -# Optional tmux socket -# socket_name: foo - -# Runs before everything. Use it to start daemons etc. -on_project_start: . <%= ENV["KAMERA_DIR"] %>/tmux/uas/startup.sh - -# Runs in each window and pane before window/pane specific commands. Useful for setting up interpreter versions. -pre_window: source <%= ENV["KAMERA_DIR"] %>/tmux/uas/env.sh - -# Pass command line options to tmux. Useful for specifying a different tmux.conf. -# tmux_options: -f ~/.tmux.mac.conf - -# Change the command to call tmux. This can be used by derivatives/wrappers like byobu. -# tmux_command: byobu - -# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used. -# startup_window: editor - -# Specitifes (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used. -# startup_pane: 1 - -# Controls whether the tmux session should be attached to automatically. Defaults to true. -attach: false - -# Runs after everything. Use it to attach to tmux with custom options etc. -# post: tmux -CC attach -t docker - -on_project_stop: echo "Stopping tmux" && docker-compose -f compose/sensors.yml down - -windows: - - rgb_cam: docker-compose -f compose/sensors.yml up cam_rgb - - ir_cam: docker-compose -f compose/sensors.yml up cam_ir diff --git a/tmux/uas/leader/00_start_core.sh b/tmux/uas/leader/00_start_core.sh index 0df1a75..c7e44b7 100755 --- a/tmux/uas/leader/00_start_core.sh +++ b/tmux/uas/leader/00_start_core.sh @@ -2,15 +2,28 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -# Kills running containers and processes -trap "{ echo Stopping session 'core'.; tmuxinator stop core; exit 0; }" EXIT +cleanup() { + echo "Stopping session 'core'." + docker-compose -f "${KAMERA_DIR}/compose/core.yml" down + tmux kill-session -t core 2>/dev/null +} +trap cleanup EXIT -source $DIR/../env.sh +. "${DIR}/../startup.sh" +source "${DIR}/../env.sh" echo "Start session 'core'." -ln -sf $DIR/config/core.yml ~/.tmuxinator/core.yml +tmux new-session -d -s core -n core -c "${KAMERA_DIR}" \ + "docker-compose -f compose/core.yml up roscore" +tmux new-window -t core: -n webvideo -c "${KAMERA_DIR}" \ + "docker-compose -f compose/core.yml up webvideo" +tmux new-window -t core: -n influxdb -c "${KAMERA_DIR}" \ + "docker-compose -f compose/core.yml up influxdb" +tmux new-window -t core: -n diagnostics -c "${KAMERA_DIR}" \ + "docker-compose -f compose/core.yml up diagnostics2influxdb" +tmux new-window -t core: -n diagnostic_aggregator -c "${KAMERA_DIR}" \ + "docker-compose -f compose/core.yml up diagnostic_aggregator" +tmux new-window -t core: -n cam_param_monitor -c "${KAMERA_DIR}" \ + "docker-compose -f compose/core.yml up cam_param_monitor" -tmuxinator start -p $DIR/config/core.yml - -# Keep process alive for supervisor sleep infinity diff --git a/tmux/uas/leader/01_start_sensors.sh b/tmux/uas/leader/01_start_sensors.sh index 37d30f2..e563874 100755 --- a/tmux/uas/leader/01_start_sensors.sh +++ b/tmux/uas/leader/01_start_sensors.sh @@ -2,15 +2,22 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -# Kills running containers and processes -trap "{ echo Stopping session 'sensors'; tmuxinator stop sensors; exit 0; }" EXIT +cleanup() { + echo "Stopping session 'sensors'." + docker-compose -f "${KAMERA_DIR}/compose/sensors.yml" down + tmux kill-session -t sensors 2>/dev/null +} +trap cleanup EXIT -source $DIR/../env.sh +. "${DIR}/../startup.sh" +source "${DIR}/../env.sh" echo "Starting session 'sensors'." -ln -sf $DIR/config/sensors.yml ~/.tmuxinator/sensors.yml +tmux new-session -d -s sensors -n rgb_cam -c "${KAMERA_DIR}" \ + "docker-compose -f compose/sensors.yml up cam_rgb" +tmux new-window -t sensors: -n ir_cam -c "${KAMERA_DIR}" \ + "docker-compose -f compose/sensors.yml up cam_ir" +tmux new-window -t sensors: -n ins -c "${KAMERA_DIR}" \ + "docker-compose -f compose/sensors.yml up ins" -tmuxinator start -n sensors -p $DIR/config/sensors.yml - -# Keep process alive for supervisor sleep infinity diff --git a/tmux/uas/leader/02_start_processing.sh b/tmux/uas/leader/02_start_processing.sh index 63f8887..7c79664 100755 --- a/tmux/uas/leader/02_start_processing.sh +++ b/tmux/uas/leader/02_start_processing.sh @@ -2,15 +2,24 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -# Kills running containers and processes -trap "{ echo Stopping session 'processing'; tmuxinator stop processing; exit 0; }" EXIT +cleanup() { + echo "Stopping session 'processing'." + docker-compose -f "${KAMERA_DIR}/compose/processing.yml" down + tmux kill-session -t processing 2>/dev/null +} +trap cleanup EXIT -source $DIR/../env.sh +. "${DIR}/../startup.sh" +source "${DIR}/../env.sh" echo "Starting session 'processing'." -ln -sf $DIR/config/processing.yml ~/.tmuxinator/processing.yml +tmux new-session -d -s processing -n viewport_rgb -c "${KAMERA_DIR}" \ + "docker-compose -f compose/processing.yml up viewport_rgb" +tmux new-window -t processing: -n viewport_ir -c "${KAMERA_DIR}" \ + "docker-compose -f compose/processing.yml up viewport_ir" +tmux new-window -t processing: -n nexus -c "${KAMERA_DIR}" \ + "docker-compose -f compose/processing.yml up nexus" +tmux new-window -t processing: -n shapefile_monitor -c "${KAMERA_DIR}" \ + "docker-compose -f compose/processing.yml up shapefile_monitor" -tmuxinator start -n processing -p $DIR/config/processing.yml - -# Keep process alive for supervisor sleep infinity diff --git a/tmux/uas/leader/config/core.yml b/tmux/uas/leader/config/core.yml deleted file mode 100644 index 5d3bd37..0000000 --- a/tmux/uas/leader/config/core.yml +++ /dev/null @@ -1,41 +0,0 @@ -# ~/.tmuxinator/docker.yml - -name: core -root: <%= ENV["KAMERA_DIR"] %> - -# Optional tmux socket -# socket_name: foo - -# Runs before everything. Use it to start daemons etc. -on_project_start: . <%= ENV["KAMERA_DIR"] %>/tmux/uas/startup.sh - -# Runs in each window and pane before window/pane specific commands. Useful for setting up interpreter versions. -pre_window: source <%= ENV["KAMERA_DIR"] %>/tmux/uas/env.sh - -# Pass command line options to tmux. Useful for specifying a different tmux.conf. -# tmux_options: -f ~/.tmux.mac.conf - -# Change the command to call tmux. This can be used by derivatives/wrappers like byobu. -# tmux_command: byobu - -# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used. -# startup_window: editor - -# Specitifes (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used. -# startup_pane: 1 - -# Controls whether the tmux session should be attached to automatically. Defaults to true. -attach: false - -# Runs after everything. Use it to attach to tmux with custom options etc. -# post: tmux -CC attach -t docker - -on_project_stop: echo "Stopping tmux" && docker-compose -f compose/core.yml down - -windows: - - core: docker-compose -f compose/core.yml up roscore - - webvideo: docker-compose -f compose/core.yml up webvideo - - influxdb: docker-compose -f compose/core.yml up influxdb - - diagnostics: docker-compose -f compose/core.yml up diagnostics2influxdb - - diagnostic_aggregator: docker-compose -f compose/core.yml up diagnostic_aggregator - - cam_param_monitor: docker-compose -f compose/core.yml up cam_param_monitor diff --git a/tmux/uas/leader/config/processing.yml b/tmux/uas/leader/config/processing.yml deleted file mode 100644 index aad3cfd..0000000 --- a/tmux/uas/leader/config/processing.yml +++ /dev/null @@ -1,39 +0,0 @@ -# ~/.tmuxinator/docker.yml - -name: processing -root: <%= ENV["KAMERA_DIR"] %> - -# Optional tmux socket -# socket_name: foo - -# Runs before everything. Use it to start daemons etc. -on_project_start: . <%= ENV["KAMERA_DIR"] %>/tmux/uas/startup.sh - -# Runs in each window and pane before window/pane specific commands. Useful for setting up interpreter versions. -pre_window: source <%= ENV["KAMERA_DIR"] %>/tmux/uas/env.sh - -# Pass command line options to tmux. Useful for specifying a different tmux.conf. -# tmux_options: -f ~/.tmux.mac.conf - -# Change the command to call tmux. This can be used by derivatives/wrappers like byobu. -# tmux_command: byobu - -# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used. -# startup_window: editor - -# Specitifes (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used. -# startup_pane: 1 - -# Controls whether the tmux session should be attached to automatically. Defaults to true. -attach: false - -# Runs after everything. Use it to attach to tmux with custom options etc. -# post: tmux -CC attach -t docker - -on_project_stop: echo "Stopping tmux" && docker-compose -f compose/processing.yml down - -windows: - - viewport_rgb: docker-compose -f compose/processing.yml up viewport_rgb - - viewport_ir: docker-compose -f compose/processing.yml up viewport_ir - - nexus: docker-compose -f compose/processing.yml up nexus - - shapefile_monitor: docker-compose -f compose/processing.yml up shapefile_monitor diff --git a/tmux/uas/leader/config/sensors.yml b/tmux/uas/leader/config/sensors.yml deleted file mode 100644 index 6c3085a..0000000 --- a/tmux/uas/leader/config/sensors.yml +++ /dev/null @@ -1,38 +0,0 @@ -# ~/.tmuxinator/docker.yml - -name: sensors -root: <%= ENV["KAMERA_DIR"] %> - -# Optional tmux socket -# socket_name: foo - -# Runs before everything. Use it to start daemons etc. -on_project_start: . <%= ENV["KAMERA_DIR"] %>/tmux/uas/startup.sh - -# Runs in each window and pane before window/pane specific commands. Useful for setting up interpreter versions. -pre_window: source <%= ENV["KAMERA_DIR"] %>/tmux/uas/env.sh - -# Pass command line options to tmux. Useful for specifying a different tmux.conf. -# tmux_options: -f ~/.tmux.mac.conf - -# Change the command to call tmux. This can be used by derivatives/wrappers like byobu. -# tmux_command: byobu - -# Specifies (by name or index) which window will be selected on project startup. If not set, the first window is used. -# startup_window: editor - -# Specitifes (by index) which pane of the specified window will be selected on project startup. If not set, the first pane is used. -# startup_pane: 1 - -# Controls whether the tmux session should be attached to automatically. Defaults to true. -attach: false - -# Runs after everything. Use it to attach to tmux with custom options etc. -# post: tmux -CC attach -t docker - -on_project_stop: echo "Stopping tmux" && docker-compose -f compose/sensors.yml down - -windows: - - rgb_cam: docker-compose -f compose/sensors.yml up cam_rgb - - ir_cam: docker-compose -f compose/sensors.yml up cam_ir - - ins: docker-compose -f compose/sensors.yml up ins diff --git a/tmux/uas/startup.sh b/tmux/uas/startup.sh index 0a4ea89..c0ac645 100644 --- a/tmux/uas/startup.sh +++ b/tmux/uas/startup.sh @@ -2,5 +2,4 @@ source /opt/ros/melodic/setup.bash rosclean purge -y -mkdir -p ~/.tmuxinator mkdir -p ~/.config/kamera/gui From 716ed4686c642d3f88df14c01d9934be812fe382 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Thu, 7 May 2026 15:16:16 -0400 Subject: [PATCH 021/139] Revert KAMERA DIR setting, hard paths are required for supervisor --- tmux/nayak/follower/supervisor.conf | 26 ++++++++++---------- tmux/nayak/leader/supervisor.conf | 38 ++++++++++++++--------------- tmux/taiga/follower/supervisor.conf | 26 ++++++++++---------- tmux/taiga/leader/supervisor.conf | 38 ++++++++++++++--------------- tmux/uas/follower/supervisor.conf | 12 ++++----- tmux/uas/guibox/supervisor.conf | 2 +- tmux/uas/leader/supervisor.conf | 10 ++++---- 7 files changed, 76 insertions(+), 76 deletions(-) diff --git a/tmux/nayak/follower/supervisor.conf b/tmux/nayak/follower/supervisor.conf index ebea601..693a559 100644 --- a/tmux/nayak/follower/supervisor.conf +++ b/tmux/nayak/follower/supervisor.conf @@ -1,67 +1,67 @@ [program:kamerad] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh kamerad +command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh kamerad user=user autostart=false [program:image_manager] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh image_manager +command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh image_manager user=user autostart=false [program:mount_nas] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/mount_nas.sh +command=/bin/bash /home/user/kw/kamera/tmux/nayak/mount_nas.sh startsecs=0 user=root autostart=true [program:set_eth_speed_max] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/set_eth_speed_max.sh +command=/bin/bash /home/user/kw/kamera/tmux/nayak/set_eth_speed_max.sh startsecs=0 user=root autostart=true [program:cam_ir] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh cam_ir +command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh cam_ir user=user autostart=false [program:cam_uv] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh cam_uv +command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh cam_uv user=user autostart=false [program:cam_rgb] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh cam_rgb +command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh cam_rgb user=user autostart=false [program:imageview] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh imageview +command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh imageview user=user autostart=false [program:fps_monitor] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh fps_monitor +command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh fps_monitor user=user autostart=false [program:detector] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh detector +command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh detector user=user autostart=false [program:flight_summary] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh flight_summary +command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh flight_summary user=user autostart=false [program:homography] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh homography +command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh homography user=user autostart=false [program:detections] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/follower/start_tmux_session.sh detections +command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh detections user=user autostart=false diff --git a/tmux/nayak/leader/supervisor.conf b/tmux/nayak/leader/supervisor.conf index 7da34c0..4677dae 100644 --- a/tmux/nayak/leader/supervisor.conf +++ b/tmux/nayak/leader/supervisor.conf @@ -1,98 +1,98 @@ [program:kamerad] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh kamerad +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh kamerad user=user autostart=false [program:image_manager] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh image_manager +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh image_manager user=user autostart=false [program:restart_redis] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/restart_redis.sh +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/restart_redis.sh startsecs=0 user=root autostart=true [program:mount_nas] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/mount_nas.sh +command=/bin/bash /home/user/kw/kamera/tmux/nayak/mount_nas.sh startsecs=0 user=root autostart=true [program:set_eth_speed_max] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/set_eth_speed_max.sh +command=/bin/bash /home/user/kw/kamera/tmux/nayak/set_eth_speed_max.sh startsecs=0 user=root autostart=true [program:roscore] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh roscore +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh roscore user=user autostart=false [program:cam_param_monitor] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh cam_param_monitor +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh cam_param_monitor user=user autostart=false [program:fps_monitor] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh fps_monitor +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh fps_monitor user=user autostart=false [program:shapefile_monitor] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh shapefile_monitor +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh shapefile_monitor user=user autostart=false [program:cam_ir] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh cam_ir +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh cam_ir user=user autostart=false [program:cam_uv] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh cam_uv +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh cam_uv user=user autostart=false [program:cam_rgb] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh cam_rgb +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh cam_rgb user=user autostart=false [program:ins] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh ins +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh ins user=user autostart=false [program:daq] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh daq +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh daq user=user autostart=false [program:imageview] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh imageview +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh imageview user=user autostart=false [program:detector] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh detector +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh detector user=user autostart=false [program:flight_summary] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh flight_summary +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh flight_summary user=user autostart=false [program:homography] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh homography +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh homography user=user autostart=false [program:detections] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/nayak/leader/start_tmux_session.sh detections +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh detections user=user autostart=false diff --git a/tmux/taiga/follower/supervisor.conf b/tmux/taiga/follower/supervisor.conf index 9ce5067..bf9b06e 100644 --- a/tmux/taiga/follower/supervisor.conf +++ b/tmux/taiga/follower/supervisor.conf @@ -1,67 +1,67 @@ [program:kamerad] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh kamerad +command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh kamerad user=user autostart=false [program:image_manager] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh image_manager +command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh image_manager user=user autostart=false [program:mount_nas] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/mount_nas.sh +command=/bin/bash /home/user/kw/kamera/tmux/taiga/mount_nas.sh startsecs=0 user=root autostart=true [program:set_eth_speed_max] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/set_eth_speed_max.sh +command=/bin/bash /home/user/kw/kamera/tmux/taiga/set_eth_speed_max.sh startsecs=0 user=root autostart=true [program:cam_ir] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh cam_ir +command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh cam_ir user=user autostart=false [program:cam_uv] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh cam_uv +command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh cam_uv user=user autostart=false [program:cam_rgb] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh cam_rgb +command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh cam_rgb user=user autostart=false [program:imageview] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh imageview +command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh imageview user=user autostart=false [program:fps_monitor] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh fps_monitor +command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh fps_monitor user=user autostart=false [program:detector] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh detector +command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh detector user=user autostart=false [program:flight_summary] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh flight_summary +command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh flight_summary user=user autostart=false [program:homography] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh homography +command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh homography user=user autostart=false [program:detections] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/follower/start_tmux_session.sh detections +command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh detections user=user autostart=false diff --git a/tmux/taiga/leader/supervisor.conf b/tmux/taiga/leader/supervisor.conf index 271c061..3c14366 100644 --- a/tmux/taiga/leader/supervisor.conf +++ b/tmux/taiga/leader/supervisor.conf @@ -1,98 +1,98 @@ [program:kamerad] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh kamerad +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh kamerad user=user autostart=false [program:image_manager] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh image_manager +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh image_manager user=user autostart=false [program:restart_redis] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/restart_redis.sh +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/restart_redis.sh startsecs=0 user=root autostart=true [program:mount_nas] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/mount_nas.sh +command=/bin/bash /home/user/kw/kamera/tmux/taiga/mount_nas.sh startsecs=0 user=root autostart=true [program:set_eth_speed_max] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/set_eth_speed_max.sh +command=/bin/bash /home/user/kw/kamera/tmux/taiga/set_eth_speed_max.sh startsecs=0 user=root autostart=true [program:roscore] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh roscore +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh roscore user=user autostart=false [program:cam_param_monitor] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh cam_param_monitor +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh cam_param_monitor user=user autostart=false [program:fps_monitor] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh fps_monitor +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh fps_monitor user=user autostart=false [program:shapefile_monitor] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh shapefile_monitor +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh shapefile_monitor user=user autostart=false [program:cam_ir] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh cam_ir +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh cam_ir user=user autostart=false [program:cam_uv] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh cam_uv +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh cam_uv user=user autostart=false [program:cam_rgb] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh cam_rgb +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh cam_rgb user=user autostart=false [program:ins] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh ins +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh ins user=user autostart=false [program:daq] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh daq +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh daq user=user autostart=false [program:imageview] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh imageview +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh imageview user=user autostart=false [program:detector] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh detector +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh detector user=user autostart=false [program:flight_summary] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh flight_summary +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh flight_summary user=user autostart=false [program:homography] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh homography +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh homography user=user autostart=false [program:detections] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/taiga/leader/start_tmux_session.sh detections +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh detections user=user autostart=false diff --git a/tmux/uas/follower/supervisor.conf b/tmux/uas/follower/supervisor.conf index 8aa16a4..ad606ad 100644 --- a/tmux/uas/follower/supervisor.conf +++ b/tmux/uas/follower/supervisor.conf @@ -1,30 +1,30 @@ [program:core] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/00_start_core.sh +command=/bin/bash /home/user/kw/kamera/tmux/uas/follower/00_start_core.sh user=user autostart=true [program:sensors] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/01_start_sensors.sh +command=/bin/bash /home/user/kw/kamera/tmux/uas/follower/01_start_sensors.sh user=user autostart=true [program:processing] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/02_start_processing.sh +command=/bin/bash /home/user/kw/kamera/tmux/uas/follower/02_start_processing.sh user=user autostart=true [program:timesync] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/03_run_clock_sync.sh +command=/bin/bash /home/user/kw/kamera/tmux/uas/follower/03_run_clock_sync.sh user=root autostart=true [program:camptp] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/04_run_cam_ptp.sh +command=/bin/bash /home/user/kw/kamera/tmux/uas/follower/04_run_cam_ptp.sh user=root autostart=true [program:docker] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/follower/05_start_docker.sh +command=/bin/bash /home/user/kw/kamera/tmux/uas/follower/05_start_docker.sh user=root autostart=true diff --git a/tmux/uas/guibox/supervisor.conf b/tmux/uas/guibox/supervisor.conf index 7a1cad8..d0d2d40 100644 --- a/tmux/uas/guibox/supervisor.conf +++ b/tmux/uas/guibox/supervisor.conf @@ -1,4 +1,4 @@ [program:flight_summary] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/guibox/00_flight_summary.sh +command=/bin/bash /home/user/kw/kamera/tmux/uas/guibox/00_flight_summary.sh user=root autostart=true diff --git a/tmux/uas/leader/supervisor.conf b/tmux/uas/leader/supervisor.conf index 13950fe..940c5cd 100644 --- a/tmux/uas/leader/supervisor.conf +++ b/tmux/uas/leader/supervisor.conf @@ -1,25 +1,25 @@ [program:core] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/00_start_core.sh +command=/bin/bash /home/user/kw/kamera/tmux/uas/leader/00_start_core.sh user=user autostart=true [program:sensors] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/01_start_sensors.sh +command=/bin/bash /home/user/kw/kamera/tmux/uas/leader/01_start_sensors.sh user=user autostart=true [program:processing] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/02_start_processing.sh +command=/bin/bash /home/user/kw/kamera/tmux/uas/leader/02_start_processing.sh user=user autostart=true [program:timesync] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/03_run_clock_sync.sh +command=/bin/bash /home/user/kw/kamera/tmux/uas/leader/03_run_clock_sync.sh user=root autostart=true [program:docker] -command=/bin/bash %(ENV_KAMERA_DIR)s/tmux/uas/leader/05_start_docker.sh +command=/bin/bash /home/user/kw/kamera/tmux/uas/leader/05_start_docker.sh user=root autostart=true From 85457967bc31729ea420cb80a1c62d8406dcccb3 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Thu, 7 May 2026 15:17:36 -0400 Subject: [PATCH 022/139] Rollback supervisord changes as well. --- src/cfg/nayak/supervisord.conf | 2 +- src/cfg/taiga/supervisord.conf | 2 +- src/cfg/uas/supervisord.conf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cfg/nayak/supervisord.conf b/src/cfg/nayak/supervisord.conf index 39ab6d8..6b26cda 100644 --- a/src/cfg/nayak/supervisord.conf +++ b/src/cfg/nayak/supervisord.conf @@ -12,7 +12,7 @@ port=0.0.0.0:9001 logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) -environment=HOME="/home/user",KAMERA_DIR="/home/user/kw/kamera" +environment=HOME="/home/user" ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be diff --git a/src/cfg/taiga/supervisord.conf b/src/cfg/taiga/supervisord.conf index 39ab6d8..6b26cda 100644 --- a/src/cfg/taiga/supervisord.conf +++ b/src/cfg/taiga/supervisord.conf @@ -12,7 +12,7 @@ port=0.0.0.0:9001 logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) -environment=HOME="/home/user",KAMERA_DIR="/home/user/kw/kamera" +environment=HOME="/home/user" ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be diff --git a/src/cfg/uas/supervisord.conf b/src/cfg/uas/supervisord.conf index 913fe0b..8449695 100644 --- a/src/cfg/uas/supervisord.conf +++ b/src/cfg/uas/supervisord.conf @@ -12,7 +12,7 @@ port=0.0.0.0:9001 logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) -environment=HOME="/home/user",KAMERA_DIR="/home/user/kw/kamera" +environment=HOME="/home/user" ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be From 6f5c269793d3ad9ecb8c656e57c478c3e0c1cb05 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Thu, 7 May 2026 15:29:47 -0400 Subject: [PATCH 023/139] Source env directly before docker startup --- tmux/nayak/follower/start_tmux_session.sh | 2 +- tmux/nayak/leader/start_tmux_session.sh | 2 +- tmux/taiga/follower/start_tmux_session.sh | 2 +- tmux/taiga/leader/start_tmux_session.sh | 2 +- tmux/uas/follower/00_start_core.sh | 2 +- tmux/uas/follower/01_start_sensors.sh | 4 ++-- tmux/uas/follower/02_start_processing.sh | 6 +++--- tmux/uas/leader/00_start_core.sh | 12 ++++++------ tmux/uas/leader/01_start_sensors.sh | 6 +++--- tmux/uas/leader/02_start_processing.sh | 8 ++++---- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/tmux/nayak/follower/start_tmux_session.sh b/tmux/nayak/follower/start_tmux_session.sh index 9b20c26..f68b16b 100755 --- a/tmux/nayak/follower/start_tmux_session.sh +++ b/tmux/nayak/follower/start_tmux_session.sh @@ -19,6 +19,6 @@ source "${DIR}/../env.sh" echo "Starting session '${SESSION}'." tmux new-session -d -s "${SESSION}" -c "${KAMERA_DIR}" \ - "docker compose -f compose/${SESSION}.yml up ${SESSION}" + "bash -c 'source ${DIR}/../env.sh && docker compose -f compose/${SESSION}.yml up ${SESSION}'" sleep infinity diff --git a/tmux/nayak/leader/start_tmux_session.sh b/tmux/nayak/leader/start_tmux_session.sh index 9b20c26..f68b16b 100755 --- a/tmux/nayak/leader/start_tmux_session.sh +++ b/tmux/nayak/leader/start_tmux_session.sh @@ -19,6 +19,6 @@ source "${DIR}/../env.sh" echo "Starting session '${SESSION}'." tmux new-session -d -s "${SESSION}" -c "${KAMERA_DIR}" \ - "docker compose -f compose/${SESSION}.yml up ${SESSION}" + "bash -c 'source ${DIR}/../env.sh && docker compose -f compose/${SESSION}.yml up ${SESSION}'" sleep infinity diff --git a/tmux/taiga/follower/start_tmux_session.sh b/tmux/taiga/follower/start_tmux_session.sh index 9b20c26..f68b16b 100755 --- a/tmux/taiga/follower/start_tmux_session.sh +++ b/tmux/taiga/follower/start_tmux_session.sh @@ -19,6 +19,6 @@ source "${DIR}/../env.sh" echo "Starting session '${SESSION}'." tmux new-session -d -s "${SESSION}" -c "${KAMERA_DIR}" \ - "docker compose -f compose/${SESSION}.yml up ${SESSION}" + "bash -c 'source ${DIR}/../env.sh && docker compose -f compose/${SESSION}.yml up ${SESSION}'" sleep infinity diff --git a/tmux/taiga/leader/start_tmux_session.sh b/tmux/taiga/leader/start_tmux_session.sh index 9b20c26..f68b16b 100755 --- a/tmux/taiga/leader/start_tmux_session.sh +++ b/tmux/taiga/leader/start_tmux_session.sh @@ -19,6 +19,6 @@ source "${DIR}/../env.sh" echo "Starting session '${SESSION}'." tmux new-session -d -s "${SESSION}" -c "${KAMERA_DIR}" \ - "docker compose -f compose/${SESSION}.yml up ${SESSION}" + "bash -c 'source ${DIR}/../env.sh && docker compose -f compose/${SESSION}.yml up ${SESSION}'" sleep infinity diff --git a/tmux/uas/follower/00_start_core.sh b/tmux/uas/follower/00_start_core.sh index eeed19f..8fda2c1 100755 --- a/tmux/uas/follower/00_start_core.sh +++ b/tmux/uas/follower/00_start_core.sh @@ -14,6 +14,6 @@ source "${DIR}/../env.sh" echo "Start session 'core'." tmux new-session -d -s core -n webvideo -c "${KAMERA_DIR}" \ - "docker-compose -f compose/core.yml up webvideo" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/core.yml up webvideo'" sleep infinity diff --git a/tmux/uas/follower/01_start_sensors.sh b/tmux/uas/follower/01_start_sensors.sh index 03d74d4..a27e270 100755 --- a/tmux/uas/follower/01_start_sensors.sh +++ b/tmux/uas/follower/01_start_sensors.sh @@ -14,8 +14,8 @@ source "${DIR}/../env.sh" echo "Starting session 'sensors'." tmux new-session -d -s sensors -n rgb_cam -c "${KAMERA_DIR}" \ - "docker-compose -f compose/sensors.yml up cam_rgb" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/sensors.yml up cam_rgb'" tmux new-window -t sensors: -n ir_cam -c "${KAMERA_DIR}" \ - "docker-compose -f compose/sensors.yml up cam_ir" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/sensors.yml up cam_ir'" sleep infinity diff --git a/tmux/uas/follower/02_start_processing.sh b/tmux/uas/follower/02_start_processing.sh index 080d062..d4af038 100755 --- a/tmux/uas/follower/02_start_processing.sh +++ b/tmux/uas/follower/02_start_processing.sh @@ -14,10 +14,10 @@ source "${DIR}/../env.sh" echo "Starting session 'processing'." tmux new-session -d -s processing -n viewport_rgb -c "${KAMERA_DIR}" \ - "docker-compose -f compose/processing.yml up viewport_rgb" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/processing.yml up viewport_rgb'" tmux new-window -t processing: -n viewport_ir -c "${KAMERA_DIR}" \ - "docker-compose -f compose/processing.yml up viewport_ir" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/processing.yml up viewport_ir'" tmux new-window -t processing: -n nexus -c "${KAMERA_DIR}" \ - "docker-compose -f compose/processing.yml up nexus" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/processing.yml up nexus'" sleep infinity diff --git a/tmux/uas/leader/00_start_core.sh b/tmux/uas/leader/00_start_core.sh index c7e44b7..7ce90c5 100755 --- a/tmux/uas/leader/00_start_core.sh +++ b/tmux/uas/leader/00_start_core.sh @@ -14,16 +14,16 @@ source "${DIR}/../env.sh" echo "Start session 'core'." tmux new-session -d -s core -n core -c "${KAMERA_DIR}" \ - "docker-compose -f compose/core.yml up roscore" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/core.yml up roscore'" tmux new-window -t core: -n webvideo -c "${KAMERA_DIR}" \ - "docker-compose -f compose/core.yml up webvideo" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/core.yml up webvideo'" tmux new-window -t core: -n influxdb -c "${KAMERA_DIR}" \ - "docker-compose -f compose/core.yml up influxdb" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/core.yml up influxdb'" tmux new-window -t core: -n diagnostics -c "${KAMERA_DIR}" \ - "docker-compose -f compose/core.yml up diagnostics2influxdb" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/core.yml up diagnostics2influxdb'" tmux new-window -t core: -n diagnostic_aggregator -c "${KAMERA_DIR}" \ - "docker-compose -f compose/core.yml up diagnostic_aggregator" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/core.yml up diagnostic_aggregator'" tmux new-window -t core: -n cam_param_monitor -c "${KAMERA_DIR}" \ - "docker-compose -f compose/core.yml up cam_param_monitor" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/core.yml up cam_param_monitor'" sleep infinity diff --git a/tmux/uas/leader/01_start_sensors.sh b/tmux/uas/leader/01_start_sensors.sh index e563874..866ad26 100755 --- a/tmux/uas/leader/01_start_sensors.sh +++ b/tmux/uas/leader/01_start_sensors.sh @@ -14,10 +14,10 @@ source "${DIR}/../env.sh" echo "Starting session 'sensors'." tmux new-session -d -s sensors -n rgb_cam -c "${KAMERA_DIR}" \ - "docker-compose -f compose/sensors.yml up cam_rgb" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/sensors.yml up cam_rgb'" tmux new-window -t sensors: -n ir_cam -c "${KAMERA_DIR}" \ - "docker-compose -f compose/sensors.yml up cam_ir" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/sensors.yml up cam_ir'" tmux new-window -t sensors: -n ins -c "${KAMERA_DIR}" \ - "docker-compose -f compose/sensors.yml up ins" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/sensors.yml up ins'" sleep infinity diff --git a/tmux/uas/leader/02_start_processing.sh b/tmux/uas/leader/02_start_processing.sh index 7c79664..2572650 100755 --- a/tmux/uas/leader/02_start_processing.sh +++ b/tmux/uas/leader/02_start_processing.sh @@ -14,12 +14,12 @@ source "${DIR}/../env.sh" echo "Starting session 'processing'." tmux new-session -d -s processing -n viewport_rgb -c "${KAMERA_DIR}" \ - "docker-compose -f compose/processing.yml up viewport_rgb" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/processing.yml up viewport_rgb'" tmux new-window -t processing: -n viewport_ir -c "${KAMERA_DIR}" \ - "docker-compose -f compose/processing.yml up viewport_ir" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/processing.yml up viewport_ir'" tmux new-window -t processing: -n nexus -c "${KAMERA_DIR}" \ - "docker-compose -f compose/processing.yml up nexus" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/processing.yml up nexus'" tmux new-window -t processing: -n shapefile_monitor -c "${KAMERA_DIR}" \ - "docker-compose -f compose/processing.yml up shapefile_monitor" + "bash -c 'source ${DIR}/../env.sh && docker-compose -f compose/processing.yml up shapefile_monitor'" sleep infinity From 3d11bb103e1ef1f96a4c8bf167a83b03f3989827 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Thu, 7 May 2026 15:33:36 -0400 Subject: [PATCH 024/139] Call env.sh only once --- tmux/nayak/follower/start_tmux_session.sh | 2 +- tmux/nayak/leader/start_tmux_session.sh | 2 +- tmux/taiga/follower/start_tmux_session.sh | 2 +- tmux/taiga/leader/start_tmux_session.sh | 2 +- tmux/uas/follower/00_start_core.sh | 2 +- tmux/uas/follower/01_start_sensors.sh | 2 +- tmux/uas/follower/02_start_processing.sh | 2 +- tmux/uas/leader/00_start_core.sh | 2 +- tmux/uas/leader/01_start_sensors.sh | 2 +- tmux/uas/leader/02_start_processing.sh | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tmux/nayak/follower/start_tmux_session.sh b/tmux/nayak/follower/start_tmux_session.sh index f68b16b..36f9da0 100755 --- a/tmux/nayak/follower/start_tmux_session.sh +++ b/tmux/nayak/follower/start_tmux_session.sh @@ -15,7 +15,7 @@ cleanup() { trap cleanup EXIT . "${DIR}/../startup.sh" -source "${DIR}/../env.sh" +export KAMERA_DIR=$(${HOME}/.config/kamera/repo_dir.bash) echo "Starting session '${SESSION}'." tmux new-session -d -s "${SESSION}" -c "${KAMERA_DIR}" \ diff --git a/tmux/nayak/leader/start_tmux_session.sh b/tmux/nayak/leader/start_tmux_session.sh index f68b16b..36f9da0 100755 --- a/tmux/nayak/leader/start_tmux_session.sh +++ b/tmux/nayak/leader/start_tmux_session.sh @@ -15,7 +15,7 @@ cleanup() { trap cleanup EXIT . "${DIR}/../startup.sh" -source "${DIR}/../env.sh" +export KAMERA_DIR=$(${HOME}/.config/kamera/repo_dir.bash) echo "Starting session '${SESSION}'." tmux new-session -d -s "${SESSION}" -c "${KAMERA_DIR}" \ diff --git a/tmux/taiga/follower/start_tmux_session.sh b/tmux/taiga/follower/start_tmux_session.sh index f68b16b..36f9da0 100755 --- a/tmux/taiga/follower/start_tmux_session.sh +++ b/tmux/taiga/follower/start_tmux_session.sh @@ -15,7 +15,7 @@ cleanup() { trap cleanup EXIT . "${DIR}/../startup.sh" -source "${DIR}/../env.sh" +export KAMERA_DIR=$(${HOME}/.config/kamera/repo_dir.bash) echo "Starting session '${SESSION}'." tmux new-session -d -s "${SESSION}" -c "${KAMERA_DIR}" \ diff --git a/tmux/taiga/leader/start_tmux_session.sh b/tmux/taiga/leader/start_tmux_session.sh index f68b16b..36f9da0 100755 --- a/tmux/taiga/leader/start_tmux_session.sh +++ b/tmux/taiga/leader/start_tmux_session.sh @@ -15,7 +15,7 @@ cleanup() { trap cleanup EXIT . "${DIR}/../startup.sh" -source "${DIR}/../env.sh" +export KAMERA_DIR=$(${HOME}/.config/kamera/repo_dir.bash) echo "Starting session '${SESSION}'." tmux new-session -d -s "${SESSION}" -c "${KAMERA_DIR}" \ diff --git a/tmux/uas/follower/00_start_core.sh b/tmux/uas/follower/00_start_core.sh index 8fda2c1..e1add96 100755 --- a/tmux/uas/follower/00_start_core.sh +++ b/tmux/uas/follower/00_start_core.sh @@ -10,7 +10,7 @@ cleanup() { trap cleanup EXIT . "${DIR}/../startup.sh" -source "${DIR}/../env.sh" +export KAMERA_DIR="/home/user/kw/kamera" echo "Start session 'core'." tmux new-session -d -s core -n webvideo -c "${KAMERA_DIR}" \ diff --git a/tmux/uas/follower/01_start_sensors.sh b/tmux/uas/follower/01_start_sensors.sh index a27e270..84bd631 100755 --- a/tmux/uas/follower/01_start_sensors.sh +++ b/tmux/uas/follower/01_start_sensors.sh @@ -10,7 +10,7 @@ cleanup() { trap cleanup EXIT . "${DIR}/../startup.sh" -source "${DIR}/../env.sh" +export KAMERA_DIR="/home/user/kw/kamera" echo "Starting session 'sensors'." tmux new-session -d -s sensors -n rgb_cam -c "${KAMERA_DIR}" \ diff --git a/tmux/uas/follower/02_start_processing.sh b/tmux/uas/follower/02_start_processing.sh index d4af038..495dce3 100755 --- a/tmux/uas/follower/02_start_processing.sh +++ b/tmux/uas/follower/02_start_processing.sh @@ -10,7 +10,7 @@ cleanup() { trap cleanup EXIT . "${DIR}/../startup.sh" -source "${DIR}/../env.sh" +export KAMERA_DIR="/home/user/kw/kamera" echo "Starting session 'processing'." tmux new-session -d -s processing -n viewport_rgb -c "${KAMERA_DIR}" \ diff --git a/tmux/uas/leader/00_start_core.sh b/tmux/uas/leader/00_start_core.sh index 7ce90c5..ca7d0f3 100755 --- a/tmux/uas/leader/00_start_core.sh +++ b/tmux/uas/leader/00_start_core.sh @@ -10,7 +10,7 @@ cleanup() { trap cleanup EXIT . "${DIR}/../startup.sh" -source "${DIR}/../env.sh" +export KAMERA_DIR="/home/user/kw/kamera" echo "Start session 'core'." tmux new-session -d -s core -n core -c "${KAMERA_DIR}" \ diff --git a/tmux/uas/leader/01_start_sensors.sh b/tmux/uas/leader/01_start_sensors.sh index 866ad26..7580293 100755 --- a/tmux/uas/leader/01_start_sensors.sh +++ b/tmux/uas/leader/01_start_sensors.sh @@ -10,7 +10,7 @@ cleanup() { trap cleanup EXIT . "${DIR}/../startup.sh" -source "${DIR}/../env.sh" +export KAMERA_DIR="/home/user/kw/kamera" echo "Starting session 'sensors'." tmux new-session -d -s sensors -n rgb_cam -c "${KAMERA_DIR}" \ diff --git a/tmux/uas/leader/02_start_processing.sh b/tmux/uas/leader/02_start_processing.sh index 2572650..fdbb03b 100755 --- a/tmux/uas/leader/02_start_processing.sh +++ b/tmux/uas/leader/02_start_processing.sh @@ -10,7 +10,7 @@ cleanup() { trap cleanup EXIT . "${DIR}/../startup.sh" -source "${DIR}/../env.sh" +export KAMERA_DIR="/home/user/kw/kamera" echo "Starting session 'processing'." tmux new-session -d -s processing -n viewport_rgb -c "${KAMERA_DIR}" \ From 15c195f5e0e4625e0abe017cdad042fa52045c54 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Thu, 7 May 2026 15:36:10 -0400 Subject: [PATCH 025/139] Remove 'version' tags from compose files to comply --- compose/cam_ir.yml | 1 - compose/cam_param_monitor.yml | 1 - compose/cam_rgb.yml | 1 - compose/cam_uv.yml | 1 - compose/daq.yml | 1 - compose/detections.yml | 1 - compose/detector.yml | 1 - compose/flight_summary.yml | 1 - compose/fps_monitor.yml | 1 - compose/gui.yml | 1 - compose/homography.yml | 1 - compose/image_manager.yml | 1 - compose/imageview.yml | 1 - compose/ins.yml | 1 - compose/kamerad.yml | 1 - compose/postproc.yml | 1 - compose/registry.yml | 1 - compose/roscore.yml | 1 - compose/shapefile_monitor.yml | 1 - compose/spoof_events.yml | 1 - compose/sync_msg_publisher.yml | 1 - 21 files changed, 21 deletions(-) diff --git a/compose/cam_ir.yml b/compose/cam_ir.yml index caed582..72629af 100644 --- a/compose/cam_ir.yml +++ b/compose/cam_ir.yml @@ -1,6 +1,5 @@ --- ## Auxiliary node to attach to master -version: '3.7' services: cam_ir: container_name: "cam-ir-${CAM_FOV}" diff --git a/compose/cam_param_monitor.yml b/compose/cam_param_monitor.yml index e227336..89763a5 100644 --- a/compose/cam_param_monitor.yml +++ b/compose/cam_param_monitor.yml @@ -1,6 +1,5 @@ --- ## Core processes -version: '3.7' services: cam_param_monitor: container_name: cam_param_monitor diff --git a/compose/cam_rgb.yml b/compose/cam_rgb.yml index d0c8b74..6d19903 100644 --- a/compose/cam_rgb.yml +++ b/compose/cam_rgb.yml @@ -1,6 +1,5 @@ --- ## Auxiliary node to attach to master -version: '3.7' services: ## =========================== headless nodes ============================= cam_rgb: diff --git a/compose/cam_uv.yml b/compose/cam_uv.yml index 799d892..fbd3d59 100644 --- a/compose/cam_uv.yml +++ b/compose/cam_uv.yml @@ -1,6 +1,5 @@ --- ## Auxiliary node to attach to master -version: '3.7' services: ## =========================== headless nodes ============================= cam_uv: diff --git a/compose/daq.yml b/compose/daq.yml index 92b95b2..1d25ab3 100644 --- a/compose/daq.yml +++ b/compose/daq.yml @@ -1,6 +1,5 @@ --- ## Bring up the core nodes (aside from roscore) -version: '3.7' services: daq: container_name: daq diff --git a/compose/detections.yml b/compose/detections.yml index 8d3ab1a..7a9f9dd 100644 --- a/compose/detections.yml +++ b/compose/detections.yml @@ -1,6 +1,5 @@ --- ## Core processes -version: '3.7' services: ## =========================== headless nodes ============================= detections: diff --git a/compose/detector.yml b/compose/detector.yml index 7733d60..4723d8d 100644 --- a/compose/detector.yml +++ b/compose/detector.yml @@ -1,7 +1,6 @@ --- ## container configuration for viame interactive building # use compose v2 to use runtime config -version: '2.4' services: ## ========================== viame ============================= diff --git a/compose/flight_summary.yml b/compose/flight_summary.yml index 4952a1c..fb0ba2f 100644 --- a/compose/flight_summary.yml +++ b/compose/flight_summary.yml @@ -1,6 +1,5 @@ --- ## Core processes -version: '3.7' services: ## =========================== headless nodes ============================= flight_summary: diff --git a/compose/fps_monitor.yml b/compose/fps_monitor.yml index beca892..b886741 100644 --- a/compose/fps_monitor.yml +++ b/compose/fps_monitor.yml @@ -1,6 +1,5 @@ --- ## Core processes -version: '3.7' services: fps_monitor: container_name: fps_monitor diff --git a/compose/gui.yml b/compose/gui.yml index 72abb11..f41d133 100644 --- a/compose/gui.yml +++ b/compose/gui.yml @@ -1,6 +1,5 @@ --- ## container configuration for GUI -version: '3.7' services: ## =========================== gui ============================= gui: diff --git a/compose/homography.yml b/compose/homography.yml index 991ca33..89c0843 100644 --- a/compose/homography.yml +++ b/compose/homography.yml @@ -1,6 +1,5 @@ --- ## Core processes -version: '3.7' services: ## =========================== headless nodes ============================= homography: diff --git a/compose/image_manager.yml b/compose/image_manager.yml index 2b7cede..b3b78ab 100644 --- a/compose/image_manager.yml +++ b/compose/image_manager.yml @@ -1,6 +1,5 @@ --- ## Auxiliary node to attach to master -version: '3.7' services: ## =========================== headless nodes ============================= image_manager: diff --git a/compose/imageview.yml b/compose/imageview.yml index 69230a6..a4e171d 100644 --- a/compose/imageview.yml +++ b/compose/imageview.yml @@ -1,5 +1,4 @@ --- -version: '3.7' services: imageview: container_name: "imageview-${CAM_FOV}" diff --git a/compose/ins.yml b/compose/ins.yml index 89ddbcc..9f4d3bf 100644 --- a/compose/ins.yml +++ b/compose/ins.yml @@ -1,6 +1,5 @@ --- ## Bring up the core nodes (aside from roscore) -version: '3.7' services: ins: container_name: ins diff --git a/compose/kamerad.yml b/compose/kamerad.yml index ddcd68d..08ba494 100644 --- a/compose/kamerad.yml +++ b/compose/kamerad.yml @@ -1,6 +1,5 @@ --- ## Core processes -version: '3.7' services: ## =========================== headless nodes ============================= kamerad: diff --git a/compose/postproc.yml b/compose/postproc.yml index e26d9d2..151c201 100644 --- a/compose/postproc.yml +++ b/compose/postproc.yml @@ -1,6 +1,5 @@ --- ## Core processes -version: '3.7' services: ## =========================== headless nodes ============================= postproc: diff --git a/compose/registry.yml b/compose/registry.yml index ccbb7cf..728fa45 100644 --- a/compose/registry.yml +++ b/compose/registry.yml @@ -1,4 +1,3 @@ -version: "3" services: registry: restart: always diff --git a/compose/roscore.yml b/compose/roscore.yml index 36fc934..2f70ce0 100644 --- a/compose/roscore.yml +++ b/compose/roscore.yml @@ -1,6 +1,5 @@ --- ## Bring up the core nodes -version: '3.7' services: ## =========================== headless nodes ============================= roscore: diff --git a/compose/shapefile_monitor.yml b/compose/shapefile_monitor.yml index ddfdd2e..12b510a 100644 --- a/compose/shapefile_monitor.yml +++ b/compose/shapefile_monitor.yml @@ -1,6 +1,5 @@ --- ## Core processes -version: '3.7' services: shapefile_monitor: container_name: shapefile_monitor diff --git a/compose/spoof_events.yml b/compose/spoof_events.yml index c7c3e33..d19bffb 100644 --- a/compose/spoof_events.yml +++ b/compose/spoof_events.yml @@ -1,6 +1,5 @@ --- ## Bring up the core nodes (aside from roscore) -version: '3.7' services: spoof_events: container_name: spoof_events diff --git a/compose/sync_msg_publisher.yml b/compose/sync_msg_publisher.yml index b83a813..7eeb8ed 100644 --- a/compose/sync_msg_publisher.yml +++ b/compose/sync_msg_publisher.yml @@ -1,5 +1,4 @@ --- -version: "3.7" ## =======================image sync publisher=================== services: sync-publisher: From c90e31e8160d0a8711975a3a83dc8d4ff61acd1b Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Fri, 1 May 2026 10:12:18 -0400 Subject: [PATCH 026/139] Cleanup roskv, remove benedict dependency, collapse RedisEnvoy into one class. Delete old shims and consul work. --- docker/base/core-ros.dockerfile | 1 - docker/base/gui-ros.dockerfile | 1 - .../kamcore/scripts/cam_param_monitor_node.py | 2 +- .../scripts/diagnostics_to_influxdb.py | 2 +- src/core/kamcore/scripts/fps_monitor_node.py | 14 +- src/core/roskv/CMakeLists.txt | 6 - src/core/roskv/include/roskv/archiver.h | 20 +- src/core/roskv/include/roskv/envoy.h | 19 +- src/core/roskv/include/roskv/roskv.h | 15 - src/core/roskv/libroskv/archiver.cpp | 41 +- src/core/roskv/libroskv/envoy.cpp | 20 +- src/core/roskv/libroskv/roskv.cpp | 9 - src/core/roskv/noros-setup.py | 2 +- src/core/roskv/scripts/roskv | 20 +- src/core/roskv/setup.py | 6 +- src/core/roskv/src/roskv/base.py | 401 +---------- src/core/roskv/src/roskv/client.py | 3 - .../src/roskv/clients/redis_envoy_client.py | 0 src/core/roskv/src/roskv/compat.py | 10 - src/core/roskv/src/roskv/impl/consul_kv.py | 97 --- .../roskv/src/roskv/impl/consul_ros_mirror.py | 38 - src/core/roskv/src/roskv/impl/redis_envoy.py | 653 ++---------------- src/core/roskv/src/roskv/nodes/kvtest.py | 36 +- src/core/roskv/src/roskv/pigeonhole.py | 199 ------ src/core/roskv/src/roskv/reactor.py | 7 +- src/core/roskv/src/roskv/rendezvous.py | 141 +--- src/core/roskv/src/roskv/util.py | 116 ++-- src/core/testbed/src/test_roskv.cpp | 2 - .../image_manager/image_manager.py | 20 +- src/process/nexus/src/nexus/archiver_core.py | 14 +- 30 files changed, 182 insertions(+), 1733 deletions(-) delete mode 100644 src/core/roskv/include/roskv/roskv.h delete mode 100644 src/core/roskv/libroskv/roskv.cpp delete mode 100644 src/core/roskv/src/roskv/clients/redis_envoy_client.py delete mode 100644 src/core/roskv/src/roskv/compat.py delete mode 100644 src/core/roskv/src/roskv/impl/consul_kv.py delete mode 100644 src/core/roskv/src/roskv/impl/consul_ros_mirror.py delete mode 100644 src/core/roskv/src/roskv/pigeonhole.py diff --git a/docker/base/core-ros.dockerfile b/docker/base/core-ros.dockerfile index 186a7c6..af8aae2 100644 --- a/docker/base/core-ros.dockerfile +++ b/docker/base/core-ros.dockerfile @@ -80,7 +80,6 @@ RUN pip install --upgrade --no-cache-dir pip \ && pip install --no-cache-dir \ ipython \ ipdb \ - python-benedict \ pyserial \ typing \ pathlib \ diff --git a/docker/base/gui-ros.dockerfile b/docker/base/gui-ros.dockerfile index 003c7aa..cea3246 100644 --- a/docker/base/gui-ros.dockerfile +++ b/docker/base/gui-ros.dockerfile @@ -40,7 +40,6 @@ RUN pip install --upgrade --no-cache-dir pip \ && pip install --no-cache-dir \ ipython \ ipdb \ - python-benedict \ pyserial \ typing \ pathlib \ diff --git a/src/core/kamcore/scripts/cam_param_monitor_node.py b/src/core/kamcore/scripts/cam_param_monitor_node.py index 4cdcbbc..e1fc540 100755 --- a/src/core/kamcore/scripts/cam_param_monitor_node.py +++ b/src/core/kamcore/scripts/cam_param_monitor_node.py @@ -115,7 +115,7 @@ def get_param_val(self, host, mode, param, requested_val): return if mode == "rgb": param = '_'.join(param.split(' ')) - self.envoy.kv.set("/sys/actual_geni_params/%s/%s/%s" + self.envoy.set("/sys/actual_geni_params/%s/%s/%s" % (host, mode, param), getsrv_val) if param == "GainValue" or param == "ExposureValue"\ or param == "ISO" or param == "Shutter_Speed"\ diff --git a/src/core/kamcore/scripts/diagnostics_to_influxdb.py b/src/core/kamcore/scripts/diagnostics_to_influxdb.py index 476d85c..be1133a 100755 --- a/src/core/kamcore/scripts/diagnostics_to_influxdb.py +++ b/src/core/kamcore/scripts/diagnostics_to_influxdb.py @@ -46,7 +46,7 @@ def diagnostics_to_influxdb(self, array): chan = parts[1] topic = '/'.join(['', 'sys', "actual_geni_params", host, chan, "fps"]) print("Setting %s to %s fps" % (topic, value)) - self.envoy.kv.set(topic, value) + self.envoy.set(topic, value) payload += measurement + "," + tag_key + "=" + tag_value + " " payload += key + "=" + value + "\n" payload=payload[:-1] diff --git a/src/core/kamcore/scripts/fps_monitor_node.py b/src/core/kamcore/scripts/fps_monitor_node.py index 8392f64..1ab296f 100755 --- a/src/core/kamcore/scripts/fps_monitor_node.py +++ b/src/core/kamcore/scripts/fps_monitor_node.py @@ -45,7 +45,7 @@ def init_ros(self): def ingest_event(self, msg): time = msg.gps_time.to_sec() rospy.loginfo("Received event message, time %0.5f." % time) - is_archiving = self.envoy.kv.get("/sys/arch/is_archiving") == "1" + is_archiving = self.envoy.get("/sys/arch/is_archiving") == "1" # Skip the first event, so we don't accidentally report drops if is_archiving and self.previously_archiving: self.evt_queue.append(time) @@ -133,13 +133,13 @@ def update(self): self.processed_times.append(time) - self.envoy.kv.set(f"/sys/arch/{hostname}/rgb/fps", rgb_fps) - self.envoy.kv.set(f"/sys/arch/{hostname}/ir/fps", ir_fps) - self.envoy.kv.set(f"/sys/arch/{hostname}/uv/fps", uv_fps) + self.envoy.set(f"/sys/arch/{hostname}/rgb/fps", rgb_fps) + self.envoy.set(f"/sys/arch/{hostname}/ir/fps", ir_fps) + self.envoy.set(f"/sys/arch/{hostname}/uv/fps", uv_fps) - self.envoy.kv.set(f"/sys/arch/{hostname}/rgb/dropped", self.rgb_drops) - self.envoy.kv.set(f"/sys/arch/{hostname}/ir/dropped", self.ir_drops) - self.envoy.kv.set(f"/sys/arch/{hostname}/uv/dropped", self.uv_drops) + self.envoy.set(f"/sys/arch/{hostname}/rgb/dropped", self.rgb_drops) + self.envoy.set(f"/sys/arch/{hostname}/ir/dropped", self.ir_drops) + self.envoy.set(f"/sys/arch/{hostname}/uv/dropped", self.uv_drops) def main(): diff --git a/src/core/roskv/CMakeLists.txt b/src/core/roskv/CMakeLists.txt index 816f92b..18d3bc8 100644 --- a/src/core/roskv/CMakeLists.txt +++ b/src/core/roskv/CMakeLists.txt @@ -15,7 +15,6 @@ find_package(catkin REQUIRED COMPONENTS roscpp ) find_package(nlohmann_json REQUIRED) -find_package(fmt REQUIRED) find_path(HIREDIS_HEADER hiredis) find_path(REDIS_PLUS_PLUS_HEADER sw) find_library(HIREDIS_LIB hiredis) @@ -65,21 +64,17 @@ include_directories(include ${Boost_INCLUDE_DIR} ${catkin_INCLUDE_DIRS} ${roscpp add_library(roskv include/roskv/envoy.h include/roskv/archiver.h - include/roskv/roskv.h libroskv/envoy.cpp libroskv/archiver.cpp - libroskv/roskv.cpp ) add_executable(test_roskv libroskv/test_roskv.cpp) target_link_libraries(roskv - fmt::fmt ${catkin_LIBRARIES} ${nlohmann_json_LIBRARIES} ${HIREDIS_LIB} ${REDIS_PLUS_PLUS_LIB}) target_link_libraries(test_roskv - fmt::fmt ${catkin_LIBRARIES} ${nlohmann_json_LIBRARIES} ${HIREDIS_LIB} @@ -140,5 +135,4 @@ install( # catkin_add_nosetests(test) cmake_print_variables(PROJECT_NAME) cmake_print_variables(CATKIN_PACKAGE_INCLUDE_DESTINATION catkin_LIBRARIES) -cmake_print_variables(fmt_FOUND FMT_HEADER FMT_LIB fmt_LIBRARIES) cmake_print_variables(nlohmann_json_LIBRARIES REDIS_PLUS_PLUS_HEADER REDIS_PLUS_PLUS_LIB) diff --git a/src/core/roskv/include/roskv/archiver.h b/src/core/roskv/include/roskv/archiver.h index 5d59c60..bf3c69e 100644 --- a/src/core/roskv/include/roskv/archiver.h +++ b/src/core/roskv/include/roskv/archiver.h @@ -8,17 +8,14 @@ #include #include -#include -#include -#include -#include +#include +#include #include #include inline std::string isoformat_u(time_t tv_sec, long tv_nsec); using namespace sw; -namespace fs = boost::filesystem; namespace json = nlohmann; /** Gets attributes (modality/fov) about a camera from the environment */ @@ -39,18 +36,7 @@ namespace FormatterHelper { inline std::string applyFormat(const std::string &fmtr, const json::json &kwargs); - - std::string generateFilename(RedisEnvoy &envoy, const std::string &ext); -// fetchArchiveKwargs(_key); -// std::string fmtr = _kwargs["template"]; -// std::string stime = boost::posix_time::to_iso_string(time); -// stime[8] = '_'; -// _kwargs["time"] = stime; -// _kwargs["ext"] = ext; -// auto tmp = FormatterHelper::conformKwargsToFormatter(fmtr, _kwargs); -// return FormatterHelper::applyFormat(fmtr, tmp); - }; class ArchiverOpts { @@ -90,7 +76,7 @@ class ArchiverFormatter { bool fetchKwargs(); /** \brief Emit a filename based on the timestamp */ - std::string generateFilename(const boost::posix_time::ptime &time, const std::string &ext); + std::string generateFilename(const std::chrono::system_clock::time_point &tp, const std::string &ext); std::string generateFilename(const std::string &ext); json::json kwargs(); diff --git a/src/core/roskv/include/roskv/envoy.h b/src/core/roskv/include/roskv/envoy.h index 33a4280..4f1c0be 100644 --- a/src/core/roskv/include/roskv/envoy.h +++ b/src/core/roskv/include/roskv/envoy.h @@ -8,16 +8,13 @@ #include #include +#include #include -#include -#include -#include -#include #include #include using namespace sw; -namespace fs = boost::filesystem; +namespace fs = std::filesystem; namespace json = nlohmann; @@ -55,7 +52,6 @@ namespace RedisHelper { class RedisEnvoyOpts { public: static RedisEnvoyOpts from_env(const std::string &client_name); -// RedisEnvoyOpts(); RedisEnvoyOpts(const RedisEnvoyOpts& opts); RedisEnvoyOpts(const std::string &client_name, const std::string &redis_uri, @@ -70,13 +66,12 @@ std::ostream& operator<<(std::ostream &os, const RedisEnvoyOpts &opts); /** - * \brief Bridge to Redis with health checks + * \brief Bridge to Redis */ class RedisEnvoy { public: static RedisEnvoy from_env(); - /// rule of 5 RedisEnvoy(const RedisEnvoyOpts &opts); @@ -92,26 +87,20 @@ class RedisEnvoy { RedisEnvoy(RedisEnvoy &&) = default; RedisEnvoy& operator=(RedisEnvoy &&) = default; - ~RedisEnvoy(); + ~RedisEnvoy() = default; - /// this is just for very limited access. if you need more, create a separate redis client std::string get(const std::string &key); bool put(const std::string &key, const std::string &val); json::json get_dict(const std::string &key); json::json put_dict(const std::string &key, const json::json &val); - json::json del(const std::string &key); std::string client_name(); std::string echo(const std::string &msg); - protected: - void register_(); - void deregister_(); const std::string client_name_; const std::string redis_uri; const std::string keypath_; redis::Redis rc; - json::json _kwargs; }; diff --git a/src/core/roskv/include/roskv/roskv.h b/src/core/roskv/include/roskv/roskv.h deleted file mode 100644 index ee9ed96..0000000 --- a/src/core/roskv/include/roskv/roskv.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Created by Michael McDermott on 1/8/21. -// - -#ifndef ROSKV_ROSKV_H -#define ROSKV_ROSKV_H - -#include -#include -#include -using namespace sw; - -void hello_roskv(); - -#endif //ROSKV_ROSKV_H diff --git a/src/core/roskv/libroskv/archiver.cpp b/src/core/roskv/libroskv/archiver.cpp index 5db1867..2fc44af 100644 --- a/src/core/roskv/libroskv/archiver.cpp +++ b/src/core/roskv/libroskv/archiver.cpp @@ -3,7 +3,6 @@ // #include -#include #include "roskv/envoy.h" #include "roskv/archiver.h" @@ -42,16 +41,16 @@ Cameratype Cameratype::from_env() { json::json FormatterHelper::conformKwargsToFormatter(const std::string &fmtr, const json::json &kwargs) { - static const boost::regex PAT_get_braced(R"((?<=\{)(\w+)(?=\}))"); + static const std::regex PAT_get_braced(R"(\{(\w+)\})"); // ensure that all the necessary named _kwargs in the template are present in the dict - boost::sregex_iterator m1(fmtr.begin(), fmtr.end(), PAT_get_braced); - boost::sregex_iterator m2; + auto m1 = std::sregex_iterator(fmtr.begin(), fmtr.end(), PAT_get_braced); + auto m2 = std::sregex_iterator(); json::json fmt_kwargs; for (auto el = m1; el != m2; ++el) { auto match = *el; - std::string sval = match.str(); + std::string sval = match[1].str(); // capture group 1 = word inside braces bool has = kwargs.contains(sval); // fmt::print("{}: {}\n", sval, has); if (has) { @@ -65,16 +64,18 @@ json::json FormatterHelper::conformKwargsToFormatter(const std::string &fmtr, co } std::string FormatterHelper::applyFormat(const std::string &fmtr, const json::json &kwargs, bool partial) { - fmt::dynamic_format_arg_store store; - for (auto &el : kwargs.items()) { - std::string key = el.key(); - std::string val = el.value(); -// fmt::print("pushing {}: {}\n", _key, val); - store.push_back(fmt::arg(key.c_str(), val.c_str())); + static const std::regex placeholder(R"(\{(\w+)\})"); + std::string out; + std::size_t last_pos = 0; + auto begin = std::sregex_iterator(fmtr.begin(), fmtr.end(), placeholder); + for (auto it = begin; it != std::sregex_iterator(); ++it) { + const auto &match = *it; + out += fmtr.substr(last_pos, match.position() - last_pos); + std::string key = match[1].str(); + out += kwargs.contains(key) ? std::string(kwargs[key]) : match[0].str(); + last_pos = match.position() + match.length(); } - - auto out = std::string(fmt::vformat(fmtr, store)); - /// Optionally convert the parens to braces e.g. to allow partial application + out += fmtr.substr(last_pos); if (partial) { std::replace(out.begin(), out.end(), '(', '{'); std::replace(out.begin(), out.end(), ')', '}'); @@ -157,11 +158,14 @@ bool ArchiverFormatter::fetchKwargs() { return true; } -std::string ArchiverFormatter::generateFilename(const boost::posix_time::ptime &time, const std::string &ext) { +std::string ArchiverFormatter::generateFilename(const std::chrono::system_clock::time_point &tp, const std::string &ext) { fetchKwargs(); std::string fmtr = _kwargs["template"]; - std::string stime = boost::posix_time::to_iso_string(time); - stime[8] = '_'; + auto duration = tp.time_since_epoch(); + auto secs = std::chrono::duration_cast(duration); + auto nsecs = std::chrono::duration_cast(duration) - + std::chrono::duration_cast(secs); + std::string stime = isoformat_u(static_cast(secs.count()), nsecs.count()); _kwargs["time"] = stime; _kwargs["ext"] = ext; auto tmp = FormatterHelper::conformKwargsToFormatter(fmtr, _kwargs); @@ -169,8 +173,7 @@ std::string ArchiverFormatter::generateFilename(const boost::posix_time::ptime & } std::string ArchiverFormatter::generateFilename(const std::string &ext) { - auto now = boost::posix_time::microsec_clock::universal_time(); - return generateFilename(now, ext); + return generateFilename(std::chrono::system_clock::now(), ext); } json::json ArchiverFormatter::kwargs() { diff --git a/src/core/roskv/libroskv/envoy.cpp b/src/core/roskv/libroskv/envoy.cpp index 7dc13f2..60629fe 100644 --- a/src/core/roskv/libroskv/envoy.cpp +++ b/src/core/roskv/libroskv/envoy.cpp @@ -1,6 +1,5 @@ #include #include -#include #include "roskv/envoy.h" @@ -37,7 +36,7 @@ namespace RedisHelper { } std::vector keys; while (true) { - cursor = rc.scan(cursor, key_ + '*', 20, std::inserter(keys, keys.begin())); + cursor = rc.scan(cursor, key_ + '*', 20, std::back_inserter(keys)); if (cursor == 0) { break; } @@ -139,8 +138,8 @@ RedisEnvoyOpts RedisEnvoyOpts::from_env(const std::string &client_name) { std::string scfg; std::string arch_key; if (env_cfg_file && env_cfg_file[0]) { - boost::filesystem::path cfg_path{env_cfg_file}; - if (!boost::filesystem::exists(cfg_path)) { + fs::path cfg_path{env_cfg_file}; + if (!fs::exists(cfg_path)) { std::cerr << "Warning: specified ENVOY_CFG_PATH but does not exist: " << cfg_path << std::endl; } else { std::ifstream ifs(cfg_path.string()); @@ -201,11 +200,6 @@ RedisEnvoy::RedisEnvoy(const std::string &client_name, std::cerr << "DEPRECATED RedisEnvoy " << client_name << " created at " << redis_uri; } -RedisEnvoy::~RedisEnvoy() { -// logr << "~Envoy dtor" << endl; -// rc.~Redis(); -} - RedisEnvoy RedisEnvoy::from_env() { return EnvoyHelper::from_env(); } @@ -240,14 +234,6 @@ std::string RedisEnvoy::echo(const std::string &msg) { return out; } -void RedisEnvoy::register_() { - -} -void RedisEnvoy::deregister_() { - -} - - namespace EnvoyHelper { RedisEnvoy from_env() { const char *env_name = std::getenv("ENVOY_NAME"); diff --git a/src/core/roskv/libroskv/roskv.cpp b/src/core/roskv/libroskv/roskv.cpp deleted file mode 100644 index d3e860c..0000000 --- a/src/core/roskv/libroskv/roskv.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// -// Created by Michael McDermott on 1/8/21. -// - -#include "roskv/roskv.h" - -void hello_roskv() { - std::cout << "Hello ROS_KV!" << std::endl; -} diff --git a/src/core/roskv/noros-setup.py b/src/core/roskv/noros-setup.py index 9e8ea45..3db6485 100644 --- a/src/core/roskv/noros-setup.py +++ b/src/core/roskv/noros-setup.py @@ -2,7 +2,7 @@ from setuptools import find_packages, setup packages = find_packages() -deps = ["typing", "six", "enum34", "pytz", "python-dateutil", "boltons", "redis", "benedict"] +deps = ["typing", "enum34", "pytz", "python-dateutil", "boltons", "redis"] setup( name="roskv", diff --git a/src/core/roskv/scripts/roskv b/src/core/roskv/scripts/roskv index 404bc40..c01f24c 100755 --- a/src/core/roskv/scripts/roskv +++ b/src/core/roskv/scripts/roskv @@ -8,7 +8,7 @@ import json import yaml from roskv.impl.redis_envoy import RedisEnvoy, redis_encode -from vprint import vprint + def menu_parser(description="roskv interface"): import argparse @@ -21,18 +21,19 @@ def menu_parser(description="roskv interface"): parser.add_argument("-i", "--input_uri", default=None, action="store", type=str, help="an input file path") parser.add_argument('val', nargs='?', default=None, type=str, help="Value to be set") parser.add_argument("-H", "--host", default="nuvo0", action="store", type=str, help="redis host") - parser.add_argument("-D", "--debug", action="store_true", help="Start in debug mode") return parser -def load_dict(input_uri, read_in=False): - # type: (str, bool) -> dict +def load_dict(input_uri, read_in=False, debug=False): + # type: (str, bool, bool) -> dict if read_in: - vprint("reading stdin") + if debug: + print("reading stdin") return json.load(sys.stdin) - vprint('loading {}'.format(input_uri)) + if debug: + print('loading {}'.format(input_uri)) ext = os.path.splitext(input_uri)[1] if ext == '.json': with open(input_uri, 'r') as fp: @@ -67,17 +68,16 @@ def do_put(key, val, envoy, dry_run=False): tups = redis_encode(key, val) for line in format_tups(tups): print(line) - return envoy.put(key, val) - return do_get(key, envoy) def main(): parser = menu_parser() args = parser.parse_args() - vprint(args) + if args.debug: + print(args) envoy = RedisEnvoy(args.host, client_name="roskv") if args.get: @@ -85,7 +85,7 @@ def main(): elif args.set: if args.input_uri or args.read: - val = load_dict(args.input_uri, args.read) + val = load_dict(args.input_uri, args.read, args.debug) else: val = args.val do_put(args.set, val, envoy, args.dry_run) diff --git a/src/core/roskv/setup.py b/src/core/roskv/setup.py index 36ec314..25e3d9e 100755 --- a/src/core/roskv/setup.py +++ b/src/core/roskv/setup.py @@ -3,11 +3,7 @@ from catkin_pkg.python_setup import generate_distutils_setup deps = [ - "python-benedict==0.23.2", - "python-fsutil==0.4.0", - "python-slugify==4.0.1", "typing", - "six", ] # this function uses information from package.xml to populate dict @@ -18,7 +14,7 @@ install_requires=deps, # entry_points={"console_scripts": ["roskv=roskv.client:main"]}, scripts=["scripts/roskv"], - extras_require={"consul": ["python-consul"], "redis": ["redis"]}, + extras_require={"redis": ["redis"]}, ) setup(**d) diff --git a/src/core/roskv/src/roskv/base.py b/src/core/roskv/src/roskv/base.py index 60a87f6..b7a25c0 100644 --- a/src/core/roskv/src/roskv/base.py +++ b/src/core/roskv/src/roskv/base.py @@ -1,9 +1,5 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- -""" -API and some documentation stubs are liberally cribbed from cablehead/python-consul, MIT License -https://github.com/cablehead/python-consul -""" from typing import Union, Tuple, List, Dict from abc import abstractmethod, ABCMeta @@ -20,85 +16,6 @@ def __str__(self): _default = NullDefault() -class Getter: - """Interface for HTTP GET - The GET method requests a representation of the specified resource. Requests using GET should only retrieve data. - """ - - __metaclass__ = ABCMeta - - @abstractmethod - def get(self, key, default=_default, **kwargs): - # type: (str, Jsonable, Jsonable) -> Jsonable - pass - - -class Header: - """Interface for HTTP HEAD - The HEAD method asks for a response identical to that of a GET request, but without the response body. - """ - - __metaclass__ = ABCMeta - - @abstractmethod - def head(self, key, default=_default, **kwargs): - # type: (str, Jsonable, Jsonable) -> Union[dict, str] - pass - - -class Putter: - """Interface for HTTP PUT - The PUT method replaces all current representations of the target resource with the request payload. - """ - - __metaclass__ = ABCMeta - - @abstractmethod - def put(self, key, val, **kwargs): - # type: (str, Jsonable, Jsonable) -> Union[int, bool, str] - pass - - -class Poster: - """Interface for HTTP POST - The POST method is used to submit an entity to the specified resource, often causing a change in state or side - effects on the server. - """ - - __metaclass__ = ABCMeta - - @abstractmethod - def post(self, key, params, **kwargs): - # type: (str, dict, Jsonable) -> Union[int, bool, str] - pass - - -class Patcher: - """Interface for HTTP PATCH - The PATCH method is used to apply partial modifications to a resource. - """ - - __metaclass__ = ABCMeta - - @abstractmethod - def patch(self, key, params, **kwargs): - # type: (str, dict, Jsonable) -> Union[int, bool, str] - pass - - -class Deleter: - """Interface for HTTP DELETE - The DELETE method deletes the specified resource. - """ - - __metaclass__ = ABCMeta - - @abstractmethod - def delete(self, key, **kwargs): - # type: (str, Jsonable) -> Union[int, bool, str] - pass - - class Monostack(object): """A stack with 0 or 1 objects""" @@ -143,330 +60,26 @@ def unhealthy(self): self.set_health("critical") -class KV(Getter, Putter, Deleter): +class KV: """Interface for a bare-bones key-value store""" __metaclass__ = ABCMeta - -class Health(object): - __metaclass__ = ABCMeta - - @abstractmethod - def service( - self, service, index=None, wait=None, passing=None, tag=None, dc=None, near=None, token=None, node_meta=None - ): - # type: (str, int, str, bool, str, str, str, str, dict) -> Tuple[int, List[Dict]] - """ - Returns a tuple of (*index*, *nodes*) - """ - pass - @abstractmethod - def checks(self, service, index=None, wait=None, dc=None, near=None, token=None, node_meta=None): - # type: (str, int, str, str, str, str, dict) -> Tuple[int, List[Dict]] - """ - Returns a tuple of (*index*, *checks*) with *checks* being the - checks associated with the service. - """ + def get(self, key, default=_default, **kwargs): + # type: (str, Jsonable, Jsonable) -> Jsonable pass @abstractmethod - def state(self, name, index=None, wait=None, dc=None, near=None, token=None, node_meta=None): - # type: (str, int, str, str, str, str, dict) -> Tuple[int, List[Dict]] - """ - Returns a tuple of (*index*, *nodes*) - """ + def put(self, key, val, **kwargs): + # type: (str, Jsonable, Jsonable) -> Union[int, bool, str] pass @abstractmethod - def node(self, node, index=None, wait=None, dc=None, token=None): - # type: (str, int, str, str, str) -> Tuple[int, List[Dict]] - """ - Returns a tuple of (*index*, *checks*) - """ + def delete(self, key, **kwargs): + # type: (str, Jsonable) -> Union[int, bool, str] pass -class Catalog(object): - __metaclass__ = ABCMeta - - def register(self, node, address, service=None, check=None, dc=None, token=None): - raise NotImplementedError() - - def deregister(self, node, service_id=None, check_id=None, dc=None, token=None): - raise NotImplementedError() - - def datacenters(self): - """ - Returns all the datacenters that are known by the Consul server. - """ - raise NotImplementedError("this api is single-datacenter only") - - @abstractmethod - def nodes(self, index=None, wait=None, consistency=None, dc=None, near=None, token=None, node_meta=None): - """ - Returns a tuple of (*index*, *nodes*) of all nodes known - about in the *dc* datacenter. *dc* defaults to the current - datacenter of this agent. - - *index* is the current Consul index, suitable for making subsequent - calls to wait for changes since this query was last run. - Maps to /catalog/nodes - """ - - @abstractmethod - def services(self, index=None, wait=None, consistency=None, dc=None, token=None, node_meta=None): - """ - Returns a tuple of (*index*, *services*) of all services known - about in the *dc* datacenter. *dc* defaults to the current - datacenter of this agent. - - Maps to /catalog/services - """ - - def node(self, node, index=None, wait=None, consistency=None, dc=None, token=None): - """ - Returns a tuple of (*index*, *services*) of all services provided - by *node*. - """ - raise NotImplementedError() - - -class Agent(object): - """ - The Agent endpoints are used to interact with a local Consul agent. - Usually, services and checks are registered with an agent, which then - takes on the burden of registering with the Catalog and performing - anti-entropy to recover from outages. - """ - - __metaclass__ = ABCMeta - - def self(self): - """ - Returns configuration of the local agent and member information. - """ - raise NotImplementedError() - - def services(self): - """ - Returns all the services that are registered with the local agent. - These services were either provided through configuration files, or - added dynamically using the HTTP API. It is important to note that - the services known by the agent may be different than those - reported by the Catalog. This is usually due to changes being made - while there is no leader elected. The agent performs active - anti-entropy, so in most situations everything will be in sync - within a few seconds. - """ - raise NotImplementedError() - - def checks(self): - """ - Returns all the checks that are registered with the local agent. - """ - raise NotImplementedError() - - def members(self, wan=False): - """ - Returns all the members that this agent currently sees. This may - vary by agent, use the nodes api of Catalog to retrieve a cluster - wide consistent view of members. - - For agents running in server mode, setting *wan* to *True* returns - the list of WAN members instead of the LAN members which is - default. - """ - raise NotImplementedError() - - def maintenance(self, enable, reason=None): - raise NotImplementedError("Maintenance mode not implemented") - - def join(self, address, wan=False): - """ - This endpoint instructs the agent to attempt to connect to a - given address. - - *address* is the ip to connect to. - - *wan* is either 'true' or 'false'. For agents running in server - mode, 'true' causes the agent to attempt to join using the WAN - pool. Default is 'false'. - """ - raise NotImplementedError() - - def force_leave(self, node): - """ - This endpoint instructs the agent to force a node into the left - state. If a node fails unexpectedly, then it will be in a failed - state. Once in the failed state, Consul will attempt to reconnect, - and the services and checks belonging to that node will not be - cleaned up. Forcing a node into the left state allows its old - entries to be removed. - - *node* is the node to change state for. - """ - raise NotImplementedError() - - -class Service(object): - __metaclass__ = ABCMeta - - def register( - self, - name, - service_id=None, - address=None, - port=None, - tags=None, - check=None, - token=None, - # *deprecated* use check parameter - script=None, - interval=None, - ttl=None, - http=None, - timeout=None, - enable_tag_override=False, - ): - """ - Add a new service to the local agent. There is more - documentation on services - `here `_. - - *name* is the name of the service. - - If the optional *service_id* is not provided it is set to - *name*. You cannot have duplicate *service_id* entries per - agent, so it may be necessary to provide one. - - *address* will default to the address of the agent if not - provided. - - An optional health *check* can be created for this service is - one of `Check.script`_, `Check.http`_, `Check.tcp`_, - `Check.ttl`_ or `Check.docker`_. - - *token* is an optional `ACL token`_ to apply to this request. - Note this call will return successful even if the token doesn't - have permissions to register this service. - - *script*, *interval*, *ttl*, *http*, and *timeout* arguments - are deprecated. use *check* instead. - - *enable_tag_override* is an optional bool that enable you - to modify a service tags from servers(consul agent role server) - Default is set to False. - This option is only for >=v0.6.0 version on both agent and - servers. - for more information - https://www.consul.io/docs/agent/services.html - """ - raise NotImplementedError() - - def deregister(self, service_id): - """ - Used to remove a service from the local agent. The agent will - take care of deregistering the service with the Catalog. If - there is an associated check, that is also deregistered. - """ - raise NotImplementedError() - - def maintenance(self, service_id, enable, reason=None): - """ - The service maintenance endpoint allows placing a given service - into "maintenance mode". - - *service_id* is the id of the service that is to be targeted - for maintenance. - - *enable* is either 'true' or 'false'. 'true' enables - maintenance mode, 'false' disables maintenance mode. - - *reason* is an optional string. This is simply to aid human - operators. - """ - - raise NotImplementedError() - - -class Check(object): - __metaclass__ = ABCMeta - - def register( - self, - name, - check=None, - check_id=None, - notes=None, - service_id=None, - token=None, - script=None, - interval=None, - ttl=None, - http=None, - timeout=None, - ): - """ - Register a new check with the local agent. More documentation - on checks can be found `here - `_. - - *name* is the name of the check. - - *check* is one of `Check.script`_, `Check.http`_, `Check.tcp`_ - `Check.ttl`_ or `Check.docker`_ and is required. - - If the optional *check_id* is not provided it is set to *name*. - *check_id* must be unique for this agent. - - *notes* is not used by Consul, and is meant to be human - readable. - - Optionally, a *service_id* can be specified to associate a - registered check with an existing service. - - *token* is an optional `ACL token`_ to apply to this request. - Note this call will return successful even if the token doesn't - have permissions to register this check. - - *script*, *interval*, *ttl*, *http*, and *timeout* arguments - are deprecated. use *check* instead. - - Returns *True* on success. - """ - raise NotImplementedError() - - def deregister(self, check_id): - """ - Remove a check from the local agent. - """ - raise NotImplementedError() - - def ttl_pass(self, check_id, notes=None): - """ - Mark a ttl based check as passing. Optional notes can be - attached to describe the status of the check. - """ - raise NotImplementedError() - - def ttl_fail(self, check_id, notes=None): - """ - Mark a ttl based check as failing. Optional notes can be - attached to describe why check is failing. The status of the - check will be set to critical and the ttl clock will be reset. - """ - raise NotImplementedError() - - def ttl_warn(self, check_id, notes=None): - """ - Mark a ttl based check with warning. Optional notes can be - attached to describe the warning. The status of the - check will be set to warn and the ttl clock will be reset. - """ - raise NotImplementedError() - - class BaseEnvoy(KV): __metaclass__ = ABCMeta diff --git a/src/core/roskv/src/roskv/client.py b/src/core/roskv/src/roskv/client.py index 4703344..97f979a 100644 --- a/src/core/roskv/src/roskv/client.py +++ b/src/core/roskv/src/roskv/client.py @@ -2,10 +2,7 @@ # -*- coding: utf-8 -*- from __future__ import division, print_function -import os import sys -from benedict import benedict -import threading import rospy diff --git a/src/core/roskv/src/roskv/clients/redis_envoy_client.py b/src/core/roskv/src/roskv/clients/redis_envoy_client.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/core/roskv/src/roskv/compat.py b/src/core/roskv/src/roskv/compat.py deleted file mode 100644 index 4984a1c..0000000 --- a/src/core/roskv/src/roskv/compat.py +++ /dev/null @@ -1,10 +0,0 @@ -from six import PY2, PY3 - -if PY2: - JSONDecodeError = ValueError - -elif PY3: - from json import JSONDecodeError - -else: - raise RuntimeError("Unknown python version") diff --git a/src/core/roskv/src/roskv/impl/consul_kv.py b/src/core/roskv/src/roskv/impl/consul_kv.py deleted file mode 100644 index b5eb8e1..0000000 --- a/src/core/roskv/src/roskv/impl/consul_kv.py +++ /dev/null @@ -1,97 +0,0 @@ -import json -from typing import Any -from collections import Mapping - -from benedict import benedict -from six import string_types, binary_type -import consul -from roskv.base import KV, NullDefault, Jsonable - -from src.core.roskv.src.roskv.util import demux_consul - -_default = NullDefault() - - -class ConsulKV(KV): - def __init__( - self, - host="127.0.0.1", - port=8500, - token=None, - scheme="http", - consistency="default", - dc=None, - verify=True, - cert=None, - ): - self.c = consul.Consul( - host=host, port=port, token=token, scheme=scheme, consistency=consistency, dc=dc, verify=verify, cert=cert - ) - - def get(self, key, default=_default, **kwargs): - """ - Consul will return a None if empty, but ROS throws a KeyError here. We shall do the same. - - - consul.kv.get Returns a tuple of (*index*, *value[s]*) - - *index* is the current Consul index, suitable for making subsequent - calls to wait for changes since this query was last run. - - value is a dict with some additional Consul metadata that this interface doesn't really care about: - {u'CreateIndex': 58, - u'Flags': 0, - u'Key': u'foo', - u'LockIndex': 0, - u'ModifyIndex': 58, - u'Value': 'spam'} - - :param key: - :param default: - :param kwargs: - :return: - """ - return self._get_mux(key, default, **kwargs) - - def _get_mux(self, key, default=_default, **kwargs): - # type: (str, Any, Any) -> Jsonable - key = key.strip('/') - index, box_values = self.c.kv.get(key=key, recurse=True, **kwargs) - if box_values is None: - if _default is _default: - raise KeyError(key) - else: - return _default - - return demux_consul(box_values, key) - - def put(self, key, val, **kwargs): - """ - Insert value into KV. - Todo: ROS param allows passing nests. These can be unrolled using benedict. For now, just dump to json as PoC - - Consul's put interface returns True on success. Not sure best way to handle it so just returning as is. - :param key: - :param val: - :param kwargs: - :return: - """ - key = key.strip('/') - if isinstance(val, Mapping): - bd = benedict(val).flatten(separator='/') - for k, v in bd.items(): - self._put(key + '/' + k, v, **kwargs) - return True - - else: - return self._put(key, val, **kwargs) - - def _put(self, key, val, **kwargs): - if not isinstance(val, (string_types, binary_type)): - val = json.dumps(val) - - return self.c.kv.put(key, val, **kwargs) - - def delete(self, key, **kwargs): - key = key.strip('/') - return self.c.kv.delete(key, **kwargs) diff --git a/src/core/roskv/src/roskv/impl/consul_ros_mirror.py b/src/core/roskv/src/roskv/impl/consul_ros_mirror.py deleted file mode 100644 index 3a28b20..0000000 --- a/src/core/roskv/src/roskv/impl/consul_ros_mirror.py +++ /dev/null @@ -1,38 +0,0 @@ -from roskv.base import KV, NullDefault -from roskv.impl.rosparam_kv import RosParamKV -from roskv.impl.consul_kv import ConsulKV - - -_default = NullDefault() - - -class ConsulRosMirrorKV(KV): - """Uses rosparam as backing store but mirrors to consul. Consul is 100% a follower. - This is mostly for PoC - """ - def __init__( - self, - host="127.0.0.1", - port=8500, - token=None, - scheme="http", - consistency="default", - dc=None, - verify=True, - cert=None, - ): - self.ckv = ConsulKV( - host=host, port=port, token=token, scheme=scheme, consistency=consistency, dc=dc, verify=verify, cert=cert - ) - self.rkv = RosParamKV() - - def get(self, key, default=_default, **kwargs): - return self.rkv.get(key, _default, **kwargs) - - def put(self, key, val, **kwargs): - self.ckv.put(key, val, **kwargs) - return self.rkv.put(key, val, **kwargs) - - def delete(self, key, **kwargs): - self.ckv.delete(key, **kwargs) - return self.rkv.delete(key, **kwargs) diff --git a/src/core/roskv/src/roskv/impl/redis_envoy.py b/src/core/roskv/src/roskv/impl/redis_envoy.py index 13d0693..c37c54d 100755 --- a/src/core/roskv/src/roskv/impl/redis_envoy.py +++ b/src/core/roskv/src/roskv/impl/redis_envoy.py @@ -1,574 +1,20 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- from __future__ import division, print_function -from typing import Any, Union, List, Mapping, Tuple, Dict -import sys +from typing import Any, Union, Dict import json import time -from six import string_types, binary_type import redis -from benedict import benedict -from roskv.base import ( - BaseEnvoy, - KV, - Health, - NullDefault, - Jsonable, - Agent, - Catalog, - Check, - Service, - ChildService, -) +from roskv.base import BaseEnvoy, KV, NullDefault, Jsonable, ChildService from roskv.util import redis_decode, redis_encode, loader23 _default = NullDefault() -class RedisKV(redis.client.Redis, KV): - """Redis-based key-value store""" - - def __init__(self, agent_name, cfgdict): - self.agent_name = agent_name - super(RedisKV, self).__init__(**cfgdict) - - def get(self, key, default=_default, **kwargs): - # type: (str, Jsonable, Any) -> Jsonable - """ - Get a single value from a keypath. - - Automatically tries to deserialize from json, skipping on failure. - - :param key: key - :param default: Default value if key not found - :param kwargs: Not currently used - :return: data dict at key - """ - maybe_keys = self.keys(key) - if len(maybe_keys) == 1: - val = super(RedisKV, self).get(key, **kwargs) - return loader23(val) - return self.get_dict(key, default=default, **kwargs) - - def get_dict(self, key, default=_default, flatten=False, **kwargs): - # type: (str, Jsonable, bool, Any) -> Jsonable - """ - Get a nested value from a keypath. - - This may be deprecated in favor of overloading `get` - - Automatically tries to deserialize from json, skipping on failure. - - :param key: key or keypath prefix - :param default: Not currently implemented - :param kwargs: Not currently used - :return: data dict at keypath - """ - # key = key.strip("/") - keys = self.keys(key + "*") - if not keys: - if default is _default: - raise KeyError(key) - else: - return default - p = self.pipeline() - for k in keys: - p.get(k) - - vals = p.execute() - as_json = kwargs.get("as_json", True) - return redis_decode(keys, vals, key, flatten, as_json) - - def put(self, key, val, **kwargs): - # type: (str, Union[Any, Dict], Any) -> bool - """ - Insert value into KV. If the val is a dict, automatically flatten and insert the keypath/value sequence. - Automatically tries to serialize acceptable types to json. - - Consul's put interface returns True on success. Not sure best way to handle it so just returning as is. - :param key: key or keypath prefix - :param val: Singular value or dict - :param kwargs: Not currently used - :return: success of transaction - """ - - tups = redis_encode(key, val) - if len(tups) == 0: - return self.set(key, val, **kwargs) - - p = self.pipeline() - for pair in tups: - p.set(pair[0], pair[1]) - - res = p.execute() - return res - - def _put(self, key, val, **kwargs): - if not isinstance(val, (string_types, binary_type)): - val = json.dumps(val) - - return self.set(key, val, **kwargs) - - def delete(self, key, **kwargs): - # key = key.strip("/") - return super(RedisKV, self).delete(key, **kwargs) - - def delete_dict(self, key, **kwargs): - print("deleting {}".format(key)) - # key = key.strip("/") - keys = self.keys(key + "*") - if not keys: - raise KeyError(key) - - p = self.pipeline() - for k in keys: - p.delete(k) - - vals = p.execute() - return vals - - -class RedisHealth(Health): - """Redis-based health checks""" - - def __init__(self, agent_name, kv): - # type: (str, RedisEnvoy) -> None - self.agent_name = agent_name - self.kv = kv - - def __del__(self): - print("health object destroyed") - - def service( - self, - service, - index=None, - wait=None, - passing=None, - tag=None, - dc=None, - near=None, - token=None, - node_meta=None, - ): - # type: (str, int, str, bool, str, str, str, str, dict) -> Tuple[int, List[Dict]] - """ - Returns a tuple of (*index*, *nodes*) - """ - pass - - def checks( - self, - service, - index=None, - wait=None, - dc=None, - near=None, - token=None, - node_meta=None, - ): - # type: (str, int, str, str, str, str, dict) -> Tuple[int, List[Dict]] - """ - Returns a tuple of (*index*, *checks*) with *checks* being the - checks associated with the service. - """ - pass - - def state( - self, - name, - index=None, - wait=None, - dc=None, - near=None, - token=None, - node_meta=None, - ): - # type: (str, int, str, str, str, str, dict) -> Tuple[int, List[Dict]] - """ - Returns a tuple of (*index*, *nodes*) - """ - pass - - def node(self, node, index=None, wait=None, dc=None, token=None): - # type: (str, int, str, str, str) -> Tuple[int, List[Dict]] - """ - Returns a tuple of (*index*, *checks*) - """ - pass - - -class RedisAgent(Agent): - """Corresponds to the local Envoy agent. - Usually, services and checks are registered with an agent, which then - takes on the burden of registering with the Catalog. - - Note, we don't actually have a centralized agent right now, since this is Redis not Consul. - We have to manually manipulate all the checks ourselves. - """ - - def __init__(self, agent_name, kv): - # type: (str, RedisKV) -> None - self.kv = kv - self.service = RedisService(agent_name, kv) - self.check = RedisCheck(agent_name, kv) - self.agent_name = agent_name - self._auto_name = agent_name + "_autoservice" - self._registered = False - self._auto_register() - - def __del__(self): - print("agent destructor: {}".format(self._auto_name)) - self.close() - - def _auto_register(self): - self.service.register(self._auto_name) - print(" registered: {}".format(self._auto_name)) - self._registered = True - - def _auto_deregister(self): - try: - if self._registered: - print("deregistered: {}".format(self._auto_name)) - self.service.deregister(self._auto_name) - except KeyError: - pass # ignore keyerror if something else cleaned it up - self._registered = False - - def close(self): - self._auto_deregister() - - def self(self): - """ - Returns configuration of the local agent and member information. - """ - return self.kv.info() - - def set_health(self, status): - """Mark this node as healthy""" - key = "health/checks/{}/{}".format(self.agent_name, self._auto_name) - val = {"Status": status, "time": time.time()} - return self.kv.put(key, val) - - def services(self): - """ - Returns all the services that are registered with the local agent. - These services were either provided through configuration files, or - added dynamically using the HTTP API. It is important to note that - the services known by the agent may be different than those - reported by the Catalog. This is usually due to changes being made - while there is no leader elected. The agent performs active - anti-entropy, so in most situations everything will be in sync - within a few seconds. - - Note, this excludes the envoy service itself in the response. - - '/v1/agent/services' - """ - return self.kv.get_dict("/catalog/services") - - def checks(self): - """ - Returns all the checks that are registered with the local agent. - """ - raise NotImplementedError() - - def members(self, wan=False): - """ - Returns all the members that this agent currently sees. This may - vary by agent, use the nodes api of Catalog to retrieve a cluster - wide consistent view of members. - - For agents running in server mode, setting *wan* to *True* returns - the list of WAN members instead of the LAN members which is - default. - """ - return self.kv.client_list() - - def maintenance(self, enable, reason=None): - raise NotImplementedError("Maintenance mode not implemented") - - def join(self, address, wan=False): - """ - This endpoint instructs the agent to attempt to connect to a - given address. - - *address* is the ip to connect to. - - *wan* is either 'true' or 'false'. For agents running in server - mode, 'true' causes the agent to attempt to join using the WAN - pool. Default is 'false'. - """ - raise NotImplementedError() - - def force_leave(self, node): - """ - This endpoint instructs the agent to force a node into the left - state. If a node fails unexpectedly, then it will be in a failed - state. Once in the failed state, Consul will attempt to reconnect, - and the services and checks belonging to that node will not be - cleaned up. Forcing a node into the left state allows its old - entries to be removed. - - *node* is the node to change state for. - """ - raise NotImplementedError() - - -class RedisCatalog(Catalog): - """This catalog is formed by aggregating information submitted by the agents. The catalog maintains the - high-level view of the cluster, including which services are available, which nodes run those services, - health information, and more.""" - - def __init__(self, agent_name, kv): - self.agent_name = agent_name - self.kv = kv - - def register(self, node, address, service=None, check=None, dc=None, token=None): - """ - A low level mechanism for directly registering or updating entries - in the catalog. It is usually recommended to use - agent.service.register and agent.check.register, as they are - simpler and perform anti-entropy. - - '/v1/catalog/register' - """ - raise NotImplementedError() - - def deregister(self, node, service_id=None, check_id=None, dc=None, token=None): - """ - A low level mechanism for directly removing entries in the catalog. - It is usually recommended to use the agent APIs, as they are - simpler and perform anti-entropy. - - '/v1/catalog/deregister' - """ - raise NotImplementedError() - - def datacenters(self): - raise NotImplementedError("this api is single-datacenter only") - - def nodes( - self, - index=None, - wait=None, - consistency=None, - dc=None, - near=None, - token=None, - node_meta=None, - ): - """ - Returns a tuple of (*index*, *nodes*) of all nodes known - about in the *dc* datacenter. *dc* defaults to the current - datacenter of this agent. - - *index* is the current Consul index, suitable for making subsequent - calls to wait for changes since this query was last run. - Maps to /v1/catalog/nodes - """ - - def services( - self, - index=None, - wait=None, - consistency=None, - dc=None, - token=None, - node_meta=None, - ): - """ - Returns a tuple of (*index*, *services*) of all services known - about in the *dc* datacenter. *dc* defaults to the current - datacenter of this agent. - - Maps to /v1/catalog/services - """ - - def node(self, node, index=None, wait=None, consistency=None, dc=None, token=None): - """ - Returns a tuple of (*index*, *services*) of all services provided - by *node*. - """ - raise NotImplementedError() - - -class RedisService(Service): - def __init__(self, agent_name, kv): - # type: (str, RedisKV) -> None - self.agent_name = agent_name - self.kv = kv - - def register( - self, - name, - service_id=None, - address=None, - port=None, - tags=None, - check=None, - token=None, - # *deprecated* use check parameter - script=None, - interval=None, - ttl=None, - http=None, - timeout=None, - enable_tag_override=False, - ): - """ - Add a new service to the local agent. There is more - documentation on services - `here `_. - - *name* is the name of the service. - - If the optional *service_id* is not provided it is set to - *name*. You cannot have duplicate *service_id* entries per - agent, so it may be necessary to provide one. - - *address* will default to the address of the agent if not - provided. - - An optional health *check* can be created for this service is - one of `Check.script`_, `Check.http`_, `Check.tcp`_, - `Check.ttl`_ or `Check.docker`_. - - *token* is an optional `ACL token`_ to apply to this request. - Note this call will return successful even if the token doesn't - have permissions to register this service. - - *script*, *interval*, *ttl*, *http*, and *timeout* arguments - are deprecated. use *check* instead. - - *enable_tag_override* is an optional bool that enable you - to modify a service tags from servers(consul agent role server) - Default is set to False. - This option is only for >=v0.6.0 version on both agent and - servers. - for more information - https://www.consul.io/docs/agent/services.html - - Example response from c.agent.services(): - 'fooid': {'ID': 'fooid', - 'Service': 'fooname', - 'Tags': ['footag'], - 'Meta': {}, - 'Port': 8500, - 'Address': 'localhost', - 'Weights': {'Passing': 1, 'Warning': 1}, - 'EnableTagOverride': False} - """ - if service_id is None: - service_id = name - key = "agent/{}/services/{}".format(self.agent_name, service_id) - val = { - "ID": service_id, - "Service": name, - "ttl": ttl, - } - - return self.kv.put(key, val) - - def deregister(self, service_id): - """ - Used to remove a service from the local agent. The agent will - take care of deregistering the service with the Catalog. If - there is an associated check, that is also deregistered. - """ - key = "agent/{}/services/{}".format(self.agent_name, service_id) - return self.kv.delete_dict(key) - - def maintenance(self, service_id, enable, reason=None): - raise NotImplementedError("not used") - - -class RedisCheck(Check): - def __init__(self, agent_name, kv): - self.agent_name = agent_name - self.kv = kv - - def register( - self, - name, - check=None, - check_id=None, - notes=None, - service_id=None, - token=None, - script=None, - interval=None, - ttl=None, - http=None, - timeout=None, - ): - """ - Register a new check with the local agent. More documentation - on checks can be found `here - `_. - - *name* is the name of the check. - - *check* is one of `Check.script`_, `Check.http`_, `Check.tcp`_ - `Check.ttl`_ or `Check.docker`_ and is required. - - If the optional *check_id* is not provided it is set to *name*. - *check_id* must be unique for this agent. - - *notes* is not used by Consul, and is meant to be human - readable. - - Optionally, a *service_id* can be specified to associate a - registered check with an existing service. - - *token* is an optional `ACL token`_ to apply to this request. - Note this call will return successful even if the token doesn't - have permissions to register this check. - - *script*, *interval*, *ttl*, *http*, and *timeout* arguments - are deprecated. use *check* instead. - - Returns *True* on success. - """ - raise NotImplementedError("work in progress") - - def deregister(self, check_id): - """ - Remove a check from the local agent. - """ - raise NotImplementedError("work in progress") - - def ttl_pass(self, check_id, notes=None): - """ - Mark a ttl based check as passing. Optional notes can be - attached to describe the status of the check. - """ - raise NotImplementedError("work in progress") - - def ttl_fail(self, check_id, notes=None): - """ - Mark a ttl based check as failing. Optional notes can be - attached to describe why check is failing. The status of the - check will be set to critical and the ttl clock will be reset. - """ - raise NotImplementedError("work in progress") - - def ttl_warn(self, check_id, notes=None): - """ - Mark a ttl based check with warning. Optional notes can be - attached to describe the warning. The status of the - check will be set to warn and the ttl clock will be reset. - """ - raise NotImplementedError("work in progress") - - -class RedisEnvoy(BaseEnvoy): - """Redis-based KV and health checking API interface. Loosely shadows the python-consul interface - KV functions are passed down to this class's namespace for convenience - """ - - __slots__ = ["heartbeat_timer"] +class RedisEnvoy(redis.client.Redis, BaseEnvoy): + """Redis-based key-value store. Extends redis-py directly with ROS-style + nested-key helpers and an auto-generated client name.""" def __init__( self, @@ -603,10 +49,10 @@ def __init__( if client_name is None: from uuid import uuid4 import socket - client_name = socket.gethostname() + "_" + str(uuid4())[:8] - cfgdict = dict( + self.client_name = client_name + super(RedisEnvoy, self).__init__( host=host, port=port, db=db, @@ -636,46 +82,57 @@ def __init__( username=username, ) - self.client_name = client_name - kv = RedisKV(client_name, cfgdict) - self.kv = kv - # self.txn = Consul.Txn(self) - self.agent = RedisAgent(client_name, kv) - self.catalog = RedisCatalog(client_name, kv) - # self.session = Consul.Session(self) - # self.acl = Consul.ACL(self) - # self.status = Consul.Status(self) - # self.query = Consul.Query(self) - # self.coordinate = Consul.Coordinate(self) - # self.operator = Consul.Operator(self) - self.health = RedisHealth(client_name, kv) - def __del__(self): - """This destructor is a little weird and doesn't always trigger correctly""" - print("envoy destructor: {}".format(self.name)) - self.close() + try: + self.close() + except Exception: + pass - def close(self): - self.agent.close() - self.kv.close() + def get(self, key, default=_default, **kwargs): + # type: (str, Jsonable, Any) -> Jsonable + """Get a value by exact key, or a nested dict by keypath prefix. + Automatically tries to deserialize from json.""" + if self.exists(key): + return loader23(super(RedisEnvoy, self).get(key)) + return self.get_dict(key, default=default, **kwargs) def get_dict(self, key, default=_default, flatten=False, **kwargs): - return self.kv.get_dict(key, default, flatten=flatten, **kwargs) - - def get(self, key, default=_default, **kwargs): - return self.kv.get(key, default, **kwargs) + # type: (str, Jsonable, bool, Any) -> Jsonable + """Get a nested dict by keypath prefix. + Automatically tries to deserialize from json.""" + keys = self.keys(key + "*") + if not keys: + if default is _default: + raise KeyError(key) + return default + p = self.pipeline() + for k in keys: + p.get(k) + vals = p.execute() + return redis_decode(keys, vals, key, flatten, kwargs.get("as_json", True)) def put(self, key, val, **kwargs): - return self.kv.put(key, val, **kwargs) + # type: (str, Union[Any, Dict], Any) -> bool + """Insert a value. Dicts are automatically flattened into the keypath.""" + tups = redis_encode(key, val) + if len(tups) == 0: + return self.set(key, val, **kwargs) + p = self.pipeline() + for pair in tups: + p.set(pair[0], pair[1]) + return p.execute() def delete(self, key, **kwargs): - return self.kv.delete(key, **kwargs) + return super(RedisEnvoy, self).delete(key, **kwargs) def delete_dict(self, key, **kwargs): - return self.kv.delete_dict(key, **kwargs) - - def client_list(self): - return self.kv.client_list() + keys = self.keys(key + "*") + if not keys: + raise KeyError(key) + p = self.pipeline() + for k in keys: + p.delete(k) + return p.execute() @property def name(self): @@ -683,17 +140,10 @@ def name(self): class StateService(ChildService): - """A service that just posts some bit of state - todo: merge with RedisService somehow. - """ + """Posts a bit of state along with a health status to Redis.""" def __init__(self, kv, node, name): # type: (KV, str, str) -> None - """ - :param kv: A key-value store object - :param node: Name of node - :param name: Name of service - """ self.node = node self.name = name super(StateService, self).__init__(kv=kv) @@ -703,7 +153,6 @@ def update_state(self, state, status="passing"): self.set_health(status=status) def set_health(self, status): - """Set the current health status along with a bit of state. Use srv.push(state) to load before setting state""" key = "health/checks/{}/{}".format(self.node, self.name) val = {"Status": status, "time": time.time(), "state": self.peek()} return self.kv.put(key, val) @@ -711,7 +160,6 @@ def set_health(self, status): if __name__ == "__main__": import sys - try: addr = sys.argv[1] host, port = addr.split(":") @@ -725,8 +173,7 @@ def set_health(self, status): "nest": {"spam": "eggs", "num": 42, "deep": {"a": 0}}, "a_list": [1, 2, "three"], } - # rc = redis.Redis(host, port) - kv = RedisKV("foo", {"host": host, "port": port}) + kv = RedisEnvoy(host=host, port=port, client_name="foo") print("keys at start: {}".format(len(kv.keys()))) key = "/TEST_DO_NOT_USE" kv.put(key, dd) diff --git a/src/core/roskv/src/roskv/nodes/kvtest.py b/src/core/roskv/src/roskv/nodes/kvtest.py index 40a906a..e00943a 100755 --- a/src/core/roskv/src/roskv/nodes/kvtest.py +++ b/src/core/roskv/src/roskv/nodes/kvtest.py @@ -5,11 +5,6 @@ import rospy from roskv.impl.rosparam_kv import RosParamKV -try: - from roskv.impl.consul_kv import ConsulKV -except ImportError as iexc: - warnings.warn("{}: {}".format(iexc.__class__.__name__, iexc)) - def ros_test(): node = "kvtest" @@ -34,36 +29,13 @@ def ros_test(): kv.put(key, [1, 2, 3]) res = kv.get(key) print("{}: {} ({})".format(key, res, type(res))) - # rospy.spin() - - -def consul_test(): - print('Consul Test') - kv = ConsulKV() - key, val = "foo", "bar_from_kvtest_consul" - x = kv.put(key, val) - res = kv.get(key) - print("{}: {}".format(key, res)) - - key = "foostruct" - val = {"name": "bar_from_kvtest_consul", "nest": {"spam": "eggs", "num": 42}} - x = kv.put(key, val) - res = kv.get(key) - print("{}: {}".format(key, res)) - try: - res = kv.get("foostruct/nest/num") - print("{}: {} ({})".format(key, res, type(res))) - except KeyError: - print('skipping keypath test') - # rospy.spin() def main(): - for func in [ros_test, consul_test]: - try: - func() - except Exception as exc: - warnings.warn("{}: {}: {}".format(func.__name__, exc.__class__.__name__, exc)) + try: + ros_test() + except Exception as exc: + warnings.warn("ros_test: {}: {}".format(exc.__class__.__name__, exc)) if __name__ == "__main__": diff --git a/src/core/roskv/src/roskv/pigeonhole.py b/src/core/roskv/src/roskv/pigeonhole.py deleted file mode 100644 index 7cfa6ed..0000000 --- a/src/core/roskv/src/roskv/pigeonhole.py +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from typing import Any, Callable -import threading -import time -from six.moves.queue import deque, Queue - -from roskv.util import MyTimeoutError - - -class Pigeonhole(object): - """A limited-size deque which can block on waiting for a boolean to evaluate. - This class also functions as a barrier / multi-threaded rendezvous""" - - def __init__(self, maxlen=1): - self._value = None - self._deque = deque(maxlen=maxlen) - self._cond = threading.Condition() - self._release = deque(maxlen=1) - self._release.append(False) - - def release(self, window=0.01): - print('release') - now = time.time() - until = now + window - with self._cond: - self._release.append(until) - self._cond.notify_all() - - def put(self, value): - print('put: {}'.format(value)) - with self._cond: - self._deque.append(value) - self._cond.notify_all() - - def contains(self, value): - with self._cond: - return value in self._deque - - def present(self, value, timeout=None, retries=None): - # type: (Any, float, float) -> bool - """Block/fail until value is present in the pigeonhole""" - return self.wait_for(lambda x: x == value, timeout=timeout, retries=retries) - - def absent(self, value, timeout=None, retries=None): - # type: (Any, float, float) -> bool - """Block/fail until value isn't presently in the pigeonhole""" - attempt = 0 - retries = 1e99 if retries is None else retries - while attempt < retries: - with self._cond: - if value not in self._deque: - return True - self._cond.wait(timeout=timeout) - attempt += 1 - raise MyTimeoutError('Timed out after {} attempts'.format(attempt)) - - def wait_for(self, func, timeout=None, retries=None): - # type: (Any, float, float) -> bool - """Block/fail until `func` evaluates true on at least one element""" - attempt = 0 - retries = 1e99 if retries is None else retries - while attempt < retries: - with self._cond: - out = filter(func, self._deque) - if out: - return True - until_time = self._release[0] - if time.time() < until_time: - return True - self._cond.wait(timeout=timeout) - attempt += 1 - raise MyTimeoutError('Timed out after {} attempts'.format(attempt)) - - - - -class _TestPigeonhole(object): - """A limited-size deque which can block on waiting for the presence or absence of - a value""" - - def __init__(self, maxlen=1): - self._value = None - self._deque = deque(maxlen=maxlen) - self._cond = threading.Condition() - - def put(self, value): - logging.debug('Calling put {}'.format(value)) - with self._cond: - logging.debug('Put: {}'.format(value)) - self._deque.append(value) - self._cond.notify_all() - - def contains(self, value): - with self._cond: - return value in self._deque - - def present(self, value, timeout=None, retries=None): - """Block/fail until value is present in the pigeonhole""" - logging.debug('Call present {}'.format(value)) - attempt = 0 - retries = 1e99 if retries is None else retries - while attempt < retries: - with self._cond: - logging.debug('Attempt {}'.format(attempt)) - if value in self._deque: - logging.debug('Pigeonhole contains {}'.format(value)) - return True - logging.debug('Pigeonhole waiting for {}'.format(value)) - self._cond.wait(timeout=timeout) - attempt += 1 - - raise RuntimeError('ran out after {} attempts'.format(attempt)) - - def absent(self, value): - """Block/fail until value isn't presently in the pigeonhole""" - logging.debug('Call absent {}'.format(value)) - while True: - with self._cond: - if value not in self._deque: - logging.debug('Pigeonhole lacks {}'.format(value)) - return True - logging.debug('Pigeonhole waiting on lack of {}'.format(value)) - self._cond.wait() - - -if __name__ == '__main__': - import time - import logging - - logging.basicConfig(level=logging.DEBUG, - format='(%(threadName)-9s) %(message)s', ) - - - def pigeon_produce(pg, value=5): - logging.debug('Producer thread started {} ...'.format(value)) - pg.put(value) - logging.debug('Producer put value {}...'.format(value)) - - - def pigeon_consume(pg, value=5): - logging.debug('Consumer thread started {}...'.format(value)) - pg.present(value, 0.5, value) - logging.debug('Consumer got value {}...'.format(value)) - - - def pigeon_absent(pg, value=5): - logging.debug('Absent consumer thread started {}...'.format(value)) - pg.absent(value) - logging.debug('Absent consumer got value {}...'.format(value)) - - - def consumer(cv): - logging.debug('Consumer thread started ...') - with cv: - logging.debug('Consumer waiting ...') - cv.wait() - logging.debug('Consumer consumed the resource') - - - def producer(cv): - logging.debug('Producer thread started ...') - with cv: - logging.debug('Making resource available') - logging.debug('Notifying to all consumers') - cv.notifyAll() - - - condition = threading.Condition() - pg = _TestPigeonhole() - pg.put(4) - # cs1 = threading.Thread(name='consumer1', target=consumer, args=(condition,)) - # cs2 = threading.Thread(name='consumer2', target=consumer, args=(condition,)) - # pd = threading.Thread(name='producer', target=producer, args=(condition,)) - pd4 = threading.Thread(name='producer4', target=pigeon_produce, args=(pg, 4)) - pd5 = threading.Thread(name='producer5', target=pigeon_produce, args=(pg, 5)) - pd6 = threading.Thread(name='producer6', target=pigeon_produce, args=(pg, 6)) - cs4 = threading.Thread(name='consumer4', target=pigeon_consume, args=(pg, 4)) - cs5 = threading.Thread(name='consumer5', target=pigeon_consume, args=(pg, 5)) - cs6 = threading.Thread(name='consumer6', target=pigeon_consume, args=(pg, 6)) - ab4 = threading.Thread(name='absent4', target=pigeon_absent, args=(pg, 4)) - ab5 = threading.Thread(name='absent5', target=pigeon_absent, args=(pg, 5)) - ab6 = threading.Thread(name='absent6', target=pigeon_absent, args=(pg, 6)) - # cs6 = threading.Thread(name='consumer2', target=pigeon_absent, args=(pg,6)) - - ab4.start() - cs5.start() - cs6.start() - time.sleep(1) - - # cs2.start() - # time.sleep(2) - pd5.start() - time.sleep(0.1) - print(pg.contains(5)) - ab5.start() - time.sleep(1) - pd6.start() diff --git a/src/core/roskv/src/roskv/reactor.py b/src/core/roskv/src/roskv/reactor.py index 40461da..5721c18 100644 --- a/src/core/roskv/src/roskv/reactor.py +++ b/src/core/roskv/src/roskv/reactor.py @@ -5,9 +5,8 @@ import os import sys import json -from benedict import benedict import threading -from six.moves.queue import Queue, Empty +from queue import Queue, Empty import rospy import rosservice @@ -99,7 +98,7 @@ class KeyWatcher(object): def __init__(self, cmd_queue, host="nuvo0"): node_host = rospy.get_namespace().strip("/") self.envoy = RedisEnvoy(host, client_name=node_host + "-reactor") - self.cmd_recv = benedict() + self.cmd_recv = dict() self.cmd_queue = cmd_queue self.queue_timer = rospy.Timer(ROS_INSTANT, self.cb_sync, oneshot=True) @@ -108,7 +107,7 @@ def cb_sync(self, event=None): resp = self.envoy.get_dict("/cmd", flatten=True) except KeyError as e: resp = {} - cmd_recv = benedict(resp) + cmd_recv = dict(resp) if cmd_recv: rospy.loginfo("Got command(s): {}".format(cmd_recv)) self.cmd_recv.update(cmd_recv) diff --git a/src/core/roskv/src/roskv/rendezvous.py b/src/core/roskv/src/roskv/rendezvous.py index 053f61b..d158b8b 100644 --- a/src/core/roskv/src/roskv/rendezvous.py +++ b/src/core/roskv/src/roskv/rendezvous.py @@ -4,23 +4,11 @@ from typing import Any, Callable import threading import time -from six.moves.queue import deque, Queue +from collections import deque +from queue import Queue from roskv.util import MyTimeoutError -class Governor(object): - def __init__(self, period=0.01): - self.period = period - self._last = time.time() - - def check(self): - """Check the elapsed time and block if it's fired too recently""" - now = time.time() - dt = now - self._last - if dt < self.period: - time.sleep(self.period - dt) - self._last = time.time() - class ConditionalRendezvous(object): """A limited-size deque which can block on waiting for a boolean to evaluate. @@ -85,128 +73,3 @@ def wait_for(self, func, timeout=None, retries=None): self._cond.wait(timeout=timeout) attempt += 1 raise MyTimeoutError('Timed out after {} attempts'.format(attempt)) - - - - -class _TestConditionalRendezvous(object): - """A limited-size deque which can block on waiting for the presence or absence of - a value""" - - def __init__(self, maxlen=1): - self._value = None - self._deque = deque(maxlen=maxlen) - self._cond = threading.Condition() - - def put(self, value): - logging.debug('Calling put {}'.format(value)) - with self._cond: - logging.debug('Put: {}'.format(value)) - self._deque.append(value) - self._cond.notify_all() - - def contains(self, value): - with self._cond: - return value in self._deque - - def present(self, value, timeout=None, retries=None): - """Block/fail until value is present in the rendezvous""" - logging.debug('Call present {}'.format(value)) - attempt = 0 - retries = 1e99 if retries is None else retries - while attempt < retries: - with self._cond: - logging.debug('Attempt {}'.format(attempt)) - if value in self._deque: - logging.debug('ConditionalRendezvous contains {}'.format(value)) - return True - logging.debug('ConditionalRendezvous waiting for {}'.format(value)) - self._cond.wait(timeout=timeout) - attempt += 1 - - raise RuntimeError('ran out after {} attempts'.format(attempt)) - - def absent(self, value): - """Block/fail until value isn't presently in the rendezvous""" - logging.debug('Call absent {}'.format(value)) - while True: - with self._cond: - if value not in self._deque: - logging.debug('ConditionalRendezvous lacks {}'.format(value)) - return True - logging.debug('ConditionalRendezvous waiting on lack of {}'.format(value)) - self._cond.wait() - - -if __name__ == '__main__': - import time - import logging - - logging.basicConfig(level=logging.DEBUG, - format='(%(threadName)-9s) %(message)s', ) - - - def pigeon_produce(pg, value=5): - logging.debug('Producer thread started {} ...'.format(value)) - pg.put(value) - logging.debug('Producer put value {}...'.format(value)) - - - def pigeon_consume(pg, value=5): - logging.debug('Consumer thread started {}...'.format(value)) - pg.present(value, 0.5, value) - logging.debug('Consumer got value {}...'.format(value)) - - - def pigeon_absent(pg, value=5): - logging.debug('Absent consumer thread started {}...'.format(value)) - pg.absent(value) - logging.debug('Absent consumer got value {}...'.format(value)) - - - def consumer(cv): - logging.debug('Consumer thread started ...') - with cv: - logging.debug('Consumer waiting ...') - cv.wait() - logging.debug('Consumer consumed the resource') - - - def producer(cv): - logging.debug('Producer thread started ...') - with cv: - logging.debug('Making resource available') - logging.debug('Notifying to all consumers') - cv.notifyAll() - - - condition = threading.Condition() - pg = _TestConditionalRendezvous() - pg.put(4) - # cs1 = threading.Thread(name='consumer1', target=consumer, args=(condition,)) - # cs2 = threading.Thread(name='consumer2', target=consumer, args=(condition,)) - # pd = threading.Thread(name='producer', target=producer, args=(condition,)) - pd4 = threading.Thread(name='producer4', target=pigeon_produce, args=(pg, 4)) - pd5 = threading.Thread(name='producer5', target=pigeon_produce, args=(pg, 5)) - pd6 = threading.Thread(name='producer6', target=pigeon_produce, args=(pg, 6)) - cs4 = threading.Thread(name='consumer4', target=pigeon_consume, args=(pg, 4)) - cs5 = threading.Thread(name='consumer5', target=pigeon_consume, args=(pg, 5)) - cs6 = threading.Thread(name='consumer6', target=pigeon_consume, args=(pg, 6)) - ab4 = threading.Thread(name='absent4', target=pigeon_absent, args=(pg, 4)) - ab5 = threading.Thread(name='absent5', target=pigeon_absent, args=(pg, 5)) - ab6 = threading.Thread(name='absent6', target=pigeon_absent, args=(pg, 6)) - # cs6 = threading.Thread(name='consumer2', target=pigeon_absent, args=(pg,6)) - - ab4.start() - cs5.start() - cs6.start() - time.sleep(1) - - # cs2.start() - # time.sleep(2) - pd5.start() - time.sleep(0.1) - print(pg.contains(5)) - ab5.start() - time.sleep(1) - pd6.start() diff --git a/src/core/roskv/src/roskv/util.py b/src/core/roskv/src/roskv/util.py index 952ae87..27c00b3 100755 --- a/src/core/roskv/src/roskv/util.py +++ b/src/core/roskv/src/roskv/util.py @@ -1,23 +1,43 @@ #! /usr/bin/env python # -*- coding: utf-8 -*- -from typing import Any, List, Dict, Optional, Tuple, Union +from typing import Any, List, Optional, Tuple, Union +from io import BytesIO import json from hashlib import md5 +from collections.abc import Mapping +from json import JSONDecodeError -from six import string_types, binary_type, PY2, PY3, BytesIO -from benedict import benedict - - -if PY2: - JSONDecodeError = ValueError - from collections import Mapping -else: - from json import JSONDecodeError - from collections.abc import Mapping class MyTimeoutError(OSError): pass + +def _flatten(d, prefix="", sep="/"): + """Recursively flatten a nested dict with sep-joined keys.""" + items = {} + for k, v in d.items(): + new_key = prefix + sep + k if prefix else k + if isinstance(v, Mapping): + items.update(_flatten(v, new_key, sep)) + else: + items[new_key] = v + return items + + +def _unflatten(flat, sep="/"): + """Reconstruct a nested dict from a flat dict with sep-joined keys.""" + result = {} + for key, value in flat.items(): + parts = key.split(sep) + node = result + for part in parts[:-1]: + if not isinstance(node.get(part), dict): + node[part] = {} + node = node[part] + node[parts[-1]] = value + return result + + def hash_genpy_msg(msg): # type: (genpy.message.Message) -> bytes buf = BytesIO() @@ -40,23 +60,21 @@ def simple_hash_args(*args): def loader23(s): - # type: (binary_type) -> str - """Python""" + # type: (bytes) -> str if s is None: return None - if isinstance(s, binary_type): + if isinstance(s, bytes): return s.decode() return s def dumper23(val): - # type: (Union[str, binary_type, dict]) -> binary_type - """Python2/3 compatible encoder for redis""" - if isinstance(val, string_types): + # type: (Union[str, bytes, dict]) -> bytes + """Encode a value for storage in Redis""" + if isinstance(val, str): return val.encode() - elif isinstance(val, binary_type): + elif isinstance(val, bytes): return val - return json.dumps(val).encode() @@ -76,8 +94,8 @@ def flatten_fs(val, root="", sep="/"): """Flatten with forward slash separator. ROS-style KV space nesting with a leading forward slash for root""" if isinstance(val, Mapping): - bd = benedict(val).flatten(separator="/") - return {root + sep + k: v for k, v in bd.items()} + flat = _flatten(val, sep=sep) + return {root + sep + k: v for k, v in flat.items()} return val @@ -97,49 +115,18 @@ def wildcard(pat, s): import re s = loader23(s) rpat = loader23(pat).replace('*', '.*').replace('?', '.') - mat = re.search(rpat, s) return mat is not None - return rpat - - -def demux_consul(box_values, key=None): - # type: (List[Dict[str, str]], Optional[str]) -> dict - """ - Unwraps and de-multiplexes a response from Consul so nested values are returned as nested dict. - :param box_values: - :param key: - :return: - - Examples: - >>> bv = [{'Key': 'foo', 'Value': b'{"nest": {"num": 42, "spam": "eggs"}}'}] - >>> demux_consul(bv, 'foo') - {'nest': {'num': 42, 'spam': 'eggs'}} - >>> bv = [{'Key': 'nest1/nest2', 'Value': b'abc'},{'Key': 'nest1/nest3', 'Value': b'123'}] - >>> bv.extend([{'Key': 'nest1/nest3/nest33','Value': b'12345'}, {'Key': 'nest1/nest3/nest45','Value': b'12345'}]) - >>> demux_consul(bv) - {'nest1': {'nest2': b'abc', 'nest3': {'nest33': 12345, 'nest45': 12345}}} - >>> demux_consul(bv, 'nest1') - {'nest2': b'abc', 'nest3': {'nest33': 12345, 'nest45': 12345}} - - """ - if len(box_values) == 1 and "/" not in box_values[0]["Key"]: - return try_jloads(box_values[0]["Value"]) - - bd = benedict({el["Key"]: try_jloads(el["Value"]) for el in box_values}) - bd = bd.unflatten(separator="/") - if key is not None: - return bd[key] - return bd def redis_decode(keys, values, key=None, flatten=False, as_json=True): # type: (List[str], List[str], Optional[str], bool, bool) -> dict """ - Unwraps and de-multiplexes a response from Consul so nested values are returned as nested dict. + Unwraps and de-multiplexes a Redis response so nested values are returned as a nested dict. :param keys: list of keys :param values: list of return values :param key: keypath prefix key + :param flatten: return the flat dict without unflattening :param as_json: Try to deserialize from json :return: nested dict from the keypath @@ -149,30 +136,20 @@ def redis_decode(keys, values, key=None, flatten=False, as_json=True): {'nest': {'num': 42, 'spam': 'eggs'}} >>> keys_ = ['nest1/nest2', 'nest1/nest3', 'nest1/nest3/nest33', 'nest1/nest3/nest45'] >>> vals = ['abc', '123', '12345', '12345'] - >>> redis_decode(keys_, vals) - {'nest1': {'nest2': b'abc', 'nest3': {'nest33': 12345, 'nest45': 12345}}} >>> redis_decode(keys_, vals, 'nest1') - {'nest2': b'abc', 'nest3': {'nest33': 12345, 'nest45': 12345}} + {'nest2': 'abc', 'nest3': {'nest33': 12345, 'nest45': 12345}} >>> redis_decode(keys_, vals, 'nest1/nest3') {'nest33': 12345, 'nest45': 12345} """ - if as_json: - loader = try_jloads - else: - loader = loader23 - ## I think this is wrong - # if len(keys) == 1: - # return loader(values[0]) - + loader = try_jloads if as_json else loader23 keys = [loader23(k) for k in keys] values = [loader(v) for v in values] - bd = benedict(zip(keys, values)) - + flat = dict(zip(keys, values)) if flatten: - return bd - bd = bd.unflatten(separator="/") + return flat + bd = _unflatten(flat) if len(bd) == 1 and "" in bd: bd = bd[""] if key is None: @@ -181,7 +158,6 @@ def redis_decode(keys, values, key=None, flatten=False, as_json=True): if not subkey: continue bd = bd[subkey] - return bd diff --git a/src/core/testbed/src/test_roskv.cpp b/src/core/testbed/src/test_roskv.cpp index fa7342e..d6afff9 100644 --- a/src/core/testbed/src/test_roskv.cpp +++ b/src/core/testbed/src/test_roskv.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -136,7 +135,6 @@ bool test_json() { } bool test_roskv() { - hello_roskv(); string redis_addr = RedisHelper::get_redis_uri(); RedisHelper::assert_redis(redis_addr); ArchiverFormatter af{redis_addr, "/sys/arch", "center", "rgb"}; diff --git a/src/kitware-ros-pkg/image_manager/image_manager.py b/src/kitware-ros-pkg/image_manager/image_manager.py index 3ae9fc4..f04786a 100755 --- a/src/kitware-ros-pkg/image_manager/image_manager.py +++ b/src/kitware-ros-pkg/image_manager/image_manager.py @@ -51,10 +51,10 @@ def __init__(self): self._image_exts = ['jpg', 'tif', 'json'] self.modalities = ['rgb', 'ir', 'uv', 'meta'] self.modality2ext = {'rgb':'jpg', 'ir':'tif', 'uv':'jpg', 'meta':'json'} - self._effort = envoy.kv.get("/sys/arch/effort") - self._wait_time_sec = int(envoy.kv.get("/sys/effort_metadata_dict/%s/wait_time_sec" % self._effort)) - self._delete_old_images_sec = int(envoy.kv.get("/sys/effort_metadata_dict/%s/delete_old_images_sec" % self._effort)) - self._save_every_x_image = int(envoy.kv.get("/sys/effort_metadata_dict/%s/save_every_x_image" % self._effort)) + self._effort = envoy.get("/sys/arch/effort") + self._wait_time_sec = int(envoy.get("/sys/effort_metadata_dict/%s/wait_time_sec" % self._effort)) + self._delete_old_images_sec = int(envoy.get("/sys/effort_metadata_dict/%s/delete_old_images_sec" % self._effort)) + self._save_every_x_image = int(envoy.get("/sys/effort_metadata_dict/%s/save_every_x_image" % self._effort)) self._log_file = '/root/kamera_ws/image_manager.log' self._image_dir = "" self._secondary_image_dir = "" @@ -91,7 +91,7 @@ def wait_time_sec(self): @property def delete_old_images_sec(self): try: - self._delete_old_images_sec = int(envoy.kv.get( + self._delete_old_images_sec = int(envoy.get( "/sys/effort_metadata_dict/%s/delete_old_images_sec" % self.effort)) except Exception as e: @@ -101,7 +101,7 @@ def delete_old_images_sec(self): @property def save_every_x_image(self): try: - self._save_every_x_image = int(envoy.kv.get( + self._save_every_x_image = int(envoy.get( "/sys/effort_metadata_dict/%s/save_every_x_image" % self.effort)) except: @@ -111,17 +111,17 @@ def save_every_x_image(self): @property def image_dir(self): - primary_storage = envoy.kv.get("/sys/local_ssd_mnt") + primary_storage = envoy.get("/sys/local_ssd_mnt") syscfg_dir = get_arch_path(base=primary_storage) - view = envoy.kv.get("/sys/arch/hosts/%s/fov" % hostname) + "_view" + view = envoy.get("/sys/arch/hosts/%s/fov" % hostname) + "_view" self._image_dir = os.path.join(syscfg_dir, view) return self._image_dir @property def secondary_image_dir(self): - secondary_storage = envoy.kv.get("/sys/nas_mnt") + secondary_storage = envoy.get("/sys/nas_mnt") syscfg_dir = get_arch_path(base=secondary_storage) - view = envoy.kv.get("/sys/arch/hosts/%s/fov" % hostname) + "_view" + view = envoy.get("/sys/arch/hosts/%s/fov" % hostname) + "_view" self._secondary_image_dir = os.path.join(syscfg_dir, view) return self._secondary_image_dir diff --git a/src/process/nexus/src/nexus/archiver_core.py b/src/process/nexus/src/nexus/archiver_core.py index 04a2d89..121f5d6 100755 --- a/src/process/nexus/src/nexus/archiver_core.py +++ b/src/process/nexus/src/nexus/archiver_core.py @@ -247,25 +247,25 @@ def __init__(self, agent_name=None, bytes_halt_archiving=1e9, verbosity=0): print("\n\n VERSION CHECK 1 \n") self.envoy = RedisEnvoy(self._redis_host, client_name=node_host + "-nexus") - self.state_service = StateService(self.envoy.kv, node_host, "nexus") + self.state_service = StateService(self.envoy, node_host, "nexus") # Get Redis Params - arch = self.envoy.kv.get("/sys/arch") + arch = self.envoy.get("/sys/arch") self.set_arch(arch) - self._is_archiving = self.envoy.kv.get("/sys/arch/is_archiving") + self._is_archiving = self.envoy.get("/sys/arch/is_archiving") self._project = self.envoy.get("/sys/arch/project") fl = self.envoy.get("/sys/arch/flight") fl_number = "".join([d for d in str(fl) if d.isdigit()]) self._flight = "fl{:0>2}".format(fl_number) self._effort = self.envoy.get("/sys/arch/effort") - self._save_every_x_image = self.envoy.kv.get( + self._save_every_x_image = self.envoy.get( f"/sys/effort_metadata_dict/{self._effort}/save_every_x_image" ) self._field = os.environ.get("CAM_FOV", "default_view") self._collection_mode = self.envoy.get("/sys/collection_mode") self._template = self.envoy.get("/sys/arch/template") - self._base = self.envoy.kv.get("/sys/arch/base") - self._data_mount_point = self.envoy.kv.get( + self._base = self.envoy.get("/sys/arch/base") + self._data_mount_point = self.envoy.get( "/sys/arch/base", "/mnt/archiver_default" ) self.disk_check(self._base, every_nth=1) @@ -722,7 +722,7 @@ def collection_mode(self): @property def save_every_x_image(self): - self._save_every_x_image = self.envoy.kv.get( + self._save_every_x_image = self.envoy.get( f"/sys/effort_metadata_dict/{self.effort}/save_every_x_image" ) return self._save_every_x_image From 095c1daf9bf5601390657630b0989504baea994b Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Fri, 1 May 2026 10:21:37 -0400 Subject: [PATCH 027/139] Pass correct arg to redis envoy --- src/core/roskv/src/roskv/impl/redis_envoy.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/core/roskv/src/roskv/impl/redis_envoy.py b/src/core/roskv/src/roskv/impl/redis_envoy.py index c37c54d..d0fae96 100755 --- a/src/core/roskv/src/roskv/impl/redis_envoy.py +++ b/src/core/roskv/src/roskv/impl/redis_envoy.py @@ -30,8 +30,6 @@ def __init__( unix_socket_path=None, encoding="utf-8", encoding_errors="strict", - charset=None, - errors=None, decode_responses=False, retry_on_timeout=False, ssl=False, @@ -65,8 +63,6 @@ def __init__( unix_socket_path=unix_socket_path, encoding=encoding, encoding_errors=encoding_errors, - charset=charset, - errors=errors, decode_responses=decode_responses, retry_on_timeout=retry_on_timeout, ssl=ssl, From ad099ea8067c061ccf8da49adae3a43ca158a511 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 10 Jun 2026 16:52:47 -0400 Subject: [PATCH 028/139] Update naming convention for hostnames --- .../{nuvo0 => center-0-taiga}/chrony.conf | 0 .../custom-netplan.yaml | 0 .../taiga/{nuvo0 => center-0-taiga}/ntp.conf | 0 src/cfg/taiga/config.yaml | 10 +-- src/cfg/taiga/default_system_state.json | 64 +++++++++---------- .../taiga/{nuvo1 => left-1-taiga}/chrony.conf | 0 .../custom-netplan.yaml | 2 - src/cfg/taiga/nuvo0/hosts | 33 ---------- src/cfg/taiga/nuvo1/hosts | 33 ---------- src/cfg/taiga/nuvo2/hosts | 33 ---------- src/cfg/taiga/redis.conf | 2 +- .../{nuvo2 => right-2-taiga}/chrony.conf | 0 .../custom-netplan.yaml | 1 - 13 files changed, 38 insertions(+), 140 deletions(-) rename src/cfg/taiga/{nuvo0 => center-0-taiga}/chrony.conf (100%) rename src/cfg/taiga/{nuvo0 => center-0-taiga}/custom-netplan.yaml (100%) rename src/cfg/taiga/{nuvo0 => center-0-taiga}/ntp.conf (100%) rename src/cfg/taiga/{nuvo1 => left-1-taiga}/chrony.conf (100%) rename src/cfg/taiga/{nuvo1 => left-1-taiga}/custom-netplan.yaml (89%) delete mode 100644 src/cfg/taiga/nuvo0/hosts delete mode 100755 src/cfg/taiga/nuvo1/hosts delete mode 100755 src/cfg/taiga/nuvo2/hosts rename src/cfg/taiga/{nuvo2 => right-2-taiga}/chrony.conf (100%) rename src/cfg/taiga/{nuvo2 => right-2-taiga}/custom-netplan.yaml (97%) diff --git a/src/cfg/taiga/nuvo0/chrony.conf b/src/cfg/taiga/center-0-taiga/chrony.conf similarity index 100% rename from src/cfg/taiga/nuvo0/chrony.conf rename to src/cfg/taiga/center-0-taiga/chrony.conf diff --git a/src/cfg/taiga/nuvo0/custom-netplan.yaml b/src/cfg/taiga/center-0-taiga/custom-netplan.yaml similarity index 100% rename from src/cfg/taiga/nuvo0/custom-netplan.yaml rename to src/cfg/taiga/center-0-taiga/custom-netplan.yaml diff --git a/src/cfg/taiga/nuvo0/ntp.conf b/src/cfg/taiga/center-0-taiga/ntp.conf similarity index 100% rename from src/cfg/taiga/nuvo0/ntp.conf rename to src/cfg/taiga/center-0-taiga/ntp.conf diff --git a/src/cfg/taiga/config.yaml b/src/cfg/taiga/config.yaml index dde064d..63d0d89 100644 --- a/src/cfg/taiga/config.yaml +++ b/src/cfg/taiga/config.yaml @@ -30,15 +30,15 @@ arch: ext_evt: json ext_ins: json hosts: - nuvo0: + center-0-taiga: fov: center idx: 0 enabled: true - nuvo1: + left-1-taiga: fov: left idx: 1 enabled: true - nuvo2: + right-2-taiga: fov: right idx: 2 enabled: true @@ -50,8 +50,8 @@ nas_mnt: "/mnt/flight_data" local_ssd_mnt: "/mnt/data" kamera_dir: "/home/user/kw/kamera" gui_cfg_dir: "/home/user/.config/kamera/gui" -master_host: nuvo0 -redis_host: nuvo0 +master_host: center-0-taiga +redis_host: center-0-taiga verbosity: 9 max_mpix: 200000 # 0.2e6 diff --git a/src/cfg/taiga/default_system_state.json b/src/cfg/taiga/default_system_state.json index af470fa..2b138b2 100755 --- a/src/cfg/taiga/default_system_state.json +++ b/src/cfg/taiga/default_system_state.json @@ -12,17 +12,17 @@ "ext_uv": "jpg", "flight": "00", "hosts": { - "nuvo0": { + "center-0-taiga": { "enabled": true, "fov": "center", "idx": 0 }, - "nuvo1": { + "left-1-taiga": { "enabled": true, "fov": "left", "idx": 1 }, - "nuvo2": { + "right-2-taiga": { "enabled": true, "fov": "right", "idx": 2 @@ -379,7 +379,7 @@ "uv": "uv_n2" } }, - "master_host": "nuvo0", + "master_host": "center-0-taiga", "max_mpix": 200000, "models": { "allied_gt4907_uv": { @@ -434,7 +434,7 @@ } }, "nas_mnt": "/mnt/flight_data", - "nuvo0": { + "center-0-taiga": { "detector": { "desired": "down", "health": { @@ -449,7 +449,7 @@ "total": 0 } }, - "nuvo1": { + "left-1-taiga": { "detector": { "desired": "down", "health": { @@ -460,7 +460,7 @@ "pipefile": null } }, - "nuvo2": { + "right-2-taiga": { "detector": { "desired": "down", "health": { @@ -477,9 +477,9 @@ "homography", "detections" ], - "redis_host": "nuvo0", + "redis_host": "center-0-taiga", "requested_geni_params": { - "nuvo0": { + "center-0-taiga": { "ir": { "CorrectionAutoEnabled": 1, "CorrectionAutoUseDeltaTime": 0 @@ -495,17 +495,17 @@ "Shutter_Speed_Min": 0.008 }, "uv": { - "ExposureAuto": "Continuous", - "ExposureAutoMax": 2400.0, - "ExposureAutoMin": 400.0, - "ExposureValue": 0, - "GainAuto": "Auto", - "GainAutoMax": 30, - "GainAutoMin": 0, + "ExposureAuto": "Continuous", + "ExposureAutoMax": 2400.0, + "ExposureAutoMin": 400.0, + "ExposureValue": 0, + "GainAuto": "Auto", + "GainAutoMax": 30, + "GainAutoMin": 0, "GainValue": 0 } }, - "nuvo1": { + "left-1-taiga": { "ir": { "CorrectionAutoEnabled": 1, "CorrectionAutoUseDeltaTime": 0 @@ -521,17 +521,17 @@ "Shutter_Speed_Min": 0.008 }, "uv": { - "ExposureAuto": "Continuous", - "ExposureAutoMax": 2400.0, - "ExposureAutoMin": 400.0, - "ExposureValue": 0, - "GainAuto": "Auto", - "GainAutoMax": 30, - "GainAutoMin": 0, + "ExposureAuto": "Continuous", + "ExposureAutoMax": 2400.0, + "ExposureAutoMin": 400.0, + "ExposureValue": 0, + "GainAuto": "Auto", + "GainAutoMax": 30, + "GainAutoMin": 0, "GainValue": 0 } }, - "nuvo2": { + "right-2-taiga": { "ir": { "CorrectionAutoEnabled": 1, "CorrectionAutoUseDeltaTime": 0 @@ -547,13 +547,13 @@ "Shutter_Speed_Min": 0.008 }, "uv": { - "ExposureAuto": "Continuous", - "ExposureAutoMax": 2400.0, - "ExposureAutoMin": 400.0, - "ExposureValue": 0, - "GainAuto": "Auto", - "GainAutoMax": 30, - "GainAutoMin": 0, + "ExposureAuto": "Continuous", + "ExposureAutoMax": 2400.0, + "ExposureAutoMin": 400.0, + "ExposureValue": 0, + "GainAuto": "Auto", + "GainAutoMax": 30, + "GainAutoMin": 0, "GainValue": 0 } } diff --git a/src/cfg/taiga/nuvo1/chrony.conf b/src/cfg/taiga/left-1-taiga/chrony.conf similarity index 100% rename from src/cfg/taiga/nuvo1/chrony.conf rename to src/cfg/taiga/left-1-taiga/chrony.conf diff --git a/src/cfg/taiga/nuvo1/custom-netplan.yaml b/src/cfg/taiga/left-1-taiga/custom-netplan.yaml similarity index 89% rename from src/cfg/taiga/nuvo1/custom-netplan.yaml rename to src/cfg/taiga/left-1-taiga/custom-netplan.yaml index 2edc845..325dbad 100755 --- a/src/cfg/taiga/nuvo1/custom-netplan.yaml +++ b/src/cfg/taiga/left-1-taiga/custom-netplan.yaml @@ -1,5 +1,3 @@ -# Important note! The ethernet device names are set by 70-persistent-net.rules on nuvo0 but netplan on nuvo1/2 - --- ## Netplan for nuvo1 network: diff --git a/src/cfg/taiga/nuvo0/hosts b/src/cfg/taiga/nuvo0/hosts deleted file mode 100644 index 6a7bf4b..0000000 --- a/src/cfg/taiga/nuvo0/hosts +++ /dev/null @@ -1,33 +0,0 @@ -127.0.0.1 localhost.localdomain localhost -::1 localhost6.localdomain6 localhost6 - -# The following lines are desirable for IPv6 capable hosts -::1 localhost ip6-localhost ip6-loopback -fe00::0 ip6-localnet -ff02::1 ip6-allnodes -ff02::2 ip6-allrouters -ff02::3 ip6-allhosts - -# Inserted from KAMERA -192.168.88.1 mikrotik - -192.168.88.10 nuvo0 -192.168.88.11 nuvo1 -192.168.88.12 nuvo2 - -192.168.88.100 cas0 -192.168.88.101 cas1 -192.168.88.102 cas2 -192.168.88.103 cas3 - -# Fallback static connections -192.168.88.210 nuvo0bak -192.168.88.211 nuvo1bak -192.168.88.212 nuvo2bak - -192.168.198.10 kamera_nas - -# Set ros master url here - typically nuvo0 -192.168.88.10 kameramaster -192.168.88.99 ins - diff --git a/src/cfg/taiga/nuvo1/hosts b/src/cfg/taiga/nuvo1/hosts deleted file mode 100755 index b65f2b1..0000000 --- a/src/cfg/taiga/nuvo1/hosts +++ /dev/null @@ -1,33 +0,0 @@ -127.0.0.1 localhost.localdomain localhost -::1 localhost6.localdomain6 localhost6 - -# The following lines are desirable for IPv6 capable hosts -::1 localhost ip6-localhost ip6-loopback -fe00::0 ip6-localnet -ff02::1 ip6-allnodes -ff02::2 ip6-allrouters -ff02::3 ip6-allhosts - -# Inserted from KAMERA -192.168.88.1 mikrotik - -192.168.88.10 nuvo0 -192.168.88.11 nuvo1 -192.168.88.12 nuvo2 - -192.168.88.100 cas0 -192.168.88.101 cas1 -192.168.88.102 cas2 -192.168.88.103 cas3 - -# Fallback static connections -192.168.88.210 nuvo0bak -192.168.88.211 nuvo1bak -192.168.88.212 nuvo2bak - -192.168.198.11 kamera_nas - -# Set ros master url here - typically nuvo0 -192.168.88.10 kameramaster -192.168.88.99 ins - diff --git a/src/cfg/taiga/nuvo2/hosts b/src/cfg/taiga/nuvo2/hosts deleted file mode 100755 index ff57904..0000000 --- a/src/cfg/taiga/nuvo2/hosts +++ /dev/null @@ -1,33 +0,0 @@ -127.0.0.1 localhost.localdomain localhost -::1 localhost6.localdomain6 localhost6 - -# The following lines are desirable for IPv6 capable hosts -::1 localhost ip6-localhost ip6-loopback -fe00::0 ip6-localnet -ff02::1 ip6-allnodes -ff02::2 ip6-allrouters -ff02::3 ip6-allhosts - -# Inserted from KAMERA -192.168.88.1 mikrotik - -192.168.88.10 nuvo0 -192.168.88.11 nuvo1 -192.168.88.12 nuvo2 - -192.168.88.100 cas0 -192.168.88.101 cas1 -192.168.88.102 cas2 -192.168.88.103 cas3 - -# Fallback static connections -192.168.88.210 nuvo0bak -192.168.88.211 nuvo1bak -192.168.88.212 nuvo2bak - -192.168.198.12 kamera_nas - -# Set ros master url here - typically nuvo0 -192.168.88.10 kameramaster -192.168.88.99 ins - diff --git a/src/cfg/taiga/redis.conf b/src/cfg/taiga/redis.conf index fc1c4f8..22b0486 100755 --- a/src/cfg/taiga/redis.conf +++ b/src/cfg/taiga/redis.conf @@ -66,7 +66,7 @@ # IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES # JUST COMMENT THE FOLLOWING LINE. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -bind nuvo0 +bind center-0-taiga # Protected mode is a layer of security protection, in order to avoid that # Redis instances left open on the internet are accessed and exploited. diff --git a/src/cfg/taiga/nuvo2/chrony.conf b/src/cfg/taiga/right-2-taiga/chrony.conf similarity index 100% rename from src/cfg/taiga/nuvo2/chrony.conf rename to src/cfg/taiga/right-2-taiga/chrony.conf diff --git a/src/cfg/taiga/nuvo2/custom-netplan.yaml b/src/cfg/taiga/right-2-taiga/custom-netplan.yaml similarity index 97% rename from src/cfg/taiga/nuvo2/custom-netplan.yaml rename to src/cfg/taiga/right-2-taiga/custom-netplan.yaml index 9dda4eb..bd12b50 100644 --- a/src/cfg/taiga/nuvo2/custom-netplan.yaml +++ b/src/cfg/taiga/right-2-taiga/custom-netplan.yaml @@ -1,5 +1,4 @@ --- -## Netplan for nuvo2 network: version: 2 ethernets: From 0ad7554779c95fdcfd67fe9174d0d016647678c8 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 10 Jun 2026 16:56:27 -0400 Subject: [PATCH 029/139] Update nayak with new naming convention as well --- src/cfg/nayak/cas0/hosts | 34 - src/cfg/nayak/cas1/hosts | 34 - src/cfg/nayak/cas2/hosts | 34 - src/cfg/nayak/cas3/hosts | 34 - .../{cas0 => center-0-nayak}/chrony.conf | 0 .../custom-netplan.yaml | 1 - .../nayak/{cas0 => center-0-nayak}/ntp.conf | 0 src/cfg/nayak/config.yaml | 10 +- src/cfg/nayak/default_system_state.json | 1150 ++++++++--------- .../nayak/{cas1 => left-1-nayak}/chrony.conf | 0 .../custom-netplan.yaml | 1 - src/cfg/nayak/redis.conf | 4 +- .../nayak/{cas2 => right-2-nayak}/chrony.conf | 0 .../custom-netplan.yaml | 1 - 14 files changed, 581 insertions(+), 722 deletions(-) delete mode 100644 src/cfg/nayak/cas0/hosts delete mode 100755 src/cfg/nayak/cas1/hosts delete mode 100755 src/cfg/nayak/cas2/hosts delete mode 100755 src/cfg/nayak/cas3/hosts rename src/cfg/nayak/{cas0 => center-0-nayak}/chrony.conf (100%) rename src/cfg/nayak/{cas0 => center-0-nayak}/custom-netplan.yaml (98%) rename src/cfg/nayak/{cas0 => center-0-nayak}/ntp.conf (100%) rename src/cfg/nayak/{cas1 => left-1-nayak}/chrony.conf (100%) rename src/cfg/nayak/{cas1 => left-1-nayak}/custom-netplan.yaml (97%) rename src/cfg/nayak/{cas2 => right-2-nayak}/chrony.conf (100%) rename src/cfg/nayak/{cas2 => right-2-nayak}/custom-netplan.yaml (97%) diff --git a/src/cfg/nayak/cas0/hosts b/src/cfg/nayak/cas0/hosts deleted file mode 100644 index ae52c06..0000000 --- a/src/cfg/nayak/cas0/hosts +++ /dev/null @@ -1,34 +0,0 @@ -127.0.0.1 localhost.localdomain localhost -::1 localhost6.localdomain6 localhost6 - -# The following lines are desirable for IPv6 capable hosts -::1 localhost ip6-localhost ip6-loopback -fe00::0 ip6-localnet -ff02::1 ip6-allnodes -ff02::2 ip6-allrouters -ff02::3 ip6-allhosts - -# Inserted from KAMERA -192.168.88.1 mikrotik - -192.168.88.10 nuvo0 -192.168.88.11 nuvo1 -192.168.88.12 nuvo2 - -192.168.88.100 cas0 -192.168.88.101 cas1 -192.168.88.102 cas2 -192.168.88.103 cas3 - -# Fallback static connections -192.168.88.210 nuvo0bak -192.168.88.211 nuvo1bak -192.168.88.212 nuvo2bak - -192.168.198.10 kamera_nas - -# Set ros master url here - typically nuvo0 -192.168.88.100 kameramaster -192.168.88.5 guibox -192.168.88.99 ins - diff --git a/src/cfg/nayak/cas1/hosts b/src/cfg/nayak/cas1/hosts deleted file mode 100755 index 068a901..0000000 --- a/src/cfg/nayak/cas1/hosts +++ /dev/null @@ -1,34 +0,0 @@ -127.0.0.1 localhost.localdomain localhost -::1 localhost6.localdomain6 localhost6 - -# The following lines are desirable for IPv6 capable hosts -::1 localhost ip6-localhost ip6-loopback -fe00::0 ip6-localnet -ff02::1 ip6-allnodes -ff02::2 ip6-allrouters -ff02::3 ip6-allhosts - -# Inserted from KAMERA -192.168.88.1 mikrotik - -192.168.88.10 nuvo0 -192.168.88.11 nuvo1 -192.168.88.12 nuvo2 - -192.168.88.100 cas0 -192.168.88.101 cas1 -192.168.88.102 cas2 -192.168.88.103 cas3 - -# Fallback static connections -192.168.88.210 nuvo0bak -192.168.88.211 nuvo1bak -192.168.88.212 nuvo2bak - -192.168.198.11 kamera_nas - -# Set ros master url here - typically nuvo0 -192.168.88.100 kameramaster -192.168.88.5 guibox -192.168.88.99 ins - diff --git a/src/cfg/nayak/cas2/hosts b/src/cfg/nayak/cas2/hosts deleted file mode 100755 index 0ebc6a9..0000000 --- a/src/cfg/nayak/cas2/hosts +++ /dev/null @@ -1,34 +0,0 @@ -127.0.0.1 localhost.localdomain localhost -::1 localhost6.localdomain6 localhost6 - -# The following lines are desirable for IPv6 capable hosts -::1 localhost ip6-localhost ip6-loopback -fe00::0 ip6-localnet -ff02::1 ip6-allnodes -ff02::2 ip6-allrouters -ff02::3 ip6-allhosts - -# Inserted from KAMERA -192.168.88.1 mikrotik - -192.168.88.10 nuvo0 -192.168.88.11 nuvo1 -192.168.88.12 nuvo2 - -192.168.88.100 cas0 -192.168.88.101 cas1 -192.168.88.102 cas2 -192.168.88.103 cas3 - -# Fallback static connections -192.168.88.210 nuvo0bak -192.168.88.211 nuvo1bak -192.168.88.212 nuvo2bak - -192.168.198.12 kamera_nas - -# Set ros master url here - typically nuvo0 -192.168.88.100 kameramaster -192.168.88.5 guibox -192.168.88.99 ins - diff --git a/src/cfg/nayak/cas3/hosts b/src/cfg/nayak/cas3/hosts deleted file mode 100755 index 0ebc6a9..0000000 --- a/src/cfg/nayak/cas3/hosts +++ /dev/null @@ -1,34 +0,0 @@ -127.0.0.1 localhost.localdomain localhost -::1 localhost6.localdomain6 localhost6 - -# The following lines are desirable for IPv6 capable hosts -::1 localhost ip6-localhost ip6-loopback -fe00::0 ip6-localnet -ff02::1 ip6-allnodes -ff02::2 ip6-allrouters -ff02::3 ip6-allhosts - -# Inserted from KAMERA -192.168.88.1 mikrotik - -192.168.88.10 nuvo0 -192.168.88.11 nuvo1 -192.168.88.12 nuvo2 - -192.168.88.100 cas0 -192.168.88.101 cas1 -192.168.88.102 cas2 -192.168.88.103 cas3 - -# Fallback static connections -192.168.88.210 nuvo0bak -192.168.88.211 nuvo1bak -192.168.88.212 nuvo2bak - -192.168.198.12 kamera_nas - -# Set ros master url here - typically nuvo0 -192.168.88.100 kameramaster -192.168.88.5 guibox -192.168.88.99 ins - diff --git a/src/cfg/nayak/cas0/chrony.conf b/src/cfg/nayak/center-0-nayak/chrony.conf similarity index 100% rename from src/cfg/nayak/cas0/chrony.conf rename to src/cfg/nayak/center-0-nayak/chrony.conf diff --git a/src/cfg/nayak/cas0/custom-netplan.yaml b/src/cfg/nayak/center-0-nayak/custom-netplan.yaml similarity index 98% rename from src/cfg/nayak/cas0/custom-netplan.yaml rename to src/cfg/nayak/center-0-nayak/custom-netplan.yaml index fb3636c..c2d257e 100644 --- a/src/cfg/nayak/cas0/custom-netplan.yaml +++ b/src/cfg/nayak/center-0-nayak/custom-netplan.yaml @@ -1,5 +1,4 @@ --- -## Netplan for cas0 network: version: 2 ethernets: diff --git a/src/cfg/nayak/cas0/ntp.conf b/src/cfg/nayak/center-0-nayak/ntp.conf similarity index 100% rename from src/cfg/nayak/cas0/ntp.conf rename to src/cfg/nayak/center-0-nayak/ntp.conf diff --git a/src/cfg/nayak/config.yaml b/src/cfg/nayak/config.yaml index cef7c7e..23a1e28 100644 --- a/src/cfg/nayak/config.yaml +++ b/src/cfg/nayak/config.yaml @@ -30,15 +30,15 @@ arch: ext_evt: json ext_ins: json hosts: - cas0: + center-0-nayak: fov: center idx: 0 enabled: true - cas1: + left-1-nayak: fov: left idx: 1 enabled: true - cas2: + right-2-nayak: fov: right idx: 2 enabled: true @@ -50,8 +50,8 @@ nas_mnt: "/mnt/flight_data" local_ssd_mnt: "/mnt/data" kamera_dir: "/home/user/kw/kamera" gui_cfg_dir: "/home/user/.config/kamera/gui" -master_host: cas0 -redis_host: cas0 +master_host: center-0-nayak +redis_host: center-0-nayak verbosity: 9 max_mpix: 200000 # 0.2e6 diff --git a/src/cfg/nayak/default_system_state.json b/src/cfg/nayak/default_system_state.json index 9ab12cd..b02b821 100644 --- a/src/cfg/nayak/default_system_state.json +++ b/src/cfg/nayak/default_system_state.json @@ -1,496 +1,496 @@ { "actual_geni_params": { - "cas0": { + "center-0-nayak": { "ir": { - "CorrectionAutoEnabled": 1, + "CorrectionAutoEnabled": 1, "CorrectionAutoUseDeltaTime": 0 - }, + }, "rgb": { - "ISO": 200, - "ISO Max": 500, - "ISO Min": 0, - "ISO_Max": 200, - "ISO_Min": 200, - "Sensor_Temperature": 40.6, - "Shutter_Speed": 0.25, - "Shutter_Speed_Max": 0.00025, + "ISO": 200, + "ISO Max": 500, + "ISO Min": 0, + "ISO_Max": 200, + "ISO_Min": 200, + "Sensor_Temperature": 40.6, + "Shutter_Speed": 0.25, + "Shutter_Speed_Max": 0.00025, "Shutter_Speed_Min": 0.25 - }, + }, "uv": { - "ExposureAuto": "error", - "ExposureAutoMax": 2400.0, - "ExposureAutoMin": 400.0, - "ExposureValue": 2400, - "GainAuto": "Auto", - "GainAutoMax": 30, - "GainAutoMin": 0, + "ExposureAuto": "error", + "ExposureAutoMax": 2400.0, + "ExposureAutoMin": 400.0, + "ExposureValue": 2400, + "GainAuto": "Auto", + "GainAutoMax": 30, + "GainAutoMin": 0, "GainValue": 30 } - }, - "cas1": { + }, + "left-1-nayak": { "ir": { "CorrectionAutoEnabled": 1 - }, + }, "rgb": { - "ISO": 200, - "ISO_Max": 200, - "ISO_Min": 200, - "Sensor_Temperature": 43.3, - "Shutter_Speed": 0.008, - "Shutter_Speed_Max": 0.00025, + "ISO": 200, + "ISO_Max": 200, + "ISO_Min": 200, + "Sensor_Temperature": 43.3, + "Shutter_Speed": 0.008, + "Shutter_Speed_Max": 0.00025, "Shutter_Speed_Min": 0.008 - }, + }, "uv": { - "ExposureAuto": "error", - "ExposureAutoMax": 5760.0, - "ExposureAutoMin": 400.0, - "ExposureValue": 5760, - "GainAuto": "Auto", - "GainAutoMax": 30, - "GainAutoMin": 2, + "ExposureAuto": "error", + "ExposureAutoMax": 5760.0, + "ExposureAutoMin": 400.0, + "ExposureValue": 5760, + "GainAuto": "Auto", + "GainAutoMax": 30, + "GainAutoMin": 2, "GainValue": 30 } - }, - "cas2": { + }, + "right-2-nayak": { "ir": { "CorrectionAutoEnabled": 1 - }, + }, "rgb": { - "ISO": 200, - "ISO_Max": 200, - "ISO_Min": 200, - "Sensor_Temperature": 44.0, - "Shutter_Speed": 0.008, - "Shutter_Speed_Max": 0.00025, + "ISO": 200, + "ISO_Max": 200, + "ISO_Min": 200, + "Sensor_Temperature": 44.0, + "Shutter_Speed": 0.008, + "Shutter_Speed_Max": 0.00025, "Shutter_Speed_Min": 0.008 - }, + }, "uv": { - "ExposureAuto": "error", - "ExposureAutoMax": 2454.0, - "ExposureAutoMin": 400.0, - "ExposureValue": 2454, - "GainAuto": "Auto", - "GainAutoMax": 30, - "GainAutoMin": 0, + "ExposureAuto": "error", + "ExposureAutoMax": 2454.0, + "ExposureAutoMin": 400.0, + "ExposureValue": 2454, + "GainAuto": "Auto", + "GainAutoMax": 30, + "GainAutoMin": 0, "GainValue": 30 } } - }, + }, "arch": { - "allow_ir_nuc": 1, - "archive_all_ir_images": 0, - "base": "/mnt/data", - "base_template": "{base}/{project}/fl{flight}/{sys_cfg}/", - "effort": "default_effort", - "ext_evt": "json", - "ext_ins": "json", - "ext_ir": "tif", - "ext_p1": "jpg", - "ext_rgb": "jpg", - "ext_uv": "jpg", - "flight": "02", + "allow_ir_nuc": 1, + "archive_all_ir_images": 0, + "base": "/mnt/data", + "base_template": "{base}/{project}/fl{flight}/{sys_cfg}/", + "effort": "default_effort", + "ext_evt": "json", + "ext_ins": "json", + "ext_ir": "tif", + "ext_p1": "jpg", + "ext_rgb": "jpg", + "ext_uv": "jpg", + "flight": "02", "hosts": { - "cas0": { - "enabled": true, - "fov": "center", + "center-0-nayak": { + "enabled": true, + "fov": "center", "idx": 0 - }, - "cas1": { - "enabled": true, - "fov": "left", + }, + "left-1-nayak": { + "enabled": true, + "fov": "left", "idx": 1 - }, - "cas2": { - "enabled": true, - "fov": "right", + }, + "right-2-nayak": { + "enabled": true, + "fov": "right", "idx": 2 } - }, - "is_archiving": 0, + }, + "is_archiving": 0, "jpeg": { "quality": 90 - }, + }, "jpg": { "quality": 95 - }, - "kamera_dir": "/home/user/kw/kamera", - "load_shapefile": 0, - "max_exposure_ms": 120, - "max_fps": 2.5, - "max_frame_rate": 2.0, - "min_fps": 0.1, - "min_frame_rate": 0.1, - "overlap_percent": 25.0, - "project": "glacial_2024", + }, + "kamera_dir": "/home/user/kw/kamera", + "load_shapefile": 0, + "max_exposure_ms": 120, + "max_fps": 2.5, + "max_frame_rate": 2.0, + "min_fps": 0.1, + "min_frame_rate": 0.1, + "overlap_percent": 25.0, + "project": "glacial_2024", "rgb": { "format": "jpg" - }, - "rgb_vfov": 14, - "sys_cfg": "images_30deg_N68RF", - "template": "{base}/{project}/fl{flight}/{sys_cfg}/{cam_fov}_view/{project}_fl{flight}_{cf}_{time}_{mode}.{ext}", - "trigger_freq": 1.0, - "turn_off_nuc_in_shapefile": 1, - "use_archive_region": 0, + }, + "rgb_vfov": 14, + "sys_cfg": "images_30deg_N68RF", + "template": "{base}/{project}/fl{flight}/{sys_cfg}/{cam_fov}_view/{project}_fl{flight}_{cf}_{time}_{mode}.{ext}", + "trigger_freq": 1.0, + "turn_off_nuc_in_shapefile": 1, + "use_archive_region": 0, "use_p1jpeg": 0 - }, - "base": "/mnt/data", + }, + "base": "/mnt/data", "camera_cfgs": { "100mm_25_5deg_DualRegionTrigger": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_C_100mm_0deg.pipe", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_uv.yaml", - "description": "JoBSS configuration: color cameras mounted with 100mm zeiss lenses, side camera mounts set to 25.5 deg, running IR to RGB region trigger model with thresholds set to 1.0", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_L_100mm_25deg.pipe", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_R_100mm_25deg.pipe", + "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", + "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_rgb.yaml", + "center_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_C_100mm_0deg.pipe", + "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_uv.yaml", + "description": "JoBSS configuration: color cameras mounted with 100mm zeiss lenses, side camera mounts set to 25.5 deg, running IR to RGB region trigger model with thresholds set to 1.0", + "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", + "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", + "left_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_L_100mm_25deg.pipe", + "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_uv.yaml", + "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", + "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", + "right_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_R_100mm_25deg.pipe", "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_uv.yaml" - }, + }, "85mm_12_0deg_NoDetectionModel": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_center_rgb.yaml", - "center_sys_pipe": "", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_center_uv.yaml", - "description": "Configuration for 85mm lenses at 12.0* angles. No detectors installed. Intended for glacial mosaic sites.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_left_rgb.yaml", - "left_sys_pipe": "", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_right_rgb.yaml", - "right_sys_pipe": "", + "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_center_ir.yaml", + "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_center_rgb.yaml", + "center_sys_pipe": "", + "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_center_uv.yaml", + "description": "Configuration for 85mm lenses at 12.0* angles. No detectors installed. Intended for glacial mosaic sites.", + "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_left_ir.yaml", + "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_left_rgb.yaml", + "left_sys_pipe": "", + "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_left_uv.yaml", + "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_right_ir.yaml", + "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_right_rgb.yaml", + "right_sys_pipe": "", "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_right_uv.yaml" - }, + }, "85mm_21_0deg_IRDetector_P1": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_uv.yaml", - "description": "Configuration for 85mm lenses at 21.0* angles. Placeholder for Phase One cameras, IR-only detectors installed for Nth image saving.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", + "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_ir.yaml", + "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_rgb.yaml", + "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", + "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_uv.yaml", + "description": "Configuration for 85mm lenses at 21.0* angles. Placeholder for Phase One cameras, IR-only detectors installed for Nth image saving.", + "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_ir.yaml", + "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_rgb.yaml", + "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", + "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_uv.yaml", + "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_ir.yaml", + "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_rgb.yaml", + "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_uv.yaml" - }, + }, "85mm_21_0deg_NoDetectionModel": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_uv.yaml", - "description": "Configuration for 85mm lenses at 21.0* angles. Placeholder for Phase One cameras, IR-only detectors installed for Nth image saving.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", + "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_ir.yaml", + "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_rgb.yaml", + "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", + "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_uv.yaml", + "description": "Configuration for 85mm lenses at 21.0* angles. Placeholder for Phase One cameras, IR-only detectors installed for Nth image saving.", + "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_ir.yaml", + "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_rgb.yaml", + "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", + "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_uv.yaml", + "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_ir.yaml", + "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_rgb.yaml", + "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_uv.yaml" - }, + }, "85mm_25_5deg_NoDetectionModel": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_center_rgb.yaml", - "center_sys_pipe": "", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_center_uv.yaml", - "description": "Configuration for 85mm lenses at 25.5* angles. No detectors installed. Intended for glacial LATTE sites.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_left_rgb.yaml", - "left_sys_pipe": "", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_right_rgb.yaml", - "right_sys_pipe": "", + "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_center_ir.yaml", + "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_center_rgb.yaml", + "center_sys_pipe": "", + "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_center_uv.yaml", + "description": "Configuration for 85mm lenses at 25.5* angles. No detectors installed. Intended for glacial LATTE sites.", + "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_left_ir.yaml", + "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_left_rgb.yaml", + "left_sys_pipe": "", + "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_left_uv.yaml", + "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_right_ir.yaml", + "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_right_rgb.yaml", + "right_sys_pipe": "", "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_right_uv.yaml" - }, + }, "cam1": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_C_100mm_0deg.pipe", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_uv.yaml", - "description": "JoBSS configuration: color cameras mounted with 100mm zeiss lenses, side camera mounts set to 25.5 deg, running IR to RGB region trigger model with thresholds set to 1.0", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_L_100mm_25deg.pipe", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_R_100mm_25deg.pipe", + "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", + "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_rgb.yaml", + "center_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_C_100mm_0deg.pipe", + "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_uv.yaml", + "description": "JoBSS configuration: color cameras mounted with 100mm zeiss lenses, side camera mounts set to 25.5 deg, running IR to RGB region trigger model with thresholds set to 1.0", + "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", + "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", + "left_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_L_100mm_25deg.pipe", + "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_uv.yaml", + "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", + "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", + "right_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_R_100mm_25deg.pipe", "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_uv.yaml" - }, + }, "images_21deg_N56RF": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/2024_AOC_Calibration_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "center_uv_yaml_path": "", - "description": "Yaml files from JoBSS other than center color from Florida. These need to be reprocessed with ANC callibration files. IR only model loaded from JoBSS 2021.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "left_uv_yaml_path": "", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", + "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", + "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/2024_AOC_Calibration_center_rgb.yaml", + "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", + "center_uv_yaml_path": "", + "description": "Yaml files from JoBSS other than center color from Florida. These need to be reprocessed with ANC callibration files. IR only model loaded from JoBSS 2021.", + "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", + "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", + "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", + "left_uv_yaml_path": "", + "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", + "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", + "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", "right_uv_yaml_path": "" - }, + }, "images_25deg_N56RF": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/2024_AOC_Calibration_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "center_uv_yaml_path": "", - "description": "Yaml files from JoBSS other than center color from Florida. These need to be reprocessed with ANC callibration files. IR only model loaded from JoBSS 2021.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "left_uv_yaml_path": "", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", + "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", + "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/2024_AOC_Calibration_center_rgb.yaml", + "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", + "center_uv_yaml_path": "", + "description": "Yaml files from JoBSS other than center color from Florida. These need to be reprocessed with ANC callibration files. IR only model loaded from JoBSS 2021.", + "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", + "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", + "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", + "left_uv_yaml_path": "", + "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", + "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", + "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", "right_uv_yaml_path": "" - }, + }, "images_30deg_N68RF": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/2024_AOC_Calibration_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "center_uv_yaml_path": "", - "description": "calibration imagery from JoBSS other than center color from Florida. These need to be reprocessed with ANC callibration files. IR only model loaded from JoBSS 2021.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "left_uv_yaml_path": "", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", + "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", + "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/2024_AOC_Calibration_center_rgb.yaml", + "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", + "center_uv_yaml_path": "", + "description": "calibration imagery from JoBSS other than center color from Florida. These need to be reprocessed with ANC callibration files. IR only model loaded from JoBSS 2021.", + "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", + "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", + "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", + "left_uv_yaml_path": "", + "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", + "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", + "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", "right_uv_yaml_path": "" } - }, - "cas0": { - "cam_fov": "center", + }, + "center-0-nayak": { + "cam_fov": "center", "detector": { - "actual": "failed", - "desired": "running", + "actual": "failed", + "desired": "running", "health": { - "frame": 0, + "frame": 0, "time": 0.0 - }, - "last_change_desired": 1732034348.769255, + }, + "last_change_desired": 1732034348.769255, "pipefile": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe" - }, + }, "p1debayerq": { - "processed": 0, + "processed": 0, "total": 0 } - }, - "cas1": { - "cam_fov": "right", + }, + "left-1-nayak": { + "cam_fov": "right", "detector": { - "actual": "stalled", - "desired": "running", + "actual": "stalled", + "desired": "running", "health": { - "frame": 0, + "frame": 0, "time": 0.0 - }, - "last_change_desired": 1732034348.765598, + }, + "last_change_desired": 1732034348.765598, "pipefile": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe" - }, + }, "p1debayerq": { - "processed": 0, + "processed": 0, "total": 0 } - }, - "cas2": { - "cam_fov": "left", + }, + "right-2-nayak": { + "cam_fov": "left", "detector": { - "actual": "stalled", - "desired": "running", + "actual": "stalled", + "desired": "running", "health": { - "frame": 0, + "frame": 0, "time": 0.0 - }, - "last_change_desired": 1732034348.775121, + }, + "last_change_desired": 1732034348.775121, "pipefile": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe" - }, + }, "p1debayerq": { - "processed": 0, + "processed": 0, "total": 0 } - }, + }, "channels": { - "ir": 1, - "rgb": 0, + "ir": 1, + "rgb": 0, "uv": 2 - }, - "collection_mode": "fixed rate", + }, + "collection_mode": "fixed rate", "detector": { "read_from_nas": false - }, + }, "devices": { "ir_n0": { - "ip_mode": "fixed", - "mac": "00:11:1c:02:40:46", - "model": "flir_a6750", + "ip_mode": "fixed", + "mac": "00:11:1c:02:40:46", + "model": "flir_a6750", "prefer_ip": "192.168.1.50" - }, + }, "ir_n1": { - "ip_mode": "fixed", - "mac": "00:11:1c:01:ec:f7", - "model": "flir_a6750", + "ip_mode": "fixed", + "mac": "00:11:1c:01:ec:f7", + "model": "flir_a6750", "prefer_ip": "192.168.1.51" - }, + }, "ir_n2": { - "ip_mode": "fixed", - "mac": "00:11:1c:01:c8:5b", - "model": "flir_a6750", + "ip_mode": "fixed", + "mac": "00:11:1c:01:c8:5b", + "model": "flir_a6750", "prefer_ip": "192.168.1.52" - }, + }, "ir_nb0": { - "ip_mode": "dhcp", - "mac": "00:11:1c:00:e6:d1", - "model": "flir_a645", + "ip_mode": "dhcp", + "mac": "00:11:1c:00:e6:d1", + "model": "flir_a645", "prefer_ip": "192.168.1.53" - }, + }, "ir_nb1": { - "ip_mode": "dhcp", - "mac": "00:11:1c:00:bf:6a", - "model": "flir_a645", + "ip_mode": "dhcp", + "mac": "00:11:1c:00:bf:6a", + "model": "flir_a645", "prefer_ip": "192.168.1.54" - }, + }, "ir_nb2": { - "ip_mode": "dhcp", - "mac": "00:11:1c", - "model": "flir_a645", + "ip_mode": "dhcp", + "mac": "00:11:1c", + "model": "flir_a645", "prefer_ip": "192.168.1.55" - }, + }, "rgb_n0": { - "guid": 145260, - "ip_mode": "fixed", - "label": "PORT", - "mac": "00:0f:31:02:37:6c", - "model": "allied_gt6600_rgb", + "guid": 145260, + "ip_mode": "fixed", + "label": "PORT", + "mac": "00:0f:31:02:37:6c", + "model": "allied_gt6600_rgb", "prefer_ip": "169.254.151.51" - }, + }, "rgb_n1": { - "guid": 180877, - "ip_mode": "fixed", - "label": "unknown", - "mac": "00:0f:31:02:c2:8d", - "model": "allied_gt6600_rgb", + "guid": 180877, + "ip_mode": "fixed", + "label": "unknown", + "mac": "00:0f:31:02:c2:8d", + "model": "allied_gt6600_rgb", "prefer_ip": "192.168.4.41" - }, + }, "rgb_n2": { - "guid": 180876, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:c2:8c", - "model": "allied_gt6600_rgb", + "guid": 180876, + "ip_mode": "fixed", + "label": "CENTER", + "mac": "00:0f:31:02:c2:8c", + "model": "allied_gt6600_rgb", "prefer_ip": "192.168.4.42" - }, + }, "rgb_nb0": { - "guid": 145260, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:37:6c", - "model": "allied_gt6600_rgb", + "guid": 145260, + "ip_mode": "fixed", + "label": "CENTER", + "mac": "00:0f:31:02:37:6c", + "model": "allied_gt6600_rgb", "prefer_ip": "192.168.4.40" - }, + }, "rgb_nb1": { - "guid": 180877, - "ip_mode": "fixed", - "label": "unknown", - "mac": "00:0f:31:02:c2:8d", - "model": "allied_gt6600_rgb", + "guid": 180877, + "ip_mode": "fixed", + "label": "unknown", + "mac": "00:0f:31:02:c2:8d", + "model": "allied_gt6600_rgb", "prefer_ip": "192.168.4.41" - }, + }, "rgb_nb2": { - "guid": 180876, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:c2:8c", - "model": "allied_gt6600_rgb", + "guid": 180876, + "ip_mode": "fixed", + "label": "CENTER", + "mac": "00:0f:31:02:c2:8c", + "model": "allied_gt6600_rgb", "prefer_ip": "192.168.4.42" - }, + }, "rgb_p0": { - "guid": 145260, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:37:6c", - "model": "gsm-ix120", + "guid": 145260, + "ip_mode": "fixed", + "label": "CENTER", + "mac": "00:0f:31:02:37:6c", + "model": "gsm-ix120", "prefer_ip": "192.168.1.6" - }, + }, "rgb_p1": { - "guid": 180877, - "ip_mode": "fixed", - "label": "unknown", - "mac": "00:0f:31:02:c2:8d", - "model": "allied_gt6600_rgb", + "guid": 180877, + "ip_mode": "fixed", + "label": "unknown", + "mac": "00:0f:31:02:c2:8d", + "model": "allied_gt6600_rgb", "prefer_ip": "192.168.4.41" - }, + }, "rgb_p2": { - "guid": 180876, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:c2:8c", - "model": "allied_gt6600_rgb", + "guid": 180876, + "ip_mode": "fixed", + "label": "CENTER", + "mac": "00:0f:31:02:c2:8c", + "model": "allied_gt6600_rgb", "prefer_ip": "192.168.4.42" - }, + }, "uv_n0": { - "guid": 222298, - "ip_mode": "linklocal", - "label": "unknown", - "mac": "00:0f:31:03:64:5a", - "model": "allied_gt4907_uv", + "guid": 222298, + "ip_mode": "linklocal", + "label": "unknown", + "mac": "00:0f:31:03:64:5a", + "model": "allied_gt4907_uv", "prefer_ip": "192.168.2.60" - }, + }, "uv_n1": { - "guid": 222672, - "ip_mode": "linklocal", - "label": "unknown", - "mac": "00:0f:31:03:65:d0", - "model": "allied_gt4907_uv", + "guid": 222672, + "ip_mode": "linklocal", + "label": "unknown", + "mac": "00:0f:31:03:65:d0", + "model": "allied_gt4907_uv", "prefer_ip": "192.168.2.61" - }, + }, "uv_n2": { - "guid": 222246, - "ip_mode": "linklocal", - "label": "unknown", - "mac": "00:0f:31:03:64:26", - "model": "allied_gt4907_uv", + "guid": 222246, + "ip_mode": "linklocal", + "label": "unknown", + "mac": "00:0f:31:03:64:26", + "model": "allied_gt4907_uv", "prefer_ip": "192.168.2.62" } - }, + }, "effort_metadata_dict": { "OFF": { - "aircraft": "N56RF", - "delete_old_images_sec": 1, - "field_notes": "OFF effort but still collecting at tails of survey lines or other imagery of interest", - "project_name": "glacial_2024", - "save_every_x_image": 1, + "aircraft": "N56RF", + "delete_old_images_sec": 1, + "field_notes": "OFF effort but still collecting at tails of survey lines or other imagery of interest", + "project_name": "glacial_2024", + "save_every_x_image": 1, "wait_time_sec": 1 - }, + }, "ON": { - "aircraft": "N56RF", - "delete_old_images_sec": 1, - "field_notes": "Collecting imagery continuously on glacial harbor seal tracklines via COCOA and LATTE survey techniques", - "project_name": "glacial_2024", - "save_every_x_image": 1, + "aircraft": "N56RF", + "delete_old_images_sec": 1, + "field_notes": "Collecting imagery continuously on glacial harbor seal tracklines via COCOA and LATTE survey techniques", + "project_name": "glacial_2024", + "save_every_x_image": 1, "wait_time_sec": 1 - }, + }, "TEST": { - "aircraft": "N56RF", - "delete_old_images_sec": 1, - "field_notes": "Lab testing in Seattle during 11/24 integration.", - "project_name": "SEA_MML_1124", - "save_every_x_image": 1, + "aircraft": "N56RF", + "delete_old_images_sec": 1, + "field_notes": "Lab testing in Seattle during 11/24 integration.", + "project_name": "SEA_MML_1124", + "save_every_x_image": 1, "wait_time_sec": 1 } - }, + }, "effort_metadata_dict": { "default_effort": { "aircraft": "N94S", @@ -503,332 +503,332 @@ }, "enabled": { "center": { - "ir": true, - "rgb": true, + "ir": true, + "rgb": true, "uv": false - }, + }, "left": { - "ir": true, - "rgb": true, + "ir": true, + "rgb": true, "uv": false - }, + }, "right": { - "ir": true, - "rgb": true, + "ir": true, + "rgb": true, "uv": false } - }, - "flight_number_str": "02", - "gui_cfg_dir": "/home/user/.config/kamera/gui", + }, + "flight_number_str": "02", + "gui_cfg_dir": "/home/user/.config/kamera/gui", "gui_config": { - "collection_mode": "fixed rate", - "collection_mode_parameter": 1.0, + "collection_mode": "fixed rate", + "collection_mode_parameter": 1.0, "effort_metadata_dict": { "BEAR": { - "aircraft": "N56RF", - "field_notes": "Breaking survey track to conduct flyover of polar bear detected outside the survey swath to collect multispectral imagery of the bear for estimating detection probability.", + "aircraft": "N56RF", + "field_notes": "Breaking survey track to conduct flyover of polar bear detected outside the survey swath to collect multispectral imagery of the bear for estimating detection probability.", "project_name": "jobss_2021" - }, + }, "CALIBRATION": { - "aircraft": "N56RF", - "field_notes": "Backup calibration image set for ice seal configuration (100mm, 25.5deg) to be used for new camera models or h5 files as needed. flown at 1000 ft, 2000 ft, 3000 ft with heavy overlap.", + "aircraft": "N56RF", + "field_notes": "Backup calibration image set for ice seal configuration (100mm, 25.5deg) to be used for new camera models or h5 files as needed. flown at 1000 ft, 2000 ft, 3000 ft with heavy overlap.", "project_name": "jobss_2021" - }, + }, "IR_max": { - "aircraft": "N56RF", - "field_notes": "Determine the altitude limit of both the existing IR detection model as well as the hotspot integrity within the IR imagery. Mount configuration: 25.5 deg angle with 85 mm lens on color cameras.", + "aircraft": "N56RF", + "field_notes": "Determine the altitude limit of both the existing IR detection model as well as the hotspot integrity within the IR imagery. Mount configuration: 25.5 deg angle with 85 mm lens on color cameras.", "project_name": "pv_2021_test" - }, + }, "NUC_temp": { - "aircraft": "N56RF", - "field_notes": "Test whether the NUC control based on temperature provides necessary NUC events when the ambient temperature changes.", + "aircraft": "N56RF", + "field_notes": "Test whether the NUC control based on temperature provides necessary NUC events when the ambient temperature changes.", "project_name": "kamera_2021_test" - }, + }, "NUC_time": { - "aircraft": "N56RF", - "field_notes": "Test whether the NUC clock resets with each time change.", + "aircraft": "N56RF", + "field_notes": "Test whether the NUC clock resets with each time change.", "project_name": "kamera_2021_test" - }, + }, "OFF": { - "aircraft": "N56RF", - "field_notes": "Images collected while OFF effort during surveys for glacial harbor seals.", + "aircraft": "N56RF", + "field_notes": "Images collected while OFF effort during surveys for glacial harbor seals.", "project_name": "glacial_2021" - }, + }, "ON": { - "aircraft": "N56RF", - "field_notes": "Images collected for counting glacial harbor seals.", + "aircraft": "N56RF", + "field_notes": "Images collected for counting glacial harbor seals.", "project_name": "glacial_2021" - }, + }, "TEST": { - "aircraft": "N56RF", - "field_notes": "Test utility of KAMERA system for both coastal and glacial harbor seal surveys.", + "aircraft": "N56RF", + "field_notes": "Test utility of KAMERA system for both coastal and glacial harbor seal surveys.", "project_name": "pv_2021_test" - }, + }, "TEST_ON": { - "aircraft": "N56RF", - "field_notes": "test on effort", + "aircraft": "N56RF", + "field_notes": "test on effort", "project_name": "test0205" - }, + }, "UV_test": { - "aircraft": "N56RF", - "field_notes": "", + "aircraft": "N56RF", + "field_notes": "", "project_name": "kamera_2021_test" - }, + }, "VISUAL_COUNT": { - "aircraft": "N56RF", - "field_notes": "", + "aircraft": "N56RF", + "field_notes": "", "project_name": "glacial_2020" - }, + }, "aoc_fl_test": { - "aircraft": "N56RF", - "field_notes": "Full system test following revamp of electrical and mechanical design of big kamera system", + "aircraft": "N56RF", + "field_notes": "Full system test following revamp of electrical and mechanical design of big kamera system", "project_name": "aoc_2022_test" - }, + }, "aoc_fl_test_fixed_overlap": { - "aircraft": "N56RF", - "field_notes": "Full system test following revamp of electrical and mechanical design of big kamera system", + "aircraft": "N56RF", + "field_notes": "Full system test following revamp of electrical and mechanical design of big kamera system", "project_name": "aoc_2022_test" - }, + }, "compression_NAS": { - "aircraft": "N56RF", - "field_notes": "Test impact of compression on detection output. KAMERA set to run compressed imagery through the detector pipeline by routing images through the NAS. (COMPRESS_IMAGERY=0 and READ_FROM_NAS=1)", + "aircraft": "N56RF", + "field_notes": "Test impact of compression on detection output. KAMERA set to run compressed imagery through the detector pipeline by routing images through the NAS. (COMPRESS_IMAGERY=0 and READ_FROM_NAS=1)", "project_name": "kamera_2021_test" - }, + }, "compression_jobss": { - "aircraft": "N56RF", - "field_notes": "Test impact of compression on detection output. KAMERA set to run raw imagery through the detector pipeline and only save compressed imagery. (COMPRESS_IMAGERY=0 and READ_FROM_NAS=0)", + "aircraft": "N56RF", + "field_notes": "Test impact of compression on detection output. KAMERA set to run raw imagery through the detector pipeline and only save compressed imagery. (COMPRESS_IMAGERY=0 and READ_FROM_NAS=0)", "project_name": "kamera_2021_test" - }, + }, "compression_nexus": { - "aircraft": "N56RF", - "field_notes": "Test impact of compression on detection output. KAMERA set to compress and then uncompress color imagery to achieve the compression artifact in the image for the detector pipeline, while providing the image format the rest of the system is expecting. (COMPRESS_IMAGERY=1 and READ_FROM_NAS=0)", + "aircraft": "N56RF", + "field_notes": "Test impact of compression on detection output. KAMERA set to compress and then uncompress color imagery to achieve the compression artifact in the image for the detector pipeline, while providing the image format the rest of the system is expecting. (COMPRESS_IMAGERY=1 and READ_FROM_NAS=0)", "project_name": "kamera_2021_test" - }, + }, "kw_lab": { - "aircraft": "N/A", - "field_notes": "Testing in KHQ lab.", + "aircraft": "N/A", + "field_notes": "Testing in KHQ lab.", "project_name": "kw_012023_test" - }, + }, "test": { - "aircraft": "N56RF", - "field_notes": "Full system test following revamp of electrical and mechanical design of big kamera system", + "aircraft": "N56RF", + "field_notes": "Full system test following revamp of electrical and mechanical design of big kamera system", "project_name": "aoc_2022_test" } - }, - "effort_selection": 0, - "flight_number_str": "00", - "ir_contrast_strength": 200.0, - "observer": "", - "rgb_vfov": 14, - "shapefile_fname": null, - "show_center": true, - "show_ir": true, - "show_left": true, - "show_rgb": true, - "show_right": true, - "show_uv": true, - "sys_cfg": null, + }, + "effort_selection": 0, + "flight_number_str": "00", + "ir_contrast_strength": 200.0, + "observer": "", + "rgb_vfov": 14, + "shapefile_fname": null, + "show_center": true, + "show_ir": true, + "show_left": true, + "show_rgb": true, + "show_right": true, + "show_uv": true, + "sys_cfg": null, "sys_config_selection": "cam9" - }, + }, "interfaces": { - "ir": "mobo_top", - "p1": "pci_bot", - "rgb": "pci_btm", + "ir": "mobo_top", + "p1": "pci_bot", + "rgb": "pci_btm", "uv": "mobo_btm" - }, - "ir_contrast_strength": 1000.0, - "kamera_dir": "/home/user/kw/noaa_kamera", - "latch_frame_rate_msg": false, + }, + "ir_contrast_strength": 1000.0, + "kamera_dir": "/home/user/kw/noaa_kamera", + "latch_frame_rate_msg": false, "launch": { "cam": { "rgb": { - "GainMode": "Auto", + "GainMode": "Auto", "GainValue": 0 - }, + }, "uv": { - "GainMode": "Auto", + "GainMode": "Auto", "GainValue": 0 } } - }, - "load_shapefile": 0, - "local_ssd_mnt": "/mnt/data", + }, + "load_shapefile": 0, + "local_ssd_mnt": "/mnt/data", "locations": { "center": { - "ir": "ir_n0", - "p1": "rgb_p0", - "rgb": "rgb_n0", + "ir": "ir_n0", + "p1": "rgb_p0", + "rgb": "rgb_n0", "uv": "uv_n0" - }, + }, "left": { - "ir": "ir_n1", - "p1": "rgb_p1", - "rgb": "rgb_n1", + "ir": "ir_n1", + "p1": "rgb_p1", + "rgb": "rgb_n1", "uv": "uv_n1" - }, + }, "right": { - "ir": "ir_n2", - "p1": "rgb_p2", - "rgb": "rgb_n2", + "ir": "ir_n2", + "p1": "rgb_p2", + "rgb": "rgb_n2", "uv": "uv_n2" } - }, - "master_host": "cas0", - "max_mpix": 200000, + }, + "master_host": "center-0-nayak", + "max_mpix": 200000, "models": { "allied_gt4907_uv": { - "mac_prefix": "00:0f:31", - "mfgr": "allied vision", - "nic_mfgr": "", + "mac_prefix": "00:0f:31", + "mfgr": "allied vision", + "nic_mfgr": "", "specs": { - "height": 3232, + "height": 3232, "width": 4864 - }, + }, "spectrum": "uv" - }, + }, "allied_gt6600_rgb": { - "mac_prefix": "00:0f:31", - "mfgr": "allied vision", - "nic_mfgr": "", + "mac_prefix": "00:0f:31", + "mfgr": "allied vision", + "nic_mfgr": "", "specs": { - "height": 4384, + "height": 4384, "width": 6576 - }, + }, "spectrum": "rgb" - }, + }, "flir_645": { - "mac_prefix": "", - "mfgr": "flir", - "nic_mfgr": "", + "mac_prefix": "", + "mfgr": "flir", + "nic_mfgr": "", "specs": { - "height": 480, + "height": 480, "width": 640 - }, + }, "spectrum": "ir" - }, + }, "flir_a6750": { - "mac_prefix": "00:11:1c", - "mfgr": "flir", - "nic_mfgr": "pleora", + "mac_prefix": "00:11:1c", + "mfgr": "flir", + "nic_mfgr": "pleora", "specs": { - "height": 512, + "height": 512, "width": 640 - }, + }, "spectrum": "ir" - }, + }, "gsm_ix120": { - "mac_prefix": "", - "mfgr": "phase one", - "nic_mfgr": "", + "mac_prefix": "", + "mfgr": "phase one", + "nic_mfgr": "", "specs": { - "height": 9654, + "height": 9654, "width": 12768 - }, + }, "spectrum": "rgb" } - }, - "nas_mnt": "/mnt/flight_data", - "observer": "AR", + }, + "nas_mnt": "/mnt/flight_data", + "observer": "AR", "postproc_commands": [ - "flight_summary", - "homography", + "flight_summary", + "homography", "detections" - ], - "redis_host": "cas0", + ], + "redis_host": "center-0-nayak", "requested_geni_params": { - "cas0": { + "center-0-nayak": { "ir": { - "CorrectionAutoEnabled": 1, + "CorrectionAutoEnabled": 1, "CorrectionAutoUseDeltaTime": 0 - }, + }, "rgb": { - "ISO": 200, - "ISO_Max": 200, - "ISO_Min": 200, - "Sensor_Temperature": 1.0, - "Shutter_Speed": 0.01, - "Shutter_Speed_Max": 6.25e-05, + "ISO": 200, + "ISO_Max": 200, + "ISO_Min": 200, + "Sensor_Temperature": 1.0, + "Shutter_Speed": 0.01, + "Shutter_Speed_Max": 6.25e-05, "Shutter_Speed_Min": 0.25 - }, + }, "uv": { - "ExposureAuto": "Continuous", - "ExposureAutoMax": 2400.0, - "ExposureAutoMin": 400.0, - "ExposureValue": 0, - "GainAuto": "Auto", - "GainAutoMax": 30, - "GainAutoMin": 0, + "ExposureAuto": "Continuous", + "ExposureAutoMax": 2400.0, + "ExposureAutoMin": 400.0, + "ExposureValue": 0, + "GainAuto": "Auto", + "GainAutoMax": 30, + "GainAutoMin": 0, "GainValue": 0 } - }, - "cas1": { + }, + "left-1-nayak": { "ir": { "CorrectionAutoEnabled": 1 - }, + }, "rgb": { - "ISO": 200, - "ISO_Max": 200, - "ISO_Min": 200, - "Sensor_Temperature": 1.0, - "Shutter_Speed": 0.01, - "Shutter_Speed_Max": 6.25e-05, + "ISO": 200, + "ISO_Max": 200, + "ISO_Min": 200, + "Sensor_Temperature": 1.0, + "Shutter_Speed": 0.01, + "Shutter_Speed_Max": 6.25e-05, "Shutter_Speed_Min": 0.008 - }, + }, "uv": { - "ExposureAuto": "Continuous", - "ExposureAutoMax": 5760.0, - "ExposureAutoMin": 400.0, - "ExposureValue": 0, - "GainAuto": "Auto", - "GainAutoMax": 30, - "GainAutoMin": 2, + "ExposureAuto": "Continuous", + "ExposureAutoMax": 5760.0, + "ExposureAutoMin": 400.0, + "ExposureValue": 0, + "GainAuto": "Auto", + "GainAutoMax": 30, + "GainAutoMin": 2, "GainValue": 0 } - }, - "cas2": { + }, + "right-2-nayak": { "ir": { "CorrectionAutoEnabled": 1 - }, + }, "rgb": { - "ISO": 200, - "ISO_Max": 200, - "ISO_Min": 200, - "Sensor_Temperature": 1.0, - "Shutter_Mode": 0, - "Shutter_Speed": 0.01, - "Shutter_Speed_Max": 6.25e-05, + "ISO": 200, + "ISO_Max": 200, + "ISO_Min": 200, + "Sensor_Temperature": 1.0, + "Shutter_Mode": 0, + "Shutter_Speed": 0.01, + "Shutter_Speed_Max": 6.25e-05, "Shutter_Speed_Min": 0.008 - }, + }, "uv": { - "ExposureAuto": "Continuous", - "ExposureAutoMax": 2454.0, - "ExposureAutoMin": 400.0, - "ExposureValue": 0, - "GainAuto": "Auto", - "GainAutoMax": 30, - "GainAutoMin": 0, + "ExposureAuto": "Continuous", + "ExposureAutoMax": 2454.0, + "ExposureAutoMin": 400.0, + "ExposureValue": 0, + "GainAuto": "Auto", + "GainAutoMax": 30, + "GainAutoMin": 0, "GainValue": 0 } } - }, - "rgb_vfov": 17.266922854601024, - "shapefile_fname": "/home/user/kamera_ws/src/kitware-ros-pkg/wxpython_gui/shapefiles/KotzTestAndUAS.shp", - "show_center": true, - "show_ir": true, - "show_left": true, - "show_rgb": true, - "show_right": true, - "show_saturated_pixels": true, - "show_uv": false, - "syscfg_dir": "/mnt/data/glacial_2024/fl02/images_30deg_N68RF/", + }, + "rgb_vfov": 17.266922854601024, + "shapefile_fname": "/home/user/kamera_ws/src/kitware-ros-pkg/wxpython_gui/shapefiles/KotzTestAndUAS.shp", + "show_center": true, + "show_ir": true, + "show_left": true, + "show_rgb": true, + "show_right": true, + "show_saturated_pixels": true, + "show_uv": false, + "syscfg_dir": "/mnt/data/glacial_2024/fl02/images_30deg_N68RF/", "uas0": { "cam_fov": "center" - }, + }, "uas1": { "cam_fov": "right" - }, + }, "uas2": { "cam_fov": "left" - }, + }, "verbosity": 9 } diff --git a/src/cfg/nayak/cas1/chrony.conf b/src/cfg/nayak/left-1-nayak/chrony.conf similarity index 100% rename from src/cfg/nayak/cas1/chrony.conf rename to src/cfg/nayak/left-1-nayak/chrony.conf diff --git a/src/cfg/nayak/cas1/custom-netplan.yaml b/src/cfg/nayak/left-1-nayak/custom-netplan.yaml similarity index 97% rename from src/cfg/nayak/cas1/custom-netplan.yaml rename to src/cfg/nayak/left-1-nayak/custom-netplan.yaml index 60538fe..6793f3a 100755 --- a/src/cfg/nayak/cas1/custom-netplan.yaml +++ b/src/cfg/nayak/left-1-nayak/custom-netplan.yaml @@ -1,5 +1,4 @@ --- -## Netplan for cas1 network: version: 2 ethernets: diff --git a/src/cfg/nayak/redis.conf b/src/cfg/nayak/redis.conf index 83b2574..f2a7ebf 100755 --- a/src/cfg/nayak/redis.conf +++ b/src/cfg/nayak/redis.conf @@ -66,9 +66,7 @@ # IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES # JUST COMMENT THE FOLLOWING LINE. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -bind 127.0.0.1 ::1 -bind ::1 -bind 100.119.87.82 192.168.88.10 +bind center-0-nayak # Protected mode is a layer of security protection, in order to avoid that # Redis instances left open on the internet are accessed and exploited. diff --git a/src/cfg/nayak/cas2/chrony.conf b/src/cfg/nayak/right-2-nayak/chrony.conf similarity index 100% rename from src/cfg/nayak/cas2/chrony.conf rename to src/cfg/nayak/right-2-nayak/chrony.conf diff --git a/src/cfg/nayak/cas2/custom-netplan.yaml b/src/cfg/nayak/right-2-nayak/custom-netplan.yaml similarity index 97% rename from src/cfg/nayak/cas2/custom-netplan.yaml rename to src/cfg/nayak/right-2-nayak/custom-netplan.yaml index 4432e02..0a4cba5 100644 --- a/src/cfg/nayak/cas2/custom-netplan.yaml +++ b/src/cfg/nayak/right-2-nayak/custom-netplan.yaml @@ -1,5 +1,4 @@ --- -## Netplan for cas2 network: version: 2 ethernets: From 0b198b627c86d740e02f73722a5deac3557d1d13 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 10 Jun 2026 16:56:46 -0400 Subject: [PATCH 030/139] Move up hosts to top-level cfg --- src/cfg/hosts | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/cfg/hosts b/src/cfg/hosts index 412acf3..9505f29 100644 --- a/src/cfg/hosts +++ b/src/cfg/hosts @@ -1,29 +1,33 @@ +127.0.0.1 localhost.localdomain localhost +::1 localhost6.localdomain6 localhost6 -# ================== Inserted from KAMERA ============================ -# Set ros master url here - typically nuvo0 -#192.168.88.10 master +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +ff02::3 ip6-allhosts +# Inserted from KAMERA 192.168.88.1 mikrotik -192.168.88.10 nuvo0 -192.168.88.11 nuvo1 -192.168.88.12 nuvo2 - -192.168.88.40 rgb0 -192.168.88.41 rgb1 -192.168.88.42 rgb2 - -192.168.88.50 ir0 -192.168.88.51 ir1 -192.168.88.52 ir2 +192.168.88.10 center-0-taiga +192.168.88.11 left-1-taiga +192.168.88.12 right-2-taiga -192.168.88.60 uv0 -192.168.88.61 uv1 -192.168.88.62 uv2 +192.168.88.100 center-0-nayak +192.168.88.101 left-1-nayak +192.168.88.102 right-2-nayak +192.168.88.103 center-1-nayak # Fallback static connections 192.168.88.210 nuvo0bak 192.168.88.211 nuvo1bak 192.168.88.212 nuvo2bak -# ========================================================================= +192.168.198.10 kamera_nas + +# Set ros master url here - typically nuvo0 +192.168.88.10 kameramaster +192.168.88.99 ins + From 9cd1b7cc4ecdec1f2aa1f613e70dc3d480975ccc Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 10 Jun 2026 17:13:19 -0400 Subject: [PATCH 031/139] Remove cruft, consolidate redis config --- .../camera_models/2019-06-01/center_ir.yaml | 35 - .../camera_models/2019-06-01/center_rgb.yaml | 35 - src/cfg/camera_models/2019-06-01/left_ir.yaml | 35 - .../camera_models/2019-06-01/left_rgb.yaml | 35 - .../camera_models/2019-06-01/right_ir.yaml | 35 - .../camera_models/2019-06-01/right_rgb.yaml | 35 - src/cfg/cas/cas0/chrony.conf | 54 - src/cfg/nayak/redis.conf | 2 +- src/cfg/redis.conf | 1319 ----------------- src/cfg/redis/nayak_redis.conf | 1319 ----------------- src/cfg/redis/nayak_system_config.txt | 19 - src/cfg/redis/taiga_system_config.txt | 19 - src/cfg/redis/uas_redis.conf | 1317 ---------------- src/cfg/redis/uas_system_config.txt | 21 - src/cfg/taiga/redis.conf | 2 +- 15 files changed, 2 insertions(+), 4280 deletions(-) delete mode 100644 src/cfg/camera_models/2019-06-01/center_ir.yaml delete mode 100644 src/cfg/camera_models/2019-06-01/center_rgb.yaml delete mode 100644 src/cfg/camera_models/2019-06-01/left_ir.yaml delete mode 100644 src/cfg/camera_models/2019-06-01/left_rgb.yaml delete mode 100644 src/cfg/camera_models/2019-06-01/right_ir.yaml delete mode 100644 src/cfg/camera_models/2019-06-01/right_rgb.yaml delete mode 100644 src/cfg/cas/cas0/chrony.conf delete mode 100755 src/cfg/redis.conf delete mode 100755 src/cfg/redis/nayak_redis.conf delete mode 100644 src/cfg/redis/nayak_system_config.txt delete mode 100644 src/cfg/redis/taiga_system_config.txt delete mode 100644 src/cfg/redis/uas_redis.conf delete mode 100644 src/cfg/redis/uas_system_config.txt diff --git a/src/cfg/camera_models/2019-06-01/center_ir.yaml b/src/cfg/camera_models/2019-06-01/center_ir.yaml deleted file mode 100644 index daa5ea8..0000000 --- a/src/cfg/camera_models/2019-06-01/center_ir.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# The type of camera model. -model_type: standard - -# Image dimensions -image_width: 640 -image_height: 512 - -# Focal length along the image's x-axis. -fx: 1681.1171203185347 - -# Focal length along the image's y-axis. -fy: 1681.1171203185347 - -# Principal point is located at (cx,cy). -cx: 320.0 -cy: 256.0 - -# Distortion coefficients following OpenCv's convention -distortion_coefficients: [0.0, 0.0, 0.0, 0.0] - -# Quaternion specifying the orientation of the camera relative to the -# navigation coordinate system. The quaternion represents a coordinate system -# rotation that takes the navigation coordinate system and rotates it into the -# camera coordinate system. -camera_quaternion: [-0.00097259209895627372, -0.0042199309122074747, 0.70144572400044503, 0.7127097182789055, 1681.1171203185347] - -# Position of the camera's center of projection within the navigation -# coordinate system. -camera_position: [0, 0, 0] - -# Topic on which this camera's image is published -image_topic: /support/camera/ir/image_raw - -# The frame_id embedded in the published image header. -frame_id: /v4l_frame \ No newline at end of file diff --git a/src/cfg/camera_models/2019-06-01/center_rgb.yaml b/src/cfg/camera_models/2019-06-01/center_rgb.yaml deleted file mode 100644 index de01058..0000000 --- a/src/cfg/camera_models/2019-06-01/center_rgb.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# The type of camera model. -model_type: standard - -# Image dimensions -image_width: 6576 -image_height: 4384 - -# Focal length along the image's x-axis. -fx: 17798.799999999999 - -# Focal length along the image's y-axis. -fy: 17799.400000000001 - -# Principal point is located at (cx,cy). -cx: 3288.0 -cy: 2192.0 - -# Distortion coefficients following OpenCv's convention -distortion_coefficients: [0.11232399999999999, -0.64612599999999998, 0.00073262900000000005, 0.0012307100000000001] - -# Quaternion specifying the orientation of the camera relative to the -# navigation coordinate system. The quaternion represents a coordinate system -# rotation that takes the navigation coordinate system and rotates it into the -# camera coordinate system. -camera_quaternion: [-0.00074393285126745094, -0.0025800289760693055, -0.70293992787349957, -0.71124415485513459] - -# Position of the camera's center of projection within the navigation -# coordinate system. -camera_position: [0, 0, 0] - -# Topic on which this camera's image is published -image_topic: /support/camera/ir/image_raw - -# The frame_id embedded in the published image header. -frame_id: /v4l_frame \ No newline at end of file diff --git a/src/cfg/camera_models/2019-06-01/left_ir.yaml b/src/cfg/camera_models/2019-06-01/left_ir.yaml deleted file mode 100644 index 2589e21..0000000 --- a/src/cfg/camera_models/2019-06-01/left_ir.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# The type of camera model. -model_type: standard - -# Image dimensions -image_width: 640 -image_height: 512 - -# Focal length along the image's x-axis. -fx: 1692.5651043929938 - -# Focal length along the image's y-axis. -fy: 1692.5651043929938 - -# Principal point is located at (cx,cy). -cx: 320.0 -cy: 256.0 - -# Distortion coefficients following OpenCv's convention -distortion_coefficients: [0.0, 0.0, 0.0, 0.0] - -# Quaternion specifying the orientation of the camera relative to the -# navigation coordinate system. The quaternion represents a coordinate system -# rotation that takes the navigation coordinate system and rotates it into the -# camera coordinate system. -camera_quaternion: [0.15235678875699318, -0.15382275838142417, 0.68735893363636913, 0.69329911601981753, 1692.5651043929938] - -# Position of the camera's center of projection within the navigation -# coordinate system. -camera_position: [0, 0, 0] - -# Topic on which this camera's image is published -image_topic: /support/camera/ir/image_raw - -# The frame_id embedded in the published image header. -frame_id: /v4l_frame \ No newline at end of file diff --git a/src/cfg/camera_models/2019-06-01/left_rgb.yaml b/src/cfg/camera_models/2019-06-01/left_rgb.yaml deleted file mode 100644 index a9fa67a..0000000 --- a/src/cfg/camera_models/2019-06-01/left_rgb.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# The type of camera model. -model_type: standard - -# Image dimensions -image_width: 6576 -image_height: 4384 - -# Focal length along the image's x-axis. -fx: 17600.900000000001 - -# Focal length along the image's y-axis. -fy: 17595.200000000001 - -# Principal point is located at (cx,cy). -cx: 3288.0 -cy: 2192.0 - -# Distortion coefficients following OpenCv's convention -distortion_coefficients: [0.067674200000000004, -0.61220300000000005, -0.00032957599999999999, 0.00079841099999999996] - -# Quaternion specifying the orientation of the camera relative to the -# navigation coordinate system. The quaternion represents a coordinate system -# rotation that takes the navigation coordinate system and rotates it into the -# camera coordinate system. -camera_quaternion: [-0.15726610480508291, 0.15265580554892136, -0.69069844765801303, -0.68912932872898236] - -# Position of the camera's center of projection within the navigation -# coordinate system. -camera_position: [0, 0, 0] - -# Topic on which this camera's image is published -image_topic: /support/camera/ir/image_raw - -# The frame_id embedded in the published image header. -frame_id: /v4l_frame \ No newline at end of file diff --git a/src/cfg/camera_models/2019-06-01/right_ir.yaml b/src/cfg/camera_models/2019-06-01/right_ir.yaml deleted file mode 100644 index bc47ede..0000000 --- a/src/cfg/camera_models/2019-06-01/right_ir.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# The type of camera model. -model_type: standard - -# Image dimensions -image_width: 640 -image_height: 512 - -# Focal length along the image's x-axis. -fx: 1426.1848098660487 - -# Focal length along the image's y-axis. -fy: 1426.1848098660487 - -# Principal point is located at (cx,cy). -cx: 320.0 -cy: 256.0 - -# Distortion coefficients following OpenCv's convention -distortion_coefficients: [0.0, 0.0, 0.0, 0.0] - -# Quaternion specifying the orientation of the camera relative to the -# navigation coordinate system. The quaternion represents a coordinate system -# rotation that takes the navigation coordinate system and rotates it into the -# camera coordinate system. -camera_quaternion: [-0.11582211405518728, 0.17934783132575322, 0.73952349852930388, 0.63837652558463887, 1426.1848098660487] - -# Position of the camera's center of projection within the navigation -# coordinate system. -camera_position: [0, 0, 0] - -# Topic on which this camera's image is published -image_topic: /support/camera/ir/image_raw - -# The frame_id embedded in the published image header. -frame_id: /v4l_frame \ No newline at end of file diff --git a/src/cfg/camera_models/2019-06-01/right_rgb.yaml b/src/cfg/camera_models/2019-06-01/right_rgb.yaml deleted file mode 100644 index a50338e..0000000 --- a/src/cfg/camera_models/2019-06-01/right_rgb.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# The type of camera model. -model_type: standard - -# Image dimensions -image_width: 6576 -image_height: 4384 - -# Focal length along the image's x-axis. -fx: 17557.099999999999 - -# Focal length along the image's y-axis. -fy: 17571.700000000001 - -# Principal point is located at (cx,cy). -cx: 3288.0 -cy: 2192.0 - -# Distortion coefficients following OpenCv's convention -distortion_coefficients: [0.070478200000000005, -0.62560199999999999, 0.0023154500000000001, -0.000130455] - -# Quaternion specifying the orientation of the camera relative to the -# navigation coordinate system. The quaternion represents a coordinate system -# rotation that takes the navigation coordinate system and rotates it into the -# camera coordinate system. -camera_quaternion: [0.15038965912165231, -0.15710272085601801, -0.68562752301905927, -0.69470611427254525] - -# Position of the camera's center of projection within the navigation -# coordinate system. -camera_position: [0, 0, 0] - -# Topic on which this camera's image is published -image_topic: /support/camera/ir/image_raw - -# The frame_id embedded in the published image header. -frame_id: /v4l_frame \ No newline at end of file diff --git a/src/cfg/cas/cas0/chrony.conf b/src/cfg/cas/cas0/chrony.conf deleted file mode 100644 index 809b3bc..0000000 --- a/src/cfg/cas/cas0/chrony.conf +++ /dev/null @@ -1,54 +0,0 @@ -# Welcome to the chrony configuration file. See chrony.conf(5) for more -# information about usuable directives. - -# This will use (up to): -# - 4 sources from ntp.ubuntu.com which some are ipv6 enabled -# - 2 sources from 2.ubuntu.pool.ntp.org which is ipv6 enabled as well -# - 1 source from [01].ubuntu.pool.ntp.org each (ipv4 only atm) -# This means by default, up to 6 dual-stack and up to 2 additional IPv4-only -# sources will be used. -# At the same time it retains some protection against one of the entries being -# down (compare to just using one of the lines). See (LP: #1754358) for the -# discussion. -# -# About using servers from the NTP Pool Project in general see (LP: #104525). -# Approved by Ubuntu Technical Board on 2011-02-08. -# See http://www.pool.ntp.org/join.html for more information. -server 192.168.88.99 iburst minpoll 0 maxpoll 2 auto_offline -pool pool.ntp.org iburst maxsources 4 auto_offline -pool ntp.ubuntu.com iburst maxsources 4 auto_offline -#pool 0.ubuntu.pool.ntp.org iburst maxsources 1 -#pool 1.ubuntu.pool.ntp.org iburst maxsources 1 -#pool 2.ubuntu.pool.ntp.org iburst maxsources 2 - -# act as server -allow 192.168.88.0/24 - -# Define self as a local source of truth if offline -# 3 is defined arbitralily here, closer to 1 is the more trusted this source is -local stratum 3 - -# This directive specify the location of the file containing ID/key pairs for -# NTP authentication. -keyfile /etc/chrony/chrony.keys - -# This directive specify the file into which chronyd will store the rate -# information. -driftfile /var/lib/chrony/chrony.drift - -# Uncomment the following line to turn logging on. -#log tracking measurements statistics - -# Log files location. -logdir /var/log/chrony - -# Stop bad estimates upsetting machine clock. -maxupdateskew 100.0 - -# This directive enables kernel synchronisation (every 11 minutes) of the -# real-time clock. Note that it can’t be used along with the 'rtcfile' directive. -rtcsync - -# Step the system clock instead of slewing it if the adjustment is larger than -# one second, but only in the first three clock updates. -makestep 1 3 diff --git a/src/cfg/nayak/redis.conf b/src/cfg/nayak/redis.conf index f2a7ebf..cf14537 100755 --- a/src/cfg/nayak/redis.conf +++ b/src/cfg/nayak/redis.conf @@ -85,7 +85,7 @@ bind center-0-nayak # you are sure you want clients from other hosts to connect to Redis # even if no authentication is configured, nor a specific set of interfaces # are explicitly listed using the "bind" directive. -protected-mode yes +protected-mode no # Accept connections on the specified port, default is 6379 (IANA #815344). # If port 0 is specified Redis will not listen on a TCP socket. diff --git a/src/cfg/redis.conf b/src/cfg/redis.conf deleted file mode 100755 index 033bfb5..0000000 --- a/src/cfg/redis.conf +++ /dev/null @@ -1,1319 +0,0 @@ -# Redis configuration file example. -# -# Note that in order to read the configuration file, Redis must be -# started with the file path as first argument: -# -# ./redis-server /path/to/redis.conf - -# Note on units: when memory size is needed, it is possible to specify -# it in the usual form of 1k 5GB 4M and so forth: -# -# 1k => 1000 bytes -# 1kb => 1024 bytes -# 1m => 1000000 bytes -# 1mb => 1024*1024 bytes -# 1g => 1000000000 bytes -# 1gb => 1024*1024*1024 bytes -# -# units are case insensitive so 1GB 1Gb 1gB are all the same. - -################################## INCLUDES ################################### - -# Include one or more other config files here. This is useful if you -# have a standard template that goes to all Redis servers but also need -# to customize a few per-server settings. Include files can include -# other files, so use this wisely. -# -# Notice option "include" won't be rewritten by command "CONFIG REWRITE" -# from admin or Redis Sentinel. Since Redis always uses the last processed -# line as value of a configuration directive, you'd better put includes -# at the beginning of this file to avoid overwriting config change at runtime. -# -# If instead you are interested in using includes to override configuration -# options, it is better to use include as the last line. -# -# include /path/to/local.conf -# include /path/to/other.conf - -################################## MODULES ##################################### - -# Load modules at startup. If the server is not able to load modules -# it will abort. It is possible to use multiple loadmodule directives. -# -# loadmodule /path/to/my_module.so -# loadmodule /path/to/other_module.so - -################################## NETWORK ##################################### - -# By default, if no "bind" configuration directive is specified, Redis listens -# for connections from all the network interfaces available on the server. -# It is possible to listen to just one or multiple selected interfaces using -# the "bind" configuration directive, followed by one or more IP addresses. -# -# Examples: -# -# bind 192.168.1.100 10.0.0.1 -# bind 127.0.0.1 ::1 -# -# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the -# internet, binding to all the interfaces is dangerous and will expose the -# instance to everybody on the internet. So by default we uncomment the -# following bind directive, that will force Redis to listen only into -# the IPv4 lookback interface address (this means Redis will be able to -# accept connections only from clients running into the same computer it -# is running). -# -# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES -# JUST COMMENT THE FOLLOWING LINE. -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -bind 127.0.0.1 ::1 -bind ::1 -bind 0.0.0.0 - -# Protected mode is a layer of security protection, in order to avoid that -# Redis instances left open on the internet are accessed and exploited. -# -# When protected mode is on and if: -# -# 1) The server is not binding explicitly to a set of addresses using the -# "bind" directive. -# 2) No password is configured. -# -# The server only accepts connections from clients connecting from the -# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain -# sockets. -# -# By default protected mode is enabled. You should disable it only if -# you are sure you want clients from other hosts to connect to Redis -# even if no authentication is configured, nor a specific set of interfaces -# are explicitly listed using the "bind" directive. -protected-mode yes - -# Accept connections on the specified port, default is 6379 (IANA #815344). -# If port 0 is specified Redis will not listen on a TCP socket. -port 6379 - -# TCP listen() backlog. -# -# In high requests-per-second environments you need an high backlog in order -# to avoid slow clients connections issues. Note that the Linux kernel -# will silently truncate it to the value of /proc/sys/net/core/somaxconn so -# make sure to raise both the value of somaxconn and tcp_max_syn_backlog -# in order to get the desired effect. -tcp-backlog 511 - -# Unix socket. -# -# Specify the path for the Unix socket that will be used to listen for -# incoming connections. There is no default, so Redis will not listen -# on a unix socket when not specified. -# -# unixsocket /var/run/redis/redis-server.sock -# unixsocketperm 700 - -# Close the connection after a client is idle for N seconds (0 to disable) -timeout 0 - -# TCP keepalive. -# -# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence -# of communication. This is useful for two reasons: -# -# 1) Detect dead peers. -# 2) Take the connection alive from the point of view of network -# equipment in the middle. -# -# On Linux, the specified value (in seconds) is the period used to send ACKs. -# Note that to close the connection the double of the time is needed. -# On other kernels the period depends on the kernel configuration. -# -# A reasonable value for this option is 300 seconds, which is the new -# Redis default starting with Redis 3.2.1. -tcp-keepalive 300 - -################################# GENERAL ##################################### - -# By default Redis does not run as a daemon. Use 'yes' if you need it. -# Note that Redis will write a pid file in /var/run/redis.pid when daemonized. -daemonize yes - -# If you run Redis from upstart or systemd, Redis can interact with your -# supervision tree. Options: -# supervised no - no supervision interaction -# supervised upstart - signal upstart by putting Redis into SIGSTOP mode -# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET -# supervised auto - detect upstart or systemd method based on -# UPSTART_JOB or NOTIFY_SOCKET environment variables -# Note: these supervision methods only signal "process is ready." -# They do not enable continuous liveness pings back to your supervisor. -supervised no - -# If a pid file is specified, Redis writes it where specified at startup -# and removes it at exit. -# -# When the server runs non daemonized, no pid file is created if none is -# specified in the configuration. When the server is daemonized, the pid file -# is used even if not specified, defaulting to "/var/run/redis.pid". -# -# Creating a pid file is best effort: if Redis is not able to create it -# nothing bad happens, the server will start and run normally. -pidfile /var/run/redis/redis-server.pid - -# Specify the server verbosity level. -# This can be one of: -# debug (a lot of information, useful for development/testing) -# verbose (many rarely useful info, but not a mess like the debug level) -# notice (moderately verbose, what you want in production probably) -# warning (only very important / critical messages are logged) -loglevel notice - -# Specify the log file name. Also the empty string can be used to force -# Redis to log on the standard output. Note that if you use standard -# output for logging but daemonize, logs will be sent to /dev/null -logfile /var/log/redis/redis-server.log - -# To enable logging to the system logger, just set 'syslog-enabled' to yes, -# and optionally update the other syslog parameters to suit your needs. -# syslog-enabled no - -# Specify the syslog identity. -# syslog-ident redis - -# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7. -# syslog-facility local0 - -# Set the number of databases. The default database is DB 0, you can select -# a different one on a per-connection basis using SELECT where -# dbid is a number between 0 and 'databases'-1 -databases 16 - -# By default Redis shows an ASCII art logo only when started to log to the -# standard output and if the standard output is a TTY. Basically this means -# that normally a logo is displayed only in interactive sessions. -# -# However it is possible to force the pre-4.0 behavior and always show a -# ASCII art logo in startup logs by setting the following option to yes. -always-show-logo yes - -################################ SNAPSHOTTING ################################ -# -# Save the DB on disk: -# -# save -# -# Will save the DB if both the given number of seconds and the given -# number of write operations against the DB occurred. -# -# In the example below the behaviour will be to save: -# after 900 sec (15 min) if at least 1 key changed -# after 300 sec (5 min) if at least 10 keys changed -# after 60 sec if at least 10000 keys changed -# -# Note: you can disable saving completely by commenting out all "save" lines. -# -# It is also possible to remove all the previously configured save -# points by adding a save directive with a single empty string argument -# like in the following example: -# -# save "" - -save 900 1 -save 300 10 -save 60 10000 - -# By default Redis will stop accepting writes if RDB snapshots are enabled -# (at least one save point) and the latest background save failed. -# This will make the user aware (in a hard way) that data is not persisting -# on disk properly, otherwise chances are that no one will notice and some -# disaster will happen. -# -# If the background saving process will start working again Redis will -# automatically allow writes again. -# -# However if you have setup your proper monitoring of the Redis server -# and persistence, you may want to disable this feature so that Redis will -# continue to work as usual even if there are problems with disk, -# permissions, and so forth. -stop-writes-on-bgsave-error yes - -# Compress string objects using LZF when dump .rdb databases? -# For default that's set to 'yes' as it's almost always a win. -# If you want to save some CPU in the saving child set it to 'no' but -# the dataset will likely be bigger if you have compressible values or keys. -rdbcompression yes - -# Since version 5 of RDB a CRC64 checksum is placed at the end of the file. -# This makes the format more resistant to corruption but there is a performance -# hit to pay (around 10%) when saving and loading RDB files, so you can disable it -# for maximum performances. -# -# RDB files created with checksum disabled have a checksum of zero that will -# tell the loading code to skip the check. -rdbchecksum yes - -# The filename where to dump the DB -dbfilename dump.rdb - -# The working directory. -# -# The DB will be written inside this directory, with the filename specified -# above using the 'dbfilename' configuration directive. -# -# The Append Only File will also be created inside this directory. -# -# Note that you must specify a directory here, not a file name. -dir /var/lib/redis - -################################# REPLICATION ################################# - -# Master-Slave replication. Use slaveof to make a Redis instance a copy of -# another Redis server. A few things to understand ASAP about Redis replication. -# -# 1) Redis replication is asynchronous, but you can configure a master to -# stop accepting writes if it appears to be not connected with at least -# a given number of slaves. -# 2) Redis slaves are able to perform a partial resynchronization with the -# master if the replication link is lost for a relatively small amount of -# time. You may want to configure the replication backlog size (see the next -# sections of this file) with a sensible value depending on your needs. -# 3) Replication is automatic and does not need user intervention. After a -# network partition slaves automatically try to reconnect to masters -# and resynchronize with them. -# -# replicaof 192.168.88.10 6379 - -# If the master is password protected (using the "requirepass" configuration -# directive below) it is possible to tell the slave to authenticate before -# starting the replication synchronization process, otherwise the master will -# refuse the slave request. -# -# masterauth - -# When a slave loses its connection with the master, or when the replication -# is still in progress, the slave can act in two different ways: -# -# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will -# still reply to client requests, possibly with out of date data, or the -# data set may just be empty if this is the first synchronization. -# -# 2) if slave-serve-stale-data is set to 'no' the slave will reply with -# an error "SYNC with master in progress" to all the kind of commands -# but to INFO and SLAVEOF. -# -slave-serve-stale-data yes - -# You can configure a slave instance to accept writes or not. Writing against -# a slave instance may be useful to store some ephemeral data (because data -# written on a slave will be easily deleted after resync with the master) but -# may also cause problems if clients are writing to it because of a -# misconfiguration. -# -# Since Redis 2.6 by default slaves are read-only. -# -# Note: read only slaves are not designed to be exposed to untrusted clients -# on the internet. It's just a protection layer against misuse of the instance. -# Still a read only slave exports by default all the administrative commands -# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve -# security of read only slaves using 'rename-command' to shadow all the -# administrative / dangerous commands. -slave-read-only no - -# Replication SYNC strategy: disk or socket. -# -# ------------------------------------------------------- -# WARNING: DISKLESS REPLICATION IS EXPERIMENTAL CURRENTLY -# ------------------------------------------------------- -# -# New slaves and reconnecting slaves that are not able to continue the replication -# process just receiving differences, need to do what is called a "full -# synchronization". An RDB file is transmitted from the master to the slaves. -# The transmission can happen in two different ways: -# -# 1) Disk-backed: The Redis master creates a new process that writes the RDB -# file on disk. Later the file is transferred by the parent -# process to the slaves incrementally. -# 2) Diskless: The Redis master creates a new process that directly writes the -# RDB file to slave sockets, without touching the disk at all. -# -# With disk-backed replication, while the RDB file is generated, more slaves -# can be queued and served with the RDB file as soon as the current child producing -# the RDB file finishes its work. With diskless replication instead once -# the transfer starts, new slaves arriving will be queued and a new transfer -# will start when the current one terminates. -# -# When diskless replication is used, the master waits a configurable amount of -# time (in seconds) before starting the transfer in the hope that multiple slaves -# will arrive and the transfer can be parallelized. -# -# With slow disks and fast (large bandwidth) networks, diskless replication -# works better. -repl-diskless-sync no - -# When diskless replication is enabled, it is possible to configure the delay -# the server waits in order to spawn the child that transfers the RDB via socket -# to the slaves. -# -# This is important since once the transfer starts, it is not possible to serve -# new slaves arriving, that will be queued for the next RDB transfer, so the server -# waits a delay in order to let more slaves arrive. -# -# The delay is specified in seconds, and by default is 5 seconds. To disable -# it entirely just set it to 0 seconds and the transfer will start ASAP. -repl-diskless-sync-delay 5 - -# Slaves send PINGs to server in a predefined interval. It's possible to change -# this interval with the repl_ping_slave_period option. The default value is 10 -# seconds. -# -# repl-ping-slave-period 10 - -# The following option sets the replication timeout for: -# -# 1) Bulk transfer I/O during SYNC, from the point of view of slave. -# 2) Master timeout from the point of view of slaves (data, pings). -# 3) Slave timeout from the point of view of masters (REPLCONF ACK pings). -# -# It is important to make sure that this value is greater than the value -# specified for repl-ping-slave-period otherwise a timeout will be detected -# every time there is low traffic between the master and the slave. -# -# repl-timeout 60 - -# Disable TCP_NODELAY on the slave socket after SYNC? -# -# If you select "yes" Redis will use a smaller number of TCP packets and -# less bandwidth to send data to slaves. But this can add a delay for -# the data to appear on the slave side, up to 40 milliseconds with -# Linux kernels using a default configuration. -# -# If you select "no" the delay for data to appear on the slave side will -# be reduced but more bandwidth will be used for replication. -# -# By default we optimize for low latency, but in very high traffic conditions -# or when the master and slaves are many hops away, turning this to "yes" may -# be a good idea. -repl-disable-tcp-nodelay no - -# Set the replication backlog size. The backlog is a buffer that accumulates -# slave data when slaves are disconnected for some time, so that when a slave -# wants to reconnect again, often a full resync is not needed, but a partial -# resync is enough, just passing the portion of data the slave missed while -# disconnected. -# -# The bigger the replication backlog, the longer the time the slave can be -# disconnected and later be able to perform a partial resynchronization. -# -# The backlog is only allocated once there is at least a slave connected. -# -# repl-backlog-size 1mb - -# After a master has no longer connected slaves for some time, the backlog -# will be freed. The following option configures the amount of seconds that -# need to elapse, starting from the time the last slave disconnected, for -# the backlog buffer to be freed. -# -# Note that slaves never free the backlog for timeout, since they may be -# promoted to masters later, and should be able to correctly "partially -# resynchronize" with the slaves: hence they should always accumulate backlog. -# -# A value of 0 means to never release the backlog. -# -# repl-backlog-ttl 3600 - -# The slave priority is an integer number published by Redis in the INFO output. -# It is used by Redis Sentinel in order to select a slave to promote into a -# master if the master is no longer working correctly. -# -# A slave with a low priority number is considered better for promotion, so -# for instance if there are three slaves with priority 10, 100, 25 Sentinel will -# pick the one with priority 10, that is the lowest. -# -# However a special priority of 0 marks the slave as not able to perform the -# role of master, so a slave with priority of 0 will never be selected by -# Redis Sentinel for promotion. -# -# By default the priority is 100. -slave-priority 100 - -# It is possible for a master to stop accepting writes if there are less than -# N slaves connected, having a lag less or equal than M seconds. -# -# The N slaves need to be in "online" state. -# -# The lag in seconds, that must be <= the specified value, is calculated from -# the last ping received from the slave, that is usually sent every second. -# -# This option does not GUARANTEE that N replicas will accept the write, but -# will limit the window of exposure for lost writes in case not enough slaves -# are available, to the specified number of seconds. -# -# For example to require at least 3 slaves with a lag <= 10 seconds use: -# -# min-slaves-to-write 3 -# min-slaves-max-lag 10 -# -# Setting one or the other to 0 disables the feature. -# -# By default min-slaves-to-write is set to 0 (feature disabled) and -# min-slaves-max-lag is set to 10. - -# A Redis master is able to list the address and port of the attached -# slaves in different ways. For example the "INFO replication" section -# offers this information, which is used, among other tools, by -# Redis Sentinel in order to discover slave instances. -# Another place where this info is available is in the output of the -# "ROLE" command of a master. -# -# The listed IP and address normally reported by a slave is obtained -# in the following way: -# -# IP: The address is auto detected by checking the peer address -# of the socket used by the slave to connect with the master. -# -# Port: The port is communicated by the slave during the replication -# handshake, and is normally the port that the slave is using to -# list for connections. -# -# However when port forwarding or Network Address Translation (NAT) is -# used, the slave may be actually reachable via different IP and port -# pairs. The following two options can be used by a slave in order to -# report to its master a specific set of IP and port, so that both INFO -# and ROLE will report those values. -# -# There is no need to use both the options if you need to override just -# the port or the IP address. -# -# slave-announce-ip 5.5.5.5 -# slave-announce-port 1234 - -################################## SECURITY ################################### - -# Require clients to issue AUTH before processing any other -# commands. This might be useful in environments in which you do not trust -# others with access to the host running redis-server. -# -# This should stay commented out for backward compatibility and because most -# people do not need auth (e.g. they run their own servers). -# -# Warning: since Redis is pretty fast an outside user can try up to -# 150k passwords per second against a good box. This means that you should -# use a very strong password otherwise it will be very easy to break. -# -# requirepass foobared - -# Command renaming. -# -# It is possible to change the name of dangerous commands in a shared -# environment. For instance the CONFIG command may be renamed into something -# hard to guess so that it will still be available for internal-use tools -# but not available for general clients. -# -# Example: -# -# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 -# -# It is also possible to completely kill a command by renaming it into -# an empty string: -# -# rename-command CONFIG "" -# -# Please note that changing the name of commands that are logged into the -# AOF file or transmitted to slaves may cause problems. - -################################### CLIENTS #################################### - -# Set the max number of connected clients at the same time. By default -# this limit is set to 10000 clients, however if the Redis server is not -# able to configure the process file limit to allow for the specified limit -# the max number of allowed clients is set to the current file limit -# minus 32 (as Redis reserves a few file descriptors for internal uses). -# -# Once the limit is reached Redis will close all the new connections sending -# an error 'max number of clients reached'. -# -# maxclients 10000 - -############################## MEMORY MANAGEMENT ################################ - -# Set a memory usage limit to the specified amount of bytes. -# When the memory limit is reached Redis will try to remove keys -# according to the eviction policy selected (see maxmemory-policy). -# -# If Redis can't remove keys according to the policy, or if the policy is -# set to 'noeviction', Redis will start to reply with errors to commands -# that would use more memory, like SET, LPUSH, and so on, and will continue -# to reply to read-only commands like GET. -# -# This option is usually useful when using Redis as an LRU or LFU cache, or to -# set a hard memory limit for an instance (using the 'noeviction' policy). -# -# WARNING: If you have slaves attached to an instance with maxmemory on, -# the size of the output buffers needed to feed the slaves are subtracted -# from the used memory count, so that network problems / resyncs will -# not trigger a loop where keys are evicted, and in turn the output -# buffer of slaves is full with DELs of keys evicted triggering the deletion -# of more keys, and so forth until the database is completely emptied. -# -# In short... if you have slaves attached it is suggested that you set a lower -# limit for maxmemory so that there is some free RAM on the system for slave -# output buffers (but this is not needed if the policy is 'noeviction'). -# -# maxmemory - -# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory -# is reached. You can select among five behaviors: -# -# volatile-lru -> Evict using approximated LRU among the keys with an expire set. -# allkeys-lru -> Evict any key using approximated LRU. -# volatile-lfu -> Evict using approximated LFU among the keys with an expire set. -# allkeys-lfu -> Evict any key using approximated LFU. -# volatile-random -> Remove a random key among the ones with an expire set. -# allkeys-random -> Remove a random key, any key. -# volatile-ttl -> Remove the key with the nearest expire time (minor TTL) -# noeviction -> Don't evict anything, just return an error on write operations. -# -# LRU means Least Recently Used -# LFU means Least Frequently Used -# -# Both LRU, LFU and volatile-ttl are implemented using approximated -# randomized algorithms. -# -# Note: with any of the above policies, Redis will return an error on write -# operations, when there are no suitable keys for eviction. -# -# At the date of writing these commands are: set setnx setex append -# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd -# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby -# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby -# getset mset msetnx exec sort -# -# The default is: -# -# maxmemory-policy noeviction - -# LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated -# algorithms (in order to save memory), so you can tune it for speed or -# accuracy. For default Redis will check five keys and pick the one that was -# used less recently, you can change the sample size using the following -# configuration directive. -# -# The default of 5 produces good enough results. 10 Approximates very closely -# true LRU but costs more CPU. 3 is faster but not very accurate. -# -# maxmemory-samples 5 - -############################# LAZY FREEING #################################### - -# Redis has two primitives to delete keys. One is called DEL and is a blocking -# deletion of the object. It means that the server stops processing new commands -# in order to reclaim all the memory associated with an object in a synchronous -# way. If the key deleted is associated with a small object, the time needed -# in order to execute the DEL command is very small and comparable to most other -# O(1) or O(log_N) commands in Redis. However if the key is associated with an -# aggregated value containing millions of elements, the server can block for -# a long time (even seconds) in order to complete the operation. -# -# For the above reasons Redis also offers non blocking deletion primitives -# such as UNLINK (non blocking DEL) and the ASYNC option of FLUSHALL and -# FLUSHDB commands, in order to reclaim memory in background. Those commands -# are executed in constant time. Another thread will incrementally free the -# object in the background as fast as possible. -# -# DEL, UNLINK and ASYNC option of FLUSHALL and FLUSHDB are user-controlled. -# It's up to the design of the application to understand when it is a good -# idea to use one or the other. However the Redis server sometimes has to -# delete keys or flush the whole database as a side effect of other operations. -# Specifically Redis deletes objects independently of a user call in the -# following scenarios: -# -# 1) On eviction, because of the maxmemory and maxmemory policy configurations, -# in order to make room for new data, without going over the specified -# memory limit. -# 2) Because of expire: when a key with an associated time to live (see the -# EXPIRE command) must be deleted from memory. -# 3) Because of a side effect of a command that stores data on a key that may -# already exist. For example the RENAME command may delete the old key -# content when it is replaced with another one. Similarly SUNIONSTORE -# or SORT with STORE option may delete existing keys. The SET command -# itself removes any old content of the specified key in order to replace -# it with the specified string. -# 4) During replication, when a slave performs a full resynchronization with -# its master, the content of the whole database is removed in order to -# load the RDB file just transfered. -# -# In all the above cases the default is to delete objects in a blocking way, -# like if DEL was called. However you can configure each case specifically -# in order to instead release memory in a non-blocking way like if UNLINK -# was called, using the following configuration directives: - -lazyfree-lazy-eviction no -lazyfree-lazy-expire no -lazyfree-lazy-server-del no -slave-lazy-flush no - -############################## APPEND ONLY MODE ############################### - -# By default Redis asynchronously dumps the dataset on disk. This mode is -# good enough in many applications, but an issue with the Redis process or -# a power outage may result into a few minutes of writes lost (depending on -# the configured save points). -# -# The Append Only File is an alternative persistence mode that provides -# much better durability. For instance using the default data fsync policy -# (see later in the config file) Redis can lose just one second of writes in a -# dramatic event like a server power outage, or a single write if something -# wrong with the Redis process itself happens, but the operating system is -# still running correctly. -# -# AOF and RDB persistence can be enabled at the same time without problems. -# If the AOF is enabled on startup Redis will load the AOF, that is the file -# with the better durability guarantees. -# -# Please check http://redis.io/topics/persistence for more information. - -appendonly no - -# The name of the append only file (default: "appendonly.aof") - -appendfilename "appendonly.aof" - -# The fsync() call tells the Operating System to actually write data on disk -# instead of waiting for more data in the output buffer. Some OS will really flush -# data on disk, some other OS will just try to do it ASAP. -# -# Redis supports three different modes: -# -# no: don't fsync, just let the OS flush the data when it wants. Faster. -# always: fsync after every write to the append only log. Slow, Safest. -# everysec: fsync only one time every second. Compromise. -# -# The default is "everysec", as that's usually the right compromise between -# speed and data safety. It's up to you to understand if you can relax this to -# "no" that will let the operating system flush the output buffer when -# it wants, for better performances (but if you can live with the idea of -# some data loss consider the default persistence mode that's snapshotting), -# or on the contrary, use "always" that's very slow but a bit safer than -# everysec. -# -# More details please check the following article: -# http://antirez.com/post/redis-persistence-demystified.html -# -# If unsure, use "everysec". - -# appendfsync always -appendfsync everysec -# appendfsync no - -# When the AOF fsync policy is set to always or everysec, and a background -# saving process (a background save or AOF log background rewriting) is -# performing a lot of I/O against the disk, in some Linux configurations -# Redis may block too long on the fsync() call. Note that there is no fix for -# this currently, as even performing fsync in a different thread will block -# our synchronous write(2) call. -# -# In order to mitigate this problem it's possible to use the following option -# that will prevent fsync() from being called in the main process while a -# BGSAVE or BGREWRITEAOF is in progress. -# -# This means that while another child is saving, the durability of Redis is -# the same as "appendfsync none". In practical terms, this means that it is -# possible to lose up to 30 seconds of log in the worst scenario (with the -# default Linux settings). -# -# If you have latency problems turn this to "yes". Otherwise leave it as -# "no" that is the safest pick from the point of view of durability. - -no-appendfsync-on-rewrite no - -# Automatic rewrite of the append only file. -# Redis is able to automatically rewrite the log file implicitly calling -# BGREWRITEAOF when the AOF log size grows by the specified percentage. -# -# This is how it works: Redis remembers the size of the AOF file after the -# latest rewrite (if no rewrite has happened since the restart, the size of -# the AOF at startup is used). -# -# This base size is compared to the current size. If the current size is -# bigger than the specified percentage, the rewrite is triggered. Also -# you need to specify a minimal size for the AOF file to be rewritten, this -# is useful to avoid rewriting the AOF file even if the percentage increase -# is reached but it is still pretty small. -# -# Specify a percentage of zero in order to disable the automatic AOF -# rewrite feature. - -auto-aof-rewrite-percentage 100 -auto-aof-rewrite-min-size 64mb - -# An AOF file may be found to be truncated at the end during the Redis -# startup process, when the AOF data gets loaded back into memory. -# This may happen when the system where Redis is running -# crashes, especially when an ext4 filesystem is mounted without the -# data=ordered option (however this can't happen when Redis itself -# crashes or aborts but the operating system still works correctly). -# -# Redis can either exit with an error when this happens, or load as much -# data as possible (the default now) and start if the AOF file is found -# to be truncated at the end. The following option controls this behavior. -# -# If aof-load-truncated is set to yes, a truncated AOF file is loaded and -# the Redis server starts emitting a log to inform the user of the event. -# Otherwise if the option is set to no, the server aborts with an error -# and refuses to start. When the option is set to no, the user requires -# to fix the AOF file using the "redis-check-aof" utility before to restart -# the server. -# -# Note that if the AOF file will be found to be corrupted in the middle -# the server will still exit with an error. This option only applies when -# Redis will try to read more data from the AOF file but not enough bytes -# will be found. -aof-load-truncated yes - -# When rewriting the AOF file, Redis is able to use an RDB preamble in the -# AOF file for faster rewrites and recoveries. When this option is turned -# on the rewritten AOF file is composed of two different stanzas: -# -# [RDB file][AOF tail] -# -# When loading Redis recognizes that the AOF file starts with the "REDIS" -# string and loads the prefixed RDB file, and continues loading the AOF -# tail. -# -# This is currently turned off by default in order to avoid the surprise -# of a format change, but will at some point be used as the default. -aof-use-rdb-preamble no - -################################ LUA SCRIPTING ############################### - -# Max execution time of a Lua script in milliseconds. -# -# If the maximum execution time is reached Redis will log that a script is -# still in execution after the maximum allowed time and will start to -# reply to queries with an error. -# -# When a long running script exceeds the maximum execution time only the -# SCRIPT KILL and SHUTDOWN NOSAVE commands are available. The first can be -# used to stop a script that did not yet called write commands. The second -# is the only way to shut down the server in the case a write command was -# already issued by the script but the user doesn't want to wait for the natural -# termination of the script. -# -# Set it to 0 or a negative value for unlimited execution without warnings. -lua-time-limit 5000 - -################################ REDIS CLUSTER ############################### -# -# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -# WARNING EXPERIMENTAL: Redis Cluster is considered to be stable code, however -# in order to mark it as "mature" we need to wait for a non trivial percentage -# of users to deploy it in production. -# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -# -# Normal Redis instances can't be part of a Redis Cluster; only nodes that are -# started as cluster nodes can. In order to start a Redis instance as a -# cluster node enable the cluster support uncommenting the following: -# -# cluster-enabled yes - -# Every cluster node has a cluster configuration file. This file is not -# intended to be edited by hand. It is created and updated by Redis nodes. -# Every Redis Cluster node requires a different cluster configuration file. -# Make sure that instances running in the same system do not have -# overlapping cluster configuration file names. -# -# cluster-config-file nodes-6379.conf - -# Cluster node timeout is the amount of milliseconds a node must be unreachable -# for it to be considered in failure state. -# Most other internal time limits are multiple of the node timeout. -# -# cluster-node-timeout 15000 - -# A slave of a failing master will avoid to start a failover if its data -# looks too old. -# -# There is no simple way for a slave to actually have an exact measure of -# its "data age", so the following two checks are performed: -# -# 1) If there are multiple slaves able to failover, they exchange messages -# in order to try to give an advantage to the slave with the best -# replication offset (more data from the master processed). -# Slaves will try to get their rank by offset, and apply to the start -# of the failover a delay proportional to their rank. -# -# 2) Every single slave computes the time of the last interaction with -# its master. This can be the last ping or command received (if the master -# is still in the "connected" state), or the time that elapsed since the -# disconnection with the master (if the replication link is currently down). -# If the last interaction is too old, the slave will not try to failover -# at all. -# -# The point "2" can be tuned by user. Specifically a slave will not perform -# the failover if, since the last interaction with the master, the time -# elapsed is greater than: -# -# (node-timeout * slave-validity-factor) + repl-ping-slave-period -# -# So for example if node-timeout is 30 seconds, and the slave-validity-factor -# is 10, and assuming a default repl-ping-slave-period of 10 seconds, the -# slave will not try to failover if it was not able to talk with the master -# for longer than 310 seconds. -# -# A large slave-validity-factor may allow slaves with too old data to failover -# a master, while a too small value may prevent the cluster from being able to -# elect a slave at all. -# -# For maximum availability, it is possible to set the slave-validity-factor -# to a value of 0, which means, that slaves will always try to failover the -# master regardless of the last time they interacted with the master. -# (However they'll always try to apply a delay proportional to their -# offset rank). -# -# Zero is the only value able to guarantee that when all the partitions heal -# the cluster will always be able to continue. -# -# cluster-slave-validity-factor 10 - -# Cluster slaves are able to migrate to orphaned masters, that are masters -# that are left without working slaves. This improves the cluster ability -# to resist to failures as otherwise an orphaned master can't be failed over -# in case of failure if it has no working slaves. -# -# Slaves migrate to orphaned masters only if there are still at least a -# given number of other working slaves for their old master. This number -# is the "migration barrier". A migration barrier of 1 means that a slave -# will migrate only if there is at least 1 other working slave for its master -# and so forth. It usually reflects the number of slaves you want for every -# master in your cluster. -# -# Default is 1 (slaves migrate only if their masters remain with at least -# one slave). To disable migration just set it to a very large value. -# A value of 0 can be set but is useful only for debugging and dangerous -# in production. -# -# cluster-migration-barrier 1 - -# By default Redis Cluster nodes stop accepting queries if they detect there -# is at least an hash slot uncovered (no available node is serving it). -# This way if the cluster is partially down (for example a range of hash slots -# are no longer covered) all the cluster becomes, eventually, unavailable. -# It automatically returns available as soon as all the slots are covered again. -# -# However sometimes you want the subset of the cluster which is working, -# to continue to accept queries for the part of the key space that is still -# covered. In order to do so, just set the cluster-require-full-coverage -# option to no. -# -# cluster-require-full-coverage yes - -# This option, when set to yes, prevents slaves from trying to failover its -# master during master failures. However the master can still perform a -# manual failover, if forced to do so. -# -# This is useful in different scenarios, especially in the case of multiple -# data center operations, where we want one side to never be promoted if not -# in the case of a total DC failure. -# -# cluster-slave-no-failover no - -# In order to setup your cluster make sure to read the documentation -# available at http://redis.io web site. - -########################## CLUSTER DOCKER/NAT support ######################## - -# In certain deployments, Redis Cluster nodes address discovery fails, because -# addresses are NAT-ted or because ports are forwarded (the typical case is -# Docker and other containers). -# -# In order to make Redis Cluster working in such environments, a static -# configuration where each node knows its public address is needed. The -# following two options are used for this scope, and are: -# -# * cluster-announce-ip -# * cluster-announce-port -# * cluster-announce-bus-port -# -# Each instruct the node about its address, client port, and cluster message -# bus port. The information is then published in the header of the bus packets -# so that other nodes will be able to correctly map the address of the node -# publishing the information. -# -# If the above options are not used, the normal Redis Cluster auto-detection -# will be used instead. -# -# Note that when remapped, the bus port may not be at the fixed offset of -# clients port + 10000, so you can specify any port and bus-port depending -# on how they get remapped. If the bus-port is not set, a fixed offset of -# 10000 will be used as usually. -# -# Example: -# -# cluster-announce-ip 10.1.1.5 -# cluster-announce-port 6379 -# cluster-announce-bus-port 6380 - -################################## SLOW LOG ################################### - -# The Redis Slow Log is a system to log queries that exceeded a specified -# execution time. The execution time does not include the I/O operations -# like talking with the client, sending the reply and so forth, -# but just the time needed to actually execute the command (this is the only -# stage of command execution where the thread is blocked and can not serve -# other requests in the meantime). -# -# You can configure the slow log with two parameters: one tells Redis -# what is the execution time, in microseconds, to exceed in order for the -# command to get logged, and the other parameter is the length of the -# slow log. When a new command is logged the oldest one is removed from the -# queue of logged commands. - -# The following time is expressed in microseconds, so 1000000 is equivalent -# to one second. Note that a negative number disables the slow log, while -# a value of zero forces the logging of every command. -slowlog-log-slower-than 10000 - -# There is no limit to this length. Just be aware that it will consume memory. -# You can reclaim memory used by the slow log with SLOWLOG RESET. -slowlog-max-len 128 - -################################ LATENCY MONITOR ############################## - -# The Redis latency monitoring subsystem samples different operations -# at runtime in order to collect data related to possible sources of -# latency of a Redis instance. -# -# Via the LATENCY command this information is available to the user that can -# print graphs and obtain reports. -# -# The system only logs operations that were performed in a time equal or -# greater than the amount of milliseconds specified via the -# latency-monitor-threshold configuration directive. When its value is set -# to zero, the latency monitor is turned off. -# -# By default latency monitoring is disabled since it is mostly not needed -# if you don't have latency issues, and collecting data has a performance -# impact, that while very small, can be measured under big load. Latency -# monitoring can easily be enabled at runtime using the command -# "CONFIG SET latency-monitor-threshold " if needed. -latency-monitor-threshold 0 - -############################# EVENT NOTIFICATION ############################## - -# Redis can notify Pub/Sub clients about events happening in the key space. -# This feature is documented at http://redis.io/topics/notifications -# -# For instance if keyspace events notification is enabled, and a client -# performs a DEL operation on key "foo" stored in the Database 0, two -# messages will be published via Pub/Sub: -# -# PUBLISH __keyspace@0__:foo del -# PUBLISH __keyevent@0__:del foo -# -# It is possible to select the events that Redis will notify among a set -# of classes. Every class is identified by a single character: -# -# K Keyspace events, published with __keyspace@__ prefix. -# E Keyevent events, published with __keyevent@__ prefix. -# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ... -# $ String commands -# l List commands -# s Set commands -# h Hash commands -# z Sorted set commands -# x Expired events (events generated every time a key expires) -# e Evicted events (events generated when a key is evicted for maxmemory) -# A Alias for g$lshzxe, so that the "AKE" string means all the events. -# -# The "notify-keyspace-events" takes as argument a string that is composed -# of zero or multiple characters. The empty string means that notifications -# are disabled. -# -# Example: to enable list and generic events, from the point of view of the -# event name, use: -# -# notify-keyspace-events Elg -# -# Example 2: to get the stream of the expired keys subscribing to channel -# name __keyevent@0__:expired use: -# -# notify-keyspace-events Ex -# -# By default all notifications are disabled because most users don't need -# this feature and the feature has some overhead. Note that if you don't -# specify at least one of K or E, no events will be delivered. -notify-keyspace-events "" - -############################### ADVANCED CONFIG ############################### - -# Hashes are encoded using a memory efficient data structure when they have a -# small number of entries, and the biggest entry does not exceed a given -# threshold. These thresholds can be configured using the following directives. -hash-max-ziplist-entries 512 -hash-max-ziplist-value 64 - -# Lists are also encoded in a special way to save a lot of space. -# The number of entries allowed per internal list node can be specified -# as a fixed maximum size or a maximum number of elements. -# For a fixed maximum size, use -5 through -1, meaning: -# -5: max size: 64 Kb <-- not recommended for normal workloads -# -4: max size: 32 Kb <-- not recommended -# -3: max size: 16 Kb <-- probably not recommended -# -2: max size: 8 Kb <-- good -# -1: max size: 4 Kb <-- good -# Positive numbers mean store up to _exactly_ that number of elements -# per list node. -# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size), -# but if your use case is unique, adjust the settings as necessary. -list-max-ziplist-size -2 - -# Lists may also be compressed. -# Compress depth is the number of quicklist ziplist nodes from *each* side of -# the list to *exclude* from compression. The head and tail of the list -# are always uncompressed for fast push/pop operations. Settings are: -# 0: disable all list compression -# 1: depth 1 means "don't start compressing until after 1 node into the list, -# going from either the head or tail" -# So: [head]->node->node->...->node->[tail] -# [head], [tail] will always be uncompressed; inner nodes will compress. -# 2: [head]->[next]->node->node->...->node->[prev]->[tail] -# 2 here means: don't compress head or head->next or tail->prev or tail, -# but compress all nodes between them. -# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail] -# etc. -list-compress-depth 0 - -# Sets have a special encoding in just one case: when a set is composed -# of just strings that happen to be integers in radix 10 in the range -# of 64 bit signed integers. -# The following configuration setting sets the limit in the size of the -# set in order to use this special memory saving encoding. -set-max-intset-entries 512 - -# Similarly to hashes and lists, sorted sets are also specially encoded in -# order to save a lot of space. This encoding is only used when the length and -# elements of a sorted set are below the following limits: -zset-max-ziplist-entries 128 -zset-max-ziplist-value 64 - -# HyperLogLog sparse representation bytes limit. The limit includes the -# 16 bytes header. When an HyperLogLog using the sparse representation crosses -# this limit, it is converted into the dense representation. -# -# A value greater than 16000 is totally useless, since at that point the -# dense representation is more memory efficient. -# -# The suggested value is ~ 3000 in order to have the benefits of -# the space efficient encoding without slowing down too much PFADD, -# which is O(N) with the sparse encoding. The value can be raised to -# ~ 10000 when CPU is not a concern, but space is, and the data set is -# composed of many HyperLogLogs with cardinality in the 0 - 15000 range. -hll-sparse-max-bytes 3000 - -# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in -# order to help rehashing the main Redis hash table (the one mapping top-level -# keys to values). The hash table implementation Redis uses (see dict.c) -# performs a lazy rehashing: the more operation you run into a hash table -# that is rehashing, the more rehashing "steps" are performed, so if the -# server is idle the rehashing is never complete and some more memory is used -# by the hash table. -# -# The default is to use this millisecond 10 times every second in order to -# actively rehash the main dictionaries, freeing memory when possible. -# -# If unsure: -# use "activerehashing no" if you have hard latency requirements and it is -# not a good thing in your environment that Redis can reply from time to time -# to queries with 2 milliseconds delay. -# -# use "activerehashing yes" if you don't have such hard requirements but -# want to free memory asap when possible. -activerehashing yes - -# The client output buffer limits can be used to force disconnection of clients -# that are not reading data from the server fast enough for some reason (a -# common reason is that a Pub/Sub client can't consume messages as fast as the -# publisher can produce them). -# -# The limit can be set differently for the three different classes of clients: -# -# normal -> normal clients including MONITOR clients -# slave -> slave clients -# pubsub -> clients subscribed to at least one pubsub channel or pattern -# -# The syntax of every client-output-buffer-limit directive is the following: -# -# client-output-buffer-limit -# -# A client is immediately disconnected once the hard limit is reached, or if -# the soft limit is reached and remains reached for the specified number of -# seconds (continuously). -# So for instance if the hard limit is 32 megabytes and the soft limit is -# 16 megabytes / 10 seconds, the client will get disconnected immediately -# if the size of the output buffers reach 32 megabytes, but will also get -# disconnected if the client reaches 16 megabytes and continuously overcomes -# the limit for 10 seconds. -# -# By default normal clients are not limited because they don't receive data -# without asking (in a push way), but just after a request, so only -# asynchronous clients may create a scenario where data is requested faster -# than it can read. -# -# Instead there is a default limit for pubsub and slave clients, since -# subscribers and slaves receive data in a push fashion. -# -# Both the hard or the soft limit can be disabled by setting them to zero. -client-output-buffer-limit normal 0 0 0 -client-output-buffer-limit slave 256mb 64mb 60 -client-output-buffer-limit pubsub 32mb 8mb 60 - -# Client query buffers accumulate new commands. They are limited to a fixed -# amount by default in order to avoid that a protocol desynchronization (for -# instance due to a bug in the client) will lead to unbound memory usage in -# the query buffer. However you can configure it here if you have very special -# needs, such us huge multi/exec requests or alike. -# -# client-query-buffer-limit 1gb - -# In the Redis protocol, bulk requests, that are, elements representing single -# strings, are normally limited ot 512 mb. However you can change this limit -# here. -# -# proto-max-bulk-len 512mb - -# Redis calls an internal function to perform many background tasks, like -# closing connections of clients in timeout, purging expired keys that are -# never requested, and so forth. -# -# Not all tasks are performed with the same frequency, but Redis checks for -# tasks to perform according to the specified "hz" value. -# -# By default "hz" is set to 10. Raising the value will use more CPU when -# Redis is idle, but at the same time will make Redis more responsive when -# there are many keys expiring at the same time, and timeouts may be -# handled with more precision. -# -# The range is between 1 and 500, however a value over 100 is usually not -# a good idea. Most users should use the default of 10 and raise this up to -# 100 only in environments where very low latency is required. -hz 10 - -# When a child rewrites the AOF file, if the following option is enabled -# the file will be fsync-ed every 32 MB of data generated. This is useful -# in order to commit the file to the disk more incrementally and avoid -# big latency spikes. -aof-rewrite-incremental-fsync yes - -# Redis LFU eviction (see maxmemory setting) can be tuned. However it is a good -# idea to start with the default settings and only change them after investigating -# how to improve the performances and how the keys LFU change over time, which -# is possible to inspect via the OBJECT FREQ command. -# -# There are two tunable parameters in the Redis LFU implementation: the -# counter logarithm factor and the counter decay time. It is important to -# understand what the two parameters mean before changing them. -# -# The LFU counter is just 8 bits per key, it's maximum value is 255, so Redis -# uses a probabilistic increment with logarithmic behavior. Given the value -# of the old counter, when a key is accessed, the counter is incremented in -# this way: -# -# 1. A random number R between 0 and 1 is extracted. -# 2. A probability P is calculated as 1/(old_value*lfu_log_factor+1). -# 3. The counter is incremented only if R < P. -# -# The default lfu-log-factor is 10. This is a table of how the frequency -# counter changes with a different number of accesses with different -# logarithmic factors: -# -# +--------+------------+------------+------------+------------+------------+ -# | factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits | -# +--------+------------+------------+------------+------------+------------+ -# | 0 | 104 | 255 | 255 | 255 | 255 | -# +--------+------------+------------+------------+------------+------------+ -# | 1 | 18 | 49 | 255 | 255 | 255 | -# +--------+------------+------------+------------+------------+------------+ -# | 10 | 10 | 18 | 142 | 255 | 255 | -# +--------+------------+------------+------------+------------+------------+ -# | 100 | 8 | 11 | 49 | 143 | 255 | -# +--------+------------+------------+------------+------------+------------+ -# -# NOTE: The above table was obtained by running the following commands: -# -# redis-benchmark -n 1000000 incr foo -# redis-cli object freq foo -# -# NOTE 2: The counter initial value is 5 in order to give new objects a chance -# to accumulate hits. -# -# The counter decay time is the time, in minutes, that must elapse in order -# for the key counter to be divided by two (or decremented if it has a value -# less <= 10). -# -# The default value for the lfu-decay-time is 1. A Special value of 0 means to -# decay the counter every time it happens to be scanned. -# -# lfu-log-factor 10 -# lfu-decay-time 1 - -########################### ACTIVE DEFRAGMENTATION ####################### -# -# WARNING THIS FEATURE IS EXPERIMENTAL. However it was stress tested -# even in production and manually tested by multiple engineers for some -# time. -# -# What is active defragmentation? -# ------------------------------- -# -# Active (online) defragmentation allows a Redis server to compact the -# spaces left between small allocations and deallocations of data in memory, -# thus allowing to reclaim back memory. -# -# Fragmentation is a natural process that happens with every allocator (but -# less so with Jemalloc, fortunately) and certain workloads. Normally a server -# restart is needed in order to lower the fragmentation, or at least to flush -# away all the data and create it again. However thanks to this feature -# implemented by Oran Agra for Redis 4.0 this process can happen at runtime -# in an "hot" way, while the server is running. -# -# Basically when the fragmentation is over a certain level (see the -# configuration options below) Redis will start to create new copies of the -# values in contiguous memory regions by exploiting certain specific Jemalloc -# features (in order to understand if an allocation is causing fragmentation -# and to allocate it in a better place), and at the same time, will release the -# old copies of the data. This process, repeated incrementally for all the keys -# will cause the fragmentation to drop back to normal values. -# -# Important things to understand: -# -# 1. This feature is disabled by default, and only works if you compiled Redis -# to use the copy of Jemalloc we ship with the source code of Redis. -# This is the default with Linux builds. -# -# 2. You never need to enable this feature if you don't have fragmentation -# issues. -# -# 3. Once you experience fragmentation, you can enable this feature when -# needed with the command "CONFIG SET activedefrag yes". -# -# The configuration parameters are able to fine tune the behavior of the -# defragmentation process. If you are not sure about what they mean it is -# a good idea to leave the defaults untouched. - -# Enabled active defragmentation -# activedefrag yes - -# Minimum amount of fragmentation waste to start active defrag -# active-defrag-ignore-bytes 100mb - -# Minimum percentage of fragmentation to start active defrag -# active-defrag-threshold-lower 10 - -# Maximum percentage of fragmentation at which we use maximum effort -# active-defrag-threshold-upper 100 - -# Minimal effort for defrag in CPU percentage -# active-defrag-cycle-min 25 - -# Maximal effort for defrag in CPU percentage -# active-defrag-cycle-max 75 - diff --git a/src/cfg/redis/nayak_redis.conf b/src/cfg/redis/nayak_redis.conf deleted file mode 100755 index 83b2574..0000000 --- a/src/cfg/redis/nayak_redis.conf +++ /dev/null @@ -1,1319 +0,0 @@ -# Redis configuration file example. -# -# Note that in order to read the configuration file, Redis must be -# started with the file path as first argument: -# -# ./redis-server /path/to/redis.conf - -# Note on units: when memory size is needed, it is possible to specify -# it in the usual form of 1k 5GB 4M and so forth: -# -# 1k => 1000 bytes -# 1kb => 1024 bytes -# 1m => 1000000 bytes -# 1mb => 1024*1024 bytes -# 1g => 1000000000 bytes -# 1gb => 1024*1024*1024 bytes -# -# units are case insensitive so 1GB 1Gb 1gB are all the same. - -################################## INCLUDES ################################### - -# Include one or more other config files here. This is useful if you -# have a standard template that goes to all Redis servers but also need -# to customize a few per-server settings. Include files can include -# other files, so use this wisely. -# -# Notice option "include" won't be rewritten by command "CONFIG REWRITE" -# from admin or Redis Sentinel. Since Redis always uses the last processed -# line as value of a configuration directive, you'd better put includes -# at the beginning of this file to avoid overwriting config change at runtime. -# -# If instead you are interested in using includes to override configuration -# options, it is better to use include as the last line. -# -# include /path/to/local.conf -# include /path/to/other.conf - -################################## MODULES ##################################### - -# Load modules at startup. If the server is not able to load modules -# it will abort. It is possible to use multiple loadmodule directives. -# -# loadmodule /path/to/my_module.so -# loadmodule /path/to/other_module.so - -################################## NETWORK ##################################### - -# By default, if no "bind" configuration directive is specified, Redis listens -# for connections from all the network interfaces available on the server. -# It is possible to listen to just one or multiple selected interfaces using -# the "bind" configuration directive, followed by one or more IP addresses. -# -# Examples: -# -# bind 192.168.1.100 10.0.0.1 -# bind 127.0.0.1 ::1 -# -# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the -# internet, binding to all the interfaces is dangerous and will expose the -# instance to everybody on the internet. So by default we uncomment the -# following bind directive, that will force Redis to listen only into -# the IPv4 lookback interface address (this means Redis will be able to -# accept connections only from clients running into the same computer it -# is running). -# -# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES -# JUST COMMENT THE FOLLOWING LINE. -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -bind 127.0.0.1 ::1 -bind ::1 -bind 100.119.87.82 192.168.88.10 - -# Protected mode is a layer of security protection, in order to avoid that -# Redis instances left open on the internet are accessed and exploited. -# -# When protected mode is on and if: -# -# 1) The server is not binding explicitly to a set of addresses using the -# "bind" directive. -# 2) No password is configured. -# -# The server only accepts connections from clients connecting from the -# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain -# sockets. -# -# By default protected mode is enabled. You should disable it only if -# you are sure you want clients from other hosts to connect to Redis -# even if no authentication is configured, nor a specific set of interfaces -# are explicitly listed using the "bind" directive. -protected-mode yes - -# Accept connections on the specified port, default is 6379 (IANA #815344). -# If port 0 is specified Redis will not listen on a TCP socket. -port 6379 - -# TCP listen() backlog. -# -# In high requests-per-second environments you need an high backlog in order -# to avoid slow clients connections issues. Note that the Linux kernel -# will silently truncate it to the value of /proc/sys/net/core/somaxconn so -# make sure to raise both the value of somaxconn and tcp_max_syn_backlog -# in order to get the desired effect. -tcp-backlog 511 - -# Unix socket. -# -# Specify the path for the Unix socket that will be used to listen for -# incoming connections. There is no default, so Redis will not listen -# on a unix socket when not specified. -# -# unixsocket /var/run/redis/redis-server.sock -# unixsocketperm 700 - -# Close the connection after a client is idle for N seconds (0 to disable) -timeout 0 - -# TCP keepalive. -# -# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence -# of communication. This is useful for two reasons: -# -# 1) Detect dead peers. -# 2) Take the connection alive from the point of view of network -# equipment in the middle. -# -# On Linux, the specified value (in seconds) is the period used to send ACKs. -# Note that to close the connection the double of the time is needed. -# On other kernels the period depends on the kernel configuration. -# -# A reasonable value for this option is 300 seconds, which is the new -# Redis default starting with Redis 3.2.1. -tcp-keepalive 300 - -################################# GENERAL ##################################### - -# By default Redis does not run as a daemon. Use 'yes' if you need it. -# Note that Redis will write a pid file in /var/run/redis.pid when daemonized. -daemonize yes - -# If you run Redis from upstart or systemd, Redis can interact with your -# supervision tree. Options: -# supervised no - no supervision interaction -# supervised upstart - signal upstart by putting Redis into SIGSTOP mode -# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET -# supervised auto - detect upstart or systemd method based on -# UPSTART_JOB or NOTIFY_SOCKET environment variables -# Note: these supervision methods only signal "process is ready." -# They do not enable continuous liveness pings back to your supervisor. -supervised no - -# If a pid file is specified, Redis writes it where specified at startup -# and removes it at exit. -# -# When the server runs non daemonized, no pid file is created if none is -# specified in the configuration. When the server is daemonized, the pid file -# is used even if not specified, defaulting to "/var/run/redis.pid". -# -# Creating a pid file is best effort: if Redis is not able to create it -# nothing bad happens, the server will start and run normally. -pidfile /var/run/redis/redis-server.pid - -# Specify the server verbosity level. -# This can be one of: -# debug (a lot of information, useful for development/testing) -# verbose (many rarely useful info, but not a mess like the debug level) -# notice (moderately verbose, what you want in production probably) -# warning (only very important / critical messages are logged) -loglevel notice - -# Specify the log file name. Also the empty string can be used to force -# Redis to log on the standard output. Note that if you use standard -# output for logging but daemonize, logs will be sent to /dev/null -logfile /var/log/redis/redis-server.log - -# To enable logging to the system logger, just set 'syslog-enabled' to yes, -# and optionally update the other syslog parameters to suit your needs. -# syslog-enabled no - -# Specify the syslog identity. -# syslog-ident redis - -# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7. -# syslog-facility local0 - -# Set the number of databases. The default database is DB 0, you can select -# a different one on a per-connection basis using SELECT where -# dbid is a number between 0 and 'databases'-1 -databases 16 - -# By default Redis shows an ASCII art logo only when started to log to the -# standard output and if the standard output is a TTY. Basically this means -# that normally a logo is displayed only in interactive sessions. -# -# However it is possible to force the pre-4.0 behavior and always show a -# ASCII art logo in startup logs by setting the following option to yes. -always-show-logo yes - -################################ SNAPSHOTTING ################################ -# -# Save the DB on disk: -# -# save -# -# Will save the DB if both the given number of seconds and the given -# number of write operations against the DB occurred. -# -# In the example below the behaviour will be to save: -# after 900 sec (15 min) if at least 1 key changed -# after 300 sec (5 min) if at least 10 keys changed -# after 60 sec if at least 10000 keys changed -# -# Note: you can disable saving completely by commenting out all "save" lines. -# -# It is also possible to remove all the previously configured save -# points by adding a save directive with a single empty string argument -# like in the following example: -# -# save "" - -save 900 1 -save 300 10 -save 60 10000 - -# By default Redis will stop accepting writes if RDB snapshots are enabled -# (at least one save point) and the latest background save failed. -# This will make the user aware (in a hard way) that data is not persisting -# on disk properly, otherwise chances are that no one will notice and some -# disaster will happen. -# -# If the background saving process will start working again Redis will -# automatically allow writes again. -# -# However if you have setup your proper monitoring of the Redis server -# and persistence, you may want to disable this feature so that Redis will -# continue to work as usual even if there are problems with disk, -# permissions, and so forth. -stop-writes-on-bgsave-error yes - -# Compress string objects using LZF when dump .rdb databases? -# For default that's set to 'yes' as it's almost always a win. -# If you want to save some CPU in the saving child set it to 'no' but -# the dataset will likely be bigger if you have compressible values or keys. -rdbcompression yes - -# Since version 5 of RDB a CRC64 checksum is placed at the end of the file. -# This makes the format more resistant to corruption but there is a performance -# hit to pay (around 10%) when saving and loading RDB files, so you can disable it -# for maximum performances. -# -# RDB files created with checksum disabled have a checksum of zero that will -# tell the loading code to skip the check. -rdbchecksum yes - -# The filename where to dump the DB -dbfilename dump.rdb - -# The working directory. -# -# The DB will be written inside this directory, with the filename specified -# above using the 'dbfilename' configuration directive. -# -# The Append Only File will also be created inside this directory. -# -# Note that you must specify a directory here, not a file name. -dir /var/lib/redis - -################################# REPLICATION ################################# - -# Master-Slave replication. Use slaveof to make a Redis instance a copy of -# another Redis server. A few things to understand ASAP about Redis replication. -# -# 1) Redis replication is asynchronous, but you can configure a master to -# stop accepting writes if it appears to be not connected with at least -# a given number of slaves. -# 2) Redis slaves are able to perform a partial resynchronization with the -# master if the replication link is lost for a relatively small amount of -# time. You may want to configure the replication backlog size (see the next -# sections of this file) with a sensible value depending on your needs. -# 3) Replication is automatic and does not need user intervention. After a -# network partition slaves automatically try to reconnect to masters -# and resynchronize with them. -# -replicaof 192.168.88.10 6379 - -# If the master is password protected (using the "requirepass" configuration -# directive below) it is possible to tell the slave to authenticate before -# starting the replication synchronization process, otherwise the master will -# refuse the slave request. -# -# masterauth - -# When a slave loses its connection with the master, or when the replication -# is still in progress, the slave can act in two different ways: -# -# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will -# still reply to client requests, possibly with out of date data, or the -# data set may just be empty if this is the first synchronization. -# -# 2) if slave-serve-stale-data is set to 'no' the slave will reply with -# an error "SYNC with master in progress" to all the kind of commands -# but to INFO and SLAVEOF. -# -slave-serve-stale-data yes - -# You can configure a slave instance to accept writes or not. Writing against -# a slave instance may be useful to store some ephemeral data (because data -# written on a slave will be easily deleted after resync with the master) but -# may also cause problems if clients are writing to it because of a -# misconfiguration. -# -# Since Redis 2.6 by default slaves are read-only. -# -# Note: read only slaves are not designed to be exposed to untrusted clients -# on the internet. It's just a protection layer against misuse of the instance. -# Still a read only slave exports by default all the administrative commands -# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve -# security of read only slaves using 'rename-command' to shadow all the -# administrative / dangerous commands. -slave-read-only no - -# Replication SYNC strategy: disk or socket. -# -# ------------------------------------------------------- -# WARNING: DISKLESS REPLICATION IS EXPERIMENTAL CURRENTLY -# ------------------------------------------------------- -# -# New slaves and reconnecting slaves that are not able to continue the replication -# process just receiving differences, need to do what is called a "full -# synchronization". An RDB file is transmitted from the master to the slaves. -# The transmission can happen in two different ways: -# -# 1) Disk-backed: The Redis master creates a new process that writes the RDB -# file on disk. Later the file is transferred by the parent -# process to the slaves incrementally. -# 2) Diskless: The Redis master creates a new process that directly writes the -# RDB file to slave sockets, without touching the disk at all. -# -# With disk-backed replication, while the RDB file is generated, more slaves -# can be queued and served with the RDB file as soon as the current child producing -# the RDB file finishes its work. With diskless replication instead once -# the transfer starts, new slaves arriving will be queued and a new transfer -# will start when the current one terminates. -# -# When diskless replication is used, the master waits a configurable amount of -# time (in seconds) before starting the transfer in the hope that multiple slaves -# will arrive and the transfer can be parallelized. -# -# With slow disks and fast (large bandwidth) networks, diskless replication -# works better. -repl-diskless-sync no - -# When diskless replication is enabled, it is possible to configure the delay -# the server waits in order to spawn the child that transfers the RDB via socket -# to the slaves. -# -# This is important since once the transfer starts, it is not possible to serve -# new slaves arriving, that will be queued for the next RDB transfer, so the server -# waits a delay in order to let more slaves arrive. -# -# The delay is specified in seconds, and by default is 5 seconds. To disable -# it entirely just set it to 0 seconds and the transfer will start ASAP. -repl-diskless-sync-delay 5 - -# Slaves send PINGs to server in a predefined interval. It's possible to change -# this interval with the repl_ping_slave_period option. The default value is 10 -# seconds. -# -# repl-ping-slave-period 10 - -# The following option sets the replication timeout for: -# -# 1) Bulk transfer I/O during SYNC, from the point of view of slave. -# 2) Master timeout from the point of view of slaves (data, pings). -# 3) Slave timeout from the point of view of masters (REPLCONF ACK pings). -# -# It is important to make sure that this value is greater than the value -# specified for repl-ping-slave-period otherwise a timeout will be detected -# every time there is low traffic between the master and the slave. -# -# repl-timeout 60 - -# Disable TCP_NODELAY on the slave socket after SYNC? -# -# If you select "yes" Redis will use a smaller number of TCP packets and -# less bandwidth to send data to slaves. But this can add a delay for -# the data to appear on the slave side, up to 40 milliseconds with -# Linux kernels using a default configuration. -# -# If you select "no" the delay for data to appear on the slave side will -# be reduced but more bandwidth will be used for replication. -# -# By default we optimize for low latency, but in very high traffic conditions -# or when the master and slaves are many hops away, turning this to "yes" may -# be a good idea. -repl-disable-tcp-nodelay no - -# Set the replication backlog size. The backlog is a buffer that accumulates -# slave data when slaves are disconnected for some time, so that when a slave -# wants to reconnect again, often a full resync is not needed, but a partial -# resync is enough, just passing the portion of data the slave missed while -# disconnected. -# -# The bigger the replication backlog, the longer the time the slave can be -# disconnected and later be able to perform a partial resynchronization. -# -# The backlog is only allocated once there is at least a slave connected. -# -# repl-backlog-size 1mb - -# After a master has no longer connected slaves for some time, the backlog -# will be freed. The following option configures the amount of seconds that -# need to elapse, starting from the time the last slave disconnected, for -# the backlog buffer to be freed. -# -# Note that slaves never free the backlog for timeout, since they may be -# promoted to masters later, and should be able to correctly "partially -# resynchronize" with the slaves: hence they should always accumulate backlog. -# -# A value of 0 means to never release the backlog. -# -# repl-backlog-ttl 3600 - -# The slave priority is an integer number published by Redis in the INFO output. -# It is used by Redis Sentinel in order to select a slave to promote into a -# master if the master is no longer working correctly. -# -# A slave with a low priority number is considered better for promotion, so -# for instance if there are three slaves with priority 10, 100, 25 Sentinel will -# pick the one with priority 10, that is the lowest. -# -# However a special priority of 0 marks the slave as not able to perform the -# role of master, so a slave with priority of 0 will never be selected by -# Redis Sentinel for promotion. -# -# By default the priority is 100. -slave-priority 100 - -# It is possible for a master to stop accepting writes if there are less than -# N slaves connected, having a lag less or equal than M seconds. -# -# The N slaves need to be in "online" state. -# -# The lag in seconds, that must be <= the specified value, is calculated from -# the last ping received from the slave, that is usually sent every second. -# -# This option does not GUARANTEE that N replicas will accept the write, but -# will limit the window of exposure for lost writes in case not enough slaves -# are available, to the specified number of seconds. -# -# For example to require at least 3 slaves with a lag <= 10 seconds use: -# -# min-slaves-to-write 3 -# min-slaves-max-lag 10 -# -# Setting one or the other to 0 disables the feature. -# -# By default min-slaves-to-write is set to 0 (feature disabled) and -# min-slaves-max-lag is set to 10. - -# A Redis master is able to list the address and port of the attached -# slaves in different ways. For example the "INFO replication" section -# offers this information, which is used, among other tools, by -# Redis Sentinel in order to discover slave instances. -# Another place where this info is available is in the output of the -# "ROLE" command of a master. -# -# The listed IP and address normally reported by a slave is obtained -# in the following way: -# -# IP: The address is auto detected by checking the peer address -# of the socket used by the slave to connect with the master. -# -# Port: The port is communicated by the slave during the replication -# handshake, and is normally the port that the slave is using to -# list for connections. -# -# However when port forwarding or Network Address Translation (NAT) is -# used, the slave may be actually reachable via different IP and port -# pairs. The following two options can be used by a slave in order to -# report to its master a specific set of IP and port, so that both INFO -# and ROLE will report those values. -# -# There is no need to use both the options if you need to override just -# the port or the IP address. -# -# slave-announce-ip 5.5.5.5 -# slave-announce-port 1234 - -################################## SECURITY ################################### - -# Require clients to issue AUTH before processing any other -# commands. This might be useful in environments in which you do not trust -# others with access to the host running redis-server. -# -# This should stay commented out for backward compatibility and because most -# people do not need auth (e.g. they run their own servers). -# -# Warning: since Redis is pretty fast an outside user can try up to -# 150k passwords per second against a good box. This means that you should -# use a very strong password otherwise it will be very easy to break. -# -# requirepass foobared - -# Command renaming. -# -# It is possible to change the name of dangerous commands in a shared -# environment. For instance the CONFIG command may be renamed into something -# hard to guess so that it will still be available for internal-use tools -# but not available for general clients. -# -# Example: -# -# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 -# -# It is also possible to completely kill a command by renaming it into -# an empty string: -# -# rename-command CONFIG "" -# -# Please note that changing the name of commands that are logged into the -# AOF file or transmitted to slaves may cause problems. - -################################### CLIENTS #################################### - -# Set the max number of connected clients at the same time. By default -# this limit is set to 10000 clients, however if the Redis server is not -# able to configure the process file limit to allow for the specified limit -# the max number of allowed clients is set to the current file limit -# minus 32 (as Redis reserves a few file descriptors for internal uses). -# -# Once the limit is reached Redis will close all the new connections sending -# an error 'max number of clients reached'. -# -# maxclients 10000 - -############################## MEMORY MANAGEMENT ################################ - -# Set a memory usage limit to the specified amount of bytes. -# When the memory limit is reached Redis will try to remove keys -# according to the eviction policy selected (see maxmemory-policy). -# -# If Redis can't remove keys according to the policy, or if the policy is -# set to 'noeviction', Redis will start to reply with errors to commands -# that would use more memory, like SET, LPUSH, and so on, and will continue -# to reply to read-only commands like GET. -# -# This option is usually useful when using Redis as an LRU or LFU cache, or to -# set a hard memory limit for an instance (using the 'noeviction' policy). -# -# WARNING: If you have slaves attached to an instance with maxmemory on, -# the size of the output buffers needed to feed the slaves are subtracted -# from the used memory count, so that network problems / resyncs will -# not trigger a loop where keys are evicted, and in turn the output -# buffer of slaves is full with DELs of keys evicted triggering the deletion -# of more keys, and so forth until the database is completely emptied. -# -# In short... if you have slaves attached it is suggested that you set a lower -# limit for maxmemory so that there is some free RAM on the system for slave -# output buffers (but this is not needed if the policy is 'noeviction'). -# -# maxmemory - -# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory -# is reached. You can select among five behaviors: -# -# volatile-lru -> Evict using approximated LRU among the keys with an expire set. -# allkeys-lru -> Evict any key using approximated LRU. -# volatile-lfu -> Evict using approximated LFU among the keys with an expire set. -# allkeys-lfu -> Evict any key using approximated LFU. -# volatile-random -> Remove a random key among the ones with an expire set. -# allkeys-random -> Remove a random key, any key. -# volatile-ttl -> Remove the key with the nearest expire time (minor TTL) -# noeviction -> Don't evict anything, just return an error on write operations. -# -# LRU means Least Recently Used -# LFU means Least Frequently Used -# -# Both LRU, LFU and volatile-ttl are implemented using approximated -# randomized algorithms. -# -# Note: with any of the above policies, Redis will return an error on write -# operations, when there are no suitable keys for eviction. -# -# At the date of writing these commands are: set setnx setex append -# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd -# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby -# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby -# getset mset msetnx exec sort -# -# The default is: -# -# maxmemory-policy noeviction - -# LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated -# algorithms (in order to save memory), so you can tune it for speed or -# accuracy. For default Redis will check five keys and pick the one that was -# used less recently, you can change the sample size using the following -# configuration directive. -# -# The default of 5 produces good enough results. 10 Approximates very closely -# true LRU but costs more CPU. 3 is faster but not very accurate. -# -# maxmemory-samples 5 - -############################# LAZY FREEING #################################### - -# Redis has two primitives to delete keys. One is called DEL and is a blocking -# deletion of the object. It means that the server stops processing new commands -# in order to reclaim all the memory associated with an object in a synchronous -# way. If the key deleted is associated with a small object, the time needed -# in order to execute the DEL command is very small and comparable to most other -# O(1) or O(log_N) commands in Redis. However if the key is associated with an -# aggregated value containing millions of elements, the server can block for -# a long time (even seconds) in order to complete the operation. -# -# For the above reasons Redis also offers non blocking deletion primitives -# such as UNLINK (non blocking DEL) and the ASYNC option of FLUSHALL and -# FLUSHDB commands, in order to reclaim memory in background. Those commands -# are executed in constant time. Another thread will incrementally free the -# object in the background as fast as possible. -# -# DEL, UNLINK and ASYNC option of FLUSHALL and FLUSHDB are user-controlled. -# It's up to the design of the application to understand when it is a good -# idea to use one or the other. However the Redis server sometimes has to -# delete keys or flush the whole database as a side effect of other operations. -# Specifically Redis deletes objects independently of a user call in the -# following scenarios: -# -# 1) On eviction, because of the maxmemory and maxmemory policy configurations, -# in order to make room for new data, without going over the specified -# memory limit. -# 2) Because of expire: when a key with an associated time to live (see the -# EXPIRE command) must be deleted from memory. -# 3) Because of a side effect of a command that stores data on a key that may -# already exist. For example the RENAME command may delete the old key -# content when it is replaced with another one. Similarly SUNIONSTORE -# or SORT with STORE option may delete existing keys. The SET command -# itself removes any old content of the specified key in order to replace -# it with the specified string. -# 4) During replication, when a slave performs a full resynchronization with -# its master, the content of the whole database is removed in order to -# load the RDB file just transfered. -# -# In all the above cases the default is to delete objects in a blocking way, -# like if DEL was called. However you can configure each case specifically -# in order to instead release memory in a non-blocking way like if UNLINK -# was called, using the following configuration directives: - -lazyfree-lazy-eviction no -lazyfree-lazy-expire no -lazyfree-lazy-server-del no -slave-lazy-flush no - -############################## APPEND ONLY MODE ############################### - -# By default Redis asynchronously dumps the dataset on disk. This mode is -# good enough in many applications, but an issue with the Redis process or -# a power outage may result into a few minutes of writes lost (depending on -# the configured save points). -# -# The Append Only File is an alternative persistence mode that provides -# much better durability. For instance using the default data fsync policy -# (see later in the config file) Redis can lose just one second of writes in a -# dramatic event like a server power outage, or a single write if something -# wrong with the Redis process itself happens, but the operating system is -# still running correctly. -# -# AOF and RDB persistence can be enabled at the same time without problems. -# If the AOF is enabled on startup Redis will load the AOF, that is the file -# with the better durability guarantees. -# -# Please check http://redis.io/topics/persistence for more information. - -appendonly no - -# The name of the append only file (default: "appendonly.aof") - -appendfilename "appendonly.aof" - -# The fsync() call tells the Operating System to actually write data on disk -# instead of waiting for more data in the output buffer. Some OS will really flush -# data on disk, some other OS will just try to do it ASAP. -# -# Redis supports three different modes: -# -# no: don't fsync, just let the OS flush the data when it wants. Faster. -# always: fsync after every write to the append only log. Slow, Safest. -# everysec: fsync only one time every second. Compromise. -# -# The default is "everysec", as that's usually the right compromise between -# speed and data safety. It's up to you to understand if you can relax this to -# "no" that will let the operating system flush the output buffer when -# it wants, for better performances (but if you can live with the idea of -# some data loss consider the default persistence mode that's snapshotting), -# or on the contrary, use "always" that's very slow but a bit safer than -# everysec. -# -# More details please check the following article: -# http://antirez.com/post/redis-persistence-demystified.html -# -# If unsure, use "everysec". - -# appendfsync always -appendfsync everysec -# appendfsync no - -# When the AOF fsync policy is set to always or everysec, and a background -# saving process (a background save or AOF log background rewriting) is -# performing a lot of I/O against the disk, in some Linux configurations -# Redis may block too long on the fsync() call. Note that there is no fix for -# this currently, as even performing fsync in a different thread will block -# our synchronous write(2) call. -# -# In order to mitigate this problem it's possible to use the following option -# that will prevent fsync() from being called in the main process while a -# BGSAVE or BGREWRITEAOF is in progress. -# -# This means that while another child is saving, the durability of Redis is -# the same as "appendfsync none". In practical terms, this means that it is -# possible to lose up to 30 seconds of log in the worst scenario (with the -# default Linux settings). -# -# If you have latency problems turn this to "yes". Otherwise leave it as -# "no" that is the safest pick from the point of view of durability. - -no-appendfsync-on-rewrite no - -# Automatic rewrite of the append only file. -# Redis is able to automatically rewrite the log file implicitly calling -# BGREWRITEAOF when the AOF log size grows by the specified percentage. -# -# This is how it works: Redis remembers the size of the AOF file after the -# latest rewrite (if no rewrite has happened since the restart, the size of -# the AOF at startup is used). -# -# This base size is compared to the current size. If the current size is -# bigger than the specified percentage, the rewrite is triggered. Also -# you need to specify a minimal size for the AOF file to be rewritten, this -# is useful to avoid rewriting the AOF file even if the percentage increase -# is reached but it is still pretty small. -# -# Specify a percentage of zero in order to disable the automatic AOF -# rewrite feature. - -auto-aof-rewrite-percentage 100 -auto-aof-rewrite-min-size 64mb - -# An AOF file may be found to be truncated at the end during the Redis -# startup process, when the AOF data gets loaded back into memory. -# This may happen when the system where Redis is running -# crashes, especially when an ext4 filesystem is mounted without the -# data=ordered option (however this can't happen when Redis itself -# crashes or aborts but the operating system still works correctly). -# -# Redis can either exit with an error when this happens, or load as much -# data as possible (the default now) and start if the AOF file is found -# to be truncated at the end. The following option controls this behavior. -# -# If aof-load-truncated is set to yes, a truncated AOF file is loaded and -# the Redis server starts emitting a log to inform the user of the event. -# Otherwise if the option is set to no, the server aborts with an error -# and refuses to start. When the option is set to no, the user requires -# to fix the AOF file using the "redis-check-aof" utility before to restart -# the server. -# -# Note that if the AOF file will be found to be corrupted in the middle -# the server will still exit with an error. This option only applies when -# Redis will try to read more data from the AOF file but not enough bytes -# will be found. -aof-load-truncated yes - -# When rewriting the AOF file, Redis is able to use an RDB preamble in the -# AOF file for faster rewrites and recoveries. When this option is turned -# on the rewritten AOF file is composed of two different stanzas: -# -# [RDB file][AOF tail] -# -# When loading Redis recognizes that the AOF file starts with the "REDIS" -# string and loads the prefixed RDB file, and continues loading the AOF -# tail. -# -# This is currently turned off by default in order to avoid the surprise -# of a format change, but will at some point be used as the default. -aof-use-rdb-preamble no - -################################ LUA SCRIPTING ############################### - -# Max execution time of a Lua script in milliseconds. -# -# If the maximum execution time is reached Redis will log that a script is -# still in execution after the maximum allowed time and will start to -# reply to queries with an error. -# -# When a long running script exceeds the maximum execution time only the -# SCRIPT KILL and SHUTDOWN NOSAVE commands are available. The first can be -# used to stop a script that did not yet called write commands. The second -# is the only way to shut down the server in the case a write command was -# already issued by the script but the user doesn't want to wait for the natural -# termination of the script. -# -# Set it to 0 or a negative value for unlimited execution without warnings. -lua-time-limit 5000 - -################################ REDIS CLUSTER ############################### -# -# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -# WARNING EXPERIMENTAL: Redis Cluster is considered to be stable code, however -# in order to mark it as "mature" we need to wait for a non trivial percentage -# of users to deploy it in production. -# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -# -# Normal Redis instances can't be part of a Redis Cluster; only nodes that are -# started as cluster nodes can. In order to start a Redis instance as a -# cluster node enable the cluster support uncommenting the following: -# -# cluster-enabled yes - -# Every cluster node has a cluster configuration file. This file is not -# intended to be edited by hand. It is created and updated by Redis nodes. -# Every Redis Cluster node requires a different cluster configuration file. -# Make sure that instances running in the same system do not have -# overlapping cluster configuration file names. -# -# cluster-config-file nodes-6379.conf - -# Cluster node timeout is the amount of milliseconds a node must be unreachable -# for it to be considered in failure state. -# Most other internal time limits are multiple of the node timeout. -# -# cluster-node-timeout 15000 - -# A slave of a failing master will avoid to start a failover if its data -# looks too old. -# -# There is no simple way for a slave to actually have an exact measure of -# its "data age", so the following two checks are performed: -# -# 1) If there are multiple slaves able to failover, they exchange messages -# in order to try to give an advantage to the slave with the best -# replication offset (more data from the master processed). -# Slaves will try to get their rank by offset, and apply to the start -# of the failover a delay proportional to their rank. -# -# 2) Every single slave computes the time of the last interaction with -# its master. This can be the last ping or command received (if the master -# is still in the "connected" state), or the time that elapsed since the -# disconnection with the master (if the replication link is currently down). -# If the last interaction is too old, the slave will not try to failover -# at all. -# -# The point "2" can be tuned by user. Specifically a slave will not perform -# the failover if, since the last interaction with the master, the time -# elapsed is greater than: -# -# (node-timeout * slave-validity-factor) + repl-ping-slave-period -# -# So for example if node-timeout is 30 seconds, and the slave-validity-factor -# is 10, and assuming a default repl-ping-slave-period of 10 seconds, the -# slave will not try to failover if it was not able to talk with the master -# for longer than 310 seconds. -# -# A large slave-validity-factor may allow slaves with too old data to failover -# a master, while a too small value may prevent the cluster from being able to -# elect a slave at all. -# -# For maximum availability, it is possible to set the slave-validity-factor -# to a value of 0, which means, that slaves will always try to failover the -# master regardless of the last time they interacted with the master. -# (However they'll always try to apply a delay proportional to their -# offset rank). -# -# Zero is the only value able to guarantee that when all the partitions heal -# the cluster will always be able to continue. -# -# cluster-slave-validity-factor 10 - -# Cluster slaves are able to migrate to orphaned masters, that are masters -# that are left without working slaves. This improves the cluster ability -# to resist to failures as otherwise an orphaned master can't be failed over -# in case of failure if it has no working slaves. -# -# Slaves migrate to orphaned masters only if there are still at least a -# given number of other working slaves for their old master. This number -# is the "migration barrier". A migration barrier of 1 means that a slave -# will migrate only if there is at least 1 other working slave for its master -# and so forth. It usually reflects the number of slaves you want for every -# master in your cluster. -# -# Default is 1 (slaves migrate only if their masters remain with at least -# one slave). To disable migration just set it to a very large value. -# A value of 0 can be set but is useful only for debugging and dangerous -# in production. -# -# cluster-migration-barrier 1 - -# By default Redis Cluster nodes stop accepting queries if they detect there -# is at least an hash slot uncovered (no available node is serving it). -# This way if the cluster is partially down (for example a range of hash slots -# are no longer covered) all the cluster becomes, eventually, unavailable. -# It automatically returns available as soon as all the slots are covered again. -# -# However sometimes you want the subset of the cluster which is working, -# to continue to accept queries for the part of the key space that is still -# covered. In order to do so, just set the cluster-require-full-coverage -# option to no. -# -# cluster-require-full-coverage yes - -# This option, when set to yes, prevents slaves from trying to failover its -# master during master failures. However the master can still perform a -# manual failover, if forced to do so. -# -# This is useful in different scenarios, especially in the case of multiple -# data center operations, where we want one side to never be promoted if not -# in the case of a total DC failure. -# -# cluster-slave-no-failover no - -# In order to setup your cluster make sure to read the documentation -# available at http://redis.io web site. - -########################## CLUSTER DOCKER/NAT support ######################## - -# In certain deployments, Redis Cluster nodes address discovery fails, because -# addresses are NAT-ted or because ports are forwarded (the typical case is -# Docker and other containers). -# -# In order to make Redis Cluster working in such environments, a static -# configuration where each node knows its public address is needed. The -# following two options are used for this scope, and are: -# -# * cluster-announce-ip -# * cluster-announce-port -# * cluster-announce-bus-port -# -# Each instruct the node about its address, client port, and cluster message -# bus port. The information is then published in the header of the bus packets -# so that other nodes will be able to correctly map the address of the node -# publishing the information. -# -# If the above options are not used, the normal Redis Cluster auto-detection -# will be used instead. -# -# Note that when remapped, the bus port may not be at the fixed offset of -# clients port + 10000, so you can specify any port and bus-port depending -# on how they get remapped. If the bus-port is not set, a fixed offset of -# 10000 will be used as usually. -# -# Example: -# -# cluster-announce-ip 10.1.1.5 -# cluster-announce-port 6379 -# cluster-announce-bus-port 6380 - -################################## SLOW LOG ################################### - -# The Redis Slow Log is a system to log queries that exceeded a specified -# execution time. The execution time does not include the I/O operations -# like talking with the client, sending the reply and so forth, -# but just the time needed to actually execute the command (this is the only -# stage of command execution where the thread is blocked and can not serve -# other requests in the meantime). -# -# You can configure the slow log with two parameters: one tells Redis -# what is the execution time, in microseconds, to exceed in order for the -# command to get logged, and the other parameter is the length of the -# slow log. When a new command is logged the oldest one is removed from the -# queue of logged commands. - -# The following time is expressed in microseconds, so 1000000 is equivalent -# to one second. Note that a negative number disables the slow log, while -# a value of zero forces the logging of every command. -slowlog-log-slower-than 10000 - -# There is no limit to this length. Just be aware that it will consume memory. -# You can reclaim memory used by the slow log with SLOWLOG RESET. -slowlog-max-len 128 - -################################ LATENCY MONITOR ############################## - -# The Redis latency monitoring subsystem samples different operations -# at runtime in order to collect data related to possible sources of -# latency of a Redis instance. -# -# Via the LATENCY command this information is available to the user that can -# print graphs and obtain reports. -# -# The system only logs operations that were performed in a time equal or -# greater than the amount of milliseconds specified via the -# latency-monitor-threshold configuration directive. When its value is set -# to zero, the latency monitor is turned off. -# -# By default latency monitoring is disabled since it is mostly not needed -# if you don't have latency issues, and collecting data has a performance -# impact, that while very small, can be measured under big load. Latency -# monitoring can easily be enabled at runtime using the command -# "CONFIG SET latency-monitor-threshold " if needed. -latency-monitor-threshold 0 - -############################# EVENT NOTIFICATION ############################## - -# Redis can notify Pub/Sub clients about events happening in the key space. -# This feature is documented at http://redis.io/topics/notifications -# -# For instance if keyspace events notification is enabled, and a client -# performs a DEL operation on key "foo" stored in the Database 0, two -# messages will be published via Pub/Sub: -# -# PUBLISH __keyspace@0__:foo del -# PUBLISH __keyevent@0__:del foo -# -# It is possible to select the events that Redis will notify among a set -# of classes. Every class is identified by a single character: -# -# K Keyspace events, published with __keyspace@__ prefix. -# E Keyevent events, published with __keyevent@__ prefix. -# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ... -# $ String commands -# l List commands -# s Set commands -# h Hash commands -# z Sorted set commands -# x Expired events (events generated every time a key expires) -# e Evicted events (events generated when a key is evicted for maxmemory) -# A Alias for g$lshzxe, so that the "AKE" string means all the events. -# -# The "notify-keyspace-events" takes as argument a string that is composed -# of zero or multiple characters. The empty string means that notifications -# are disabled. -# -# Example: to enable list and generic events, from the point of view of the -# event name, use: -# -# notify-keyspace-events Elg -# -# Example 2: to get the stream of the expired keys subscribing to channel -# name __keyevent@0__:expired use: -# -# notify-keyspace-events Ex -# -# By default all notifications are disabled because most users don't need -# this feature and the feature has some overhead. Note that if you don't -# specify at least one of K or E, no events will be delivered. -notify-keyspace-events "" - -############################### ADVANCED CONFIG ############################### - -# Hashes are encoded using a memory efficient data structure when they have a -# small number of entries, and the biggest entry does not exceed a given -# threshold. These thresholds can be configured using the following directives. -hash-max-ziplist-entries 512 -hash-max-ziplist-value 64 - -# Lists are also encoded in a special way to save a lot of space. -# The number of entries allowed per internal list node can be specified -# as a fixed maximum size or a maximum number of elements. -# For a fixed maximum size, use -5 through -1, meaning: -# -5: max size: 64 Kb <-- not recommended for normal workloads -# -4: max size: 32 Kb <-- not recommended -# -3: max size: 16 Kb <-- probably not recommended -# -2: max size: 8 Kb <-- good -# -1: max size: 4 Kb <-- good -# Positive numbers mean store up to _exactly_ that number of elements -# per list node. -# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size), -# but if your use case is unique, adjust the settings as necessary. -list-max-ziplist-size -2 - -# Lists may also be compressed. -# Compress depth is the number of quicklist ziplist nodes from *each* side of -# the list to *exclude* from compression. The head and tail of the list -# are always uncompressed for fast push/pop operations. Settings are: -# 0: disable all list compression -# 1: depth 1 means "don't start compressing until after 1 node into the list, -# going from either the head or tail" -# So: [head]->node->node->...->node->[tail] -# [head], [tail] will always be uncompressed; inner nodes will compress. -# 2: [head]->[next]->node->node->...->node->[prev]->[tail] -# 2 here means: don't compress head or head->next or tail->prev or tail, -# but compress all nodes between them. -# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail] -# etc. -list-compress-depth 0 - -# Sets have a special encoding in just one case: when a set is composed -# of just strings that happen to be integers in radix 10 in the range -# of 64 bit signed integers. -# The following configuration setting sets the limit in the size of the -# set in order to use this special memory saving encoding. -set-max-intset-entries 512 - -# Similarly to hashes and lists, sorted sets are also specially encoded in -# order to save a lot of space. This encoding is only used when the length and -# elements of a sorted set are below the following limits: -zset-max-ziplist-entries 128 -zset-max-ziplist-value 64 - -# HyperLogLog sparse representation bytes limit. The limit includes the -# 16 bytes header. When an HyperLogLog using the sparse representation crosses -# this limit, it is converted into the dense representation. -# -# A value greater than 16000 is totally useless, since at that point the -# dense representation is more memory efficient. -# -# The suggested value is ~ 3000 in order to have the benefits of -# the space efficient encoding without slowing down too much PFADD, -# which is O(N) with the sparse encoding. The value can be raised to -# ~ 10000 when CPU is not a concern, but space is, and the data set is -# composed of many HyperLogLogs with cardinality in the 0 - 15000 range. -hll-sparse-max-bytes 3000 - -# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in -# order to help rehashing the main Redis hash table (the one mapping top-level -# keys to values). The hash table implementation Redis uses (see dict.c) -# performs a lazy rehashing: the more operation you run into a hash table -# that is rehashing, the more rehashing "steps" are performed, so if the -# server is idle the rehashing is never complete and some more memory is used -# by the hash table. -# -# The default is to use this millisecond 10 times every second in order to -# actively rehash the main dictionaries, freeing memory when possible. -# -# If unsure: -# use "activerehashing no" if you have hard latency requirements and it is -# not a good thing in your environment that Redis can reply from time to time -# to queries with 2 milliseconds delay. -# -# use "activerehashing yes" if you don't have such hard requirements but -# want to free memory asap when possible. -activerehashing yes - -# The client output buffer limits can be used to force disconnection of clients -# that are not reading data from the server fast enough for some reason (a -# common reason is that a Pub/Sub client can't consume messages as fast as the -# publisher can produce them). -# -# The limit can be set differently for the three different classes of clients: -# -# normal -> normal clients including MONITOR clients -# slave -> slave clients -# pubsub -> clients subscribed to at least one pubsub channel or pattern -# -# The syntax of every client-output-buffer-limit directive is the following: -# -# client-output-buffer-limit -# -# A client is immediately disconnected once the hard limit is reached, or if -# the soft limit is reached and remains reached for the specified number of -# seconds (continuously). -# So for instance if the hard limit is 32 megabytes and the soft limit is -# 16 megabytes / 10 seconds, the client will get disconnected immediately -# if the size of the output buffers reach 32 megabytes, but will also get -# disconnected if the client reaches 16 megabytes and continuously overcomes -# the limit for 10 seconds. -# -# By default normal clients are not limited because they don't receive data -# without asking (in a push way), but just after a request, so only -# asynchronous clients may create a scenario where data is requested faster -# than it can read. -# -# Instead there is a default limit for pubsub and slave clients, since -# subscribers and slaves receive data in a push fashion. -# -# Both the hard or the soft limit can be disabled by setting them to zero. -client-output-buffer-limit normal 0 0 0 -client-output-buffer-limit slave 256mb 64mb 60 -client-output-buffer-limit pubsub 32mb 8mb 60 - -# Client query buffers accumulate new commands. They are limited to a fixed -# amount by default in order to avoid that a protocol desynchronization (for -# instance due to a bug in the client) will lead to unbound memory usage in -# the query buffer. However you can configure it here if you have very special -# needs, such us huge multi/exec requests or alike. -# -# client-query-buffer-limit 1gb - -# In the Redis protocol, bulk requests, that are, elements representing single -# strings, are normally limited ot 512 mb. However you can change this limit -# here. -# -# proto-max-bulk-len 512mb - -# Redis calls an internal function to perform many background tasks, like -# closing connections of clients in timeout, purging expired keys that are -# never requested, and so forth. -# -# Not all tasks are performed with the same frequency, but Redis checks for -# tasks to perform according to the specified "hz" value. -# -# By default "hz" is set to 10. Raising the value will use more CPU when -# Redis is idle, but at the same time will make Redis more responsive when -# there are many keys expiring at the same time, and timeouts may be -# handled with more precision. -# -# The range is between 1 and 500, however a value over 100 is usually not -# a good idea. Most users should use the default of 10 and raise this up to -# 100 only in environments where very low latency is required. -hz 10 - -# When a child rewrites the AOF file, if the following option is enabled -# the file will be fsync-ed every 32 MB of data generated. This is useful -# in order to commit the file to the disk more incrementally and avoid -# big latency spikes. -aof-rewrite-incremental-fsync yes - -# Redis LFU eviction (see maxmemory setting) can be tuned. However it is a good -# idea to start with the default settings and only change them after investigating -# how to improve the performances and how the keys LFU change over time, which -# is possible to inspect via the OBJECT FREQ command. -# -# There are two tunable parameters in the Redis LFU implementation: the -# counter logarithm factor and the counter decay time. It is important to -# understand what the two parameters mean before changing them. -# -# The LFU counter is just 8 bits per key, it's maximum value is 255, so Redis -# uses a probabilistic increment with logarithmic behavior. Given the value -# of the old counter, when a key is accessed, the counter is incremented in -# this way: -# -# 1. A random number R between 0 and 1 is extracted. -# 2. A probability P is calculated as 1/(old_value*lfu_log_factor+1). -# 3. The counter is incremented only if R < P. -# -# The default lfu-log-factor is 10. This is a table of how the frequency -# counter changes with a different number of accesses with different -# logarithmic factors: -# -# +--------+------------+------------+------------+------------+------------+ -# | factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits | -# +--------+------------+------------+------------+------------+------------+ -# | 0 | 104 | 255 | 255 | 255 | 255 | -# +--------+------------+------------+------------+------------+------------+ -# | 1 | 18 | 49 | 255 | 255 | 255 | -# +--------+------------+------------+------------+------------+------------+ -# | 10 | 10 | 18 | 142 | 255 | 255 | -# +--------+------------+------------+------------+------------+------------+ -# | 100 | 8 | 11 | 49 | 143 | 255 | -# +--------+------------+------------+------------+------------+------------+ -# -# NOTE: The above table was obtained by running the following commands: -# -# redis-benchmark -n 1000000 incr foo -# redis-cli object freq foo -# -# NOTE 2: The counter initial value is 5 in order to give new objects a chance -# to accumulate hits. -# -# The counter decay time is the time, in minutes, that must elapse in order -# for the key counter to be divided by two (or decremented if it has a value -# less <= 10). -# -# The default value for the lfu-decay-time is 1. A Special value of 0 means to -# decay the counter every time it happens to be scanned. -# -# lfu-log-factor 10 -# lfu-decay-time 1 - -########################### ACTIVE DEFRAGMENTATION ####################### -# -# WARNING THIS FEATURE IS EXPERIMENTAL. However it was stress tested -# even in production and manually tested by multiple engineers for some -# time. -# -# What is active defragmentation? -# ------------------------------- -# -# Active (online) defragmentation allows a Redis server to compact the -# spaces left between small allocations and deallocations of data in memory, -# thus allowing to reclaim back memory. -# -# Fragmentation is a natural process that happens with every allocator (but -# less so with Jemalloc, fortunately) and certain workloads. Normally a server -# restart is needed in order to lower the fragmentation, or at least to flush -# away all the data and create it again. However thanks to this feature -# implemented by Oran Agra for Redis 4.0 this process can happen at runtime -# in an "hot" way, while the server is running. -# -# Basically when the fragmentation is over a certain level (see the -# configuration options below) Redis will start to create new copies of the -# values in contiguous memory regions by exploiting certain specific Jemalloc -# features (in order to understand if an allocation is causing fragmentation -# and to allocate it in a better place), and at the same time, will release the -# old copies of the data. This process, repeated incrementally for all the keys -# will cause the fragmentation to drop back to normal values. -# -# Important things to understand: -# -# 1. This feature is disabled by default, and only works if you compiled Redis -# to use the copy of Jemalloc we ship with the source code of Redis. -# This is the default with Linux builds. -# -# 2. You never need to enable this feature if you don't have fragmentation -# issues. -# -# 3. Once you experience fragmentation, you can enable this feature when -# needed with the command "CONFIG SET activedefrag yes". -# -# The configuration parameters are able to fine tune the behavior of the -# defragmentation process. If you are not sure about what they mean it is -# a good idea to leave the defaults untouched. - -# Enabled active defragmentation -# activedefrag yes - -# Minimum amount of fragmentation waste to start active defrag -# active-defrag-ignore-bytes 100mb - -# Minimum percentage of fragmentation to start active defrag -# active-defrag-threshold-lower 10 - -# Maximum percentage of fragmentation at which we use maximum effort -# active-defrag-threshold-upper 100 - -# Minimal effort for defrag in CPU percentage -# active-defrag-cycle-min 25 - -# Maximal effort for defrag in CPU percentage -# active-defrag-cycle-max 75 - diff --git a/src/cfg/redis/nayak_system_config.txt b/src/cfg/redis/nayak_system_config.txt deleted file mode 100644 index 5fe470e..0000000 --- a/src/cfg/redis/nayak_system_config.txt +++ /dev/null @@ -1,19 +0,0 @@ -/sys/arch/is_archiving 0 -/sys/arch/trigger_freq 1.0 -/sys/arch/base_template {base}/{project}/fl{flight}/{sys_cfg}/ -/sys/arch/template {base}/{project}/fl{flight}/{sys_cfg}/{cam_fov}_view/{project}_fl{flight}_{cf}_{time}_{mode}.{ext} -/sys/arch/project default_project -/sys/arch/effort default_effort -/sys/arch/sys_cfg default_cfg -/sys/arch/flight 00 -/sys/arch/ext_ir tif -/sys/arch/ext_rgb jpg -/sys/arch/ext_p1 jpg -/sys/arch/base /mnt/data -/sys/arch/kamera_dir /home/user/kw/noaa_kamera -/sys/arch/hosts/cas0/fov center -/sys/arch/hosts/cas1/fov left -/sys/arch/hosts/cas2/fov right -/sys/arch/jpg/quality 90 -/sys/arch/load_shapefile 0 -/sys/arch/use_nvjpeg 1 diff --git a/src/cfg/redis/taiga_system_config.txt b/src/cfg/redis/taiga_system_config.txt deleted file mode 100644 index 5fe470e..0000000 --- a/src/cfg/redis/taiga_system_config.txt +++ /dev/null @@ -1,19 +0,0 @@ -/sys/arch/is_archiving 0 -/sys/arch/trigger_freq 1.0 -/sys/arch/base_template {base}/{project}/fl{flight}/{sys_cfg}/ -/sys/arch/template {base}/{project}/fl{flight}/{sys_cfg}/{cam_fov}_view/{project}_fl{flight}_{cf}_{time}_{mode}.{ext} -/sys/arch/project default_project -/sys/arch/effort default_effort -/sys/arch/sys_cfg default_cfg -/sys/arch/flight 00 -/sys/arch/ext_ir tif -/sys/arch/ext_rgb jpg -/sys/arch/ext_p1 jpg -/sys/arch/base /mnt/data -/sys/arch/kamera_dir /home/user/kw/noaa_kamera -/sys/arch/hosts/cas0/fov center -/sys/arch/hosts/cas1/fov left -/sys/arch/hosts/cas2/fov right -/sys/arch/jpg/quality 90 -/sys/arch/load_shapefile 0 -/sys/arch/use_nvjpeg 1 diff --git a/src/cfg/redis/uas_redis.conf b/src/cfg/redis/uas_redis.conf deleted file mode 100644 index b074790..0000000 --- a/src/cfg/redis/uas_redis.conf +++ /dev/null @@ -1,1317 +0,0 @@ -# Redis configuration file example. -# -# Note that in order to read the configuration file, Redis must be -# started with the file path as first argument: -# -# ./redis-server /path/to/redis.conf - -# Note on units: when memory size is needed, it is possible to specify -# it in the usual form of 1k 5GB 4M and so forth: -# -# 1k => 1000 bytes -# 1kb => 1024 bytes -# 1m => 1000000 bytes -# 1mb => 1024*1024 bytes -# 1g => 1000000000 bytes -# 1gb => 1024*1024*1024 bytes -# -# units are case insensitive so 1GB 1Gb 1gB are all the same. - -################################## INCLUDES ################################### - -# Include one or more other config files here. This is useful if you -# have a standard template that goes to all Redis servers but also need -# to customize a few per-server settings. Include files can include -# other files, so use this wisely. -# -# Notice option "include" won't be rewritten by command "CONFIG REWRITE" -# from admin or Redis Sentinel. Since Redis always uses the last processed -# line as value of a configuration directive, you'd better put includes -# at the beginning of this file to avoid overwriting config change at runtime. -# -# If instead you are interested in using includes to override configuration -# options, it is better to use include as the last line. -# -# include /path/to/local.conf -# include /path/to/other.conf - -################################## MODULES ##################################### - -# Load modules at startup. If the server is not able to load modules -# it will abort. It is possible to use multiple loadmodule directives. -# -# loadmodule /path/to/my_module.so -# loadmodule /path/to/other_module.so - -################################## NETWORK ##################################### - -# By default, if no "bind" configuration directive is specified, Redis listens -# for connections from all the network interfaces available on the server. -# It is possible to listen to just one or multiple selected interfaces using -# the "bind" configuration directive, followed by one or more IP addresses. -# -# Examples: -# -# bind 192.168.1.100 10.0.0.1 -# bind 127.0.0.1 ::1 -# -# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the -# internet, binding to all the interfaces is dangerous and will expose the -# instance to everybody on the internet. So by default we uncomment the -# following bind directive, that will force Redis to listen only into -# the IPv4 lookback interface address (this means Redis will be able to -# accept connections only from clients running into the same computer it -# is running). -# -# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES -# JUST COMMENT THE FOLLOWING LINE. -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -bind uas0 192.168.88.70 127.0.0.1 - -# Protected mode is a layer of security protection, in order to avoid that -# Redis instances left open on the internet are accessed and exploited. -# -# When protected mode is on and if: -# -# 1) The server is not binding explicitly to a set of addresses using the -# "bind" directive. -# 2) No password is configured. -# -# The server only accepts connections from clients connecting from the -# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain -# sockets. -# -# By default protected mode is enabled. You should disable it only if -# you are sure you want clients from other hosts to connect to Redis -# even if no authentication is configured, nor a specific set of interfaces -# are explicitly listed using the "bind" directive. -protected-mode yes - -# Accept connections on the specified port, default is 6379 (IANA #815344). -# If port 0 is specified Redis will not listen on a TCP socket. -port 6379 - -# TCP listen() backlog. -# -# In high requests-per-second environments you need an high backlog in order -# to avoid slow clients connections issues. Note that the Linux kernel -# will silently truncate it to the value of /proc/sys/net/core/somaxconn so -# make sure to raise both the value of somaxconn and tcp_max_syn_backlog -# in order to get the desired effect. -tcp-backlog 511 - -# Unix socket. -# -# Specify the path for the Unix socket that will be used to listen for -# incoming connections. There is no default, so Redis will not listen -# on a unix socket when not specified. -# -# unixsocket /var/run/redis/redis-server.sock -# unixsocketperm 700 - -# Close the connection after a client is idle for N seconds (0 to disable) -timeout 0 - -# TCP keepalive. -# -# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence -# of communication. This is useful for two reasons: -# -# 1) Detect dead peers. -# 2) Take the connection alive from the point of view of network -# equipment in the middle. -# -# On Linux, the specified value (in seconds) is the period used to send ACKs. -# Note that to close the connection the double of the time is needed. -# On other kernels the period depends on the kernel configuration. -# -# A reasonable value for this option is 300 seconds, which is the new -# Redis default starting with Redis 3.2.1. -tcp-keepalive 300 - -################################# GENERAL ##################################### - -# By default Redis does not run as a daemon. Use 'yes' if you need it. -# Note that Redis will write a pid file in /var/run/redis.pid when daemonized. -daemonize yes - -# If you run Redis from upstart or systemd, Redis can interact with your -# supervision tree. Options: -# supervised no - no supervision interaction -# supervised upstart - signal upstart by putting Redis into SIGSTOP mode -# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET -# supervised auto - detect upstart or systemd method based on -# UPSTART_JOB or NOTIFY_SOCKET environment variables -# Note: these supervision methods only signal "process is ready." -# They do not enable continuous liveness pings back to your supervisor. -supervised no - -# If a pid file is specified, Redis writes it where specified at startup -# and removes it at exit. -# -# When the server runs non daemonized, no pid file is created if none is -# specified in the configuration. When the server is daemonized, the pid file -# is used even if not specified, defaulting to "/var/run/redis.pid". -# -# Creating a pid file is best effort: if Redis is not able to create it -# nothing bad happens, the server will start and run normally. -pidfile /var/run/redis/redis-server.pid - -# Specify the server verbosity level. -# This can be one of: -# debug (a lot of information, useful for development/testing) -# verbose (many rarely useful info, but not a mess like the debug level) -# notice (moderately verbose, what you want in production probably) -# warning (only very important / critical messages are logged) -loglevel notice - -# Specify the log file name. Also the empty string can be used to force -# Redis to log on the standard output. Note that if you use standard -# output for logging but daemonize, logs will be sent to /dev/null -logfile /var/log/redis/redis-server.log - -# To enable logging to the system logger, just set 'syslog-enabled' to yes, -# and optionally update the other syslog parameters to suit your needs. -# syslog-enabled no - -# Specify the syslog identity. -# syslog-ident redis - -# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7. -# syslog-facility local0 - -# Set the number of databases. The default database is DB 0, you can select -# a different one on a per-connection basis using SELECT where -# dbid is a number between 0 and 'databases'-1 -databases 16 - -# By default Redis shows an ASCII art logo only when started to log to the -# standard output and if the standard output is a TTY. Basically this means -# that normally a logo is displayed only in interactive sessions. -# -# However it is possible to force the pre-4.0 behavior and always show a -# ASCII art logo in startup logs by setting the following option to yes. -always-show-logo yes - -################################ SNAPSHOTTING ################################ -# -# Save the DB on disk: -# -# save -# -# Will save the DB if both the given number of seconds and the given -# number of write operations against the DB occurred. -# -# In the example below the behaviour will be to save: -# after 900 sec (15 min) if at least 1 key changed -# after 300 sec (5 min) if at least 10 keys changed -# after 60 sec if at least 10000 keys changed -# -# Note: you can disable saving completely by commenting out all "save" lines. -# -# It is also possible to remove all the previously configured save -# points by adding a save directive with a single empty string argument -# like in the following example: -# -# save "" - -save 900 1 -save 300 10 -save 60 10000 - -# By default Redis will stop accepting writes if RDB snapshots are enabled -# (at least one save point) and the latest background save failed. -# This will make the user aware (in a hard way) that data is not persisting -# on disk properly, otherwise chances are that no one will notice and some -# disaster will happen. -# -# If the background saving process will start working again Redis will -# automatically allow writes again. -# -# However if you have setup your proper monitoring of the Redis server -# and persistence, you may want to disable this feature so that Redis will -# continue to work as usual even if there are problems with disk, -# permissions, and so forth. -stop-writes-on-bgsave-error yes - -# Compress string objects using LZF when dump .rdb databases? -# For default that's set to 'yes' as it's almost always a win. -# If you want to save some CPU in the saving child set it to 'no' but -# the dataset will likely be bigger if you have compressible values or keys. -rdbcompression yes - -# Since version 5 of RDB a CRC64 checksum is placed at the end of the file. -# This makes the format more resistant to corruption but there is a performance -# hit to pay (around 10%) when saving and loading RDB files, so you can disable it -# for maximum performances. -# -# RDB files created with checksum disabled have a checksum of zero that will -# tell the loading code to skip the check. -rdbchecksum yes - -# The filename where to dump the DB -dbfilename dump.rdb - -# The working directory. -# -# The DB will be written inside this directory, with the filename specified -# above using the 'dbfilename' configuration directive. -# -# The Append Only File will also be created inside this directory. -# -# Note that you must specify a directory here, not a file name. -dir /var/lib/redis - -################################# REPLICATION ################################# - -# Master-Slave replication. Use slaveof to make a Redis instance a copy of -# another Redis server. A few things to understand ASAP about Redis replication. -# -# 1) Redis replication is asynchronous, but you can configure a master to -# stop accepting writes if it appears to be not connected with at least -# a given number of slaves. -# 2) Redis slaves are able to perform a partial resynchronization with the -# master if the replication link is lost for a relatively small amount of -# time. You may want to configure the replication backlog size (see the next -# sections of this file) with a sensible value depending on your needs. -# 3) Replication is automatic and does not need user intervention. After a -# network partition slaves automatically try to reconnect to masters -# and resynchronize with them. -# -#replicaof 192.168.88.10 6379 - -# If the master is password protected (using the "requirepass" configuration -# directive below) it is possible to tell the slave to authenticate before -# starting the replication synchronization process, otherwise the master will -# refuse the slave request. -# -# masterauth - -# When a slave loses its connection with the master, or when the replication -# is still in progress, the slave can act in two different ways: -# -# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will -# still reply to client requests, possibly with out of date data, or the -# data set may just be empty if this is the first synchronization. -# -# 2) if slave-serve-stale-data is set to 'no' the slave will reply with -# an error "SYNC with master in progress" to all the kind of commands -# but to INFO and SLAVEOF. -# -slave-serve-stale-data yes - -# You can configure a slave instance to accept writes or not. Writing against -# a slave instance may be useful to store some ephemeral data (because data -# written on a slave will be easily deleted after resync with the master) but -# may also cause problems if clients are writing to it because of a -# misconfiguration. -# -# Since Redis 2.6 by default slaves are read-only. -# -# Note: read only slaves are not designed to be exposed to untrusted clients -# on the internet. It's just a protection layer against misuse of the instance. -# Still a read only slave exports by default all the administrative commands -# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve -# security of read only slaves using 'rename-command' to shadow all the -# administrative / dangerous commands. -slave-read-only yes - -# Replication SYNC strategy: disk or socket. -# -# ------------------------------------------------------- -# WARNING: DISKLESS REPLICATION IS EXPERIMENTAL CURRENTLY -# ------------------------------------------------------- -# -# New slaves and reconnecting slaves that are not able to continue the replication -# process just receiving differences, need to do what is called a "full -# synchronization". An RDB file is transmitted from the master to the slaves. -# The transmission can happen in two different ways: -# -# 1) Disk-backed: The Redis master creates a new process that writes the RDB -# file on disk. Later the file is transferred by the parent -# process to the slaves incrementally. -# 2) Diskless: The Redis master creates a new process that directly writes the -# RDB file to slave sockets, without touching the disk at all. -# -# With disk-backed replication, while the RDB file is generated, more slaves -# can be queued and served with the RDB file as soon as the current child producing -# the RDB file finishes its work. With diskless replication instead once -# the transfer starts, new slaves arriving will be queued and a new transfer -# will start when the current one terminates. -# -# When diskless replication is used, the master waits a configurable amount of -# time (in seconds) before starting the transfer in the hope that multiple slaves -# will arrive and the transfer can be parallelized. -# -# With slow disks and fast (large bandwidth) networks, diskless replication -# works better. -repl-diskless-sync no - -# When diskless replication is enabled, it is possible to configure the delay -# the server waits in order to spawn the child that transfers the RDB via socket -# to the slaves. -# -# This is important since once the transfer starts, it is not possible to serve -# new slaves arriving, that will be queued for the next RDB transfer, so the server -# waits a delay in order to let more slaves arrive. -# -# The delay is specified in seconds, and by default is 5 seconds. To disable -# it entirely just set it to 0 seconds and the transfer will start ASAP. -repl-diskless-sync-delay 5 - -# Slaves send PINGs to server in a predefined interval. It's possible to change -# this interval with the repl_ping_slave_period option. The default value is 10 -# seconds. -# -# repl-ping-slave-period 10 - -# The following option sets the replication timeout for: -# -# 1) Bulk transfer I/O during SYNC, from the point of view of slave. -# 2) Master timeout from the point of view of slaves (data, pings). -# 3) Slave timeout from the point of view of masters (REPLCONF ACK pings). -# -# It is important to make sure that this value is greater than the value -# specified for repl-ping-slave-period otherwise a timeout will be detected -# every time there is low traffic between the master and the slave. -# -# repl-timeout 60 - -# Disable TCP_NODELAY on the slave socket after SYNC? -# -# If you select "yes" Redis will use a smaller number of TCP packets and -# less bandwidth to send data to slaves. But this can add a delay for -# the data to appear on the slave side, up to 40 milliseconds with -# Linux kernels using a default configuration. -# -# If you select "no" the delay for data to appear on the slave side will -# be reduced but more bandwidth will be used for replication. -# -# By default we optimize for low latency, but in very high traffic conditions -# or when the master and slaves are many hops away, turning this to "yes" may -# be a good idea. -repl-disable-tcp-nodelay no - -# Set the replication backlog size. The backlog is a buffer that accumulates -# slave data when slaves are disconnected for some time, so that when a slave -# wants to reconnect again, often a full resync is not needed, but a partial -# resync is enough, just passing the portion of data the slave missed while -# disconnected. -# -# The bigger the replication backlog, the longer the time the slave can be -# disconnected and later be able to perform a partial resynchronization. -# -# The backlog is only allocated once there is at least a slave connected. -# -# repl-backlog-size 1mb - -# After a master has no longer connected slaves for some time, the backlog -# will be freed. The following option configures the amount of seconds that -# need to elapse, starting from the time the last slave disconnected, for -# the backlog buffer to be freed. -# -# Note that slaves never free the backlog for timeout, since they may be -# promoted to masters later, and should be able to correctly "partially -# resynchronize" with the slaves: hence they should always accumulate backlog. -# -# A value of 0 means to never release the backlog. -# -# repl-backlog-ttl 3600 - -# The slave priority is an integer number published by Redis in the INFO output. -# It is used by Redis Sentinel in order to select a slave to promote into a -# master if the master is no longer working correctly. -# -# A slave with a low priority number is considered better for promotion, so -# for instance if there are three slaves with priority 10, 100, 25 Sentinel will -# pick the one with priority 10, that is the lowest. -# -# However a special priority of 0 marks the slave as not able to perform the -# role of master, so a slave with priority of 0 will never be selected by -# Redis Sentinel for promotion. -# -# By default the priority is 100. -slave-priority 100 - -# It is possible for a master to stop accepting writes if there are less than -# N slaves connected, having a lag less or equal than M seconds. -# -# The N slaves need to be in "online" state. -# -# The lag in seconds, that must be <= the specified value, is calculated from -# the last ping received from the slave, that is usually sent every second. -# -# This option does not GUARANTEE that N replicas will accept the write, but -# will limit the window of exposure for lost writes in case not enough slaves -# are available, to the specified number of seconds. -# -# For example to require at least 3 slaves with a lag <= 10 seconds use: -# -# min-slaves-to-write 3 -# min-slaves-max-lag 10 -# -# Setting one or the other to 0 disables the feature. -# -# By default min-slaves-to-write is set to 0 (feature disabled) and -# min-slaves-max-lag is set to 10. - -# A Redis master is able to list the address and port of the attached -# slaves in different ways. For example the "INFO replication" section -# offers this information, which is used, among other tools, by -# Redis Sentinel in order to discover slave instances. -# Another place where this info is available is in the output of the -# "ROLE" command of a master. -# -# The listed IP and address normally reported by a slave is obtained -# in the following way: -# -# IP: The address is auto detected by checking the peer address -# of the socket used by the slave to connect with the master. -# -# Port: The port is communicated by the slave during the replication -# handshake, and is normally the port that the slave is using to -# list for connections. -# -# However when port forwarding or Network Address Translation (NAT) is -# used, the slave may be actually reachable via different IP and port -# pairs. The following two options can be used by a slave in order to -# report to its master a specific set of IP and port, so that both INFO -# and ROLE will report those values. -# -# There is no need to use both the options if you need to override just -# the port or the IP address. -# -# slave-announce-ip 5.5.5.5 -# slave-announce-port 1234 - -################################## SECURITY ################################### - -# Require clients to issue AUTH before processing any other -# commands. This might be useful in environments in which you do not trust -# others with access to the host running redis-server. -# -# This should stay commented out for backward compatibility and because most -# people do not need auth (e.g. they run their own servers). -# -# Warning: since Redis is pretty fast an outside user can try up to -# 150k passwords per second against a good box. This means that you should -# use a very strong password otherwise it will be very easy to break. -# -# requirepass foobared - -# Command renaming. -# -# It is possible to change the name of dangerous commands in a shared -# environment. For instance the CONFIG command may be renamed into something -# hard to guess so that it will still be available for internal-use tools -# but not available for general clients. -# -# Example: -# -# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 -# -# It is also possible to completely kill a command by renaming it into -# an empty string: -# -# rename-command CONFIG "" -# -# Please note that changing the name of commands that are logged into the -# AOF file or transmitted to slaves may cause problems. - -################################### CLIENTS #################################### - -# Set the max number of connected clients at the same time. By default -# this limit is set to 10000 clients, however if the Redis server is not -# able to configure the process file limit to allow for the specified limit -# the max number of allowed clients is set to the current file limit -# minus 32 (as Redis reserves a few file descriptors for internal uses). -# -# Once the limit is reached Redis will close all the new connections sending -# an error 'max number of clients reached'. -# -# maxclients 10000 - -############################## MEMORY MANAGEMENT ################################ - -# Set a memory usage limit to the specified amount of bytes. -# When the memory limit is reached Redis will try to remove keys -# according to the eviction policy selected (see maxmemory-policy). -# -# If Redis can't remove keys according to the policy, or if the policy is -# set to 'noeviction', Redis will start to reply with errors to commands -# that would use more memory, like SET, LPUSH, and so on, and will continue -# to reply to read-only commands like GET. -# -# This option is usually useful when using Redis as an LRU or LFU cache, or to -# set a hard memory limit for an instance (using the 'noeviction' policy). -# -# WARNING: If you have slaves attached to an instance with maxmemory on, -# the size of the output buffers needed to feed the slaves are subtracted -# from the used memory count, so that network problems / resyncs will -# not trigger a loop where keys are evicted, and in turn the output -# buffer of slaves is full with DELs of keys evicted triggering the deletion -# of more keys, and so forth until the database is completely emptied. -# -# In short... if you have slaves attached it is suggested that you set a lower -# limit for maxmemory so that there is some free RAM on the system for slave -# output buffers (but this is not needed if the policy is 'noeviction'). -# -# maxmemory - -# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory -# is reached. You can select among five behaviors: -# -# volatile-lru -> Evict using approximated LRU among the keys with an expire set. -# allkeys-lru -> Evict any key using approximated LRU. -# volatile-lfu -> Evict using approximated LFU among the keys with an expire set. -# allkeys-lfu -> Evict any key using approximated LFU. -# volatile-random -> Remove a random key among the ones with an expire set. -# allkeys-random -> Remove a random key, any key. -# volatile-ttl -> Remove the key with the nearest expire time (minor TTL) -# noeviction -> Don't evict anything, just return an error on write operations. -# -# LRU means Least Recently Used -# LFU means Least Frequently Used -# -# Both LRU, LFU and volatile-ttl are implemented using approximated -# randomized algorithms. -# -# Note: with any of the above policies, Redis will return an error on write -# operations, when there are no suitable keys for eviction. -# -# At the date of writing these commands are: set setnx setex append -# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd -# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby -# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby -# getset mset msetnx exec sort -# -# The default is: -# -# maxmemory-policy noeviction - -# LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated -# algorithms (in order to save memory), so you can tune it for speed or -# accuracy. For default Redis will check five keys and pick the one that was -# used less recently, you can change the sample size using the following -# configuration directive. -# -# The default of 5 produces good enough results. 10 Approximates very closely -# true LRU but costs more CPU. 3 is faster but not very accurate. -# -# maxmemory-samples 5 - -############################# LAZY FREEING #################################### - -# Redis has two primitives to delete keys. One is called DEL and is a blocking -# deletion of the object. It means that the server stops processing new commands -# in order to reclaim all the memory associated with an object in a synchronous -# way. If the key deleted is associated with a small object, the time needed -# in order to execute the DEL command is very small and comparable to most other -# O(1) or O(log_N) commands in Redis. However if the key is associated with an -# aggregated value containing millions of elements, the server can block for -# a long time (even seconds) in order to complete the operation. -# -# For the above reasons Redis also offers non blocking deletion primitives -# such as UNLINK (non blocking DEL) and the ASYNC option of FLUSHALL and -# FLUSHDB commands, in order to reclaim memory in background. Those commands -# are executed in constant time. Another thread will incrementally free the -# object in the background as fast as possible. -# -# DEL, UNLINK and ASYNC option of FLUSHALL and FLUSHDB are user-controlled. -# It's up to the design of the application to understand when it is a good -# idea to use one or the other. However the Redis server sometimes has to -# delete keys or flush the whole database as a side effect of other operations. -# Specifically Redis deletes objects independently of a user call in the -# following scenarios: -# -# 1) On eviction, because of the maxmemory and maxmemory policy configurations, -# in order to make room for new data, without going over the specified -# memory limit. -# 2) Because of expire: when a key with an associated time to live (see the -# EXPIRE command) must be deleted from memory. -# 3) Because of a side effect of a command that stores data on a key that may -# already exist. For example the RENAME command may delete the old key -# content when it is replaced with another one. Similarly SUNIONSTORE -# or SORT with STORE option may delete existing keys. The SET command -# itself removes any old content of the specified key in order to replace -# it with the specified string. -# 4) During replication, when a slave performs a full resynchronization with -# its master, the content of the whole database is removed in order to -# load the RDB file just transfered. -# -# In all the above cases the default is to delete objects in a blocking way, -# like if DEL was called. However you can configure each case specifically -# in order to instead release memory in a non-blocking way like if UNLINK -# was called, using the following configuration directives: - -lazyfree-lazy-eviction no -lazyfree-lazy-expire no -lazyfree-lazy-server-del no -slave-lazy-flush no - -############################## APPEND ONLY MODE ############################### - -# By default Redis asynchronously dumps the dataset on disk. This mode is -# good enough in many applications, but an issue with the Redis process or -# a power outage may result into a few minutes of writes lost (depending on -# the configured save points). -# -# The Append Only File is an alternative persistence mode that provides -# much better durability. For instance using the default data fsync policy -# (see later in the config file) Redis can lose just one second of writes in a -# dramatic event like a server power outage, or a single write if something -# wrong with the Redis process itself happens, but the operating system is -# still running correctly. -# -# AOF and RDB persistence can be enabled at the same time without problems. -# If the AOF is enabled on startup Redis will load the AOF, that is the file -# with the better durability guarantees. -# -# Please check http://redis.io/topics/persistence for more information. - -appendonly no - -# The name of the append only file (default: "appendonly.aof") - -appendfilename "appendonly.aof" - -# The fsync() call tells the Operating System to actually write data on disk -# instead of waiting for more data in the output buffer. Some OS will really flush -# data on disk, some other OS will just try to do it ASAP. -# -# Redis supports three different modes: -# -# no: don't fsync, just let the OS flush the data when it wants. Faster. -# always: fsync after every write to the append only log. Slow, Safest. -# everysec: fsync only one time every second. Compromise. -# -# The default is "everysec", as that's usually the right compromise between -# speed and data safety. It's up to you to understand if you can relax this to -# "no" that will let the operating system flush the output buffer when -# it wants, for better performances (but if you can live with the idea of -# some data loss consider the default persistence mode that's snapshotting), -# or on the contrary, use "always" that's very slow but a bit safer than -# everysec. -# -# More details please check the following article: -# http://antirez.com/post/redis-persistence-demystified.html -# -# If unsure, use "everysec". - -# appendfsync always -appendfsync everysec -# appendfsync no - -# When the AOF fsync policy is set to always or everysec, and a background -# saving process (a background save or AOF log background rewriting) is -# performing a lot of I/O against the disk, in some Linux configurations -# Redis may block too long on the fsync() call. Note that there is no fix for -# this currently, as even performing fsync in a different thread will block -# our synchronous write(2) call. -# -# In order to mitigate this problem it's possible to use the following option -# that will prevent fsync() from being called in the main process while a -# BGSAVE or BGREWRITEAOF is in progress. -# -# This means that while another child is saving, the durability of Redis is -# the same as "appendfsync none". In practical terms, this means that it is -# possible to lose up to 30 seconds of log in the worst scenario (with the -# default Linux settings). -# -# If you have latency problems turn this to "yes". Otherwise leave it as -# "no" that is the safest pick from the point of view of durability. - -no-appendfsync-on-rewrite no - -# Automatic rewrite of the append only file. -# Redis is able to automatically rewrite the log file implicitly calling -# BGREWRITEAOF when the AOF log size grows by the specified percentage. -# -# This is how it works: Redis remembers the size of the AOF file after the -# latest rewrite (if no rewrite has happened since the restart, the size of -# the AOF at startup is used). -# -# This base size is compared to the current size. If the current size is -# bigger than the specified percentage, the rewrite is triggered. Also -# you need to specify a minimal size for the AOF file to be rewritten, this -# is useful to avoid rewriting the AOF file even if the percentage increase -# is reached but it is still pretty small. -# -# Specify a percentage of zero in order to disable the automatic AOF -# rewrite feature. - -auto-aof-rewrite-percentage 100 -auto-aof-rewrite-min-size 64mb - -# An AOF file may be found to be truncated at the end during the Redis -# startup process, when the AOF data gets loaded back into memory. -# This may happen when the system where Redis is running -# crashes, especially when an ext4 filesystem is mounted without the -# data=ordered option (however this can't happen when Redis itself -# crashes or aborts but the operating system still works correctly). -# -# Redis can either exit with an error when this happens, or load as much -# data as possible (the default now) and start if the AOF file is found -# to be truncated at the end. The following option controls this behavior. -# -# If aof-load-truncated is set to yes, a truncated AOF file is loaded and -# the Redis server starts emitting a log to inform the user of the event. -# Otherwise if the option is set to no, the server aborts with an error -# and refuses to start. When the option is set to no, the user requires -# to fix the AOF file using the "redis-check-aof" utility before to restart -# the server. -# -# Note that if the AOF file will be found to be corrupted in the middle -# the server will still exit with an error. This option only applies when -# Redis will try to read more data from the AOF file but not enough bytes -# will be found. -aof-load-truncated yes - -# When rewriting the AOF file, Redis is able to use an RDB preamble in the -# AOF file for faster rewrites and recoveries. When this option is turned -# on the rewritten AOF file is composed of two different stanzas: -# -# [RDB file][AOF tail] -# -# When loading Redis recognizes that the AOF file starts with the "REDIS" -# string and loads the prefixed RDB file, and continues loading the AOF -# tail. -# -# This is currently turned off by default in order to avoid the surprise -# of a format change, but will at some point be used as the default. -aof-use-rdb-preamble no - -################################ LUA SCRIPTING ############################### - -# Max execution time of a Lua script in milliseconds. -# -# If the maximum execution time is reached Redis will log that a script is -# still in execution after the maximum allowed time and will start to -# reply to queries with an error. -# -# When a long running script exceeds the maximum execution time only the -# SCRIPT KILL and SHUTDOWN NOSAVE commands are available. The first can be -# used to stop a script that did not yet called write commands. The second -# is the only way to shut down the server in the case a write command was -# already issued by the script but the user doesn't want to wait for the natural -# termination of the script. -# -# Set it to 0 or a negative value for unlimited execution without warnings. -lua-time-limit 5000 - -################################ REDIS CLUSTER ############################### -# -# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -# WARNING EXPERIMENTAL: Redis Cluster is considered to be stable code, however -# in order to mark it as "mature" we need to wait for a non trivial percentage -# of users to deploy it in production. -# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -# -# Normal Redis instances can't be part of a Redis Cluster; only nodes that are -# started as cluster nodes can. In order to start a Redis instance as a -# cluster node enable the cluster support uncommenting the following: -# -# cluster-enabled yes - -# Every cluster node has a cluster configuration file. This file is not -# intended to be edited by hand. It is created and updated by Redis nodes. -# Every Redis Cluster node requires a different cluster configuration file. -# Make sure that instances running in the same system do not have -# overlapping cluster configuration file names. -# -# cluster-config-file nodes-6379.conf - -# Cluster node timeout is the amount of milliseconds a node must be unreachable -# for it to be considered in failure state. -# Most other internal time limits are multiple of the node timeout. -# -# cluster-node-timeout 15000 - -# A slave of a failing master will avoid to start a failover if its data -# looks too old. -# -# There is no simple way for a slave to actually have an exact measure of -# its "data age", so the following two checks are performed: -# -# 1) If there are multiple slaves able to failover, they exchange messages -# in order to try to give an advantage to the slave with the best -# replication offset (more data from the master processed). -# Slaves will try to get their rank by offset, and apply to the start -# of the failover a delay proportional to their rank. -# -# 2) Every single slave computes the time of the last interaction with -# its master. This can be the last ping or command received (if the master -# is still in the "connected" state), or the time that elapsed since the -# disconnection with the master (if the replication link is currently down). -# If the last interaction is too old, the slave will not try to failover -# at all. -# -# The point "2" can be tuned by user. Specifically a slave will not perform -# the failover if, since the last interaction with the master, the time -# elapsed is greater than: -# -# (node-timeout * slave-validity-factor) + repl-ping-slave-period -# -# So for example if node-timeout is 30 seconds, and the slave-validity-factor -# is 10, and assuming a default repl-ping-slave-period of 10 seconds, the -# slave will not try to failover if it was not able to talk with the master -# for longer than 310 seconds. -# -# A large slave-validity-factor may allow slaves with too old data to failover -# a master, while a too small value may prevent the cluster from being able to -# elect a slave at all. -# -# For maximum availability, it is possible to set the slave-validity-factor -# to a value of 0, which means, that slaves will always try to failover the -# master regardless of the last time they interacted with the master. -# (However they'll always try to apply a delay proportional to their -# offset rank). -# -# Zero is the only value able to guarantee that when all the partitions heal -# the cluster will always be able to continue. -# -# cluster-slave-validity-factor 10 - -# Cluster slaves are able to migrate to orphaned masters, that are masters -# that are left without working slaves. This improves the cluster ability -# to resist to failures as otherwise an orphaned master can't be failed over -# in case of failure if it has no working slaves. -# -# Slaves migrate to orphaned masters only if there are still at least a -# given number of other working slaves for their old master. This number -# is the "migration barrier". A migration barrier of 1 means that a slave -# will migrate only if there is at least 1 other working slave for its master -# and so forth. It usually reflects the number of slaves you want for every -# master in your cluster. -# -# Default is 1 (slaves migrate only if their masters remain with at least -# one slave). To disable migration just set it to a very large value. -# A value of 0 can be set but is useful only for debugging and dangerous -# in production. -# -# cluster-migration-barrier 1 - -# By default Redis Cluster nodes stop accepting queries if they detect there -# is at least an hash slot uncovered (no available node is serving it). -# This way if the cluster is partially down (for example a range of hash slots -# are no longer covered) all the cluster becomes, eventually, unavailable. -# It automatically returns available as soon as all the slots are covered again. -# -# However sometimes you want the subset of the cluster which is working, -# to continue to accept queries for the part of the key space that is still -# covered. In order to do so, just set the cluster-require-full-coverage -# option to no. -# -# cluster-require-full-coverage yes - -# This option, when set to yes, prevents slaves from trying to failover its -# master during master failures. However the master can still perform a -# manual failover, if forced to do so. -# -# This is useful in different scenarios, especially in the case of multiple -# data center operations, where we want one side to never be promoted if not -# in the case of a total DC failure. -# -# cluster-slave-no-failover no - -# In order to setup your cluster make sure to read the documentation -# available at http://redis.io web site. - -########################## CLUSTER DOCKER/NAT support ######################## - -# In certain deployments, Redis Cluster nodes address discovery fails, because -# addresses are NAT-ted or because ports are forwarded (the typical case is -# Docker and other containers). -# -# In order to make Redis Cluster working in such environments, a static -# configuration where each node knows its public address is needed. The -# following two options are used for this scope, and are: -# -# * cluster-announce-ip -# * cluster-announce-port -# * cluster-announce-bus-port -# -# Each instruct the node about its address, client port, and cluster message -# bus port. The information is then published in the header of the bus packets -# so that other nodes will be able to correctly map the address of the node -# publishing the information. -# -# If the above options are not used, the normal Redis Cluster auto-detection -# will be used instead. -# -# Note that when remapped, the bus port may not be at the fixed offset of -# clients port + 10000, so you can specify any port and bus-port depending -# on how they get remapped. If the bus-port is not set, a fixed offset of -# 10000 will be used as usually. -# -# Example: -# -# cluster-announce-ip 10.1.1.5 -# cluster-announce-port 6379 -# cluster-announce-bus-port 6380 - -################################## SLOW LOG ################################### - -# The Redis Slow Log is a system to log queries that exceeded a specified -# execution time. The execution time does not include the I/O operations -# like talking with the client, sending the reply and so forth, -# but just the time needed to actually execute the command (this is the only -# stage of command execution where the thread is blocked and can not serve -# other requests in the meantime). -# -# You can configure the slow log with two parameters: one tells Redis -# what is the execution time, in microseconds, to exceed in order for the -# command to get logged, and the other parameter is the length of the -# slow log. When a new command is logged the oldest one is removed from the -# queue of logged commands. - -# The following time is expressed in microseconds, so 1000000 is equivalent -# to one second. Note that a negative number disables the slow log, while -# a value of zero forces the logging of every command. -slowlog-log-slower-than 10000 - -# There is no limit to this length. Just be aware that it will consume memory. -# You can reclaim memory used by the slow log with SLOWLOG RESET. -slowlog-max-len 128 - -################################ LATENCY MONITOR ############################## - -# The Redis latency monitoring subsystem samples different operations -# at runtime in order to collect data related to possible sources of -# latency of a Redis instance. -# -# Via the LATENCY command this information is available to the user that can -# print graphs and obtain reports. -# -# The system only logs operations that were performed in a time equal or -# greater than the amount of milliseconds specified via the -# latency-monitor-threshold configuration directive. When its value is set -# to zero, the latency monitor is turned off. -# -# By default latency monitoring is disabled since it is mostly not needed -# if you don't have latency issues, and collecting data has a performance -# impact, that while very small, can be measured under big load. Latency -# monitoring can easily be enabled at runtime using the command -# "CONFIG SET latency-monitor-threshold " if needed. -latency-monitor-threshold 0 - -############################# EVENT NOTIFICATION ############################## - -# Redis can notify Pub/Sub clients about events happening in the key space. -# This feature is documented at http://redis.io/topics/notifications -# -# For instance if keyspace events notification is enabled, and a client -# performs a DEL operation on key "foo" stored in the Database 0, two -# messages will be published via Pub/Sub: -# -# PUBLISH __keyspace@0__:foo del -# PUBLISH __keyevent@0__:del foo -# -# It is possible to select the events that Redis will notify among a set -# of classes. Every class is identified by a single character: -# -# K Keyspace events, published with __keyspace@__ prefix. -# E Keyevent events, published with __keyevent@__ prefix. -# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ... -# $ String commands -# l List commands -# s Set commands -# h Hash commands -# z Sorted set commands -# x Expired events (events generated every time a key expires) -# e Evicted events (events generated when a key is evicted for maxmemory) -# A Alias for g$lshzxe, so that the "AKE" string means all the events. -# -# The "notify-keyspace-events" takes as argument a string that is composed -# of zero or multiple characters. The empty string means that notifications -# are disabled. -# -# Example: to enable list and generic events, from the point of view of the -# event name, use: -# -# notify-keyspace-events Elg -# -# Example 2: to get the stream of the expired keys subscribing to channel -# name __keyevent@0__:expired use: -# -# notify-keyspace-events Ex -# -# By default all notifications are disabled because most users don't need -# this feature and the feature has some overhead. Note that if you don't -# specify at least one of K or E, no events will be delivered. -notify-keyspace-events "" - -############################### ADVANCED CONFIG ############################### - -# Hashes are encoded using a memory efficient data structure when they have a -# small number of entries, and the biggest entry does not exceed a given -# threshold. These thresholds can be configured using the following directives. -hash-max-ziplist-entries 512 -hash-max-ziplist-value 64 - -# Lists are also encoded in a special way to save a lot of space. -# The number of entries allowed per internal list node can be specified -# as a fixed maximum size or a maximum number of elements. -# For a fixed maximum size, use -5 through -1, meaning: -# -5: max size: 64 Kb <-- not recommended for normal workloads -# -4: max size: 32 Kb <-- not recommended -# -3: max size: 16 Kb <-- probably not recommended -# -2: max size: 8 Kb <-- good -# -1: max size: 4 Kb <-- good -# Positive numbers mean store up to _exactly_ that number of elements -# per list node. -# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size), -# but if your use case is unique, adjust the settings as necessary. -list-max-ziplist-size -2 - -# Lists may also be compressed. -# Compress depth is the number of quicklist ziplist nodes from *each* side of -# the list to *exclude* from compression. The head and tail of the list -# are always uncompressed for fast push/pop operations. Settings are: -# 0: disable all list compression -# 1: depth 1 means "don't start compressing until after 1 node into the list, -# going from either the head or tail" -# So: [head]->node->node->...->node->[tail] -# [head], [tail] will always be uncompressed; inner nodes will compress. -# 2: [head]->[next]->node->node->...->node->[prev]->[tail] -# 2 here means: don't compress head or head->next or tail->prev or tail, -# but compress all nodes between them. -# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail] -# etc. -list-compress-depth 0 - -# Sets have a special encoding in just one case: when a set is composed -# of just strings that happen to be integers in radix 10 in the range -# of 64 bit signed integers. -# The following configuration setting sets the limit in the size of the -# set in order to use this special memory saving encoding. -set-max-intset-entries 512 - -# Similarly to hashes and lists, sorted sets are also specially encoded in -# order to save a lot of space. This encoding is only used when the length and -# elements of a sorted set are below the following limits: -zset-max-ziplist-entries 128 -zset-max-ziplist-value 64 - -# HyperLogLog sparse representation bytes limit. The limit includes the -# 16 bytes header. When an HyperLogLog using the sparse representation crosses -# this limit, it is converted into the dense representation. -# -# A value greater than 16000 is totally useless, since at that point the -# dense representation is more memory efficient. -# -# The suggested value is ~ 3000 in order to have the benefits of -# the space efficient encoding without slowing down too much PFADD, -# which is O(N) with the sparse encoding. The value can be raised to -# ~ 10000 when CPU is not a concern, but space is, and the data set is -# composed of many HyperLogLogs with cardinality in the 0 - 15000 range. -hll-sparse-max-bytes 3000 - -# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in -# order to help rehashing the main Redis hash table (the one mapping top-level -# keys to values). The hash table implementation Redis uses (see dict.c) -# performs a lazy rehashing: the more operation you run into a hash table -# that is rehashing, the more rehashing "steps" are performed, so if the -# server is idle the rehashing is never complete and some more memory is used -# by the hash table. -# -# The default is to use this millisecond 10 times every second in order to -# actively rehash the main dictionaries, freeing memory when possible. -# -# If unsure: -# use "activerehashing no" if you have hard latency requirements and it is -# not a good thing in your environment that Redis can reply from time to time -# to queries with 2 milliseconds delay. -# -# use "activerehashing yes" if you don't have such hard requirements but -# want to free memory asap when possible. -activerehashing yes - -# The client output buffer limits can be used to force disconnection of clients -# that are not reading data from the server fast enough for some reason (a -# common reason is that a Pub/Sub client can't consume messages as fast as the -# publisher can produce them). -# -# The limit can be set differently for the three different classes of clients: -# -# normal -> normal clients including MONITOR clients -# slave -> slave clients -# pubsub -> clients subscribed to at least one pubsub channel or pattern -# -# The syntax of every client-output-buffer-limit directive is the following: -# -# client-output-buffer-limit -# -# A client is immediately disconnected once the hard limit is reached, or if -# the soft limit is reached and remains reached for the specified number of -# seconds (continuously). -# So for instance if the hard limit is 32 megabytes and the soft limit is -# 16 megabytes / 10 seconds, the client will get disconnected immediately -# if the size of the output buffers reach 32 megabytes, but will also get -# disconnected if the client reaches 16 megabytes and continuously overcomes -# the limit for 10 seconds. -# -# By default normal clients are not limited because they don't receive data -# without asking (in a push way), but just after a request, so only -# asynchronous clients may create a scenario where data is requested faster -# than it can read. -# -# Instead there is a default limit for pubsub and slave clients, since -# subscribers and slaves receive data in a push fashion. -# -# Both the hard or the soft limit can be disabled by setting them to zero. -client-output-buffer-limit normal 0 0 0 -client-output-buffer-limit slave 256mb 64mb 60 -client-output-buffer-limit pubsub 32mb 8mb 60 - -# Client query buffers accumulate new commands. They are limited to a fixed -# amount by default in order to avoid that a protocol desynchronization (for -# instance due to a bug in the client) will lead to unbound memory usage in -# the query buffer. However you can configure it here if you have very special -# needs, such us huge multi/exec requests or alike. -# -# client-query-buffer-limit 1gb - -# In the Redis protocol, bulk requests, that are, elements representing single -# strings, are normally limited ot 512 mb. However you can change this limit -# here. -# -# proto-max-bulk-len 512mb - -# Redis calls an internal function to perform many background tasks, like -# closing connections of clients in timeout, purging expired keys that are -# never requested, and so forth. -# -# Not all tasks are performed with the same frequency, but Redis checks for -# tasks to perform according to the specified "hz" value. -# -# By default "hz" is set to 10. Raising the value will use more CPU when -# Redis is idle, but at the same time will make Redis more responsive when -# there are many keys expiring at the same time, and timeouts may be -# handled with more precision. -# -# The range is between 1 and 500, however a value over 100 is usually not -# a good idea. Most users should use the default of 10 and raise this up to -# 100 only in environments where very low latency is required. -hz 10 - -# When a child rewrites the AOF file, if the following option is enabled -# the file will be fsync-ed every 32 MB of data generated. This is useful -# in order to commit the file to the disk more incrementally and avoid -# big latency spikes. -aof-rewrite-incremental-fsync yes - -# Redis LFU eviction (see maxmemory setting) can be tuned. However it is a good -# idea to start with the default settings and only change them after investigating -# how to improve the performances and how the keys LFU change over time, which -# is possible to inspect via the OBJECT FREQ command. -# -# There are two tunable parameters in the Redis LFU implementation: the -# counter logarithm factor and the counter decay time. It is important to -# understand what the two parameters mean before changing them. -# -# The LFU counter is just 8 bits per key, it's maximum value is 255, so Redis -# uses a probabilistic increment with logarithmic behavior. Given the value -# of the old counter, when a key is accessed, the counter is incremented in -# this way: -# -# 1. A random number R between 0 and 1 is extracted. -# 2. A probability P is calculated as 1/(old_value*lfu_log_factor+1). -# 3. The counter is incremented only if R < P. -# -# The default lfu-log-factor is 10. This is a table of how the frequency -# counter changes with a different number of accesses with different -# logarithmic factors: -# -# +--------+------------+------------+------------+------------+------------+ -# | factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits | -# +--------+------------+------------+------------+------------+------------+ -# | 0 | 104 | 255 | 255 | 255 | 255 | -# +--------+------------+------------+------------+------------+------------+ -# | 1 | 18 | 49 | 255 | 255 | 255 | -# +--------+------------+------------+------------+------------+------------+ -# | 10 | 10 | 18 | 142 | 255 | 255 | -# +--------+------------+------------+------------+------------+------------+ -# | 100 | 8 | 11 | 49 | 143 | 255 | -# +--------+------------+------------+------------+------------+------------+ -# -# NOTE: The above table was obtained by running the following commands: -# -# redis-benchmark -n 1000000 incr foo -# redis-cli object freq foo -# -# NOTE 2: The counter initial value is 5 in order to give new objects a chance -# to accumulate hits. -# -# The counter decay time is the time, in minutes, that must elapse in order -# for the key counter to be divided by two (or decremented if it has a value -# less <= 10). -# -# The default value for the lfu-decay-time is 1. A Special value of 0 means to -# decay the counter every time it happens to be scanned. -# -# lfu-log-factor 10 -# lfu-decay-time 1 - -########################### ACTIVE DEFRAGMENTATION ####################### -# -# WARNING THIS FEATURE IS EXPERIMENTAL. However it was stress tested -# even in production and manually tested by multiple engineers for some -# time. -# -# What is active defragmentation? -# ------------------------------- -# -# Active (online) defragmentation allows a Redis server to compact the -# spaces left between small allocations and deallocations of data in memory, -# thus allowing to reclaim back memory. -# -# Fragmentation is a natural process that happens with every allocator (but -# less so with Jemalloc, fortunately) and certain workloads. Normally a server -# restart is needed in order to lower the fragmentation, or at least to flush -# away all the data and create it again. However thanks to this feature -# implemented by Oran Agra for Redis 4.0 this process can happen at runtime -# in an "hot" way, while the server is running. -# -# Basically when the fragmentation is over a certain level (see the -# configuration options below) Redis will start to create new copies of the -# values in contiguous memory regions by exploiting certain specific Jemalloc -# features (in order to understand if an allocation is causing fragmentation -# and to allocate it in a better place), and at the same time, will release the -# old copies of the data. This process, repeated incrementally for all the keys -# will cause the fragmentation to drop back to normal values. -# -# Important things to understand: -# -# 1. This feature is disabled by default, and only works if you compiled Redis -# to use the copy of Jemalloc we ship with the source code of Redis. -# This is the default with Linux builds. -# -# 2. You never need to enable this feature if you don't have fragmentation -# issues. -# -# 3. Once you experience fragmentation, you can enable this feature when -# needed with the command "CONFIG SET activedefrag yes". -# -# The configuration parameters are able to fine tune the behavior of the -# defragmentation process. If you are not sure about what they mean it is -# a good idea to leave the defaults untouched. - -# Enabled active defragmentation -# activedefrag yes - -# Minimum amount of fragmentation waste to start active defrag -# active-defrag-ignore-bytes 100mb - -# Minimum percentage of fragmentation to start active defrag -# active-defrag-threshold-lower 10 - -# Maximum percentage of fragmentation at which we use maximum effort -# active-defrag-threshold-upper 100 - -# Minimal effort for defrag in CPU percentage -# active-defrag-cycle-min 25 - -# Maximal effort for defrag in CPU percentage -# active-defrag-cycle-max 75 - diff --git a/src/cfg/redis/uas_system_config.txt b/src/cfg/redis/uas_system_config.txt deleted file mode 100644 index 229cf81..0000000 --- a/src/cfg/redis/uas_system_config.txt +++ /dev/null @@ -1,21 +0,0 @@ -/sys/arch/is_archiving 0 -/sys/arch/trigger_freq 1.0 -/sys/arch/base_template {base}/{project}/fl{flight}/{sys_cfg}/ -/sys/arch/template {base}/{project}/fl{flight}/{sys_cfg}/{cam_fov}_view/{project}_fl{flight}_{cf}_{time}_{mode}.{ext} -/sys/arch/project default_project -/sys/arch/effort default_effort -/sys/arch/sys_cfg default_cfg -/sys/arch/flight 00 -/sys/arch/ext_ir tif -/sys/arch/ext_rgb jpg -/sys/arch/base /mnt/flight_data -/sys/arch/kamera_dir /home/user/kw/noaa_kamera -/sys/uas0/rgb_device_id devicemodul00_0f_31_02_c2_8d -/sys/uas0/ir_device_id devicemodul00_11_1c_00_bf_6a -/sys/uas0/cam_fov center -/sys/uas1/rgb_device_id devicemodul00_0f_31_02_c2_8c -/sys/uas1/ir_device_id devicemodul00_11_1c_00_e1_1b -/sys/uas1/cam_fov right -/sys/uas2/rgb_device_id devicemodul00_0f_31_02_37_6c -/sys/uas2/ir_device_id devicemodul00_11_1c_00_e6_d1 -/sys/uas2/cam_fov left diff --git a/src/cfg/taiga/redis.conf b/src/cfg/taiga/redis.conf index 22b0486..2405d5a 100755 --- a/src/cfg/taiga/redis.conf +++ b/src/cfg/taiga/redis.conf @@ -85,7 +85,7 @@ bind center-0-taiga # you are sure you want clients from other hosts to connect to Redis # even if no authentication is configured, nor a specific set of interfaces # are explicitly listed using the "bind" directive. -protected-mode yes +protected-mode no # Accept connections on the specified port, default is 6379 (IANA #815344). # If port 0 is specified Redis will not listen on a TCP socket. From a4d1618757cee62ab4d4711dde1a236db165936b Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 10 Jun 2026 17:25:39 -0400 Subject: [PATCH 032/139] makefile, provisioning updates --- Makefile | 26 ++--------- docker-compose.yml | 10 ++--- provision/ansible/hosts.yml | 38 ++++++++-------- provision/ansible/playbooks/cas/configure.yml | 43 ++++++++----------- provision/ansible/playbooks/cas/provision.yml | 36 +++++----------- 5 files changed, 57 insertions(+), 96 deletions(-) diff --git a/Makefile b/Makefile index f64b5a6..c181dc7 100644 --- a/Makefile +++ b/Makefile @@ -1,32 +1,12 @@ -CMD ?= bash -runtime ?= runc -network ?= host -name ?= kamera -DAQDEV ?= mcc_daq -REPO_DIR ?= $(shell realpath ${PWD}) -REPO_DIR_BASEDIR ?= $(shell dirname $(REPO_DIR)) -ROS_MASTER_URI ?= not_set_your_config_is_bad -## Docker buildkit - disable by setting to 0 if you have issues - -DAQPATH = $(shell readlink -f "/dev/$(DAQDEV)") -PROJ_DIR=/root/kamera -WS_DIR=/root/kamera ROS_DISTRO=noetic -BRANCH=latest - -.PHONY: info -info: - @echo REPO_DIR_BASEDIR=$(REPO_DIR_BASEDIR) - @echo ROS_MASTER_URI=$(ROS_MASTER_URI) - @echo REDIS_HOST=$(REDIS_HOST) .PHONY: build build: docker compose build -.PHONY: nuvo -nuvo: - docker compose --profile nuvo build +.PHONY: core +core: + docker compose --profile core build .PHONY: viame viame: diff --git a/docker-compose.yml b/docker-compose.yml index 21d57fc..53e1638 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,7 +15,7 @@ services: context: ./src/core/kamerad image: "kitware/kamera:kamerad" profiles: - - nuvo + - core - all # The core ROS image with CUDA and basic APT packages, no KAMERA code. @@ -25,7 +25,7 @@ services: dockerfile: docker/base/core-ros.dockerfile image: "kamera/base/core-ros:${TAG_KAMERA_DEPS:-latest}" profiles: - - nuvo + - core - gui - all @@ -41,7 +41,7 @@ services: depends_on: - core-ros profiles: - - nuvo + - core - gui - all @@ -69,7 +69,7 @@ services: - "/tmp/.X11-unix:/tmp/.X11-unix" - "${PWD}/src:/root/kamera/src" profiles: - - nuvo + - core - all ## =========================== gui ============================= @@ -94,7 +94,7 @@ services: network_mode: host tty: true profiles: - - nuvo + - core - all - pf diff --git a/provision/ansible/hosts.yml b/provision/ansible/hosts.yml index 763e39c..1d9f30e 100644 --- a/provision/ansible/hosts.yml +++ b/provision/ansible/hosts.yml @@ -1,17 +1,17 @@ all: hosts: - nuvo0: - nuvo1: - nuvo2: - cas0: - cas1: - cas2: - cas3: - guibox: - uas: - uas0: - uas1: - uas2: + center-0-taiga: + left-1-taiga: + right-2-taiga: + center-0-nayak: + left-1-nayak: + right-2-nayak: + center-bak-nayak: + guibox: + uas: + uas0: + uas1: + uas2: vars: kamera_dir: "/home/user/kw/kamera" # Where the git repo is located data_dir: "/mnt/flight_data" # Where the flight data is stored @@ -20,7 +20,7 @@ all: children: taiga: hosts: - nuvo0: + center-0-taiga: redis_host: true supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/leader/supervisor.conf" leader: True @@ -28,13 +28,13 @@ all: gui: True # /dev/disk/by-uuid ssd_id: "ca0a9985-84ac-4019-95a6-242d3c81c86d" - nuvo1: + left-1-taiga: redis_host: False supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/follower/supervisor.conf" leader: False follower: True ssd_id: "d31ab8b6-b273-49c3-bd32-56c4fb76219c" - nuvo2: + right-2-taiga: redis_host: False supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/follower/supervisor.conf" leader: False @@ -73,25 +73,25 @@ all: nvidia_cuda: False cas: hosts: - cas0: + center-0-nayak: redis_host: true supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/leader/supervisor.conf" leader: True follower: False ssd_id: "3ca48dde-3b0f-440a-bbc2-69e6bd559325" - cas1: + left-1-nayak: redis_host: False supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/follower/supervisor.conf" leader: False follower: True ssd_id: "40d83577-292f-4795-b275-9b3c38504c22" - cas2: + right-2-nayak: redis_host: False supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/follower/supervisor.conf" leader: False follower: True ssd_id: "1b5b6c41-48f2-43fe-82db-fdc598387ea3" - cas3: + center-bak-nayak: redis_host: True supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/leader/supervisor.conf" leader: True diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index cba3785..94a9274 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -5,21 +5,21 @@ - name: Crewed system tasks block: - # - name: Clone kamera repo - # git: - # repo: "git@github.com:Kitware/kamera.git" - # dest: "{{ kamera_dir }}" - # version: main - # recursive: True - # accept_hostkey: True - # update: True - # force: True - - - name: "Set redis configuration to {{ kamera_dir }}/src/cfg/redis.conf" + - name: Clone kamera repo + git: + repo: "git@github.com:Kitware/kamera.git" + dest: "{{ kamera_dir }}" + version: develop + recursive: True + accept_hostkey: True + update: True + force: True + + - name: "Set redis configuration to {{ kamera_dir }}/src/cfg/{{ config_dir }}redis.conf" become: True when: redis_host copy: - src: "{{ kamera_dir }}/src/cfg/redis.conf" + src: "{{ kamera_dir }}/src/cfg/{{ config_dir }}/redis.conf" remote_src: true dest: /etc/redis/redis.conf owner: root @@ -100,13 +100,13 @@ dest: /etc/netplan/{{ inventory_hostname }}-netplan.yaml owner: root - # - name: Add mappings to /etc/hosts - # become: True - # copy: - # src: "{{ kamera_dir }}/src/cfg/{{ config_dir }}/{{ inventory_hostname }}/hosts" - # remote_src: true - # dest: /etc/hosts - # owner: root + - name: Add mappings to /etc/hosts + become: True + copy: + src: "{{ kamera_dir }}/src/cfg/hosts" + remote_src: true + dest: /etc/hosts + owner: root # Overwrite default, this is for our 10G cameras - name: Add sysctl rmem params. @@ -186,11 +186,6 @@ remote_src: true dest: /home/user/.bash_aliases - - name: Disable timesyncd on subsystems. - become: True - when: follower or leader or gui - shell: sudo systemctl disable systemd-timesyncd - - name: Disable sleep state on subsystems. become: True when: follower or leader or gui diff --git a/provision/ansible/playbooks/cas/provision.yml b/provision/ansible/playbooks/cas/provision.yml index a4b8621..2ff3546 100644 --- a/provision/ansible/playbooks/cas/provision.yml +++ b/provision/ansible/playbooks/cas/provision.yml @@ -3,8 +3,8 @@ - hosts: all vars: - nvidia_driver_version: 590 - linux_distro: ubuntu22.04 + nvidia_driver_version: 595 + linux_distro: ubuntu24.04 ansible_user: user sys_packages: [ 'apt-transport-https', 'gnupg-agent', # secure socket / signing @@ -32,14 +32,9 @@ 'openssh-server', # For ssh key use 'redis-server', 'redis-tools', # Redis tools 'ubuntu-drivers-common', # For hardware drivers - 'python3-pip' # Pip goodness + 'python3-pip', # Pip goodness + 'python3-redis', ] - pip_packages: [ - "ansible", - "ruff", - "redis", # seed_redis.py: Redis client for provisioning - "pyyaml", # seed_redis.py: YAML config loading - ] pre_tasks: - shell: uname -s @@ -65,7 +60,7 @@ repo: ppa:graphics-drivers/ppa state: present tags: - - nuvo + - cuda - name: Install "nvidia-driver-{{ nvidia_driver_version }}" become: True @@ -74,7 +69,7 @@ state: present update_cache: yes tags: - - nuvo + - cuda - name: Install required system packages become: True @@ -96,11 +91,12 @@ - name: Get nvidia-docker key become: True shell: | - curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey -o /usr/share/keyrings/nvidia-container-toolkit-keyring - gpg --dearmor /usr/share/keyrings/nvidia-container-toolkit-keyring - curl -s -L https://nvidia.github.io/libnvidia-container/{{ linux_distro }}/libnvidia-container.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | tee /etc/apt/sources.list.d/nvidia-container-toolkit.list + curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --dearmor --batch --yes -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ + && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \ + sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ + tee /etc/apt/sources.list.d/nvidia-container-toolkit.list tags: - - nuvo + - cuda - name: Add NVIDIA GPG key become: True @@ -152,9 +148,6 @@ group: name: dialout state: present - tags: - - base - - nuvo - name: "Add the user {{ ansible_user }} to group 'docker' and 'dialout'" become: True @@ -171,13 +164,6 @@ dest: /usr/local/bin/yq mode: '0755' - - name: Install pip packages - become: True - pip: - name: "{{ pip_packages }}" - state: latest - executable: pip3 - # - name: Reboot system # become: True # reboot: From 07907419328dfa2c25ac6cfb99e548857d54aab4 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Fri, 12 Jun 2026 12:44:29 -0400 Subject: [PATCH 033/139] Cleanup docker build chain, add concrete build steps to the makefile --- Makefile | 26 +++++++++++++++++++------- docker/base/core-deps.dockerfile | 27 --------------------------- docker/base/gui-ros.dockerfile | 6 +++--- docker/core.dockerfile | 24 ++++++++++++++++++------ docker/gui.dockerfile | 2 +- 5 files changed, 41 insertions(+), 44 deletions(-) diff --git a/Makefile b/Makefile index c181dc7..e0844d3 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,37 @@ -ROS_DISTRO=noetic +ROS_DISTRO ?= noetic + +.PHONY: build core viame gui postflight follower leader all clean -.PHONY: build build: docker compose build -.PHONY: core +## --- individual layer targets --- + core: docker compose --profile core build -.PHONY: viame viame: docker compose --profile viame build -.PHONY: gui gui: ROS_DISTRO=kinetic docker compose --profile gui build -.PHONY: postflight postflight: docker compose --profile pf build -.PHONY: clean +## --- deployment-target targets --- + +# Follower node: headless sensor node — core + VIAME + postproc +follower: + docker compose --profile follower build + +# Leader node: operator workstation — Kinetic GUI + postproc +leader: + ROS_DISTRO=kinetic docker compose --profile leader build + +# Everything +all: + docker compose --profile all build + clean: rm -rf .ros .catkin_tools .cmake .config build* devel* logs* diff --git a/docker/base/core-deps.dockerfile b/docker/base/core-deps.dockerfile index a6a5f64..18df1ef 100644 --- a/docker/base/core-deps.dockerfile +++ b/docker/base/core-deps.dockerfile @@ -102,30 +102,3 @@ RUN cd /src/DALSA &&\ > GigeV/bin/temp && mv GigeV/bin/temp GigeV/bin/install.gigev &&\ chmod +x GigeV/bin/install.gigev && ./corinstall install -## === === === === === === Project specifics === === === === === === === === -ENV WS_DIR=/root/kamera -WORKDIR /root/kamera - -# Copy products into container -COPY . $WS_DIR - -RUN rm -rf /entry &&\ - ln -sf $WS_DIR/src/run_scripts/entry /entry &&\ - printf "\nsource /entry/project.sh\n" >> /root/.bashrc &&\ - touch $WS_DIR/.catkin_workspace &&\ - ln -sf $WS_DIR/src/run_scripts/aliases.sh /aliases.sh &&\ - printf "\nsource /aliases.sh\n" >> /root/.bashrc - -# Making useful links and copies -RUN ln -sf $WS_DIR/scripts/activate_ros.bash $WS_DIR/activate_ros.bash -RUN ln -sf $WS_DIR/src/cfg /cfg -RUN mkdir -p /root/.config/kamera && \ - ln -sf $WS_DIR/.dir /root/.config/kamera/repo_dir.bash - -# Need to build phase one first to generate SRV -RUN ln -sv /usr/bin/python3 /usr/bin/python || true -RUN [ "/bin/bash", "-c", "source ${WS_DIR}/activate_ros.bash && catkin build phase_one"] -RUN [ "/bin/bash", "-c", "source /entry/project.sh && catkin build backend"] - -ENTRYPOINT ["/entry/project.sh"] -CMD ["bash"] diff --git a/docker/base/gui-ros.dockerfile b/docker/base/gui-ros.dockerfile index cea3246..fec3cf2 100644 --- a/docker/base/gui-ros.dockerfile +++ b/docker/base/gui-ros.dockerfile @@ -1,6 +1,6 @@ -FROM ros:noetic-robot as noetic-robot -ENV PYTHON=python3 \ - ROS_PKG_VERS=1.5.0-1 +FROM ros:kinetic-robot as kinetic-robot +ENV PYTHON=python2 \ + ROS_PKG_VERS=1.3.2-0 ## Necessary, followed by unessential but useful packages RUN apt-key adv --keyserver hkps://keyserver.ubuntu.com --refresh-keys diff --git a/docker/core.dockerfile b/docker/core.dockerfile index 0a95cef..18cd4d4 100644 --- a/docker/core.dockerfile +++ b/docker/core.dockerfile @@ -2,15 +2,27 @@ FROM kamera/base/core-deps:latest -COPY . /root/kamera -WORKDIR /root/kamera +ENV WS_DIR=/root/kamera +WORKDIR $WS_DIR -# use the exec form of run because we need bash syntax -RUN [ "/bin/bash", "-c", "source /entry/project.sh && catkin build -s backend"] -# python package is currently only supported for python3.10+, not on ubuntu20.04 -# RUN [ "/bin/bash", "-c", "pip install ."] +COPY . $WS_DIR + +RUN rm -rf /entry \ + && ln -sf $WS_DIR/src/run_scripts/entry /entry \ + && printf "\nsource /entry/project.sh\n" >> /root/.bashrc \ + && touch $WS_DIR/.catkin_workspace \ + && ln -sf $WS_DIR/src/run_scripts/aliases.sh /aliases.sh \ + && printf "\nsource /aliases.sh\n" >> /root/.bashrc +RUN ln -sf $WS_DIR/scripts/activate_ros.bash $WS_DIR/activate_ros.bash +RUN ln -sf $WS_DIR/src/cfg /cfg +RUN mkdir -p /root/.config/kamera && \ + ln -sf $WS_DIR/.dir /root/.config/kamera/repo_dir.bash +# Need to build phase_one first to generate SRV, then build backend +RUN ln -sv /usr/bin/python3 /usr/bin/python || true +RUN [ "/bin/bash", "-c", "source ${WS_DIR}/activate_ros.bash && catkin build phase_one"] +RUN [ "/bin/bash", "-c", "source /entry/project.sh && catkin build -s backend"] ENTRYPOINT ["/entry/project.sh"] CMD ["bash"] diff --git a/docker/gui.dockerfile b/docker/gui.dockerfile index 02be9e3..da0a79d 100644 --- a/docker/gui.dockerfile +++ b/docker/gui.dockerfile @@ -1,5 +1,5 @@ ARG BRANCH=latest -FROM kamera/base/kamera-gui-deps:latest +FROM kamera/base/core-gui-deps:latest # Create a non-root user and switch to it. Running X11 applications as root does From 261cff769eba4475e37cc3eecb129fee46c54342 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 09:52:24 -0400 Subject: [PATCH 034/139] Begin port to noetic GUI, moving all images to ubuntu 20.04 --- .github/workflows/gui-noetic-build.yml | 31 ++++++ Makefile | 5 +- docker-compose.yml | 139 +++++++++++++++++-------- docker/base/gui-deps-noetic.dockerfile | 27 +++++ docker/base/gui-deps.dockerfile | 1 - docker/gui.dockerfile | 3 +- 6 files changed, 162 insertions(+), 44 deletions(-) create mode 100644 .github/workflows/gui-noetic-build.yml create mode 100644 docker/base/gui-deps-noetic.dockerfile diff --git a/.github/workflows/gui-noetic-build.yml b/.github/workflows/gui-noetic-build.yml new file mode 100644 index 0000000..8da2b6d --- /dev/null +++ b/.github/workflows/gui-noetic-build.yml @@ -0,0 +1,31 @@ +name: GUI Noetic build + +on: + push: + paths: + - ".github/workflows/gui-noetic-build.yml" + - "docker/base/gui-deps-noetic.dockerfile" + - "docker/gui.dockerfile" + - "docker-compose.yml" + - "Makefile" + pull_request: + paths: + - ".github/workflows/gui-noetic-build.yml" + - "docker/base/gui-deps-noetic.dockerfile" + - "docker/gui.dockerfile" + - "docker-compose.yml" + - "Makefile" + +# NOTE: This is config validation only, not an image build. A real `make +# gui-noetic` build cannot pass until the Python 2 -> 3 port (Phases 2-3) lands, +# because gui.dockerfile runs `catkin build wxpython_gui` + `pip install -e .` +# against currently-unported Py2 code. Upgrade this to an actual layer build +# (e.g. build gui-deps-noetic against a published core-deps) once that is done. +jobs: + validate-compose: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Validate gui-noetic compose config + run: docker compose --profile gui-noetic config diff --git a/Makefile b/Makefile index e0844d3..05e28b3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ ROS_DISTRO ?= noetic -.PHONY: build core viame gui postflight follower leader all clean +.PHONY: build core viame gui gui-noetic postflight follower leader all clean build: docker compose build @@ -16,6 +16,9 @@ viame: gui: ROS_DISTRO=kinetic docker compose --profile gui build +gui-noetic: + docker compose --profile gui-noetic build + postflight: docker compose --profile pf build diff --git a/docker-compose.yml b/docker-compose.yml index 53e1638..76b72dc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,20 +5,33 @@ ## provide permissions with xhost, usually `xhost +local:root` (not the safest) ## You also have to volume mount `/tmp/.X11-unix`, blank out $DISPLAY, and ## disable X11 shared memory `QT_X11_NO_MITSHM=1` +## +## Deployment profiles: +## follower -- headless sensor node: core + VIAME + postproc +## leader -- operator workstation: Kinetic GUI + postproc +## all -- everything +## +## Individual layer profiles: +## core -- Noetic base images only (no VIAME, no GUI) +## viame -- VIAME detector images only +## gui -- Kinetic GUI images only +## gui-noetic -- Noetic GUI images only (parallel chain until cutover) +## pf -- postproc / postflight only -version: '3.7' services: -## ======================= base containers & bases ======================== - # Docker file for kamerad service +## ======================= Noetic core chain ======================== + + # Lightweight Python service; independent of ROS distro. kamerad: build: context: ./src/core/kamerad image: "kitware/kamera:kamerad" profiles: - core + - follower - all - # The core ROS image with CUDA and basic APT packages, no KAMERA code. + # CUDA + ROS Noetic base with utility packages. No KAMERA source. core-ros: build: context: . @@ -26,37 +39,26 @@ services: image: "kamera/base/core-ros:${TAG_KAMERA_DEPS:-latest}" profiles: - core - - gui + - follower - all + - gui-noetic -## =========================== main (full dependencies) ======================= - - ## This is the main image with all dependendencies required for KAMERA, built on - # the basic ROS image. + # System dependencies (drivers, C++ libs, ROS packages). No source copy. core-deps: build: context: . dockerfile: docker/base/core-deps.dockerfile image: "kamera/base/core-deps:${TAG_KAMERA_DEPS:-latest}" depends_on: - - core-ros + - core-ros profiles: - core - - gui + - follower - all + - gui-noetic - core-gui-deps: - build: - context: . - dockerfile: docker/base/gui-deps.dockerfile - image: "kamera/base/core-gui-deps:${TAG_KAMERA_GUI_DEPS:-latest}" - depends_on: - - core-deps - profiles: - - gui - - # Just for the catkin rebuild, if we want to save the static image. - core-final: + # KAMERA source + catkin build on top of core-deps. + core: build: context: . dockerfile: docker/core.dockerfile @@ -64,26 +66,15 @@ services: tty: true network_mode: host depends_on: - - core-deps + - core-deps volumes: - - "/tmp/.X11-unix:/tmp/.X11-unix" - - "${PWD}/src:/root/kamera/src" + - "/tmp/.X11-unix:/tmp/.X11-unix" + - "${PWD}/src:/root/kamera/src" profiles: - core + - follower - all -## =========================== gui ============================= - gui: - container_name: gui - build: - context: . - dockerfile: docker/gui.dockerfile - image: "kitware/kamera:gui" - depends_on: - - core-gui-deps - profiles: - - gui - postproc: build: context: . @@ -95,12 +86,13 @@ services: tty: true profiles: - core + - follower + - leader - all - pf +## ========================== VIAME detector chain ============================= - -## ========================== viame ============================= viame-base: build: context: . @@ -111,6 +103,7 @@ services: image: "kamera/base/viame:${VIAME_BRANCH:-latest}" profiles: - viame + - follower - all viame: @@ -125,10 +118,74 @@ services: network_mode: host command: ["bash"] depends_on: - - viame-base + - viame-base profiles: - viame + - follower + - all + +## ========================== Kinetic GUI chain ================================ + + # Kinetic ROS base for the GUI — independent of the Noetic core chain. + core-deps-kinetic: + build: + context: . + dockerfile: docker/base/gui-ros.dockerfile + image: "kamera/base/core-deps-kinetic:latest" + profiles: + - gui + - leader - all + core-gui-deps: + build: + context: . + dockerfile: docker/base/gui-deps.dockerfile + image: "kamera/base/core-gui-deps:${TAG_KAMERA_GUI_DEPS:-latest}" + depends_on: + - core-deps-kinetic + profiles: + - gui + - leader + - all + + gui: + container_name: gui + build: + context: . + dockerfile: docker/gui.dockerfile + image: "kitware/kamera:gui" + depends_on: + - core-gui-deps + profiles: + - gui + - leader + - all + +## ========================== Noetic GUI chain (parallel) ====================== + + gui-deps-noetic: + build: + context: . + dockerfile: docker/base/gui-deps-noetic.dockerfile + image: "kamera/base/gui-deps-noetic:${TAG_KAMERA_GUI_DEPS:-latest}" + depends_on: + - core-deps + profiles: + - gui-noetic + + gui-noetic: + container_name: gui-noetic + build: + context: . + dockerfile: docker/gui.dockerfile + args: + GUI_DEPS_IMAGE: "kamera/base/gui-deps-noetic:${TAG_KAMERA_GUI_DEPS:-latest}" + image: "kitware/kamera:gui-noetic" + depends_on: + - gui-deps-noetic + profiles: + - gui-noetic + ## ==================================================================== ... diff --git a/docker/base/gui-deps-noetic.dockerfile b/docker/base/gui-deps-noetic.dockerfile new file mode 100644 index 0000000..24d58bd --- /dev/null +++ b/docker/base/gui-deps-noetic.dockerfile @@ -0,0 +1,27 @@ +## GUI deps on the Noetic core-deps chain (parallel to Kinetic core-gui-deps). +FROM kamera/base/core-deps:latest + +RUN apt-get update && apt-get install -y --no-install-recommends \ + gdal-bin \ + python3-gdal \ + python3-tk \ + python3-wxgtk4.0 \ + libgl1-mesa-glx \ + libqt5x11extras5 \ + && rm -rf /var/lib/apt/lists/* + +RUN pip install --upgrade \ + pip \ + Pillow + +# numpy/scipy/shapely/pyshp come from core-deps; only GUI-unique deps here. +# TODO: validate the unpinned pygeodesy already installed by core-deps and drop +# this <19.12 downgrade (legacy Py2-era pin, untested on Py3). +RUN pip install --no-cache-dir \ + 'PyGeodesy<19.12' \ + exifread \ + ipython \ + simplekml + +COPY src/core/roskv /src/roskv +RUN pip install --no-cache-dir '/src/roskv[redis]' diff --git a/docker/base/gui-deps.dockerfile b/docker/base/gui-deps.dockerfile index c2e4b33..41e9fd2 100644 --- a/docker/base/gui-deps.dockerfile +++ b/docker/base/gui-deps.dockerfile @@ -7,7 +7,6 @@ RUN apt-get update && apt-get install -y \ python-tk \ libgl1-mesa-glx \ libqt5x11extras5 \ - openssh-server \ && rm -rf /var/lib/apt/lists/* RUN pip install --upgrade \ diff --git a/docker/gui.dockerfile b/docker/gui.dockerfile index da0a79d..38ce736 100644 --- a/docker/gui.dockerfile +++ b/docker/gui.dockerfile @@ -1,5 +1,6 @@ ARG BRANCH=latest -FROM kamera/base/core-gui-deps:latest +ARG GUI_DEPS_IMAGE=kamera/base/core-gui-deps:latest +FROM ${GUI_DEPS_IMAGE} # Create a non-root user and switch to it. Running X11 applications as root does From 8d3cdfeccbb99912580cca4babdfba6a24f05e73 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 10:01:28 -0400 Subject: [PATCH 035/139] Port all WX py2 code to WX py3 --- .../scripts/system_control_panel_node.py | 2 +- src/kitware-ros-pkg/wxpython_gui/setup.py | 2 +- .../wxpython_gui/src/wxpython_gui/LogFrame.py | 2 +- .../src/wxpython_gui/RemoteImagePanel.py | 4 +- .../src/wxpython_gui/SystemCommands.py | 2 +- .../src/wxpython_gui/UpdateImageThread.py | 10 +- .../src/wxpython_gui/camera_models.py | 4 +- .../wxpython_gui/src/wxpython_gui/cfg.py | 2 +- .../src/wxpython_gui/nav_conversion.py | 2 +- .../src/wxpython_gui/nav_state.py | 2 +- .../form_builder_output.py | 166 +++++++++--------- ...orm_builder_output_camera_configuration.py | 44 ++--- .../form_builder_output_collection_mode.py | 12 +- .../form_builder_output_effort_metadata.py | 34 ++-- .../form_builder_output_event_log_note.py | 10 +- .../form_builder_output_hot_key_list.py | 32 ++-- .../form_builder_output_imagery_inspection.py | 16 +- .../form_builder_output_log_panel.py | 4 +- .../form_builder_output_system_startup.py | 12 +- .../wxpython_gui/system_control_panel/gui.py | 5 +- .../system_control_panel/gui_utils.py | 2 +- .../wxpython_gui/src/wxpython_gui/utils.py | 3 +- 22 files changed, 186 insertions(+), 186 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py b/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py index 08f7082..03c632d 100755 --- a/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py +++ b/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ ckwg +31 Copyright 2017 by Kitware, Inc. diff --git a/src/kitware-ros-pkg/wxpython_gui/setup.py b/src/kitware-ros-pkg/wxpython_gui/setup.py index 4d81090..54db6e5 100644 --- a/src/kitware-ros-pkg/wxpython_gui/setup.py +++ b/src/kitware-ros-pkg/wxpython_gui/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from distutils.core import setup from catkin_pkg.python_setup import generate_distutils_setup diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/LogFrame.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/LogFrame.py index 4b1e61a..415f4d6 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/LogFrame.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/LogFrame.py @@ -20,7 +20,7 @@ def __init__(self, parent): wx.ALIGN_CENTRE|wx.ST_NO_AUTORESIZE) self.static_text.Wrap( -1 ) - self.static_text.SetFont(wx.Font(14, 70, 90, 92, False, + self.static_text.SetFont(wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString)) bsizer.Add(self.static_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/RemoteImagePanel.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/RemoteImagePanel.py index fd0bcb6..89dd89d 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/RemoteImagePanel.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/RemoteImagePanel.py @@ -185,7 +185,7 @@ def warp_image(self): wx_image = wx.EmptyImage(self.panel_image_width, self.panel_image_height) try: - wx_image.SetData(image.tostring()) + wx_image.SetData(image.tobytes()) except ValueError as err: raise ValueError('Shape: {} Chan {} \n {}'.format(image.shape, self.raw_image.dtype, err)) self.wx_bitmap = wx_image.ConvertToBitmap() @@ -277,7 +277,7 @@ def on_paint(self, event=None): panel_height), interpolation=cv2.INTER_NEAREST) wx_image = wx.EmptyImage(panel_width, panel_height) - wx_image.SetData(image.tostring()) + wx_image.SetData(image.tobytes()) wx_histogram_bitmap = wx_image.ConvertToBitmap() pdc = wx.PaintDC(self.wx_histogram_panel) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemCommands.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemCommands.py index f73876b..aa604b2 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemCommands.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemCommands.py @@ -1,6 +1,6 @@ from wxpython_gui.cfg import kv, DOCK_KAM_REPO_DIR, REAL_KAM_REPO_DIR import time -import xmlrpclib +import xmlrpc.client as xmlrpclib class SystemCommandsCall(object): diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/UpdateImageThread.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/UpdateImageThread.py index b9391a6..1005a64 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/UpdateImageThread.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/UpdateImageThread.py @@ -3,7 +3,7 @@ import datetime import threading import rospy -import StringIO +from io import BytesIO import cv2 import sys import time @@ -163,7 +163,7 @@ def process_pub_image(self, image_msg): if len(image_msg.data) == 0: return if self._compressed: - sio = StringIO.StringIO(image_msg.data) + sio = BytesIO(image_msg.data) im = PILImage.open(sio) preview = np.array(im) raw_preview = preview.copy() @@ -253,7 +253,7 @@ def get_new_raw_image(self, release=0): if len(image_msg.data) == 0: return if self._compressed: - sio = StringIO.StringIO(image_msg.data) + sio = BytesIO(image_msg.data) im = PILImage.open(sio) image = np.array(im) image = image.copy() @@ -281,12 +281,12 @@ def get_new_raw_image(self, release=0): ) return - except wx._core.PyDeadObjectError as e: + except RuntimeError as e: rospy.logwarn(e) return def update_status_msg(self, img_header): - # type: (std_msgs.msg.Header) -> unicode + # type: (std_msgs.msg.Header) -> str """Update the status bar for an image view""" t = img_header.stamp.to_sec() t = datetime.datetime.utcfromtimestamp(t) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py index c526f45..b2933ef 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ ckwg +31 Copyright 2017-2018 by Kitware, Inc. @@ -640,7 +640,7 @@ def publish_image_from_list(self, t): # Compressed image image_message = CompressedImage() image_message.format = "jpeg" - image_message.data = np.array(cv2.imencode('.jpg', img)[1]).tostring() + image_message.data = np.array(cv2.imencode('.jpg', img)[1]).tobytes() image_message.header.frame_id = self._frame_id image_message.header.stamp = genpy.Time.from_sec(t) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py index de6b6e2..07c8562 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py @@ -331,7 +331,7 @@ def format_status( total=None, processed=None, ): - # type: (datetime.datetime, int, int, int, float, float, str) -> unicode + # type: (datetime.datetime, int, int, int, float, float, str) -> str """ Render the status message. ☒☀⚠⍙ diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/nav_conversion.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/nav_conversion.py index 952b4d6..38a58ed 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/nav_conversion.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/nav_conversion.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ The MIT License (MIT); this license applies to GeographicLib, versions 1.12 and later. diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/nav_state.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/nav_state.py index 8b4c60a..1379a5d 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/nav_state.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/nav_state.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ ckwg +31 Copyright 2017-2019 by Kitware, Inc. diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index fbb5323..8c2c9a6 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -16,7 +16,7 @@ ID_STOP_DETECTOR_SYS0_CENTER = 1003 ID_STOP_DETECTOR_SYS1_LEFT = 1004 ID_STOP_DETECTOR_SYS2_RIGHT = 1005 -wx._ID_ANY = 1006 +ID_MENU_FIN_TUNE_TRACKING = 1006 ########################################################################### ## Class MainFrame @@ -27,8 +27,8 @@ class MainFrame ( wx.Frame ): def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"System Control Panel", pos = wx.DefaultPosition, size = wx.Size( 1117,1062 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) - self.SetSizeHintsSz( wx.Size( 400,400 ), wx.DefaultSize ) - self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) ) + self.SetSizeHints( wx.Size( 400,400 ), wx.DefaultSize ) + self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) self.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOWTEXT ) ) main_size = wx.BoxSizer( wx.HORIZONTAL ) @@ -40,7 +40,7 @@ def __init__( self, parent ): self.m_staticText142 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Navigation Data", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText142.Wrap( -1 ) - self.m_staticText142.SetFont( wx.Font( 16, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText142.SetFont( wx.Font( 16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer191.Add( self.m_staticText142, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT, 5 ) @@ -51,7 +51,7 @@ def __init__( self, parent ): self.m_staticText181 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Lat (deg)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText181.Wrap( -1 ) - self.m_staticText181.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText181.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer181.Add( self.m_staticText181, 0, wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM|wx.RIGHT|wx.LEFT, 5 ) @@ -67,7 +67,7 @@ def __init__( self, parent ): self.m_staticText = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Lon (deg)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText.Wrap( -1 ) - self.m_staticText.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer1811.Add( self.m_staticText, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) @@ -81,7 +81,7 @@ def __init__( self, parent ): self.m_staticText1812 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Alt HAE (m)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText1812.Wrap( -1 ) - self.m_staticText1812.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText1812.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer1812.Add( self.m_staticText1812, 0, wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM|wx.RIGHT|wx.LEFT, 5 ) @@ -95,7 +95,7 @@ def __init__( self, parent ): self.m_staticText18121 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Alt MSL (m)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText18121.Wrap( -1 ) - self.m_staticText18121.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText18121.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer18121.Add( self.m_staticText18121, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) @@ -109,7 +109,7 @@ def __init__( self, parent ): self.m_staticText18191 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Speed (kts)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText18191.Wrap( -1 ) - self.m_staticText18191.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText18191.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer18191.Add( self.m_staticText18191, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) @@ -123,7 +123,7 @@ def __init__( self, parent ): self.m_staticText1819 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Heading (deg)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText1819.Wrap( -1 ) - self.m_staticText1819.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText1819.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer1819.Add( self.m_staticText1819, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) @@ -137,7 +137,7 @@ def __init__( self, parent ): self.m_staticText1818 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Pitch (deg)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText1818.Wrap( -1 ) - self.m_staticText1818.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText1818.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer1818.Add( self.m_staticText1818, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) @@ -151,7 +151,7 @@ def __init__( self, parent ): self.m_staticText1817 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Roll (deg)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText1817.Wrap( -1 ) - self.m_staticText1817.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText1817.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer1817.Add( self.m_staticText1817, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) @@ -165,7 +165,7 @@ def __init__( self, parent ): self.m_staticText1817131 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Time (s)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText1817131.Wrap( -1 ) - self.m_staticText1817131.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText1817131.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer1817131.Add( self.m_staticText1817131, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) @@ -181,7 +181,7 @@ def __init__( self, parent ): self.m_staticText181713131 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"GNSS Status", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText181713131.Wrap( -1 ) - self.m_staticText181713131.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText181713131.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer511.Add( self.m_staticText181713131, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT, 5 ) @@ -195,7 +195,7 @@ def __init__( self, parent ): self.m_staticText18171313 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Align Status", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText18171313.Wrap( -1 ) - self.m_staticText18171313.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText18171313.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer51.Add( self.m_staticText18171313, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT, 5 ) @@ -219,7 +219,7 @@ def __init__( self, parent ): self.m_staticText142111 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Camera Settings", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText142111.Wrap( -1 ) - self.m_staticText142111.SetFont( wx.Font( 16, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText142111.SetFont( wx.Font( 16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) m_staticText14211.Add( self.m_staticText142111, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT, 5 ) @@ -243,7 +243,7 @@ def __init__( self, parent ): self.m_staticText42 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Auto Exposure (ms)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText42.Wrap( -1 ) - self.m_staticText42.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText42.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) m_staticText14211.Add( self.m_staticText42, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -251,7 +251,7 @@ def __init__( self, parent ): self.m_staticText423 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Min:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText423.Wrap( -1 ) - self.m_staticText423.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText423.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer442.Add( self.m_staticText423, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) @@ -263,7 +263,7 @@ def __init__( self, parent ): self.m_staticText4231 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Max:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText4231.Wrap( -1 ) - self.m_staticText4231.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText4231.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer442.Add( self.m_staticText4231, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) @@ -278,7 +278,7 @@ def __init__( self, parent ): self.m_staticText422 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Auto Gain (0-32)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText422.Wrap( -1 ) - self.m_staticText422.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText422.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) m_staticText14211.Add( self.m_staticText422, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT, 5 ) @@ -286,7 +286,7 @@ def __init__( self, parent ): self.m_staticText4232 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Min:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText4232.Wrap( -1 ) - self.m_staticText4232.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText4232.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4421.Add( self.m_staticText4232, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) @@ -298,7 +298,7 @@ def __init__( self, parent ): self.m_staticText42311 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Max:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText42311.Wrap( -1 ) - self.m_staticText42311.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText42311.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4421.Add( self.m_staticText42311, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) @@ -315,7 +315,7 @@ def __init__( self, parent ): self.txtNUC = wx.StaticText( self.camera_panel, wx.ID_ANY, u"IR NUC Time (min):", wx.DefaultPosition, wx.DefaultSize, 0 ) self.txtNUC.Wrap( -1 ) - self.txtNUC.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.txtNUC.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer44211.Add( self.txtNUC, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 5 ) @@ -331,12 +331,12 @@ def __init__( self, parent ): m_staticText14211.Add( bSizer442111, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.BOTTOM, 5 ) self.m_button10 = wx.Button( self.camera_panel, wx.ID_ANY, u"Set Camera Parameter", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_button10.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_button10.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) m_staticText14211.Add( self.m_button10, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT, 5 ) self.m_manual_ir_nuc = wx.Button( self.camera_panel, wx.ID_ANY, u"Manual IR NUC", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_manual_ir_nuc.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_manual_ir_nuc.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) m_staticText14211.Add( self.m_manual_ir_nuc, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT, 5 ) @@ -351,7 +351,7 @@ def __init__( self, parent ): self.m_staticText14211 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"Data Collection", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText14211.Wrap( -1 ) - self.m_staticText14211.SetFont( wx.Font( 16, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText14211.SetFont( wx.Font( 16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer391.Add( self.m_staticText14211, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT, 5 ) @@ -366,7 +366,7 @@ def __init__( self, parent ): self.m_staticText18171311 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"Effort", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText18171311.Wrap( -1 ) - self.m_staticText18171311.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText18171311.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer441.Add( self.m_staticText18171311, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) @@ -398,7 +398,7 @@ def __init__( self, parent ): self.m_staticText33 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"Flight:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText33.Wrap( -1 ) - self.m_staticText33.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText33.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer45.Add( self.m_staticText33, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) @@ -416,7 +416,7 @@ def __init__( self, parent ): self.m_staticText331 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"Observer", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText331.Wrap( -1 ) - self.m_staticText331.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText331.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer451.Add( self.m_staticText331, 0, wx.RIGHT|wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -489,7 +489,7 @@ def __init__( self, parent ): self.nas_disk_space = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"NAS Disk Space: ?", wx.DefaultPosition, wx.DefaultSize, 0 ) self.nas_disk_space.Wrap( -1 ) - self.nas_disk_space.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.nas_disk_space.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer391.Add( self.nas_disk_space, 0, wx.TOP|wx.RIGHT|wx.LEFT, 5 ) @@ -526,7 +526,7 @@ def __init__( self, parent ): self.m_staticText40 = wx.StaticText( self.m_panel37, wx.ID_ANY, u"Camera/Mount Configuration", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText40.Wrap( -1 ) - self.m_staticText40.SetFont( wx.Font( 12, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText40.SetFont( wx.Font( 12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer61.Add( self.m_staticText40, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -547,7 +547,7 @@ def __init__( self, parent ): bsizer12.Add( self.m_panel37, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND|wx.TOP|wx.RIGHT, 5 ) self.images_panel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.Size( -1,-1 ), wx.TAB_TRAVERSAL ) - self.images_panel.SetFont( wx.Font( 9, 70, 90, 90, False, wx.EmptyString ) ) + self.images_panel.SetFont( wx.Font( 9, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) bSizer16 = wx.BoxSizer( wx.VERTICAL ) @@ -558,7 +558,7 @@ def __init__( self, parent ): self.cueing_left_image_title3 = wx.StaticText( self.m_panel_left_rgb, wx.ID_ANY, u"Left RGB", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_left_image_title3.Wrap( -1 ) - self.cueing_left_image_title3.SetFont( wx.Font( 14, 74, 90, 92, False, "Sans" ) ) + self.cueing_left_image_title3.SetFont( wx.Font( 14, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Sans" ) ) left_bsizer0.Add( self.cueing_left_image_title3, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -570,7 +570,7 @@ def __init__( self, parent ): self.left_rgb_status_text = wx.StaticText( self.m_panel_left_rgb, wx.ID_ANY, u"Empty", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) self.left_rgb_status_text.Wrap( -1 ) - self.left_rgb_status_text.SetFont( wx.Font( 10, 70, 90, 92, False, wx.EmptyString ) ) + self.left_rgb_status_text.SetFont( wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) left_bsizer0.Add( self.left_rgb_status_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -585,7 +585,7 @@ def __init__( self, parent ): self.cueing_right_image_title = wx.StaticText( self.m_panel_center_rgb, wx.ID_ANY, u"Center RGB", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_right_image_title.Wrap( -1 ) - self.cueing_right_image_title.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.cueing_right_image_title.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) right_bsizer0.Add( self.cueing_right_image_title, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -602,7 +602,7 @@ def __init__( self, parent ): self.center_rgb_status_text = wx.StaticText( self.m_panel_center_rgb, wx.ID_ANY, u"Empty", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) self.center_rgb_status_text.Wrap( -1 ) - self.center_rgb_status_text.SetFont( wx.Font( 10, 70, 90, 92, False, wx.EmptyString ) ) + self.center_rgb_status_text.SetFont( wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) right_bsizer0.Add( self.center_rgb_status_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -617,7 +617,7 @@ def __init__( self, parent ): self.ptz_image_title = wx.StaticText( self.m_panel_right_rgb, wx.ID_ANY, u"Right RGB", wx.DefaultPosition, wx.DefaultSize, 0 ) self.ptz_image_title.Wrap( -1 ) - self.ptz_image_title.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.ptz_image_title.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) right_bsizer0.Add( self.ptz_image_title, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -634,7 +634,7 @@ def __init__( self, parent ): self.right_rgb_status_text = wx.StaticText( self.m_panel_right_rgb, wx.ID_ANY, u"Empty", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) self.right_rgb_status_text.Wrap( -1 ) - self.right_rgb_status_text.SetFont( wx.Font( 10, 70, 90, 92, False, wx.EmptyString ) ) + self.right_rgb_status_text.SetFont( wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) right_bsizer0.Add( self.right_rgb_status_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -654,7 +654,7 @@ def __init__( self, parent ): self.cueing_left_image_title1 = wx.StaticText( self.m_panel_left_ir, wx.ID_ANY, u"Left IR", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_left_image_title1.Wrap( -1 ) - self.cueing_left_image_title1.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.cueing_left_image_title1.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) left_bsizer1.Add( self.cueing_left_image_title1, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -671,7 +671,7 @@ def __init__( self, parent ): self.left_ir_status_text = wx.StaticText( self.m_panel_left_ir, wx.ID_ANY, u"Empty", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) self.left_ir_status_text.Wrap( -1 ) - self.left_ir_status_text.SetFont( wx.Font( 10, 70, 90, 92, False, wx.EmptyString ) ) + self.left_ir_status_text.SetFont( wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) left_bsizer1.Add( self.left_ir_status_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -686,7 +686,7 @@ def __init__( self, parent ): self.cueing_right_image_title1 = wx.StaticText( self.m_panel_center_ir, wx.ID_ANY, u"Center IR", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_right_image_title1.Wrap( -1 ) - self.cueing_right_image_title1.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.cueing_right_image_title1.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) right_bsizer1.Add( self.cueing_right_image_title1, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -703,7 +703,7 @@ def __init__( self, parent ): self.center_ir_status_text = wx.StaticText( self.m_panel_center_ir, wx.ID_ANY, u"Empty", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) self.center_ir_status_text.Wrap( -1 ) - self.center_ir_status_text.SetFont( wx.Font( 10, 70, 90, 92, False, wx.EmptyString ) ) + self.center_ir_status_text.SetFont( wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) right_bsizer1.Add( self.center_ir_status_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -718,7 +718,7 @@ def __init__( self, parent ): self.ptz_image_title1 = wx.StaticText( self.m_panel_right_ir, wx.ID_ANY, u"Right IR", wx.DefaultPosition, wx.DefaultSize, 0 ) self.ptz_image_title1.Wrap( -1 ) - self.ptz_image_title1.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.ptz_image_title1.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) ptz_bsizer1.Add( self.ptz_image_title1, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -735,7 +735,7 @@ def __init__( self, parent ): self.right_ir_status_text = wx.StaticText( self.m_panel_right_ir, wx.ID_ANY, u"Empty", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) self.right_ir_status_text.Wrap( -1 ) - self.right_ir_status_text.SetFont( wx.Font( 10, 70, 90, 92, False, wx.EmptyString ) ) + self.right_ir_status_text.SetFont( wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) ptz_bsizer1.Add( self.right_ir_status_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -755,7 +755,7 @@ def __init__( self, parent ): self.cueing_left_image_title2 = wx.StaticText( self.m_panel_left_uv, wx.ID_ANY, u"Left UV", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_left_image_title2.Wrap( -1 ) - self.cueing_left_image_title2.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.cueing_left_image_title2.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) left_bsizer2.Add( self.cueing_left_image_title2, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -772,7 +772,7 @@ def __init__( self, parent ): self.left_uv_status_text = wx.StaticText( self.m_panel_left_uv, wx.ID_ANY, u"Empty", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) self.left_uv_status_text.Wrap( -1 ) - self.left_uv_status_text.SetFont( wx.Font( 10, 70, 90, 92, False, wx.EmptyString ) ) + self.left_uv_status_text.SetFont( wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) left_bsizer2.Add( self.left_uv_status_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -787,7 +787,7 @@ def __init__( self, parent ): self.cueing_right_image_title2 = wx.StaticText( self.m_panel_center_uv, wx.ID_ANY, u"Center UV", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_right_image_title2.Wrap( -1 ) - self.cueing_right_image_title2.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.cueing_right_image_title2.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) right_bsizer2.Add( self.cueing_right_image_title2, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -804,7 +804,7 @@ def __init__( self, parent ): self.center_uv_status_text = wx.StaticText( self.m_panel_center_uv, wx.ID_ANY, u"Empty", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) self.center_uv_status_text.Wrap( -1 ) - self.center_uv_status_text.SetFont( wx.Font( 10, 70, 90, 92, False, wx.EmptyString ) ) + self.center_uv_status_text.SetFont( wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) right_bsizer2.Add( self.center_uv_status_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -819,7 +819,7 @@ def __init__( self, parent ): self.ptz_image_title2 = wx.StaticText( self.m_panel_right_uv, wx.ID_ANY, u"Right UV", wx.DefaultPosition, wx.DefaultSize, 0 ) self.ptz_image_title2.Wrap( -1 ) - self.ptz_image_title2.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.ptz_image_title2.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) ptz_bsizer2.Add( self.ptz_image_title2, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -836,7 +836,7 @@ def __init__( self, parent ): self.right_uv_status_text = wx.StaticText( self.m_panel_right_uv, wx.ID_ANY, u"Empty", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) self.right_uv_status_text.Wrap( -1 ) - self.right_uv_status_text.SetFont( wx.Font( 10, 70, 90, 92, False, wx.EmptyString ) ) + self.right_uv_status_text.SetFont( wx.Font( 10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) ptz_bsizer2.Add( self.right_uv_status_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -856,7 +856,7 @@ def __init__( self, parent ): self.left_sys_detector_frames = wx.StaticText( self.sys1_detector_frames, wx.ID_ANY, u"Detector Frames: ?", wx.DefaultPosition, wx.DefaultSize, 0 ) self.left_sys_detector_frames.Wrap( -1 ) - self.left_sys_detector_frames.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.left_sys_detector_frames.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bsizer2131.Add( self.left_sys_detector_frames, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -871,7 +871,7 @@ def __init__( self, parent ): self.center_sys_detector_frames = wx.StaticText( self.sys0_detector_frame1, wx.ID_ANY, u"Detector Frames: ?", wx.DefaultPosition, wx.DefaultSize, 0 ) self.center_sys_detector_frames.Wrap( -1 ) - self.center_sys_detector_frames.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.center_sys_detector_frames.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bsizer21221.Add( self.center_sys_detector_frames, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -886,7 +886,7 @@ def __init__( self, parent ): self.right_sys_detector_frames = wx.StaticText( self.sys2_detector_frames, wx.ID_ANY, u"Detector Frames: ?", wx.DefaultPosition, wx.DefaultSize, 0 ) self.right_sys_detector_frames.Wrap( -1 ) - self.right_sys_detector_frames.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.right_sys_detector_frames.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bsizer2121.Add( self.right_sys_detector_frames, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -906,7 +906,7 @@ def __init__( self, parent ): self.left_sys_space_static_text = wx.StaticText( self.sys1_disk_usage_panel, wx.ID_ANY, u"Disk Space: ?", wx.DefaultPosition, wx.DefaultSize, 0 ) self.left_sys_space_static_text.Wrap( -1 ) - self.left_sys_space_static_text.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.left_sys_space_static_text.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bsizer213.Add( self.left_sys_space_static_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -921,7 +921,7 @@ def __init__( self, parent ): self.center_sys_space_static_text = wx.StaticText( self.sys0_disk_usage_panel, wx.ID_ANY, u"Disk Space: ?", wx.DefaultPosition, wx.DefaultSize, 0 ) self.center_sys_space_static_text.Wrap( -1 ) - self.center_sys_space_static_text.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.center_sys_space_static_text.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bsizer2122.Add( self.center_sys_space_static_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -936,7 +936,7 @@ def __init__( self, parent ): self.right_sys_space_static_text = wx.StaticText( self.sys2_disk_usage_panel, wx.ID_ANY, u"Disk Space: ?", wx.DefaultPosition, wx.DefaultSize, 0 ) self.right_sys_space_static_text.Wrap( -1 ) - self.right_sys_space_static_text.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.right_sys_space_static_text.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bsizer212.Add( self.right_sys_space_static_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -964,101 +964,101 @@ def __init__( self, parent ): self.m_menubar1 = wx.MenuBar( 0 ) self.exit_menu = wx.Menu() self.exit_menu_item = wx.MenuItem( self.exit_menu, wx.ID_ANY, u"Exit", wx.EmptyString, wx.ITEM_NORMAL ) - self.exit_menu.AppendItem( self.exit_menu_item ) + self.exit_menu.Append( self.exit_menu_item ) self.m_menubar1.Append( self.exit_menu, u"File" ) self.view_menu = wx.Menu() self.m_menuItem3 = wx.MenuItem( self.view_menu, wx.ID_ANY, u"Show/Hide Left Subsystem", wx.EmptyString, wx.ITEM_NORMAL ) - self.view_menu.AppendItem( self.m_menuItem3 ) + self.view_menu.Append( self.m_menuItem3 ) self.m_menuItem4 = wx.MenuItem( self.view_menu, wx.ID_ANY, u"Show/Hide Center Subsystem", wx.EmptyString, wx.ITEM_NORMAL ) - self.view_menu.AppendItem( self.m_menuItem4 ) + self.view_menu.Append( self.m_menuItem4 ) self.m_menuItem5 = wx.MenuItem( self.view_menu, wx.ID_ANY, u"Show/Hide Right Subsystem", wx.EmptyString, wx.ITEM_NORMAL ) - self.view_menu.AppendItem( self.m_menuItem5 ) + self.view_menu.Append( self.m_menuItem5 ) self.m_menuItem6 = wx.MenuItem( self.view_menu, wx.ID_ANY, u"Show/Hide RGB", wx.EmptyString, wx.ITEM_NORMAL ) - self.view_menu.AppendItem( self.m_menuItem6 ) + self.view_menu.Append( self.m_menuItem6 ) self.m_menuItem7 = wx.MenuItem( self.view_menu, wx.ID_ANY, u"Show/Hide IR", wx.EmptyString, wx.ITEM_NORMAL ) - self.view_menu.AppendItem( self.m_menuItem7 ) + self.view_menu.Append( self.m_menuItem7 ) self.m_menuItem8 = wx.MenuItem( self.view_menu, wx.ID_ANY, u"Show/Hide UV", wx.EmptyString, wx.ITEM_NORMAL ) - self.view_menu.AppendItem( self.m_menuItem8 ) + self.view_menu.Append( self.m_menuItem8 ) self.m_menuItem9 = wx.MenuItem( self.view_menu, wx.ID_ANY, u"Toggle Saturated Pixels", wx.EmptyString, wx.ITEM_NORMAL ) - self.view_menu.AppendItem( self.m_menuItem9 ) + self.view_menu.Append( self.m_menuItem9 ) self.m_menubar1.Append( self.view_menu, u"View" ) self.calibration_menu = wx.Menu() self.m_menuItem19 = wx.MenuItem( self.calibration_menu, wx.ID_ANY, u"Edit System Configurations", wx.EmptyString, wx.ITEM_NORMAL ) - self.calibration_menu.AppendItem( self.m_menuItem19 ) + self.calibration_menu.Append( self.m_menuItem19 ) self.m_menubar1.Append( self.calibration_menu, u"Configuration" ) self.m_menu_detection = wx.Menu() self.m_menu_start_detectors = wx.MenuItem( self.m_menu_detection, wx.ID_ANY, u"Start Detectors", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu_detection.AppendItem( self.m_menu_start_detectors ) + self.m_menu_detection.Append( self.m_menu_start_detectors ) self.m_menu_stop_detectors = wx.MenuItem( self.m_menu_detection, wx.ID_ANY, u"Stop Detectors", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu_detection.AppendItem( self.m_menu_stop_detectors ) + self.m_menu_detection.Append( self.m_menu_stop_detectors ) self.m_menu_start_detector_sys0 = wx.MenuItem( self.m_menu_detection, ID_START_DETECTOR_SYS0_CENTER, u"Start Detector Sys0 (Center)", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu_detection.AppendItem( self.m_menu_start_detector_sys0 ) + self.m_menu_detection.Append( self.m_menu_start_detector_sys0 ) self.m_menu_start_detector_sys1 = wx.MenuItem( self.m_menu_detection, ID_START_DETECTOR_SYS1_LEFT, u"Start Detector Sys1 (Left)", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu_detection.AppendItem( self.m_menu_start_detector_sys1 ) + self.m_menu_detection.Append( self.m_menu_start_detector_sys1 ) self.m_menu_start_detector_sys2 = wx.MenuItem( self.m_menu_detection, ID_START_DETECTOR_SYS2_RIGHT, u"Start Detector Sys2 (Right)", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu_detection.AppendItem( self.m_menu_start_detector_sys2 ) + self.m_menu_detection.Append( self.m_menu_start_detector_sys2 ) self.m_menu_stop_detector_sys0 = wx.MenuItem( self.m_menu_detection, ID_STOP_DETECTOR_SYS0_CENTER, u"Stop Detector Sys0 (Center)", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu_detection.AppendItem( self.m_menu_stop_detector_sys0 ) + self.m_menu_detection.Append( self.m_menu_stop_detector_sys0 ) self.m_menu_stop_detector_sys1 = wx.MenuItem( self.m_menu_detection, ID_STOP_DETECTOR_SYS1_LEFT, u"Stop Detector Sys1 (Left)", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu_detection.AppendItem( self.m_menu_stop_detector_sys1 ) + self.m_menu_detection.Append( self.m_menu_stop_detector_sys1 ) self.m_menu_stop_detector_sys2 = wx.MenuItem( self.m_menu_detection, ID_STOP_DETECTOR_SYS2_RIGHT, u"Stop Detector Sys2 (Right)", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu_detection.AppendItem( self.m_menu_stop_detector_sys2 ) + self.m_menu_detection.Append( self.m_menu_stop_detector_sys2 ) self.m_menubar1.Append( self.m_menu_detection, u"Detection" ) self.m_menu81 = wx.Menu() self.m_menuItem24 = wx.MenuItem( self.m_menu81, wx.ID_ANY, u"System Control Panel", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu81.AppendItem( self.m_menuItem24 ) + self.m_menu81.Append( self.m_menuItem24 ) self.m_menubar1.Append( self.m_menu81, u"System-Control" ) self.m_menu8 = wx.Menu() self.m_menuItem281 = wx.MenuItem( self.m_menu8, wx.ID_ANY, u"Create Flight Summary", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu8.AppendItem( self.m_menuItem281 ) + self.m_menu8.Append( self.m_menuItem281 ) - self.m_menu_fin_tune_tracking = wx.MenuItem( self.m_menu8, wx._ID_ANY, u"Fine Tune Tracking", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu8.AppendItem( self.m_menu_fin_tune_tracking ) + self.m_menu_fin_tune_tracking = wx.MenuItem( self.m_menu8, ID_MENU_FIN_TUNE_TRACKING, u"Fine Tune Tracking", wx.EmptyString, wx.ITEM_NORMAL ) + self.m_menu8.Append( self.m_menu_fin_tune_tracking ) self.m_menu_detection_summary = wx.MenuItem( self.m_menu8, wx.ID_ANY, u"Detection Summary", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu8.AppendItem( self.m_menu_detection_summary ) + self.m_menu8.Append( self.m_menu_detection_summary ) self.view_queue = wx.MenuItem( self.m_menu8, wx.ID_ANY, u"View Queue", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu8.AppendItem( self.view_queue ) + self.m_menu8.Append( self.view_queue ) self.clear_queue = wx.MenuItem( self.m_menu8, wx.ID_ANY, u"Clear Queue", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu8.AppendItem( self.clear_queue ) + self.m_menu8.Append( self.clear_queue ) self.cancel_running_jobs = wx.MenuItem( self.m_menu8, wx.ID_ANY, u"Cancel Running Jobs", wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu8.AppendItem( self.cancel_running_jobs ) + self.m_menu8.Append( self.cancel_running_jobs ) self.m_menubar1.Append( self.m_menu8, u"Post-Flight Processing" ) self.menu_help = wx.Menu() self.m_menuItem131 = wx.MenuItem( self.menu_help, wx.ID_ANY, u"Hot Keys", wx.EmptyString, wx.ITEM_NORMAL ) - self.menu_help.AppendItem( self.m_menuItem131 ) + self.menu_help.Append( self.m_menuItem131 ) self.menu_item_about = wx.MenuItem( self.menu_help, wx.ID_ANY, u"About", wx.EmptyString, wx.ITEM_NORMAL ) - self.menu_help.AppendItem( self.menu_item_about ) + self.menu_help.Append( self.menu_item_about ) self.m_menubar1.Append( self.menu_help, u"Help" ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py index 9e5904c..4c48920 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py @@ -19,8 +19,8 @@ class MainFrame ( wx.Frame ): def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"System Configuration Editor", pos = wx.DefaultPosition, size = wx.Size( 994,969 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) - self.SetSizeHintsSz( wx.Size( 400,400 ), wx.DefaultSize ) - self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) ) + self.SetSizeHints( wx.Size( 400,400 ), wx.DefaultSize ) + self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) self.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOWTEXT ) ) main_size = wx.BoxSizer( wx.VERTICAL ) @@ -30,7 +30,7 @@ def __init__( self, parent ): self.m_staticText34 = wx.StaticText( self.m_panel2, wx.ID_ANY, u"System Configuration", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText34.Wrap( -1 ) - self.m_staticText34.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText34.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer22.Add( self.m_staticText34, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -38,7 +38,7 @@ def __init__( self, parent ): self.m_staticText6 = wx.StaticText( self.m_panel2, wx.ID_ANY, u"Select\nConfiguration", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) self.m_staticText6.Wrap( -1 ) - self.m_staticText6.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText6.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer9.Add( self.m_staticText6, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -92,7 +92,7 @@ def __init__( self, parent ): self.m_staticText3412 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"System Configuration Name", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText3412.Wrap( -1 ) - self.m_staticText3412.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3412.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer102.Add( self.m_staticText3412, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -109,7 +109,7 @@ def __init__( self, parent ): self.m_staticText341 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Left-View System", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText341.Wrap( -1 ) - self.m_staticText341.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText341.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer10.Add( self.m_staticText341, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -120,7 +120,7 @@ def __init__( self, parent ): self.m_staticText33 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Left RGB .yaml", wx.DefaultPosition, wx.Size( 190,-1 ), wx.ALIGN_CENTRE ) self.m_staticText33.Wrap( -1 ) - self.m_staticText33.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText33.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer45.Add( self.m_staticText33, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -140,7 +140,7 @@ def __init__( self, parent ): self.m_staticText332 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Left IR .yaml", wx.DefaultPosition, wx.Size( 190,-1 ), wx.ALIGN_CENTRE ) self.m_staticText332.Wrap( -1 ) - self.m_staticText332.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText332.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer452.Add( self.m_staticText332, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -160,7 +160,7 @@ def __init__( self, parent ): self.m_staticText331 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Left UV .yaml", wx.DefaultPosition, wx.Size( 190,-1 ), wx.ALIGN_CENTRE ) self.m_staticText331.Wrap( -1 ) - self.m_staticText331.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText331.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer451.Add( self.m_staticText331, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -180,7 +180,7 @@ def __init__( self, parent ): self.m_staticText3311 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Detection .pipe", wx.DefaultPosition, wx.Size( 190,-1 ), wx.ALIGN_CENTRE ) self.m_staticText3311.Wrap( -1 ) - self.m_staticText3311.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3311.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4511.Add( self.m_staticText3311, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -203,7 +203,7 @@ def __init__( self, parent ): self.m_staticText3411 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Center-View System", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText3411.Wrap( -1 ) - self.m_staticText3411.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3411.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer101.Add( self.m_staticText3411, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -214,7 +214,7 @@ def __init__( self, parent ): self.m_staticText3321 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Center RGB.yaml", wx.DefaultPosition, wx.Size( 190,-1 ), wx.ALIGN_CENTRE ) self.m_staticText3321.Wrap( -1 ) - self.m_staticText3321.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3321.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4521.Add( self.m_staticText3321, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -234,7 +234,7 @@ def __init__( self, parent ): self.m_staticText3322 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Center IR .yaml", wx.DefaultPosition, wx.Size( 190,-1 ), wx.ALIGN_CENTRE ) self.m_staticText3322.Wrap( -1 ) - self.m_staticText3322.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3322.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4522.Add( self.m_staticText3322, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -254,7 +254,7 @@ def __init__( self, parent ): self.m_staticText3323 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Center UV .yaml", wx.DefaultPosition, wx.Size( 190,-1 ), wx.ALIGN_CENTRE ) self.m_staticText3323.Wrap( -1 ) - self.m_staticText3323.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3323.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4523.Add( self.m_staticText3323, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -274,7 +274,7 @@ def __init__( self, parent ): self.m_staticText33111 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Detection .pipe", wx.DefaultPosition, wx.Size( 190,-1 ), wx.ALIGN_CENTRE ) self.m_staticText33111.Wrap( -1 ) - self.m_staticText33111.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText33111.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer45111.Add( self.m_staticText33111, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -297,7 +297,7 @@ def __init__( self, parent ): self.m_staticText34111 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Right-View System", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText34111.Wrap( -1 ) - self.m_staticText34111.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText34111.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer1011.Add( self.m_staticText34111, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -308,7 +308,7 @@ def __init__( self, parent ): self.m_staticText3324 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Right RGB .yaml", wx.DefaultPosition, wx.Size( 190,-1 ), wx.ALIGN_CENTRE ) self.m_staticText3324.Wrap( -1 ) - self.m_staticText3324.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3324.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4524.Add( self.m_staticText3324, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -328,7 +328,7 @@ def __init__( self, parent ): self.m_staticText3325 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Right IR .yaml", wx.DefaultPosition, wx.Size( 190,-1 ), wx.ALIGN_CENTRE ) self.m_staticText3325.Wrap( -1 ) - self.m_staticText3325.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3325.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4525.Add( self.m_staticText3325, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -348,7 +348,7 @@ def __init__( self, parent ): self.m_staticText3326 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Right UV .yaml", wx.DefaultPosition, wx.Size( 190,-1 ), wx.ALIGN_CENTRE ) self.m_staticText3326.Wrap( -1 ) - self.m_staticText3326.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3326.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4526.Add( self.m_staticText3326, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -368,7 +368,7 @@ def __init__( self, parent ): self.m_staticText33112 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Detection .pipe", wx.DefaultPosition, wx.Size( 190,-1 ), wx.ALIGN_CENTRE ) self.m_staticText33112.Wrap( -1 ) - self.m_staticText33112.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText33112.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer45112.Add( self.m_staticText33112, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -391,12 +391,12 @@ def __init__( self, parent ): self.m_staticText334 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Configuration\nDescription", wx.DefaultPosition, wx.Size( -1,-1 ), wx.ALIGN_CENTRE ) self.m_staticText334.Wrap( -1 ) - self.m_staticText334.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText334.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer454.Add( self.m_staticText334, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) self.configuration_notes_txt_ctrl = wx.TextCtrl( self.m_panel33, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE ) - self.configuration_notes_txt_ctrl.SetFont( wx.Font( 14, 70, 90, 90, False, wx.EmptyString ) ) + self.configuration_notes_txt_ctrl.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) bSizer454.Add( self.configuration_notes_txt_ctrl, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_collection_mode.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_collection_mode.py index 7b437e6..971c78b 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_collection_mode.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_collection_mode.py @@ -19,8 +19,8 @@ class MainFrame ( wx.Frame ): def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Collection Mode", pos = wx.DefaultPosition, size = wx.Size( 517,350 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) - self.SetSizeHintsSz( wx.Size( -1,-1 ), wx.DefaultSize ) - self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) ) + self.SetSizeHints( wx.Size( -1,-1 ), wx.DefaultSize ) + self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) self.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOWTEXT ) ) main_size = wx.BoxSizer( wx.HORIZONTAL ) @@ -30,7 +30,7 @@ def __init__( self, parent ): self.m_staticText34 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Set Collection Mode", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText34.Wrap( -1 ) - self.m_staticText34.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText34.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer44.Add( self.m_staticText34, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -40,7 +40,7 @@ def __init__( self, parent ): self.m_staticText3 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Collection Mode:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText3.Wrap( -1 ) - self.m_staticText3.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer5.Add( self.m_staticText3, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -57,7 +57,7 @@ def __init__( self, parent ): self.m_staticText41 = wx.StaticText( self.percent_panel, wx.ID_ANY, u"Overlap (percent)", wx.DefaultPosition, wx.Size( -1,-1 ), 0 ) self.m_staticText41.Wrap( -1 ) - self.m_staticText41.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText41.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer61.Add( self.m_staticText41, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -75,7 +75,7 @@ def __init__( self, parent ): self.m_staticText4 = wx.StaticText( self.rate_panel, wx.ID_ANY, u"Rate (fps)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText4.Wrap( -1 ) - self.m_staticText4.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText4.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer6.Add( self.m_staticText4, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_effort_metadata.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_effort_metadata.py index 0cff192..4a3b94e 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_effort_metadata.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_effort_metadata.py @@ -19,8 +19,8 @@ class MainFrame ( wx.Frame ): def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Effort Metadata Entry", pos = wx.DefaultPosition, size = wx.Size( 753,473 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) - self.SetSizeHintsSz( wx.Size( 400,400 ), wx.DefaultSize ) - self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) ) + self.SetSizeHints( wx.Size( 400,400 ), wx.DefaultSize ) + self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) self.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOWTEXT ) ) main_size = wx.BoxSizer( wx.HORIZONTAL ) @@ -30,7 +30,7 @@ def __init__( self, parent ): self.m_staticText34 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Collection Effort Metadata", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText34.Wrap( -1 ) - self.m_staticText34.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText34.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer44.Add( self.m_staticText34, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -46,12 +46,12 @@ def __init__( self, parent ): self.m_staticText33 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Effort Name", wx.DefaultPosition, wx.Size( 180,-1 ), wx.ALIGN_CENTRE ) self.m_staticText33.Wrap( -1 ) - self.m_staticText33.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText33.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer45.Add( self.m_staticText33, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) self.effort_nickname_textCtrl = wx.TextCtrl( self.m_panel33, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.effort_nickname_textCtrl.SetFont( wx.Font( 14, 70, 90, 90, False, wx.EmptyString ) ) + self.effort_nickname_textCtrl.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) bSizer45.Add( self.effort_nickname_textCtrl, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -62,12 +62,12 @@ def __init__( self, parent ): self.m_staticText331 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Project Name", wx.DefaultPosition, wx.Size( 180,-1 ), wx.ALIGN_CENTRE ) self.m_staticText331.Wrap( -1 ) - self.m_staticText331.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText331.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer451.Add( self.m_staticText331, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) self.project_name_textCtrl = wx.TextCtrl( self.m_panel33, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.project_name_textCtrl.SetFont( wx.Font( 14, 70, 90, 90, False, wx.EmptyString ) ) + self.project_name_textCtrl.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) bSizer451.Add( self.project_name_textCtrl, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -78,12 +78,12 @@ def __init__( self, parent ): self.m_staticText3321 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Aircraft", wx.DefaultPosition, wx.Size( 180,-1 ), wx.ALIGN_CENTRE ) self.m_staticText3321.Wrap( -1 ) - self.m_staticText3321.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3321.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4521.Add( self.m_staticText3321, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) self.aircraft_textCtrl = wx.TextCtrl( self.m_panel33, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.aircraft_textCtrl.SetFont( wx.Font( 14, 70, 90, 90, False, wx.EmptyString ) ) + self.aircraft_textCtrl.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) bSizer4521.Add( self.aircraft_textCtrl, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -94,12 +94,12 @@ def __init__( self, parent ): self.m_staticText334 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Effort\nDescription", wx.DefaultPosition, wx.Size( 180,-1 ), wx.ALIGN_CENTRE ) self.m_staticText334.Wrap( -1 ) - self.m_staticText334.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText334.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer454.Add( self.m_staticText334, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) self.field_notes_textCtrl = wx.TextCtrl( self.m_panel33, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE ) - self.field_notes_textCtrl.SetFont( wx.Font( 14, 70, 90, 90, False, wx.EmptyString ) ) + self.field_notes_textCtrl.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) bSizer454.Add( self.field_notes_textCtrl, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5 ) @@ -110,34 +110,34 @@ def __init__( self, parent ): self.m_staticText3341 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Image-Process\nWait Time (s)", wx.DefaultPosition, wx.Size( 180,-1 ), wx.ALIGN_CENTRE ) self.m_staticText3341.Wrap( -1 ) - self.m_staticText3341.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3341.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4541.Add( self.m_staticText3341, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) self.wait_time_sec = wx.TextCtrl( self.m_panel33, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.wait_time_sec.SetFont( wx.Font( 14, 70, 90, 90, False, wx.EmptyString ) ) + self.wait_time_sec.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) bSizer4541.Add( self.wait_time_sec, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) self.m_staticText33411 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Delete Old\nImages (s)", wx.DefaultPosition, wx.Size( 120,-1 ), wx.ALIGN_CENTRE ) self.m_staticText33411.Wrap( -1 ) - self.m_staticText33411.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText33411.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4541.Add( self.m_staticText33411, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) self.delete_old_images_sec = wx.TextCtrl( self.m_panel33, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.delete_old_images_sec.SetFont( wx.Font( 14, 70, 90, 90, False, wx.EmptyString ) ) + self.delete_old_images_sec.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) bSizer4541.Add( self.delete_old_images_sec, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) self.m_staticText33412 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Save every\nNth Image", wx.DefaultPosition, wx.Size( 140,-1 ), wx.ALIGN_CENTRE ) self.m_staticText33412.Wrap( -1 ) - self.m_staticText33412.SetFont( wx.Font( 14, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText33412.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer4541.Add( self.m_staticText33412, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) self.save_every_x_image = wx.TextCtrl( self.m_panel33, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.save_every_x_image.SetFont( wx.Font( 14, 70, 90, 90, False, wx.EmptyString ) ) + self.save_every_x_image.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) bSizer4541.Add( self.save_every_x_image, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_event_log_note.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_event_log_note.py index 2f7d582..c22e048 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_event_log_note.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_event_log_note.py @@ -19,8 +19,8 @@ class MainFrame ( wx.Frame ): def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Event Log Note", pos = wx.DefaultPosition, size = wx.Size( 700,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) - self.SetSizeHintsSz( wx.Size( 400,300 ), wx.DefaultSize ) - self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) ) + self.SetSizeHints( wx.Size( 400,300 ), wx.DefaultSize ) + self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) self.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOWTEXT ) ) main_size = wx.BoxSizer( wx.HORIZONTAL ) @@ -30,7 +30,7 @@ def __init__( self, parent ): self.m_staticText34 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Add Note to Event Log", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText34.Wrap( -1 ) - self.m_staticText34.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText34.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer44.Add( self.m_staticText34, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -44,7 +44,7 @@ def __init__( self, parent ): self.m_staticText3 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Event Type:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText3.Wrap( -1 ) - self.m_staticText3.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer5.Add( self.m_staticText3, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) @@ -57,7 +57,7 @@ def __init__( self, parent ): bSizer454.Add( bSizer5, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) self.note_textCtrl = wx.TextCtrl( self.m_panel33, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE ) - self.note_textCtrl.SetFont( wx.Font( 14, 70, 90, 90, False, wx.EmptyString ) ) + self.note_textCtrl.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) bSizer454.Add( self.note_textCtrl, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_hot_key_list.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_hot_key_list.py index ba57a0c..2b4913e 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_hot_key_list.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_hot_key_list.py @@ -19,8 +19,8 @@ class MainFrame ( wx.Frame ): def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Hot Key List", pos = wx.DefaultPosition, size = wx.Size( 400,377 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) - self.SetSizeHintsSz( wx.Size( 400,450 ), wx.DefaultSize ) - self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) ) + self.SetSizeHints( wx.Size( 400,450 ), wx.DefaultSize ) + self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) self.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOWTEXT ) ) main_size = wx.BoxSizer( wx.HORIZONTAL ) @@ -30,7 +30,7 @@ def __init__( self, parent ): self.m_staticText34 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Hot Keys", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText34.Wrap( -1 ) - self.m_staticText34.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText34.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer44.Add( self.m_staticText34, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -42,7 +42,7 @@ def __init__( self, parent ): self.m_staticText4 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"ctrl+h", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText4.Wrap( -1 ) - self.m_staticText4.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText4.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gbSizer1.Add( self.m_staticText4, wx.GBPosition( 0, 0 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -52,7 +52,7 @@ def __init__( self, parent ): self.m_staticText41 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"ctrl+e", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText41.Wrap( -1 ) - self.m_staticText41.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText41.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gbSizer1.Add( self.m_staticText41, wx.GBPosition( 1, 0 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -62,43 +62,43 @@ def __init__( self, parent ): self.m_staticText42 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"ctrl+s", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText42.Wrap( -1 ) - self.m_staticText42.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText42.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gbSizer1.Add( self.m_staticText42, wx.GBPosition( 2, 0 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) self.m_staticText422 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"ctrl+d", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText422.Wrap( -1 ) - self.m_staticText422.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText422.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gbSizer1.Add( self.m_staticText422, wx.GBPosition( 3, 0 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) self.m_staticText4221 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"ctrl+f", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText4221.Wrap( -1 ) - self.m_staticText4221.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText4221.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gbSizer1.Add( self.m_staticText4221, wx.GBPosition( 4, 0 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) self.m_staticText42211 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"ctrl+o", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText42211.Wrap( -1 ) - self.m_staticText42211.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText42211.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gbSizer1.Add( self.m_staticText42211, wx.GBPosition( 5, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) - self.m_staticText422111 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"ctrl+p", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText422111 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"ctrl+p", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText422111.Wrap( -1 ) - self.m_staticText422111.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText422111.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gbSizer1.Add( self.m_staticText422111, wx.GBPosition( 6, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) self.m_staticText421111 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"ctrl+i", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText421111.Wrap( -1 ) - self.m_staticText421111.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText421111.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - gbSizer1.Add( self.m_staticText421111, wx.GBPosition( 7, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) + gbSizer1.Add( self.m_staticText421111, wx.GBPosition( 7, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) self.m_staticText42111 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"ctrl+k", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText42111.Wrap( -1 ) - self.m_staticText42111.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText42111.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gbSizer1.Add( self.m_staticText42111, wx.GBPosition( 8, 0 ), wx.GBSpan( 1, 1 ), wx.ALL, 5 ) @@ -132,7 +132,7 @@ def __init__( self, parent ): self.m_staticText421 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"ctrl+n", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT ) self.m_staticText421.Wrap( -1 ) - self.m_staticText421.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText421.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gbSizer1.Add( self.m_staticText421, wx.GBPosition( 9, 0 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -142,7 +142,7 @@ def __init__( self, parent ): self.m_staticText4211 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"alt+F4", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_RIGHT ) self.m_staticText4211.Wrap( -1 ) - self.m_staticText4211.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText4211.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gbSizer1.Add( self.m_staticText4211, wx.GBPosition( 10, 0 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_imagery_inspection.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_imagery_inspection.py index d0428f8..7aa4f96 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_imagery_inspection.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_imagery_inspection.py @@ -19,8 +19,8 @@ class MainFrame ( wx.Frame ): def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"System Control Panel", pos = wx.DefaultPosition, size = wx.Size( 1538,900 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) - self.SetSizeHintsSz( wx.Size( 400,400 ), wx.DefaultSize ) - self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) ) + self.SetSizeHints( wx.Size( 400,400 ), wx.DefaultSize ) + self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) self.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOWTEXT ) ) main_size = wx.BoxSizer( wx.HORIZONTAL ) @@ -32,7 +32,7 @@ def __init__( self, parent ): self.m_staticText142 = wx.StaticText( self.image_stream_panel, wx.ID_ANY, u"Image Stream", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText142.Wrap( -1 ) - self.m_staticText142.SetFont( wx.Font( 16, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText142.SetFont( wx.Font( 16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer191.Add( self.m_staticText142, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) @@ -52,7 +52,7 @@ def __init__( self, parent ): self.m_staticText1421 = wx.StaticText( self.m_panel11, wx.ID_ANY, u"Histogram", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText1421.Wrap( -1 ) - self.m_staticText1421.SetFont( wx.Font( 16, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText1421.SetFont( wx.Font( 16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer11.Add( self.m_staticText1421, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) @@ -124,7 +124,7 @@ def __init__( self, parent ): bsizer12 = wx.BoxSizer( wx.VERTICAL ) self.images_panel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.Size( -1,-1 ), wx.TAB_TRAVERSAL ) - self.images_panel.SetFont( wx.Font( 9, 70, 90, 90, False, wx.EmptyString ) ) + self.images_panel.SetFont( wx.Font( 9, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) bSizer16 = wx.BoxSizer( wx.VERTICAL ) @@ -133,7 +133,7 @@ def __init__( self, parent ): self.cueing_left_image_title3 = wx.StaticText( self.m_panel24, wx.ID_ANY, u"Click To Set Zoom Location", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_left_image_title3.Wrap( -1 ) - self.cueing_left_image_title3.SetFont( wx.Font( 16, 70, 90, 92, False, wx.EmptyString ) ) + self.cueing_left_image_title3.SetFont( wx.Font( 16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) left_bsizer.Add( self.cueing_left_image_title3, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -142,7 +142,7 @@ def __init__( self, parent ): self.status_text = wx.StaticText( self.m_panel24, wx.ID_ANY, u"Empty", wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) self.status_text.Wrap( -1 ) - self.status_text.SetFont( wx.Font( 9, 70, 90, 90, False, wx.EmptyString ) ) + self.status_text.SetFont( wx.Font( 9, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) left_bsizer.Add( self.status_text, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -157,7 +157,7 @@ def __init__( self, parent ): self.cueing_left_image_title2 = wx.StaticText( self.m_panel37, wx.ID_ANY, u"Zoomed View", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_left_image_title2.Wrap( -1 ) - self.cueing_left_image_title2.SetFont( wx.Font( 16, 70, 90, 92, False, wx.EmptyString ) ) + self.cueing_left_image_title2.SetFont( wx.Font( 16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) left_bsizer2.Add( self.cueing_left_image_title2, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_log_panel.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_log_panel.py index 4dc1f88..4453a75 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_log_panel.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_log_panel.py @@ -19,8 +19,8 @@ class MainFrame ( wx.Frame ): def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"Log Messages", pos = wx.DefaultPosition, size = wx.Size( 1500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) - self.SetSizeHintsSz( wx.Size( 400,300 ), wx.DefaultSize ) - self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) ) + self.SetSizeHints( wx.Size( 400,300 ), wx.DefaultSize ) + self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) self.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOWTEXT ) ) main_size = wx.BoxSizer( wx.HORIZONTAL ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_system_startup.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_system_startup.py index a634373..59a643e 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_system_startup.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_system_startup.py @@ -19,8 +19,8 @@ class MainFrame ( wx.Frame ): def __init__( self, parent ): wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"System Startup and Control Commands", pos = wx.DefaultPosition, size = wx.Size( 893,701 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) - self.SetSizeHintsSz( wx.Size( -1,-1 ), wx.DefaultSize ) - self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) ) + self.SetSizeHints( wx.Size( -1,-1 ), wx.DefaultSize ) + self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) self.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_WINDOWTEXT ) ) main_size = wx.BoxSizer( wx.HORIZONTAL ) @@ -37,7 +37,7 @@ def __init__( self, parent ): self.m_staticText341 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Entire System", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText341.Wrap( -1 ) - self.m_staticText341.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText341.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gSizer1.Add( self.m_staticText341, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -119,7 +119,7 @@ def __init__( self, parent ): self.m_staticText3411 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Left-View Computer (sys1)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText3411.Wrap( -1 ) - self.m_staticText3411.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText3411.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gSizer11.Add( self.m_staticText3411, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -195,7 +195,7 @@ def __init__( self, parent ): self.m_staticText34111 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Center-View Computer (sys0)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText34111.Wrap( -1 ) - self.m_staticText34111.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText34111.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gSizer111.Add( self.m_staticText34111, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -271,7 +271,7 @@ def __init__( self, parent ): self.m_staticText34112 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Right-View Computer (sys2)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText34112.Wrap( -1 ) - self.m_staticText34112.SetFont( wx.Font( 18, 70, 90, 92, False, wx.EmptyString ) ) + self.m_staticText34112.SetFont( wx.Font( 18, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) gSizer112.Add( self.m_staticText34112, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 33d7f62..88437aa 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- from __future__ import division, print_function @@ -17,8 +17,7 @@ import psutil from collections import OrderedDict from functools import partial -from six import StringIO, string_types -from six.moves import queue +import queue import requests # import redis diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui_utils.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui_utils.py index 0281654..6cd01a4 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui_utils.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui_utils.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/utils.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/utils.py index 66da0c7..15fb37e 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/utils.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/utils.py @@ -4,6 +4,7 @@ import time import json from collections import OrderedDict +from collections.abc import Iterable import rospy @@ -64,7 +65,7 @@ def omap(func, maybe_itr): """Map over optional""" if maybe_itr is None: return None - if isinstance(maybe_itr, string_types): + if isinstance(maybe_itr, str): return func(maybe_itr) elif isinstance(maybe_itr, Iterable): return map(func, maybe_itr) From d7261652f0de4e16ab0262752b142d63b8266390 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 10:08:04 -0400 Subject: [PATCH 036/139] Turn off docker compose 'base' so build order follows depends_on order --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 05e28b3..480adc4 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,9 @@ ROS_DISTRO ?= noetic +# Disable docker compose 'bake' so build order follows depends_on statements +COMPOSE_BAKE = false +export COMPOSE_BAKE + .PHONY: build core viame gui gui-noetic postflight follower leader all clean build: From fc9848745012dcd609e6d23566db7d8b26b4bf5e Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 10:17:28 -0400 Subject: [PATCH 037/139] No bake isn't listened to, switch to explicit docker compose builds --- Makefile | 24 +++++++++++++++++++----- docker-compose.yml | 14 -------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 480adc4..5158c5b 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,5 @@ ROS_DISTRO ?= noetic -# Disable docker compose 'bake' so build order follows depends_on statements -COMPOSE_BAKE = false -export COMPOSE_BAKE - .PHONY: build core viame gui gui-noetic postflight follower leader all clean build: @@ -12,16 +8,24 @@ build: ## --- individual layer targets --- core: + docker compose --profile core build core-ros + docker compose --profile core build core-deps docker compose --profile core build viame: + docker compose --profile viame build viame-base docker compose --profile viame build gui: + ROS_DISTRO=kinetic docker compose --profile gui build core-deps-kinetic + ROS_DISTRO=kinetic docker compose --profile gui build core-gui-deps ROS_DISTRO=kinetic docker compose --profile gui build gui-noetic: - docker compose --profile gui-noetic build + docker compose --profile gui-noetic build core-ros + docker compose --profile gui-noetic build core-deps + docker compose --profile gui-noetic build gui-deps-noetic + docker compose --profile gui-noetic build gui-noetic postflight: docker compose --profile pf build @@ -30,14 +34,24 @@ postflight: # Follower node: headless sensor node — core + VIAME + postproc follower: + docker compose --profile follower build core-ros + docker compose --profile follower build core-deps + docker compose --profile follower build viame-base docker compose --profile follower build # Leader node: operator workstation — Kinetic GUI + postproc leader: + ROS_DISTRO=kinetic docker compose --profile leader build core-deps-kinetic + ROS_DISTRO=kinetic docker compose --profile leader build core-gui-deps ROS_DISTRO=kinetic docker compose --profile leader build # Everything all: + docker compose --profile all build core-ros + docker compose --profile all build core-deps + docker compose --profile all build viame-base + docker compose --profile all build core-deps-kinetic + docker compose --profile all build core-gui-deps docker compose --profile all build clean: diff --git a/docker-compose.yml b/docker-compose.yml index 76b72dc..9fa708e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -49,8 +49,6 @@ services: context: . dockerfile: docker/base/core-deps.dockerfile image: "kamera/base/core-deps:${TAG_KAMERA_DEPS:-latest}" - depends_on: - - core-ros profiles: - core - follower @@ -65,8 +63,6 @@ services: image: "kitware/kamera:core" tty: true network_mode: host - depends_on: - - core-deps volumes: - "/tmp/.X11-unix:/tmp/.X11-unix" - "${PWD}/src:/root/kamera/src" @@ -117,8 +113,6 @@ services: tty: true network_mode: host command: ["bash"] - depends_on: - - viame-base profiles: - viame - follower @@ -142,8 +136,6 @@ services: context: . dockerfile: docker/base/gui-deps.dockerfile image: "kamera/base/core-gui-deps:${TAG_KAMERA_GUI_DEPS:-latest}" - depends_on: - - core-deps-kinetic profiles: - gui - leader @@ -155,8 +147,6 @@ services: context: . dockerfile: docker/gui.dockerfile image: "kitware/kamera:gui" - depends_on: - - core-gui-deps profiles: - gui - leader @@ -169,8 +159,6 @@ services: context: . dockerfile: docker/base/gui-deps-noetic.dockerfile image: "kamera/base/gui-deps-noetic:${TAG_KAMERA_GUI_DEPS:-latest}" - depends_on: - - core-deps profiles: - gui-noetic @@ -182,8 +170,6 @@ services: args: GUI_DEPS_IMAGE: "kamera/base/gui-deps-noetic:${TAG_KAMERA_GUI_DEPS:-latest}" image: "kitware/kamera:gui-noetic" - depends_on: - - gui-deps-noetic profiles: - gui-noetic From 19b0364314c062fbe671775a585c26e24e454652 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 10:28:52 -0400 Subject: [PATCH 038/139] Move GUI supporting packages from py2 -> py3 syntax --- .../ins_driver/gsof_utils/gsof_utils/avx_time.py | 2 +- .../ins_driver/gsof_utils/gsof_utils/parsers.py | 2 +- .../gsof_utils/gsof_utils/test_samples.py | 2 +- src/core/ins_driver/gsof_utils/setup.py | 2 +- src/core/ins_driver/package.xml | 2 +- src/core/ins_driver/scripts/ins_socket_driver | 2 +- src/core/ins_driver/scripts/ins_spoof_driver | 2 +- src/core/ins_driver/scripts/nmea_serial_driver | 2 +- src/core/ins_driver/scripts/nmea_socket_driver | 2 +- src/core/ins_driver/scripts/nmea_topic_driver | 2 +- .../ins_driver/scripts/nmea_topic_serial_reader | 2 +- src/core/ins_driver/scripts/spoof_events.py | 2 +- src/core/ins_driver/setup.py | 4 ++-- .../ins_driver/src/libnmea_navsat_driver/driver.py | 14 ++++++-------- .../src/libnmea_navsat_driver/gps_leap_seconds.py | 2 +- .../ins_driver/src/libnmea_navsat_driver/gsof.py | 5 ++--- .../ins_driver/src/libnmea_navsat_driver/parser.py | 5 +---- .../src/libnmea_navsat_driver/stream_archive.py | 2 +- src/kitware-ros-pkg/wxpython_gui/CMakeLists.txt | 11 ++++------- src/kitware-ros-pkg/wxpython_gui/package.xml | 4 ++-- src/kitware-ros-pkg/wxpython_gui/setup.py | 8 +++----- 21 files changed, 34 insertions(+), 45 deletions(-) diff --git a/src/core/ins_driver/gsof_utils/gsof_utils/avx_time.py b/src/core/ins_driver/gsof_utils/gsof_utils/avx_time.py index 9e9cf5e..fcb8abd 100755 --- a/src/core/ins_driver/gsof_utils/gsof_utils/avx_time.py +++ b/src/core/ins_driver/gsof_utils/gsof_utils/avx_time.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- diff --git a/src/core/ins_driver/gsof_utils/gsof_utils/parsers.py b/src/core/ins_driver/gsof_utils/gsof_utils/parsers.py index 097b941..49d1732 100644 --- a/src/core/ins_driver/gsof_utils/gsof_utils/parsers.py +++ b/src/core/ins_driver/gsof_utils/gsof_utils/parsers.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- import re diff --git a/src/core/ins_driver/gsof_utils/gsof_utils/test_samples.py b/src/core/ins_driver/gsof_utils/gsof_utils/test_samples.py index b4d5613..6cf9b38 100644 --- a/src/core/ins_driver/gsof_utils/gsof_utils/test_samples.py +++ b/src/core/ins_driver/gsof_utils/gsof_utils/test_samples.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- import datetime diff --git a/src/core/ins_driver/gsof_utils/setup.py b/src/core/ins_driver/gsof_utils/setup.py index 006fc88..6e5f309 100644 --- a/src/core/ins_driver/gsof_utils/setup.py +++ b/src/core/ins_driver/gsof_utils/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from setuptools import find_packages, setup packages = find_packages() diff --git a/src/core/ins_driver/package.xml b/src/core/ins_driver/package.xml index 9054cb2..2f8c206 100644 --- a/src/core/ins_driver/package.xml +++ b/src/core/ins_driver/package.xml @@ -19,7 +19,7 @@ catkin rospy - python-serial + python3-serial geometry_msgs nmea_msgs sensor_msgs diff --git a/src/core/ins_driver/scripts/ins_socket_driver b/src/core/ins_driver/scripts/ins_socket_driver index 768e27d..b6b6b0b 100755 --- a/src/core/ins_driver/scripts/ins_socket_driver +++ b/src/core/ins_driver/scripts/ins_socket_driver @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Software License Agreement (BSD License) diff --git a/src/core/ins_driver/scripts/ins_spoof_driver b/src/core/ins_driver/scripts/ins_spoof_driver index b3b94b4..93b75eb 100755 --- a/src/core/ins_driver/scripts/ins_spoof_driver +++ b/src/core/ins_driver/scripts/ins_spoof_driver @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Software License Agreement (BSD License) diff --git a/src/core/ins_driver/scripts/nmea_serial_driver b/src/core/ins_driver/scripts/nmea_serial_driver index fddd6bb..4d6f912 100755 --- a/src/core/ins_driver/scripts/nmea_serial_driver +++ b/src/core/ins_driver/scripts/nmea_serial_driver @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/usr/bin/env python3 # Software License Agreement (BSD License) # diff --git a/src/core/ins_driver/scripts/nmea_socket_driver b/src/core/ins_driver/scripts/nmea_socket_driver index b48d615..b01fe0c 100755 --- a/src/core/ins_driver/scripts/nmea_socket_driver +++ b/src/core/ins_driver/scripts/nmea_socket_driver @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Software License Agreement (BSD License) diff --git a/src/core/ins_driver/scripts/nmea_topic_driver b/src/core/ins_driver/scripts/nmea_topic_driver index 92cc851..580bd4d 100755 --- a/src/core/ins_driver/scripts/nmea_topic_driver +++ b/src/core/ins_driver/scripts/nmea_topic_driver @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/usr/bin/env python3 # Software License Agreement (BSD License) # diff --git a/src/core/ins_driver/scripts/nmea_topic_serial_reader b/src/core/ins_driver/scripts/nmea_topic_serial_reader index 814fe71..b7af6a9 100755 --- a/src/core/ins_driver/scripts/nmea_topic_serial_reader +++ b/src/core/ins_driver/scripts/nmea_topic_serial_reader @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/usr/bin/env python3 # Software License Agreement (BSD License) # diff --git a/src/core/ins_driver/scripts/spoof_events.py b/src/core/ins_driver/scripts/spoof_events.py index 950585c..f9ac3a7 100755 --- a/src/core/ins_driver/scripts/spoof_events.py +++ b/src/core/ins_driver/scripts/spoof_events.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 import rospy import math diff --git a/src/core/ins_driver/setup.py b/src/core/ins_driver/setup.py index 87bb2c0..0a1d458 100644 --- a/src/core/ins_driver/setup.py +++ b/src/core/ins_driver/setup.py @@ -1,10 +1,10 @@ -from distutils.core import setup +#!/usr/bin/env python3 +from setuptools import setup from catkin_pkg.python_setup import generate_distutils_setup d = generate_distutils_setup( packages=['libnmea_navsat_driver'], package_dir={'': 'src'}, - install_requires=[], ) setup(**d) diff --git a/src/core/ins_driver/src/libnmea_navsat_driver/driver.py b/src/core/ins_driver/src/libnmea_navsat_driver/driver.py index cfb5f4a..46b4b04 100644 --- a/src/core/ins_driver/src/libnmea_navsat_driver/driver.py +++ b/src/core/ins_driver/src/libnmea_navsat_driver/driver.py @@ -43,8 +43,6 @@ from libnmea_navsat_driver.checksum_utils import check_nmea_checksum import libnmea_navsat_driver.parser from . import nmea_class -from vprint import aprint - class PashrPub(nmea_class.NMEA): def __init__(self, name, queue_size=1): @@ -208,19 +206,19 @@ def add_sentence(self, nmea_string, frame_id=None, timestamp=None): if not check_nmea_checksum(nmea_string): rospy.logwarn("Received a sentence with an invalid checksum. " + "Sentence was: %s" % repr(nmea_string)) - aprint('invalid checksum') + print('invalid checksum') return False parsed_sentence = libnmea_navsat_driver.parser.parse_nmea_sentence(nmea_string) if not parsed_sentence: rospy.logdebug("Failed to parse NMEA sentence. Sentence was: %s" % nmea_string) - aprint('failed to parse: {}'.format(nmea_string)) + print('failed to parse: {}'.format(nmea_string)) return False if frame_id is None: frame_id = self.get_frame_id() - # aprint('\n' + str(parsed_sentence)) + # print('\n' + str(parsed_sentence)) if timestamp: current_time = timestamp @@ -241,12 +239,12 @@ def add_sentence(self, nmea_string, frame_id=None, timestamp=None): # GGA with no RMC if not self.use_RMC and 'GGA' in parsed_sentence: - aprint('Branch 1') + print('Branch 1') current_fix.position_covariance_type = \ NavSatFix.COVARIANCE_TYPE_APPROXIMATED data = parsed_sentence['GGA'] - aprint(data) + print(data) fix_type = data['fix_type'] if not (fix_type in self.gps_qualities): fix_type = -1 @@ -272,7 +270,7 @@ def add_sentence(self, nmea_string, frame_id=None, timestamp=None): elif 'RMC' in parsed_sentence: - aprint('Branch 2') + print('Branch 2') data = parsed_sentence['RMC'] # Only publish a fix from RMC if the use_RMC flag is set. diff --git a/src/core/ins_driver/src/libnmea_navsat_driver/gps_leap_seconds.py b/src/core/ins_driver/src/libnmea_navsat_driver/gps_leap_seconds.py index d1da549..2b95ca5 100644 --- a/src/core/ins_driver/src/libnmea_navsat_driver/gps_leap_seconds.py +++ b/src/core/ins_driver/src/libnmea_navsat_driver/gps_leap_seconds.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # This file is automatically edited at line 5 # # VVVVVV this line is modified automatically diff --git a/src/core/ins_driver/src/libnmea_navsat_driver/gsof.py b/src/core/ins_driver/src/libnmea_navsat_driver/gsof.py index 8dd370f..4ff9262 100644 --- a/src/core/ins_driver/src/libnmea_navsat_driver/gsof.py +++ b/src/core/ins_driver/src/libnmea_navsat_driver/gsof.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- import struct import datetime @@ -569,13 +569,12 @@ def separate_nmea(buf): def run_tests(): from pprint import pprint - from vprint.base256 import b256encode nmea_list, data = separate_nmea(TEST_GSOF_PACKET) dispatch = parse_gsof(data) pprint(nmea_list) print(len(data)) - print(b256encode(data)) + print(data.hex()) pprint(dispatch.msg) diff --git a/src/core/ins_driver/src/libnmea_navsat_driver/parser.py b/src/core/ins_driver/src/libnmea_navsat_driver/parser.py index 4292fe5..c23f133 100644 --- a/src/core/ins_driver/src/libnmea_navsat_driver/parser.py +++ b/src/core/ins_driver/src/libnmea_navsat_driver/parser.py @@ -38,10 +38,7 @@ import logging # for doctests and debugging from pprint import pprint -from vprint import aprint -from vprint.loggers import get_verbose_logger -# logger = logging.getLogger('rosout') -logger = get_verbose_logger('rosout2', verbose=True) +logger = logging.getLogger('rosout2') def safe_float(field): diff --git a/src/core/ins_driver/src/libnmea_navsat_driver/stream_archive.py b/src/core/ins_driver/src/libnmea_navsat_driver/stream_archive.py index 3f8e5fa..8cc171b 100644 --- a/src/core/ins_driver/src/libnmea_navsat_driver/stream_archive.py +++ b/src/core/ins_driver/src/libnmea_navsat_driver/stream_archive.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os diff --git a/src/kitware-ros-pkg/wxpython_gui/CMakeLists.txt b/src/kitware-ros-pkg/wxpython_gui/CMakeLists.txt index 2d8a527..8e3a949 100644 --- a/src/kitware-ros-pkg/wxpython_gui/CMakeLists.txt +++ b/src/kitware-ros-pkg/wxpython_gui/CMakeLists.txt @@ -161,13 +161,10 @@ include_directories( ## Mark executable scripts (Python etc.) for installation ## in contrast to setup.py, you can choose the destination - install(PROGRAMS - scripts/publish_test_image.py - scripts/detection_generator_node.py - scripts/detection_viewer_node.py - scripts/focus_gui_node.py - DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} - ) +install(PROGRAMS + scripts/system_control_panel_node.py + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) ## Mark executables and/or libraries for installation # install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node diff --git a/src/kitware-ros-pkg/wxpython_gui/package.xml b/src/kitware-ros-pkg/wxpython_gui/package.xml index f25d3bc..23d7550 100644 --- a/src/kitware-ros-pkg/wxpython_gui/package.xml +++ b/src/kitware-ros-pkg/wxpython_gui/package.xml @@ -49,8 +49,8 @@ cv_bridge image_view genpy - python-numpy - python-wxgtk2.8 + python3-numpy + python3-wxgtk4.0 sensor_models roskv diff --git a/src/kitware-ros-pkg/wxpython_gui/setup.py b/src/kitware-ros-pkg/wxpython_gui/setup.py index 54db6e5..188a922 100644 --- a/src/kitware-ros-pkg/wxpython_gui/setup.py +++ b/src/kitware-ros-pkg/wxpython_gui/setup.py @@ -1,12 +1,10 @@ #!/usr/bin/env python3 -from distutils.core import setup +from setuptools import setup from catkin_pkg.python_setup import generate_distutils_setup -# this function uses information from package.xml to populate dict -requires = ["PyGeodesy", "shapely", "pyshp", "wxPython"] - d = generate_distutils_setup( - packages=["wxpython_gui"], package_dir={"": "src"}, install_requires=[], + packages=["wxpython_gui"], + package_dir={"": "src"}, ) setup(**d) From 3adfb4909c02c22dc47ec8fb16aacdc62e360454 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 10:31:19 -0400 Subject: [PATCH 039/139] Remove some old scripts --- src/run_scripts/run_kamera_from_bag.sh | 89 -------------- src/run_scripts/run_system_simulation.sh | 112 ------------------ .../setup/get_rid_of_transport_plugins.sh | 15 --- 3 files changed, 216 deletions(-) delete mode 100755 src/run_scripts/run_kamera_from_bag.sh delete mode 100755 src/run_scripts/run_system_simulation.sh delete mode 100755 src/run_scripts/setup/get_rid_of_transport_plugins.sh diff --git a/src/run_scripts/run_kamera_from_bag.sh b/src/run_scripts/run_kamera_from_bag.sh deleted file mode 100755 index dc8efa6..0000000 --- a/src/run_scripts/run_kamera_from_bag.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/bash - -#WSDIR=$(catkin locate) -SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" -WSDIR="$SCRIPTDIR/../../" - -TMUX_SESSION=run_system_from_bag - -# Specify the bag to replay. -BAGFNAME='/mnt/2019-02-12-03-48-12.bag' - -tmux kill-session -t $TMUX_SESSION - -# Start tmux session -tmux new-session -d -s $TMUX_SESSION -#tmux source ./.tmux.conf - -# Roscore -tmux select-window -t $TMUX_SESSION:0 -tmux rename-window -t $TMUX_SESSION:0 'Roscore' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "docker compose up -d kamera && docker exec -it kamera bash" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -tmux send-keys "roscore" C-m - -sleep 3 - -# Image driver -tmux new-window -t $TMUX_SESSION:1 -n 'Rosbag' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -tmux send-keys "rosbag play ${BAGFNAME} --l" C-m - -# Image Nexus -tmux new-window -t $TMUX_SESSION:2 -n 'Image Nexus' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -tmux send-keys "catkin build nexus" C-m -tmux send-keys "data_mount_point=/media/mattb/datapartition/kamera/testing" C-m -tmux send-keys "roslaunch --wait nexus nexus.launch max_wait:=1" C-m - -# Debayer -tmux new-window -t $TMUX_SESSION:3 -n 'DeBayer' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -tmux send-keys "catkin build color_processing" C-m -tmux send-keys "roslaunch --wait color_processing debayer.launch" C-m - -# INS -tmux new-window -t $TMUX_SESSION:4 -n 'INS Sim' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -tmux send-keys "catkin build sensor_simulator" C-m -tmux send-keys "source activate_ros.bash" C-m -tmux send-keys "roslaunch sensor_simulator simulate_ins.launch \ - lat:=67.32755634 lon:=-166.53534026 height:=300" C-m - -# GUI -tmux new-window -t $TMUX_SESSION:5 -n 'GUI' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "source run_gui.sh" C-m -tmux send-keys "roslaunch --wait wxpython_gui system_control_panel.launch" C-m - -# ImageView -tmux new-window -t $TMUX_SESSION:6 -n 'ImageViewServer' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -tmux send-keys "roslaunch --wait wxpython_gui image_view_server.launch" C-m - -# Test -tmux new-window -t $TMUX_SESSION:7 -n 'Test' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -tmux select-window -t $TMUX_SESSION:6 -# Bring up the tmux session -tmux attach -t $TMUX_SESSION diff --git a/src/run_scripts/run_system_simulation.sh b/src/run_scripts/run_system_simulation.sh deleted file mode 100755 index 56cc321..0000000 --- a/src/run_scripts/run_system_simulation.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/bash - -#WSDIR=$(catkin locate) -SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" -WSDIR="$SCRIPTDIR/../../" -#SCRIPTDIR=$(catkin locate)/src/run_scripts/ee3/sentry - -TMUX_SESSION=run_system_sim -DOCKER_NAME=roskamera - -xhost +local:root - -# Start tmux session -tmux new-session -d -s $TMUX_SESSION -tmux source ./.tmux.conf - -# Roscore -tmux select-window -t $TMUX_SESSION:0 -tmux rename-window -t $TMUX_SESSION:0 'Roscore' -#tmux send-keys "source ${SCRIPTDIR}/nuvo5k/000_core.sh" C-m -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make name=${DOCKER_NAME} rungui" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -#tmux send-keys "source devel/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -tmux send-keys "roscore" C-m - -sleep 5 - -# Image Simulator -tmux new-window -t $TMUX_SESSION:1 -n 'Image Sim' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make name=${DOCKER_NAME} rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -#tmux send-keys "source devel/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -sleep 1 -tmux send-keys "roslaunch --wait sensor_simulator simulate_cameras_one_sys.launch frame_rate:=1" C-m - -sleep 1 - -# Image Nexus -tmux new-window -t $TMUX_SESSION:2 -n 'Image Nexus' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make name=${DOCKER_NAME} rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -#tmux send-keys "source devel/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -sleep 1 -tmux send-keys "roslaunch --wait image_nexus nexus.launch max_wait:=1" C-m - -sleep 1 - -# Debayer -tmux new-window -t $TMUX_SESSION:3 -n 'DeBayer' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make name=${DOCKER_NAME} rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -#tmux send-keys "source devel/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -sleep 1 -tmux send-keys "roslaunch --wait color_processing debayer.launch" C-m - -sleep 1 - -# INS -tmux new-window -t $TMUX_SESSION:4 -n 'INS Sim' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make name=${DOCKER_NAME} rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -#tmux send-keys "source devel/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -sleep 1 -tmux send-keys "roslaunch sensor_simulator simulate_ins.launch" C-m - -sleep 1 - -# GUI -tmux new-window -t $TMUX_SESSION:5 -n 'GUI' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make name=${DOCKER_NAME} rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -#tmux send-keys "source devel/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -sleep 1 -tmux send-keys "roslaunch --wait wxpython_gui system_control_panel.launch" C-m - -sleep 1 - -# ImageView -tmux new-window -t $TMUX_SESSION:6 -n 'ImageViewServer' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make name=${DOCKER_NAME} rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -#tmux send-keys "source devel/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -sleep 1 -tmux send-keys "roslaunch --wait wxpython_gui image_view_server.launch" C-m - -sleep 1 - -# Test -tmux new-window -t $TMUX_SESSION:7 -n 'Test' -tmux send-keys "cd ${WSDIR}" C-m -tmux send-keys "make name=${DOCKER_NAME} rungui-existing" C-m -tmux send-keys "source /opt/ros/kinetic/setup.bash" C-m -#tmux send-keys "source devel/setup.bash" C-m -tmux send-keys "source activate_ros.bash" C-m -sleep 1 -tmux select-window -t $TMUX_SESSION:6 -# Bring up the tmux session -tmux attach -t $TMUX_SESSION diff --git a/src/run_scripts/setup/get_rid_of_transport_plugins.sh b/src/run_scripts/setup/get_rid_of_transport_plugins.sh deleted file mode 100755 index b896b35..0000000 --- a/src/run_scripts/setup/get_rid_of_transport_plugins.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - - -# Image transport plugins create a bunch of unnecssary topics. We are gonna -# force-uninstall them to keep the clutter down -printf "Force-uninstall transport plugins which come bundled with ros-desktop-full. -This cleans up the topic-space in ROS. -This will show some angry looking messages. -Do not use this script if you actually need these message channels. -" -dpkg -r --force-depends \ - ros-kinetic-theora-image-transport \ - ros-kinetic-compressed-depth-image-transport \ - ros-kinetic-compressed-image-transport \ - ros-kinetic-image-transport-plugins \ No newline at end of file From 7c0d79e9b08077a29e367fe4afda450d3cfb9818 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 10:35:54 -0400 Subject: [PATCH 040/139] Remove some unused functions in the GUI, make sure casing matches in docker files --- docker/base/core-ros.dockerfile | 2 +- docker/base/detector-viame-deps.dockerfile | 2 +- docker/base/gui-ros.dockerfile | 2 +- scripts/docker_images.sh | 1 + src/kitware-ros-pkg/wxpython_gui/README.rst | 32 ++++++++++--------- .../wxpython_gui/system_control_panel/gui.py | 18 +---------- 6 files changed, 22 insertions(+), 35 deletions(-) diff --git a/docker/base/core-ros.dockerfile b/docker/base/core-ros.dockerfile index af8aae2..7fc2389 100644 --- a/docker/base/core-ros.dockerfile +++ b/docker/base/core-ros.dockerfile @@ -1,6 +1,6 @@ # This image contains the base of the ROS/CUDA for the system, plus # a bunch of utility packages -FROM nvidia/cuda:12.6.2-devel-ubuntu20.04 as base_cuda_ubuntu +FROM nvidia/cuda:12.6.2-devel-ubuntu20.04 AS base_cuda_ubuntu WORKDIR /root # setup environment diff --git a/docker/base/detector-viame-deps.dockerfile b/docker/base/detector-viame-deps.dockerfile index 2caa84c..2016777 100644 --- a/docker/base/detector-viame-deps.dockerfile +++ b/docker/base/detector-viame-deps.dockerfile @@ -1,5 +1,5 @@ # Build off the public VIAME docker build (with ITK support) -FROM kitware/viame:gpu-algorithms-seal as vb +FROM kitware/viame:gpu-algorithms-seal AS vb WORKDIR /root # setup environment diff --git a/docker/base/gui-ros.dockerfile b/docker/base/gui-ros.dockerfile index fec3cf2..dc8a765 100644 --- a/docker/base/gui-ros.dockerfile +++ b/docker/base/gui-ros.dockerfile @@ -1,4 +1,4 @@ -FROM ros:kinetic-robot as kinetic-robot +FROM ros:kinetic-robot AS kinetic-robot ENV PYTHON=python2 \ ROS_PKG_VERS=1.3.2-0 diff --git a/scripts/docker_images.sh b/scripts/docker_images.sh index 0e8bd2f..6dec8a8 100755 --- a/scripts/docker_images.sh +++ b/scripts/docker_images.sh @@ -3,6 +3,7 @@ IMAGES=(\ "kitware/kamera:viame" "kitware/kamera:core" + "kitware/kamera:gui" "kitware/kamera:postproc" "kitware/kamera:kamerad" ) diff --git a/src/kitware-ros-pkg/wxpython_gui/README.rst b/src/kitware-ros-pkg/wxpython_gui/README.rst index 50c2dbc..e756633 100644 --- a/src/kitware-ros-pkg/wxpython_gui/README.rst +++ b/src/kitware-ros-pkg/wxpython_gui/README.rst @@ -1,33 +1,35 @@ GUIs implemented with wxPython ============================== -This package provides various GUIs implemented with wxPython. +This package provides the KAMERA system control panel and related GUI +components. Source Tree Layout ================== launch/ ------- -ROS launch files launching the node or nodes in /scripts. - -resources/ ----------- -Any data (e.g., images) required for the GUIs. +ROS launch files for the GUI nodes (e.g. ``system_control_panel.launch``). scripts/ -------- -The ROS node launcher for each GUI is defined with a Python script here. +ROS node entry points (e.g. ``system_control_panel_node.py``). src/wxpython_gui/ ----------------- -The current convention is that each module under `src/wxpython_gui` defines one GUI. Each folder contains a `gui.py`, where the wx main loop is defined. However, the general layout of the GUI is defined using wxFormBuilder (`necessary version `_, see install instructions for Ubuntu), stored in `gui.fbp`. wxFormBuilder automatically generates the code `form_builder_output.py`, which defines MainFrame, a subclass of wx.Frame, setting up the layout. In `gui.py`, the MainFrame of the gui is subclassed from `form_builder_output.MainFrame`, absorbing all of the layout definition. Then additional processing is defined within gui.py to complete the GUI functionality. - -src/wxpython_gui/wx_elements.py -------------------------------- -Common GUI functionality. Currently, the ImagePanelManager is the only object -defined (see documentation therein). +Python modules for the GUI. The main window lives under +``system_control_panel/``: ``gui.fbp`` is the wxFormBuilder layout, +``form_builder_output*.py`` are the generated frame classes, and +``gui.py`` subclasses them with application logic. Shared helpers +(e.g. ``RemoteImagePanel.py``, ``camera_models.py``) sit alongside +that directory. Notes ===== -- The wx.Frame loop and ROS callbacks will run on different threads. Therefore, when a method of the wx.Frame is provided as a ROS callback, attributes of the wx.Frame should not be modified directly but rather wx.CallAfter should be used to call another method to make the modifications. By convention, any method that interfaces with ROS should have the subscript '_ros'. -- For ROS callbacks providing new images, if the rate at which new images arrive exceeds the rate at which the wx.Frame can handle updating images, the frame will crash. Therefore, a catch should be used to only try to update images if the frame is idle. +- The wx.Frame loop and ROS callbacks run on different threads. When a + method of the wx.Frame is used as a ROS callback, do not modify frame + attributes directly; use ``wx.CallAfter`` to schedule updates on the + GUI thread. By convention, ROS-facing methods use the ``_ros`` suffix. +- For ROS image callbacks, if new images arrive faster than the frame + can repaint, the GUI can crash. Only update images when the frame is + idle. diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 88437aa..fd36484 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -40,7 +40,7 @@ # ROS imports import rospy import std_msgs.msg -from custom_msgs.msg import GSOF_INS, Stat +from custom_msgs.msg import GSOF_INS from sensor_msgs.msg import Image, CompressedImage from cv_bridge import CvBridge, CvBridgeError @@ -56,12 +56,8 @@ RequestCompressedImageView, RequestImageMetadata, RequestImageView, - SetArchiving, CamSetAttr, - CamGetAttr, - CamGetAttrResponse, ) -import sys from wxpython_gui.camera_models import load_from_file # Relative Imports @@ -1201,18 +1197,6 @@ def add_to_console_log(self, msg, msg_type="Info"): if self._log_panel: self._log_panel.add_message(msg_type, msg) - def set_cam_attr(self, fov, chan, param, val): - try: - set_cam_attr(fov, chan, param, val, log_cb=self._add_to_event_log) - except Exception as e: - self.exception_window(e, "SetCamAttr Error") - - def set_ir_attr(self, fov, chan, param, val): - try: - set_ir_attr(fov, chan, param, val, log_cb=self._add_to_event_log) - except Exception as e: - rospy.logerr(e) # , 'SetCamAttr Error') - def start_collecting(self, event=None): self._disable_state_controls() self.log_state() From f8bd281fbf097ca3495e3cbd08b844fdf3dd3034 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 10:43:12 -0400 Subject: [PATCH 041/139] Remove references to files / dirs that no longer exist --- docker/gui.dockerfile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docker/gui.dockerfile b/docker/gui.dockerfile index 38ce736..d3db6b0 100644 --- a/docker/gui.dockerfile +++ b/docker/gui.dockerfile @@ -19,10 +19,9 @@ ENV HOME_DIR=/home/user \ # trying to speed up chown operation RUN mkdir -p /home/user && chown -R user:user /home/user -COPY --chown=user:user src/kitware-ros-pkg/wxpython_gui/config $GUI_CFG_DIR/config -COPY --chown=user:user repo_dir.bash $REPO_DIR/repo_dir.bash -COPY --chown=user:user src $REPO_DIR/src -COPY --chown=user:user activate_ros.bash $WS_DIR/activate_ros.bash +COPY --chown=user:user .dir $REPO_DIR/repo_dir.bash +COPY --chown=user:user src $REPO_DIR/src +COPY --chown=user:user scripts/activate_ros.bash $WS_DIR/activate_ros.bash RUN ln -sf $REPO_DIR/src $WS_DIR/src &&\ rm -rf /entry &&\ ln -sf $REPO_DIR/src/run_scripts/entry /entry &&\ From 2453ee3272483cc098fbb999c0eb95994ba5752c Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 15 Jun 2026 10:53:07 -0400 Subject: [PATCH 042/139] Remove old syntax from gui.dockerfile --- docker/gui.dockerfile | 20 ++++------- src/run_scripts/entry/project_env.sh | 8 ++--- src/run_scripts/newstartup/assert_nas.sh | 44 ------------------------ src/run_scripts/setup/install_links.sh | 23 ------------- 4 files changed, 8 insertions(+), 87 deletions(-) delete mode 100755 src/run_scripts/newstartup/assert_nas.sh delete mode 100755 src/run_scripts/setup/install_links.sh diff --git a/docker/gui.dockerfile b/docker/gui.dockerfile index d3db6b0..50df862 100644 --- a/docker/gui.dockerfile +++ b/docker/gui.dockerfile @@ -12,27 +12,19 @@ RUN useradd -m --uid=1000 user \ # Source code goes into ~/noaa_kamera, live dir goes into ~/kamera_ws ENV HOME_DIR=/home/user \ - REPO_DIR=/home/user/noaa_kamera \ - WS_DIR=/home/user/kamera_ws \ + REPO_DIR=/home/user/kamera \ GUI_CFG_DIR=/home/user/.config/kamera/gui # trying to speed up chown operation RUN mkdir -p /home/user && chown -R user:user /home/user -COPY --chown=user:user .dir $REPO_DIR/repo_dir.bash -COPY --chown=user:user src $REPO_DIR/src -COPY --chown=user:user scripts/activate_ros.bash $WS_DIR/activate_ros.bash -RUN ln -sf $REPO_DIR/src $WS_DIR/src &&\ - rm -rf /entry &&\ - ln -sf $REPO_DIR/src/run_scripts/entry /entry &&\ +COPY --chown=user:user . $REPO_DIR +RUN ln -sf $REPO_DIR/src/run_scripts/entry /entry &&\ printf "\nsource /entry/project.sh\n" >> /home/user/.bashrc &&\ - touch $WS_DIR/.catkin_workspace &&\ - ln -sf $REPO_DIR/src/run_scripts/aliases.sh /aliases.sh &&\ - printf "\nsource /aliases.sh\n" >> /root/.bashrc &&\ - ln -sf $REPO_DIR/src/cfg /cfg &&\ - HOME=/home/user $REPO_DIR/src/run_scripts/setup/install_links.sh + touch $REPO_DIR/.catkin_workspace &&\ + ln -sf $REPO_DIR/src/cfg /cfg -WORKDIR $WS_DIR +WORKDIR $REPO_DIR RUN find /home/user -not -user user -execdir chown user {} \+ # use the exec form of run because we need bash syntax diff --git a/src/run_scripts/entry/project_env.sh b/src/run_scripts/entry/project_env.sh index 1f3d950..6e72112 100755 --- a/src/run_scripts/entry/project_env.sh +++ b/src/run_scripts/entry/project_env.sh @@ -3,7 +3,7 @@ # Source environment variables for the project.sh entrypoint. No exec. echo "~~~ ~~~ Project entry point project_env.sh ~~~ ~~~" -for VNAME in ROS_DISTRO WS_DIR +for VNAME in ROS_DISTRO REPO_DIR do if [[ -z "${!VNAME}" || "${!VNAME}" == 'null' ]]; then printf " Unable to determine $VNAME. Check project_env.sh and user-config\n" @@ -32,16 +32,12 @@ prependToPath () { # setup ros environment source "/opt/ros/$ROS_DISTRO/setup.bash" -source "${WS_DIR}/scripts/activate_ros.bash" +source "${REPO_DIR}/scripts/activate_ros.bash" export REDIS_HOST=${REDIS_HOST} export ARCH_KEY="/sys/arch/" # Try turning respawning back to roslaunch export NORESPAWN="true" -## alternate path syntax -#[ "${PATH#*$HOME/.local/bin:}" == "$PATH" ] && export PATH="$HOME/.local/bin:$PATH" -#[ "${PATH#*$REPO_DIR/src/run_scripts/inpath:}" == "$PATH" ] && export PATH="$REPO_DIR/src/run_scripts/inpath:$PATH" -#[ "${PATH#*/opt/ros/$ROS_DISTRO/bin:}" == "$PATH" ] && export PATH="/opt/ros/$ROS_DISTRO/bin:$PATH" prependToPath $HOME/.local/bin prependToPath $REPO_DIR/src/run_scripts/inpath prependToPath /opt/ros/$ROS_DISTRO/bin diff --git a/src/run_scripts/newstartup/assert_nas.sh b/src/run_scripts/newstartup/assert_nas.sh deleted file mode 100755 index 06aa686..0000000 --- a/src/run_scripts/newstartup/assert_nas.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -source ~/.config/kamera/bootstrap_app.sh -KAM_REPO_DIR=${KAM_REPO_DIR:-} -if [[ -z "${KAM_REPO_DIR}" ]]; then - errcho "ERROR: Could not resolve KAM_REPO_DIR. Check ~/.config/kamera" - exit 1 -fi - -source ${KAM_REPO_DIR}/src/cfg/cfg-aliases.sh - -pids=("$@") -for host in $(cq '.hosts | keys | join("\n" )') ; do - if [[ $(cq ".hosts.${host}.enabled") == 'true' ]]; then - ssh_checked.sh $host "mount_nas ${ARGS[@]}" & - pids[${i}]=$! - else - echo "${host} disabled." - fi -done - -for pid in ${pids[*]}; do - wait $pid -done - -declare -A RESULTS -declare -A EXITS -i=0 -for host in $(cq '.hosts | keys | join("\n" )') ; do - echo $i - if [[ $(cq ".hosts.${host}.enabled") == 'true' ]]; then - OUT=$(ssh_checked.sh $host "mount | grep kamera_nas") - EXITS[${host}]=$? - RESULTS[${host}]="$OUT" - else - echo "${host} disabled." - fi - i=$((i+1)) -done - -echo "results: ${RESULTS[@]}" -echo "exits: ${EXITS[@]}" - - diff --git a/src/run_scripts/setup/install_links.sh b/src/run_scripts/setup/install_links.sh deleted file mode 100755 index 3ce5e8d..0000000 --- a/src/run_scripts/setup/install_links.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -## Install breadcrumb links so we can find this repo -HEREDIR=$(cd "$(dirname $(realpath ${0}))" && pwd) -REPO_DIR=$(cd ${HEREDIR}/../../../ && pwd) -echo "REPO_DIR: $REPO_DIR" - -if [[ -n `grep docker /proc/1/cgroup` ]] ; then - export IS_CONTAINER=true -fi - -mkdir -p ${HOME}/.config/kamera/ -mkdir -p ${HOME}/.local/bin/ - -ln -sfv ${REPO_DIR}/repo_dir.bash ${HOME}/.config/kamera/repo_dir.bash -ln -sfv ${REPO_DIR}/src/run_scripts/bootstrap_app.sh ${HOME}/.config/kamera/bootstrap_app.sh -ln -sfv ${REPO_DIR}/src/run_scripts/newstartup/kamera_run.sh ${HOME}/.local/bin/kamera_run - - -if [[ -n $IS_CONTAINER ]]; then - echo "ln -srf ${REPO_DIR}/src/cfg /" - ln -srf "${REPO_DIR}/src/cfg /" -fi \ No newline at end of file From 2faad74ddb0e74eb90fb3cd349756619b9d3b8a8 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 10:56:54 -0400 Subject: [PATCH 043/139] Modernize gui.dockerfile a little more --- docker/gui.dockerfile | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/docker/gui.dockerfile b/docker/gui.dockerfile index 50df862..018d87b 100644 --- a/docker/gui.dockerfile +++ b/docker/gui.dockerfile @@ -10,7 +10,7 @@ RUN useradd -m --uid=1000 user \ && useradd --uid=7777 share \ && usermod -aG share user -# Source code goes into ~/noaa_kamera, live dir goes into ~/kamera_ws +# Source code goes into ~/kamera ENV HOME_DIR=/home/user \ REPO_DIR=/home/user/kamera \ GUI_CFG_DIR=/home/user/.config/kamera/gui @@ -18,13 +18,22 @@ ENV HOME_DIR=/home/user \ # trying to speed up chown operation RUN mkdir -p /home/user && chown -R user:user /home/user -COPY --chown=user:user . $REPO_DIR -RUN ln -sf $REPO_DIR/src/run_scripts/entry /entry &&\ - printf "\nsource /entry/project.sh\n" >> /home/user/.bashrc &&\ - touch $REPO_DIR/.catkin_workspace &&\ - ln -sf $REPO_DIR/src/cfg /cfg - WORKDIR $REPO_DIR +COPY --chown=user:user . $REPO_DIR + +RUN rm -rf /entry \ + && ln -sf $REPO_DIR/src/run_scripts/entry /entry \ + && printf "\nsource /entry/project.sh\n" >> /home/user/.bashrc \ + && touch $REPO_DIR/.catkin_workspace \ + && ln -sf $REPO_DIR/src/run_scripts/aliases.sh /aliases.sh \ + && printf "\nsource /aliases.sh\n" >> /home/user/.bashrc + +RUN ln -sf $REPO_DIR/scripts/activate_ros.bash $REPO_DIR/activate_ros.bash +RUN ln -sf $REPO_DIR/src/cfg /cfg +RUN mkdir -p /home/user/.config/kamera && \ + ln -sf $REPO_DIR/.dir /home/user/.config/kamera/repo_dir.bash + +RUN ln -sv /usr/bin/python3 /usr/bin/python || true RUN find /home/user -not -user user -execdir chown user {} \+ # use the exec form of run because we need bash syntax From de52f0356ad02720c6768cda4e3fcb86957f22be Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 10:59:48 -0400 Subject: [PATCH 044/139] Remove kamera pip install - the gui doesn't need it --- docker/gui.dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/docker/gui.dockerfile b/docker/gui.dockerfile index 018d87b..4011fc6 100644 --- a/docker/gui.dockerfile +++ b/docker/gui.dockerfile @@ -40,7 +40,6 @@ RUN find /home/user -not -user user -execdir chown user {} \+ USER user RUN [ "/bin/bash", "-c", "source /entry/project.sh && catkin build wxpython_gui "] RUN [ "/bin/bash", "-c", "source /entry/project.sh && catkin build ins_driver "] -RUN [ "/bin/bash", "-c", "pip install -e ."] USER root RUN find /home/user -not -user user -execdir chown user {} \+ USER user From 48f9ffa07b7c3ce1e1127433d2052e0ff8d724c1 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 11:11:25 -0400 Subject: [PATCH 045/139] Escape host config queries to support hyphens in hostnames --- src/run_scripts/newstartup/kamera_halt.sh | 2 +- src/run_scripts/newstartup/kamera_run.sh | 6 +++--- tmux/nayak/env.sh | 2 +- tmux/taiga/env.sh | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/run_scripts/newstartup/kamera_halt.sh b/src/run_scripts/newstartup/kamera_halt.sh index 1cced79..6c375b6 100755 --- a/src/run_scripts/newstartup/kamera_halt.sh +++ b/src/run_scripts/newstartup/kamera_halt.sh @@ -64,7 +64,7 @@ blueprintf "done\nGui down. Killing pods...\n" # Query list of hosts as line delim array declare -A PIDS for host in $(cq '.arch.hosts | keys | join("\n" )') ; do - if [[ $(cq ".arch.hosts.${host}.enabled") == 'true' ]]; then + if [[ $(cq ".arch.hosts[\"${host}\"].enabled") == 'true' ]]; then python3 ${KAM_REPO_DIR}/scripts/system.py $host ${ARGS[@]} pod & PIDS["${host}_pod"]=$! python3 ${KAM_REPO_DIR}/scripts/system.py $host ${ARGS[@]} detector & diff --git a/src/run_scripts/newstartup/kamera_run.sh b/src/run_scripts/newstartup/kamera_run.sh index 4c0f427..8dea066 100755 --- a/src/run_scripts/newstartup/kamera_run.sh +++ b/src/run_scripts/newstartup/kamera_run.sh @@ -85,7 +85,7 @@ if [[ -n ${SKIP_PING} ]]; then else for host in $(cq '.arch.hosts | keys | join("\n" )') ; do echo "Waiting on ping $host." - if [[ $(cq ".arch.hosts.${host}.enabled") == 'true' ]]; then + if [[ $(cq ".arch.hosts[\"${host}\"].enabled") == 'true' ]]; then until ping -c1 -W1 ${host} &>/dev/null; do printf "\b${SP:i++%${#SP}:1}" done @@ -107,7 +107,7 @@ else fi declare -A PIDS for host in $(cq '.arch.hosts | keys | join("\n" )') ; do - if [[ $(cq ".arch.hosts.${host}.enabled") == 'true' ]]; then + if [[ $(cq ".arch.hosts[\"${host}\"].enabled") == 'true' ]]; then python3 ${KAM_REPO_DIR}/scripts/system.py $host restart nas & PIDS[${host}]=$! else @@ -154,7 +154,7 @@ hosts=$(cq '.arch.hosts | keys | join("\n" )') IFS=$'\n' sorted_hosts=($(sort <<<"${hosts[*]}")) unset IFS for host in "${sorted_hosts[@]}"; do - if [[ $(cq ".arch.hosts.${host}.enabled") == 'true' ]]; then + if [[ $(cq ".arch.hosts[\"${host}\"].enabled") == 'true' ]]; then python3 ${KAM_REPO_DIR}/scripts/system.py $host "${ARGS[@]}" pod & PIDS[${host}]=$! else diff --git a/tmux/nayak/env.sh b/tmux/nayak/env.sh index 0a5ab02..a6b993f 100644 --- a/tmux/nayak/env.sh +++ b/tmux/nayak/env.sh @@ -35,7 +35,7 @@ export ROS_HOSTNAME=${NODE_HOSTNAME} export ROS_MASTER_URI="http://${ROS_MASTER}:11311" export DOCKER_KAMERA_DIR="/root/kamera" export DATA_MOUNT_POINT=$(cq .local_ssd_mnt) -export CAM_FOV=$(cq .arch.hosts.${NODE_HOSTNAME}.fov) +export CAM_FOV=$(cq ".arch.hosts[\"${NODE_HOSTNAME}\"].fov") export ROS_DISTRO="noetic" export KAMERA_DNS_IP="192.168.88.1" diff --git a/tmux/taiga/env.sh b/tmux/taiga/env.sh index 77f2a6f..5420de8 100644 --- a/tmux/taiga/env.sh +++ b/tmux/taiga/env.sh @@ -33,7 +33,7 @@ export NODE_HOSTNAME=$(hostname) export ROS_MASTER_URI="http://${ROS_HOSTNAME}:11311" export DOCKER_KAMERA_DIR="/root/kamera" export DATA_MOUNT_POINT=$(cq .local_ssd_mnt) -export CAM_FOV=$(cq .arch.hosts.${NODE_HOSTNAME}.fov) +export CAM_FOV=$(cq ".arch.hosts[\"${NODE_HOSTNAME}\"].fov") export ROS_DISTRO="noetic" export KAMERA_DNS_IP="192.168.88.1" From 755c30e8c1526c5acadfe6a67217159eeb3e613a Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 11:21:38 -0400 Subject: [PATCH 046/139] Remove custom tini install, use docker's built-in init stack --- compose/cam_ir.yml | 1 + compose/cam_param_monitor.yml | 1 + compose/cam_rgb.yml | 1 + compose/cam_uv.yml | 1 + compose/daq.yml | 1 + compose/detections.yml | 1 + compose/detector.yml | 1 + compose/flight_summary.yml | 1 + compose/fps_monitor.yml | 1 + compose/gui.yml | 4 ++-- compose/homography.yml | 1 + compose/image_manager.yml | 1 + compose/imageview.yml | 1 + compose/ins.yml | 1 + compose/kamerad.yml | 1 + compose/nodelist.yml | 1 + compose/postproc.yml | 1 + compose/registry.yml | 1 + compose/roscore.yml | 1 + compose/shapefile_monitor.yml | 1 + compose/spoof_events.yml | 1 + compose/sync_msg_publisher.yml | 1 + docker/base/detector-viame-deps.dockerfile | 4 ---- 23 files changed, 23 insertions(+), 6 deletions(-) diff --git a/compose/cam_ir.yml b/compose/cam_ir.yml index 72629af..9d7bcb1 100644 --- a/compose/cam_ir.yml +++ b/compose/cam_ir.yml @@ -4,6 +4,7 @@ services: cam_ir: container_name: "cam-ir-${CAM_FOV}" image: ${KAMERA_CORE_IMAGE} + init: true tty: true environment: ROS_MASTER_URI: "${ROS_MASTER_URI}" diff --git a/compose/cam_param_monitor.yml b/compose/cam_param_monitor.yml index 89763a5..b975e0f 100644 --- a/compose/cam_param_monitor.yml +++ b/compose/cam_param_monitor.yml @@ -4,6 +4,7 @@ services: cam_param_monitor: container_name: cam_param_monitor image: ${KAMERA_CORE_IMAGE} + init: true tty: true environment: ROS_MASTER_URI: "${ROS_MASTER_URI}" diff --git a/compose/cam_rgb.yml b/compose/cam_rgb.yml index 6d19903..474401d 100644 --- a/compose/cam_rgb.yml +++ b/compose/cam_rgb.yml @@ -5,6 +5,7 @@ services: cam_rgb: container_name: "cam-rgb-${CAM_FOV}" image: ${KAMERA_CORE_IMAGE} + init: true tty: true environment: ROS_MASTER_URI: "${ROS_MASTER_URI}" diff --git a/compose/cam_uv.yml b/compose/cam_uv.yml index fbd3d59..52b7478 100644 --- a/compose/cam_uv.yml +++ b/compose/cam_uv.yml @@ -5,6 +5,7 @@ services: cam_uv: container_name: "cam-uv-${CAM_FOV}" image: ${KAMERA_CORE_IMAGE} + init: true tty: true environment: ROS_MASTER_URI: "${ROS_MASTER_URI}" diff --git a/compose/daq.yml b/compose/daq.yml index 1d25ab3..7d0633b 100644 --- a/compose/daq.yml +++ b/compose/daq.yml @@ -4,6 +4,7 @@ services: daq: container_name: daq image: ${KAMERA_CORE_IMAGE} + init: true tty: true devices: - "${MCC_DAQ}:${MCC_DAQ}" diff --git a/compose/detections.yml b/compose/detections.yml index 7a9f9dd..22f973c 100644 --- a/compose/detections.yml +++ b/compose/detections.yml @@ -4,6 +4,7 @@ services: ## =========================== headless nodes ============================= detections: image: ${KAMERA_POSTPROC_IMAGE} + init: true network_mode: host environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/detector.yml b/compose/detector.yml index 4723d8d..d2cae26 100644 --- a/compose/detector.yml +++ b/compose/detector.yml @@ -7,6 +7,7 @@ services: detector: container_name: "viame-${CAM_FOV}" image: ${KAMERA_VIAME_IMAGE} + init: true tty: true environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/flight_summary.yml b/compose/flight_summary.yml index fb0ba2f..2d7efcc 100644 --- a/compose/flight_summary.yml +++ b/compose/flight_summary.yml @@ -4,6 +4,7 @@ services: ## =========================== headless nodes ============================= flight_summary: image: ${KAMERA_POSTPROC_IMAGE} + init: true network_mode: host environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/fps_monitor.yml b/compose/fps_monitor.yml index b886741..53fb05b 100644 --- a/compose/fps_monitor.yml +++ b/compose/fps_monitor.yml @@ -4,6 +4,7 @@ services: fps_monitor: container_name: fps_monitor image: ${KAMERA_CORE_IMAGE} + init: true tty: true environment: ROS_MASTER_URI: "${ROS_MASTER_URI}" diff --git a/compose/gui.yml b/compose/gui.yml index f41d133..9da6f3c 100644 --- a/compose/gui.yml +++ b/compose/gui.yml @@ -5,6 +5,7 @@ services: gui: container_name: gui image: ${KAMERA_GUI_IMAGE} + init: true tty: true environment: REDIS_HOST: "${REDIS_HOST}" @@ -31,8 +32,7 @@ services: - "${PWD}/assets:/home/user/noaa_kamera/assets:ro" - "save-gui:/home/user/.config/kamera/gui" - "${HOME}/.ssh:/home/user/.ssh" - entrypoint: ["/bin/tini", "--"] - command: ["/entry/gui.sh"] + entrypoint: ["/entry/gui.sh"] #command: ["bash"] volumes: diff --git a/compose/homography.yml b/compose/homography.yml index 89c0843..cb9fc3a 100644 --- a/compose/homography.yml +++ b/compose/homography.yml @@ -4,6 +4,7 @@ services: ## =========================== headless nodes ============================= homography: image: ${KAMERA_POSTPROC_IMAGE} + init: true network_mode: host environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/image_manager.yml b/compose/image_manager.yml index b3b78ab..8437bb1 100644 --- a/compose/image_manager.yml +++ b/compose/image_manager.yml @@ -5,6 +5,7 @@ services: image_manager: container_name: "image_manager" image: ${KAMERA_CORE_IMAGE} + init: true tty: true environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/imageview.yml b/compose/imageview.yml index a4e171d..78d824c 100644 --- a/compose/imageview.yml +++ b/compose/imageview.yml @@ -3,6 +3,7 @@ services: imageview: container_name: "imageview-${CAM_FOV}" image: ${KAMERA_CORE_IMAGE} + init: true tty: true environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/ins.yml b/compose/ins.yml index 9f4d3bf..ffab818 100644 --- a/compose/ins.yml +++ b/compose/ins.yml @@ -4,6 +4,7 @@ services: ins: container_name: ins image: ${KAMERA_CORE_IMAGE} + init: true tty: true devices: - "${PULSE_TTY}:${PULSE_TTY}" diff --git a/compose/kamerad.yml b/compose/kamerad.yml index 08ba494..6beb260 100644 --- a/compose/kamerad.yml +++ b/compose/kamerad.yml @@ -4,6 +4,7 @@ services: ## =========================== headless nodes ============================= kamerad: image: ${KAMERA_KAMERAD_IMAGE} + init: true network_mode: host build: ../src/core/kamerad tty: true diff --git a/compose/nodelist.yml b/compose/nodelist.yml index 79c3b74..9a0eb69 100644 --- a/compose/nodelist.yml +++ b/compose/nodelist.yml @@ -5,6 +5,7 @@ services: nodelist: container_name: nodelist image: ${KAMERA_CORE_IMAGE} + init: true tty: true network_mode: host environment: diff --git a/compose/postproc.yml b/compose/postproc.yml index 151c201..23ccebb 100644 --- a/compose/postproc.yml +++ b/compose/postproc.yml @@ -4,6 +4,7 @@ services: ## =========================== headless nodes ============================= postproc: image: ${KAMERA_POSTPROC_IMAGE} + init: true network_mode: host environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/registry.yml b/compose/registry.yml index 728fa45..14f4f6a 100644 --- a/compose/registry.yml +++ b/compose/registry.yml @@ -2,6 +2,7 @@ services: registry: restart: always image: registry:2 + init: true ports: - 5000:5000 volumes: diff --git a/compose/roscore.yml b/compose/roscore.yml index 2f70ce0..5b2e379 100644 --- a/compose/roscore.yml +++ b/compose/roscore.yml @@ -5,6 +5,7 @@ services: roscore: container_name: roscore image: ${KAMERA_CORE_IMAGE} + init: true tty: true network_mode: host environment: diff --git a/compose/shapefile_monitor.yml b/compose/shapefile_monitor.yml index 12b510a..2184930 100644 --- a/compose/shapefile_monitor.yml +++ b/compose/shapefile_monitor.yml @@ -4,6 +4,7 @@ services: shapefile_monitor: container_name: shapefile_monitor image: ${KAMERA_CORE_IMAGE} + init: true tty: true environment: REDIS_HOST: "${REDIS_HOST}" diff --git a/compose/spoof_events.yml b/compose/spoof_events.yml index d19bffb..0272cc6 100644 --- a/compose/spoof_events.yml +++ b/compose/spoof_events.yml @@ -4,6 +4,7 @@ services: spoof_events: container_name: spoof_events image: ${KAMERA_CORE_IMAGE} + init: true tty: true devices: - "${PULSE_TTY}:${PULSE_TTY}" diff --git a/compose/sync_msg_publisher.yml b/compose/sync_msg_publisher.yml index 7eeb8ed..5d6f18a 100644 --- a/compose/sync_msg_publisher.yml +++ b/compose/sync_msg_publisher.yml @@ -4,6 +4,7 @@ services: sync-publisher: container_name: "sync-publisher-${CAM_FOV}" image: ${KAMERA_VIAME_IMAGE} + init: true tty: true environment: ROS_MASTER_URI: "${ROS_MASTER_URI}" diff --git a/docker/base/detector-viame-deps.dockerfile b/docker/base/detector-viame-deps.dockerfile index 2016777..1267513 100644 --- a/docker/base/detector-viame-deps.dockerfile +++ b/docker/base/detector-viame-deps.dockerfile @@ -37,10 +37,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ # Build tools necessary for catkin and roskv -# Add Tini to handle signals -RUN curl -sSL https://github.com/krallin/tini/releases/download/v0.18.0/tini -o /tini && \ - chmod +x /tini - # Add yq to make config query work RUN curl -sL https://github.com/mikefarah/yq/releases/download/2.4.0/yq_linux_amd64 \ -o /usr/local/bin/yq && \ From 1f15a5b2a9436e7476bc2be41779e5423d23963d Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 15 Jun 2026 11:22:21 -0400 Subject: [PATCH 047/139] Remove local ros calls --- tmux/taiga/startup.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/tmux/taiga/startup.sh b/tmux/taiga/startup.sh index de83212..174fb9b 100644 --- a/tmux/taiga/startup.sh +++ b/tmux/taiga/startup.sh @@ -1,7 +1,5 @@ #!/bin/sh #DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -. /opt/ros/noetic/setup.sh -rosclean purge -y mkdir -p ~/.config/kamera/gui From b413ba420cd57562828e306b5594161c57955349 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 11:34:06 -0400 Subject: [PATCH 048/139] Remove py2 relative imports, use absolute --- .../wxpython_gui/system_control_panel/gui.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index fd36484..98bf178 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -60,16 +60,16 @@ ) from wxpython_gui.camera_models import load_from_file -# Relative Imports -import form_builder_output -import form_builder_output_effort_metadata -import form_builder_output_imagery_inspection -import form_builder_output_event_log_note -import form_builder_output_hot_key_list -import form_builder_output_collection_mode -import form_builder_output_log_panel -import form_builder_output_system_startup -import form_builder_output_camera_configuration +# Sibling modules within the system_control_panel package +import wxpython_gui.system_control_panel.form_builder_output as form_builder_output +import wxpython_gui.system_control_panel.form_builder_output_effort_metadata as form_builder_output_effort_metadata +import wxpython_gui.system_control_panel.form_builder_output_imagery_inspection as form_builder_output_imagery_inspection +import wxpython_gui.system_control_panel.form_builder_output_event_log_note as form_builder_output_event_log_note +import wxpython_gui.system_control_panel.form_builder_output_hot_key_list as form_builder_output_hot_key_list +import wxpython_gui.system_control_panel.form_builder_output_collection_mode as form_builder_output_collection_mode +import wxpython_gui.system_control_panel.form_builder_output_log_panel as form_builder_output_log_panel +import wxpython_gui.system_control_panel.form_builder_output_system_startup as form_builder_output_system_startup +import wxpython_gui.system_control_panel.form_builder_output_camera_configuration as form_builder_output_camera_configuration # Absolute imports from wxpython_gui.cfg import ( @@ -108,7 +108,7 @@ from wxpython_gui.SystemCommands import SystemCommands from wxpython_gui.DetectorState import set_detector_state, detector_state, EPodStatus -import gui_utils +import wxpython_gui.system_control_panel.gui_utils as gui_utils G_time_note_started = None # type: datetime.datetime From e15234aea903a89da358153bb8ec01a2296eac30 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 11:37:01 -0400 Subject: [PATCH 049/139] Load defaults based on system name, not from within gui --- src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py index 07c8562..0f75f71 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py @@ -93,7 +93,10 @@ def update(self, *args, **kwargs): # create from template if it doesn't exist if not os.path.isfile(config_filename): wxpython_gui.utils.make_path(config_filename, from_file=True) - with open(os.path.join(PKG_DIR, "config/default_system_state.json"), "r") as infile: + default_system_state_file = os.path.join( + REAL_KAM_REPO_DIR, "src/cfg", system_name, "default_system_state.json" + ) + with open(default_system_state_file, "r") as infile: with open(config_filename, "w") as outfile: outfile.write(infile.read()) print("Created config from scratch: {}".format(config_filename)) From b1b418d8b1066eee41f477d41dc9aff3b2dbe1b1 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 11:42:07 -0400 Subject: [PATCH 050/139] Add psutil pip package, generate locales so GUI doesn't flop initially --- docker/base/gui-deps-noetic.dockerfile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docker/base/gui-deps-noetic.dockerfile b/docker/base/gui-deps-noetic.dockerfile index 24d58bd..320034d 100644 --- a/docker/base/gui-deps-noetic.dockerfile +++ b/docker/base/gui-deps-noetic.dockerfile @@ -8,8 +8,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ python3-wxgtk4.0 \ libgl1-mesa-glx \ libqt5x11extras5 \ + locales \ && rm -rf /var/lib/apt/lists/* +# wxPython's wx.App init sets the en_US locale at startup; generate it so the +# GUI doesn't fail with "locale en_US cannot be set". +RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8 +ENV LANG=en_US.UTF-8 \ + LANGUAGE=en_US:en \ + LC_ALL=en_US.UTF-8 + RUN pip install --upgrade \ pip \ Pillow @@ -21,6 +29,7 @@ RUN pip install --no-cache-dir \ 'PyGeodesy<19.12' \ exifread \ ipython \ + psutil \ simplekml COPY src/core/roskv /src/roskv From b1496a6dc546649004c85b0088c71fb047c35b9e Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 11:44:00 -0400 Subject: [PATCH 051/139] Move AddSpacer to Add for wx4 --- .../system_control_panel/form_builder_output.py | 8 ++++---- .../form_builder_output_camera_configuration.py | 6 +++--- .../form_builder_output_system_startup.py | 16 ++++++++-------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index 8c2c9a6..bbfd9de 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -259,7 +259,7 @@ def __init__( self, parent ): bSizer442.Add( self.exposure_min_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - bSizer442.AddSpacer( ( 10, 0), 1, wx.EXPAND, 5 ) + bSizer442.Add( ( 10, 0), 1, wx.EXPAND, 5 ) self.m_staticText4231 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Max:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText4231.Wrap( -1 ) @@ -294,7 +294,7 @@ def __init__( self, parent ): bSizer4421.Add( self.gain_min_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - bSizer4421.AddSpacer( ( 10, 0), 1, wx.EXPAND, 5 ) + bSizer4421.Add( ( 10, 0), 1, wx.EXPAND, 5 ) self.m_staticText42311 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Max:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText42311.Wrap( -1 ) @@ -494,7 +494,7 @@ def __init__( self, parent ): bSizer391.Add( self.nas_disk_space, 0, wx.TOP|wx.RIGHT|wx.LEFT, 5 ) - bSizer391.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) + bSizer391.Add( ( 0, 0), 1, wx.EXPAND, 5 ) self.flight_data_panel.SetSizer( bSizer391 ) @@ -535,7 +535,7 @@ def __init__( self, parent ): bSizer61.Add( self.camera_config_combo, 0, wx.ALL, 5 ) - bSizer61.AddSpacer( ( 20, 0), 1, wx.EXPAND, 5 ) + bSizer61.Add( ( 20, 0), 1, wx.EXPAND, 5 ) bSizer59.Add( bSizer61, 1, wx.ALIGN_CENTER_HORIZONTAL, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py index 4c48920..438462d 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py @@ -47,19 +47,19 @@ def __init__( self, parent ): bSizer9.Add( self.camera_config_combo, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) - bSizer9.AddSpacer( ( 20, 0), 1, wx.EXPAND, 5 ) + bSizer9.Add( ( 20, 0), 1, wx.EXPAND, 5 ) self.m_button4 = wx.Button( self.m_panel2, wx.ID_ANY, u"New", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer9.Add( self.m_button4, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) - bSizer9.AddSpacer( ( 20, 0), 1, wx.EXPAND, 5 ) + bSizer9.Add( ( 20, 0), 1, wx.EXPAND, 5 ) self.m_button41 = wx.Button( self.m_panel2, wx.ID_ANY, u"New from Current", wx.DefaultPosition, wx.Size( 150,-1 ), 0 ) bSizer9.Add( self.m_button41, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) - bSizer9.AddSpacer( ( 20, 0), 1, wx.EXPAND, 5 ) + bSizer9.Add( ( 20, 0), 1, wx.EXPAND, 5 ) self.m_button42 = wx.Button( self.m_panel2, wx.ID_ANY, u"Delete", wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer9.Add( self.m_button42, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_system_startup.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_system_startup.py index 59a643e..8f64463 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_system_startup.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_system_startup.py @@ -33,7 +33,7 @@ def __init__( self, parent ): gSizer1 = wx.GridSizer( 4, 3, 0, 0 ) - gSizer1.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) + gSizer1.Add( ( 0, 0), 1, wx.EXPAND, 5 ) self.m_staticText341 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Entire System", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText341.Wrap( -1 ) @@ -42,7 +42,7 @@ def __init__( self, parent ): gSizer1.Add( self.m_staticText341, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) - gSizer1.AddSpacer( ( 0, 0), 1, wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL, 5 ) + gSizer1.Add( ( 0, 0), 1, wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL, 5 ) self.m_button14211 = wx.Button( self.m_panel33, wx.ID_ANY, u"Start Entire System", wx.DefaultPosition, wx.DefaultSize, 0 ) gSizer1.Add( self.m_button14211, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) @@ -115,7 +115,7 @@ def __init__( self, parent ): gSizer11 = wx.GridSizer( 4, 3, 0, 0 ) - gSizer11.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) + gSizer11.Add( ( 0, 0), 1, wx.EXPAND, 5 ) self.m_staticText3411 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Left-View Computer (sys1)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText3411.Wrap( -1 ) @@ -124,7 +124,7 @@ def __init__( self, parent ): gSizer11.Add( self.m_staticText3411, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) - gSizer11.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) + gSizer11.Add( ( 0, 0), 1, wx.EXPAND, 5 ) bSizer101 = wx.BoxSizer( wx.VERTICAL ) @@ -191,7 +191,7 @@ def __init__( self, parent ): gSizer111 = wx.GridSizer( 4, 3, 0, 0 ) - gSizer111.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) + gSizer111.Add( ( 0, 0), 1, wx.EXPAND, 5 ) self.m_staticText34111 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Center-View Computer (sys0)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText34111.Wrap( -1 ) @@ -200,7 +200,7 @@ def __init__( self, parent ): gSizer111.Add( self.m_staticText34111, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) - gSizer111.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) + gSizer111.Add( ( 0, 0), 1, wx.EXPAND, 5 ) bSizer1011 = wx.BoxSizer( wx.VERTICAL ) @@ -267,7 +267,7 @@ def __init__( self, parent ): gSizer112 = wx.GridSizer( 4, 3, 0, 0 ) - gSizer112.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) + gSizer112.Add( ( 0, 0), 1, wx.EXPAND, 5 ) self.m_staticText34112 = wx.StaticText( self.m_panel33, wx.ID_ANY, u"Right-View Computer (sys2)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText34112.Wrap( -1 ) @@ -276,7 +276,7 @@ def __init__( self, parent ): gSizer112.Add( self.m_staticText34112, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) - gSizer112.AddSpacer( ( 0, 0), 1, wx.EXPAND, 5 ) + gSizer112.Add( ( 0, 0), 1, wx.EXPAND, 5 ) bSizer1012 = wx.BoxSizer( wx.VERTICAL ) From 7e62cbfe29c024cbde82ae1d6c42224932a50e3e Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 11:48:38 -0400 Subject: [PATCH 052/139] Make config conflict resolution a little more verbose / useful --- .../wxpython_gui/src/wxpython_gui/cfg.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py index 0f75f71..b7f914c 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py @@ -150,8 +150,13 @@ def save_config_settings(): # =================== FINISHED CAMERA CONFIG ======================= +# Tracks conflict paths already reported so the same divergence isn't logged +# once per merge pass (merge_two_dicts is called several times below). +_reported_conflicts = set() + + def merge_two_dicts(a, b, path=None): - "merges b into a" + "merges b into a; on a leaf conflict a's value is kept and b's is ignored" if path is None: path = [] for key in b: @@ -161,7 +166,13 @@ def merge_two_dicts(a, b, path=None): elif a[key] == b[key]: pass # same leaf value else: - print("Warning: conflict at %s" % ".".join(path + [str(key)])) + dotted = ".".join(path + [str(key)]) + if dotted not in _reported_conflicts: + _reported_conflicts.add(dotted) + print( + "Warning: config conflict at %s -> keeping %r, ignoring %r" + % (dotted, a[key], b[key]) + ) else: a[key] = b[key] return a From df7df2f9495d524ef4294596f0c340224c21108c Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 11:58:16 -0400 Subject: [PATCH 053/139] Numerous classic -> phoenix GUI fixes --- .../src/wxpython_gui/CameraConfiguration.py | 4 +- .../src/wxpython_gui/HotKeyList.py | 4 +- .../wxpython_gui/src/wxpython_gui/LogFrame.py | 6 +-- .../src/wxpython_gui/RemoteImagePanel.py | 8 ++-- .../form_builder_output.py | 8 ++-- ...orm_builder_output_camera_configuration.py | 2 +- .../form_builder_output_effort_metadata.py | 2 +- .../form_builder_output_event_log_note.py | 2 +- .../form_builder_output_imagery_inspection.py | 2 +- .../wxpython_gui/system_control_panel/gui.py | 39 ++++++++++++------- 10 files changed, 46 insertions(+), 31 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py index 3f3a38b..a9027fd 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py @@ -56,7 +56,7 @@ def update_combo(self, select_str=""): select_str - select this str after updating. """ # First cache which camera configuration is currently selected. - if select_str is "": + if select_str == "": select_str = self.camera_config_combo.GetStringSelection() self.camera_config_combo.SetEditable(True) @@ -300,7 +300,7 @@ def on_clear_right_pipe(self, event): def file_picker(self, wildcard='*'): dialog = wx.FileDialog(None, "Choose a file", SYS_CFG["nas_mnt"], '', - wildcard, wx.OPEN) + wildcard, wx.FD_OPEN) if dialog.ShowModal() == wx.ID_OK: file_path = dialog.GetPath() else: diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/HotKeyList.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/HotKeyList.py index 30dd36c..2812063 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/HotKeyList.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/HotKeyList.py @@ -13,7 +13,9 @@ def __init__(self, parent): # ----------------------------- Hot Keys ----------------------------- entries = [wx.AcceleratorEntry() for _ in range(1)] - random_id = wx.NewId() + random_id = wx.NewIdRef() + # Retain the id ref so its reserved id isn't recycled. + self._accel_id = random_id self.Bind(wx.EVT_MENU, self.on_cancel, id=random_id) entries[0].Set(wx.ACCEL_NORMAL, wx.WXK_ESCAPE, random_id) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/LogFrame.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/LogFrame.py index 415f4d6..40afe6c 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/LogFrame.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/LogFrame.py @@ -47,9 +47,9 @@ def add_message(self, msg_type, msg): tstamp = str(datetime.datetime.utcfromtimestamp(time.time())) #i = self.list_ctrl.GetItemCount() i = 0 - self.list_ctrl.InsertStringItem(i, tstamp) - self.list_ctrl.SetStringItem(i, 1, msg_type) - self.list_ctrl.SetStringItem(i, 2, msg) + self.list_ctrl.InsertItem(i, tstamp) + self.list_ctrl.SetItem(i, 1, msg_type) + self.list_ctrl.SetItem(i, 2, msg) def on_cancel(self, event=None): """when the 'cancel' button is selected. diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/RemoteImagePanel.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/RemoteImagePanel.py index 89dd89d..e55a123 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/RemoteImagePanel.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/RemoteImagePanel.py @@ -114,7 +114,7 @@ def update_all_if_needed(self): if self.raw_image is not None: #print('on_size') panel_width, panel_height = self.wx_panel.GetSize() - self.wx_image = wx.EmptyImage(panel_width, panel_height) + self.wx_image = wx.Image(panel_width, panel_height) self.update_homography() self.update_inverse_homography() self.warp_image() @@ -182,8 +182,8 @@ def warp_image(self): self.panel_image_height), flags=flags) - wx_image = wx.EmptyImage(self.panel_image_width, - self.panel_image_height) + wx_image = wx.Image(self.panel_image_width, + self.panel_image_height) try: wx_image.SetData(image.tobytes()) except ValueError as err: @@ -276,7 +276,7 @@ def on_paint(self, event=None): image = cv2.resize(self._histogram, dsize=(panel_width, panel_height), interpolation=cv2.INTER_NEAREST) - wx_image = wx.EmptyImage(panel_width, panel_height) + wx_image = wx.Image(panel_width, panel_height) wx_image.SetData(image.tobytes()) wx_histogram_bitmap = wx_image.ConvertToBitmap() diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index bbfd9de..72e43b7 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -186,7 +186,7 @@ def __init__( self, parent ): bSizer511.Add( self.m_staticText181713131, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT, 5 ) self.gnss_status_flag_txtctrl = wx.TextCtrl( self.ins_control_panel, wx.ID_ANY, u"not available", wx.DefaultPosition, wx.Size( -1,-1 ), wx.TE_CENTRE|wx.TE_READONLY ) - bSizer511.Add( self.gnss_status_flag_txtctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND|wx.BOTTOM|wx.RIGHT|wx.LEFT, 5 ) + bSizer511.Add( self.gnss_status_flag_txtctrl, 0, wx.EXPAND|wx.BOTTOM|wx.RIGHT|wx.LEFT, 5 ) bSizer18171313.Add( bSizer511, 1, wx.EXPAND, 5 ) @@ -515,7 +515,7 @@ def __init__( self, parent ): bSizer20.Add( self.m_panel7, 0, wx.EXPAND|wx.TOP, 5 ) - main_size.Add( bSizer20, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.ALL, 5 ) + main_size.Add( bSizer20, 0, wx.EXPAND|wx.ALL, 5 ) bsizer12 = wx.BoxSizer( wx.VERTICAL ) @@ -679,7 +679,7 @@ def __init__( self, parent ): self.m_panel_left_ir.SetSizer( left_bsizer1 ) self.m_panel_left_ir.Layout() left_bsizer1.Fit( self.m_panel_left_ir ) - middle_row_bSizer.Add( self.m_panel_left_ir, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 ) + middle_row_bSizer.Add( self.m_panel_left_ir, 1, wx.EXPAND, 5 ) self.m_panel_center_ir = wx.Panel( self.images_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) right_bsizer1 = wx.BoxSizer( wx.VERTICAL ) @@ -1064,7 +1064,7 @@ def __init__( self, parent ): self.SetMenuBar( self.m_menubar1 ) - self.m_status_bar = self.CreateStatusBar( 1, wx.ST_SIZEGRIP, wx.ID_ANY ) + self.m_status_bar = self.CreateStatusBar( 1, wx.STB_SIZEGRIP, wx.ID_ANY ) self.Centre( wx.BOTH ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py index 438462d..6f4a1ff 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py @@ -398,7 +398,7 @@ def __init__( self, parent ): self.configuration_notes_txt_ctrl = wx.TextCtrl( self.m_panel33, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE ) self.configuration_notes_txt_ctrl.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) - bSizer454.Add( self.configuration_notes_txt_ctrl, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5 ) + bSizer454.Add( self.configuration_notes_txt_ctrl, 1, wx.ALL|wx.EXPAND, 5 ) bSizer44.Add( bSizer454, 1, wx.EXPAND|wx.LEFT, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_effort_metadata.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_effort_metadata.py index 4a3b94e..114ad53 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_effort_metadata.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_effort_metadata.py @@ -101,7 +101,7 @@ def __init__( self, parent ): self.field_notes_textCtrl = wx.TextCtrl( self.m_panel33, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE ) self.field_notes_textCtrl.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) - bSizer454.Add( self.field_notes_textCtrl, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5 ) + bSizer454.Add( self.field_notes_textCtrl, 1, wx.ALL|wx.EXPAND, 5 ) bSizer44.Add( bSizer454, 1, wx.EXPAND, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_event_log_note.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_event_log_note.py index c22e048..c753f39 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_event_log_note.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_event_log_note.py @@ -59,7 +59,7 @@ def __init__( self, parent ): self.note_textCtrl = wx.TextCtrl( self.m_panel33, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE ) self.note_textCtrl.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) - bSizer454.Add( self.note_textCtrl, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5 ) + bSizer454.Add( self.note_textCtrl, 1, wx.ALL|wx.EXPAND, 5 ) bSizer44.Add( bSizer454, 1, wx.EXPAND, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_imagery_inspection.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_imagery_inspection.py index 7aa4f96..5af43ea 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_imagery_inspection.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_imagery_inspection.py @@ -119,7 +119,7 @@ def __init__( self, parent ): bSizer20.Add( self.m_panel7, 0, wx.EXPAND|wx.TOP, 5 ) - main_size.Add( bSizer20, 5, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.ALL, 5 ) + main_size.Add( bSizer20, 5, wx.EXPAND|wx.ALL, 5 ) bsizer12 = wx.BoxSizer( wx.VERTICAL ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 98bf178..17698bf 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -199,7 +199,7 @@ def __init__( # initialize parent class form_builder_output.MainFrame.__init__(self, parent) self.SetTitle(window_title) - icon = wx.EmptyIcon() + icon = wx.Icon() icon.CopyFromBitmap( wx.Bitmap( os.path.expanduser("~/noaa_kamera/src/cfg/seal-icon.png"), @@ -439,62 +439,75 @@ def __init__( # ----------------------------- Hot Keys ----------------------------- entries = [] + # Retain the id refs so their reserved ids aren't recycled (NewIdRef + # releases the id once the ref is garbage collected). + self._accel_ids = [] # Bind ctrl+s to start/stop recording. entries.append(wx.AcceleratorEntry()) - random_id = wx.NewId() + random_id = wx.NewIdRef() + self._accel_ids.append(random_id) self.Bind(wx.EVT_MENU, self.reverse_collecting_state, id=random_id) entries[-1].Set(wx.ACCEL_CTRL, ord("S"), random_id) # Bind ctrl+d to start detectors. entries.append(wx.AcceleratorEntry()) - random_id = wx.NewId() + random_id = wx.NewIdRef() + self._accel_ids.append(random_id) self.Bind(wx.EVT_MENU, self.on_start_detectors, id=random_id) entries[-1].Set(wx.ACCEL_CTRL, ord("D"), random_id) # Bind ctrl+f to stop detectors. entries.append(wx.AcceleratorEntry()) - random_id = wx.NewId() + random_id = wx.NewIdRef() + self._accel_ids.append(random_id) self.Bind(wx.EVT_MENU, self.on_stop_detectors, id=random_id) entries[-1].Set(wx.ACCEL_CTRL, ord("F"), random_id) # Bind ctrl+h to hot key menu. entries.append(wx.AcceleratorEntry()) - random_id = wx.NewId() + random_id = wx.NewIdRef() + self._accel_ids.append(random_id) self.Bind(wx.EVT_MENU, self.on_hot_key_help, id=random_id) entries[-1].Set(wx.ACCEL_CTRL, ord("H"), random_id) # Bind ctrl+e to set context to exposure entry. entries.append(wx.AcceleratorEntry()) - random_id = wx.NewId() + random_id = wx.NewIdRef() + self._accel_ids.append(random_id) self.Bind(wx.EVT_MENU, self.set_focus_to_exposure, id=random_id) entries[-1].Set(wx.ACCEL_CTRL, ord("E"), random_id) # Bind ctrl+n to add note to log. entries.append(wx.AcceleratorEntry()) - random_id = wx.NewId() + random_id = wx.NewIdRef() + self._accel_ids.append(random_id) self.Bind(wx.EVT_MENU, self.on_add_to_event_log, id=random_id) entries[-1].Set(wx.ACCEL_CTRL, ord("N"), random_id) # Bind ctrl+o to next previous camera configuration. entries.append(wx.AcceleratorEntry()) - random_id = wx.NewId() + random_id = wx.NewIdRef() + self._accel_ids.append(random_id) self.Bind(wx.EVT_MENU, self.previous_camera_config, id=random_id) entries[-1].Set(wx.ACCEL_CTRL, ord("O"), random_id) # Bind ctrl+p to next camera configuration. entries.append(wx.AcceleratorEntry()) - random_id = wx.NewId() + random_id = wx.NewIdRef() + self._accel_ids.append(random_id) self.Bind(wx.EVT_MENU, self.next_camera_config, id=random_id) entries[-1].Set(wx.ACCEL_CTRL, ord("P"), random_id) # Bind ctrl+i to next previous effort configuration. entries.append(wx.AcceleratorEntry()) - random_id = wx.NewId() + random_id = wx.NewIdRef() + self._accel_ids.append(random_id) self.Bind(wx.EVT_MENU, self.previous_effort_config, id=random_id) entries[-1].Set(wx.ACCEL_CTRL, ord("I"), random_id) # Bind ctrl+k to next effort configuration. entries.append(wx.AcceleratorEntry()) - random_id = wx.NewId() + random_id = wx.NewIdRef() + self._accel_ids.append(random_id) self.Bind(wx.EVT_MENU, self.next_effort_config, id=random_id) entries[-1].Set(wx.ACCEL_CTRL, ord("K"), random_id) @@ -1837,7 +1850,7 @@ def reverse_collecting_state(self, event=None): def load_camera_model(self, name, fname): wildcard = "Camera model (*.yaml)" dialog = wx.FileDialog( - None, "Choose a file", os.getcwd(), "", wildcard, wx.OPEN + None, "Choose a file", os.getcwd(), "", wildcard, wx.FD_OPEN ) if dialog.ShowModal() == wx.ID_OK: print(dialog.GetPath()) @@ -1846,7 +1859,7 @@ def load_camera_model(self, name, fname): def save_flight_summary(self, event=None): wildcard = "Camera model (*.yaml)" - dialog = wx.FileDialog(None, "Choose a file", "/mnt", "", wildcard, wx.SAVE) + dialog = wx.FileDialog(None, "Choose a file", "/mnt", "", wildcard, wx.FD_SAVE) if dialog.ShowModal() == wx.ID_OK: print(dialog.GetPath()) From 32aed5b3fd6a0af7457467e1c722ea7786995e3f Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 12:08:51 -0400 Subject: [PATCH 054/139] Move SSD / NAS checks to side thread so GUI doesn't hang, make hosts a subset based on SYSTEM_NAME --- .../wxpython_gui/system_control_panel/gui.py | 220 ++++++++++-------- 1 file changed, 126 insertions(+), 94 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 17698bf..826f4b7 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -223,7 +223,18 @@ def __init__( "flight_summary": "Flight Summary", } - self.hosts = sorted(SYS_CFG["arch"]["hosts"].keys()) + all_hosts = sorted(SYS_CFG["arch"]["hosts"].keys()) + # Only manage hosts belonging to the current system. Redis (/sys) can + # accumulate host entries from other systems (cas, nayak, ...); host + # names are suffixed with the system name, e.g. "center-0-taiga". + system_name = os.environ.get("SYSTEM_NAME") + if system_name: + self.hosts = [h for h in all_hosts if h.endswith("-" + system_name)] + else: + self.hosts = [] + if not self.hosts: + # Fall back to every host if the naming convention doesn't match. + self.hosts = all_hosts print("HOSTS: ") print(self.hosts) self.last_busy = {h: False for h in self.hosts} @@ -547,105 +558,126 @@ def __init__( # Add in pause before displaying imagery def system_sanity_check(self): - fails = 0 - unmounts = [] - nas_unmounts = [] - for host in self.hosts: - try: - diskinfo = requests.post( - "http://{}:8987/diskinfo".format(host), - data=SYS_CFG["local_ssd_mnt"], - timeout=0.1, - ) - except requests.exceptions.ConnectionError: - rospy.logwarn("Could not access disk info from system %s." % host) - continue - diskinfo = json.loads(diskinfo.text) - mounted = diskinfo["ismount"] - try: - if not mounted: - unmounts.append(host) - else: - if 0 == int(host[-1]): - self.center_sys_space_static_text.SetLabel( - "Disk Space: %0.2f GB" - % (float(diskinfo["bytes_free"]) / 1e9) - ) - self.center_sys_space_static_text.SetForegroundColour( - COLLECT_GREEN - ) - elif 1 == int(host[-1]): - self.left_sys_space_static_text.SetLabel( - "Disk Space: %0.2f GB" - % (float(diskinfo["bytes_free"]) / 1e9) - ) - self.left_sys_space_static_text.SetForegroundColour( - COLLECT_GREEN - ) + # Run the disk / NAS checks off the UI thread so unreachable hosts + # can't freeze the GUI. Skip if the previous check is still in flight. + if getattr(self, "_sanity_check_running", False): + return + self._sanity_check_running = True + worker = threading.Thread( + target=self._system_sanity_worker, args=(list(self.hosts),) + ) + worker.daemon = True + worker.start() + + def _system_sanity_worker(self, hosts): + """Background-thread network I/O for system_sanity_check. + + Collects results and marshals UI updates back onto the main thread via + wx.CallAfter. Every request has a timeout so an offline host can't hang + the check. + """ + timeout = 0.5 + ssd_mnt = SYS_CFG["local_ssd_mnt"] + nas_mnt = SYS_CFG["nas_mnt"] + try: + results = {} + unmounts = [] + nas_unmounts = [] + for host in hosts: + entry = {"ssd_gb": None, "ssd_err": False, "nas_gb": None} + try: + resp = requests.post( + "http://{}:8987/diskinfo".format(host), + data=ssd_mnt, + timeout=timeout, + ) + info = json.loads(resp.text) + if info["ismount"]: + entry["ssd_gb"] = float(info["bytes_free"]) / 1e9 else: - self.right_sys_space_static_text.SetLabel( - "Disk Space: %0.2f GB" - % (float(diskinfo["bytes_free"]) / 1e9) - ) - self.right_sys_space_static_text.SetForegroundColour( - COLLECT_GREEN - ) - except Exception as e: - rospy.logerr("Failed to connect to host {}: {}".format(host, e)) - return - try: - diskinfo = requests.post( - "http://{}:8987/diskinfo".format(host), - SYS_CFG["nas_mnt"], - timeout=0.1, + entry["ssd_err"] = True + unmounts.append(host) + except (requests.exceptions.RequestException, ValueError, KeyError): + rospy.logwarn( + "Could not access disk info from system %s." % host + ) + results[host] = entry + continue + try: + resp = requests.post( + "http://{}:8987/diskinfo".format(host), + data=nas_mnt, + timeout=timeout, + ) + info = json.loads(resp.text) + if info["ismount"]: + entry["nas_gb"] = float(info["bytes_free"]) / 1e9 + else: + nas_unmounts.append(host) + except (requests.exceptions.RequestException, ValueError, KeyError): + pass + results[host] = entry + + # Attempt to remount any host that responded but wasn't mounted. + if unmounts: + rospy.logerr( + "ERROR: One or more hosts has an ssd mount issue: {}".format( + unmounts + ) ) - diskinfo = json.loads(diskinfo.text) - # rospy.loginfo("{}: {}".format(host, diskinfo)) - mounted = diskinfo["ismount"] - if not mounted: - nas_unmounts.append(host) - else: - if 0 == int(host[-1]): - self.nas_disk_space.SetLabel( - "NAS Disk Space: %0.2f GB" - % (float(diskinfo["bytes_free"]) / 1e9) + for host in unmounts: + try: + requests.post( + "http://{}:8987/mountall".format(host), + data="/mnt/data", + timeout=timeout, ) - self.nas_disk_space.SetForegroundColour(COLLECT_GREEN) - except Exception as exc: - # rospy.logerr("unable to connect to host {}: {}".format(host, exc)) - fails += 1 - for host in unmounts: - if 0 == int(host[-1]): - self.center_sys_space_static_text.SetLabel("Disk Space: Err") - self.center_sys_space_static_text.SetForegroundColour(ERROR_RED) - elif 1 == int(host[-1]): - self.left_sys_space_static_text.SetLabel("Disk Space: Err") - self.left_sys_space_static_text.SetForegroundColour(ERROR_RED) - else: - self.right_sys_space_static_text.SetLabel("Disk Space: Err") - self.right_sys_space_static_text.SetForegroundColour(ERROR_RED) - if len(unmounts) > 0: - errmsg = "ERROR: One or more hosts has an sdd mount issue: {}\n".format( - unmounts - ) - rospy.logerr(errmsg) - for host in unmounts: - res = requests.post( - "http://{}:8987/mountall".format(host), data="/mnt/data" + except requests.exceptions.RequestException: + pass + if nas_unmounts: + rospy.logerr( + "ERROR: One or more hosts has a NAS mount issue: {}".format( + nas_unmounts + ) ) + for host in nas_unmounts: + try: + requests.post( + "http://{}:8987/mountall".format(host), + data=nas_mnt, + timeout=timeout, + ) + except requests.exceptions.RequestException: + pass - if len(nas_unmounts) > 0: - err_host_str = "NAS Err: " + "".join(nas_unmounts) - self.nas_disk_space.SetLabel(err_host_str) - self.nas_disk_space.SetForegroundColour(ERROR_RED) - errmsg = "ERROR: One or more hosts has an NAS mount issue: {}\n".format( - nas_unmounts - ) - rospy.logerr(errmsg) - for host in nas_unmounts: - res = requests.post( - "http://{}:8987/mountall".format(host), data=SYS_CFG["nas_mnt"] + wx.CallAfter(self._apply_system_sanity, results, nas_unmounts) + finally: + self._sanity_check_running = False + + def _apply_system_sanity(self, results, nas_unmounts): + """Apply system_sanity_check results to the UI (main thread only).""" + for host, entry in results.items(): + try: + fov = SYS_CFG["arch"]["hosts"][host]["fov"] + except KeyError: + continue + ssd_label = getattr(self, "{}_sys_space_static_text".format(fov), None) + if ssd_label is not None: + if entry["ssd_err"]: + ssd_label.SetLabel("Disk Space: Err") + ssd_label.SetForegroundColour(ERROR_RED) + elif entry["ssd_gb"] is not None: + ssd_label.SetLabel("Disk Space: %0.2f GB" % entry["ssd_gb"]) + ssd_label.SetForegroundColour(COLLECT_GREEN) + # The NAS is shared, so it's only displayed once (center host). + if fov == "center" and entry["nas_gb"] is not None: + self.nas_disk_space.SetLabel( + "NAS Disk Space: %0.2f GB" % entry["nas_gb"] ) + self.nas_disk_space.SetForegroundColour(COLLECT_GREEN) + if nas_unmounts: + self.nas_disk_space.SetLabel("NAS Err: " + "".join(nas_unmounts)) + self.nas_disk_space.SetForegroundColour(ERROR_RED) def on_modal_selection(self, event): self.on_camera_setting_subsys_selection(event) From 319301533d5234303ef31ddc8c71b4cdb1d1fbf5 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 12:13:53 -0400 Subject: [PATCH 055/139] Hopefully a resolution to our mysterious X Windows errors --- .../scripts/system_control_panel_node.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py b/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py index 03c632d..b115b83 100755 --- a/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py +++ b/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py @@ -37,6 +37,20 @@ from __future__ import division, print_function import os +# The GUI runs background threads (per-panel image fetchers, disk-status +# checks). Xlib must be told the client is multi-threaded *before* any X +# connection is opened, otherwise we get non-deterministic Xlib/xcb errors +# ("Unknown sequence number" / "XInitThreads has not been called"). This must +# happen before wx (and thus GTK/X11) is imported. +import ctypes +import ctypes.util + +try: + _x11 = ctypes.cdll.LoadLibrary(ctypes.util.find_library("X11") or "libX11.so") + _x11.XInitThreads() +except Exception as _exc: # pragma: no cover - non-fatal best effort + print("Warning: XInitThreads() failed: {}".format(_exc)) + import wx import rospy From 7135f2954b5202ee9756ea5159de0d16fa2d8738 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 12:19:10 -0400 Subject: [PATCH 056/139] Revert last commit, ipc:host seems like the actual solution --- compose/gui.yml | 1 + .../scripts/system_control_panel_node.py | 14 -------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/compose/gui.yml b/compose/gui.yml index 9da6f3c..51ba6dd 100644 --- a/compose/gui.yml +++ b/compose/gui.yml @@ -23,6 +23,7 @@ services: dns_search: - kamera.systems network_mode: host + ipc: host # fixes bad X Windows startups volumes: - "/mnt:/mnt" - "/tmp/.X11-unix:/tmp/.X11-unix" diff --git a/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py b/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py index b115b83..03c632d 100755 --- a/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py +++ b/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py @@ -37,20 +37,6 @@ from __future__ import division, print_function import os -# The GUI runs background threads (per-panel image fetchers, disk-status -# checks). Xlib must be told the client is multi-threaded *before* any X -# connection is opened, otherwise we get non-deterministic Xlib/xcb errors -# ("Unknown sequence number" / "XInitThreads has not been called"). This must -# happen before wx (and thus GTK/X11) is imported. -import ctypes -import ctypes.util - -try: - _x11 = ctypes.cdll.LoadLibrary(ctypes.util.find_library("X11") or "libX11.so") - _x11.XInitThreads() -except Exception as _exc: # pragma: no cover - non-fatal best effort - print("Warning: XInitThreads() failed: {}".format(_exc)) - import wx import rospy From 51d91ae8ced26de2d41d28d8ad88f1cd98dd08ec Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 12:31:21 -0400 Subject: [PATCH 057/139] Render font size after pane is created, to avoid clipping text --- .../src/wxpython_gui/CameraConfiguration.py | 3 +++ .../src/wxpython_gui/CollectionModeFrame.py | 3 +++ .../src/wxpython_gui/EventLogNoteFrame.py | 4 +++ .../src/wxpython_gui/HotKeyList.py | 3 +++ .../src/wxpython_gui/ImageInspectionFrame.py | 4 +++ .../wxpython_gui/src/wxpython_gui/LogFrame.py | 3 +++ .../src/wxpython_gui/MetadataEntryFrame.py | 3 +++ .../src/wxpython_gui/SystemStartup.py | 4 +++ .../wxpython_gui/system_control_panel/gui.py | 2 ++ .../system_control_panel/gui_utils.py | 26 +++++++++++++++++++ 10 files changed, 55 insertions(+) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py index a9027fd..39f902b 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py @@ -7,6 +7,7 @@ from wxpython_gui.camera_models import load_from_file import wxpython_gui.system_control_panel.form_builder_output_camera_configuration as fbocc from wxpython_gui.cfg import SYS_CFG, save_camera_config +from wxpython_gui.system_control_panel.gui_utils import unclip_static_text class CameraConfiguration(fbocc.MainFrame): """Defines how the cameras are layed out. @@ -22,6 +23,8 @@ def __init__(self, parent, """ # Initialize parent class fbocc.MainFrame.__init__(self, parent) + # Recompute enlarged title fonts so they are not clipped under Phoenix. + wx.CallAfter(unclip_static_text, self) self.parent = parent self.curr_cfg = sel_camera_config diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CollectionModeFrame.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CollectionModeFrame.py index f345937..276bb69 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CollectionModeFrame.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CollectionModeFrame.py @@ -3,6 +3,7 @@ import wx import wxpython_gui.system_control_panel.form_builder_output_collection_mode as form_builder_output_collection_mode from wxpython_gui.cfg import SYS_CFG, redis +from wxpython_gui.system_control_panel.gui_utils import unclip_static_text class CollectionModeFrame(form_builder_output_collection_mode.MainFrame): """. @@ -22,6 +23,8 @@ def __init__(self, parent, collection_mode, shapefile_fname, :type use_archive_region: Optional[bool] """ form_builder_output_collection_mode.MainFrame.__init__(self, parent) + # Recompute enlarged title fonts so they are not clipped under Phoenix. + wx.CallAfter(unclip_static_text, self) self.parent = parent self.shapefile_fname = shapefile_fname self.use_archive_region = int(use_archive_region) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/EventLogNoteFrame.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/EventLogNoteFrame.py index 9fdfc72..36f5e27 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/EventLogNoteFrame.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/EventLogNoteFrame.py @@ -1,4 +1,6 @@ +import wx import wxpython_gui.system_control_panel.form_builder_output_event_log_note as form_builder_output_event_log_note +from wxpython_gui.system_control_panel.gui_utils import unclip_static_text class EventLogNoteFrame(form_builder_output_event_log_note.MainFrame): """. @@ -10,6 +12,8 @@ def __init__(self, parent): """ # Initialize parent class form_builder_output_event_log_note.MainFrame.__init__(self, parent) + # Recompute enlarged title fonts so they are not clipped under Phoenix. + wx.CallAfter(unclip_static_text, self) self.parent = parent self.Show() self.SetMinSize(self.GetSize()) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/HotKeyList.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/HotKeyList.py index 2812063..4717b71 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/HotKeyList.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/HotKeyList.py @@ -1,5 +1,6 @@ import wx import wxpython_gui.system_control_panel.form_builder_output_hot_key_list as form_builder_output_hot_key_list +from wxpython_gui.system_control_panel.gui_utils import unclip_static_text class HotKeyList(form_builder_output_hot_key_list.MainFrame): @@ -25,6 +26,8 @@ def __init__(self, parent): self.Show() self.SetMinSize(self.GetSize()) + # Recompute enlarged title fonts so they are not clipped under Phoenix. + wx.CallAfter(unclip_static_text, self) def on_cancel(self, event=None): """When the 'Cancel' button is selected. diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py index d73ebb2..cf90338 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py @@ -2,6 +2,7 @@ import wxpython_gui.system_control_panel.form_builder_output_imagery_inspection as form_builder_output_imagery_inspection from wxpython_gui.FullAndZoomView import FullAndZoomView from wxpython_gui.cfg import SYS_CFG +from wxpython_gui.system_control_panel.gui_utils import unclip_static_text class ImageInspectionFrame(form_builder_output_imagery_inspection.MainFrame): @@ -45,6 +46,9 @@ def __init__(self, parent, topic_names, self.Bind(wx.EVT_CLOSE, self.when_closed) + # Recompute enlarged title fonts so they are not clipped under Phoenix. + wx.CallAfter(unclip_static_text, self) + def on_select_stream(self, event=None): if self.full_view_rp is not None: self.full_view_rp.release() diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/LogFrame.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/LogFrame.py index 40afe6c..9fa5336 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/LogFrame.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/LogFrame.py @@ -1,5 +1,6 @@ import wx import wxpython_gui.system_control_panel.form_builder_output_log_panel as form_builder_output_log_panel +from wxpython_gui.system_control_panel.gui_utils import unclip_static_text class LogFrame(form_builder_output_log_panel.MainFrame): @@ -42,6 +43,8 @@ def __init__(self, parent): self.Show() self.SetMinSize(self.GetSize()) + # Recompute enlarged title fonts so they are not clipped under Phoenix. + wx.CallAfter(unclip_static_text, self) def add_message(self, msg_type, msg): tstamp = str(datetime.datetime.utcfromtimestamp(time.time())) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/MetadataEntryFrame.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/MetadataEntryFrame.py index cece227..e7625b0 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/MetadataEntryFrame.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/MetadataEntryFrame.py @@ -1,6 +1,7 @@ import wx import wxpython_gui.system_control_panel.form_builder_output_effort_metadata as form_builder_output_effort_metadata from wxpython_gui.cfg import SYS_CFG +from wxpython_gui.system_control_panel.gui_utils import unclip_static_text class MetadataEntryFrame(form_builder_output_effort_metadata.MainFrame): @@ -28,6 +29,8 @@ def __init__( """ # Initialize parent class form_builder_output_effort_metadata.MainFrame.__init__(self, parent) + # Recompute enlarged title fonts so they are not clipped under Phoenix. + wx.CallAfter(unclip_static_text, self) self.parent = parent self.effort_metadata_dict = effort_metadata_dict self.effort_combo_box = effort_combo_box diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemStartup.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemStartup.py index aac07cb..b4434a9 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemStartup.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemStartup.py @@ -1,4 +1,6 @@ +import wx import wxpython_gui.system_control_panel.form_builder_output_system_startup as form_builder_output_system_startup +from wxpython_gui.system_control_panel.gui_utils import unclip_static_text class SystemStartup(form_builder_output_system_startup.MainFrame): @@ -8,6 +10,8 @@ def __init__(self, parent, system): """ # Initialize parent class form_builder_output_system_startup.MainFrame.__init__(self, parent) + # Recompute enlarged title fonts so they are not clipped under Phoenix. + wx.CallAfter(unclip_static_text, self) # Store the function that allow us to send logging requests. self.add_to_event_log = parent.add_to_event_log diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 826f4b7..dc23295 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -199,6 +199,8 @@ def __init__( # initialize parent class form_builder_output.MainFrame.__init__(self, parent) self.SetTitle(window_title) + # Recompute enlarged title fonts so they are not clipped under Phoenix. + wx.CallAfter(gui_utils.unclip_static_text, self) icon = wx.Icon() icon.CopyFromBitmap( wx.Bitmap( diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui_utils.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui_utils.py index 6cd01a4..e2df69f 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui_utils.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui_utils.py @@ -4,6 +4,32 @@ import os import errno +import wx + + +def unclip_static_text(window): + """Recompute StaticText best sizes so enlarged fonts are not clipped. + + wxFormBuilder enlarges title fonts *after* the StaticText controls are + created, so under wxPython Phoenix/GTK the labels keep a best size computed + with the original (smaller) font and the enlarged text gets clipped. Walk + the window's child controls, recompute each label's best size with its + final font, and re-layout. Should be invoked once the frame has been + realized (e.g. via ``wx.CallAfter``). + + :param window: Top-level window (frame/panel) to fix up. + :type window: wx.Window + """ + def _walk(parent): + for child in parent.GetChildren(): + if isinstance(child, wx.StaticText): + child.InvalidateBestSize() + child.SetMinSize(child.GetBestSize()) + _walk(child) + + _walk(window) + window.Layout() + def make_path(path, from_file=False, verbose=False): """ Make a path, ignoring already-exists error. Python 2/3 compliant. From eb4019fa324d9a681510c0e53fbe54e52a4fce8c Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 12:39:54 -0400 Subject: [PATCH 058/139] More scaling / unsquishing fixes for buttons and panels --- .../form_builder_output.py | 23 ++++++++++++----- .../wxpython_gui/system_control_panel/gui.py | 25 ++++++++++++++++++- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index 72e43b7..25e2146 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -9,6 +9,7 @@ import wx import wx.xrc +import wx.lib.scrolledpanel as scrolledpanel ID_START_DETECTOR_SYS0_CENTER = 1000 ID_START_DETECTOR_SYS1_LEFT = 1001 @@ -35,7 +36,13 @@ def __init__( self, parent ): bSizer20 = wx.BoxSizer( wx.VERTICAL ) - self.ins_control_panel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) + # The left control column can be taller than the work area on smaller + # (e.g. 1920x1080) displays. Host it in a scrolled panel so the controls + # keep their natural size and a vertical scrollbar appears only when the + # column does not fully fit, instead of squishing the bottom rows. + self.left_scroll_panel = scrolledpanel.ScrolledPanel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + + self.ins_control_panel = wx.Panel( self.left_scroll_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) bSizer191 = wx.BoxSizer( wx.VERTICAL ) self.m_staticText142 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Navigation Data", wx.DefaultPosition, wx.DefaultSize, 0 ) @@ -214,7 +221,7 @@ def __init__( self, parent ): bSizer191.Fit( self.ins_control_panel ) bSizer20.Add( self.ins_control_panel, 0, wx.EXPAND|wx.BOTTOM, 5 ) - self.camera_panel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) + self.camera_panel = wx.Panel( self.left_scroll_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) m_staticText14211 = wx.BoxSizer( wx.VERTICAL ) self.m_staticText142111 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Camera Settings", wx.DefaultPosition, wx.DefaultSize, 0 ) @@ -346,7 +353,7 @@ def __init__( self, parent ): m_staticText14211.Fit( self.camera_panel ) bSizer20.Add( self.camera_panel, 0, wx.EXPAND|wx.BOTTOM, 5 ) - self.flight_data_panel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) + self.flight_data_panel = wx.Panel( self.left_scroll_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) bSizer391 = wx.BoxSizer( wx.VERTICAL ) self.m_staticText14211 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"Data Collection", wx.DefaultPosition, wx.DefaultSize, 0 ) @@ -482,7 +489,7 @@ def __init__( self, parent ): bSizer443.Add( self.stop_detectors_button, 0, wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM|wx.RIGHT|wx.LEFT, 5 ) - bSizer391.Add( bSizer443, 1, wx.EXPAND, 5 ) + bSizer391.Add( bSizer443, 0, wx.EXPAND, 5 ) self.m_staticline13 = wx.StaticLine( self.flight_data_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) bSizer391.Add( self.m_staticline13, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) @@ -502,7 +509,7 @@ def __init__( self, parent ): bSizer391.Fit( self.flight_data_panel ) bSizer20.Add( self.flight_data_panel, 1, wx.EXPAND, 5 ) - self.m_panel7 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) + self.m_panel7 = wx.Panel( self.left_scroll_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) bSizer17 = wx.BoxSizer( wx.VERTICAL ) self.close_button = wx.Button( self.m_panel7, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.Size( -1,-1 ), 0 ) @@ -515,7 +522,11 @@ def __init__( self, parent ): bSizer20.Add( self.m_panel7, 0, wx.EXPAND|wx.TOP, 5 ) - main_size.Add( bSizer20, 0, wx.EXPAND|wx.ALL, 5 ) + self.left_scroll_panel.SetSizer( bSizer20 ) + self.left_scroll_panel.Layout() + self.left_scroll_panel.SetupScrolling( scroll_x = False, scroll_y = True ) + + main_size.Add( self.left_scroll_panel, 0, wx.EXPAND|wx.ALL, 5 ) bsizer12 = wx.BoxSizer( wx.VERTICAL ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index dc23295..db05a4b 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -552,13 +552,36 @@ def __init__( self.delay = 0 self.Show() print(self.GetSize()) - self.SetMinSize((1500, 980)) + self._fit_to_display() # self.detector_gauge.Hide() if self.collecting: self._disable_state_controls() # Add in pause before displaying imagery + def _fit_to_display(self): + """Keep the window within the usable area of its display. + + On smaller monitors (e.g. 1920x1080) the design size is taller than the + work area, which pushes the bottom of the side panel (detector / + archiving controls, Close button) off-screen. Clamp the window size and + position to the display's client area, and cap the minimum size so the + window can always be shrunk to fit. + """ + idx = wx.Display.GetFromWindow(self) + if idx == wx.NOT_FOUND: + idx = 0 + area = wx.Display(idx).GetClientArea() + + min_w = min(1500, area.width) + min_h = min(980, area.height) + self.SetMinSize((min_w, min_h)) + + w, h = self.GetSize() + self.SetSize(min(w, area.width), min(h, area.height)) + self.SetPosition((area.x, area.y)) + self.Layout() + def system_sanity_check(self): # Run the disk / NAS checks off the UI thread so unreachable hosts # can't freeze the GUI. Skip if the previous check is still in flight. From 5f825aedc01f801665472b17c68a760d4e57701a Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 12:47:40 -0400 Subject: [PATCH 059/139] Split INS data into 2 columns for vertical space savings --- .../form_builder_output.py | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index 25e2146..659bec3 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -63,12 +63,13 @@ def __init__( self, parent ): bSizer181.Add( self.m_staticText181, 0, wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM|wx.RIGHT|wx.LEFT, 5 ) self.lat_txtctrl = wx.TextCtrl( self.ins_control_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_CENTRE|wx.TE_READONLY ) - self.lat_txtctrl.SetMinSize( wx.Size( 180,-1 ) ) + self.lat_txtctrl.SetMinSize( wx.Size( 120,-1 ) ) bSizer181.Add( self.lat_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - bSizer191.Add( bSizer181, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, 5 ) + ins_row_a = wx.BoxSizer( wx.HORIZONTAL ) + ins_row_a.Add( bSizer181, 1, wx.EXPAND, 5 ) bSizer1811 = wx.BoxSizer( wx.HORIZONTAL ) @@ -82,7 +83,9 @@ def __init__( self, parent ): bSizer1811.Add( self.lon_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - bSizer191.Add( bSizer1811, 0, wx.EXPAND, 5 ) + ins_row_a.Add( bSizer1811, 1, wx.EXPAND, 5 ) + + bSizer191.Add( ins_row_a, 0, wx.EXPAND, 5 ) bSizer1812 = wx.BoxSizer( wx.HORIZONTAL ) @@ -96,7 +99,8 @@ def __init__( self, parent ): bSizer1812.Add( self.alt_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - bSizer191.Add( bSizer1812, 0, wx.EXPAND, 5 ) + ins_row_b = wx.BoxSizer( wx.HORIZONTAL ) + ins_row_b.Add( bSizer1812, 1, wx.EXPAND, 5 ) bSizer18121 = wx.BoxSizer( wx.HORIZONTAL ) @@ -110,7 +114,9 @@ def __init__( self, parent ): bSizer18121.Add( self.alt_msl_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - bSizer191.Add( bSizer18121, 1, wx.EXPAND, 5 ) + ins_row_b.Add( bSizer18121, 1, wx.EXPAND, 5 ) + + bSizer191.Add( ins_row_b, 0, wx.EXPAND, 5 ) bSizer18191 = wx.BoxSizer( wx.HORIZONTAL ) @@ -124,7 +130,8 @@ def __init__( self, parent ): bSizer18191.Add( self.speed_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - bSizer191.Add( bSizer18191, 1, wx.EXPAND, 5 ) + ins_row_c = wx.BoxSizer( wx.HORIZONTAL ) + ins_row_c.Add( bSizer18191, 1, wx.EXPAND, 5 ) bSizer1819 = wx.BoxSizer( wx.HORIZONTAL ) @@ -138,7 +145,9 @@ def __init__( self, parent ): bSizer1819.Add( self.heading_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - bSizer191.Add( bSizer1819, 0, wx.EXPAND, 5 ) + ins_row_c.Add( bSizer1819, 1, wx.EXPAND, 5 ) + + bSizer191.Add( ins_row_c, 0, wx.EXPAND, 5 ) bSizer1818 = wx.BoxSizer( wx.HORIZONTAL ) @@ -152,7 +161,8 @@ def __init__( self, parent ): bSizer1818.Add( self.pitch_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - bSizer191.Add( bSizer1818, 0, wx.EXPAND, 5 ) + ins_row_d = wx.BoxSizer( wx.HORIZONTAL ) + ins_row_d.Add( bSizer1818, 1, wx.EXPAND, 5 ) bSizer1817 = wx.BoxSizer( wx.HORIZONTAL ) @@ -166,7 +176,9 @@ def __init__( self, parent ): bSizer1817.Add( self.roll_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - bSizer191.Add( bSizer1817, 0, wx.EXPAND, 5 ) + ins_row_d.Add( bSizer1817, 1, wx.EXPAND, 5 ) + + bSizer191.Add( ins_row_d, 0, wx.EXPAND, 5 ) bSizer1817131 = wx.BoxSizer( wx.HORIZONTAL ) From 5ef845695af81e6d2697c38303c24c26e5ecce35 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 12:49:13 -0400 Subject: [PATCH 060/139] Increase width for camera dropdown, make about dialog open --- .../system_control_panel/form_builder_output.py | 8 +++++--- .../src/wxpython_gui/system_control_panel/gui.py | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index 659bec3..aed1e96 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -247,15 +247,17 @@ def __init__( self, parent ): camera_setting_rgb_uv_comboChoices = [ u"RGB", u"IR", u"UV" ] self.camera_setting_rgb_uv_combo = wx.ComboBox( self.camera_panel, wx.ID_ANY, u"RGB", wx.DefaultPosition, wx.DefaultSize, camera_setting_rgb_uv_comboChoices, wx.CB_READONLY ) self.camera_setting_rgb_uv_combo.SetSelection( 0 ) - bSizer55.Add( self.camera_setting_rgb_uv_combo, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + self.camera_setting_rgb_uv_combo.SetMinSize( wx.Size( 80, -1 ) ) + bSizer55.Add( self.camera_setting_rgb_uv_combo, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT|wx.EXPAND, 5 ) camera_setting_subsysChoices = [ u"Left", u"Center", u"Right", u"All" ] self.camera_setting_subsys = wx.ComboBox( self.camera_panel, wx.ID_ANY, u"Right", wx.DefaultPosition, wx.DefaultSize, camera_setting_subsysChoices, wx.CB_READONLY ) self.camera_setting_subsys.SetSelection( 3 ) - bSizer55.Add( self.camera_setting_subsys, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + self.camera_setting_subsys.SetMinSize( wx.Size( 100, -1 ) ) + bSizer55.Add( self.camera_setting_subsys, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT|wx.EXPAND, 5 ) - m_staticText14211.Add( bSizer55, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) + m_staticText14211.Add( bSizer55, 0, wx.EXPAND, 5 ) self.m_staticline5 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline5, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index db05a4b..269e9f7 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -24,6 +24,7 @@ # GUI imports import wx +import wx.adv from wx.lib.wordwrap import wordwrap # Vision / math @@ -2201,7 +2202,7 @@ def on_hot_key_help(self, event=None): def on_menu_item_about(self, event): about_panel = wx.Panel(self, wx.ID_ANY) - info = wx.AboutDialogInfo() + info = wx.adv.AboutDialogInfo() info.Name = "KAMERA System Control Panel" info.Version = "2.0.0" info.Copyright = "(C) 2023 Kitware" @@ -2213,8 +2214,7 @@ def on_menu_item_about(self, event): info.WebSite = ("http://www.kitware.com", "Kitware") info.Developers = ["Matt Brown, Adam Romlein, Mike McDermott"] info.License = wordwrap(LICENSE_STR, 500, wx.ClientDC(about_panel)) - # Show the wx.AboutBox - wx.AboutBox(info) + wx.adv.AboutBox(info) # ------------------------------------------------------------------------ From b69a92413dedf62de764fb143c9d16edd3f0971d Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 12:53:49 -0400 Subject: [PATCH 061/139] Squeeze vertical block --- .../form_builder_output.py | 111 +++++++++--------- 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index aed1e96..1081a5d 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -34,12 +34,10 @@ def __init__( self, parent ): main_size = wx.BoxSizer( wx.HORIZONTAL ) + left_column = wx.BoxSizer( wx.VERTICAL ) bSizer20 = wx.BoxSizer( wx.VERTICAL ) - # The left control column can be taller than the work area on smaller - # (e.g. 1920x1080) displays. Host it in a scrolled panel so the controls - # keep their natural size and a vertical scrollbar appears only when the - # column does not fully fit, instead of squishing the bottom rows. + # Scrollable region for the left control panels; Close stays pinned below. self.left_scroll_panel = scrolledpanel.ScrolledPanel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) self.ins_control_panel = wx.Panel( self.left_scroll_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) @@ -47,7 +45,7 @@ def __init__( self, parent ): self.m_staticText142 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Navigation Data", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText142.Wrap( -1 ) - self.m_staticText142.SetFont( wx.Font( 16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) + self.m_staticText142.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer191.Add( self.m_staticText142, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT, 5 ) @@ -182,82 +180,83 @@ def __init__( self, parent ): bSizer1817131 = wx.BoxSizer( wx.HORIZONTAL ) - self.m_staticText1817131 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Time (s)", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText1817131 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Time", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText1817131.Wrap( -1 ) self.m_staticText1817131.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - bSizer1817131.Add( self.m_staticText1817131, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + bSizer1817131.Add( self.m_staticText1817131, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 2 ) self.ins_time_txtctrl = wx.TextCtrl( self.ins_control_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_CENTRE|wx.TE_READONLY ) - bSizer1817131.Add( self.ins_time_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) + bSizer1817131.Add( self.ins_time_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 2 ) - bSizer191.Add( bSizer1817131, 0, wx.EXPAND, 5 ) - bSizer18171313 = wx.BoxSizer( wx.HORIZONTAL ) - bSizer511 = wx.BoxSizer( wx.VERTICAL ) + bSizer18171313.Add( bSizer1817131, 1, wx.EXPAND, 2 ) + + bSizer511 = wx.BoxSizer( wx.HORIZONTAL ) - self.m_staticText181713131 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"GNSS Status", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText181713131 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"GNSS", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText181713131.Wrap( -1 ) self.m_staticText181713131.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - bSizer511.Add( self.m_staticText181713131, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT, 5 ) + bSizer511.Add( self.m_staticText181713131, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 2 ) self.gnss_status_flag_txtctrl = wx.TextCtrl( self.ins_control_panel, wx.ID_ANY, u"not available", wx.DefaultPosition, wx.Size( -1,-1 ), wx.TE_CENTRE|wx.TE_READONLY ) - bSizer511.Add( self.gnss_status_flag_txtctrl, 0, wx.EXPAND|wx.BOTTOM|wx.RIGHT|wx.LEFT, 5 ) + bSizer511.Add( self.gnss_status_flag_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 2 ) - bSizer18171313.Add( bSizer511, 1, wx.EXPAND, 5 ) + bSizer18171313.Add( bSizer511, 1, wx.EXPAND, 2 ) - bSizer51 = wx.BoxSizer( wx.VERTICAL ) + bSizer51 = wx.BoxSizer( wx.HORIZONTAL ) - self.m_staticText18171313 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Align Status", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText18171313 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Align", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText18171313.Wrap( -1 ) self.m_staticText18171313.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - bSizer51.Add( self.m_staticText18171313, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT, 5 ) + bSizer51.Add( self.m_staticText18171313, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 2 ) self.ins_status_flag_txtctrl = wx.TextCtrl( self.ins_control_panel, wx.ID_ANY, u"unknown", wx.DefaultPosition, wx.Size( 120,-1 ), wx.TE_CENTRE|wx.TE_READONLY ) - bSizer51.Add( self.ins_status_flag_txtctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL|wx.BOTTOM|wx.RIGHT|wx.LEFT, 5 ) + bSizer51.Add( self.ins_status_flag_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 2 ) - bSizer18171313.Add( bSizer51, 0, wx.EXPAND, 5 ) + bSizer18171313.Add( bSizer51, 1, wx.EXPAND, 2 ) - bSizer191.Add( bSizer18171313, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5 ) + bSizer191.Add( bSizer18171313, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 2 ) self.ins_control_panel.SetSizer( bSizer191 ) self.ins_control_panel.Layout() bSizer191.Fit( self.ins_control_panel ) - bSizer20.Add( self.ins_control_panel, 0, wx.EXPAND|wx.BOTTOM, 5 ) + bSizer20.Add( self.ins_control_panel, 0, wx.EXPAND|wx.BOTTOM, 3 ) self.camera_panel = wx.Panel( self.left_scroll_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) m_staticText14211 = wx.BoxSizer( wx.VERTICAL ) self.m_staticText142111 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Camera Settings", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText142111.Wrap( -1 ) - self.m_staticText142111.SetFont( wx.Font( 16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) + self.m_staticText142111.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) m_staticText14211.Add( self.m_staticText142111, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT, 5 ) bSizer55 = wx.BoxSizer( wx.HORIZONTAL ) camera_setting_rgb_uv_comboChoices = [ u"RGB", u"IR", u"UV" ] - self.camera_setting_rgb_uv_combo = wx.ComboBox( self.camera_panel, wx.ID_ANY, u"RGB", wx.DefaultPosition, wx.DefaultSize, camera_setting_rgb_uv_comboChoices, wx.CB_READONLY ) + self.camera_setting_rgb_uv_combo = wx.ComboBox( self.camera_panel, wx.ID_ANY, u"RGB", wx.DefaultPosition, wx.Size( 70,-1 ), camera_setting_rgb_uv_comboChoices, wx.CB_READONLY ) self.camera_setting_rgb_uv_combo.SetSelection( 0 ) - self.camera_setting_rgb_uv_combo.SetMinSize( wx.Size( 80, -1 ) ) - bSizer55.Add( self.camera_setting_rgb_uv_combo, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT|wx.EXPAND, 5 ) + bSizer55.Add( self.camera_setting_rgb_uv_combo, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + + + bSizer55.Add( ( 10, 0), 1, wx.EXPAND, 5 ) camera_setting_subsysChoices = [ u"Left", u"Center", u"Right", u"All" ] - self.camera_setting_subsys = wx.ComboBox( self.camera_panel, wx.ID_ANY, u"Right", wx.DefaultPosition, wx.DefaultSize, camera_setting_subsysChoices, wx.CB_READONLY ) + self.camera_setting_subsys = wx.ComboBox( self.camera_panel, wx.ID_ANY, u"Right", wx.DefaultPosition, wx.Size( 70,-1 ), camera_setting_subsysChoices, wx.CB_READONLY ) self.camera_setting_subsys.SetSelection( 3 ) - self.camera_setting_subsys.SetMinSize( wx.Size( 100, -1 ) ) - bSizer55.Add( self.camera_setting_subsys, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT|wx.EXPAND, 5 ) + bSizer55.Add( self.camera_setting_subsys, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - m_staticText14211.Add( bSizer55, 0, wx.EXPAND, 5 ) + m_staticText14211.Add( bSizer55, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) self.m_staticline5 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline5, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) @@ -351,28 +350,33 @@ def __init__( self, parent ): m_staticText14211.Add( bSizer442111, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.BOTTOM, 5 ) + camera_buttons_row = wx.BoxSizer( wx.HORIZONTAL ) + self.m_button10 = wx.Button( self.camera_panel, wx.ID_ANY, u"Set Camera Parameter", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_button10.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - m_staticText14211.Add( self.m_button10, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT, 5 ) + camera_buttons_row.Add( self.m_button10, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 3 ) self.m_manual_ir_nuc = wx.Button( self.camera_panel, wx.ID_ANY, u"Manual IR NUC", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_manual_ir_nuc.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - m_staticText14211.Add( self.m_manual_ir_nuc, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT, 5 ) + camera_buttons_row.Add( self.m_manual_ir_nuc, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 3 ) + + + m_staticText14211.Add( camera_buttons_row, 0, wx.ALIGN_CENTER_HORIZONTAL, 3 ) self.camera_panel.SetSizer( m_staticText14211 ) self.camera_panel.Layout() m_staticText14211.Fit( self.camera_panel ) - bSizer20.Add( self.camera_panel, 0, wx.EXPAND|wx.BOTTOM, 5 ) + bSizer20.Add( self.camera_panel, 0, wx.EXPAND|wx.BOTTOM, 3 ) self.flight_data_panel = wx.Panel( self.left_scroll_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) bSizer391 = wx.BoxSizer( wx.VERTICAL ) self.m_staticText14211 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"Data Collection", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText14211.Wrap( -1 ) - self.m_staticText14211.SetFont( wx.Font( 16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) + self.m_staticText14211.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) bSizer391.Add( self.m_staticText14211, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT, 5 ) @@ -431,7 +435,8 @@ def __init__( self, parent ): bSizer45.Add( self.flight_number_text_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - bSizer42.Add( bSizer45, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, 5 ) + flight_observer_row = wx.BoxSizer( wx.HORIZONTAL ) + flight_observer_row.Add( bSizer45, 1, wx.EXPAND, 2 ) bSizer451 = wx.BoxSizer( wx.HORIZONTAL ) @@ -445,18 +450,15 @@ def __init__( self, parent ): bSizer451.Add( self.observer_text_ctrl, 1, wx.RIGHT|wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5 ) - bSizer42.Add( bSizer451, 1, wx.EXPAND, 5 ) - + flight_observer_row.Add( bSizer451, 1, wx.EXPAND, 2 ) - bSizer41.Add( bSizer42, 1, wx.EXPAND, 5 ) + bSizer42.Add( flight_observer_row, 0, wx.EXPAND, 2 ) - bSizer391.Add( bSizer41, 0, wx.EXPAND, 5 ) - - bSizer401 = wx.BoxSizer( wx.HORIZONTAL ) + bSizer41.Add( bSizer42, 1, wx.EXPAND, 5 ) - bSizer391.Add( bSizer401, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) + bSizer391.Add( bSizer41, 0, wx.EXPAND, 3 ) self.m_staticline3 = wx.StaticLine( self.flight_data_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) bSizer391.Add( self.m_staticline3, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) @@ -512,35 +514,34 @@ def __init__( self, parent ): self.nas_disk_space.Wrap( -1 ) self.nas_disk_space.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - bSizer391.Add( self.nas_disk_space, 0, wx.TOP|wx.RIGHT|wx.LEFT, 5 ) - - - bSizer391.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + bSizer391.Add( self.nas_disk_space, 0, wx.TOP|wx.RIGHT|wx.LEFT, 3 ) self.flight_data_panel.SetSizer( bSizer391 ) self.flight_data_panel.Layout() bSizer391.Fit( self.flight_data_panel ) - bSizer20.Add( self.flight_data_panel, 1, wx.EXPAND, 5 ) + bSizer20.Add( self.flight_data_panel, 0, wx.EXPAND, 3 ) + - self.m_panel7 = wx.Panel( self.left_scroll_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) + self.left_scroll_panel.SetSizer( bSizer20 ) + self.left_scroll_panel.Layout() + self.left_scroll_panel.SetupScrolling( scroll_x = False, scroll_y = True ) + + self.m_panel7 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) bSizer17 = wx.BoxSizer( wx.VERTICAL ) self.close_button = wx.Button( self.m_panel7, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.Size( -1,-1 ), 0 ) - bSizer17.Add( self.close_button, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) + bSizer17.Add( self.close_button, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 3 ) self.m_panel7.SetSizer( bSizer17 ) self.m_panel7.Layout() bSizer17.Fit( self.m_panel7 ) - bSizer20.Add( self.m_panel7, 0, wx.EXPAND|wx.TOP, 5 ) - - self.left_scroll_panel.SetSizer( bSizer20 ) - self.left_scroll_panel.Layout() - self.left_scroll_panel.SetupScrolling( scroll_x = False, scroll_y = True ) + left_column.Add( self.left_scroll_panel, 1, wx.EXPAND, 0 ) + left_column.Add( self.m_panel7, 0, wx.EXPAND|wx.TOP, 3 ) - main_size.Add( self.left_scroll_panel, 0, wx.EXPAND|wx.ALL, 5 ) + main_size.Add( left_column, 0, wx.EXPAND|wx.ALL, 5 ) bsizer12 = wx.BoxSizer( wx.VERTICAL ) From f3de197b98a7c36a2c5cd5b8db3a4ef079f2a36c Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 13:02:04 -0400 Subject: [PATCH 062/139] More spacing adjustments. --- .../form_builder_output.py | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index 1081a5d..9e5f033 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -180,19 +180,19 @@ def __init__( self, parent ): bSizer1817131 = wx.BoxSizer( wx.HORIZONTAL ) - self.m_staticText1817131 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Time", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText1817131 = wx.StaticText( self.ins_control_panel, wx.ID_ANY, u"Time (s)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText1817131.Wrap( -1 ) self.m_staticText1817131.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - bSizer1817131.Add( self.m_staticText1817131, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 2 ) + bSizer1817131.Add( self.m_staticText1817131, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) self.ins_time_txtctrl = wx.TextCtrl( self.ins_control_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_CENTRE|wx.TE_READONLY ) - bSizer1817131.Add( self.ins_time_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 2 ) + bSizer1817131.Add( self.ins_time_txtctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - bSizer18171313 = wx.BoxSizer( wx.HORIZONTAL ) + bSizer191.Add( bSizer1817131, 0, wx.EXPAND, 5 ) - bSizer18171313.Add( bSizer1817131, 1, wx.EXPAND, 2 ) + bSizer18171313 = wx.BoxSizer( wx.HORIZONTAL ) bSizer511 = wx.BoxSizer( wx.HORIZONTAL ) @@ -243,7 +243,7 @@ def __init__( self, parent ): bSizer55 = wx.BoxSizer( wx.HORIZONTAL ) camera_setting_rgb_uv_comboChoices = [ u"RGB", u"IR", u"UV" ] - self.camera_setting_rgb_uv_combo = wx.ComboBox( self.camera_panel, wx.ID_ANY, u"RGB", wx.DefaultPosition, wx.Size( 70,-1 ), camera_setting_rgb_uv_comboChoices, wx.CB_READONLY ) + self.camera_setting_rgb_uv_combo = wx.ComboBox( self.camera_panel, wx.ID_ANY, u"RGB", wx.DefaultPosition, wx.Size( 90,-1 ), camera_setting_rgb_uv_comboChoices, wx.CB_READONLY ) self.camera_setting_rgb_uv_combo.SetSelection( 0 ) bSizer55.Add( self.camera_setting_rgb_uv_combo, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) @@ -251,7 +251,7 @@ def __init__( self, parent ): bSizer55.Add( ( 10, 0), 1, wx.EXPAND, 5 ) camera_setting_subsysChoices = [ u"Left", u"Center", u"Right", u"All" ] - self.camera_setting_subsys = wx.ComboBox( self.camera_panel, wx.ID_ANY, u"Right", wx.DefaultPosition, wx.Size( 70,-1 ), camera_setting_subsysChoices, wx.CB_READONLY ) + self.camera_setting_subsys = wx.ComboBox( self.camera_panel, wx.ID_ANY, u"Right", wx.DefaultPosition, wx.Size( 90,-1 ), camera_setting_subsysChoices, wx.CB_READONLY ) self.camera_setting_subsys.SetSelection( 3 ) bSizer55.Add( self.camera_setting_subsys, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) @@ -339,31 +339,26 @@ def __init__( self, parent ): bSizer44211.Add( self.txtNUC, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 5 ) - self.ir_nuc_time = wx.TextCtrl( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 80,-1 ), wx.TE_CENTRE ) - bSizer44211.Add( self.ir_nuc_time, 1, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + self.ir_nuc_time = wx.TextCtrl( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 60,-1 ), wx.TE_CENTRE ) + bSizer44211.Add( self.ir_nuc_time, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - m_staticText14211.Add( bSizer44211, 1, wx.EXPAND, 5 ) + m_staticText14211.Add( bSizer44211, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP, 12 ) bSizer442111 = wx.BoxSizer( wx.HORIZONTAL ) m_staticText14211.Add( bSizer442111, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.BOTTOM, 5 ) - camera_buttons_row = wx.BoxSizer( wx.HORIZONTAL ) - self.m_button10 = wx.Button( self.camera_panel, wx.ID_ANY, u"Set Camera Parameter", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_button10.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - camera_buttons_row.Add( self.m_button10, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 3 ) + m_staticText14211.Add( self.m_button10, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT, 3 ) self.m_manual_ir_nuc = wx.Button( self.camera_panel, wx.ID_ANY, u"Manual IR NUC", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_manual_ir_nuc.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - camera_buttons_row.Add( self.m_manual_ir_nuc, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 3 ) - - - m_staticText14211.Add( camera_buttons_row, 0, wx.ALIGN_CENTER_HORIZONTAL, 3 ) + m_staticText14211.Add( self.m_manual_ir_nuc, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT, 3 ) self.camera_panel.SetSizer( m_staticText14211 ) @@ -472,7 +467,7 @@ def __init__( self, parent ): bSizer611.Add( self.m_button81, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) - bSizer391.Add( bSizer611, 0, wx.EXPAND, 5 ) + bSizer391.Add( bSizer611, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) bSizer44 = wx.BoxSizer( wx.HORIZONTAL ) @@ -487,7 +482,7 @@ def __init__( self, parent ): bSizer44.Add( self.m_button8, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) - bSizer391.Add( bSizer44, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) + bSizer391.Add( bSizer44, 0, wx.EXPAND, 5 ) self.m_staticline411 = wx.StaticLine( self.flight_data_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) bSizer391.Add( self.m_staticline411, 0, wx.EXPAND|wx.BOTTOM|wx.RIGHT|wx.LEFT, 5 ) From 0624093fc62bad0c0b846a2ceaa5dd074acdb826 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 13:10:34 -0400 Subject: [PATCH 063/139] Move observer back to its own row, expand camera settings a bit --- .../system_control_panel/form_builder_output.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index 9e5f033..36a6b40 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -256,7 +256,7 @@ def __init__( self, parent ): bSizer55.Add( self.camera_setting_subsys, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - m_staticText14211.Add( bSizer55, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) + m_staticText14211.Add( bSizer55, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 10 ) self.m_staticline5 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline5, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) @@ -291,7 +291,7 @@ def __init__( self, parent ): bSizer442.Add( self.exposure_max_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - m_staticText14211.Add( bSizer442, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) + m_staticText14211.Add( bSizer442, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 10 ) self.m_staticline51 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline51, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) @@ -326,7 +326,7 @@ def __init__( self, parent ): bSizer4421.Add( self.gain_max_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - m_staticText14211.Add( bSizer4421, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) + m_staticText14211.Add( bSizer4421, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 10 ) self.m_staticline52 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline52, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) @@ -430,8 +430,7 @@ def __init__( self, parent ): bSizer45.Add( self.flight_number_text_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - flight_observer_row = wx.BoxSizer( wx.HORIZONTAL ) - flight_observer_row.Add( bSizer45, 1, wx.EXPAND, 2 ) + bSizer42.Add( bSizer45, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, 5 ) bSizer451 = wx.BoxSizer( wx.HORIZONTAL ) @@ -445,9 +444,7 @@ def __init__( self, parent ): bSizer451.Add( self.observer_text_ctrl, 1, wx.RIGHT|wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5 ) - flight_observer_row.Add( bSizer451, 1, wx.EXPAND, 2 ) - - bSizer42.Add( flight_observer_row, 0, wx.EXPAND, 2 ) + bSizer42.Add( bSizer451, 1, wx.EXPAND, 5 ) bSizer41.Add( bSizer42, 1, wx.EXPAND, 5 ) From 15fade0a054bc30a531e9468b897a514818a5294 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 13:14:59 -0400 Subject: [PATCH 064/139] Darker gray for disabled controls, spacing changes --- .../wxpython_gui/src/wxpython_gui/cfg.py | 1 + .../form_builder_output.py | 5 +-- .../wxpython_gui/system_control_panel/gui.py | 43 +++++++++++++------ 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py index b7f914c..8f15c77 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py @@ -205,6 +205,7 @@ def merge_two_dicts(a, b, path=None): TEXTCTRL_DARK = (20, 20, 20) APP_GRAY = (220, 218, 213) # Default application background FLAT_GRAY = (200, 200, 200) +DISABLED_GRAY = (150, 150, 150) # Darker fill for disabled input fields COLLECT_GREEN = (55, 120, 25) SHAPE_COLLECT_BLUE = ( 52, diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index 36a6b40..273a686 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -247,16 +247,13 @@ def __init__( self, parent ): self.camera_setting_rgb_uv_combo.SetSelection( 0 ) bSizer55.Add( self.camera_setting_rgb_uv_combo, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - - bSizer55.Add( ( 10, 0), 1, wx.EXPAND, 5 ) - camera_setting_subsysChoices = [ u"Left", u"Center", u"Right", u"All" ] self.camera_setting_subsys = wx.ComboBox( self.camera_panel, wx.ID_ANY, u"Right", wx.DefaultPosition, wx.Size( 90,-1 ), camera_setting_subsysChoices, wx.CB_READONLY ) self.camera_setting_subsys.SetSelection( 3 ) bSizer55.Add( self.camera_setting_subsys, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - m_staticText14211.Add( bSizer55, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 10 ) + m_staticText14211.Add( bSizer55, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) self.m_staticline5 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline5, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 269e9f7..cb85b65 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -80,6 +80,7 @@ COLLECT_GREEN, ERROR_RED, FLAT_GRAY, + DISABLED_GRAY, WARN_AMBER, BRIGHT_GREEN, VERDANT_GREEN, @@ -705,21 +706,33 @@ def _apply_system_sanity(self, results, nas_unmounts): self.nas_disk_space.SetLabel("NAS Err: " + "".join(nas_unmounts)) self.nas_disk_space.SetForegroundColour(ERROR_RED) + def _set_field_enabled(self, ctrl, enabled): + """Enable/disable an input field and make the disabled state obvious. + + GTK's default disabled styling is subtle, so also darken the background + of disabled fields and restore white when re-enabled. + """ + ctrl.Enable(enabled) + ctrl.SetBackgroundColour( + wx.WHITE if enabled else wx.Colour(*DISABLED_GRAY) + ) + ctrl.Refresh() + def on_modal_selection(self, event): self.on_camera_setting_subsys_selection(event) mode = self.camera_setting_rgb_uv_combo.GetStringSelection() if mode == "IR": - self.exposure_max_value_txt_ctrl.Disable() - self.exposure_min_value_txt_ctrl.Disable() - self.gain_min_value_txt_ctrl.Disable() - self.gain_max_value_txt_ctrl.Disable() - self.ir_nuc_time.Enable() + self._set_field_enabled(self.exposure_max_value_txt_ctrl, False) + self._set_field_enabled(self.exposure_min_value_txt_ctrl, False) + self._set_field_enabled(self.gain_min_value_txt_ctrl, False) + self._set_field_enabled(self.gain_max_value_txt_ctrl, False) + self._set_field_enabled(self.ir_nuc_time, True) else: - self.exposure_max_value_txt_ctrl.Enable() - self.exposure_min_value_txt_ctrl.Enable() - self.gain_min_value_txt_ctrl.Enable() - self.gain_max_value_txt_ctrl.Enable() - self.ir_nuc_time.Disable() + self._set_field_enabled(self.exposure_max_value_txt_ctrl, True) + self._set_field_enabled(self.exposure_min_value_txt_ctrl, True) + self._set_field_enabled(self.gain_min_value_txt_ctrl, True) + self._set_field_enabled(self.gain_max_value_txt_ctrl, True) + self._set_field_enabled(self.ir_nuc_time, False) def set_camera_parameter(self, hosts, mode, param, val): mode = mode.lower() @@ -2220,7 +2233,10 @@ def on_menu_item_about(self, event): def _enable_state_controls(self): for child in self.flight_data_panel.GetChildren(): - child.Enable() + if isinstance(child, wx.TextCtrl): + self._set_field_enabled(child, True) + else: + child.Enable() self.camera_config_combo.Enable() self.close_button.Enable() @@ -2238,7 +2254,10 @@ def _disable_state_controls(self): continue if isinstance(child, wx.ComboBox): # Effort dropdown element continue - child.Disable() + if isinstance(child, wx.TextCtrl): + self._set_field_enabled(child, False) + else: + child.Disable() self.camera_config_combo.Disable() # self.close_button.Disable() From 8f16d6b38803779753ccb81eb05dc70fdd06feab Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 13:17:42 -0400 Subject: [PATCH 065/139] Make sure disabled values are shown --- .../src/wxpython_gui/system_control_panel/gui.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index cb85b65..597f64d 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -709,10 +709,18 @@ def _apply_system_sanity(self, results, nas_unmounts): def _set_field_enabled(self, ctrl, enabled): """Enable/disable an input field and make the disabled state obvious. - GTK's default disabled styling is subtle, so also darken the background - of disabled fields and restore white when re-enabled. + For text fields we use read-only instead of a full Disable() so the + frozen value stays fully legible (GTK greys out the text of disabled + controls, hiding the value). A darker background plus dark text makes + the read-only/frozen state obvious while keeping the value visible. """ - ctrl.Enable(enabled) + if isinstance(ctrl, wx.TextCtrl): + ctrl.SetEditable(enabled) + ctrl.SetForegroundColour( + wx.BLACK if enabled else wx.Colour(*TEXTCTRL_DARK) + ) + else: + ctrl.Enable(enabled) ctrl.SetBackgroundColour( wx.WHITE if enabled else wx.Colour(*DISABLED_GRAY) ) From 57ea42ea45b16d20c3bb08d5a418670bf8f48bb9 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 13:20:45 -0400 Subject: [PATCH 066/139] Remove race condition on detector guage starting red --- .../wxpython_gui/system_control_panel/gui.py | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 597f64d..d3f8e6e 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -552,6 +552,7 @@ def __init__( # self.lastCdet = kv.get("/nuvo0/detector/health//frame") # self.lastRdet = kv.get("/nuvo2/detector/health//frame") self.delay = 0 + self.detectors_gauge.SetBackgroundColour(FLAT_GRAY) self.Show() print(self.GetSize()) self._fit_to_display() @@ -1036,19 +1037,22 @@ def on_slow_timer(self, event): print(d_status.values()) - if not len(d_desired): + active_statuses = [ + status for status in d_status.values() + if status is not EPodStatus.Unknown + ] + if not d_desired or not active_statuses: self.detectors_gauge.SetBackgroundColour(FLAT_GRAY) + elif any(status is EPodStatus.Failed for status in active_statuses): + self.detectors_gauge.SetBackgroundColour(ERROR_RED) + elif any(status is EPodStatus.Pending for status in active_statuses): + self.detectors_gauge.SetBackgroundColour(WARN_AMBER) + elif any(status is EPodStatus.Stalled for status in active_statuses): + self.detectors_gauge.SetBackgroundColour(WARN_AMBER) + elif all(status.is_ok() for status in active_statuses): + self.detectors_gauge.SetBackgroundColour(BRIGHT_GREEN) else: - if any([status is EPodStatus.Failed for status in d_status.values()]): - self.detectors_gauge.SetBackgroundColour(ERROR_RED) - elif any([status is EPodStatus.Pending for status in d_status.values()]): - self.detectors_gauge.SetBackgroundColour(WARN_AMBER) - elif any([status is EPodStatus.Stalled for status in d_status.values()]): - self.detectors_gauge.SetBackgroundColour(WARN_AMBER) - elif all([status.is_ok() for status in d_status.values()]): - self.detectors_gauge.SetBackgroundColour(BRIGHT_GREEN) - else: - self.detectors_gauge.SetBackgroundColour(ERROR_RED) + self.detectors_gauge.SetBackgroundColour(FLAT_GRAY) is_busy = {h: 0 for h in self.hosts} current_task = {} From 35b4b8b7ec08a25cd7684882715206226b0cfc1e Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 15 Jun 2026 13:23:41 -0400 Subject: [PATCH 067/139] Change volume mounts to match --- compose/gui.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compose/gui.yml b/compose/gui.yml index 51ba6dd..005122d 100644 --- a/compose/gui.yml +++ b/compose/gui.yml @@ -27,12 +27,10 @@ services: volumes: - "/mnt:/mnt" - "/tmp/.X11-unix:/tmp/.X11-unix" - - "/home/user/kw/kamera/scripts:/home/user/kamera_ws/scripts" - - "${PWD}/src:/home/user/kamera_ws/src:ro" - - "${PWD}/kamera:/home/user/kamera_ws/kamera:ro" - - "${PWD}/assets:/home/user/noaa_kamera/assets:ro" + - "/home/user/kw/kamera/scripts:/home/user/kamera/scripts" + - "${PWD}/src:/home/user/kamera/src:ro" + - "${PWD}/assets:/home/user/kamera/assets:ro" - "save-gui:/home/user/.config/kamera/gui" - - "${HOME}/.ssh:/home/user/.ssh" entrypoint: ["/entry/gui.sh"] #command: ["bash"] From 535ca8facecc28ecefe3940d632fc0ebcd91f372 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 15 Jun 2026 13:24:15 -0400 Subject: [PATCH 068/139] Use repo dir, not ws dir --- scripts/activate_ros.bash | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/scripts/activate_ros.bash b/scripts/activate_ros.bash index 16ec161..fe54ac2 100644 --- a/scripts/activate_ros.bash +++ b/scripts/activate_ros.bash @@ -3,17 +3,6 @@ # Activate the ROS bash environment, either sourcing the current workspace # devel setup or the base ROS environment setup script. This cascades down # ROS versions when a development environment does not exist. -# -# $WS_DIR and $ROS_DISTRO should be provided by the container -# If not, define them here: -#ROS_DISTRO=kinetic -#WS_DIR=/root/kamera_ws - -#source ${REPO_DIR}/src/run_scripts/entry/setup_kamera_env.sh - -#myips() { -# echo $(ip addr | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v 127.0) || "false" -#} # may have changed MASTER_HOST=$(echo $ROS_MASTER_URI| grep -Po -e '(?<=http:\/\/)([\w\.]+)(?=:)') @@ -26,20 +15,16 @@ HOSTNAME : `hostname` NODE_HOSTNAME : ${NODE_HOSTNAME} ROS_HOST/IP : ${ROS_HOSTNAME} ${ROS_IP} ROS_MASTER_URI : ${ROS_MASTER_URI} +REPO_DIR : ${REPO_DIR} " -#RMU DIG : $(dig +short ${MASTER_HOST}) -#This Host's dig : $(dig +short `hostname`) - -#printf "WS_DIR : ${WS_DIR} -#SERVICE_NAME : ${SERVICE_NAME} -#SYSIDX : ${SYSIDX}" } + rosinfo echo "Sourcing files and establishing environment" ## This presumes ROS_DISTRO is set -DEVEL_SETUP="${WS_DIR}/devel/setup.bash" +DEVEL_SETUP="${REPO_DIR}/devel/setup.bash" VERSION_SETUP_PATH="/opt/ros/${ROS_DISTRO}/setup.bash" if [ -f "${VERSION_SETUP_PATH}" ] then From a54a2f00069b37b3e7012248b3e0288c5f322693 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 15 Jun 2026 13:24:54 -0400 Subject: [PATCH 069/139] Point to correct logo file --- .../wxpython_gui/src/wxpython_gui/system_control_panel/gui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index d3f8e6e..17076c2 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -206,7 +206,7 @@ def __init__( icon = wx.Icon() icon.CopyFromBitmap( wx.Bitmap( - os.path.expanduser("~/noaa_kamera/src/cfg/seal-icon.png"), + os.path.expanduser("~/kamera/src/cfg/seal-icon.png"), wx.BITMAP_TYPE_ANY, ) ) From 8452d2dac2a0c2614457faad8763d5e1e3d752c3 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 13:29:54 -0400 Subject: [PATCH 070/139] Spacing --- .../system_control_panel/form_builder_output.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index 273a686..4963c90 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -276,7 +276,7 @@ def __init__( self, parent ): bSizer442.Add( self.exposure_min_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - bSizer442.Add( ( 10, 0), 1, wx.EXPAND, 5 ) + bSizer442.Add( ( 40, 0), 0, 0, 5 ) self.m_staticText4231 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Max:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText4231.Wrap( -1 ) @@ -288,7 +288,7 @@ def __init__( self, parent ): bSizer442.Add( self.exposure_max_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - m_staticText14211.Add( bSizer442, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 10 ) + m_staticText14211.Add( bSizer442, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) self.m_staticline51 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline51, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) @@ -311,7 +311,7 @@ def __init__( self, parent ): bSizer4421.Add( self.gain_min_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - bSizer4421.Add( ( 10, 0), 1, wx.EXPAND, 5 ) + bSizer4421.Add( ( 40, 0), 0, 0, 5 ) self.m_staticText42311 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Max:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText42311.Wrap( -1 ) @@ -323,7 +323,7 @@ def __init__( self, parent ): bSizer4421.Add( self.gain_max_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - m_staticText14211.Add( bSizer4421, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 10 ) + m_staticText14211.Add( bSizer4421, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) self.m_staticline52 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline52, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) @@ -520,7 +520,7 @@ def __init__( self, parent ): bSizer17 = wx.BoxSizer( wx.VERTICAL ) self.close_button = wx.Button( self.m_panel7, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.Size( -1,-1 ), 0 ) - bSizer17.Add( self.close_button, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 3 ) + bSizer17.Add( self.close_button, 0, wx.ALL|wx.ALIGN_LEFT, 3 ) self.m_panel7.SetSizer( bSizer17 ) From d1a258dc7ef1eabd12134ea6dbf2c3bcce6423cf Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 13:33:05 -0400 Subject: [PATCH 071/139] Change divider --- .../wxpython_gui/system_control_panel/form_builder_output.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index 4963c90..064d9aa 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -516,9 +516,12 @@ def __init__( self, parent ): self.left_scroll_panel.Layout() self.left_scroll_panel.SetupScrolling( scroll_x = False, scroll_y = True ) - self.m_panel7 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) + self.m_panel7 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) bSizer17 = wx.BoxSizer( wx.VERTICAL ) + self.m_staticline_close = wx.StaticLine( self.m_panel7, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) + bSizer17.Add( self.m_staticline_close, 0, wx.EXPAND, 0 ) + self.close_button = wx.Button( self.m_panel7, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.Size( -1,-1 ), 0 ) bSizer17.Add( self.close_button, 0, wx.ALL|wx.ALIGN_LEFT, 3 ) From 554b18b40dec3e7d4925af50dfd8fe9c92e4b18b Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 13:53:38 -0400 Subject: [PATCH 072/139] Move completely to noetic - remove kinetic shims --- .github/workflows/gui-build.yml | 30 ++++++++++++++ .github/workflows/gui-noetic-build.yml | 31 --------------- Makefile | 27 ++++++------- docker-compose.yml | 52 ++++++------------------ docker/base/gui-deps-noetic.dockerfile | 36 ----------------- docker/base/gui-deps.dockerfile | 55 +++++++++++++++----------- docker/base/gui-ros.dockerfile | 49 ----------------------- docker/gui.dockerfile | 2 +- src/core/roskv/tests-py2.df | 31 --------------- 9 files changed, 85 insertions(+), 228 deletions(-) create mode 100644 .github/workflows/gui-build.yml delete mode 100644 .github/workflows/gui-noetic-build.yml delete mode 100644 docker/base/gui-deps-noetic.dockerfile delete mode 100644 docker/base/gui-ros.dockerfile delete mode 100644 src/core/roskv/tests-py2.df diff --git a/.github/workflows/gui-build.yml b/.github/workflows/gui-build.yml new file mode 100644 index 0000000..e706977 --- /dev/null +++ b/.github/workflows/gui-build.yml @@ -0,0 +1,30 @@ +name: GUI build + +on: + push: + paths: + - ".github/workflows/gui-build.yml" + - "docker/base/gui-deps.dockerfile" + - "docker/gui.dockerfile" + - "docker-compose.yml" + - "Makefile" + pull_request: + paths: + - ".github/workflows/gui-build.yml" + - "docker/base/gui-deps.dockerfile" + - "docker/gui.dockerfile" + - "docker-compose.yml" + - "Makefile" + +# NOTE: This is config validation only, not an image build. A real `make gui` +# build requires the published Noetic core-deps image as a base and a display +# for the wx smoke test. Upgrade this to an actual layer build (e.g. build +# gui-deps against a published core-deps) when CI infrastructure allows. +jobs: + validate-compose: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Validate gui compose config + run: docker compose --profile gui config diff --git a/.github/workflows/gui-noetic-build.yml b/.github/workflows/gui-noetic-build.yml deleted file mode 100644 index 8da2b6d..0000000 --- a/.github/workflows/gui-noetic-build.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: GUI Noetic build - -on: - push: - paths: - - ".github/workflows/gui-noetic-build.yml" - - "docker/base/gui-deps-noetic.dockerfile" - - "docker/gui.dockerfile" - - "docker-compose.yml" - - "Makefile" - pull_request: - paths: - - ".github/workflows/gui-noetic-build.yml" - - "docker/base/gui-deps-noetic.dockerfile" - - "docker/gui.dockerfile" - - "docker-compose.yml" - - "Makefile" - -# NOTE: This is config validation only, not an image build. A real `make -# gui-noetic` build cannot pass until the Python 2 -> 3 port (Phases 2-3) lands, -# because gui.dockerfile runs `catkin build wxpython_gui` + `pip install -e .` -# against currently-unported Py2 code. Upgrade this to an actual layer build -# (e.g. build gui-deps-noetic against a published core-deps) once that is done. -jobs: - validate-compose: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Validate gui-noetic compose config - run: docker compose --profile gui-noetic config diff --git a/Makefile b/Makefile index 5158c5b..1c51581 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ ROS_DISTRO ?= noetic -.PHONY: build core viame gui gui-noetic postflight follower leader all clean +.PHONY: build core viame gui postflight follower leader all clean build: docker compose build @@ -17,15 +17,10 @@ viame: docker compose --profile viame build gui: - ROS_DISTRO=kinetic docker compose --profile gui build core-deps-kinetic - ROS_DISTRO=kinetic docker compose --profile gui build core-gui-deps - ROS_DISTRO=kinetic docker compose --profile gui build - -gui-noetic: - docker compose --profile gui-noetic build core-ros - docker compose --profile gui-noetic build core-deps - docker compose --profile gui-noetic build gui-deps-noetic - docker compose --profile gui-noetic build gui-noetic + docker compose --profile gui build core-ros + docker compose --profile gui build core-deps + docker compose --profile gui build gui-deps + docker compose --profile gui build gui postflight: docker compose --profile pf build @@ -39,19 +34,19 @@ follower: docker compose --profile follower build viame-base docker compose --profile follower build -# Leader node: operator workstation — Kinetic GUI + postproc +# Leader node: operator workstation — GUI + postproc leader: - ROS_DISTRO=kinetic docker compose --profile leader build core-deps-kinetic - ROS_DISTRO=kinetic docker compose --profile leader build core-gui-deps - ROS_DISTRO=kinetic docker compose --profile leader build + docker compose --profile leader build core-ros + docker compose --profile leader build core-deps + docker compose --profile leader build gui-deps + docker compose --profile leader build # Everything all: docker compose --profile all build core-ros docker compose --profile all build core-deps docker compose --profile all build viame-base - docker compose --profile all build core-deps-kinetic - docker compose --profile all build core-gui-deps + docker compose --profile all build gui-deps docker compose --profile all build clean: diff --git a/docker-compose.yml b/docker-compose.yml index 9fa708e..0914eb4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,14 +8,13 @@ ## ## Deployment profiles: ## follower -- headless sensor node: core + VIAME + postproc -## leader -- operator workstation: Kinetic GUI + postproc +## leader -- operator workstation: GUI + postproc ## all -- everything ## ## Individual layer profiles: ## core -- Noetic base images only (no VIAME, no GUI) ## viame -- VIAME detector images only -## gui -- Kinetic GUI images only -## gui-noetic -- Noetic GUI images only (parallel chain until cutover) +## gui -- Noetic GUI images only ## pf -- postproc / postflight only services: @@ -41,7 +40,8 @@ services: - core - follower - all - - gui-noetic + - gui + - leader # System dependencies (drivers, C++ libs, ROS packages). No source copy. core-deps: @@ -53,7 +53,8 @@ services: - core - follower - all - - gui-noetic + - gui + - leader # KAMERA source + catkin build on top of core-deps. core: @@ -118,24 +119,14 @@ services: - follower - all -## ========================== Kinetic GUI chain ================================ - - # Kinetic ROS base for the GUI — independent of the Noetic core chain. - core-deps-kinetic: - build: - context: . - dockerfile: docker/base/gui-ros.dockerfile - image: "kamera/base/core-deps-kinetic:latest" - profiles: - - gui - - leader - - all +## ========================== GUI chain ======================================== - core-gui-deps: + # GUI deps layered on the Noetic core-deps image. + gui-deps: build: context: . dockerfile: docker/base/gui-deps.dockerfile - image: "kamera/base/core-gui-deps:${TAG_KAMERA_GUI_DEPS:-latest}" + image: "kamera/base/gui-deps:${TAG_KAMERA_GUI_DEPS:-latest}" profiles: - gui - leader @@ -146,32 +137,13 @@ services: build: context: . dockerfile: docker/gui.dockerfile + args: + GUI_DEPS_IMAGE: "kamera/base/gui-deps:${TAG_KAMERA_GUI_DEPS:-latest}" image: "kitware/kamera:gui" profiles: - gui - leader - all -## ========================== Noetic GUI chain (parallel) ====================== - - gui-deps-noetic: - build: - context: . - dockerfile: docker/base/gui-deps-noetic.dockerfile - image: "kamera/base/gui-deps-noetic:${TAG_KAMERA_GUI_DEPS:-latest}" - profiles: - - gui-noetic - - gui-noetic: - container_name: gui-noetic - build: - context: . - dockerfile: docker/gui.dockerfile - args: - GUI_DEPS_IMAGE: "kamera/base/gui-deps-noetic:${TAG_KAMERA_GUI_DEPS:-latest}" - image: "kitware/kamera:gui-noetic" - profiles: - - gui-noetic - ## ==================================================================== ... diff --git a/docker/base/gui-deps-noetic.dockerfile b/docker/base/gui-deps-noetic.dockerfile deleted file mode 100644 index 320034d..0000000 --- a/docker/base/gui-deps-noetic.dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -## GUI deps on the Noetic core-deps chain (parallel to Kinetic core-gui-deps). -FROM kamera/base/core-deps:latest - -RUN apt-get update && apt-get install -y --no-install-recommends \ - gdal-bin \ - python3-gdal \ - python3-tk \ - python3-wxgtk4.0 \ - libgl1-mesa-glx \ - libqt5x11extras5 \ - locales \ - && rm -rf /var/lib/apt/lists/* - -# wxPython's wx.App init sets the en_US locale at startup; generate it so the -# GUI doesn't fail with "locale en_US cannot be set". -RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8 -ENV LANG=en_US.UTF-8 \ - LANGUAGE=en_US:en \ - LC_ALL=en_US.UTF-8 - -RUN pip install --upgrade \ - pip \ - Pillow - -# numpy/scipy/shapely/pyshp come from core-deps; only GUI-unique deps here. -# TODO: validate the unpinned pygeodesy already installed by core-deps and drop -# this <19.12 downgrade (legacy Py2-era pin, untested on Py3). -RUN pip install --no-cache-dir \ - 'PyGeodesy<19.12' \ - exifread \ - ipython \ - psutil \ - simplekml - -COPY src/core/roskv /src/roskv -RUN pip install --no-cache-dir '/src/roskv[redis]' diff --git a/docker/base/gui-deps.dockerfile b/docker/base/gui-deps.dockerfile index 41e9fd2..fbf5533 100644 --- a/docker/base/gui-deps.dockerfile +++ b/docker/base/gui-deps.dockerfile @@ -1,29 +1,36 @@ -## this is currently ONLY supported on kinetic! -FROM kamera/base/core-deps-kinetic:latest +## GUI deps layered on the Noetic core-deps chain. +FROM kamera/base/core-deps:latest -RUN apt-get update && apt-get install -y \ - gdal-bin \ - python-gdal \ - python-tk \ - libgl1-mesa-glx \ - libqt5x11extras5 \ - && rm -rf /var/lib/apt/lists/* +RUN apt-get update && apt-get install -y --no-install-recommends \ + gdal-bin \ + python3-gdal \ + python3-tk \ + python3-wxgtk4.0 \ + libgl1-mesa-glx \ + libqt5x11extras5 \ + locales \ + && rm -rf /var/lib/apt/lists/* -RUN pip install --upgrade \ - pip \ - Pillow +# wxPython's wx.App init sets the en_US locale at startup; generate it so the +# GUI doesn't fail with "locale en_US cannot be set". +RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8 +ENV LANG=en_US.UTF-8 \ + LANGUAGE=en_US:en \ + LC_ALL=en_US.UTF-8 +RUN pip install --upgrade \ + pip \ + Pillow -RUN pip install --no-cache-dir \ - 'PyGeodesy<19.12' \ - 'IPython==5.0' \ - exifread \ - numpy \ - shapely \ - pyshp \ - scipy\ - simplekml \ - wxPython \ - typing +# numpy/scipy/shapely/pyshp come from core-deps; only GUI-unique deps here. +# TODO: validate the unpinned pygeodesy already installed by core-deps and drop +# this <19.12 downgrade (legacy Py2-era pin, untested on Py3). +RUN pip install --no-cache-dir \ + 'PyGeodesy<19.12' \ + exifread \ + ipython \ + psutil \ + simplekml -RUN pip install 'src/core/roskv[redis]' +COPY src/core/roskv /src/roskv +RUN pip install --no-cache-dir '/src/roskv[redis]' diff --git a/docker/base/gui-ros.dockerfile b/docker/base/gui-ros.dockerfile deleted file mode 100644 index dc8a765..0000000 --- a/docker/base/gui-ros.dockerfile +++ /dev/null @@ -1,49 +0,0 @@ -FROM ros:kinetic-robot AS kinetic-robot -ENV PYTHON=python2 \ - ROS_PKG_VERS=1.3.2-0 - -## Necessary, followed by unessential but useful packages -RUN apt-key adv --keyserver hkps://keyserver.ubuntu.com --refresh-keys -RUN apt-get update -q && apt-get install --no-install-recommends -y \ - curl \ - git \ - iputils-ping \ - iproute2 \ - net-tools \ - dnsutils \ - jq \ - redis-tools \ - sqlite3 \ - python3-pip \ - python3-rosdep \ - python3-rosinstall \ - python3-vcstools \ - python3-catkin-tools \ - unzip \ - && apt-get update -q && apt-get install --no-install-recommends -y \ - autoconf \ - automake\ - build-essential \ - dirmngr \ - pkg-config \ - sudo \ - nano \ - vim \ - inetutils-traceroute \ - tmux \ - python3-dev \ - && rm -rf /var/lib/apt/lists/* - - -## ipython isn't strictly required (like most things in is kitchen sink image) but it's extremely useful for debugging -RUN pip install --upgrade --no-cache-dir pip \ - && pip install --no-cache-dir \ - ipython \ - ipdb \ - pyserial \ - typing \ - pathlib \ - profilehooks \ - redis \ - osrf-pycommon \ - six diff --git a/docker/gui.dockerfile b/docker/gui.dockerfile index 4011fc6..bf25bc5 100644 --- a/docker/gui.dockerfile +++ b/docker/gui.dockerfile @@ -1,5 +1,5 @@ ARG BRANCH=latest -ARG GUI_DEPS_IMAGE=kamera/base/core-gui-deps:latest +ARG GUI_DEPS_IMAGE=kamera/base/gui-deps:latest FROM ${GUI_DEPS_IMAGE} diff --git a/src/core/roskv/tests-py2.df b/src/core/roskv/tests-py2.df deleted file mode 100644 index 5f4bc03..0000000 --- a/src/core/roskv/tests-py2.df +++ /dev/null @@ -1,31 +0,0 @@ -ARG ROS_DISTRO=kinetic -FROM ros:kinetic-robot as kinetic-robot -ENV PYTHON=python \ - ROS_PKG_VERS=1.3.2-0 - -FROM ros:melodic-robot as melodic-robot -ENV PYTHON=python \ - ROS_PKG_VERS=1.4.1-0 - -FROM ros:noetic-robot as noetic-robot -ENV PYTHON=python3 \ - ROS_PKG_VERS=1.5.0-1 - -## === === === === === === === ros desktop === === === === === === === === === === -FROM ${ROS_DISTRO}-robot as ros-desktop -RUN printf "\n======\nenv: ROS_DISTRO: ${ROS_DISTRO} PYTHON: ${PYTHON}\n======\n" \ - && apt-get update -q && apt-get install --no-install-recommends -y \ - curl \ - git \ - jq \ - redis-server \ - redis-tools \ - sqlite3 \ - supervisor \ - ${PYTHON}-rosdep \ - ${PYTHON}-rosinstall \ - ${PYTHON}-vcstools \ - ${PYTHON}-catkin-tools \ - python3-dev \ - unzip \ - && rm -rf /var/lib/apt/lists/* \ No newline at end of file From a01af885f6aaafb5d5803b0aa652429858d8254e Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 14:09:15 -0400 Subject: [PATCH 073/139] Add viame to leader build --- Makefile | 3 ++- docker-compose.yml | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1c51581..0d0026f 100644 --- a/Makefile +++ b/Makefile @@ -34,10 +34,11 @@ follower: docker compose --profile follower build viame-base docker compose --profile follower build -# Leader node: operator workstation — GUI + postproc +# Leader node: operator workstation — GUI + VIAME + postproc leader: docker compose --profile leader build core-ros docker compose --profile leader build core-deps + docker compose --profile leader build viame-base docker compose --profile leader build gui-deps docker compose --profile leader build diff --git a/docker-compose.yml b/docker-compose.yml index 0914eb4..e7d5cc8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ ## ## Deployment profiles: ## follower -- headless sensor node: core + VIAME + postproc -## leader -- operator workstation: GUI + postproc +## leader -- operator workstation: GUI + VIAME + postproc ## all -- everything ## ## Individual layer profiles: @@ -101,6 +101,7 @@ services: profiles: - viame - follower + - leader - all viame: @@ -117,6 +118,7 @@ services: profiles: - viame - follower + - leader - all ## ========================== GUI chain ======================================== From 29ae0afd67ce3a3068518b91991555da21d70085 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 15:02:32 -0400 Subject: [PATCH 074/139] Remove WS_DIR variable, make REPO_DIR use consistent --- docker/core.dockerfile | 20 ++++++++++---------- docker/detector.dockerfile | 3 +-- src/run_scripts/entry/setup_kamera_env.sh | 1 - src/run_scripts/entry/update_hosts.sh | 2 +- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/docker/core.dockerfile b/docker/core.dockerfile index 18cd4d4..7dc471b 100644 --- a/docker/core.dockerfile +++ b/docker/core.dockerfile @@ -2,26 +2,26 @@ FROM kamera/base/core-deps:latest -ENV WS_DIR=/root/kamera -WORKDIR $WS_DIR +ENV REPO_DIR=/root/kamera +WORKDIR $REPO_DIR -COPY . $WS_DIR +COPY . $REPO_DIR RUN rm -rf /entry \ - && ln -sf $WS_DIR/src/run_scripts/entry /entry \ + && ln -sf $REPO_DIR/src/run_scripts/entry /entry \ && printf "\nsource /entry/project.sh\n" >> /root/.bashrc \ - && touch $WS_DIR/.catkin_workspace \ - && ln -sf $WS_DIR/src/run_scripts/aliases.sh /aliases.sh \ + && touch $REPO_DIR/.catkin_workspace \ + && ln -sf $REPO_DIR/src/run_scripts/aliases.sh /aliases.sh \ && printf "\nsource /aliases.sh\n" >> /root/.bashrc -RUN ln -sf $WS_DIR/scripts/activate_ros.bash $WS_DIR/activate_ros.bash -RUN ln -sf $WS_DIR/src/cfg /cfg +RUN ln -sf $REPO_DIR/scripts/activate_ros.bash $REPO_DIR/activate_ros.bash +RUN ln -sf $REPO_DIR/src/cfg /cfg RUN mkdir -p /root/.config/kamera && \ - ln -sf $WS_DIR/.dir /root/.config/kamera/repo_dir.bash + ln -sf $REPO_DIR/.dir /root/.config/kamera/repo_dir.bash # Need to build phase_one first to generate SRV, then build backend RUN ln -sv /usr/bin/python3 /usr/bin/python || true -RUN [ "/bin/bash", "-c", "source ${WS_DIR}/activate_ros.bash && catkin build phase_one"] +RUN [ "/bin/bash", "-c", "source ${REPO_DIR}/activate_ros.bash && catkin build phase_one"] RUN [ "/bin/bash", "-c", "source /entry/project.sh && catkin build -s backend"] ENTRYPOINT ["/entry/project.sh"] diff --git a/docker/detector.dockerfile b/docker/detector.dockerfile index 2cc0c8c..250f056 100644 --- a/docker/detector.dockerfile +++ b/docker/detector.dockerfile @@ -5,8 +5,7 @@ COPY . /root/kamera RUN ln -sf /root/kamera/src/run_scripts/entry /entry WORKDIR /root/kamera -ENV REPO_DIR=/root/kamera \ - WS_DIR=/root/kamera +ENV REPO_DIR=/root/kamera RUN ["/bin/bash", "-c", "source /entry/project.sh && \ source src/run_scripts/setup/setup_viame_build.sh && \ diff --git a/src/run_scripts/entry/setup_kamera_env.sh b/src/run_scripts/entry/setup_kamera_env.sh index 151231d..2fdcbb7 100755 --- a/src/run_scripts/entry/setup_kamera_env.sh +++ b/src/run_scripts/entry/setup_kamera_env.sh @@ -55,7 +55,6 @@ fi if [[ -z $IS_CONTAINER ]] ; then SUBDIR=/kw export REPO_DIR=${HOME}${SUBDIR}/kamera - export WS_DIR=${HOME}${SUBDIR}/kamera_ws fi diff --git a/src/run_scripts/entry/update_hosts.sh b/src/run_scripts/entry/update_hosts.sh index 08bd2a2..a6e74e3 100755 --- a/src/run_scripts/entry/update_hosts.sh +++ b/src/run_scripts/entry/update_hosts.sh @@ -3,7 +3,7 @@ # Update /etc/hosts with our preconfigured ones # /etc/hosts will tolerate multiple duplicate entries. It just takes the first row as the IP resolve -# $WS_DIR and $ROS_DISTRO should be provided by the container +# $REPO_DIR and $ROS_DISTRO should be provided by the container # skip if we definitely know it's been appended with KAMERA entries if [[ -n `grep KAMERA /etc/hosts` ]] ; then From 43c7d704cfbbbf3d6902e6314f3ceb3a81c5782a Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 15:17:58 -0400 Subject: [PATCH 075/139] Add defaults for debug in provisioning to avoid crashes in certain nodes --- provision/ansible/playbooks/cas/configure.yml | 8 ++++++++ scripts/seed_redis.py | 2 ++ src/cfg/debug_defaults.json | 8 ++++++++ 3 files changed, 18 insertions(+) create mode 100644 src/cfg/debug_defaults.json diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index 94a9274..688336e 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -37,6 +37,14 @@ --redis-host {{ inventory_hostname }} --config {{ kamera_dir }}/src/cfg/{{ config_dir }}/default_system_state.json + - name: Seed Redis debug defaults + when: redis_host + command: > + python3 {{ kamera_dir }}/scripts/seed_redis.py + --redis-host {{ inventory_hostname }} + --prefix /debug + --config {{ kamera_dir }}/src/cfg/debug_defaults.json + - name: Set up supervisor trampoline become: True file: diff --git a/scripts/seed_redis.py b/scripts/seed_redis.py index 5b17f74..1789799 100755 --- a/scripts/seed_redis.py +++ b/scripts/seed_redis.py @@ -15,6 +15,8 @@ Example: seed_redis.py --redis-host nuvo0 \\ --config src/cfg/taiga/default_system_state.json + seed_redis.py --redis-host nuvo0 \\ + --prefix /debug --config src/cfg/debug_defaults.json """ from __future__ import print_function import argparse diff --git a/src/cfg/debug_defaults.json b/src/cfg/debug_defaults.json new file mode 100644 index 0000000..085b598 --- /dev/null +++ b/src/cfg/debug_defaults.json @@ -0,0 +1,8 @@ +{ + "enable": false, + "norespawn": false, + "rebuild": false, + "spoof_events": 0, + "spoof_gps": false, + "trigger_pps": 0 +} From 60fef39aa52e9d004ce91a1cf685ed43b7ebc589 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 15:46:17 -0400 Subject: [PATCH 076/139] Remove hyphens from hostnames - does not play nicely with ROS. Example: 'center0taiga' --- provision/ansible/hosts.yml | 24 ++++++++-------- src/cfg/hosts | 16 +++++------ .../chrony.conf | 0 .../custom-netplan.yaml | 0 .../{center-0-nayak => center0nayak}/ntp.conf | 0 src/cfg/nayak/config.yaml | 10 +++---- src/cfg/nayak/default_system_state.json | 28 +++++++++---------- .../{left-1-nayak => left1nayak}/chrony.conf | 0 .../custom-netplan.yaml | 0 src/cfg/nayak/redis.conf | 2 +- .../chrony.conf | 0 .../custom-netplan.yaml | 0 .../chrony.conf | 0 .../custom-netplan.yaml | 0 .../{center-0-taiga => center0taiga}/ntp.conf | 0 src/cfg/taiga/config.yaml | 10 +++---- src/cfg/taiga/default_system_state.json | 22 +++++++-------- .../{left-1-taiga => left1taiga}/chrony.conf | 0 .../custom-netplan.yaml | 0 src/cfg/taiga/redis.conf | 2 +- .../chrony.conf | 0 .../custom-netplan.yaml | 0 .../wxpython_gui/system_control_panel/gui.py | 4 +-- 23 files changed, 59 insertions(+), 59 deletions(-) rename src/cfg/nayak/{center-0-nayak => center0nayak}/chrony.conf (100%) rename src/cfg/nayak/{center-0-nayak => center0nayak}/custom-netplan.yaml (100%) rename src/cfg/nayak/{center-0-nayak => center0nayak}/ntp.conf (100%) rename src/cfg/nayak/{left-1-nayak => left1nayak}/chrony.conf (100%) rename src/cfg/nayak/{left-1-nayak => left1nayak}/custom-netplan.yaml (100%) rename src/cfg/nayak/{right-2-nayak => right2nayak}/chrony.conf (100%) rename src/cfg/nayak/{right-2-nayak => right2nayak}/custom-netplan.yaml (100%) rename src/cfg/taiga/{center-0-taiga => center0taiga}/chrony.conf (100%) rename src/cfg/taiga/{center-0-taiga => center0taiga}/custom-netplan.yaml (100%) rename src/cfg/taiga/{center-0-taiga => center0taiga}/ntp.conf (100%) rename src/cfg/taiga/{left-1-taiga => left1taiga}/chrony.conf (100%) rename src/cfg/taiga/{left-1-taiga => left1taiga}/custom-netplan.yaml (100%) rename src/cfg/taiga/{right-2-taiga => right2taiga}/chrony.conf (100%) rename src/cfg/taiga/{right-2-taiga => right2taiga}/custom-netplan.yaml (100%) diff --git a/provision/ansible/hosts.yml b/provision/ansible/hosts.yml index 1d9f30e..00aaaaf 100644 --- a/provision/ansible/hosts.yml +++ b/provision/ansible/hosts.yml @@ -1,11 +1,11 @@ all: hosts: - center-0-taiga: - left-1-taiga: - right-2-taiga: - center-0-nayak: - left-1-nayak: - right-2-nayak: + center0taiga: + left1taiga: + right2taiga: + center0nayak: + left1nayak: + right2nayak: center-bak-nayak: guibox: uas: @@ -20,7 +20,7 @@ all: children: taiga: hosts: - center-0-taiga: + center0taiga: redis_host: true supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/leader/supervisor.conf" leader: True @@ -28,13 +28,13 @@ all: gui: True # /dev/disk/by-uuid ssd_id: "ca0a9985-84ac-4019-95a6-242d3c81c86d" - left-1-taiga: + left1taiga: redis_host: False supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/follower/supervisor.conf" leader: False follower: True ssd_id: "d31ab8b6-b273-49c3-bd32-56c4fb76219c" - right-2-taiga: + right2taiga: redis_host: False supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/follower/supervisor.conf" leader: False @@ -73,19 +73,19 @@ all: nvidia_cuda: False cas: hosts: - center-0-nayak: + center0nayak: redis_host: true supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/leader/supervisor.conf" leader: True follower: False ssd_id: "3ca48dde-3b0f-440a-bbc2-69e6bd559325" - left-1-nayak: + left1nayak: redis_host: False supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/follower/supervisor.conf" leader: False follower: True ssd_id: "40d83577-292f-4795-b275-9b3c38504c22" - right-2-nayak: + right2nayak: redis_host: False supervisor_file: "{{ kamera_dir }}/tmux/{{ config_dir }}/follower/supervisor.conf" leader: False diff --git a/src/cfg/hosts b/src/cfg/hosts index 9505f29..1e1807b 100644 --- a/src/cfg/hosts +++ b/src/cfg/hosts @@ -11,14 +11,14 @@ ff02::3 ip6-allhosts # Inserted from KAMERA 192.168.88.1 mikrotik -192.168.88.10 center-0-taiga -192.168.88.11 left-1-taiga -192.168.88.12 right-2-taiga - -192.168.88.100 center-0-nayak -192.168.88.101 left-1-nayak -192.168.88.102 right-2-nayak -192.168.88.103 center-1-nayak +192.168.88.10 center0taiga +192.168.88.11 left1taiga +192.168.88.12 right2taiga + +192.168.88.100 center0nayak +192.168.88.101 left1nayak +192.168.88.102 right2nayak +192.168.88.103 center1nayak # Fallback static connections 192.168.88.210 nuvo0bak diff --git a/src/cfg/nayak/center-0-nayak/chrony.conf b/src/cfg/nayak/center0nayak/chrony.conf similarity index 100% rename from src/cfg/nayak/center-0-nayak/chrony.conf rename to src/cfg/nayak/center0nayak/chrony.conf diff --git a/src/cfg/nayak/center-0-nayak/custom-netplan.yaml b/src/cfg/nayak/center0nayak/custom-netplan.yaml similarity index 100% rename from src/cfg/nayak/center-0-nayak/custom-netplan.yaml rename to src/cfg/nayak/center0nayak/custom-netplan.yaml diff --git a/src/cfg/nayak/center-0-nayak/ntp.conf b/src/cfg/nayak/center0nayak/ntp.conf similarity index 100% rename from src/cfg/nayak/center-0-nayak/ntp.conf rename to src/cfg/nayak/center0nayak/ntp.conf diff --git a/src/cfg/nayak/config.yaml b/src/cfg/nayak/config.yaml index 23a1e28..b0ed79a 100644 --- a/src/cfg/nayak/config.yaml +++ b/src/cfg/nayak/config.yaml @@ -30,15 +30,15 @@ arch: ext_evt: json ext_ins: json hosts: - center-0-nayak: + center0nayak: fov: center idx: 0 enabled: true - left-1-nayak: + left1nayak: fov: left idx: 1 enabled: true - right-2-nayak: + right2nayak: fov: right idx: 2 enabled: true @@ -50,8 +50,8 @@ nas_mnt: "/mnt/flight_data" local_ssd_mnt: "/mnt/data" kamera_dir: "/home/user/kw/kamera" gui_cfg_dir: "/home/user/.config/kamera/gui" -master_host: center-0-nayak -redis_host: center-0-nayak +master_host: center0nayak +redis_host: center0nayak verbosity: 9 max_mpix: 200000 # 0.2e6 diff --git a/src/cfg/nayak/default_system_state.json b/src/cfg/nayak/default_system_state.json index b02b821..6b251a1 100644 --- a/src/cfg/nayak/default_system_state.json +++ b/src/cfg/nayak/default_system_state.json @@ -1,6 +1,6 @@ { "actual_geni_params": { - "center-0-nayak": { + "center0nayak": { "ir": { "CorrectionAutoEnabled": 1, "CorrectionAutoUseDeltaTime": 0 @@ -27,7 +27,7 @@ "GainValue": 30 } }, - "left-1-nayak": { + "left1nayak": { "ir": { "CorrectionAutoEnabled": 1 }, @@ -51,7 +51,7 @@ "GainValue": 30 } }, - "right-2-nayak": { + "right2nayak": { "ir": { "CorrectionAutoEnabled": 1 }, @@ -90,17 +90,17 @@ "ext_uv": "jpg", "flight": "02", "hosts": { - "center-0-nayak": { + "center0nayak": { "enabled": true, "fov": "center", "idx": 0 }, - "left-1-nayak": { + "left1nayak": { "enabled": true, "fov": "left", "idx": 1 }, - "right-2-nayak": { + "right2nayak": { "enabled": true, "fov": "right", "idx": 2 @@ -271,7 +271,7 @@ "right_uv_yaml_path": "" } }, - "center-0-nayak": { + "center0nayak": { "cam_fov": "center", "detector": { "actual": "failed", @@ -288,7 +288,7 @@ "total": 0 } }, - "left-1-nayak": { + "left1nayak": { "cam_fov": "right", "detector": { "actual": "stalled", @@ -305,7 +305,7 @@ "total": 0 } }, - "right-2-nayak": { + "right2nayak": { "cam_fov": "left", "detector": { "actual": "stalled", @@ -673,7 +673,7 @@ "uv": "uv_n2" } }, - "master_host": "center-0-nayak", + "master_host": "center0nayak", "max_mpix": 200000, "models": { "allied_gt4907_uv": { @@ -734,9 +734,9 @@ "homography", "detections" ], - "redis_host": "center-0-nayak", + "redis_host": "center0nayak", "requested_geni_params": { - "center-0-nayak": { + "center0nayak": { "ir": { "CorrectionAutoEnabled": 1, "CorrectionAutoUseDeltaTime": 0 @@ -761,7 +761,7 @@ "GainValue": 0 } }, - "left-1-nayak": { + "left1nayak": { "ir": { "CorrectionAutoEnabled": 1 }, @@ -785,7 +785,7 @@ "GainValue": 0 } }, - "right-2-nayak": { + "right2nayak": { "ir": { "CorrectionAutoEnabled": 1 }, diff --git a/src/cfg/nayak/left-1-nayak/chrony.conf b/src/cfg/nayak/left1nayak/chrony.conf similarity index 100% rename from src/cfg/nayak/left-1-nayak/chrony.conf rename to src/cfg/nayak/left1nayak/chrony.conf diff --git a/src/cfg/nayak/left-1-nayak/custom-netplan.yaml b/src/cfg/nayak/left1nayak/custom-netplan.yaml similarity index 100% rename from src/cfg/nayak/left-1-nayak/custom-netplan.yaml rename to src/cfg/nayak/left1nayak/custom-netplan.yaml diff --git a/src/cfg/nayak/redis.conf b/src/cfg/nayak/redis.conf index cf14537..cdababc 100755 --- a/src/cfg/nayak/redis.conf +++ b/src/cfg/nayak/redis.conf @@ -66,7 +66,7 @@ # IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES # JUST COMMENT THE FOLLOWING LINE. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -bind center-0-nayak +bind center0nayak # Protected mode is a layer of security protection, in order to avoid that # Redis instances left open on the internet are accessed and exploited. diff --git a/src/cfg/nayak/right-2-nayak/chrony.conf b/src/cfg/nayak/right2nayak/chrony.conf similarity index 100% rename from src/cfg/nayak/right-2-nayak/chrony.conf rename to src/cfg/nayak/right2nayak/chrony.conf diff --git a/src/cfg/nayak/right-2-nayak/custom-netplan.yaml b/src/cfg/nayak/right2nayak/custom-netplan.yaml similarity index 100% rename from src/cfg/nayak/right-2-nayak/custom-netplan.yaml rename to src/cfg/nayak/right2nayak/custom-netplan.yaml diff --git a/src/cfg/taiga/center-0-taiga/chrony.conf b/src/cfg/taiga/center0taiga/chrony.conf similarity index 100% rename from src/cfg/taiga/center-0-taiga/chrony.conf rename to src/cfg/taiga/center0taiga/chrony.conf diff --git a/src/cfg/taiga/center-0-taiga/custom-netplan.yaml b/src/cfg/taiga/center0taiga/custom-netplan.yaml similarity index 100% rename from src/cfg/taiga/center-0-taiga/custom-netplan.yaml rename to src/cfg/taiga/center0taiga/custom-netplan.yaml diff --git a/src/cfg/taiga/center-0-taiga/ntp.conf b/src/cfg/taiga/center0taiga/ntp.conf similarity index 100% rename from src/cfg/taiga/center-0-taiga/ntp.conf rename to src/cfg/taiga/center0taiga/ntp.conf diff --git a/src/cfg/taiga/config.yaml b/src/cfg/taiga/config.yaml index 63d0d89..4ccce14 100644 --- a/src/cfg/taiga/config.yaml +++ b/src/cfg/taiga/config.yaml @@ -30,15 +30,15 @@ arch: ext_evt: json ext_ins: json hosts: - center-0-taiga: + center0taiga: fov: center idx: 0 enabled: true - left-1-taiga: + left1taiga: fov: left idx: 1 enabled: true - right-2-taiga: + right2taiga: fov: right idx: 2 enabled: true @@ -50,8 +50,8 @@ nas_mnt: "/mnt/flight_data" local_ssd_mnt: "/mnt/data" kamera_dir: "/home/user/kw/kamera" gui_cfg_dir: "/home/user/.config/kamera/gui" -master_host: center-0-taiga -redis_host: center-0-taiga +master_host: center0taiga +redis_host: center0taiga verbosity: 9 max_mpix: 200000 # 0.2e6 diff --git a/src/cfg/taiga/default_system_state.json b/src/cfg/taiga/default_system_state.json index 2b138b2..4c69be1 100755 --- a/src/cfg/taiga/default_system_state.json +++ b/src/cfg/taiga/default_system_state.json @@ -12,17 +12,17 @@ "ext_uv": "jpg", "flight": "00", "hosts": { - "center-0-taiga": { + "center0taiga": { "enabled": true, "fov": "center", "idx": 0 }, - "left-1-taiga": { + "left1taiga": { "enabled": true, "fov": "left", "idx": 1 }, - "right-2-taiga": { + "right2taiga": { "enabled": true, "fov": "right", "idx": 2 @@ -379,7 +379,7 @@ "uv": "uv_n2" } }, - "master_host": "center-0-taiga", + "master_host": "center0taiga", "max_mpix": 200000, "models": { "allied_gt4907_uv": { @@ -434,7 +434,7 @@ } }, "nas_mnt": "/mnt/flight_data", - "center-0-taiga": { + "center0taiga": { "detector": { "desired": "down", "health": { @@ -449,7 +449,7 @@ "total": 0 } }, - "left-1-taiga": { + "left1taiga": { "detector": { "desired": "down", "health": { @@ -460,7 +460,7 @@ "pipefile": null } }, - "right-2-taiga": { + "right2taiga": { "detector": { "desired": "down", "health": { @@ -477,9 +477,9 @@ "homography", "detections" ], - "redis_host": "center-0-taiga", + "redis_host": "center0taiga", "requested_geni_params": { - "center-0-taiga": { + "center0taiga": { "ir": { "CorrectionAutoEnabled": 1, "CorrectionAutoUseDeltaTime": 0 @@ -505,7 +505,7 @@ "GainValue": 0 } }, - "left-1-taiga": { + "left1taiga": { "ir": { "CorrectionAutoEnabled": 1, "CorrectionAutoUseDeltaTime": 0 @@ -531,7 +531,7 @@ "GainValue": 0 } }, - "right-2-taiga": { + "right2taiga": { "ir": { "CorrectionAutoEnabled": 1, "CorrectionAutoUseDeltaTime": 0 diff --git a/src/cfg/taiga/left-1-taiga/chrony.conf b/src/cfg/taiga/left1taiga/chrony.conf similarity index 100% rename from src/cfg/taiga/left-1-taiga/chrony.conf rename to src/cfg/taiga/left1taiga/chrony.conf diff --git a/src/cfg/taiga/left-1-taiga/custom-netplan.yaml b/src/cfg/taiga/left1taiga/custom-netplan.yaml similarity index 100% rename from src/cfg/taiga/left-1-taiga/custom-netplan.yaml rename to src/cfg/taiga/left1taiga/custom-netplan.yaml diff --git a/src/cfg/taiga/redis.conf b/src/cfg/taiga/redis.conf index 2405d5a..7cf8b01 100755 --- a/src/cfg/taiga/redis.conf +++ b/src/cfg/taiga/redis.conf @@ -66,7 +66,7 @@ # IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES # JUST COMMENT THE FOLLOWING LINE. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -bind center-0-taiga +bind center0taiga # Protected mode is a layer of security protection, in order to avoid that # Redis instances left open on the internet are accessed and exploited. diff --git a/src/cfg/taiga/right-2-taiga/chrony.conf b/src/cfg/taiga/right2taiga/chrony.conf similarity index 100% rename from src/cfg/taiga/right-2-taiga/chrony.conf rename to src/cfg/taiga/right2taiga/chrony.conf diff --git a/src/cfg/taiga/right-2-taiga/custom-netplan.yaml b/src/cfg/taiga/right2taiga/custom-netplan.yaml similarity index 100% rename from src/cfg/taiga/right-2-taiga/custom-netplan.yaml rename to src/cfg/taiga/right2taiga/custom-netplan.yaml diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 17076c2..ae4a480 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -230,10 +230,10 @@ def __init__( all_hosts = sorted(SYS_CFG["arch"]["hosts"].keys()) # Only manage hosts belonging to the current system. Redis (/sys) can # accumulate host entries from other systems (cas, nayak, ...); host - # names are suffixed with the system name, e.g. "center-0-taiga". + # names are suffixed with the system name, e.g. "center0taiga". system_name = os.environ.get("SYSTEM_NAME") if system_name: - self.hosts = [h for h in all_hosts if h.endswith("-" + system_name)] + self.hosts = [h for h in all_hosts if h.endswith(system_name)] else: self.hosts = [] if not self.hosts: From 76873524bb7e7710a89d16b87227925b690e8999 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 15:53:38 -0400 Subject: [PATCH 077/139] Move host filtering to a general helper function, use across all nodes that require it --- .../kamcore/scripts/cam_param_monitor_node.py | 5 ++++- .../kamcore/scripts/shapefile_monitor_node.py | 17 +++++++++++----- src/core/roskv/src/roskv/util.py | 20 +++++++++++++++++++ .../scripts/system_control_panel_node.py | 4 +++- .../src/wxpython_gui/DetectorState.py | 7 ++++++- .../wxpython_gui/system_control_panel/gui.py | 14 ++----------- 6 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/core/kamcore/scripts/cam_param_monitor_node.py b/src/core/kamcore/scripts/cam_param_monitor_node.py index e1fc540..ed04154 100755 --- a/src/core/kamcore/scripts/cam_param_monitor_node.py +++ b/src/core/kamcore/scripts/cam_param_monitor_node.py @@ -14,6 +14,7 @@ from roskv.impl.redis_envoy import RedisEnvoy from phase_one.srv import GetPhaseOneParameter, SetPhaseOneParameter from custom_msgs.srv import CamGetAttr, CamSetAttr +from roskv.util import filter_hosts_by_system p1setsrv = "set_phaseone_parameter" p1getsrv = "get_phaseone_parameter" @@ -30,7 +31,9 @@ def __init__(self): print("Redis host: %s" % redis_host) self.envoy = RedisEnvoy(os.environ["REDIS_HOST"], client_name="cam_param_monitor") - self.hosts = self.envoy.get("/sys/arch/hosts").keys() + self.hosts = filter_hosts_by_system( + self.envoy.get("/sys/arch/hosts").keys() + ) self.modes = self.envoy.get("/sys/channels").keys() print("hosts: ") print(self.hosts) diff --git a/src/core/kamcore/scripts/shapefile_monitor_node.py b/src/core/kamcore/scripts/shapefile_monitor_node.py index bfe650c..7f4f6c3 100755 --- a/src/core/kamcore/scripts/shapefile_monitor_node.py +++ b/src/core/kamcore/scripts/shapefile_monitor_node.py @@ -14,8 +14,8 @@ import rospy from custom_msgs.msg import GSOF_INS - -HOSTS = [] +from roskv.impl.redis_envoy import RedisEnvoy +from roskv.util import filter_hosts_by_system # Location of the geod file. KAM_DIR = os.environ["DOCKER_KAMERA_DIR"] @@ -31,6 +31,13 @@ class ShapefileMonitor(object): def __init__(self): self.redis = redis.Redis(os.environ["REDIS_HOST"], client_name="shapefile_monitor") + envoy = RedisEnvoy(os.environ["REDIS_HOST"], + client_name="shapefile_monitor") + self.hosts = filter_hosts_by_system( + envoy.get("/sys/arch/hosts").keys() + ) + print("hosts: ") + print(self.hosts) self.cnt = 0 self.use_archive_region = False self.archive_region = None @@ -138,13 +145,13 @@ def ins_callback(self, msg): print("is_archiving = 0") self.redis.set("/sys/arch/is_archiving", 0) # make sure nucmode is set to automatic by default - for host in HOSTS: + for host in self.hosts: topic = "/".join(["", 'sys', 'requested_geni_params', host, "ir", "CorrectionAutoEnabled"]) self.redis.set(topic, "1") else: # make sure nucmode is set to automatic by default - for host in HOSTS: + for host in self.hosts: topic = "/".join(["", 'sys', 'requested_geni_params', host, "ir", "CorrectionAutoEnabled"]) self.redis.set(topic, "1") @@ -153,7 +160,7 @@ def ins_callback(self, msg): if not allow_ir_nuc and is_archiving: print("Turning off NUCing when archiving.") # Make sure NUCing is turned off - for host in HOSTS: + for host in self.hosts: topic = "/".join(["", 'sys', 'requested_geni_params', host, "ir", "CorrectionAutoEnabled"]) self.redis.set(topic, "0") diff --git a/src/core/roskv/src/roskv/util.py b/src/core/roskv/src/roskv/util.py index 27c00b3..9266b41 100755 --- a/src/core/roskv/src/roskv/util.py +++ b/src/core/roskv/src/roskv/util.py @@ -119,6 +119,26 @@ def wildcard(pat, s): return mat is not None +def filter_hosts_by_system(all_hosts, system_name=None): + """Return host names belonging to the current system. + + Redis (/sys) can accumulate host entries from other systems; host + names are suffixed with the system name, e.g. "center0taiga". + """ + import os + if system_name is None: + system_name = os.environ.get("SYSTEM_NAME") + all_hosts = sorted(all_hosts) + if system_name: + hosts = [h for h in all_hosts if h.endswith(system_name)] + else: + hosts = [] + if not hosts: + # Fall back to every host if the naming convention doesn't match. + hosts = all_hosts + return hosts + + def redis_decode(keys, values, key=None, flatten=False, as_json=True): # type: (List[str], List[str], Optional[str], bool, bool) -> dict """ diff --git a/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py b/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py index 03c632d..15dda6e 100755 --- a/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py +++ b/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py @@ -42,6 +42,7 @@ from wxpython_gui.system_control_panel.gui import MainFrame from roskv.impl.redis_envoy import RedisEnvoy +from roskv.util import filter_hosts_by_system def main(): @@ -50,7 +51,8 @@ def main(): envoy = RedisEnvoy(os.environ["REDIS_HOST"], client_name=node_name) channels = envoy.get("/sys/channels").keys() - hosts = envoy.get("/sys/arch/hosts") + all_hosts = envoy.get("/sys/arch/hosts") + hosts = {h: all_hosts[h] for h in filter_hosts_by_system(all_hosts.keys())} topic_names = {} diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/DetectorState.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/DetectorState.py index b8cbb02..1b5892b 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/DetectorState.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/DetectorState.py @@ -3,6 +3,7 @@ from enum import Enum from wxpython_gui.cfg import SYS_CFG, kv from wxpython_gui.utils import diffpair +from roskv.util import filter_hosts_by_system class EPodStatus(Enum): @@ -161,4 +162,8 @@ def set_detector_state(system, host, desired): system.run_command("detector", host, verb) -detector_state = DetectorState(kv, SYS_CFG["arch"]["hosts"]) +_hosts = SYS_CFG["arch"]["hosts"] +detector_state = DetectorState( + kv, + {h: _hosts[h] for h in filter_hosts_by_system(_hosts.keys())}, +) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index ae4a480..8fdf8b5 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -49,7 +49,7 @@ # from roskv.impl.rosparam_kv import RosParamKV as ImplKV from roskv.impl.redis_envoy import RedisEnvoy as ImplEnvoy from roskv.rendezvous import ConditionalRendezvous # , Governor -from roskv.util import simple_hash_args, MyTimeoutError +from roskv.util import simple_hash_args, MyTimeoutError, filter_hosts_by_system # Kamera imports from custom_msgs.srv import ( @@ -228,17 +228,7 @@ def __init__( } all_hosts = sorted(SYS_CFG["arch"]["hosts"].keys()) - # Only manage hosts belonging to the current system. Redis (/sys) can - # accumulate host entries from other systems (cas, nayak, ...); host - # names are suffixed with the system name, e.g. "center0taiga". - system_name = os.environ.get("SYSTEM_NAME") - if system_name: - self.hosts = [h for h in all_hosts if h.endswith(system_name)] - else: - self.hosts = [] - if not self.hosts: - # Fall back to every host if the naming convention doesn't match. - self.hosts = all_hosts + self.hosts = filter_hosts_by_system(all_hosts) print("HOSTS: ") print(self.hosts) self.last_busy = {h: False for h in self.hosts} From 42ebc80198aa8577c63d7ace37cf1c7f8834c6ab Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 15 Jun 2026 16:23:42 -0400 Subject: [PATCH 078/139] Update netplans for taiga systems --- .../taiga/center0taiga/custom-netplan.yaml | 1 - src/cfg/taiga/custom-netplan.yaml | 1 + src/cfg/taiga/left1taiga/custom-netplan.yaml | 46 ----------------- src/cfg/taiga/right2taiga/custom-netplan.yaml | 50 ------------------- 4 files changed, 1 insertion(+), 97 deletions(-) delete mode 100644 src/cfg/taiga/center0taiga/custom-netplan.yaml create mode 100644 src/cfg/taiga/custom-netplan.yaml delete mode 100755 src/cfg/taiga/left1taiga/custom-netplan.yaml delete mode 100644 src/cfg/taiga/right2taiga/custom-netplan.yaml diff --git a/src/cfg/taiga/center0taiga/custom-netplan.yaml b/src/cfg/taiga/center0taiga/custom-netplan.yaml deleted file mode 100644 index 6948d55..0000000 --- a/src/cfg/taiga/center0taiga/custom-netplan.yaml +++ /dev/null @@ -1 +0,0 @@ -# Important note! The ethernet device names are set by 70-persistent-net.rules on nuvo0 but netplan on nuvo1/2 --- ## Netplan for nuvo1 network: version: 2 ethernets: # IR Camera mobo_top: match: macaddress: 78:d0:04:26:c7:26 set-name: mobo_top addresses: [192.168.1.10/24] optional: true # UV Camera mobo_btm: match: macaddress: 78:d0:04:26:c7:27 set-name: mobo_btm addresses: [192.168.2.10/24] optional: true # LAN 1g_pci_bot: match: macaddress: 90:e2:ba:9f:ff:6b set-name: 1g_pci_bot addresses: - 192.168.88.10/24 gateway4: 192.168.88.1 nameservers: addresses: [8.8.8.8, 192.168.88.10] optional: true # NAS pci_top: mtu: 9000 match: macaddress: a0:36:9f:c2:3e:3c set-name: pci_top addresses: [192.168.198.100/24] optional: true # P1 Camera pci_btm: mtu: 9000 match: macaddress: a0:36:9f:c2:3e:3e set-name: pci_btm addresses: [192.168.4.10/24] optional: true ... \ No newline at end of file diff --git a/src/cfg/taiga/custom-netplan.yaml b/src/cfg/taiga/custom-netplan.yaml new file mode 100644 index 0000000..edc4cc1 --- /dev/null +++ b/src/cfg/taiga/custom-netplan.yaml @@ -0,0 +1 @@ +--- network: version: 2 ethernets: # IR Camera - outer mobo enp0s31f6: addresses: [192.168.1.10/24] optional: true # LAN - inner MOBO enp2s0: addresses: - 192.168.88.10/24 routes: - to: default via: 192.168.88.1 nameservers: addresses: [8.8.8.8, 192.168.88.10] optional: true # P1 Camera - PCIE 0 enp3s0f0np0: mtu: 9000 addresses: [192.168.4.10/24] optional: true # UV Camera - PCIE 1 enp3s0f1np1: addresses: [192.168.2.10/24] optional: true # NAS - PCIE 3 enp3s0f3np3: mtu: 9000 addresses: [192.168.198.100/24] optional: true ... \ No newline at end of file diff --git a/src/cfg/taiga/left1taiga/custom-netplan.yaml b/src/cfg/taiga/left1taiga/custom-netplan.yaml deleted file mode 100755 index 325dbad..0000000 --- a/src/cfg/taiga/left1taiga/custom-netplan.yaml +++ /dev/null @@ -1,46 +0,0 @@ ---- -## Netplan for nuvo1 -network: - version: 2 - ethernets: - # IR Camera - mobo_top: - match: - macaddress: 78:d0:04:26:c7:28 - set-name: mobo_top - addresses: [192.168.1.11/24] - optional: true - # UV Camera - mobo_btm: - match: - macaddress: 78:d0:04:26:c7:29 - set-name: mobo_btm - addresses: [192.168.2.11/24] - optional: true - # LAN - 1g_pci_bot: - match: - macaddress: 90:e2:ba:5c:97:cf - set-name: 1g_pci_bot - addresses: - - 192.168.88.11/24 - gateway4: 192.168.88.1 - nameservers: - addresses: [8.8.8.8, 192.168.88.10] - optional: true - # NAS - pci_top: - match: - macaddress: a0:36:9f:21:3c:04 - set-name: pci_top - addresses: - - 192.168.198.101/24 - optional: true - # P1 Camera - pci_btm: - match: - macaddress: a0:36:9f:21:3c:06 - set-name: pci_btm - addresses: [192.168.4.11/24] - optional: true -... diff --git a/src/cfg/taiga/right2taiga/custom-netplan.yaml b/src/cfg/taiga/right2taiga/custom-netplan.yaml deleted file mode 100644 index bd12b50..0000000 --- a/src/cfg/taiga/right2taiga/custom-netplan.yaml +++ /dev/null @@ -1,50 +0,0 @@ ---- -network: - version: 2 - ethernets: - # IR Camera - mobo_top: - match: - macaddress: 78:d0:04:26:c7:2a - set-name: mobo_top - addresses: - - 192.168.1.12/24 - optional: true - # UV Camera - mobo_btm: - match: - macaddress: 78:d0:04:26:c7:2b - set-name: mobo_btm - addresses: - - 192.168.2.12/24 - optional: true - # LAN - 1g_pci_bot: - match: - macaddress: 90:e2:ba:9f:fb:13 - set-name: 1g_pci_bot - addresses: - - 192.168.88.12/24 - gateway4: 192.168.88.1 - nameservers: - addresses: [8.8.8.8, 192.168.88.12] - optional: true - # NAS - pci_top: - mtu: 9000 - match: - macaddress: a0:36:9f:50:66:cc - set-name: pci_top - addresses: [192.168.198.102/24] - optional: true - # P1 Camera - pci_btm: - mtu: 9000 - match: - macaddress: a0:36:9f:50:66:ce - set-name: pci_btm - addresses: - - 192.168.4.12/24 - optional: true -... - From f86c60e45d9e9c4c168cd583c8c41a07d9b68308 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Mon, 15 Jun 2026 16:26:03 -0400 Subject: [PATCH 079/139] Add core to leader docker build --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index e7d5cc8..8d0dd82 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -70,6 +70,7 @@ services: profiles: - core - follower + - leader - all postproc: From c1b00a402d0f3f28e5add3d74b75f7c3bb67851c Mon Sep 17 00:00:00 2001 From: romleiaj Date: Mon, 15 Jun 2026 16:29:58 -0400 Subject: [PATCH 080/139] Move location of netplan yaml --- provision/ansible/playbooks/cas/configure.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index 688336e..70004d7 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -103,7 +103,7 @@ - name: Setup netplan configuration. become: True copy: - src: "{{ kamera_dir }}/src/cfg/{{ config_dir }}/{{ inventory_hostname }}/custom-netplan.yaml" + src: "{{ kamera_dir }}/src/cfg/{{ config_dir }}/custom-netplan.yaml" remote_src: true dest: /etc/netplan/{{ inventory_hostname }}-netplan.yaml owner: root From 26cc5ddedd3e59f63d7bd0252ca84cf76b075e51 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 07:12:01 -0400 Subject: [PATCH 081/139] Reconfigure start/stop scripts to use center/left/right convention, rather than per system unique names --- provision/ansible/functions.sh | 15 +++++++++++++++ .../desktop_shortcuts/reboot_all.desktop | 2 +- .../desktop_shortcuts/reboot_cas0.desktop | 6 ------ .../desktop_shortcuts/reboot_cas1.desktop | 6 ------ .../desktop_shortcuts/reboot_cas2.desktop | 6 ------ ...utdown_nuvo1.desktop => reboot_center.desktop} | 6 +++--- .../{reboot_nuvo2.desktop => reboot_left.desktop} | 6 +++--- ...{reboot_nuvo1.desktop => reboot_right.desktop} | 6 +++--- .../desktop_shortcuts/shutdown_all.desktop | 2 +- .../desktop_shortcuts/shutdown_cas0.desktop | 6 ------ .../desktop_shortcuts/shutdown_cas1.desktop | 6 ------ .../desktop_shortcuts/shutdown_cas2.desktop | 6 ------ .../desktop_shortcuts/shutdown_center.desktop | 6 ++++++ ...utdown_nuvo2.desktop => shutdown_left.desktop} | 6 +++--- .../desktop_shortcuts/shutdown_right.desktop | 6 ++++++ provision/start_stop/reboot_all.sh | 2 +- .../{reboot_cas2.sh => reboot_center.sh} | 2 +- .../start_stop/{reboot_cas0.sh => reboot_left.sh} | 2 +- provision/start_stop/reboot_nuvo2.sh | 8 -------- .../{reboot_cas1.sh => reboot_right.sh} | 2 +- provision/start_stop/shutdown_all.sh | 2 +- provision/start_stop/shutdown_cas0.sh | 8 -------- provision/start_stop/shutdown_cas1.sh | 8 -------- provision/start_stop/shutdown_cas2.sh | 8 -------- provision/start_stop/shutdown_center.sh | 8 ++++++++ .../{reboot_nuvo1.sh => shutdown_left.sh} | 2 +- provision/start_stop/shutdown_nuvo1.sh | 8 -------- provision/start_stop/shutdown_nuvo2.sh | 8 -------- provision/start_stop/shutdown_right.sh | 8 ++++++++ 29 files changed, 63 insertions(+), 104 deletions(-) delete mode 100755 provision/start_stop/desktop_shortcuts/reboot_cas0.desktop delete mode 100755 provision/start_stop/desktop_shortcuts/reboot_cas1.desktop delete mode 100755 provision/start_stop/desktop_shortcuts/reboot_cas2.desktop rename provision/start_stop/desktop_shortcuts/{shutdown_nuvo1.desktop => reboot_center.desktop} (62%) mode change 100755 => 100644 rename provision/start_stop/desktop_shortcuts/{reboot_nuvo2.desktop => reboot_left.desktop} (64%) mode change 100755 => 100644 rename provision/start_stop/desktop_shortcuts/{reboot_nuvo1.desktop => reboot_right.desktop} (64%) mode change 100755 => 100644 delete mode 100755 provision/start_stop/desktop_shortcuts/shutdown_cas0.desktop delete mode 100755 provision/start_stop/desktop_shortcuts/shutdown_cas1.desktop delete mode 100755 provision/start_stop/desktop_shortcuts/shutdown_cas2.desktop create mode 100644 provision/start_stop/desktop_shortcuts/shutdown_center.desktop rename provision/start_stop/desktop_shortcuts/{shutdown_nuvo2.desktop => shutdown_left.desktop} (62%) mode change 100755 => 100644 create mode 100644 provision/start_stop/desktop_shortcuts/shutdown_right.desktop rename provision/start_stop/{reboot_cas2.sh => reboot_center.sh} (77%) rename provision/start_stop/{reboot_cas0.sh => reboot_left.sh} (78%) delete mode 100755 provision/start_stop/reboot_nuvo2.sh rename provision/start_stop/{reboot_cas1.sh => reboot_right.sh} (78%) delete mode 100755 provision/start_stop/shutdown_cas0.sh delete mode 100755 provision/start_stop/shutdown_cas1.sh delete mode 100755 provision/start_stop/shutdown_cas2.sh create mode 100755 provision/start_stop/shutdown_center.sh rename provision/start_stop/{reboot_nuvo1.sh => shutdown_left.sh} (77%) delete mode 100755 provision/start_stop/shutdown_nuvo1.sh delete mode 100755 provision/start_stop/shutdown_nuvo2.sh create mode 100755 provision/start_stop/shutdown_right.sh diff --git a/provision/ansible/functions.sh b/provision/ansible/functions.sh index eb5f2fe..c73d7c5 100644 --- a/provision/ansible/functions.sh +++ b/provision/ansible/functions.sh @@ -38,6 +38,21 @@ function kamera_cas_all() { ansible-playbook playbooks/cas/all.yml -i hosts.yml --ask-become-pass -u "user" -e 'ansible_python_interpreter=/usr/bin/python3' --limit $1 } +function kamera_host_for_position() { + local position=$1 + local system_name + system_name=$(tr -d '[:space:]' < /home/user/kw/SYSTEM_NAME) + case $position in + center) echo "center0${system_name}" ;; + left) echo "left1${system_name}" ;; + right) echo "right2${system_name}" ;; + *) + echo "Unknown position: ${position} (expected center, left, or right)" >&2 + return 1 + ;; + esac +} + function kamera_shutdown() { ansible-playbook playbooks/cas/stopstart.yml -i hosts.yml --become-password-file ".password" --tags "shutdown" --limit $1 } diff --git a/provision/start_stop/desktop_shortcuts/reboot_all.desktop b/provision/start_stop/desktop_shortcuts/reboot_all.desktop index 60cebe6..1979eab 100755 --- a/provision/start_stop/desktop_shortcuts/reboot_all.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_all.desktop @@ -1,5 +1,5 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/noaa_kamera/provision/start_stop/reboot_all.sh' +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/reboot_all.sh' Name=reboot_all Terminal=true Type=Application diff --git a/provision/start_stop/desktop_shortcuts/reboot_cas0.desktop b/provision/start_stop/desktop_shortcuts/reboot_cas0.desktop deleted file mode 100755 index f2f1dbd..0000000 --- a/provision/start_stop/desktop_shortcuts/reboot_cas0.desktop +++ /dev/null @@ -1,6 +0,0 @@ -[Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/noaa_kamera/provision/start_stop/reboot_cas0.sh' -Name=reboot_cas0 -Terminal=true -Type=Application -Name[en_US]=reboot_cas0 diff --git a/provision/start_stop/desktop_shortcuts/reboot_cas1.desktop b/provision/start_stop/desktop_shortcuts/reboot_cas1.desktop deleted file mode 100755 index ee329fd..0000000 --- a/provision/start_stop/desktop_shortcuts/reboot_cas1.desktop +++ /dev/null @@ -1,6 +0,0 @@ -[Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/noaa_kamera/provision/start_stop/reboot_cas1.sh' -Name=reboot_cas1 -Terminal=true -Type=Application -Name[en_US]=reboot_cas1 diff --git a/provision/start_stop/desktop_shortcuts/reboot_cas2.desktop b/provision/start_stop/desktop_shortcuts/reboot_cas2.desktop deleted file mode 100755 index 8f889e0..0000000 --- a/provision/start_stop/desktop_shortcuts/reboot_cas2.desktop +++ /dev/null @@ -1,6 +0,0 @@ -[Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/noaa_kamera/provision/start_stop/reboot_cas2.sh' -Name=reboot_cas2 -Terminal=true -Type=Application -Name[en_US]=reboot_cas2 diff --git a/provision/start_stop/desktop_shortcuts/shutdown_nuvo1.desktop b/provision/start_stop/desktop_shortcuts/reboot_center.desktop old mode 100755 new mode 100644 similarity index 62% rename from provision/start_stop/desktop_shortcuts/shutdown_nuvo1.desktop rename to provision/start_stop/desktop_shortcuts/reboot_center.desktop index 1688508..21b2440 --- a/provision/start_stop/desktop_shortcuts/shutdown_nuvo1.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_center.desktop @@ -1,6 +1,6 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/shutdown_nuvo1.sh' -Name=shutdown_nuvo1 +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/reboot_center.sh' +Name=reboot_center Terminal=true Type=Application -Name[en_US]=shutdown_nuvo1 +Name[en_US]=reboot_center diff --git a/provision/start_stop/desktop_shortcuts/reboot_nuvo2.desktop b/provision/start_stop/desktop_shortcuts/reboot_left.desktop old mode 100755 new mode 100644 similarity index 64% rename from provision/start_stop/desktop_shortcuts/reboot_nuvo2.desktop rename to provision/start_stop/desktop_shortcuts/reboot_left.desktop index d7e34f8..b0a6a66 --- a/provision/start_stop/desktop_shortcuts/reboot_nuvo2.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_left.desktop @@ -1,6 +1,6 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/reboot_nuvo2.sh' -Name=reboot_nuvo2 +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/reboot_left.sh' +Name=reboot_left Terminal=true Type=Application -Name[en_US]=reboot_nuvo2 +Name[en_US]=reboot_left diff --git a/provision/start_stop/desktop_shortcuts/reboot_nuvo1.desktop b/provision/start_stop/desktop_shortcuts/reboot_right.desktop old mode 100755 new mode 100644 similarity index 64% rename from provision/start_stop/desktop_shortcuts/reboot_nuvo1.desktop rename to provision/start_stop/desktop_shortcuts/reboot_right.desktop index 0513c28..6b43c05 --- a/provision/start_stop/desktop_shortcuts/reboot_nuvo1.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_right.desktop @@ -1,6 +1,6 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/reboot_nuvo1.sh' -Name=reboot_nuvo1 +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/reboot_right.sh' +Name=reboot_right Terminal=true Type=Application -Name[en_US]=reboot_nuvo1 +Name[en_US]=reboot_right diff --git a/provision/start_stop/desktop_shortcuts/shutdown_all.desktop b/provision/start_stop/desktop_shortcuts/shutdown_all.desktop index b871eb8..4e65c37 100755 --- a/provision/start_stop/desktop_shortcuts/shutdown_all.desktop +++ b/provision/start_stop/desktop_shortcuts/shutdown_all.desktop @@ -1,5 +1,5 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/noaa_kamera/provision/start_stop/shutdown_all.sh' +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/shutdown_all.sh' Name=shutdown_all Terminal=true Type=Application diff --git a/provision/start_stop/desktop_shortcuts/shutdown_cas0.desktop b/provision/start_stop/desktop_shortcuts/shutdown_cas0.desktop deleted file mode 100755 index 72df05a..0000000 --- a/provision/start_stop/desktop_shortcuts/shutdown_cas0.desktop +++ /dev/null @@ -1,6 +0,0 @@ -[Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/noaa_kamera/provision/start_stop/shutdown_cas0.sh' -Name=shutdown_cas0 -Terminal=true -Type=Application -Name[en_US]=shutdown_cas0 diff --git a/provision/start_stop/desktop_shortcuts/shutdown_cas1.desktop b/provision/start_stop/desktop_shortcuts/shutdown_cas1.desktop deleted file mode 100755 index a3cfbe4..0000000 --- a/provision/start_stop/desktop_shortcuts/shutdown_cas1.desktop +++ /dev/null @@ -1,6 +0,0 @@ -[Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/noaa_kamera/provision/start_stop/shutdown_cas1.sh' -Name=shutdown_cas1 -Terminal=true -Type=Application -Name[en_US]=shutdown_cas1 diff --git a/provision/start_stop/desktop_shortcuts/shutdown_cas2.desktop b/provision/start_stop/desktop_shortcuts/shutdown_cas2.desktop deleted file mode 100755 index 442d80d..0000000 --- a/provision/start_stop/desktop_shortcuts/shutdown_cas2.desktop +++ /dev/null @@ -1,6 +0,0 @@ -[Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/noaa_kamera/provision/start_stop/shutdown_cas2.sh' -Name=shutdown_cas2 -Terminal=true -Type=Application -Name[en_US]=shutdown_cas2 diff --git a/provision/start_stop/desktop_shortcuts/shutdown_center.desktop b/provision/start_stop/desktop_shortcuts/shutdown_center.desktop new file mode 100644 index 0000000..6db3d90 --- /dev/null +++ b/provision/start_stop/desktop_shortcuts/shutdown_center.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/shutdown_center.sh' +Name=shutdown_center +Terminal=true +Type=Application +Name[en_US]=shutdown_center diff --git a/provision/start_stop/desktop_shortcuts/shutdown_nuvo2.desktop b/provision/start_stop/desktop_shortcuts/shutdown_left.desktop old mode 100755 new mode 100644 similarity index 62% rename from provision/start_stop/desktop_shortcuts/shutdown_nuvo2.desktop rename to provision/start_stop/desktop_shortcuts/shutdown_left.desktop index 983c23f..57e0ec7 --- a/provision/start_stop/desktop_shortcuts/shutdown_nuvo2.desktop +++ b/provision/start_stop/desktop_shortcuts/shutdown_left.desktop @@ -1,6 +1,6 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/shutdown_nuvo2.sh' -Name=shutdown_nuvo2 +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/shutdown_left.sh' +Name=shutdown_left Terminal=true Type=Application -Name[en_US]=shutdown_nuvo2 +Name[en_US]=shutdown_left diff --git a/provision/start_stop/desktop_shortcuts/shutdown_right.desktop b/provision/start_stop/desktop_shortcuts/shutdown_right.desktop new file mode 100644 index 0000000..5688b18 --- /dev/null +++ b/provision/start_stop/desktop_shortcuts/shutdown_right.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/shutdown_right.sh' +Name=shutdown_right +Terminal=true +Type=Application +Name[en_US]=shutdown_right diff --git a/provision/start_stop/reboot_all.sh b/provision/start_stop/reboot_all.sh index aa568d6..0473162 100755 --- a/provision/start_stop/reboot_all.sh +++ b/provision/start_stop/reboot_all.sh @@ -7,4 +7,4 @@ SYSTEM_NAME=$(cat /home/user/kw/SYSTEM_NAME) cd ${DIR}/../ansible/ source ${DIR}/../ansible/functions.sh -kamera_reboot SYSTEM_NAME +kamera_reboot ${SYSTEM_NAME} diff --git a/provision/start_stop/reboot_cas2.sh b/provision/start_stop/reboot_center.sh similarity index 77% rename from provision/start_stop/reboot_cas2.sh rename to provision/start_stop/reboot_center.sh index ab7b5ee..ca172a4 100755 --- a/provision/start_stop/reboot_cas2.sh +++ b/provision/start_stop/reboot_center.sh @@ -5,4 +5,4 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" cd ${DIR}/../ansible/ source ${DIR}/../ansible/functions.sh -kamera_reboot cas2 +kamera_reboot $(kamera_host_for_position center) diff --git a/provision/start_stop/reboot_cas0.sh b/provision/start_stop/reboot_left.sh similarity index 78% rename from provision/start_stop/reboot_cas0.sh rename to provision/start_stop/reboot_left.sh index 6bd6125..634a4f5 100755 --- a/provision/start_stop/reboot_cas0.sh +++ b/provision/start_stop/reboot_left.sh @@ -5,4 +5,4 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" cd ${DIR}/../ansible/ source ${DIR}/../ansible/functions.sh -kamera_reboot cas0 +kamera_reboot $(kamera_host_for_position left) diff --git a/provision/start_stop/reboot_nuvo2.sh b/provision/start_stop/reboot_nuvo2.sh deleted file mode 100755 index 20224b4..0000000 --- a/provision/start_stop/reboot_nuvo2.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_reboot nuvo2 diff --git a/provision/start_stop/reboot_cas1.sh b/provision/start_stop/reboot_right.sh similarity index 78% rename from provision/start_stop/reboot_cas1.sh rename to provision/start_stop/reboot_right.sh index dc8fbae..f9eb368 100755 --- a/provision/start_stop/reboot_cas1.sh +++ b/provision/start_stop/reboot_right.sh @@ -5,4 +5,4 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" cd ${DIR}/../ansible/ source ${DIR}/../ansible/functions.sh -kamera_reboot cas1 +kamera_reboot $(kamera_host_for_position right) diff --git a/provision/start_stop/shutdown_all.sh b/provision/start_stop/shutdown_all.sh index e1f6563..b075f73 100755 --- a/provision/start_stop/shutdown_all.sh +++ b/provision/start_stop/shutdown_all.sh @@ -6,4 +6,4 @@ SYSTEM_NAME=$(cat /home/user/kw/SYSTEM_NAME) cd ${DIR}/../ansible/ source ${DIR}/../ansible/functions.sh -kamera_shutdown SYSTEM_NAME +kamera_shutdown ${SYSTEM_NAME} diff --git a/provision/start_stop/shutdown_cas0.sh b/provision/start_stop/shutdown_cas0.sh deleted file mode 100755 index 58355f5..0000000 --- a/provision/start_stop/shutdown_cas0.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_shutdown cas0 diff --git a/provision/start_stop/shutdown_cas1.sh b/provision/start_stop/shutdown_cas1.sh deleted file mode 100755 index ddcdec5..0000000 --- a/provision/start_stop/shutdown_cas1.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_shutdown cas1 diff --git a/provision/start_stop/shutdown_cas2.sh b/provision/start_stop/shutdown_cas2.sh deleted file mode 100755 index d12a3ef..0000000 --- a/provision/start_stop/shutdown_cas2.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_shutdown cas2 diff --git a/provision/start_stop/shutdown_center.sh b/provision/start_stop/shutdown_center.sh new file mode 100755 index 0000000..ebe417c --- /dev/null +++ b/provision/start_stop/shutdown_center.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# Location of this script. +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +cd ${DIR}/../ansible/ +source ${DIR}/../ansible/functions.sh +kamera_shutdown $(kamera_host_for_position center) diff --git a/provision/start_stop/reboot_nuvo1.sh b/provision/start_stop/shutdown_left.sh similarity index 77% rename from provision/start_stop/reboot_nuvo1.sh rename to provision/start_stop/shutdown_left.sh index 7dcac5f..847f7ac 100755 --- a/provision/start_stop/reboot_nuvo1.sh +++ b/provision/start_stop/shutdown_left.sh @@ -5,4 +5,4 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" cd ${DIR}/../ansible/ source ${DIR}/../ansible/functions.sh -kamera_reboot nuvo1 +kamera_shutdown $(kamera_host_for_position left) diff --git a/provision/start_stop/shutdown_nuvo1.sh b/provision/start_stop/shutdown_nuvo1.sh deleted file mode 100755 index 8be79a9..0000000 --- a/provision/start_stop/shutdown_nuvo1.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_shutdown nuvo1 diff --git a/provision/start_stop/shutdown_nuvo2.sh b/provision/start_stop/shutdown_nuvo2.sh deleted file mode 100755 index 6be2431..0000000 --- a/provision/start_stop/shutdown_nuvo2.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_shutdown nuvo2 diff --git a/provision/start_stop/shutdown_right.sh b/provision/start_stop/shutdown_right.sh new file mode 100755 index 0000000..7f61cae --- /dev/null +++ b/provision/start_stop/shutdown_right.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# Location of this script. +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +cd ${DIR}/../ansible/ +source ${DIR}/../ansible/functions.sh +kamera_shutdown $(kamera_host_for_position right) From c655f8723de6b06288204215275c934494545f37 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Tue, 16 Jun 2026 07:17:54 -0400 Subject: [PATCH 082/139] Update startup script to be more general, new naming scheme --- scripts/system.py | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/scripts/system.py b/scripts/system.py index f6b7087..4d35520 100644 --- a/scripts/system.py +++ b/scripts/system.py @@ -1,35 +1,21 @@ import sys -# import xmlrpclib # Python2 from xmlrpc.client import ServerProxy, Fault with open("/home/user/kw/SYSTEM_NAME") as f: SYSTEM_NAME = f.read().strip() -if SYSTEM_NAME == "taiga": - group = "taiga" - hosts = ["nuvo0", "nuvo1", "nuvo2"] - pod = [ - "image_manager", - "kamerad", - f"{group}:fps_monitor", - f"{group}:imageview", - f"{group}:cam_rgb", - f"{group}:cam_ir", - f"{group}:cam_uv", - ] -else: - group = "nayak" - hosts = ["cas0", "cas1", "cas2"] - pod = [ - "image_manager", - "kamerad", - f"{group}:fps_monitor", - f"{group}:imageview", - f"{group}:cam_rgb", - f"{group}:cam_ir", - f"{group}:cam_uv", - ] +hosts = [ f"center0{SYSTEM_NAME}", "left1{SYSTEM_NAME}", "right2{SYSTEM_NAME}"] +group = SYSTEM_NAME +pod = [ + "image_manager", + "kamerad", + f"{group}:fps_monitor", + f"{group}:imageview", + f"{group}:cam_rgb", + f"{group}:cam_ir", + f"{group}:cam_uv", +] host = sys.argv[1].strip() if host not in hosts: From dabbaec57e9743016b88d4238940bf9295a76526 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Tue, 26 May 2026 08:33:17 -0400 Subject: [PATCH 083/139] README --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 09aa463..0c82ba9 100644 --- a/README.md +++ b/README.md @@ -38,9 +38,7 @@ make gui Note that these images take up a large amount of disk space, especially the VIAME image which is 30Gb, and it can take several hours to builds. The core images are faster and lighter weight. ## Partners and Acknowledgements -KAMERA was developed in collaboration with: - - NOAA Marine Mammal Laboratory - - University of Washington +KAMERA was developed in collaboration with the NOAA Marine Mammal Laboratory and the University of Washington. We thank all contributors who have helped in developing KAMERA, with special thanks to Mike McDermott and Matt Brown who created the core system back in 2018. ## License From e68fad4b50894ead7a5a43d1ae275119cc415123 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 07:22:58 -0400 Subject: [PATCH 084/139] Add script to install desktop shortcuts --- .../start_stop/install_desktop_shortcuts.sh | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100755 provision/start_stop/install_desktop_shortcuts.sh diff --git a/provision/start_stop/install_desktop_shortcuts.sh b/provision/start_stop/install_desktop_shortcuts.sh new file mode 100755 index 0000000..6ef5b06 --- /dev/null +++ b/provision/start_stop/install_desktop_shortcuts.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# Copy start_stop .desktop shortcuts to a desktop folder and mark them launchable. +# +# GNOME requires both metadata::trusted and the executable bit before a .desktop +# file on the Desktop can be double-clicked without the "Allow launching" prompt. +# Order matters: set trusted first, then chmod +x. +# +# Usage: +# ./install_desktop_shortcuts.sh # installs to ~/Desktop +# ./install_desktop_shortcuts.sh ~/Desktop # custom destination + +set -euo pipefail + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" +SRC="${DIR}/desktop_shortcuts" +DEST="${1:-${HOME}/Desktop}" + +if [[ ! -d "${SRC}" ]]; then + echo "Missing shortcut directory: ${SRC}" >&2 + exit 1 +fi + +mkdir -p "${DEST}" + +trust_desktop_file() { + local file=$1 + if command -v gio >/dev/null 2>&1; then + if [[ -n "${DBUS_SESSION_BUS_ADDRESS:-}" ]]; then + gio set "${file}" metadata::trusted true + else + dbus-launch gio set "${file}" metadata::trusted true + fi + else + echo "Warning: gio not found; ${file} may still prompt for trust" >&2 + fi + chmod +x "${file}" +} + +for shortcut in "${SRC}"/*.desktop; do + [[ -e "${shortcut}" ]] || continue + dest_file="${DEST}/$(basename "${shortcut}")" + cp "${shortcut}" "${dest_file}" + trust_desktop_file "${dest_file}" + echo "Installed ${dest_file}" +done From e4440bc1eabf95e7ee0b7580e941d7792fb620d0 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 07:26:53 -0400 Subject: [PATCH 085/139] Add desktop install to leader provision --- provision/ansible/playbooks/cas/configure.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index 70004d7..1f987fc 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -194,6 +194,10 @@ remote_src: true dest: /home/user/.bash_aliases + - name: Install start/stop desktop shortcuts + when: leader | default(false) + command: bash {{ kamera_dir }}/provision/start_stop/install_desktop_shortcuts.sh + - name: Disable sleep state on subsystems. become: True when: follower or leader or gui From 8ad74c0709d5ba4f45031dfcef2eda111cbde12d Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Tue, 16 Jun 2026 07:35:56 -0400 Subject: [PATCH 086/139] Remove unused runscripts, collapse swap dockerd to one script --- scripts/kamera_halt.sh | 1 - scripts/kamera_run.sh | 1 - scripts/swap_dockerd.sh | 11 ++ scripts/swap_dockerd_cas.sh | 2 - scripts/swap_dockerd_nuvo.sh | 2 - src/run_scripts/newstartup/fixcamip.sh | 25 --- src/run_scripts/newstartup/kamera_halt.sh | 92 --------- src/run_scripts/newstartup/kamera_run.sh | 196 ------------------- src/run_scripts/newstartup/launchcams.sh | 49 ----- src/run_scripts/newstartup/launchcentral.sh | 23 --- src/run_scripts/newstartup/launchdetector.sh | 46 ----- src/run_scripts/newstartup/launchgui.sh | 37 ---- src/run_scripts/newstartup/launchmaster.sh | 17 -- src/run_scripts/newstartup/launchnexus.sh | 44 ----- src/run_scripts/newstartup/launchpod.sh | 50 ----- src/run_scripts/newstartup/launchpostproc.sh | 20 -- src/run_scripts/newstartup/launchsyncpub.sh | 47 ----- src/run_scripts/newstartup/start_central.sh | 14 -- 18 files changed, 11 insertions(+), 666 deletions(-) delete mode 120000 scripts/kamera_halt.sh delete mode 120000 scripts/kamera_run.sh create mode 100755 scripts/swap_dockerd.sh delete mode 100755 scripts/swap_dockerd_cas.sh delete mode 100755 scripts/swap_dockerd_nuvo.sh delete mode 100755 src/run_scripts/newstartup/fixcamip.sh delete mode 100755 src/run_scripts/newstartup/kamera_halt.sh delete mode 100755 src/run_scripts/newstartup/kamera_run.sh delete mode 100755 src/run_scripts/newstartup/launchcams.sh delete mode 100755 src/run_scripts/newstartup/launchcentral.sh delete mode 100755 src/run_scripts/newstartup/launchdetector.sh delete mode 100755 src/run_scripts/newstartup/launchgui.sh delete mode 100755 src/run_scripts/newstartup/launchmaster.sh delete mode 100755 src/run_scripts/newstartup/launchnexus.sh delete mode 100755 src/run_scripts/newstartup/launchpod.sh delete mode 100755 src/run_scripts/newstartup/launchpostproc.sh delete mode 100755 src/run_scripts/newstartup/launchsyncpub.sh delete mode 100755 src/run_scripts/newstartup/start_central.sh diff --git a/scripts/kamera_halt.sh b/scripts/kamera_halt.sh deleted file mode 120000 index a94aea2..0000000 --- a/scripts/kamera_halt.sh +++ /dev/null @@ -1 +0,0 @@ -../src/run_scripts/newstartup/kamera_halt.sh \ No newline at end of file diff --git a/scripts/kamera_run.sh b/scripts/kamera_run.sh deleted file mode 120000 index 6e0812c..0000000 --- a/scripts/kamera_run.sh +++ /dev/null @@ -1 +0,0 @@ -../src/run_scripts/newstartup/kamera_run.sh \ No newline at end of file diff --git a/scripts/swap_dockerd.sh b/scripts/swap_dockerd.sh new file mode 100755 index 0000000..2ef5aa0 --- /dev/null +++ b/scripts/swap_dockerd.sh @@ -0,0 +1,11 @@ +#!/usr/bin/bash + +KAM_REPO_DIR=$(/home/user/.config/kamera/repo_dir.bash) +echo $KAM_REPO_DIR +SYSTEM_NAME=$(cat /home/user/kw/SYSTEM_NAME) +source "${KAM_REPO_DIR}/tmux/${SYSTEM_NAME}/env.sh" + +MASTER_HOST=$(cq '.master_host') + +sudo service docker stop +sudo dockerd --insecure-registry ${MASTER_HOST}:5000 diff --git a/scripts/swap_dockerd_cas.sh b/scripts/swap_dockerd_cas.sh deleted file mode 100755 index 090858e..0000000 --- a/scripts/swap_dockerd_cas.sh +++ /dev/null @@ -1,2 +0,0 @@ -sudo service docker stop -sudo dockerd --insecure-registry cas0:5000 diff --git a/scripts/swap_dockerd_nuvo.sh b/scripts/swap_dockerd_nuvo.sh deleted file mode 100755 index 7661be8..0000000 --- a/scripts/swap_dockerd_nuvo.sh +++ /dev/null @@ -1,2 +0,0 @@ -sudo service docker stop -sudo dockerd --insecure-registry nuvo0:5000 diff --git a/src/run_scripts/newstartup/fixcamip.sh b/src/run_scripts/newstartup/fixcamip.sh deleted file mode 100755 index 8e28300..0000000 --- a/src/run_scripts/newstartup/fixcamip.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -export COMPOSE_IGNORE_ORPHANS=True - - -KAM_REPO_DIR=$(~/.config/kamera/repo_dir.bash) -cd ${KAM_REPO_DIR} -# get configQuery -source ${KAM_REPO_DIR}/src/cfg/cfg-aliases.sh - -set -a # automatically export all variables - -. ${KAM_REPO_DIR}/.env - -# infer position from the config based on acting hostname (defaults to actual hostname) -NODE_HOSTNAME=${NODE_HOSTNAME:-$(hostname)} -CAM_FOV=$(cq ".hosts.${NODE_HOSTNAME}.fov") -export NODE_HOSTNAME -export CAM_FOV - -docker compose -f compose/debug.yml run --rm dbg_cam /entry/make_cameras_ip_static.sh - -set +a - - diff --git a/src/run_scripts/newstartup/kamera_halt.sh b/src/run_scripts/newstartup/kamera_halt.sh deleted file mode 100755 index 6c375b6..0000000 --- a/src/run_scripts/newstartup/kamera_halt.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env bash - -## Like kamera_run, but opposite -export COMPOSE_IGNORE_ORPHANS=True # make compose quieter -KAM_REPO_DIR=$(/home/user/.config/kamera/repo_dir.bash) -echo $KAM_REPO_DIR -SYSTEM_NAME=$(cat /home/user/kw/SYSTEM_NAME) -source "${KAM_REPO_DIR}/tmux/${SYSTEM_NAME}/env.sh" - - -errcho() { - (>&2 echo -e "\e[31m$1\e[0m") -} - -blueprintf() { - (printf "\e[34m$@\e[0m") -} - -if [[ -z "$@" ]] ; then - ARGS=(stop) -else - ARGS=("$@") - -fi - -MODE="" -for arg in "${ARGS[@]}" ; do - blueprintf "arg: ${arg}\n" - if [[ "${arg}" == "-d" || "${arg}" == "--detach" ]] ; then DETACH="-d" ; fi - if [[ "${arg}" == "--remove-orphans" ]] ; then REM_ORPH="--remove-orphans" ; fi - if [[ "${arg}" == "up" ]] ; then errcho "Do not use this script to start"; exit 1; fi - if [[ "${arg}" == "kill" ]] ; then MODE=kill ; fi - if [[ "${arg}" == "restart" ]] ; then MODE=restart ; fi - if [[ "${arg}" == "stop" ]] ; then MODE=stop ; fi - if [[ "${arg}" == "down" ]] ; then MODE=down ; fi - if [[ "${arg}" == "rm" ]] ; then MODE=rm ; fi -done - -if [[ -z "${MODE}" ]]; then - errcho "Missing compose mode (up/down etc)" - exit 1 -fi - -## === === === === === === Env setup === === === === === === === -blueprintf "Configuring main KAMERA entrypoint." -if [[ -z "${KAM_REPO_DIR}" ]]; then - echo "ERROR: Could not resolve KAM_REPO_DIR. Check ~/.config/kamera" - exit 1 -fi -blueprintf "." - -MASTER_HOST=$(cq '.master_host') -## === === === === === === End Env setup === === === === === === - - -OPTIONS=(${VERBOSE}) - -blueprintf "done\nBringing down gui..." -docker compose -f "${KAM_REPO_DIR}/compose/gui.yml" "${ARGS[@]}" & -STAT_GUI=$! - -blueprintf "done\nGui down. Killing pods...\n" -# Bring up all pod systems -# Query list of hosts as line delim array -declare -A PIDS -for host in $(cq '.arch.hosts | keys | join("\n" )') ; do - if [[ $(cq ".arch.hosts[\"${host}\"].enabled") == 'true' ]]; then - python3 ${KAM_REPO_DIR}/scripts/system.py $host ${ARGS[@]} pod & - PIDS["${host}_pod"]=$! - python3 ${KAM_REPO_DIR}/scripts/system.py $host ${ARGS[@]} detector & - PIDS["${host}_det"]=$! - fi -done -blueprintf "done\nBringing down central..." -python3 ${KAM_REPO_DIR}/scripts/system.py $MASTER_HOST ${ARGS[@]} central & -PIDS["${host}_cen"]=$! -python3 ${KAM_REPO_DIR}/scripts/system.py $MASTER_HOST ${ARGS[@]} monitor & -PIDS["${host}_mon"]=$! -wait $STAT_GUI -# wait for all pids -for pid in ${PIDS[*]}; do - wait $pid -done - -blueprintf "done\nBringing down master..." -python3 ${KAM_REPO_DIR}/scripts/system.py $MASTER_HOST ${ARGS[@]} master -blueprintf "done. ROS should be down\n" - -blueprintf "Dismounting drives..." -# todo: dismounts -blueprintf "done\n " -docker ps diff --git a/src/run_scripts/newstartup/kamera_run.sh b/src/run_scripts/newstartup/kamera_run.sh deleted file mode 100755 index 8dea066..0000000 --- a/src/run_scripts/newstartup/kamera_run.sh +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env bash - -## This script provides turnkey operation to spin up the whole system -export COMPOSE_IGNORE_ORPHANS=True # make compose quieter -KAM_REPO_DIR=$(/home/user/.config/kamera/repo_dir.bash) -echo $KAM_REPO_DIR -SYSTEM_NAME=$(cat /home/user/kw/SYSTEM_NAME) -source "${KAM_REPO_DIR}/tmux/${SYSTEM_NAME}/env.sh" - -errcho() { - (>&2 echo -e "\e[31m$1\e[0m") -} - -blueprintf() { - (printf "\e[34m$@\e[0m") -} - -if [[ -z "$@" ]] ; then - ARGS=(start) -else - ARGS=("$@") - -fi - -MODE="" -for arg in "${ARGS[@]}" ; do - blueprintf "arg: ${arg}\n" - if [[ "${arg}" == "-d" || "${arg}" == "--detach" ]] ; then DETACH="-d" ; fi - if [[ "${arg}" == "--remove-orphans" ]] ; then REM_ORPH="--remove-orphans" ; fi - if [[ "${arg}" == "up" ]] ; then MODE=up ; fi - if [[ "${arg}" == "start" ]] ; then MODE=up ; fi - if [[ "${arg}" == "kill" ]] ; then MODE=kill ; fi - if [[ "${arg}" == "restart" ]] ; then MODE=restart ; fi - if [[ "${arg}" == "stop" ]] ; then MODE=stop ; fi - if [[ "${arg}" == "down" ]] ; then errcho "Do not use this script to 'down'"; exit 1 ; fi - if [[ "${arg}" == "rm" ]] ; then MODE=rm ; fi -done - -if [[ -z "${MODE}" ]]; then - errcho "Missing compose mode (up/down etc)" - exit 1 -fi - -## === === === === === === Env setup === === === === === === === -blueprintf "Configuring main KAMERA entrypoint." -# Add detector ENV variables to Redis -source ${KAM_REPO_DIR}/src/cfg/set_detector_read_state.sh -blueprintf "." - -MASTER_HOST=$(cq '.master_host') - -for VNAME in MASTER_HOST KAM_REPO_DIR -do - if [[ -z "${!VNAME}" || "${!VNAME}" == 'null' ]]; then - printf " Unable to determine $VNAME: Check user-config\n" - exit 1 - fi -done - -## === === === === === === End Env setup === === === === === === - -## === === === === === Handle drive mounts === === === === === -echo "Waiting for master host to come online. Hit ctrl-c or window X to cancel" -i=1 -SP="/-\|" -until ping -c1 -W1 ${MASTER_HOST} &>/dev/null; do - printf "\b${SP:i++%${#SP}:1}" -done - -SKIP_PING=true -for host in $(cq '.arch.hosts | keys | join("\n" )') ; do - hostip=$(dig +short $host) - if [[ $? != 0 ]]; then - errcho "FATAL: Cannot resolve IP for necassary host ${host}" - fi - - _CLIENTS=$(redis-cli -h $REDIS_HOST client list | grep $hostip) - if [[ $? != 0 ]]; then - SKIP_PING= - fi -done - -if [[ -n ${SKIP_PING} ]]; then - echo "all clients located, yay!" -else - for host in $(cq '.arch.hosts | keys | join("\n" )') ; do - echo "Waiting on ping $host." - if [[ $(cq ".arch.hosts[\"${host}\"].enabled") == 'true' ]]; then - until ping -c1 -W1 ${host} &>/dev/null; do - printf "\b${SP:i++%${#SP}:1}" - done - else - echo "${host} disabled." - fi - done -fi - -supervisorctl restart mount_nas -ls /mnt/flight_data/.flight_data_mounted -NAS_CODE=$? -if ! [[ $NAS_CODE == 0 ]]; then - echo "Failed to connect to NAS! Troubleshoot!" - sleep 5 -# exit -else - echo "NAS mounted!" -fi -declare -A PIDS -for host in $(cq '.arch.hosts | keys | join("\n" )') ; do - if [[ $(cq ".arch.hosts[\"${host}\"].enabled") == 'true' ]]; then - python3 ${KAM_REPO_DIR}/scripts/system.py $host restart nas & - PIDS[${host}]=$! - else - echo "${host} disabled." - - fi -done - -for pid in ${PIDS[*]}; do - wait $pid -done - - -# Bring up master and core nodes -MASTER_HOST=$(cq '.master_host') -blueprintf "done\nBringing up master $MASTER_HOST..." -python3 ${KAM_REPO_DIR}/scripts/system.py $MASTER_HOST "${ARGS[@]}" master - -# check that master is in fact up -FAIL_COUNT=0 -cd $KAM_REPO_DIR -until docker compose -f ${KAM_REPO_DIR}/compose/nodelist.yml run --rm nodelist; do - echo "Attempt $((++FAIL_COUNT))"; - if [[ $FAIL_COUNT -gt 3 ]]; then - errcho "Unable to contact ros master. Running WTF and aborting startup" - docker compose -f ${KAM_REPO_DIR}/compose/nodelist.yml run --rm nodelist /entry/wat.sh - exit 1 - fi -done - -# === === === === Checks have passed === === === === -blueprintf "done. Init checks are good! \nBringing up central..." -python3 ${KAM_REPO_DIR}/scripts/system.py $MASTER_HOST "${ARGS[@]}" central & -STAT_CENTRAL=$! - - -blueprintf "done\nLaunching pod nodes...\n" - -# Bring up all pod systems -# Query list of hosts as line delim array -declare -A PIDS -# sort, so hosts are started idempotently -hosts=$(cq '.arch.hosts | keys | join("\n" )') -IFS=$'\n' sorted_hosts=($(sort <<<"${hosts[*]}")) -unset IFS -for host in "${sorted_hosts[@]}"; do - if [[ $(cq ".arch.hosts[\"${host}\"].enabled") == 'true' ]]; then - python3 ${KAM_REPO_DIR}/scripts/system.py $host "${ARGS[@]}" pod & - PIDS[${host}]=$! - else - echo "${host} disabled." - - fi -done -echo " PIDS : ${PIDS[@]}" - -# === === === === Checks have passed === === === === -blueprintf "Bringing up monitor..." -python3 ${KAM_REPO_DIR}/scripts/system.py $MASTER_HOST "${ARGS[@]}" monitor & -STAT_MONITOR=$! - -blueprintf "done. \nPods launched. Starting GUI..." - -cd ${KAM_REPO_DIR} -set -a # automatically export all variables -xhost +local:root -docker compose -f "${KAM_REPO_DIR}/compose/gui.yml" "${ARGS[@]}" & -STAT_GUI=$! -blueprintf "done\n === Starting System Control Panel :D === " -set +a - -gui_splash() { - notify-send -t 5000 -i ~/kw/kamera/src/cfg/seal-icon.png \ - "KAMERA" "Starting KAMERA Control Panel, please wait" || true -} -gui_splash - -wait $STAT_CENTRAL -wait $STAT_MONITOR -# wait for all pids -for pid in ${PIDS[*]}; do - echo "waiting on: $pid" - wait $pid -done -wait $STAT_GUI - diff --git a/src/run_scripts/newstartup/launchcams.sh b/src/run_scripts/newstartup/launchcams.sh deleted file mode 100755 index cea7c3e..0000000 --- a/src/run_scripts/newstartup/launchcams.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash - -# Launch all pod nodes (replicated across all systems) -export COMPOSE_IGNORE_ORPHANS=True - -if [[ -z "$@" ]] ; then - ARGS=(up -d) -else - ARGS=("$@") -fi - - -#for value in "${ARGS[@]}" ; do #print the new array -#echo "$value" -#done - -KAM_REPO_DIR=$(~/.config/kamera/repo_dir.bash) -cd ${KAM_REPO_DIR} -set -a # automatically export all variables -. ${KAM_REPO_DIR}/.env - -# get configQuery -source ${KAM_REPO_DIR}/src/cfg/cfg-aliases.sh - -# infer position from the config based on acting hostname (defaults to actual hostname) -NODE_HOSTNAME=${NODE_HOSTNAME:-$(hostname)} -CAM_FOV=$(cq ".hosts.${NODE_HOSTNAME}.fov") -export NODE_HOSTNAME -export CAM_FOV - -for VNAME in CFG_ALIAS_SET NODE_HOSTNAME CAM_FOV -do - if [[ -z "${!VNAME}" || "${!VNAME}" == 'null' ]]; then - printf " Unable to determine $VNAME: ${CAM_FOV}. Check user-config\n" - exit 1 - fi -done - -# crazy script to ensure that ethernet speed is max -# ONLY RUN ONCE AT STARTUP -# set_eth_speed_max.sh - - -docker compose -f ${KAM_REPO_DIR}/compose/cam.yml "${ARGS[@]}" & -CAM_STAT=$! -set +a - -wait $CAM_STAT -docker ps diff --git a/src/run_scripts/newstartup/launchcentral.sh b/src/run_scripts/newstartup/launchcentral.sh deleted file mode 100755 index 90b99ee..0000000 --- a/src/run_scripts/newstartup/launchcentral.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -# Bring up central nodes - e.g. INS and DAQ -export COMPOSE_IGNORE_ORPHANS=True - -if [[ -z "$@" ]] ; then - ARGS=(up -d) -else - ARGS=("$@") -fi - -KAM_REPO_DIR=$(~/.config/kamera/repo_dir.bash) -cd ${KAM_REPO_DIR} -set -a # automatically export all variables -. ${KAM_REPO_DIR}/.env - -source ${KAM_REPO_DIR}/src/run_scripts/inpath/locate_daq - -docker compose -f "${KAM_REPO_DIR}/compose/central.yml" "${ARGS[@]}" & -STAT_CENTRAL=$! -set +a - -wait $STAT_CENTRAL diff --git a/src/run_scripts/newstartup/launchdetector.sh b/src/run_scripts/newstartup/launchdetector.sh deleted file mode 100755 index b92ed3b..0000000 --- a/src/run_scripts/newstartup/launchdetector.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash - -export COMPOSE_IGNORE_ORPHANS=True - -if [[ -z "$@" ]] ; then - ARGS=(up -d) -else - ARGS=("$@") -fi - -gui_splash() { - MSG_STRING="${1}ing KAMERA Detector, please wait" - notify-send -t 5000 -i ~/kw/kamera/src/cfg/seal-icon.png \ - "KAMERA" "${MSG_STRING}" 2>/dev/null || echo "${MSG_STRING}"; -} - -for arg in "${ARGS[@]}" ; do - if [[ "${arg}" == "up" ]] ; then gui_splash 'start' ; fi - if [[ "${arg}" == "restart" ]] ; then gui_splash 'restart' ; fi -done - -KAM_REPO_DIR=$(~/.config/kamera/repo_dir.bash) -cd ${KAM_REPO_DIR} -# get configQuery -source ${KAM_REPO_DIR}/src/cfg/cfg-aliases.sh - -set -a # automatically export all variables - -. ${KAM_REPO_DIR}/.env - - - -# infer position from the config based on acting hostname (defaults to actual hostname) -NODE_HOSTNAME=${NODE_HOSTNAME:-$(hostname)} -CAM_FOV=$(cq ".hosts.${NODE_HOSTNAME}.fov") -export NODE_HOSTNAME -export CAM_FOV - -docker compose -f "${KAM_REPO_DIR}/compose/detector.yml" "${ARGS[@]}" -STAT_DETECTOR=$! - -set +a - -wait $STAT_GUI -sleep 1 - diff --git a/src/run_scripts/newstartup/launchgui.sh b/src/run_scripts/newstartup/launchgui.sh deleted file mode 100755 index 93c6014..0000000 --- a/src/run_scripts/newstartup/launchgui.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash - -export COMPOSE_IGNORE_ORPHANS=True - -if [[ -z "$@" ]] ; then - ARGS=(up -d) -else - ARGS=("$@") -fi - -gui_splash() { - notify-send -t 5000 -i ~/kw/kamera/src/cfg/seal-icon.png \ - "KAMERA" "Starting KAMERA Control Panel, please wait" || true -} - -for arg in "${ARGS[@]}" ; do - if [[ "${arg}" == "up" ]] ; then xhost +local:root; gui_splash ; fi -done - -KAM_REPO_DIR=$(~/.config/kamera/repo_dir.bash) -cd ${KAM_REPO_DIR} -set -a # automatically export all variables -source ${KAM_REPO_DIR}/tmux/mas/env.sh -xhost +local:root -docker-compose -f "${KAM_REPO_DIR}/compose/gui.yml" "${ARGS[@]}" -STAT_GUI=$! - -set +a - -wait $STAT_GUI - -for arg in "${ARGS[@]}" ; do - if [[ "${arg}" == "kill" ]] ; then xhost_disable ; fi - if [[ "${arg}" == "stop" ]] ; then xhost_disable ; fi - if [[ "${arg}" == "down" ]] ; then xhost_disable ; fi - if [[ "${arg}" == "rm" ]] ; then xhost_disable ; fi -done diff --git a/src/run_scripts/newstartup/launchmaster.sh b/src/run_scripts/newstartup/launchmaster.sh deleted file mode 100755 index 11c55a9..0000000 --- a/src/run_scripts/newstartup/launchmaster.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -export COMPOSE_IGNORE_ORPHANS=True - -if [[ -z "$@" ]] ; then - ARGS=(up -d) -else - ARGS=("$@") -fi - -KAM_REPO_DIR=$(~/.config/kamera/repo_dir.bash) -cd ${KAM_REPO_DIR} -set -a # automatically export all variables -. ${KAM_REPO_DIR}/.env - -docker compose -f ${KAM_REPO_DIR}/compose/master.yml "${ARGS[@]}" -set +a \ No newline at end of file diff --git a/src/run_scripts/newstartup/launchnexus.sh b/src/run_scripts/newstartup/launchnexus.sh deleted file mode 100755 index aa17e81..0000000 --- a/src/run_scripts/newstartup/launchnexus.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -# Launch all pod nodes (replicated across all systems) -export COMPOSE_IGNORE_ORPHANS=True - -if [[ -z "$@" ]] ; then - ARGS=(up -d) -else - ARGS=("$@") -fi - - -#for value in "${ARGS[@]}" ; do #print the new array -#echo "$value" -#done - -KAM_REPO_DIR=$(~/.config/kamera/repo_dir.bash) -cd ${KAM_REPO_DIR} -set -a # automatically export all variables -. ${KAM_REPO_DIR}/.env - -# get configQuery -source ${KAM_REPO_DIR}/src/cfg/cfg-aliases.sh - -# infer position from the config based on acting hostname (defaults to actual hostname) -NODE_HOSTNAME=${NODE_HOSTNAME:-$(hostname)} -CAM_FOV=$(cq ".hosts.${NODE_HOSTNAME}.fov") -export NODE_HOSTNAME -export CAM_FOV - -for VNAME in CFG_ALIAS_SET NODE_HOSTNAME CAM_FOV -do - if [[ -z "${!VNAME}" || "${!VNAME}" == 'null' ]]; then - printf " Unable to determine $VNAME: ${CAM_FOV}. Check user-config\n" - exit 1 - fi -done - -docker compose -f ${KAM_REPO_DIR}/compose/process.yml "${ARGS[@]}" & -PROC_STAT=$! -set +a - -wait $PROC_STAT -docker ps diff --git a/src/run_scripts/newstartup/launchpod.sh b/src/run_scripts/newstartup/launchpod.sh deleted file mode 100755 index acf0ae0..0000000 --- a/src/run_scripts/newstartup/launchpod.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash - -# Launch all pod nodes (replicated across all systems) -export COMPOSE_IGNORE_ORPHANS=True - -if [[ -z "$@" ]] ; then - ARGS=(up -d) -else - ARGS=("$@") -fi - - -#for value in "${ARGS[@]}" ; do #print the new array -#echo "$value" -#done - -KAM_REPO_DIR=$(~/.config/kamera/repo_dir.bash) -cd ${KAM_REPO_DIR} -set -a # automatically export all variables -. ${KAM_REPO_DIR}/.env - -# get configQuery -source ${KAM_REPO_DIR}/src/cfg/cfg-aliases.sh - -# infer position from the config based on acting hostname (defaults to actual hostname) -NODE_HOSTNAME=${NODE_HOSTNAME:-$(hostname)} -CAM_FOV=$(cq ".hosts.${NODE_HOSTNAME}.fov") -export NODE_HOSTNAME -export CAM_FOV - -for VNAME in CFG_ALIAS_SET NODE_HOSTNAME CAM_FOV -do - if [[ -z "${!VNAME}" || "${!VNAME}" == 'null' ]]; then - printf " Unable to determine $VNAME: ${CAM_FOV}. Check user-config\n" - exit 1 - fi -done - -# crazy script to ensure that ethernet speed is max -set_eth_speed_max.sh - - - -docker compose -f ${KAM_REPO_DIR}/compose/process.yml -f ${KAM_REPO_DIR}/compose/cam.yml "${ARGS[@]}" & -PROC_STAT=$! -set +a - -wait $SYSN_STAT -wait $PROC_STAT -docker ps diff --git a/src/run_scripts/newstartup/launchpostproc.sh b/src/run_scripts/newstartup/launchpostproc.sh deleted file mode 100755 index 66a9320..0000000 --- a/src/run_scripts/newstartup/launchpostproc.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -export COMPOSE_IGNORE_ORPHANS=True - -KAM_REPO_DIR=$(~/.config/kamera/repo_dir.bash) -cd ${KAM_REPO_DIR} - -set -a # automatically export all variables - -. ${KAM_REPO_DIR}/.env - -RUNSCRIPT=$1 -export KAM_FLIGHT_DIR="$2" -echo docker compose -f "${KAM_REPO_DIR}/compose/postproc.yml" run --rm postproc $RUNSCRIPT -docker compose -f "${KAM_REPO_DIR}/compose/postproc.yml" run --rm postproc $RUNSCRIPT - -set +a - -sleep 1 - diff --git a/src/run_scripts/newstartup/launchsyncpub.sh b/src/run_scripts/newstartup/launchsyncpub.sh deleted file mode 100755 index cf71bc2..0000000 --- a/src/run_scripts/newstartup/launchsyncpub.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bash - -export COMPOSE_IGNORE_ORPHANS=True - -if [[ -z "$@" ]] ; then - ARGS=(up -d) -else - ARGS=("$@") -fi - -gui_splash() { - MSG_STRING="${1}ing KAMERA Sync Msg Publisher, please wait" - notify-send -t 5000 -i ~/kw/kamera/src/cfg/seal-icon.png \ - "KAMERA" "${MSG_STRING}" 2>/dev/null || echo "${MSG_STRING}"; -} - -for arg in "${ARGS[@]}" ; do - if [[ "${arg}" == "up" ]] ; then gui_splash 'start' ; fi - if [[ "${arg}" == "restart" ]] ; then gui_splash 'restart' ; fi -done - -KAM_REPO_DIR=$(~/.config/kamera/repo_dir.bash) -cd ${KAM_REPO_DIR} -# get configQuery -source ${KAM_REPO_DIR}/src/cfg/cfg-aliases.sh - -set -a # automatically export all variables - -. ${KAM_REPO_DIR}/.env - - - -# infer position from the config based on acting hostname (defaults to actual hostname) -NODE_HOSTNAME=${NODE_HOSTNAME:-$(hostname)} -CAM_FOV=$(cq ".hosts.${NODE_HOSTNAME}.fov") -export NODE_HOSTNAME -export CAM_FOV -echo "PIPEFILE to use: ${PIPEFILE}" - -docker compose -f "${KAM_REPO_DIR}/compose/sync_msg_publisher.yml" "${ARGS[@]}" -STAT_SYNCPUB=$! - -set +a - -wait $STAT_SYNCPUB -sleep 1 - diff --git a/src/run_scripts/newstartup/start_central.sh b/src/run_scripts/newstartup/start_central.sh deleted file mode 100755 index aed2db4..0000000 --- a/src/run_scripts/newstartup/start_central.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -# Start the master and center -KAM_REPO_DIR=$(~/.config/kamera/repo_dir.bash) -if [[ -z "${KAM_REPO_DIR}" ]]; then - echo "ERROR: Could not resolve KAM_REPO_DIR. Check ~/.config/kamera" - exit 1 -fi - -MCC_DAQ=`readlink -f /dev/mcc_daq` -export MCC_DAQ -printf "MCC_DAQ.........: ${MCC_DAQ} -" -docker compose -f "${KAM_REPO_DIR}/compose/central.yml" up -d From 0cc76f32f3db213e52505252023c217bb77caf90 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Tue, 16 Jun 2026 08:02:12 -0400 Subject: [PATCH 087/139] Add local push/pull docker config, automatically start registry container on leader machines --- provision/ansible/playbooks/cas/configure.yml | 9 +++++++++ scripts/swap_dockerd.sh | 11 ----------- src/cfg/nayak/docker-daemon.json | 9 +++++++++ src/cfg/taiga/docker-daemon.json | 9 +++++++++ tmux/nayak/leader/supervisor.conf | 5 +++++ tmux/taiga/leader/supervisor.conf | 5 +++++ 6 files changed, 37 insertions(+), 11 deletions(-) delete mode 100755 scripts/swap_dockerd.sh create mode 100644 src/cfg/nayak/docker-daemon.json create mode 100644 src/cfg/taiga/docker-daemon.json diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index 1f987fc..681903f 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -164,6 +164,15 @@ dest: /etc/chrony/chrony.conf owner: root + - name: Place docker daemon config. + become: True + when: leader or follower or gui + copy: + src: "{{ kamera_dir }}/src/cfg/{{ config_dir }}/docker-daemon.json" + remote_src: true + dest: /etc/docker/daemon.json + owner: root + - name: Place tmux config. become: True when: leader or follower or gui diff --git a/scripts/swap_dockerd.sh b/scripts/swap_dockerd.sh deleted file mode 100755 index 2ef5aa0..0000000 --- a/scripts/swap_dockerd.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/bash - -KAM_REPO_DIR=$(/home/user/.config/kamera/repo_dir.bash) -echo $KAM_REPO_DIR -SYSTEM_NAME=$(cat /home/user/kw/SYSTEM_NAME) -source "${KAM_REPO_DIR}/tmux/${SYSTEM_NAME}/env.sh" - -MASTER_HOST=$(cq '.master_host') - -sudo service docker stop -sudo dockerd --insecure-registry ${MASTER_HOST}:5000 diff --git a/src/cfg/nayak/docker-daemon.json b/src/cfg/nayak/docker-daemon.json new file mode 100644 index 0000000..2ee8d9a --- /dev/null +++ b/src/cfg/nayak/docker-daemon.json @@ -0,0 +1,9 @@ +{ + "insecure-registries": ["center0nayak:5000"], + "runtimes": { + "nvidia": { + "args": [], + "path": "nvidia-container-runtime" + } + } +} diff --git a/src/cfg/taiga/docker-daemon.json b/src/cfg/taiga/docker-daemon.json new file mode 100644 index 0000000..25d21c8 --- /dev/null +++ b/src/cfg/taiga/docker-daemon.json @@ -0,0 +1,9 @@ +{ + "insecure-registries": ["center0taiga:5000"], + "runtimes": { + "nvidia": { + "args": [], + "path": "nvidia-container-runtime" + } + } +} diff --git a/tmux/nayak/leader/supervisor.conf b/tmux/nayak/leader/supervisor.conf index 4677dae..17257bb 100644 --- a/tmux/nayak/leader/supervisor.conf +++ b/tmux/nayak/leader/supervisor.conf @@ -26,6 +26,11 @@ startsecs=0 user=root autostart=true +[program:docker_registry] +command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh registry +user=user +autostart=true + [program:roscore] command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh roscore user=user diff --git a/tmux/taiga/leader/supervisor.conf b/tmux/taiga/leader/supervisor.conf index 3c14366..01437eb 100644 --- a/tmux/taiga/leader/supervisor.conf +++ b/tmux/taiga/leader/supervisor.conf @@ -26,6 +26,11 @@ startsecs=0 user=root autostart=true +[program:docker_registry] +command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh registry +user=user +autostart=true + [program:roscore] command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh roscore user=user From 5b82c08d8b222d6c983e6a743028de59b982d4b5 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Tue, 16 Jun 2026 08:17:11 -0400 Subject: [PATCH 088/139] Add kamerad to leader --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 8d0dd82..b0424b2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,6 +28,7 @@ services: profiles: - core - follower + - leader - all # CUDA + ROS Noetic base with utility packages. No KAMERA source. From c7b848fa014b04fde1ce6638168f9f7a333e8493 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 08:17:50 -0400 Subject: [PATCH 089/139] Add a docker restart to ansible --- provision/ansible/playbooks/cas/configure.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index 681903f..fa037f5 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -173,6 +173,10 @@ dest: /etc/docker/daemon.json owner: root + - name: Docker restart + become: true + service: name=docker state=restarted enabled=yes + - name: Place tmux config. become: True when: leader or follower or gui From 0b31734551e0b4b2284eaad7c7186ca8ee73f80a Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 08:53:49 -0400 Subject: [PATCH 090/139] Leave docker configuration for configure step --- provision/ansible/playbooks/cas/provision.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/provision/ansible/playbooks/cas/provision.yml b/provision/ansible/playbooks/cas/provision.yml index 2ff3546..95af7ad 100644 --- a/provision/ansible/playbooks/cas/provision.yml +++ b/provision/ansible/playbooks/cas/provision.yml @@ -126,17 +126,6 @@ name: nvidia-container-toolkit state: present - - name: Configure Docker runtime - become: True - command: - cmd: nvidia-ctk runtime configure --runtime=docker - - - name: Restart Docker Service - become: True - service: - name: docker - state: restarted - - name: Ensure group "docker" exists become: True group: From d14b306baf97e550caee5d1c6c9c0ca3559a8e00 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 09:41:54 -0400 Subject: [PATCH 091/139] Rollback to per-machine netplans, the specificity is needed --- provision/ansible/playbooks/cas/configure.yml | 2 +- src/cfg/taiga/center0taiga/custom-netplan.yaml | 1 + src/cfg/taiga/custom-netplan.yaml | 1 - src/cfg/taiga/left1taiga/custom-netplan.yaml | 1 + 4 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 src/cfg/taiga/center0taiga/custom-netplan.yaml delete mode 100644 src/cfg/taiga/custom-netplan.yaml create mode 100644 src/cfg/taiga/left1taiga/custom-netplan.yaml diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index fa037f5..413829e 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -103,7 +103,7 @@ - name: Setup netplan configuration. become: True copy: - src: "{{ kamera_dir }}/src/cfg/{{ config_dir }}/custom-netplan.yaml" + src: "{{ kamera_dir }}/src/cfg/{{ config_dir }}/{{ inventory_hostname }}/custom-netplan.yaml" remote_src: true dest: /etc/netplan/{{ inventory_hostname }}-netplan.yaml owner: root diff --git a/src/cfg/taiga/center0taiga/custom-netplan.yaml b/src/cfg/taiga/center0taiga/custom-netplan.yaml new file mode 100644 index 0000000..941e6fb --- /dev/null +++ b/src/cfg/taiga/center0taiga/custom-netplan.yaml @@ -0,0 +1 @@ +network: version: 2 ethernets: # IR Camera - outer mobo (onboard, 1G, e1000e) ir_cam: match: macaddress: 78:d0:04:39:f9:69 set-name: ir_cam dhcp4: false dhcp6: false addresses: [192.168.1.10/24] optional: true # LAN - inner mobo (2.5G, igc) lan: match: macaddress: 78:d0:04:39:f9:6a set-name: lan dhcp4: false dhcp6: false addresses: - 192.168.88.10/24 routes: - to: default via: 192.168.88.1 nameservers: addresses: [8.8.8.8, 192.168.88.10] optional: true # P1 Camera - PCIe f0 (10G, i40e) p1_cam: match: macaddress: f0:b2:b9:3f:68:a4 set-name: p1_cam mtu: 9000 dhcp4: false dhcp6: false addresses: [192.168.4.10/24] optional: true # UV Camera - PCIe f1 (i40e, 1G link but on 10G) uv_cam: match: macaddress: f0:b2:b9:3f:68:a5 set-name: uv_cam dhcp4: false dhcp6: false addresses: [192.168.2.10/24] optional: true # NAS - PCIe f3 (10G, i40e) nas: match: macaddress: f0:b2:b9:3f:68:a7 set-name: nas mtu: 9000 dhcp4: false dhcp6: false addresses: [192.168.198.100/24] optional: true # PCIe f2 (f0:b2:b9:3f:68:a6) unused - no connection \ No newline at end of file diff --git a/src/cfg/taiga/custom-netplan.yaml b/src/cfg/taiga/custom-netplan.yaml deleted file mode 100644 index edc4cc1..0000000 --- a/src/cfg/taiga/custom-netplan.yaml +++ /dev/null @@ -1 +0,0 @@ ---- network: version: 2 ethernets: # IR Camera - outer mobo enp0s31f6: addresses: [192.168.1.10/24] optional: true # LAN - inner MOBO enp2s0: addresses: - 192.168.88.10/24 routes: - to: default via: 192.168.88.1 nameservers: addresses: [8.8.8.8, 192.168.88.10] optional: true # P1 Camera - PCIE 0 enp3s0f0np0: mtu: 9000 addresses: [192.168.4.10/24] optional: true # UV Camera - PCIE 1 enp3s0f1np1: addresses: [192.168.2.10/24] optional: true # NAS - PCIE 3 enp3s0f3np3: mtu: 9000 addresses: [192.168.198.100/24] optional: true ... \ No newline at end of file diff --git a/src/cfg/taiga/left1taiga/custom-netplan.yaml b/src/cfg/taiga/left1taiga/custom-netplan.yaml new file mode 100644 index 0000000..c725379 --- /dev/null +++ b/src/cfg/taiga/left1taiga/custom-netplan.yaml @@ -0,0 +1 @@ +network: version: 2 ethernets: # IR Camera - outer mobo (onboard, 1G, e1000e) ir_cam: match: macaddress: 78:d0:04:39:cf:95 set-name: ir_cam dhcp4: false dhcp6: false addresses: [192.168.1.11/24] optional: true # LAN - inner mobo (2.5G, igc) lan: match: macaddress: 78:d0:04:39:cf:96 set-name: lan dhcp4: false dhcp6: false addresses: - 192.168.88.11/24 routes: - to: default via: 192.168.88.1 nameservers: addresses: [8.8.8.8, 192.168.88.10] optional: true # P1 Camera - PCIe f0 (10G, i40e) p1_cam: match: macaddress: f0:b2:b9:3f:68:54 set-name: p1_cam mtu: 9000 dhcp4: false dhcp6: false addresses: [192.168.4.11/24] optional: true # UV Camera - PCIe f1 (i40e, currently 1G link) uv_cam: match: macaddress: f0:b2:b9:3f:68:55 set-name: uv_cam dhcp4: false dhcp6: false addresses: [192.168.2.11/24] optional: true # NAS - PCIe f3 (10G, i40e) nas: match: macaddress: f0:b2:b9:3f:68:57 set-name: nas mtu: 9000 dhcp4: false dhcp6: false addresses: [192.168.198.101/24] optional: true # PCIe f2 (f0:b2:b9:3f:68:56) unused - no carrier. Add a stanza here if needed. \ No newline at end of file From bb0bf1a73b07a08b7b7c6c23a41a0a10f3bc0313 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 09:50:34 -0400 Subject: [PATCH 092/139] Add sys2 netplan --- src/cfg/taiga/right2taiga/custom-netplan.yaml | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/cfg/taiga/right2taiga/custom-netplan.yaml diff --git a/src/cfg/taiga/right2taiga/custom-netplan.yaml b/src/cfg/taiga/right2taiga/custom-netplan.yaml new file mode 100644 index 0000000..5a43ff0 --- /dev/null +++ b/src/cfg/taiga/right2taiga/custom-netplan.yaml @@ -0,0 +1 @@ +network: version: 2 ethernets: # IR Camera - outer mobo (onboard, 1G, e1000e) ir_cam: match: macaddress: 78:d0:04:39:f9:6d set-name: ir_cam dhcp4: false dhcp6: false addresses: [192.168.1.12/24] optional: true # LAN - inner mobo (2.5G, igc) lan: match: macaddress: 78:d0:04:39:f9:6e set-name: lan dhcp4: false dhcp6: false addresses: - 192.168.88.12/24 routes: - to: default via: 192.168.88.1 nameservers: addresses: [8.8.8.8, 192.168.88.10] optional: true # P1 Camera - PCIe f0 (10G, i40e) p1_cam: match: macaddress: f0:b2:b9:3f:68:34 set-name: p1_cam mtu: 9000 dhcp4: false dhcp6: false addresses: [192.168.4.12/24] optional: true # UV Camera - PCIe f1 (i40e, no carrier at last check) uv_cam: match: macaddress: f0:b2:b9:3f:68:35 set-name: uv_cam dhcp4: false dhcp6: false addresses: [192.168.2.12/24] optional: true # NAS - PCIe f3 (10G, i40e) nas: match: macaddress: f0:b2:b9:3f:68:37 set-name: nas mtu: 9000 dhcp4: false dhcp6: false addresses: [192.168.198.102/24] optional: true # PCIe f2 (f0:b2:b9:3f:68:36) unused - no carrier. Add a stanza here if needed. \ No newline at end of file From 1f3d0e1aa25e7124abdb0bc36db1308eee526c59 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 09:55:37 -0400 Subject: [PATCH 093/139] Remove eth speed max scripts - obe --- tmux/nayak/ethtoolp.py | 190 ---------------------------- tmux/nayak/follower/supervisor.conf | 6 - tmux/nayak/leader/supervisor.conf | 6 - tmux/nayak/set_eth_speed_max.sh | 11 -- tmux/taiga/ethtoolp.py | 190 ---------------------------- tmux/taiga/follower/supervisor.conf | 6 - tmux/taiga/leader/supervisor.conf | 6 - tmux/taiga/set_eth_speed_max.sh | 11 -- 8 files changed, 426 deletions(-) delete mode 100755 tmux/nayak/ethtoolp.py delete mode 100755 tmux/nayak/set_eth_speed_max.sh delete mode 100755 tmux/taiga/ethtoolp.py delete mode 100755 tmux/taiga/set_eth_speed_max.sh diff --git a/tmux/nayak/ethtoolp.py b/tmux/nayak/ethtoolp.py deleted file mode 100755 index cb0fcb3..0000000 --- a/tmux/nayak/ethtoolp.py +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -from __future__ import division, print_function, absolute_import -import os -import sys -import subprocess -import re -import json -import yaml -import argparse -import time -from pprint import pprint - -assert sys.version_info.major >= 3, "must be python >=3" - - -PAT_SPACED = re.compile(r'(?=\w)(\w+)(?<=\w)') - - -def vprint(*args): - vprint_level = os.environ.get('VPRINTV', 0) - if vprint_level: - print(*args, file=sys.stderr) - - -def get_space_separated_line(line): - return re.findall(PAT_SPACED, line) - - -def menu(description='Wrapper around ethtool used to set interface speed to max'): - parser = argparse.ArgumentParser(description=description) - parser.add_argument("-c", "--config_uri", default=None, action="store", type=str, help="input config file") - parser.add_argument('iface', nargs='?', default=None, type=str, help="Interface to be set") - - parser.add_argument("-s", "--speed", default=None, action="store", type=int, help="speed to set") - parser.add_argument("-H", "--host", default=None, action="store", type=str, help="host name") - parser.add_argument("-p", "--port", default=8987, action="store", type=int, help="port") - parser.add_argument("-M", "--maximize-speed", "--max-speed", action="store_true", help="Set interface to use max possible speed") - parser.add_argument("-+", "--health", action="store_true", help="Run a health check") - parser.add_argument("-D", "--debug", action="store_true", help="Start in debug mode") - parser.add_argument("-F", "--force", action="store_true", help="Force option even if it's already set") - parser.add_argument("-a", "--all", action="store_true", help="Show all attributes") - - return parser - - -def run_cmd(cmd): - # type: (list) -> (str, str) - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - proc.wait() - data = proc.stdout.read().decode() - err = proc.stderr.read().decode() - - return data, err - -def errcho(s): - # type: (str) -> None - sys.stderr.write('\033[31m' + s + '\n\033[0m') - sys.stderr.flush() - -def esplit(s, sep=" "): - # type: (str, str) -> str - try: - return s.split(sep) - - except AttributeError: - return s - - -def kmap(func, d): - # type: (Callable, dict) -> dict - return {k: func(v) for k, v in d.items()} - -def parse_nmcli_line(line): - # type: (str) -> dict - parts = get_space_separated_line(line) - device = parts[0] - dtype = parts[1] - state = parts[2] - connection = ' '.join(parts[3:]) - return dict(device=device, dtype=dtype, state=state, connection=connection) - -def nmcli_device_status(): - data, err = run_cmd(["nmcli", "device", "status"]) - if err: - errcho('Subprocess `ethtool` failed with following error: \n{}'.format(err)) - sys.exit(1) - - recs = [parse_nmcli_line(line) for line in data.split('\n') if line][1:] - return recs - -def get_wired_devices(): - recs = nmcli_device_status() - return [r for r in recs if 'wired' in r["connection"].lower()] - - -def ethtool_read(iface, show_all=False): - cmd = ['sudo', 'ethtool', iface] - - data, err = run_cmd(cmd) - if err: - errcho('Subprocess `ethtool` failed with following error: \n{}'.format(err)) - sys.exit(1) - data2 = data.replace(" \n\t" + " " * 24, "\n\t\t").replace("\t", " " * 4) - dd = yaml.load(data2, yaml.Loader) - if not dd: - raise ValueError('failed to parse yaml:\n{}'.format(data)) - dd2 = {k: kmap(esplit, v) for k, v in dd.items()} - dd3 = {k.replace('Settings for ', ''): v for k, v in dd2.items()} - vprint(dd3) - out = dd3[iface] - if show_all: - return out - - out = {k: v for k,v in out.items() if k in ["Speed", "Link detected", "Duplex", "Supported link modes"]} - return out - - - -def parse_speed(link_string, default=0): - # type: (str, int) -> int - res = re.findall('(\d+)', link_string) - try: - return int(res[0]) - except (IndexError, ValueError): - return default - -def get_current_speed(iface): - iface_data = ethtool_read(iface) - vprint(iface_data) - current_speed = parse_speed(iface_data["Speed"][0]) - return current_speed - - -def set_speed_to_max(iface, maxspeed): - # type: (str, int) -> str - stdout, stderr = run_cmd(['sudo', 'ethtool', '-s', iface, 'speed', str(maxspeed), 'duplex', 'full']) - print(stdout) - return stdout - -def main(): - parser = menu() - args = parser.parse_args() - vprint(args) - iface = args.iface - wired_devices = get_wired_devices() - if not iface: - print("E: must specify an interface", file=sys.stderr) - pprint(wired_devices) - sys.exit(1) - - iface_data = ethtool_read(iface, show_all=args.all) - - current_speed = parse_speed(iface_data["Speed"][0]) - speeds = [parse_speed(s) for s in iface_data["Supported link modes"]] - max_speed = max(speeds) - if not args.maximize_speed: - sys.stdout.write(json.dumps(iface_data, indent=2) + '\n') - sys.stdout.flush() - return - - vprint("Current speed: {}".format(current_speed)) - if args.speed is not None: - set_speed_to_max(iface, args.speed) - print('{} Speed set to: {}'.format(iface, args.speed)) - return - - if args.maximize_speed: - vprint("Maximizing speed. Max advertized speed: {}, currently ".format(max_speed, current_speed)) - if not args.force and current_speed == max_speed: - print("Speed is currently maximized: {}: {}".format(iface, current_speed)) - return - if not max_speed: - errcho(iface_data) - raise RuntimeError("Could not ascertain speed") - - set_speed_to_max(iface, max_speed) - time.sleep(0.5) - read_back_speed = get_current_speed(iface) - print('{} Speed set to: {}'.format(iface, read_back_speed)) - if read_back_speed != max_speed: - print("WARNING! Could not verify speed was set to max") - sys.exit(1) - - return - - -if __name__ == '__main__': - main() diff --git a/tmux/nayak/follower/supervisor.conf b/tmux/nayak/follower/supervisor.conf index 693a559..39326f6 100644 --- a/tmux/nayak/follower/supervisor.conf +++ b/tmux/nayak/follower/supervisor.conf @@ -14,12 +14,6 @@ startsecs=0 user=root autostart=true -[program:set_eth_speed_max] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/set_eth_speed_max.sh -startsecs=0 -user=root -autostart=true - [program:cam_ir] command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh cam_ir user=user diff --git a/tmux/nayak/leader/supervisor.conf b/tmux/nayak/leader/supervisor.conf index 17257bb..b1bb108 100644 --- a/tmux/nayak/leader/supervisor.conf +++ b/tmux/nayak/leader/supervisor.conf @@ -20,12 +20,6 @@ startsecs=0 user=root autostart=true -[program:set_eth_speed_max] -command=/bin/bash /home/user/kw/kamera/tmux/nayak/set_eth_speed_max.sh -startsecs=0 -user=root -autostart=true - [program:docker_registry] command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh registry user=user diff --git a/tmux/nayak/set_eth_speed_max.sh b/tmux/nayak/set_eth_speed_max.sh deleted file mode 100755 index 07b8255..0000000 --- a/tmux/nayak/set_eth_speed_max.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -# Set all the interface speeds to maximum -# don't do the interconnect -# this is a stupid hack and shouldn't exist but I do not understand why the -# IR camera connection is defaulting to 10M rather than 1Gbps. - -for iface in 25g_outer 25g_inner 1g pci_bot pci_top; do -# this may do weird things to the IP connection of the camera ports - /home/user/kw/kamera/tmux/nayak/ethtoolp.py $iface --maximize-speed -done diff --git a/tmux/taiga/ethtoolp.py b/tmux/taiga/ethtoolp.py deleted file mode 100755 index cb0fcb3..0000000 --- a/tmux/taiga/ethtoolp.py +++ /dev/null @@ -1,190 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -from __future__ import division, print_function, absolute_import -import os -import sys -import subprocess -import re -import json -import yaml -import argparse -import time -from pprint import pprint - -assert sys.version_info.major >= 3, "must be python >=3" - - -PAT_SPACED = re.compile(r'(?=\w)(\w+)(?<=\w)') - - -def vprint(*args): - vprint_level = os.environ.get('VPRINTV', 0) - if vprint_level: - print(*args, file=sys.stderr) - - -def get_space_separated_line(line): - return re.findall(PAT_SPACED, line) - - -def menu(description='Wrapper around ethtool used to set interface speed to max'): - parser = argparse.ArgumentParser(description=description) - parser.add_argument("-c", "--config_uri", default=None, action="store", type=str, help="input config file") - parser.add_argument('iface', nargs='?', default=None, type=str, help="Interface to be set") - - parser.add_argument("-s", "--speed", default=None, action="store", type=int, help="speed to set") - parser.add_argument("-H", "--host", default=None, action="store", type=str, help="host name") - parser.add_argument("-p", "--port", default=8987, action="store", type=int, help="port") - parser.add_argument("-M", "--maximize-speed", "--max-speed", action="store_true", help="Set interface to use max possible speed") - parser.add_argument("-+", "--health", action="store_true", help="Run a health check") - parser.add_argument("-D", "--debug", action="store_true", help="Start in debug mode") - parser.add_argument("-F", "--force", action="store_true", help="Force option even if it's already set") - parser.add_argument("-a", "--all", action="store_true", help="Show all attributes") - - return parser - - -def run_cmd(cmd): - # type: (list) -> (str, str) - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - proc.wait() - data = proc.stdout.read().decode() - err = proc.stderr.read().decode() - - return data, err - -def errcho(s): - # type: (str) -> None - sys.stderr.write('\033[31m' + s + '\n\033[0m') - sys.stderr.flush() - -def esplit(s, sep=" "): - # type: (str, str) -> str - try: - return s.split(sep) - - except AttributeError: - return s - - -def kmap(func, d): - # type: (Callable, dict) -> dict - return {k: func(v) for k, v in d.items()} - -def parse_nmcli_line(line): - # type: (str) -> dict - parts = get_space_separated_line(line) - device = parts[0] - dtype = parts[1] - state = parts[2] - connection = ' '.join(parts[3:]) - return dict(device=device, dtype=dtype, state=state, connection=connection) - -def nmcli_device_status(): - data, err = run_cmd(["nmcli", "device", "status"]) - if err: - errcho('Subprocess `ethtool` failed with following error: \n{}'.format(err)) - sys.exit(1) - - recs = [parse_nmcli_line(line) for line in data.split('\n') if line][1:] - return recs - -def get_wired_devices(): - recs = nmcli_device_status() - return [r for r in recs if 'wired' in r["connection"].lower()] - - -def ethtool_read(iface, show_all=False): - cmd = ['sudo', 'ethtool', iface] - - data, err = run_cmd(cmd) - if err: - errcho('Subprocess `ethtool` failed with following error: \n{}'.format(err)) - sys.exit(1) - data2 = data.replace(" \n\t" + " " * 24, "\n\t\t").replace("\t", " " * 4) - dd = yaml.load(data2, yaml.Loader) - if not dd: - raise ValueError('failed to parse yaml:\n{}'.format(data)) - dd2 = {k: kmap(esplit, v) for k, v in dd.items()} - dd3 = {k.replace('Settings for ', ''): v for k, v in dd2.items()} - vprint(dd3) - out = dd3[iface] - if show_all: - return out - - out = {k: v for k,v in out.items() if k in ["Speed", "Link detected", "Duplex", "Supported link modes"]} - return out - - - -def parse_speed(link_string, default=0): - # type: (str, int) -> int - res = re.findall('(\d+)', link_string) - try: - return int(res[0]) - except (IndexError, ValueError): - return default - -def get_current_speed(iface): - iface_data = ethtool_read(iface) - vprint(iface_data) - current_speed = parse_speed(iface_data["Speed"][0]) - return current_speed - - -def set_speed_to_max(iface, maxspeed): - # type: (str, int) -> str - stdout, stderr = run_cmd(['sudo', 'ethtool', '-s', iface, 'speed', str(maxspeed), 'duplex', 'full']) - print(stdout) - return stdout - -def main(): - parser = menu() - args = parser.parse_args() - vprint(args) - iface = args.iface - wired_devices = get_wired_devices() - if not iface: - print("E: must specify an interface", file=sys.stderr) - pprint(wired_devices) - sys.exit(1) - - iface_data = ethtool_read(iface, show_all=args.all) - - current_speed = parse_speed(iface_data["Speed"][0]) - speeds = [parse_speed(s) for s in iface_data["Supported link modes"]] - max_speed = max(speeds) - if not args.maximize_speed: - sys.stdout.write(json.dumps(iface_data, indent=2) + '\n') - sys.stdout.flush() - return - - vprint("Current speed: {}".format(current_speed)) - if args.speed is not None: - set_speed_to_max(iface, args.speed) - print('{} Speed set to: {}'.format(iface, args.speed)) - return - - if args.maximize_speed: - vprint("Maximizing speed. Max advertized speed: {}, currently ".format(max_speed, current_speed)) - if not args.force and current_speed == max_speed: - print("Speed is currently maximized: {}: {}".format(iface, current_speed)) - return - if not max_speed: - errcho(iface_data) - raise RuntimeError("Could not ascertain speed") - - set_speed_to_max(iface, max_speed) - time.sleep(0.5) - read_back_speed = get_current_speed(iface) - print('{} Speed set to: {}'.format(iface, read_back_speed)) - if read_back_speed != max_speed: - print("WARNING! Could not verify speed was set to max") - sys.exit(1) - - return - - -if __name__ == '__main__': - main() diff --git a/tmux/taiga/follower/supervisor.conf b/tmux/taiga/follower/supervisor.conf index bf9b06e..e4edfe6 100644 --- a/tmux/taiga/follower/supervisor.conf +++ b/tmux/taiga/follower/supervisor.conf @@ -14,12 +14,6 @@ startsecs=0 user=root autostart=true -[program:set_eth_speed_max] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/set_eth_speed_max.sh -startsecs=0 -user=root -autostart=true - [program:cam_ir] command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh cam_ir user=user diff --git a/tmux/taiga/leader/supervisor.conf b/tmux/taiga/leader/supervisor.conf index 01437eb..9232e76 100644 --- a/tmux/taiga/leader/supervisor.conf +++ b/tmux/taiga/leader/supervisor.conf @@ -20,12 +20,6 @@ startsecs=0 user=root autostart=true -[program:set_eth_speed_max] -command=/bin/bash /home/user/kw/kamera/tmux/taiga/set_eth_speed_max.sh -startsecs=0 -user=root -autostart=true - [program:docker_registry] command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh registry user=user diff --git a/tmux/taiga/set_eth_speed_max.sh b/tmux/taiga/set_eth_speed_max.sh deleted file mode 100755 index 901f1b6..0000000 --- a/tmux/taiga/set_eth_speed_max.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -# Set all the interface speeds to maximum -# don't do the interconnect -# this is a stupid hack and shouldn't exist but I do not understand why the -# IR camera connection is defaulting to 10M rather than 1Gbps. - -for iface in mobo_top mobo_btm 1g_pci_bot pci_btm pci_top; do -# this may do weird things to the IP connection of the camera ports - /home/user/kw/kamera/tmux/taiga/ethtoolp.py $iface --maximize-speed -done From 9e24a9fcc753350344486c2e02dabdb8bda35105 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Tue, 16 Jun 2026 10:14:15 -0400 Subject: [PATCH 094/139] Got a little too carried away, need these scripts --- scripts/kamera_halt.sh | 92 +++++++++++++++++++ scripts/kamera_run.sh | 196 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 288 insertions(+) create mode 100644 scripts/kamera_halt.sh create mode 100644 scripts/kamera_run.sh diff --git a/scripts/kamera_halt.sh b/scripts/kamera_halt.sh new file mode 100644 index 0000000..1cced79 --- /dev/null +++ b/scripts/kamera_halt.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash + +## Like kamera_run, but opposite +export COMPOSE_IGNORE_ORPHANS=True # make compose quieter +KAM_REPO_DIR=$(/home/user/.config/kamera/repo_dir.bash) +echo $KAM_REPO_DIR +SYSTEM_NAME=$(cat /home/user/kw/SYSTEM_NAME) +source "${KAM_REPO_DIR}/tmux/${SYSTEM_NAME}/env.sh" + + +errcho() { + (>&2 echo -e "\e[31m$1\e[0m") +} + +blueprintf() { + (printf "\e[34m$@\e[0m") +} + +if [[ -z "$@" ]] ; then + ARGS=(stop) +else + ARGS=("$@") + +fi + +MODE="" +for arg in "${ARGS[@]}" ; do + blueprintf "arg: ${arg}\n" + if [[ "${arg}" == "-d" || "${arg}" == "--detach" ]] ; then DETACH="-d" ; fi + if [[ "${arg}" == "--remove-orphans" ]] ; then REM_ORPH="--remove-orphans" ; fi + if [[ "${arg}" == "up" ]] ; then errcho "Do not use this script to start"; exit 1; fi + if [[ "${arg}" == "kill" ]] ; then MODE=kill ; fi + if [[ "${arg}" == "restart" ]] ; then MODE=restart ; fi + if [[ "${arg}" == "stop" ]] ; then MODE=stop ; fi + if [[ "${arg}" == "down" ]] ; then MODE=down ; fi + if [[ "${arg}" == "rm" ]] ; then MODE=rm ; fi +done + +if [[ -z "${MODE}" ]]; then + errcho "Missing compose mode (up/down etc)" + exit 1 +fi + +## === === === === === === Env setup === === === === === === === +blueprintf "Configuring main KAMERA entrypoint." +if [[ -z "${KAM_REPO_DIR}" ]]; then + echo "ERROR: Could not resolve KAM_REPO_DIR. Check ~/.config/kamera" + exit 1 +fi +blueprintf "." + +MASTER_HOST=$(cq '.master_host') +## === === === === === === End Env setup === === === === === === + + +OPTIONS=(${VERBOSE}) + +blueprintf "done\nBringing down gui..." +docker compose -f "${KAM_REPO_DIR}/compose/gui.yml" "${ARGS[@]}" & +STAT_GUI=$! + +blueprintf "done\nGui down. Killing pods...\n" +# Bring up all pod systems +# Query list of hosts as line delim array +declare -A PIDS +for host in $(cq '.arch.hosts | keys | join("\n" )') ; do + if [[ $(cq ".arch.hosts.${host}.enabled") == 'true' ]]; then + python3 ${KAM_REPO_DIR}/scripts/system.py $host ${ARGS[@]} pod & + PIDS["${host}_pod"]=$! + python3 ${KAM_REPO_DIR}/scripts/system.py $host ${ARGS[@]} detector & + PIDS["${host}_det"]=$! + fi +done +blueprintf "done\nBringing down central..." +python3 ${KAM_REPO_DIR}/scripts/system.py $MASTER_HOST ${ARGS[@]} central & +PIDS["${host}_cen"]=$! +python3 ${KAM_REPO_DIR}/scripts/system.py $MASTER_HOST ${ARGS[@]} monitor & +PIDS["${host}_mon"]=$! +wait $STAT_GUI +# wait for all pids +for pid in ${PIDS[*]}; do + wait $pid +done + +blueprintf "done\nBringing down master..." +python3 ${KAM_REPO_DIR}/scripts/system.py $MASTER_HOST ${ARGS[@]} master +blueprintf "done. ROS should be down\n" + +blueprintf "Dismounting drives..." +# todo: dismounts +blueprintf "done\n " +docker ps diff --git a/scripts/kamera_run.sh b/scripts/kamera_run.sh new file mode 100644 index 0000000..4c0f427 --- /dev/null +++ b/scripts/kamera_run.sh @@ -0,0 +1,196 @@ +#!/usr/bin/env bash + +## This script provides turnkey operation to spin up the whole system +export COMPOSE_IGNORE_ORPHANS=True # make compose quieter +KAM_REPO_DIR=$(/home/user/.config/kamera/repo_dir.bash) +echo $KAM_REPO_DIR +SYSTEM_NAME=$(cat /home/user/kw/SYSTEM_NAME) +source "${KAM_REPO_DIR}/tmux/${SYSTEM_NAME}/env.sh" + +errcho() { + (>&2 echo -e "\e[31m$1\e[0m") +} + +blueprintf() { + (printf "\e[34m$@\e[0m") +} + +if [[ -z "$@" ]] ; then + ARGS=(start) +else + ARGS=("$@") + +fi + +MODE="" +for arg in "${ARGS[@]}" ; do + blueprintf "arg: ${arg}\n" + if [[ "${arg}" == "-d" || "${arg}" == "--detach" ]] ; then DETACH="-d" ; fi + if [[ "${arg}" == "--remove-orphans" ]] ; then REM_ORPH="--remove-orphans" ; fi + if [[ "${arg}" == "up" ]] ; then MODE=up ; fi + if [[ "${arg}" == "start" ]] ; then MODE=up ; fi + if [[ "${arg}" == "kill" ]] ; then MODE=kill ; fi + if [[ "${arg}" == "restart" ]] ; then MODE=restart ; fi + if [[ "${arg}" == "stop" ]] ; then MODE=stop ; fi + if [[ "${arg}" == "down" ]] ; then errcho "Do not use this script to 'down'"; exit 1 ; fi + if [[ "${arg}" == "rm" ]] ; then MODE=rm ; fi +done + +if [[ -z "${MODE}" ]]; then + errcho "Missing compose mode (up/down etc)" + exit 1 +fi + +## === === === === === === Env setup === === === === === === === +blueprintf "Configuring main KAMERA entrypoint." +# Add detector ENV variables to Redis +source ${KAM_REPO_DIR}/src/cfg/set_detector_read_state.sh +blueprintf "." + +MASTER_HOST=$(cq '.master_host') + +for VNAME in MASTER_HOST KAM_REPO_DIR +do + if [[ -z "${!VNAME}" || "${!VNAME}" == 'null' ]]; then + printf " Unable to determine $VNAME: Check user-config\n" + exit 1 + fi +done + +## === === === === === === End Env setup === === === === === === + +## === === === === === Handle drive mounts === === === === === +echo "Waiting for master host to come online. Hit ctrl-c or window X to cancel" +i=1 +SP="/-\|" +until ping -c1 -W1 ${MASTER_HOST} &>/dev/null; do + printf "\b${SP:i++%${#SP}:1}" +done + +SKIP_PING=true +for host in $(cq '.arch.hosts | keys | join("\n" )') ; do + hostip=$(dig +short $host) + if [[ $? != 0 ]]; then + errcho "FATAL: Cannot resolve IP for necassary host ${host}" + fi + + _CLIENTS=$(redis-cli -h $REDIS_HOST client list | grep $hostip) + if [[ $? != 0 ]]; then + SKIP_PING= + fi +done + +if [[ -n ${SKIP_PING} ]]; then + echo "all clients located, yay!" +else + for host in $(cq '.arch.hosts | keys | join("\n" )') ; do + echo "Waiting on ping $host." + if [[ $(cq ".arch.hosts.${host}.enabled") == 'true' ]]; then + until ping -c1 -W1 ${host} &>/dev/null; do + printf "\b${SP:i++%${#SP}:1}" + done + else + echo "${host} disabled." + fi + done +fi + +supervisorctl restart mount_nas +ls /mnt/flight_data/.flight_data_mounted +NAS_CODE=$? +if ! [[ $NAS_CODE == 0 ]]; then + echo "Failed to connect to NAS! Troubleshoot!" + sleep 5 +# exit +else + echo "NAS mounted!" +fi +declare -A PIDS +for host in $(cq '.arch.hosts | keys | join("\n" )') ; do + if [[ $(cq ".arch.hosts.${host}.enabled") == 'true' ]]; then + python3 ${KAM_REPO_DIR}/scripts/system.py $host restart nas & + PIDS[${host}]=$! + else + echo "${host} disabled." + + fi +done + +for pid in ${PIDS[*]}; do + wait $pid +done + + +# Bring up master and core nodes +MASTER_HOST=$(cq '.master_host') +blueprintf "done\nBringing up master $MASTER_HOST..." +python3 ${KAM_REPO_DIR}/scripts/system.py $MASTER_HOST "${ARGS[@]}" master + +# check that master is in fact up +FAIL_COUNT=0 +cd $KAM_REPO_DIR +until docker compose -f ${KAM_REPO_DIR}/compose/nodelist.yml run --rm nodelist; do + echo "Attempt $((++FAIL_COUNT))"; + if [[ $FAIL_COUNT -gt 3 ]]; then + errcho "Unable to contact ros master. Running WTF and aborting startup" + docker compose -f ${KAM_REPO_DIR}/compose/nodelist.yml run --rm nodelist /entry/wat.sh + exit 1 + fi +done + +# === === === === Checks have passed === === === === +blueprintf "done. Init checks are good! \nBringing up central..." +python3 ${KAM_REPO_DIR}/scripts/system.py $MASTER_HOST "${ARGS[@]}" central & +STAT_CENTRAL=$! + + +blueprintf "done\nLaunching pod nodes...\n" + +# Bring up all pod systems +# Query list of hosts as line delim array +declare -A PIDS +# sort, so hosts are started idempotently +hosts=$(cq '.arch.hosts | keys | join("\n" )') +IFS=$'\n' sorted_hosts=($(sort <<<"${hosts[*]}")) +unset IFS +for host in "${sorted_hosts[@]}"; do + if [[ $(cq ".arch.hosts.${host}.enabled") == 'true' ]]; then + python3 ${KAM_REPO_DIR}/scripts/system.py $host "${ARGS[@]}" pod & + PIDS[${host}]=$! + else + echo "${host} disabled." + + fi +done +echo " PIDS : ${PIDS[@]}" + +# === === === === Checks have passed === === === === +blueprintf "Bringing up monitor..." +python3 ${KAM_REPO_DIR}/scripts/system.py $MASTER_HOST "${ARGS[@]}" monitor & +STAT_MONITOR=$! + +blueprintf "done. \nPods launched. Starting GUI..." + +cd ${KAM_REPO_DIR} +set -a # automatically export all variables +xhost +local:root +docker compose -f "${KAM_REPO_DIR}/compose/gui.yml" "${ARGS[@]}" & +STAT_GUI=$! +blueprintf "done\n === Starting System Control Panel :D === " +set +a + +gui_splash() { + notify-send -t 5000 -i ~/kw/kamera/src/cfg/seal-icon.png \ + "KAMERA" "Starting KAMERA Control Panel, please wait" || true +} +gui_splash + +wait $STAT_CENTRAL +wait $STAT_MONITOR +# wait for all pids +for pid in ${PIDS[*]}; do + echo "waiting on: $pid" + wait $pid +done +wait $STAT_GUI + From 26573202bb826682ef4bcb82214bd1acc6f977fb Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Tue, 16 Jun 2026 10:39:11 -0400 Subject: [PATCH 095/139] Make scripts executable, strs be f-strs --- scripts/kamera_halt.sh | 0 scripts/kamera_run.sh | 0 scripts/system.py | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 scripts/kamera_halt.sh mode change 100644 => 100755 scripts/kamera_run.sh diff --git a/scripts/kamera_halt.sh b/scripts/kamera_halt.sh old mode 100644 new mode 100755 diff --git a/scripts/kamera_run.sh b/scripts/kamera_run.sh old mode 100644 new mode 100755 diff --git a/scripts/system.py b/scripts/system.py index 4d35520..00e9cf9 100644 --- a/scripts/system.py +++ b/scripts/system.py @@ -5,7 +5,7 @@ with open("/home/user/kw/SYSTEM_NAME") as f: SYSTEM_NAME = f.read().strip() -hosts = [ f"center0{SYSTEM_NAME}", "left1{SYSTEM_NAME}", "right2{SYSTEM_NAME}"] +hosts = [ f"center0{SYSTEM_NAME}", f"left1{SYSTEM_NAME}", f"right2{SYSTEM_NAME}"] group = SYSTEM_NAME pod = [ "image_manager", From 7a1949e6f8b79b3942fb8e9c0d5f93beab3773c5 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 10:40:13 -0400 Subject: [PATCH 096/139] Pin NFS version, make nas mount dir beforehand --- provision/ansible/playbooks/cas/configure.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index 413829e..0e1fa29 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -132,11 +132,18 @@ state: directory mode: '0777' + - name: Make NAS mount directory "{{ nas_mnt }}" + become: True + file: + path: "{{ nas_mnt }}" + state: directory + mode: '0777' + - name: Edit fstab to mount NAS to "{{ data_dir }}" become: True lineinfile: path: /etc/fstab - line: kamera_nas:/volume1/kamera/flight_data {{ data_dir }} nfs auto,nofail,noatime,nolock,intr,tcp,actimeo=1800 0 0 + line: kamera_nas:/volume1/kamera/flight_data {{ data_dir }} nfs vers=3,auto,nofail,noatime,nolock,intr,tcp,actimeo=1800 0 0 state: present insertbefore: EOF From a4ff4a9ae10db37bbc6a83e17b996b24e723b459 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 10:47:04 -0400 Subject: [PATCH 097/139] Whoops didn't need that folder creation --- provision/ansible/playbooks/cas/configure.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index 0e1fa29..db26acd 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -132,13 +132,6 @@ state: directory mode: '0777' - - name: Make NAS mount directory "{{ nas_mnt }}" - become: True - file: - path: "{{ nas_mnt }}" - state: directory - mode: '0777' - - name: Edit fstab to mount NAS to "{{ data_dir }}" become: True lineinfile: From 6d2dfc920348fa5ff1fa1f8c6ac3df27fc569a7c Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 11:00:30 -0400 Subject: [PATCH 098/139] Rollback hosts to a per-machine config, as the NAS requires a distinct IP per machine --- provision/ansible/playbooks/cas/configure.yml | 2 +- src/cfg/nayak/cas3/hosts | 32 +++++++++++++++++++ src/cfg/{ => nayak/center0nayak}/hosts | 1 - src/cfg/nayak/left1nayak/hosts | 32 +++++++++++++++++++ src/cfg/nayak/right2nayak/hosts | 32 +++++++++++++++++++ src/cfg/taiga/center0taiga/hosts | 32 +++++++++++++++++++ src/cfg/taiga/left1taiga/hosts | 32 +++++++++++++++++++ src/cfg/taiga/right2taiga/hosts | 32 +++++++++++++++++++ 8 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 src/cfg/nayak/cas3/hosts rename src/cfg/{ => nayak/center0nayak}/hosts (99%) create mode 100644 src/cfg/nayak/left1nayak/hosts create mode 100644 src/cfg/nayak/right2nayak/hosts create mode 100644 src/cfg/taiga/center0taiga/hosts create mode 100644 src/cfg/taiga/left1taiga/hosts create mode 100644 src/cfg/taiga/right2taiga/hosts diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index db26acd..b7aaf2f 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -111,7 +111,7 @@ - name: Add mappings to /etc/hosts become: True copy: - src: "{{ kamera_dir }}/src/cfg/hosts" + src: "{{ kamera_dir }}/src/cfg/{{ config_dir }}/{{ inventory_hostname }}/hosts" remote_src: true dest: /etc/hosts owner: root diff --git a/src/cfg/nayak/cas3/hosts b/src/cfg/nayak/cas3/hosts new file mode 100644 index 0000000..dd430e3 --- /dev/null +++ b/src/cfg/nayak/cas3/hosts @@ -0,0 +1,32 @@ +127.0.0.1 localhost.localdomain localhost +::1 localhost6.localdomain6 localhost6 + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +ff02::3 ip6-allhosts + +# Inserted from KAMERA +192.168.88.1 mikrotik + +192.168.88.10 center0taiga +192.168.88.11 left1taiga +192.168.88.12 right2taiga + +192.168.88.100 center0nayak +192.168.88.101 left1nayak +192.168.88.102 right2nayak +192.168.88.103 center1nayak + +# Fallback static connections +192.168.88.210 nuvo0bak +192.168.88.211 nuvo1bak +192.168.88.212 nuvo2bak + +192.168.198.13 kamera_nas + +# Set ros master url here - typically nuvo0 +192.168.88.10 kameramaster +192.168.88.99 ins diff --git a/src/cfg/hosts b/src/cfg/nayak/center0nayak/hosts similarity index 99% rename from src/cfg/hosts rename to src/cfg/nayak/center0nayak/hosts index 1e1807b..4ddd9ab 100644 --- a/src/cfg/hosts +++ b/src/cfg/nayak/center0nayak/hosts @@ -30,4 +30,3 @@ ff02::3 ip6-allhosts # Set ros master url here - typically nuvo0 192.168.88.10 kameramaster 192.168.88.99 ins - diff --git a/src/cfg/nayak/left1nayak/hosts b/src/cfg/nayak/left1nayak/hosts new file mode 100644 index 0000000..a8ac0cd --- /dev/null +++ b/src/cfg/nayak/left1nayak/hosts @@ -0,0 +1,32 @@ +127.0.0.1 localhost.localdomain localhost +::1 localhost6.localdomain6 localhost6 + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +ff02::3 ip6-allhosts + +# Inserted from KAMERA +192.168.88.1 mikrotik + +192.168.88.10 center0taiga +192.168.88.11 left1taiga +192.168.88.12 right2taiga + +192.168.88.100 center0nayak +192.168.88.101 left1nayak +192.168.88.102 right2nayak +192.168.88.103 center1nayak + +# Fallback static connections +192.168.88.210 nuvo0bak +192.168.88.211 nuvo1bak +192.168.88.212 nuvo2bak + +192.168.198.11 kamera_nas + +# Set ros master url here - typically nuvo0 +192.168.88.10 kameramaster +192.168.88.99 ins diff --git a/src/cfg/nayak/right2nayak/hosts b/src/cfg/nayak/right2nayak/hosts new file mode 100644 index 0000000..a9f910f --- /dev/null +++ b/src/cfg/nayak/right2nayak/hosts @@ -0,0 +1,32 @@ +127.0.0.1 localhost.localdomain localhost +::1 localhost6.localdomain6 localhost6 + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +ff02::3 ip6-allhosts + +# Inserted from KAMERA +192.168.88.1 mikrotik + +192.168.88.10 center0taiga +192.168.88.11 left1taiga +192.168.88.12 right2taiga + +192.168.88.100 center0nayak +192.168.88.101 left1nayak +192.168.88.102 right2nayak +192.168.88.103 center1nayak + +# Fallback static connections +192.168.88.210 nuvo0bak +192.168.88.211 nuvo1bak +192.168.88.212 nuvo2bak + +192.168.198.12 kamera_nas + +# Set ros master url here - typically nuvo0 +192.168.88.10 kameramaster +192.168.88.99 ins diff --git a/src/cfg/taiga/center0taiga/hosts b/src/cfg/taiga/center0taiga/hosts new file mode 100644 index 0000000..4ddd9ab --- /dev/null +++ b/src/cfg/taiga/center0taiga/hosts @@ -0,0 +1,32 @@ +127.0.0.1 localhost.localdomain localhost +::1 localhost6.localdomain6 localhost6 + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +ff02::3 ip6-allhosts + +# Inserted from KAMERA +192.168.88.1 mikrotik + +192.168.88.10 center0taiga +192.168.88.11 left1taiga +192.168.88.12 right2taiga + +192.168.88.100 center0nayak +192.168.88.101 left1nayak +192.168.88.102 right2nayak +192.168.88.103 center1nayak + +# Fallback static connections +192.168.88.210 nuvo0bak +192.168.88.211 nuvo1bak +192.168.88.212 nuvo2bak + +192.168.198.10 kamera_nas + +# Set ros master url here - typically nuvo0 +192.168.88.10 kameramaster +192.168.88.99 ins diff --git a/src/cfg/taiga/left1taiga/hosts b/src/cfg/taiga/left1taiga/hosts new file mode 100644 index 0000000..a8ac0cd --- /dev/null +++ b/src/cfg/taiga/left1taiga/hosts @@ -0,0 +1,32 @@ +127.0.0.1 localhost.localdomain localhost +::1 localhost6.localdomain6 localhost6 + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +ff02::3 ip6-allhosts + +# Inserted from KAMERA +192.168.88.1 mikrotik + +192.168.88.10 center0taiga +192.168.88.11 left1taiga +192.168.88.12 right2taiga + +192.168.88.100 center0nayak +192.168.88.101 left1nayak +192.168.88.102 right2nayak +192.168.88.103 center1nayak + +# Fallback static connections +192.168.88.210 nuvo0bak +192.168.88.211 nuvo1bak +192.168.88.212 nuvo2bak + +192.168.198.11 kamera_nas + +# Set ros master url here - typically nuvo0 +192.168.88.10 kameramaster +192.168.88.99 ins diff --git a/src/cfg/taiga/right2taiga/hosts b/src/cfg/taiga/right2taiga/hosts new file mode 100644 index 0000000..a9f910f --- /dev/null +++ b/src/cfg/taiga/right2taiga/hosts @@ -0,0 +1,32 @@ +127.0.0.1 localhost.localdomain localhost +::1 localhost6.localdomain6 localhost6 + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +ff02::3 ip6-allhosts + +# Inserted from KAMERA +192.168.88.1 mikrotik + +192.168.88.10 center0taiga +192.168.88.11 left1taiga +192.168.88.12 right2taiga + +192.168.88.100 center0nayak +192.168.88.101 left1nayak +192.168.88.102 right2nayak +192.168.88.103 center1nayak + +# Fallback static connections +192.168.88.210 nuvo0bak +192.168.88.211 nuvo1bak +192.168.88.212 nuvo2bak + +192.168.198.12 kamera_nas + +# Set ros master url here - typically nuvo0 +192.168.88.10 kameramaster +192.168.88.99 ins From b55a1283cb85de02ea718caa02a5e7e456e847cc Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 12:27:25 -0400 Subject: [PATCH 099/139] Numerous gui updates to bring it closer to previous behavior --- .../src/wxpython_gui/ImageInspectionFrame.py | 4 +- .../src/wxpython_gui/RemoteImagePanel.py | 32 +++++++--- .../src/wxpython_gui/UpdateImageThread.py | 22 +++++-- .../wxpython_gui/src/wxpython_gui/cfg.py | 59 +++++++++++-------- .../form_builder_output.py | 8 +-- .../wxpython_gui/system_control_panel/gui.py | 26 ++++++-- .../system_control_panel/gui_utils.py | 20 ++++++- 7 files changed, 123 insertions(+), 48 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py index cf90338..b1b56db 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py @@ -89,8 +89,8 @@ def on_toggle_saturated_pixels(self, event): def on_ir_contrast_strength(self, event=None): try: - SYS_CFG["ir_contrast_strength"] = float( - self.ir_contrast_strength_txt_ctrl.GetValue()) + SYS_CFG["ir_contrast_strength"] = int(float( + self.ir_contrast_strength_txt_ctrl.GetValue())) except ValueError: pass diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/RemoteImagePanel.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/RemoteImagePanel.py index e55a123..296fded 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/RemoteImagePanel.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/RemoteImagePanel.py @@ -58,6 +58,8 @@ def __init__(self, wx_panel, srv_topic, self.raw_image_lock = threading.RLock() self.wx_panel.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) + if self.wx_histogram_panel is not None: + self.wx_histogram_panel.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) self.status_static_text = status_static_text self.update_status_msg(format_status()) @@ -70,6 +72,8 @@ def __init__(self, wx_panel, srv_topic, self.wx_panel.Bind(wx.EVT_RIGHT_DOWN, self.on_click) self.wx_panel.Bind(wx.EVT_PAINT, self.on_paint) self.wx_panel.Bind(wx.EVT_SIZE, self.on_size) + if self.wx_histogram_panel is not None: + self.wx_histogram_panel.Bind(wx.EVT_PAINT, self.on_histogram_paint) # -------------------------------------------------------------------- def start_image_thread(self): @@ -119,10 +123,14 @@ def update_all_if_needed(self): self.update_inverse_homography() self.warp_image() self.wx_panel.Refresh(True) + if self.wx_histogram_panel is not None: + self.wx_histogram_panel.Refresh(True) else: self.wx_bitmap = None self._histogram = None self.wx_panel.Refresh(True) + if self.wx_histogram_panel is not None: + self.wx_histogram_panel.Refresh(True) def update_all(self): self.needs_update = True @@ -250,7 +258,7 @@ def generate_histogram(self): #vmax = min([vmax1,vmax2*2]) vmax = vmax1 v = v/(vmax)*panel_height - h = panel_height - np.round(v).astype(np.int) + h = panel_height - np.round(v).astype(int) image = np.full((panel_height,256,3), 255, np.uint8) for i in range(len(h)): @@ -262,8 +270,9 @@ def on_paint(self, event=None): """Called on event wx.EVT_PAINT. """ + # Phoenix requires a PaintDC every paint event to validate the region. + pdc = wx.PaintDC(self.wx_panel) if self.wx_bitmap is not None: - pdc = wx.PaintDC(self.wx_panel) dc = wx.GCDC(pdc) panel_width, panel_height = self.wx_panel.GetSize() @@ -271,6 +280,13 @@ def on_paint(self, event=None): dy = (panel_height - self.panel_image_height)//2 dc.DrawBitmap(self.wx_bitmap, dx, dy) + def on_histogram_paint(self, event=None): + """Called on event wx.EVT_PAINT for the histogram panel. + + Phoenix only allows a PaintDC for the window being painted, so the + histogram can't be drawn from on_paint above. + """ + pdc = wx.PaintDC(self.wx_histogram_panel) if self._histogram is not None: panel_width, panel_height = self.wx_histogram_panel.GetSize() image = cv2.resize(self._histogram, dsize=(panel_width, @@ -280,13 +296,9 @@ def on_paint(self, event=None): wx_image.SetData(image.tobytes()) wx_histogram_bitmap = wx_image.ConvertToBitmap() - pdc = wx.PaintDC(self.wx_histogram_panel) dc = wx.GCDC(pdc) dc.DrawBitmap(wx_histogram_bitmap, 0, 0) - if event is not None: - event.Skip() - def refresh(self, event): """Useful to bind the Refresh of self.wx_panel to an event. @@ -304,7 +316,11 @@ def update_status_msg(self, string): else: self.status_static_text.SetForegroundColour((0,0,0)) - if len(string0) != len(string): + # Re-fit on any change so the centered label tracks its text: a pinned + # min size (from unclip) would otherwise mis-center variable-width text. + if string0 != string: + self.status_static_text.InvalidateBestSize() + self.status_static_text.SetMinSize(self.status_static_text.GetBestSize()) self.status_static_text.GetParent().Layout() def release(self): @@ -314,6 +330,8 @@ def release(self): self.wx_panel.Unbind(wx.EVT_PAINT) self.wx_panel.Unbind(wx.EVT_SIZE) + if self.wx_histogram_panel is not None: + self.wx_histogram_panel.Unbind(wx.EVT_PAINT) if self.update_image_thread: self.update_image_thread.stop() diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/UpdateImageThread.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/UpdateImageThread.py index 1005a64..f6f2bb9 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/UpdateImageThread.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/UpdateImageThread.py @@ -214,6 +214,11 @@ def get_new_raw_image(self, release=0): try: homography, output_height, output_width = self.get_homography() + # py3 rospy is strict: int fields reject floats (incl. numpy). + output_height = int(output_height) + output_width = int(output_width) + contrast_strength = int(SYS_CFG["ir_contrast_strength"]) + # Invert and flatten homography_ = tuple(np.linalg.inv(homography).ravel()) frame = "%s_%s_%s" % (self._fov, self._chan, self._id) @@ -239,7 +244,7 @@ def get_new_raw_image(self, release=0): release=release, frame=frame, apply_clahe=self.apply_clahe, - contrast_strength=SYS_CFG["ir_contrast_strength"], + contrast_strength=contrast_strength, show_saturated_pixels=SYS_CFG["show_saturated_pixels"], ) if not resp.success: @@ -291,11 +296,16 @@ def update_status_msg(self, img_header): t = img_header.stamp.to_sec() t = datetime.datetime.utcfromtimestamp(t) # string = format_status(timeval=t, num_dropped=0) - string = channel_format_status( - self._fov, - self._chan, - timeval=t, - ) + # Don't let a missing redis key block imagery dispatch. + try: + string = channel_format_status( + self._fov, + self._chan, + timeval=t, + ) + except Exception as e: + rospy.logwarn_throttle(10, "Could not format status: {}".format(e)) + return None wx.CallAfter(self._parent.update_status_msg, string) return string diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py index 8f15c77..7af9faf 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py @@ -13,6 +13,7 @@ from cv_bridge import CvBridge, CvBridgeError from roskv.impl.redis_envoy import RedisEnvoy as ImplEnvoy +from roskv.util import filter_hosts_by_system import wxpython_gui from wxpython_gui.utils import check_default @@ -337,11 +338,11 @@ def save_camera_config(curr_cfg=None): def format_status( timeval=None, - num_dropped=0, + num_dropped=None, exposure_us=None, gain=None, dt=0, - fps=0.0, + fps=None, chan=None, total=None, processed=None, @@ -364,17 +365,18 @@ def format_status( return "☒ No image stream\n" + extra time_str = str(timeval.time())[3:11] - drop_str = ( - "{} dropped".format(num_dropped) - if num_dropped < 10000 - else "{:.0e} dropped".format(num_dropped) - ) + if num_dropped is None: + drop_str = "? dropped" + elif num_dropped < 10000: + drop_str = "{} dropped".format(num_dropped) + else: + drop_str = "{:.0e} dropped".format(num_dropped) gain_str = "Gain:?" if gain is None else "Gain:{}".format(gain) - # display N/N, even if internally it's N-1/N - # make sure processed isn't above total - if processed < total: - total = total - 1 if total > 0 else total + fps_str = "? fps" if fps is None else "{:4.2f} fps".format(fps) if total is not None and processed is not None: + # display N/N, even if internally it's N-1/N + if processed < total: + total = total - 1 if total > 0 else total drop_str += " | DB: {}/{}".format(processed, total) processed_str = "" if processed is None else "{}".format(processed) expo_str = ( @@ -383,12 +385,12 @@ def format_status( else "Exp: {:0.2f} ms".format(float(exposure_us) * 1e-3) ) if chan == "ir": - fmt = "{fps: 4.2f} fps\n{drop}" - out = fmt.format(fps=fps, drop=drop_str) + fmt = "{fps}\n{drop}" + out = fmt.format(fps=fps_str, drop=drop_str) else: - fmt = "{gain} | {fps: 4.2f} fps\n{expo}\n{drop}" + fmt = "{gain} | {fps} | {expo}\n{drop}" out = fmt.format( - time=time_str, gain=gain_str, fps=fps, expo=expo_str, drop=drop_str + time=time_str, gain=gain_str, fps=fps_str, expo=expo_str, drop=drop_str ) return out @@ -400,9 +402,11 @@ def channel_format_status(fov, chan, timeval=None, dt=0): a = "actual_geni_params" param_ns = "/".join(["", "sys", a, host, chan]) drop_ns = "/".join(["", "sys", "arch", host, chan, "dropped"]) - num_dropped = int(kv.get(drop_ns)) + dropped_val = kv.get(drop_ns, None) + num_dropped = int(dropped_val) if dropped_val is not None else None fps_ns = "/".join(["", "sys", "arch", host, chan, "fps"]) - fps = float(kv.get(fps_ns)) + fps_val = kv.get(fps_ns, None) + fps = float(fps_val) if fps_val is not None else None exposure_us = None gain = None total = None @@ -411,11 +415,17 @@ def channel_format_status(fov, chan, timeval=None, dt=0): gain = kv.get(param_ns + "/GainValue", None) exposure_us = kv.get(param_ns + "/ExposureValue", None) elif chan == "rgb": - gain = int(float(kv.get(param_ns + "/ISO", None)) / 50.0) - # convert float point seconds to us - exposure_us = float(kv.get(param_ns + "/Shutter_Speed", None)) * 1e6 - total = int(kv.get("/sys/" + host + "/p1debayerq/total")) - processed = int(kv.get("/sys/" + host + "/p1debayerq/processed")) + iso = kv.get(param_ns + "/ISO", None) + if iso is not None: + gain = int(float(iso) / 50.0) + shutter = kv.get(param_ns + "/Shutter_Speed", None) + if shutter is not None: + # convert float point seconds to us + exposure_us = float(shutter) * 1e6 + total = kv.get("/sys/" + host + "/p1debayerq/total", None) + total = int(total) if total is not None else None + processed = kv.get("/sys/" + host + "/p1debayerq/processed", None) + processed = int(processed) if processed is not None else None try: dt = float(kv.get(param_ns + "/last_msg_time", None)) except: @@ -436,7 +446,8 @@ def channel_format_status(fov, chan, timeval=None, dt=0): def host_from_fov(fov): # type: (str) -> str hosts = SYS_CFG["arch"]["hosts"] - for host, attrs in hosts.items(): - if fov == attrs["fov"]: + # Skip stale hosts left in redis from other systems. + for host in filter_hosts_by_system(hosts.keys()): + if fov == hosts[host]["fov"]: return host raise KeyError("FOV not found: '{}'".format(fov)) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index 064d9aa..6a3677d 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -503,7 +503,7 @@ def __init__( self, parent ): self.nas_disk_space.Wrap( -1 ) self.nas_disk_space.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - bSizer391.Add( self.nas_disk_space, 0, wx.TOP|wx.RIGHT|wx.LEFT, 3 ) + bSizer391.Add( self.nas_disk_space, 0, wx.TOP|wx.RIGHT|wx.LEFT|wx.ALIGN_CENTER_HORIZONTAL, 3 ) self.flight_data_panel.SetSizer( bSizer391 ) @@ -932,7 +932,7 @@ def __init__( self, parent ): self.sys1_disk_usage_panel.SetSizer( bsizer213 ) self.sys1_disk_usage_panel.Layout() bsizer213.Fit( self.sys1_disk_usage_panel ) - disk_space_row_bSizer1.Add( self.sys1_disk_usage_panel, 1, 0, 5 ) + disk_space_row_bSizer1.Add( self.sys1_disk_usage_panel, 1, wx.EXPAND, 5 ) self.sys0_disk_usage_panel = wx.Panel( self.images_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) bsizer2122 = wx.BoxSizer( wx.VERTICAL ) @@ -947,7 +947,7 @@ def __init__( self, parent ): self.sys0_disk_usage_panel.SetSizer( bsizer2122 ) self.sys0_disk_usage_panel.Layout() bsizer2122.Fit( self.sys0_disk_usage_panel ) - disk_space_row_bSizer1.Add( self.sys0_disk_usage_panel, 1, 0, 5 ) + disk_space_row_bSizer1.Add( self.sys0_disk_usage_panel, 1, wx.EXPAND, 5 ) self.sys2_disk_usage_panel = wx.Panel( self.images_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) bsizer212 = wx.BoxSizer( wx.VERTICAL ) @@ -962,7 +962,7 @@ def __init__( self, parent ): self.sys2_disk_usage_panel.SetSizer( bsizer212 ) self.sys2_disk_usage_panel.Layout() bsizer212.Fit( self.sys2_disk_usage_panel ) - disk_space_row_bSizer1.Add( self.sys2_disk_usage_panel, 1, 0, 5 ) + disk_space_row_bSizer1.Add( self.sys2_disk_usage_panel, 1, wx.EXPAND, 5 ) bSizer16.Add( disk_space_row_bSizer1, 0, wx.EXPAND, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 8fdf8b5..0be4455 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -525,16 +525,20 @@ def __init__( self.system = SystemCommands(self.hosts) self.Bind(wx.EVT_CLOSE, self.when_closed) + self._did_initial_unclip = False self.Bind(wx.EVT_SIZE, self.on_resize) - # So that we can check that the node is still alive. - self.timer = wx.Timer(self) + # Distinct ids so the two EVT_TIMER bindings don't collide; keep the + # refs alive so the ids aren't recycled. + self._fast_timer_id = wx.NewIdRef() + self._slow_timer_id = wx.NewIdRef() + self.timer = wx.Timer(self, id=self._fast_timer_id) self.Bind(wx.EVT_TIMER, self.on_timer, self.timer) FAST_TIMER_MS = 200 self.timer.Start(FAST_TIMER_MS) # So that we can check that the node is still alive. - self.slow_timer = wx.Timer(self) + self.slow_timer = wx.Timer(self, id=self._slow_timer_id) self.Bind(wx.EVT_TIMER, self.on_slow_timer, self.slow_timer) self.slow_timer.Start(1000) # TODO @@ -687,15 +691,18 @@ def _apply_system_sanity(self, results, nas_unmounts): elif entry["ssd_gb"] is not None: ssd_label.SetLabel("Disk Space: %0.2f GB" % entry["ssd_gb"]) ssd_label.SetForegroundColour(COLLECT_GREEN) + gui_utils.refit_label(ssd_label) # The NAS is shared, so it's only displayed once (center host). if fov == "center" and entry["nas_gb"] is not None: self.nas_disk_space.SetLabel( "NAS Disk Space: %0.2f GB" % entry["nas_gb"] ) self.nas_disk_space.SetForegroundColour(COLLECT_GREEN) + gui_utils.refit_label(self.nas_disk_space) if nas_unmounts: self.nas_disk_space.SetLabel("NAS Err: " + "".join(nas_unmounts)) self.nas_disk_space.SetForegroundColour(ERROR_RED) + gui_utils.refit_label(self.nas_disk_space) def _set_field_enabled(self, ctrl, enabled): """Enable/disable an input field and make the disabled state obvious. @@ -1116,6 +1123,13 @@ def on_timer(self, event): if rospy.is_shutdown(): self.on_close_button(None) + # The startup unclip runs before GTK finalizes panel sizes, so labels + # center against stale widths. Re-run once, after the window is fully + # realized (the first timer tick is guaranteed to be late enough). + if not self._did_initial_unclip: + self._did_initial_unclip = True + gui_utils.unclip_static_text(self) + self.update_collect_colors() # Check to see if imagery has been received recently. @@ -1126,11 +1140,13 @@ def on_timer(self, event): if panel.last_update is None: panel.status_static_text.SetLabel(format_status()) panel.status_static_text.SetForegroundColour(BRIGHT_RED) + gui_utils.refit_label(panel.status_static_text) else: dt = time.time() - panel.last_update if dt > 10: panel.status_static_text.SetLabel(format_status(dt=dt)) panel.status_static_text.SetForegroundColour(BRIGHT_RED) + gui_utils.refit_label(panel.status_static_text) # Check to see if imagery has been received recently. if self._image_inspection_frame: @@ -1652,7 +1668,7 @@ def ins_state(self, msg): """ if self._spoof_gps: - spoofed = kv.get_dict("/spoof/ins") + spoofed = kv.get_dict("/debug", {}).get("spoof", {}).get("ins", {}) apply_ins_spoof(msg, spoofed) t = msg.time lat = msg.latitude @@ -1855,6 +1871,8 @@ def update_show_hide(self): self.sys2_detector_frames.Hide() self.sys2_disk_usage_panel.Hide() self.Layout() + # Titles get a stale best size while hidden; re-fit them once shown. + wx.CallAfter(gui_utils.unclip_static_text, self) # ------------------------------------------------------------------------ # ---------------------------- Detection Menu ---------------------------- diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui_utils.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui_utils.py index e2df69f..bc3cea5 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui_utils.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui_utils.py @@ -26,9 +26,27 @@ def _walk(parent): child.InvalidateBestSize() child.SetMinSize(child.GetBestSize()) _walk(child) + # Re-layout each container (not just the top window) so labels are + # repositioned (e.g. recentered) to the current container size. + if parent.GetSizer() is not None: + parent.Layout() _walk(window) - window.Layout() + + +def refit_label(static_text): + """Resize a StaticText to its current text and re-center it. + + A variable-length label keeps a min size pinned to an earlier value, which + mis-centers the control once the text changes. Reset it to the current text + and relayout the parent. + """ + static_text.InvalidateBestSize() + static_text.SetMinSize(static_text.GetBestSize()) + parent = static_text.GetParent() + if parent is not None: + parent.Layout() + def make_path(path, from_file=False, verbose=False): """ From 219052fd1da4cd575b10c41c66ea7c9051140ced Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Tue, 16 Jun 2026 12:34:55 -0400 Subject: [PATCH 100/139] Let gain breathe a little --- src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py index 7af9faf..21a7cb9 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py @@ -371,7 +371,7 @@ def format_status( drop_str = "{} dropped".format(num_dropped) else: drop_str = "{:.0e} dropped".format(num_dropped) - gain_str = "Gain:?" if gain is None else "Gain:{}".format(gain) + gain_str = "Gain: ?" if gain is None else "Gain: {}".format(gain) fps_str = "? fps" if fps is None else "{:4.2f} fps".format(fps) if total is not None and processed is not None: # display N/N, even if internally it's N-1/N From 6c874711fd6a077a1c516e14314afed049ae2441 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 12:51:59 -0400 Subject: [PATCH 101/139] Update some necessary defaults --- src/cfg/nayak/default_system_state.json | 2 +- src/cfg/taiga/default_system_state.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cfg/nayak/default_system_state.json b/src/cfg/nayak/default_system_state.json index 6b251a1..8ad568d 100644 --- a/src/cfg/nayak/default_system_state.json +++ b/src/cfg/nayak/default_system_state.json @@ -131,6 +131,7 @@ "trigger_freq": 1.0, "turn_off_nuc_in_shapefile": 1, "use_archive_region": 0, + "use_nvjpeg": 1, "use_p1jpeg": 0 }, "base": "/mnt/data", @@ -651,7 +652,6 @@ } } }, - "load_shapefile": 0, "local_ssd_mnt": "/mnt/data", "locations": { "center": { diff --git a/src/cfg/taiga/default_system_state.json b/src/cfg/taiga/default_system_state.json index 4c69be1..66db163 100755 --- a/src/cfg/taiga/default_system_state.json +++ b/src/cfg/taiga/default_system_state.json @@ -32,6 +32,7 @@ "jpg": { "quality": 95 }, + "load_shapefile": 0, "max_exposure_ms": 120, "max_fps": 2.5, "max_frame_rate": 2.0, @@ -45,6 +46,7 @@ "trigger_freq": 1, "turn_off_nuc_in_shapefile": 1, "use_archive_region": 0, + "use_nvjpeg": 1, "use_p1jpeg": 0 }, "base": "/mnt/data", @@ -360,7 +362,6 @@ } } }, - "load_shapefile": 0, "local_ssd_mnt": "/mnt/data", "locations": { "center": { From 242f7fa947cc7e40a616942420b6b8136b6d0af4 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 12:54:27 -0400 Subject: [PATCH 102/139] Grey out contrast control, as server uses it --- .../wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py index b1b56db..1cfde7e 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/ImageInspectionFrame.py @@ -38,6 +38,11 @@ def __init__(self, parent, topic_names, ir_contrast_strength = SYS_CFG["ir_contrast_strength"] self.ir_contrast_strength_txt_ctrl.SetValue(str(ir_contrast_strength)) + # The server applies a fixed detector-matching IR stretch and ignores + # contrast_strength, so grey out this control to avoid misleading. + self.ir_contrast_strength_txt_ctrl.Disable() + self.m_staticText71.Disable() + self.m_staticText71.SetLabel("IR Contrast Stretch Strength (n/a)") for i in range(self.image_stream_combo_box.GetCount()): if stream == self.image_stream_combo_box.GetString(i): From bf78ceb1fba1b7c0573792cf6aaf0acab52584e8 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 13:00:14 -0400 Subject: [PATCH 103/139] Fix startup spacing --- .../wxpython_gui/src/wxpython_gui/SystemStartup.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemStartup.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemStartup.py index b4434a9..f4283ef 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemStartup.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemStartup.py @@ -10,8 +10,6 @@ def __init__(self, parent, system): """ # Initialize parent class form_builder_output_system_startup.MainFrame.__init__(self, parent) - # Recompute enlarged title fonts so they are not clipped under Phoenix. - wx.CallAfter(unclip_static_text, self) # Store the function that allow us to send logging requests. self.add_to_event_log = parent.add_to_event_log @@ -19,6 +17,13 @@ def __init__(self, parent, system): self.hosts = system.scc.hosts self.Show() + # Unclip enlarged fonts (Phoenix), then grow the frame to fit all + # controls so the buttons don't overlap. + wx.CallAfter(self._finalize_layout) + + def _finalize_layout(self): + unclip_static_text(self) + self.Fit() self.SetMinSize(self.GetSize()) # -------------------------- All self.systems Commands ------------------------ From fecc1b508dbbc3054d0dae912cbb82f06d7e1f94 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 13:21:57 -0400 Subject: [PATCH 104/139] Shrink observer box, minimize prints --- .../form_builder_output.py | 5 +++- .../wxpython_gui/system_control_panel/gui.fbp | 23 +++++++++++++++++-- .../wxpython_gui/system_control_panel/gui.py | 3 --- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index 6a3677d..1ef09db 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -438,7 +438,10 @@ def __init__( self, parent ): bSizer451.Add( self.m_staticText331, 0, wx.RIGHT|wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5 ) self.observer_text_ctrl = wx.TextCtrl( self.flight_data_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - bSizer451.Add( self.observer_text_ctrl, 1, wx.RIGHT|wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5 ) + observer_box = wx.BoxSizer(wx.HORIZONTAL) + observer_box.Add(self.observer_text_ctrl, 1, wx.EXPAND) + bSizer451.Add(observer_box, 1, wx.EXPAND, 5) + bSizer451.AddStretchSpacer(2) bSizer42.Add( bSizer451, 1, wx.EXPAND, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.fbp b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.fbp index cca8a56..318df7b 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.fbp +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.fbp @@ -5447,9 +5447,18 @@ 5 - wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL + wxEXPAND 1 - + + + bSizer_observer_box + wxHORIZONTAL + none + + 0 + wxEXPAND + 1 + 1 1 1 @@ -5538,6 +5547,16 @@ + + 0 + wxEXPAND + 2 + + 0 + protected + 0 + + diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 0be4455..9e47a02 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -1020,7 +1020,6 @@ def on_slow_timer(self, event): status = detector_state.decide_status(host, desired) d_desired[host] = desired d_status[host] = status - print(status) if status is EPodStatus.Unknown: text_attr.SetForegroundColour(WTF_PURPLE) elif status is EPodStatus.Pending: @@ -1032,8 +1031,6 @@ def on_slow_timer(self, event): else: text_attr.SetForegroundColour(ERROR_RED) - print(d_status.values()) - active_statuses = [ status for status in d_status.values() if status is not EPodStatus.Unknown From f82db30e5173b1fe89b57c0ab0efd82fc0296132 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 13:30:08 -0400 Subject: [PATCH 105/139] Some minor GUI adjustments --- .../form_builder_output.py | 33 ++++++++++--------- .../wxpython_gui/system_control_panel/gui.fbp | 27 +++------------ .../wxpython_gui/system_control_panel/gui.py | 2 +- 3 files changed, 22 insertions(+), 40 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index 1ef09db..e8eac75 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -438,13 +438,11 @@ def __init__( self, parent ): bSizer451.Add( self.m_staticText331, 0, wx.RIGHT|wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5 ) self.observer_text_ctrl = wx.TextCtrl( self.flight_data_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - observer_box = wx.BoxSizer(wx.HORIZONTAL) - observer_box.Add(self.observer_text_ctrl, 1, wx.EXPAND) - bSizer451.Add(observer_box, 1, wx.EXPAND, 5) - bSizer451.AddStretchSpacer(2) + self.observer_text_ctrl.SetMinSize(self.flight_number_text_ctrl.GetBestSize()) + bSizer451.Add( self.observer_text_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - bSizer42.Add( bSizer451, 1, wx.EXPAND, 5 ) + bSizer42.Add( bSizer451, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, 5 ) bSizer41.Add( bSizer42, 1, wx.EXPAND, 5 ) @@ -499,16 +497,6 @@ def __init__( self, parent ): bSizer391.Add( bSizer443, 0, wx.EXPAND, 5 ) - self.m_staticline13 = wx.StaticLine( self.flight_data_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - bSizer391.Add( self.m_staticline13, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) - - self.nas_disk_space = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"NAS Disk Space: ?", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.nas_disk_space.Wrap( -1 ) - self.nas_disk_space.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - - bSizer391.Add( self.nas_disk_space, 0, wx.TOP|wx.RIGHT|wx.LEFT|wx.ALIGN_CENTER_HORIZONTAL, 3 ) - - self.flight_data_panel.SetSizer( bSizer391 ) self.flight_data_panel.Layout() bSizer391.Fit( self.flight_data_panel ) @@ -525,8 +513,21 @@ def __init__( self, parent ): self.m_staticline_close = wx.StaticLine( self.m_panel7, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) bSizer17.Add( self.m_staticline_close, 0, wx.EXPAND, 0 ) + bSizer17_footer = wx.BoxSizer( wx.HORIZONTAL ) + self.close_button = wx.Button( self.m_panel7, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.Size( -1,-1 ), 0 ) - bSizer17.Add( self.close_button, 0, wx.ALL|wx.ALIGN_LEFT, 3 ) + bSizer17_footer.Add( self.close_button, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 3 ) + + self.nas_close_divider = wx.StaticLine( self.m_panel7, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_VERTICAL ) + bSizer17_footer.Add( self.nas_close_divider, 0, wx.EXPAND|wx.TOP|wx.BOTTOM|wx.LEFT|wx.RIGHT, 8 ) + + self.nas_disk_space = wx.StaticText( self.m_panel7, wx.ID_ANY, u"NAS Space: ?", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.nas_disk_space.Wrap( -1 ) + self.nas_disk_space.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) + + bSizer17_footer.Add( self.nas_disk_space, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 3 ) + + bSizer17.Add( bSizer17_footer, 0, wx.EXPAND, 0 ) self.m_panel7.SetSizer( bSizer17 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.fbp b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.fbp index 318df7b..2ba4e1a 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.fbp +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.fbp @@ -5447,18 +5447,9 @@ 5 - wxEXPAND - 1 - - - bSizer_observer_box - wxHORIZONTAL - none - - 0 - wxEXPAND - 1 - + wxALIGN_CENTER_VERTICAL|wxRIGHT + 0 + 1 1 1 @@ -5547,16 +5538,6 @@ - - 0 - wxEXPAND - 2 - - 0 - protected - 0 - - @@ -6582,7 +6563,7 @@ 0 0 wxID_ANY - NAS Disk Space: ? + NAS Space: ? 0 diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 9e47a02..02bc6b7 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -695,7 +695,7 @@ def _apply_system_sanity(self, results, nas_unmounts): # The NAS is shared, so it's only displayed once (center host). if fov == "center" and entry["nas_gb"] is not None: self.nas_disk_space.SetLabel( - "NAS Disk Space: %0.2f GB" % entry["nas_gb"] + "NAS Space: %0.2f GB" % entry["nas_gb"] ) self.nas_disk_space.SetForegroundColour(COLLECT_GREEN) gui_utils.refit_label(self.nas_disk_space) From e4bde081bd00420909752fb6928fc00068f1a369 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 13:39:26 -0400 Subject: [PATCH 106/139] Update some defaults, add warning if no pipefile --- src/cfg/nayak/config.yaml | 2 +- src/cfg/nayak/default_system_state.json | 2 +- src/cfg/taiga/config.yaml | 2 +- src/cfg/taiga/default_system_state.json | 2 +- .../src/wxpython_gui/system_control_panel/gui.py | 11 ++++++++++- tmux/uas/default_params.conf | 2 +- 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/cfg/nayak/config.yaml b/src/cfg/nayak/config.yaml index b0ed79a..0d9e6ec 100644 --- a/src/cfg/nayak/config.yaml +++ b/src/cfg/nayak/config.yaml @@ -23,7 +23,7 @@ arch: min_frame_rate: 0.1 base_template: "{base}/{project}/fl{flight}/{sys_cfg}/" template: "{base}/{project}/fl{flight}/{sys_cfg}/{cam_fov}_view/{project}_fl{flight}_{cf}_{time}_{mode}.{ext}" - max_exposure_ms: 100 + max_exposure_ms: 125 ext_rgb: jpg ext_uv: jpg ext_ir: tif diff --git a/src/cfg/nayak/default_system_state.json b/src/cfg/nayak/default_system_state.json index 8ad568d..4569094 100644 --- a/src/cfg/nayak/default_system_state.json +++ b/src/cfg/nayak/default_system_state.json @@ -115,7 +115,7 @@ }, "kamera_dir": "/home/user/kw/kamera", "load_shapefile": 0, - "max_exposure_ms": 120, + "max_exposure_ms": 125, "max_fps": 2.5, "max_frame_rate": 2.0, "min_fps": 0.1, diff --git a/src/cfg/taiga/config.yaml b/src/cfg/taiga/config.yaml index 4ccce14..a02b2f1 100644 --- a/src/cfg/taiga/config.yaml +++ b/src/cfg/taiga/config.yaml @@ -23,7 +23,7 @@ arch: min_frame_rate: 0.1 base_template: "{base}/{project}/fl{flight}/{sys_cfg}/" template: "{base}/{project}/fl{flight}/{sys_cfg}/{cam_fov}_view/{project}_fl{flight}_{cf}_{time}_{mode}.{ext}" - max_exposure_ms: 100 + max_exposure_ms: 125 ext_rgb: jpg ext_uv: jpg ext_ir: tif diff --git a/src/cfg/taiga/default_system_state.json b/src/cfg/taiga/default_system_state.json index 66db163..8905ae7 100755 --- a/src/cfg/taiga/default_system_state.json +++ b/src/cfg/taiga/default_system_state.json @@ -33,7 +33,7 @@ "quality": 95 }, "load_shapefile": 0, - "max_exposure_ms": 120, + "max_exposure_ms": 125, "max_fps": 2.5, "max_frame_rate": 2.0, "min_fps": 0.1, diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 02bc6b7..76e155c 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -1876,7 +1876,16 @@ def update_show_hide(self): def do_start_a_detector(self, event=None, host="unset", log=True): cmdpipef = SYS_CFG[host]["detector"]["pipefile"] - cmdpipef = SYS_CFG[host]["detector"]["pipefile"] + if not cmdpipef: + msg = ( + "No detector pipefile configured for %s; " + "select a camera configuration with a detector model." + % host + ) + dlg = wx.MessageDialog(self, msg, "Error", wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return if not os.path.exists(cmdpipef): msg = ( "Pipefile for detector %s does not exist, not starting detector." % host diff --git a/tmux/uas/default_params.conf b/tmux/uas/default_params.conf index c3760eb..2e4ff4e 100644 --- a/tmux/uas/default_params.conf +++ b/tmux/uas/default_params.conf @@ -1,7 +1,7 @@ /sys/arch/rgb_vfov 14 /sys/arch/min_fps 0.1 /sys/arch/max_fps 2.5 -/sys/arch/max_exposure_ms 120 +/sys/arch/max_exposure_ms 125 /sys/arch/turn_off_nuc_in_shapefile 1 /sys/arch/archive_all_ir_images 0 /sys/arch/base /mnt/flight_data From 295874897c3e34e6808aa847d4b6ba7487574d22 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 13:44:06 -0400 Subject: [PATCH 107/139] Make pipefile loading a little more robust --- .../wxpython_gui/system_control_panel/gui.py | 54 ++++++++++++++++--- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 76e155c..dc1302d 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -1874,8 +1874,48 @@ def update_show_hide(self): # ------------------------------------------------------------------------ # ---------------------------- Detection Menu ---------------------------- + def _valid_detector_pipe(self, pipe): + return pipe and pipe != "null" + + def apply_detector_pipefiles(self, sys_cfg_name=None): + """Sync per-host detector pipefiles from the active camera configuration.""" + if sys_cfg_name is None: + sys_cfg_name = self.get_sys_cfg() + try: + cc = SYS_CFG["camera_cfgs"][sys_cfg_name] + except KeyError: + return + fov_pipes = { + "center": cc.get("center_sys_pipe"), + "left": cc.get("left_sys_pipe"), + "right": cc.get("right_sys_pipe"), + } + for host in self.hosts: + fov = SYS_CFG["arch"]["hosts"][host]["fov"] + pipe = fov_pipes.get(fov) + if self._valid_detector_pipe(pipe): + SYS_CFG[host]["detector"]["pipefile"] = pipe + else: + SYS_CFG[host]["detector"]["pipefile"] = None + + def resolve_detector_pipefile(self, host): + """Return the detector pipefile for a host, using camera config if needed.""" + pipe = SYS_CFG[host]["detector"].get("pipefile") + if self._valid_detector_pipe(pipe): + return pipe + try: + cc = SYS_CFG["camera_cfgs"][self.get_sys_cfg()] + fov = SYS_CFG["arch"]["hosts"][host]["fov"] + pipe = cc.get("{}_sys_pipe".format(fov)) + except KeyError: + return None + if self._valid_detector_pipe(pipe): + SYS_CFG[host]["detector"]["pipefile"] = pipe + return pipe + return None + def do_start_a_detector(self, event=None, host="unset", log=True): - cmdpipef = SYS_CFG[host]["detector"]["pipefile"] + cmdpipef = self.resolve_detector_pipefile(host) if not cmdpipef: msg = ( "No detector pipefile configured for %s; " @@ -2165,6 +2205,8 @@ def set_camera_config_dict(self, config_dict=None): self.camera_config_combo.SetSelection(0) SYS_CFG["arch"]["sys_cfg"] = self.camera_config_combo.GetStringSelection() + self.apply_detector_pipefiles() + def next_camera_config(self, event=None): ind = self.camera_config_combo.GetSelection() if ind == wx.NOT_FOUND: @@ -2176,6 +2218,7 @@ def next_camera_config(self, event=None): ind = 0 self.camera_config_combo.SetSelection(ind) + self.apply_detector_pipefiles() def previous_camera_config(self, event=None): ind = self.camera_config_combo.GetSelection() @@ -2188,6 +2231,7 @@ def previous_camera_config(self, event=None): ind = self.camera_config_combo.GetCount() - 1 self.camera_config_combo.SetSelection(ind) + self.apply_detector_pipefiles() def on_camera_config_combo(self, event=None): """ """ @@ -2200,13 +2244,7 @@ def on_camera_config_combo(self, event=None): SYS_CFG["rgb_vfov"] = vfov save_camera_config(curr_str) self.update_project_flight_params() - - if cc["center_sys_pipe"] != "null": - SYS_CFG[self.hosts[0]]["detector"]["pipefile"] = cc["center_sys_pipe"] - if cc["left_sys_pipe"] != "null": - SYS_CFG[self.hosts[1]]["detector"]["pipefile"] = cc["left_sys_pipe"] - if cc["right_sys_pipe"] != "null": - SYS_CFG[self.hosts[2]]["detector"]["pipefile"] = cc["right_sys_pipe"] + self.apply_detector_pipefiles(curr_str) # ------------------------- END Camera Configuration ------------------------- From 66d837edbc8d3dde723fa63af3db15e636778cc6 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 13:49:11 -0400 Subject: [PATCH 108/139] More robust host filtering for detectors --- .../wxpython_gui/src/wxpython_gui/SystemCommands.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemCommands.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemCommands.py index aa604b2..0af192b 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemCommands.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/SystemCommands.py @@ -1,4 +1,5 @@ -from wxpython_gui.cfg import kv, DOCK_KAM_REPO_DIR, REAL_KAM_REPO_DIR +from wxpython_gui.cfg import kv, DOCK_KAM_REPO_DIR, REAL_KAM_REPO_DIR, system_name +from roskv.util import filter_hosts_by_system import time import xmlrpc.client as xmlrpclib @@ -9,8 +10,10 @@ class SystemCommandsCall(object): """ def __init__(self, hosts): - self.hosts = hosts - self.process_group = "taiga" if "nuvo0" in hosts else "nayak" + if isinstance(hosts, dict): + hosts = list(hosts.keys()) + self.hosts = filter_hosts_by_system(hosts) + self.process_group = system_name self.supers = { host: xmlrpclib.Server("http://%s:9001/RPC2" % host) for host in self.hosts } From b9dfeafe7812f0c116c1a22b76f53d58e638220a Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 13:54:00 -0400 Subject: [PATCH 109/139] Don't try to copy perms to avoid NAS noise in copy --- src/kitware-ros-pkg/image_manager/image_manager.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/kitware-ros-pkg/image_manager/image_manager.py b/src/kitware-ros-pkg/image_manager/image_manager.py index f04786a..0c5a4ef 100755 --- a/src/kitware-ros-pkg/image_manager/image_manager.py +++ b/src/kitware-ros-pkg/image_manager/image_manager.py @@ -377,7 +377,9 @@ def copy_files(self): print("Number of files to copy: %s" % len(imgs_to_copy)) csz = 10000 for chunk in chunker(list(imgs_to_copy), csz): - rsync_bash = ["rsync", "-a"] + # -a implies -o/-g (preserve owner/group), which require root to + # chown; the NAS mount rejects that, so skip owner/group. + rsync_bash = ["rsync", "-a", "--no-owner", "--no-group"] rsync_bash += chunk rsync_bash += [secondary_image_dir] print("Running rsync on chunk...") From 4c3a2bccbbeba7104a1cac800540163cf1f1adca Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 13:59:09 -0400 Subject: [PATCH 110/139] We don't use that image manager, change the data migration script --- .../image_manager/image_manager.py | 448 ------------------ .../image_manager/image_queue.py | 156 ------ src/run_scripts/entry/data_migration.sh | 6 +- 3 files changed, 3 insertions(+), 607 deletions(-) delete mode 100755 src/kitware-ros-pkg/image_manager/image_manager.py delete mode 100644 src/kitware-ros-pkg/image_manager/image_queue.py diff --git a/src/kitware-ros-pkg/image_manager/image_manager.py b/src/kitware-ros-pkg/image_manager/image_manager.py deleted file mode 100755 index 0c5a4ef..0000000 --- a/src/kitware-ros-pkg/image_manager/image_manager.py +++ /dev/null @@ -1,448 +0,0 @@ -import os -import shutil -import glob -import socket -import re -import time -import threading -import datetime -import errno -import psutil -import subprocess -from pathlib import Path - -import image_queue -from roskv.impl.redis_envoy import RedisEnvoy - - -hostname = socket.gethostname() -redis_host = os.environ.get('REDIS_HOST', 'nuvo0') -envoy = RedisEnvoy(redis_host, client_name='image_manager') - -def chunker(seq, size): - return (seq[pos:pos + size] for pos in range(0, len(seq), size)) - -# Ported over from GUI to maintain parity in filepaths -PAT_BRACED = re.compile(r'\{(\w+)\}') -def get_template_keys(tmpl): - return re.findall(PAT_BRACED, tmpl) - -def conformKwargsToFormatter(tmpl, kwargs): - # type: (str, dict) -> dict - required_keys = set(get_template_keys(tmpl)) - missing_keys = required_keys.difference(kwargs) - fmt_dict = {k:v for k,v in kwargs.items() if k in required_keys} - fmt_dict.update({k:'({})'.format(k) for k in missing_keys}) - return fmt_dict - -def get_arch_path(**kwargs): - arch_dict = envoy.get("/sys/arch") - tmpl = arch_dict['base_template'] - # Offer manual override - for k,v in kwargs.items(): - arch_dict[k] = v - fmt_dict = conformKwargsToFormatter(tmpl, arch_dict) - return tmpl.format(**fmt_dict) - - -class ImageManager(object): - def __init__(self): - self.lock = threading.Lock() - self._image_exts = ['jpg', 'tif', 'json'] - self.modalities = ['rgb', 'ir', 'uv', 'meta'] - self.modality2ext = {'rgb':'jpg', 'ir':'tif', 'uv':'jpg', 'meta':'json'} - self._effort = envoy.get("/sys/arch/effort") - self._wait_time_sec = int(envoy.get("/sys/effort_metadata_dict/%s/wait_time_sec" % self._effort)) - self._delete_old_images_sec = int(envoy.get("/sys/effort_metadata_dict/%s/delete_old_images_sec" % self._effort)) - self._save_every_x_image = int(envoy.get("/sys/effort_metadata_dict/%s/save_every_x_image" % self._effort)) - self._log_file = '/root/kamera_ws/image_manager.log' - self._image_dir = "" - self._secondary_image_dir = "" - self._detection_dir = "" - self._secondary_detection_dir = "" - - self.frame_index = 0 - self.dets = set() - self.processed = set() - self.modulo_n = set() - self.previous_imgs_copied = set() - self.stop_threads = False - self.previous_detection_dir = "" - self.thread = None - - @property - def effort(self): - try: - self._effort = envoy.get("/sys/arch/effort") - except: - self._effort = "ON" - return self._effort - - @property - def wait_time_sec(self): - try: - self._wait_time_sec = int(envoy.get( - "/sys/effort_metadata_dict/%s/wait_time_sec" - % self.effort)) - except Exception as e: - self._wait_time_sec = 60 - return self._wait_time_sec - - @property - def delete_old_images_sec(self): - try: - self._delete_old_images_sec = int(envoy.get( - "/sys/effort_metadata_dict/%s/delete_old_images_sec" - % self.effort)) - except Exception as e: - self._delete_old_images_sec = 60 - return self._delete_old_images_sec - - @property - def save_every_x_image(self): - try: - self._save_every_x_image = int(envoy.get( - "/sys/effort_metadata_dict/%s/save_every_x_image" - % self.effort)) - except: - # Default to save every image - self._save_every_x_image = 1 - return self._save_every_x_image - - @property - def image_dir(self): - primary_storage = envoy.get("/sys/local_ssd_mnt") - syscfg_dir = get_arch_path(base=primary_storage) - view = envoy.get("/sys/arch/hosts/%s/fov" % hostname) + "_view" - self._image_dir = os.path.join(syscfg_dir, view) - return self._image_dir - - @property - def secondary_image_dir(self): - secondary_storage = envoy.get("/sys/nas_mnt") - syscfg_dir = get_arch_path(base=secondary_storage) - view = envoy.get("/sys/arch/hosts/%s/fov" % hostname) + "_view" - self._secondary_image_dir = os.path.join(syscfg_dir, view) - return self._secondary_image_dir - - @property - def flight_dir(self): - d = os.path.dirname(os.path.dirname(self.image_dir)) - return d - - @property - def secondary_flight_dir(self): - d = os.path.dirname(os.path.dirname(self.secondary_image_dir)) - return d - - @property - def detection_dir(self): - d = os.path.dirname(os.path.dirname(self.image_dir)) - self._detection_dir = os.path.join(d, "detections") - return self._detection_dir - - @property - def secondary_detection_dir(self): - d = os.path.dirname(os.path.dirname(self.secondary_image_dir)) - self._secondary_detection_dir = os.path.join(d, "detections") - return self._secondary_detection_dir - - def get_file_name_parts(self, full_filename): - name, us, ext = full_filename.split("/")[-1].split(".") - fname = name + "." + us - folder = os.path.dirname(full_filename) - bname = fname.split("_")[0:-1] - bname = "_".join(bname) - ftype = fname.split("_")[-1] - return (folder, fname, bname, ext, ftype) - - def watch_files(self, files): - print("Opening files.") - open_files = [] - last_name = "" - for f in files: - open_files.append(open(f, "r")) - while not self.stop_threads: - if not self.lock.locked(): - self.lock.acquire() - det_files = glob.glob(self.detection_dir + "/*.csv") - det_files += glob.glob(self.detection_dir + "/*.txt") - for f1 in det_files: - if f1 not in files: - open_files.append(open(f1, "r")) - files.append(f1) - empty = 0 - for i, file in enumerate(open_files): - line = file.readline() - if not line: - empty += 1 - continue - if ".csv" in files[i]: - if len(line) < 1 or line[0] == "#": - continue - fullname = line.split(',')[1].strip() - folder, fname, bname, ext, ftype = self.get_file_name_parts( - fullname) - self.dets.add(bname) - elif ".txt" in files[i]: - fullname = line.strip() - folder, fname, bname, ext, ftype = self.get_file_name_parts( - fullname) - if bname not in self.processed and bname not in self.modulo_n: - self.frame_index += 1 - if (self.frame_index % self.save_every_x_image) != 0: - # Only add to processed if not part of the nth - self.processed.add(bname) - try: - # Reconsider these images again since they've - # now been detected on, possible they'll - # get deleted - self.previous_imgs_copied.remove(fullname) - except KeyError: - pass - else: - self.modulo_n.add(bname) - # If all files were empty, sleep a bit - if empty == len(open_files): - # Only release when files have been read - if self.lock.locked(): - self.lock.release() - time.sleep(0.5) - - print("Closing files") - for f in open_files: - f.close() - - def copy_files(self): - continue_looping = True - os.umask(0) - - print("Wait time in seconds: %s" % self.wait_time_sec) - print("Delete old images time in seconds: %s" % self.delete_old_images_sec) - print("Save every x image: %s" % self.save_every_x_image) - print("Image dir: %s" % self.image_dir) - print("Secondary image dir: %s" % self.secondary_image_dir) - print("Detection dir: %s" % self.detection_dir) - print("Secondary detection dir: %s" % self.secondary_detection_dir) - - while continue_looping: - if not os.path.exists("/mnt/flight_data/.flight_data_mounted"): - raise SystemError("NAS not mounted! Skipping.") - image_dir = self.image_dir - detection_dir = self.detection_dir - secondary_image_dir = self.secondary_image_dir - secondary_detection_dir = self.secondary_detection_dir - to_copy = set() - imgs_to_copy = set() - det_files = glob.glob(self.detection_dir + "/*.csv") - det_files += glob.glob(self.detection_dir + "/*.txt") - # Copy over log file too - log_files = glob.glob(self.flight_dir+ "/*.txt") - if detection_dir != self.previous_detection_dir: - with self.lock: - self.stop_threads = True - if self.thread is not None: - self.thread.join() - self.dets.clear() - self.processed.clear() - self.modulo_n.clear() - self.previous_imgs_copied.clear() - self.stop_threads = False - self.thread = threading.Thread(target=self.watch_files, - args=(det_files,)) - self.thread.daemon = True - # Start filling up dets from csvs - print("Pulling from detection files...") - self.thread.start() - time.sleep(1) - with self.lock: - ims = len(self.processed) - print("Number of images detected on: %s" % ims) - print("Number of detections %s." % len(self.dets)) - # Always place detection files in queue since they - # are constantly being written to - [ to_copy.add(det) for det in det_files ] - [ to_copy.add(lf) for lf in log_files ] - self.previous_detection_dir = detection_dir - try: - os.makedirs(secondary_image_dir, 0o777) - except (OSError, IOError) as exception: - if exception.errno != errno.EEXIST: - raise - print("Checking dir: %s" % image_dir) - # get the current image files - impath = Path(image_dir) - images = list(impath.glob("*")) - images = set([str(im) for im in images]) - print("Images globbed.") - # Only consider images that haven't been copied yet - with self.lock: - noncopied_images = list(images.difference( - self.previous_imgs_copied)) - - if len(noncopied_images) > 0: - # We have to copy/delete these still, so mark as processing - envoy.put("/stat/image_manager/processing", 1) - else: - envoy.put("/stat/image_manager/processing", 0) - - # add them to the image queue - try: - os.makedirs(secondary_detection_dir, 0o777) - except (OSError, IOError) as exception: - if exception.errno != errno.EEXIST: - raise - - # remove files from the list that are not older than the wait time - noncopied_paths = [Path(f) for f in noncopied_images] - present = time.time() - process_time = present - self.wait_time_sec - # only look at files if they are older than n seconds - files_to_process = sorted([ p for p in noncopied_paths - if p.stat().st_mtime - process_time < 0 ]) - print(f"files left = %s" % len(files_to_process)) - - # loop through the files and see if we need to copy/delete - to_touch = set() - last_saved_index = 0 - last_name = "" - print("Images queued.") - for img in files_to_process: - mtime = img.stat().st_mtime - fullname = str(img.resolve()) - # get the name without the extension and ir/uv/rgb component - folder, fname, bname, ext, ftype = self.get_file_name_parts\ - (fullname) - #print(bname + "." + ext + " from " + folder + " type " + ftype) - - # see if we have a match with the detections - with self.lock: - if bname in list(self.dets): - #print("Added because it has a detection.") - imgs_to_copy.add(fullname) - continue - - # If we've waited the minimum amount of time and no - # detection has been generated, copy over as well. - with self.lock: - # If modified time is older than current, copy - if bname in self.processed and ext != "json": - #print("Adding %s to touch." % bname) - # if we made it here then this needs to be deleted - # this means this image is not amongst - # those being copied over. Leave meta.json alone - to_touch.add(fullname) - else: - #print("Added because it hasn't been detected on in too long," - # " or is part of modulo N.") - imgs_to_copy.add(fullname) - - # For files that are not copied over, we will create a dummy file - # so we can still generate the gis footprint. - print("Number of files to touch : %s" % len(to_touch)) - for fname in list(to_touch): - fnamebase = os.path.basename(fname) - new_file = os.path.join(secondary_image_dir, fnamebase) - try: - if os.path.exists(new_file): - # If it exists on remote, delete first, then touch - os.remove(new_file) - Path(new_file).touch() - except Exception as e: - print(e) - - # copy files - for cfile in list(to_copy): - bname = cfile.split("/")[-1] - if ".csv" in bname or ".txt" in bname: - if "log" in bname: - new_file = os.path.join( - self.secondary_flight_dir, bname) - else: - new_file = os.path.join(secondary_detection_dir, bname) - else: - new_file = os.path.join(secondary_image_dir, bname) - try: - # Only copy file if modification times differ - if os.path.exists(new_file): - if (os.stat(cfile).st_mtime - os.stat(new_file).st_mtime) > 0: - shutil.copy2(cfile, new_file) - else: - print("File exists with the same modification time!") - else: - shutil.copy2(cfile, new_file) - except (IOError, OSError) as e: - print(f"Error: {e.filename}, {e.strerror}") - continue - print("Number of files to copy: %s" % len(imgs_to_copy)) - csz = 10000 - for chunk in chunker(list(imgs_to_copy), csz): - # -a implies -o/-g (preserve owner/group), which require root to - # chown; the NAS mount rejects that, so skip owner/group. - rsync_bash = ["rsync", "-a", "--no-owner", "--no-group"] - rsync_bash += chunk - rsync_bash += [secondary_image_dir] - print("Running rsync on chunk...") - try: - subprocess.run(rsync_bash) - except subprocess.CalledProcessError as e: - print("Subprocess call failed.") - print(e) - print("Finished rsync!") - # Keeps a rolling window of what's been copied but not what's - # been deleted - with self.lock: - self.previous_imgs_copied = (self.previous_imgs_copied.union( - imgs_to_copy).union(to_touch)).intersection(images) - print("Length of prev copied; %s" % len(self.previous_imgs_copied)) - - present = time.time() - old_time = present - self.delete_old_images_sec - with self.lock: - sorted_previous_imgs = sorted(self.previous_imgs_copied) - for fp in sorted_previous_imgs: - # If it's been copied, and older than time, delete - img = Path(fp) - mtime = img.stat().st_mtime - if mtime < old_time: - folder, fname, bname, ext, ftype = self.get_file_name_parts\ - (fp) - fpbase = os.path.basename(fp) - mntfname = os.path.join(secondary_image_dir, fpbase) - # Confirm file was copied before removing, else try to - # copy again - if os.path.exists(mntfname): - try: - os.remove(fp) - except Exception as e: - print(f"Error: {e.filename}, {e.strerror}") - try: - self.processed.remove(bname) - except Exception as e: - pass - try: - self.dets.remove(bname) - except Exception as e: - pass - try: - self.modulo_n.remove(fp) - except Exception as e: - pass - else: - with self.lock: - # Add image back to retry copy - self.previous_imgs_copied.remove(fp) - else: - # Since we're sorted, break upon finding a file newer than - # parameter - break - time.sleep(1) - - -if __name__ == "__main__": - im = ImageManager() - im.copy_files() - # save the log from the image queue - #with open(_log_file, 'w') as jfile: - # jfile.write(js) - # end while diff --git a/src/kitware-ros-pkg/image_manager/image_queue.py b/src/kitware-ros-pkg/image_manager/image_queue.py deleted file mode 100644 index f151cb7..0000000 --- a/src/kitware-ros-pkg/image_manager/image_queue.py +++ /dev/null @@ -1,156 +0,0 @@ -# a basic state machine to handle the queue of images -import sys -import datetime -import json - -class States(): - new_image = "new_image" - processing = "processing" - deleted = "deleted" - copied = "copied" - - -class Image_State(): - name = "" - state = None - init_time = None - changed_time = None - detection = None - time_format = '%Y%m%d_%H%M%S_%f' - def __init__(self, name): - self.name = name - self.state = States.new_image # default state - self.init_time = self.getTime() - self.changed_time = None - self.detection = None - - def getTime(self): - dt = datetime.datetime.now() - return dt.strftime(self.time_format) - - # this checks that we have a state that is valid - def get_props(self, clss): - return [i for i in clss.__dict__.keys() if i[:1] != '_'] - - def change_state(self, newState): - try: - # make sure the state is valid - validProps = self.get_props(States) - if newState not in validProps: - print('Error in Image_State: state must be a valid member of States class.') - return - # make sure it isn't already there - if newState == self.state: - print('Error in Image_State: requested change in state, but it is already at: ' + str(self.state)) - return - - # finally, change the state - self.changed_time = self.getTime() - self.state = newState - except Exception as e: - exc_type, exc_obj, exc_tb = sys.exc_info() - print('error in changeState: ' + str(e) + ', line ' + str(exc_tb.tb_lineno) ) - - def set_detection(self, true_or_false): - self.detection = true_or_false - - def get_info(self): - info = self.name + "," - info += " init: " + str(self.init_time) + "," - info += " state: " + str(self.state) + "," - info += " changed: " + str(self.changed_time) - info += " detection: " + str(self.detection) - return info - - def get_dict(self): - js = {} - js["name"] = self.name - js["init_time"] = self.init_time - js["state"] = self.state - js["changed_time"] = self.changed_time - js["detection"] = self.detection - return js - - def get_json(self): - js = self.get_dict() - return json.dumps(js, sort_keys=True, indent=4) - - -class Image_Queue(): - images = [] - def __init__(self): - self.images = list() - - def get_names(self): - return [x.name for x in self.images] - - def get_new_files(self, files): - # check to see if we already have these files - prev_files = self.get_names() - for img in files: - if img in prev_files: - continue # skip files we already have - new_img = Image_State(img) - self.images.append(new_img) - - def get_list(self): - js = [] - for img in self.images: - js.append(img.get_dict()) - return js - - def get_json(self): - js = self.get_list() - return json.dumps(js, sort_keys=True, indent=4) - - def get_image_by_name(self, img_name): - im = None - for img in self.images: - if img_name == img.name: - im = img - break - - if im is None: - print(f"could not find file {img_name}") - return im - - def change_state(self, img_name, new_state): - im = self.get_image_by_name(img_name) - if im is None: - return - im.change_state(new_state) - - def set_detection(self, img_name, true_or_false): - im = self.get_image_by_name(img_name) - if im is None: - return - im.set_detection(true_or_false) - - -if __name__ == "__main__": - - # ------------ tests------------ - - # basic state tests - img = Image_State("file1.jpg") - print(f"{img.name} state = {img.state}, created = {img.init_time}") - print(img.get_info()) - img.change_state(States.deleted) - print(f"{img.name} state = {img.state}, changed = {img.changed_time}") - print(img.get_info()) - - print(img.get_json()) - - # basic image queue tests - iq = Image_Queue() - files = ["i1.jpg", "i2.jpg", "i3.jpg"] - iq.get_new_files(files) - print(iq.get_names()) - files = ["i1.jpg", "i4.jpg", "i5.jpg"] # 2 new files - one existing - iq.get_new_files(files) - print(iq.get_names()) # we should only see 5 here - - iq.change_state("i2.jpg", States.copied) - iq.set_detection("i1.jpg", False) - iq.set_detection("i2.jpg", True) - print(iq.get_json()) diff --git a/src/run_scripts/entry/data_migration.sh b/src/run_scripts/entry/data_migration.sh index ea27bd2..79dc4de 100755 --- a/src/run_scripts/entry/data_migration.sh +++ b/src/run_scripts/entry/data_migration.sh @@ -45,7 +45,7 @@ do # cap max argument length for rsync head -n 1000 | \ # copy all files removing source files on success - rsync -a --recursive --files-from=- --chmod=777 $source_dir $dest_dir + rsync -a --recursive --no-owner --no-group --files-from=- --chmod=777 $source_dir $dest_dir echo "Finished copying." # STAGE 2 @@ -59,7 +59,7 @@ do # cap max argument length for rsync head -n 1000 | \ # copy all files removing source files on success - rsync -a --recursive --remove-source-files --files-from=- --chmod=777 $source_dir $dest_dir + rsync -a --recursive --no-owner --no-group --remove-source-files --files-from=- --chmod=777 $source_dir $dest_dir echo "Finished copying and removing image files." # STAGE 3 @@ -72,7 +72,7 @@ do # cap max argument length for rsync head -n 1000 | \ # copy all files removing source files on success - rsync -a --recursive --remove-source-files --files-from=- --chmod=777 $source_dir $dest_dir + rsync -a --recursive --no-owner --no-group --remove-source-files --files-from=- --chmod=777 $source_dir $dest_dir echo "Finished removing text files." sleep 1 From 594a3d296edba4d95853de02afa3f6231c9eb434 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 14:07:17 -0400 Subject: [PATCH 111/139] More gui spacing --- .../form_builder_output.py | 10 ++++--- .../wxpython_gui/system_control_panel/gui.fbp | 26 ++++++++++++++----- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index e8eac75..d7a7063 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -258,6 +258,8 @@ def __init__( self, parent ): self.m_staticline5 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline5, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + m_staticText14211.Add( ( 0, 3 ), 0, 0, 0 ) + self.m_staticText42 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Auto Exposure (ms)", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText42.Wrap( -1 ) self.m_staticText42.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) @@ -288,7 +290,7 @@ def __init__( self, parent ): bSizer442.Add( self.exposure_max_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - m_staticText14211.Add( bSizer442, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) + m_staticText14211.Add( bSizer442, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.BOTTOM, 3 ) self.m_staticline51 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline51, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) @@ -323,7 +325,7 @@ def __init__( self, parent ): bSizer4421.Add( self.gain_max_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - m_staticText14211.Add( bSizer4421, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) + m_staticText14211.Add( bSizer4421, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.BOTTOM, 3 ) self.m_staticline52 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline52, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) @@ -350,12 +352,12 @@ def __init__( self, parent ): self.m_button10 = wx.Button( self.camera_panel, wx.ID_ANY, u"Set Camera Parameter", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_button10.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - m_staticText14211.Add( self.m_button10, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT, 3 ) + m_staticText14211.Add( self.m_button10, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT, 6 ) self.m_manual_ir_nuc = wx.Button( self.camera_panel, wx.ID_ANY, u"Manual IR NUC", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_manual_ir_nuc.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - m_staticText14211.Add( self.m_manual_ir_nuc, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT, 3 ) + m_staticText14211.Add( self.m_manual_ir_nuc, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT|wx.BOTTOM, 6 ) self.camera_panel.SetSizer( m_staticText14211 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.fbp b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.fbp index 2ba4e1a..5a0dde2 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.fbp +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.fbp @@ -2838,6 +2838,18 @@ + + 0 + + 0 + + 3 + + m_staticSpacerCameraSettings + none + 0 + + 5 wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxALIGN_CENTER_HORIZONTAL @@ -2922,8 +2934,8 @@ - 5 - wxALIGN_CENTER_HORIZONTAL + 3 + wxALIGN_CENTER_HORIZONTAL|wxBOTTOM 0 @@ -3455,8 +3467,8 @@ - 5 - wxALIGN_CENTER_HORIZONTAL + 3 + wxALIGN_CENTER_HORIZONTAL|wxBOTTOM 0 @@ -4101,7 +4113,7 @@ - 5 + 6 wxALIGN_CENTER_HORIZONTAL|wxTOP|wxRIGHT|wxLEFT 0 @@ -4189,8 +4201,8 @@ - 5 - wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT + 6 + wxALIGN_CENTER_HORIZONTAL|wxTOP|wxRIGHT|wxLEFT|wxBOTTOM 0 1 From e3f3cec0d171889200c7546954acd567497ed25d Mon Sep 17 00:00:00 2001 From: romleiaj Date: Tue, 16 Jun 2026 15:55:58 -0400 Subject: [PATCH 112/139] Add ansible for system stop / starts --- provision/ansible/playbooks/cas/provision.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/provision/ansible/playbooks/cas/provision.yml b/provision/ansible/playbooks/cas/provision.yml index 95af7ad..3b15169 100644 --- a/provision/ansible/playbooks/cas/provision.yml +++ b/provision/ansible/playbooks/cas/provision.yml @@ -34,6 +34,7 @@ 'ubuntu-drivers-common', # For hardware drivers 'python3-pip', # Pip goodness 'python3-redis', + 'ansible', # ansible-playbook for on-target provisioning ] pre_tasks: From dd72076e81c6de037b2026939df1f9aad60ac127 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 09:27:09 -0400 Subject: [PATCH 113/139] Add task to symlink nas to desktop (for convenience) --- provision/ansible/playbooks/cas/configure.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/provision/ansible/playbooks/cas/configure.yml b/provision/ansible/playbooks/cas/configure.yml index b7aaf2f..7a6ab33 100644 --- a/provision/ansible/playbooks/cas/configure.yml +++ b/provision/ansible/playbooks/cas/configure.yml @@ -208,9 +208,17 @@ dest: /home/user/.bash_aliases - name: Install start/stop desktop shortcuts - when: leader | default(false) + when: leader command: bash {{ kamera_dir }}/provision/start_stop/install_desktop_shortcuts.sh + - name: Symlink NAS mount to Desktop + when: leader + file: + src: "{{ data_dir }}" + dest: "/home/{{ ansible_user }}/Desktop/NAS" + state: link + force: true + - name: Disable sleep state on subsystems. become: True when: follower or leader or gui From ea95dc425b5a8d1c43f831dca824398fe03bde7f Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 09:32:25 -0400 Subject: [PATCH 114/139] Add power management to kamerad, adding supervisor tasks for startup / shutdown. Simplifies the system reboot --- compose/kamerad.yml | 4 + provision/start_stop/host_reboot.sh | 4 + provision/start_stop/host_shutdown.sh | 4 + src/cfg/nayak/default_system_state.json | 18 +++ src/cfg/taiga/default_system_state.json | 18 +++ src/core/kamerad/kamerad/appserver.py | 57 ++++++--- src/core/kamerad/kamerad/power.py | 149 ++++++++++++++++++++++++ tmux/nayak/follower/supervisor.conf | 14 +++ tmux/nayak/leader/supervisor.conf | 14 +++ tmux/taiga/follower/supervisor.conf | 14 +++ tmux/taiga/leader/supervisor.conf | 14 +++ 11 files changed, 294 insertions(+), 16 deletions(-) create mode 100755 provision/start_stop/host_reboot.sh create mode 100755 provision/start_stop/host_shutdown.sh create mode 100644 src/core/kamerad/kamerad/power.py diff --git a/compose/kamerad.yml b/compose/kamerad.yml index 6beb260..fb6e30c 100644 --- a/compose/kamerad.yml +++ b/compose/kamerad.yml @@ -9,6 +9,10 @@ services: build: ../src/core/kamerad tty: true user: root + environment: + REDIS_HOST: "${REDIS_HOST}" + NODE_HOSTNAME: "${NODE_HOSTNAME}" + SYSTEM_NAME: "${SYSTEM_NAME}" volumes: - "/mnt:/mnt:ro,rshared" restart: unless-stopped diff --git a/provision/start_stop/host_reboot.sh b/provision/start_stop/host_reboot.sh new file mode 100755 index 0000000..3ef56fe --- /dev/null +++ b/provision/start_stop/host_reboot.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# One-shot host reboot invoked by supervisor (user=root). +set -euo pipefail +exec /usr/bin/systemctl reboot diff --git a/provision/start_stop/host_shutdown.sh b/provision/start_stop/host_shutdown.sh new file mode 100755 index 0000000..db9dbc2 --- /dev/null +++ b/provision/start_stop/host_shutdown.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# One-shot host shutdown invoked by supervisor (user=root). +set -euo pipefail +exec /sbin/shutdown -h now diff --git a/src/cfg/nayak/default_system_state.json b/src/cfg/nayak/default_system_state.json index 4569094..e6212b3 100644 --- a/src/cfg/nayak/default_system_state.json +++ b/src/cfg/nayak/default_system_state.json @@ -287,6 +287,12 @@ "p1debayerq": { "processed": 0, "total": 0 + }, + "power": { + "actual": "idle", + "desired": "idle", + "status": "ready", + "updated_at": 0 } }, "left1nayak": { @@ -304,6 +310,12 @@ "p1debayerq": { "processed": 0, "total": 0 + }, + "power": { + "actual": "idle", + "desired": "idle", + "status": "ready", + "updated_at": 0 } }, "right2nayak": { @@ -321,6 +333,12 @@ "p1debayerq": { "processed": 0, "total": 0 + }, + "power": { + "actual": "idle", + "desired": "idle", + "status": "ready", + "updated_at": 0 } }, "channels": { diff --git a/src/cfg/taiga/default_system_state.json b/src/cfg/taiga/default_system_state.json index 8905ae7..9cbd900 100755 --- a/src/cfg/taiga/default_system_state.json +++ b/src/cfg/taiga/default_system_state.json @@ -448,6 +448,12 @@ "p1debayerq": { "processed": 0, "total": 0 + }, + "power": { + "actual": "idle", + "desired": "idle", + "status": "ready", + "updated_at": 0 } }, "left1taiga": { @@ -459,6 +465,12 @@ }, "last_change_desired": 0.0, "pipefile": null + }, + "power": { + "actual": "idle", + "desired": "idle", + "status": "ready", + "updated_at": 0 } }, "right2taiga": { @@ -470,6 +482,12 @@ }, "last_change_desired": 0.0, "pipefile": null + }, + "power": { + "actual": "idle", + "desired": "idle", + "status": "ready", + "updated_at": 0 } }, "observer": "", diff --git a/src/core/kamerad/kamerad/appserver.py b/src/core/kamerad/kamerad/appserver.py index c0d6ea4..c70119f 100755 --- a/src/core/kamerad/kamerad/appserver.py +++ b/src/core/kamerad/kamerad/appserver.py @@ -1,24 +1,24 @@ #!/usr/bin/env python +import json import os import subprocess -from pathlib import Path -import time -import json from collections import deque +from pathlib import Path from xmlrpc.client import ServerProxy -import redis +from flask import Flask, request from loguru import logger -from kamerad.kam_types import server_parser, ServerArgs -from kamerad import arpj -from flask import Flask, request +from kamerad import arpj +from kamerad.kam_types import ServerArgs, server_parser +from kamerad.power import PowerManager # todo: global thread pool or maybe celery app = Flask(__name__) arp_scan_deque = deque(maxlen=1) threads = {} -server = ServerProxy('http://localhost:9001/RPC2') +server = ServerProxy("http://localhost:9001/RPC2") +power_manager = None def run_cmd(cmd): @@ -37,6 +37,8 @@ def loop_arp_scan(iface, period=10): dd = arpj.run_arp_scan(iface) print(dd) arp_scan_deque.append(dd) + import time + time.sleep(period) @@ -118,7 +120,7 @@ def mountall_p(): process = "mount_nas" try: server.supervisor.stopProcess(process, True) - except: + except Exception: pass server.supervisor.startProcess(process, True) code = 1 @@ -127,16 +129,39 @@ def mountall_p(): return json.dumps({"code": code, "out": out, "err": err}) -# @app.route("/arp-scan//start", methods=["POST"]) -# def arp_scan_start(iface): -# global threads -# t = threading.Thread(target=loop_arp_scan, args=(iface, 10)) -# t.start() -# threads[iface] = t -# return 'true' +@app.route("/power/status", methods=["GET"]) +def power_status(): + if power_manager is None: + return json.dumps({"ok": False, "error": "power manager unavailable"}), 503 + return json.dumps(power_manager.get_status()) + + +@app.route("/power/shutdown", methods=["POST"]) +def power_shutdown(): + if power_manager is None: + return json.dumps({"ok": False, "error": "power manager unavailable"}), 503 + logger.info("Shutdown requested for {}", power_manager.hostname) + result = power_manager.request_shutdown() + status = 200 if result.get("ok", True) else 500 + return json.dumps(result), status + + +@app.route("/power/reboot", methods=["POST"]) +def power_reboot(): + if power_manager is None: + return json.dumps({"ok": False, "error": "power manager unavailable"}), 503 + logger.info("Reboot requested for {}", power_manager.hostname) + result = power_manager.request_reboot() + status = 200 if result.get("ok", True) else 500 + return json.dumps(result), status def entry(args: ServerArgs): + global power_manager + redis_host = os.environ.get("REDIS_HOST") + power_manager = PowerManager(server, redis_host=redis_host) + power_manager.publish_diagnostics() + power_manager.start_diagnostics() app.run(host=args.host, port=args.port, debug=args.debug) diff --git a/src/core/kamerad/kamerad/power.py b/src/core/kamerad/kamerad/power.py new file mode 100644 index 0000000..e85fcab --- /dev/null +++ b/src/core/kamerad/kamerad/power.py @@ -0,0 +1,149 @@ +"""Host power control and Redis diagnostics for kamerad. + +HTTP endpoints set desired/actual state in memory and trigger supervisor +one-shot shutdown/reboot programs. A background loop publishes the current +desired vs actual state to Redis for observability only (not command input). +""" + +from __future__ import annotations + +import os +import socket +import threading +import time +from typing import Any, Dict, Optional + +import redis +from loguru import logger + + +class PowerManager(object): + def __init__( + self, + supervisor_proxy, + redis_host: Optional[str] = None, + hostname: Optional[str] = None, + diagnostics_period: float = 2.0, + ): + self._supervisor = supervisor_proxy + self.hostname = hostname or os.environ.get( + "NODE_HOSTNAME", socket.gethostname() + ) + self._redis = ( + redis.Redis(host=redis_host, decode_responses=True) + if redis_host + else None + ) + self._period = diagnostics_period + self._stop = threading.Event() + self._lock = threading.Lock() + self.desired = "idle" + self.actual = "idle" + self.status = "ready" + self.updated_at = time.time() + + def _redis_key(self, field: str) -> str: + return "/sys/{}/power/{}".format(self.hostname, field) + + def publish_diagnostics(self) -> None: + if not self._redis: + return + with self._lock: + state = { + "desired": self.desired, + "actual": self.actual, + "status": self.status, + "updated_at": self.updated_at, + } + pipe = self._redis.pipeline() + for field, value in state.items(): + key = self._redis_key(field) + if isinstance(value, str): + pipe.set(key, value) + else: + pipe.set(key, str(value)) + pipe.execute() + + def diagnostics_loop(self) -> None: + while not self._stop.is_set(): + try: + self.publish_diagnostics() + except Exception as exc: + logger.warning("power diagnostics publish failed: {}", exc) + self._stop.wait(self._period) + + def start_diagnostics(self) -> None: + if not self._redis: + logger.warning( + "REDIS_HOST not set; power diagnostics loop disabled on {}", + self.hostname, + ) + return + thread = threading.Thread( + target=self.diagnostics_loop, name="power-diagnostics", daemon=True + ) + thread.start() + logger.info( + "Started power diagnostics loop for {} (redis={})", + self.hostname, + self._redis.connection_pool.connection_kwargs.get("host"), + ) + + def stop_diagnostics(self) -> None: + self._stop.set() + + def get_status(self) -> Dict[str, Any]: + with self._lock: + return { + "hostname": self.hostname, + "desired": self.desired, + "actual": self.actual, + "status": self.status, + "updated_at": self.updated_at, + } + + def request_shutdown(self) -> Dict[str, Any]: + return self._request_power("shutdown", "host_shutdown", "shutting_down") + + def request_reboot(self) -> Dict[str, Any]: + return self._request_power("reboot", "host_reboot", "rebooting") + + def _request_power( + self, desired: str, supervisor_process: str, actual_state: str + ) -> Dict[str, Any]: + with self._lock: + self.desired = desired + self.actual = "pending" + self.status = "requested {}".format(desired) + self.updated_at = time.time() + self.publish_diagnostics() + + system_name = os.environ.get("SYSTEM_NAME", "").strip() + if system_name: + try: + self._supervisor.supervisor.stopProcessGroup(system_name, True) + logger.info("Stopped supervisor group {}", system_name) + except Exception as exc: + logger.warning( + "stopProcessGroup {} failed: {}", system_name, exc + ) + + try: + self._supervisor.supervisor.startProcess(supervisor_process, False) + logger.info("Started supervisor process {}", supervisor_process) + except Exception as exc: + with self._lock: + self.actual = "failed" + self.status = str(exc) + self.updated_at = time.time() + self.publish_diagnostics() + return {"ok": False, "error": str(exc)} + + with self._lock: + self.actual = actual_state + self.status = "executing {}".format(desired) + self.updated_at = time.time() + self.publish_diagnostics() + result = self.get_status() + result["ok"] = True + return result diff --git a/tmux/nayak/follower/supervisor.conf b/tmux/nayak/follower/supervisor.conf index 39326f6..0123889 100644 --- a/tmux/nayak/follower/supervisor.conf +++ b/tmux/nayak/follower/supervisor.conf @@ -14,6 +14,20 @@ startsecs=0 user=root autostart=true +[program:host_shutdown] +command=/bin/bash /home/user/kw/kamera/provision/start_stop/host_shutdown.sh +startsecs=0 +user=root +autostart=false +autorestart=false + +[program:host_reboot] +command=/bin/bash /home/user/kw/kamera/provision/start_stop/host_reboot.sh +startsecs=0 +user=root +autostart=false +autorestart=false + [program:cam_ir] command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh cam_ir user=user diff --git a/tmux/nayak/leader/supervisor.conf b/tmux/nayak/leader/supervisor.conf index b1bb108..59e5d5f 100644 --- a/tmux/nayak/leader/supervisor.conf +++ b/tmux/nayak/leader/supervisor.conf @@ -20,6 +20,20 @@ startsecs=0 user=root autostart=true +[program:host_shutdown] +command=/bin/bash /home/user/kw/kamera/provision/start_stop/host_shutdown.sh +startsecs=0 +user=root +autostart=false +autorestart=false + +[program:host_reboot] +command=/bin/bash /home/user/kw/kamera/provision/start_stop/host_reboot.sh +startsecs=0 +user=root +autostart=false +autorestart=false + [program:docker_registry] command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh registry user=user diff --git a/tmux/taiga/follower/supervisor.conf b/tmux/taiga/follower/supervisor.conf index e4edfe6..626133e 100644 --- a/tmux/taiga/follower/supervisor.conf +++ b/tmux/taiga/follower/supervisor.conf @@ -14,6 +14,20 @@ startsecs=0 user=root autostart=true +[program:host_shutdown] +command=/bin/bash /home/user/kw/kamera/provision/start_stop/host_shutdown.sh +startsecs=0 +user=root +autostart=false +autorestart=false + +[program:host_reboot] +command=/bin/bash /home/user/kw/kamera/provision/start_stop/host_reboot.sh +startsecs=0 +user=root +autostart=false +autorestart=false + [program:cam_ir] command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh cam_ir user=user diff --git a/tmux/taiga/leader/supervisor.conf b/tmux/taiga/leader/supervisor.conf index 9232e76..041fa46 100644 --- a/tmux/taiga/leader/supervisor.conf +++ b/tmux/taiga/leader/supervisor.conf @@ -20,6 +20,20 @@ startsecs=0 user=root autostart=true +[program:host_shutdown] +command=/bin/bash /home/user/kw/kamera/provision/start_stop/host_shutdown.sh +startsecs=0 +user=root +autostart=false +autorestart=false + +[program:host_reboot] +command=/bin/bash /home/user/kw/kamera/provision/start_stop/host_reboot.sh +startsecs=0 +user=root +autostart=false +autorestart=false + [program:docker_registry] command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh registry user=user From c60035aea7d8a53fece99f2065d1d9560a56da59 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 09:35:30 -0400 Subject: [PATCH 115/139] Cleanup old power scripts, update desktop to point at new endpoints --- provision/ansible/functions.sh | 8 --- provision/ansible/playbooks/cas/provision.yml | 1 - provision/ansible/playbooks/cas/stopstart.yml | 16 ------ .../desktop_shortcuts/reboot_all.desktop | 2 +- .../desktop_shortcuts/reboot_center.desktop | 2 +- .../desktop_shortcuts/reboot_left.desktop | 2 +- .../desktop_shortcuts/reboot_right.desktop | 2 +- .../desktop_shortcuts/shutdown_all.desktop | 2 +- .../desktop_shortcuts/shutdown_center.desktop | 2 +- .../desktop_shortcuts/shutdown_left.desktop | 2 +- .../desktop_shortcuts/shutdown_right.desktop | 2 +- provision/start_stop/kamera_power.sh | 52 +++++++++++++++++++ provision/start_stop/reboot_all.sh | 10 ---- provision/start_stop/reboot_center.sh | 8 --- provision/start_stop/reboot_left.sh | 8 --- provision/start_stop/reboot_right.sh | 8 --- provision/start_stop/shutdown_all.sh | 9 ---- provision/start_stop/shutdown_center.sh | 8 --- provision/start_stop/shutdown_left.sh | 8 --- provision/start_stop/shutdown_right.sh | 8 --- 20 files changed, 60 insertions(+), 100 deletions(-) delete mode 100644 provision/ansible/playbooks/cas/stopstart.yml create mode 100755 provision/start_stop/kamera_power.sh delete mode 100755 provision/start_stop/reboot_all.sh delete mode 100755 provision/start_stop/reboot_center.sh delete mode 100755 provision/start_stop/reboot_left.sh delete mode 100755 provision/start_stop/reboot_right.sh delete mode 100755 provision/start_stop/shutdown_all.sh delete mode 100755 provision/start_stop/shutdown_center.sh delete mode 100755 provision/start_stop/shutdown_left.sh delete mode 100755 provision/start_stop/shutdown_right.sh diff --git a/provision/ansible/functions.sh b/provision/ansible/functions.sh index c73d7c5..654a28c 100644 --- a/provision/ansible/functions.sh +++ b/provision/ansible/functions.sh @@ -52,11 +52,3 @@ function kamera_host_for_position() { ;; esac } - -function kamera_shutdown() { - ansible-playbook playbooks/cas/stopstart.yml -i hosts.yml --become-password-file ".password" --tags "shutdown" --limit $1 -} - -function kamera_reboot() { - ansible-playbook playbooks/cas/stopstart.yml -i hosts.yml --become-password-file ".password" --tags "reboot" --limit $1 -} diff --git a/provision/ansible/playbooks/cas/provision.yml b/provision/ansible/playbooks/cas/provision.yml index 3b15169..95af7ad 100644 --- a/provision/ansible/playbooks/cas/provision.yml +++ b/provision/ansible/playbooks/cas/provision.yml @@ -34,7 +34,6 @@ 'ubuntu-drivers-common', # For hardware drivers 'python3-pip', # Pip goodness 'python3-redis', - 'ansible', # ansible-playbook for on-target provisioning ] pre_tasks: diff --git a/provision/ansible/playbooks/cas/stopstart.yml b/provision/ansible/playbooks/cas/stopstart.yml deleted file mode 100644 index e2cb68e..0000000 --- a/provision/ansible/playbooks/cas/stopstart.yml +++ /dev/null @@ -1,16 +0,0 @@ -# Playbook for properly configuring individual systems -- hosts: all - - tasks: - - - name: Reboot system. - reboot: - become: True - tags: - - reboot - - - name: Shutdown system. - community.general.shutdown: - become: True - tags: - - shutdown diff --git a/provision/start_stop/desktop_shortcuts/reboot_all.desktop b/provision/start_stop/desktop_shortcuts/reboot_all.desktop index 1979eab..298294f 100755 --- a/provision/start_stop/desktop_shortcuts/reboot_all.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_all.desktop @@ -1,5 +1,5 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/reboot_all.sh' +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.sh reboot all' Name=reboot_all Terminal=true Type=Application diff --git a/provision/start_stop/desktop_shortcuts/reboot_center.desktop b/provision/start_stop/desktop_shortcuts/reboot_center.desktop index 21b2440..2f4e2ae 100644 --- a/provision/start_stop/desktop_shortcuts/reboot_center.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_center.desktop @@ -1,5 +1,5 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/reboot_center.sh' +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.sh reboot center' Name=reboot_center Terminal=true Type=Application diff --git a/provision/start_stop/desktop_shortcuts/reboot_left.desktop b/provision/start_stop/desktop_shortcuts/reboot_left.desktop index b0a6a66..634f0bd 100644 --- a/provision/start_stop/desktop_shortcuts/reboot_left.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_left.desktop @@ -1,5 +1,5 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/reboot_left.sh' +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.sh reboot left' Name=reboot_left Terminal=true Type=Application diff --git a/provision/start_stop/desktop_shortcuts/reboot_right.desktop b/provision/start_stop/desktop_shortcuts/reboot_right.desktop index 6b43c05..ef12ed4 100644 --- a/provision/start_stop/desktop_shortcuts/reboot_right.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_right.desktop @@ -1,5 +1,5 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/reboot_right.sh' +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.sh reboot right' Name=reboot_right Terminal=true Type=Application diff --git a/provision/start_stop/desktop_shortcuts/shutdown_all.desktop b/provision/start_stop/desktop_shortcuts/shutdown_all.desktop index 4e65c37..e0e883b 100755 --- a/provision/start_stop/desktop_shortcuts/shutdown_all.desktop +++ b/provision/start_stop/desktop_shortcuts/shutdown_all.desktop @@ -1,5 +1,5 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/shutdown_all.sh' +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.sh shutdown all' Name=shutdown_all Terminal=true Type=Application diff --git a/provision/start_stop/desktop_shortcuts/shutdown_center.desktop b/provision/start_stop/desktop_shortcuts/shutdown_center.desktop index 6db3d90..d90c2ff 100644 --- a/provision/start_stop/desktop_shortcuts/shutdown_center.desktop +++ b/provision/start_stop/desktop_shortcuts/shutdown_center.desktop @@ -1,5 +1,5 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/shutdown_center.sh' +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.sh shutdown center' Name=shutdown_center Terminal=true Type=Application diff --git a/provision/start_stop/desktop_shortcuts/shutdown_left.desktop b/provision/start_stop/desktop_shortcuts/shutdown_left.desktop index 57e0ec7..4ab9709 100644 --- a/provision/start_stop/desktop_shortcuts/shutdown_left.desktop +++ b/provision/start_stop/desktop_shortcuts/shutdown_left.desktop @@ -1,5 +1,5 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/shutdown_left.sh' +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.sh shutdown left' Name=shutdown_left Terminal=true Type=Application diff --git a/provision/start_stop/desktop_shortcuts/shutdown_right.desktop b/provision/start_stop/desktop_shortcuts/shutdown_right.desktop index 5688b18..2c04bd2 100644 --- a/provision/start_stop/desktop_shortcuts/shutdown_right.desktop +++ b/provision/start_stop/desktop_shortcuts/shutdown_right.desktop @@ -1,5 +1,5 @@ [Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/shutdown_right.sh' +Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.sh shutdown right' Name=shutdown_right Terminal=true Type=Application diff --git a/provision/start_stop/kamera_power.sh b/provision/start_stop/kamera_power.sh new file mode 100755 index 0000000..2360c8d --- /dev/null +++ b/provision/start_stop/kamera_power.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# Request host shutdown or reboot via kamerad HTTP API. +# +# Usage: +# kamera_power.sh shutdown left +# kamera_power.sh reboot all +# kamera_power.sh shutdown center0taiga + +set -euo pipefail + +ACTION=${1:?usage: kamera_power.sh } +TARGET=${2:?usage: kamera_power.sh } + +kamera_host_for_position() { + local position=$1 + local system_name + system_name=$(tr -d '[:space:]' < /home/user/kw/SYSTEM_NAME) + case $position in + center) echo "center0${system_name}" ;; + left) echo "left1${system_name}" ;; + right) echo "right2${system_name}" ;; + *) + echo "Unknown position: ${position} (expected center, left, or right)" >&2 + return 1 + ;; + esac +} + +kamera_power() { + local host=$1 + local action=$2 + echo "Requesting ${action} on ${host} via kamerad..." + curl -sf -X POST "http://${host}:8987/power/${action}" || { + echo "Failed to request ${action} on ${host}" >&2 + return 1 + } + echo "OK: ${action} requested on ${host}" +} + +case "${TARGET}" in + all) + for pos in left right center; do + kamera_power "$(kamera_host_for_position "${pos}")" "${ACTION}" + done + ;; + center|left|right) + kamera_power "$(kamera_host_for_position "${TARGET}")" "${ACTION}" + ;; + *) + kamera_power "${TARGET}" "${ACTION}" + ;; +esac diff --git a/provision/start_stop/reboot_all.sh b/provision/start_stop/reboot_all.sh deleted file mode 100755 index 0473162..0000000 --- a/provision/start_stop/reboot_all.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -SYSTEM_NAME=$(cat /home/user/kw/SYSTEM_NAME) - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_reboot ${SYSTEM_NAME} diff --git a/provision/start_stop/reboot_center.sh b/provision/start_stop/reboot_center.sh deleted file mode 100755 index ca172a4..0000000 --- a/provision/start_stop/reboot_center.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_reboot $(kamera_host_for_position center) diff --git a/provision/start_stop/reboot_left.sh b/provision/start_stop/reboot_left.sh deleted file mode 100755 index 634a4f5..0000000 --- a/provision/start_stop/reboot_left.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_reboot $(kamera_host_for_position left) diff --git a/provision/start_stop/reboot_right.sh b/provision/start_stop/reboot_right.sh deleted file mode 100755 index f9eb368..0000000 --- a/provision/start_stop/reboot_right.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_reboot $(kamera_host_for_position right) diff --git a/provision/start_stop/shutdown_all.sh b/provision/start_stop/shutdown_all.sh deleted file mode 100755 index b075f73..0000000 --- a/provision/start_stop/shutdown_all.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -SYSTEM_NAME=$(cat /home/user/kw/SYSTEM_NAME) - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_shutdown ${SYSTEM_NAME} diff --git a/provision/start_stop/shutdown_center.sh b/provision/start_stop/shutdown_center.sh deleted file mode 100755 index ebe417c..0000000 --- a/provision/start_stop/shutdown_center.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_shutdown $(kamera_host_for_position center) diff --git a/provision/start_stop/shutdown_left.sh b/provision/start_stop/shutdown_left.sh deleted file mode 100755 index 847f7ac..0000000 --- a/provision/start_stop/shutdown_left.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_shutdown $(kamera_host_for_position left) diff --git a/provision/start_stop/shutdown_right.sh b/provision/start_stop/shutdown_right.sh deleted file mode 100755 index 7f61cae..0000000 --- a/provision/start_stop/shutdown_right.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -# Location of this script. -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -cd ${DIR}/../ansible/ -source ${DIR}/../ansible/functions.sh -kamera_shutdown $(kamera_host_for_position right) From 0921df4c05f5bbc9e4703b603ef10fe748d339fb Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 09:37:37 -0400 Subject: [PATCH 116/139] Cut out threading and redis from power management, just make it a simple stateful REST api. --- compose/kamerad.yml | 1 - src/core/kamerad/kamerad/appserver.py | 12 +-- src/core/kamerad/kamerad/power.py | 118 +++++--------------------- 3 files changed, 24 insertions(+), 107 deletions(-) diff --git a/compose/kamerad.yml b/compose/kamerad.yml index fb6e30c..3b6e7d0 100644 --- a/compose/kamerad.yml +++ b/compose/kamerad.yml @@ -10,7 +10,6 @@ services: tty: true user: root environment: - REDIS_HOST: "${REDIS_HOST}" NODE_HOSTNAME: "${NODE_HOSTNAME}" SYSTEM_NAME: "${SYSTEM_NAME}" volumes: diff --git a/src/core/kamerad/kamerad/appserver.py b/src/core/kamerad/kamerad/appserver.py index c70119f..885d821 100755 --- a/src/core/kamerad/kamerad/appserver.py +++ b/src/core/kamerad/kamerad/appserver.py @@ -2,6 +2,7 @@ import json import os import subprocess +import time from collections import deque from pathlib import Path from xmlrpc.client import ServerProxy @@ -37,8 +38,6 @@ def loop_arp_scan(iface, period=10): dd = arpj.run_arp_scan(iface) print(dd) arp_scan_deque.append(dd) - import time - time.sleep(period) @@ -129,8 +128,8 @@ def mountall_p(): return json.dumps({"code": code, "out": out, "err": err}) -@app.route("/power/status", methods=["GET"]) -def power_status(): +@app.route("/powerinfo", methods=["POST"]) +def powerinfo_p(): if power_manager is None: return json.dumps({"ok": False, "error": "power manager unavailable"}), 503 return json.dumps(power_manager.get_status()) @@ -158,10 +157,7 @@ def power_reboot(): def entry(args: ServerArgs): global power_manager - redis_host = os.environ.get("REDIS_HOST") - power_manager = PowerManager(server, redis_host=redis_host) - power_manager.publish_diagnostics() - power_manager.start_diagnostics() + power_manager = PowerManager(server) app.run(host=args.host, port=args.port, debug=args.debug) diff --git a/src/core/kamerad/kamerad/power.py b/src/core/kamerad/kamerad/power.py index e85fcab..17dab0c 100644 --- a/src/core/kamerad/kamerad/power.py +++ b/src/core/kamerad/kamerad/power.py @@ -1,106 +1,34 @@ -"""Host power control and Redis diagnostics for kamerad. - -HTTP endpoints set desired/actual state in memory and trigger supervisor -one-shot shutdown/reboot programs. A background loop publishes the current -desired vs actual state to Redis for observability only (not command input). -""" +"""Host power control for kamerad.""" from __future__ import annotations import os import socket -import threading import time -from typing import Any, Dict, Optional +from typing import Any, Dict -import redis from loguru import logger class PowerManager(object): - def __init__( - self, - supervisor_proxy, - redis_host: Optional[str] = None, - hostname: Optional[str] = None, - diagnostics_period: float = 2.0, - ): + def __init__(self, supervisor_proxy, hostname=None): self._supervisor = supervisor_proxy self.hostname = hostname or os.environ.get( "NODE_HOSTNAME", socket.gethostname() ) - self._redis = ( - redis.Redis(host=redis_host, decode_responses=True) - if redis_host - else None - ) - self._period = diagnostics_period - self._stop = threading.Event() - self._lock = threading.Lock() self.desired = "idle" self.actual = "idle" self.status = "ready" self.updated_at = time.time() - def _redis_key(self, field: str) -> str: - return "/sys/{}/power/{}".format(self.hostname, field) - - def publish_diagnostics(self) -> None: - if not self._redis: - return - with self._lock: - state = { - "desired": self.desired, - "actual": self.actual, - "status": self.status, - "updated_at": self.updated_at, - } - pipe = self._redis.pipeline() - for field, value in state.items(): - key = self._redis_key(field) - if isinstance(value, str): - pipe.set(key, value) - else: - pipe.set(key, str(value)) - pipe.execute() - - def diagnostics_loop(self) -> None: - while not self._stop.is_set(): - try: - self.publish_diagnostics() - except Exception as exc: - logger.warning("power diagnostics publish failed: {}", exc) - self._stop.wait(self._period) - - def start_diagnostics(self) -> None: - if not self._redis: - logger.warning( - "REDIS_HOST not set; power diagnostics loop disabled on {}", - self.hostname, - ) - return - thread = threading.Thread( - target=self.diagnostics_loop, name="power-diagnostics", daemon=True - ) - thread.start() - logger.info( - "Started power diagnostics loop for {} (redis={})", - self.hostname, - self._redis.connection_pool.connection_kwargs.get("host"), - ) - - def stop_diagnostics(self) -> None: - self._stop.set() - def get_status(self) -> Dict[str, Any]: - with self._lock: - return { - "hostname": self.hostname, - "desired": self.desired, - "actual": self.actual, - "status": self.status, - "updated_at": self.updated_at, - } + return { + "hostname": self.hostname, + "desired": self.desired, + "actual": self.actual, + "status": self.status, + "updated_at": self.updated_at, + } def request_shutdown(self) -> Dict[str, Any]: return self._request_power("shutdown", "host_shutdown", "shutting_down") @@ -111,12 +39,10 @@ def request_reboot(self) -> Dict[str, Any]: def _request_power( self, desired: str, supervisor_process: str, actual_state: str ) -> Dict[str, Any]: - with self._lock: - self.desired = desired - self.actual = "pending" - self.status = "requested {}".format(desired) - self.updated_at = time.time() - self.publish_diagnostics() + self.desired = desired + self.actual = "pending" + self.status = "requested {}".format(desired) + self.updated_at = time.time() system_name = os.environ.get("SYSTEM_NAME", "").strip() if system_name: @@ -132,18 +58,14 @@ def _request_power( self._supervisor.supervisor.startProcess(supervisor_process, False) logger.info("Started supervisor process {}", supervisor_process) except Exception as exc: - with self._lock: - self.actual = "failed" - self.status = str(exc) - self.updated_at = time.time() - self.publish_diagnostics() + self.actual = "failed" + self.status = str(exc) + self.updated_at = time.time() return {"ok": False, "error": str(exc)} - with self._lock: - self.actual = actual_state - self.status = "executing {}".format(desired) - self.updated_at = time.time() - self.publish_diagnostics() + self.actual = actual_state + self.status = "executing {}".format(desired) + self.updated_at = time.time() result = self.get_status() result["ok"] = True return result From f2e27d2cf512362f06fb78b24d6a2f32c64c559f Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 10:48:20 -0400 Subject: [PATCH 117/139] Add tailscale to system install --- provision/ansible/playbooks/cas/provision.yml | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/provision/ansible/playbooks/cas/provision.yml b/provision/ansible/playbooks/cas/provision.yml index 95af7ad..31c0824 100644 --- a/provision/ansible/playbooks/cas/provision.yml +++ b/provision/ansible/playbooks/cas/provision.yml @@ -75,6 +75,34 @@ become: True apt: name={{ sys_packages }} + - name: Add Tailscale apt key + become: True + get_url: + url: "https://pkgs.tailscale.com/stable/ubuntu/{{ ansible_lsb.codename }}.noarmor.gpg" + dest: /usr/share/keyrings/tailscale-archive-keyring.gpg + mode: '0644' + + - name: Add Tailscale apt repository + become: True + get_url: + url: "https://pkgs.tailscale.com/stable/ubuntu/{{ ansible_lsb.codename }}.tailscale-keyring.list" + dest: /etc/apt/sources.list.d/tailscale.list + mode: '0644' + + - name: Install Tailscale + become: True + apt: + name: tailscale + state: present + update_cache: yes + + - name: Enable Tailscale daemon + become: True + service: + name: tailscaled + state: started + enabled: yes + - name: Install redis on redis host become: True apt: name=redis-server From 310294e9a212da5b20f28e3293199afd8c1e6603 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 11:27:55 -0400 Subject: [PATCH 118/139] Define clear boundaries for each configuration file - yaml contains static, system-specific options. system_state.json contains the GUI-specific, more mutable configuration options --- src/cfg/nayak/default_system_state.json | 734 +----------------- src/cfg/taiga/default_system_state.json | 519 +------------ .../wxpython_gui/src/wxpython_gui/cfg.py | 202 +++-- 3 files changed, 136 insertions(+), 1319 deletions(-) diff --git a/src/cfg/nayak/default_system_state.json b/src/cfg/nayak/default_system_state.json index e6212b3..26bee26 100644 --- a/src/cfg/nayak/default_system_state.json +++ b/src/cfg/nayak/default_system_state.json @@ -1,133 +1,21 @@ { - "actual_geni_params": { - "center0nayak": { - "ir": { - "CorrectionAutoEnabled": 1, - "CorrectionAutoUseDeltaTime": 0 - }, - "rgb": { - "ISO": 200, - "ISO Max": 500, - "ISO Min": 0, - "ISO_Max": 200, - "ISO_Min": 200, - "Sensor_Temperature": 40.6, - "Shutter_Speed": 0.25, - "Shutter_Speed_Max": 0.00025, - "Shutter_Speed_Min": 0.25 - }, - "uv": { - "ExposureAuto": "error", - "ExposureAutoMax": 2400.0, - "ExposureAutoMin": 400.0, - "ExposureValue": 2400, - "GainAuto": "Auto", - "GainAutoMax": 30, - "GainAutoMin": 0, - "GainValue": 30 - } - }, - "left1nayak": { - "ir": { - "CorrectionAutoEnabled": 1 - }, - "rgb": { - "ISO": 200, - "ISO_Max": 200, - "ISO_Min": 200, - "Sensor_Temperature": 43.3, - "Shutter_Speed": 0.008, - "Shutter_Speed_Max": 0.00025, - "Shutter_Speed_Min": 0.008 - }, - "uv": { - "ExposureAuto": "error", - "ExposureAutoMax": 5760.0, - "ExposureAutoMin": 400.0, - "ExposureValue": 5760, - "GainAuto": "Auto", - "GainAutoMax": 30, - "GainAutoMin": 2, - "GainValue": 30 - } - }, - "right2nayak": { - "ir": { - "CorrectionAutoEnabled": 1 - }, - "rgb": { - "ISO": 200, - "ISO_Max": 200, - "ISO_Min": 200, - "Sensor_Temperature": 44.0, - "Shutter_Speed": 0.008, - "Shutter_Speed_Max": 0.00025, - "Shutter_Speed_Min": 0.008 - }, - "uv": { - "ExposureAuto": "error", - "ExposureAutoMax": 2454.0, - "ExposureAutoMin": 400.0, - "ExposureValue": 2454, - "GainAuto": "Auto", - "GainAutoMax": 30, - "GainAutoMin": 0, - "GainValue": 30 - } - } - }, "arch": { "allow_ir_nuc": 1, "archive_all_ir_images": 0, "base": "/mnt/data", - "base_template": "{base}/{project}/fl{flight}/{sys_cfg}/", "effort": "default_effort", - "ext_evt": "json", - "ext_ins": "json", - "ext_ir": "tif", - "ext_p1": "jpg", - "ext_rgb": "jpg", - "ext_uv": "jpg", "flight": "02", - "hosts": { - "center0nayak": { - "enabled": true, - "fov": "center", - "idx": 0 - }, - "left1nayak": { - "enabled": true, - "fov": "left", - "idx": 1 - }, - "right2nayak": { - "enabled": true, - "fov": "right", - "idx": 2 - } - }, "is_archiving": 0, - "jpeg": { - "quality": 90 - }, "jpg": { "quality": 95 }, - "kamera_dir": "/home/user/kw/kamera", "load_shapefile": 0, - "max_exposure_ms": 125, "max_fps": 2.5, - "max_frame_rate": 2.0, "min_fps": 0.1, - "min_frame_rate": 0.1, "overlap_percent": 25.0, "project": "glacial_2024", - "rgb": { - "format": "jpg" - }, "rgb_vfov": 14, "sys_cfg": "images_30deg_N68RF", - "template": "{base}/{project}/fl{flight}/{sys_cfg}/{cam_fov}_view/{project}_fl{flight}_{cf}_{time}_{mode}.{ext}", "trigger_freq": 1.0, "turn_off_nuc_in_shapefile": 1, "use_archive_region": 0, @@ -135,381 +23,10 @@ "use_p1jpeg": 0 }, "base": "/mnt/data", - "camera_cfgs": { - "100mm_25_5deg_DualRegionTrigger": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_C_100mm_0deg.pipe", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_uv.yaml", - "description": "JoBSS configuration: color cameras mounted with 100mm zeiss lenses, side camera mounts set to 25.5 deg, running IR to RGB region trigger model with thresholds set to 1.0", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_L_100mm_25deg.pipe", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_R_100mm_25deg.pipe", - "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_uv.yaml" - }, - "85mm_12_0deg_NoDetectionModel": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_center_rgb.yaml", - "center_sys_pipe": "", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_center_uv.yaml", - "description": "Configuration for 85mm lenses at 12.0* angles. No detectors installed. Intended for glacial mosaic sites.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_left_rgb.yaml", - "left_sys_pipe": "", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_right_rgb.yaml", - "right_sys_pipe": "", - "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_right_uv.yaml" - }, - "85mm_21_0deg_IRDetector_P1": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_uv.yaml", - "description": "Configuration for 85mm lenses at 21.0* angles. Placeholder for Phase One cameras, IR-only detectors installed for Nth image saving.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_uv.yaml" - }, - "85mm_21_0deg_NoDetectionModel": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_uv.yaml", - "description": "Configuration for 85mm lenses at 21.0* angles. Placeholder for Phase One cameras, IR-only detectors installed for Nth image saving.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_uv.yaml" - }, - "85mm_25_5deg_NoDetectionModel": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_center_rgb.yaml", - "center_sys_pipe": "", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_center_uv.yaml", - "description": "Configuration for 85mm lenses at 25.5* angles. No detectors installed. Intended for glacial LATTE sites.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_left_rgb.yaml", - "left_sys_pipe": "", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_right_rgb.yaml", - "right_sys_pipe": "", - "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_right_uv.yaml" - }, - "cam1": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_C_100mm_0deg.pipe", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_uv.yaml", - "description": "JoBSS configuration: color cameras mounted with 100mm zeiss lenses, side camera mounts set to 25.5 deg, running IR to RGB region trigger model with thresholds set to 1.0", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_L_100mm_25deg.pipe", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_R_100mm_25deg.pipe", - "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_uv.yaml" - }, - "images_21deg_N56RF": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/2024_AOC_Calibration_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "center_uv_yaml_path": "", - "description": "Yaml files from JoBSS other than center color from Florida. These need to be reprocessed with ANC callibration files. IR only model loaded from JoBSS 2021.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "left_uv_yaml_path": "", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "right_uv_yaml_path": "" - }, - "images_25deg_N56RF": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/2024_AOC_Calibration_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "center_uv_yaml_path": "", - "description": "Yaml files from JoBSS other than center color from Florida. These need to be reprocessed with ANC callibration files. IR only model loaded from JoBSS 2021.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "left_uv_yaml_path": "", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "right_uv_yaml_path": "" - }, - "images_30deg_N68RF": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/2024_AOC_Calibration_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "center_uv_yaml_path": "", - "description": "calibration imagery from JoBSS other than center color from Florida. These need to be reprocessed with ANC callibration files. IR only model loaded from JoBSS 2021.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "left_uv_yaml_path": "", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "right_uv_yaml_path": "" - } - }, - "center0nayak": { - "cam_fov": "center", - "detector": { - "actual": "failed", - "desired": "running", - "health": { - "frame": 0, - "time": 0.0 - }, - "last_change_desired": 1732034348.769255, - "pipefile": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe" - }, - "p1debayerq": { - "processed": 0, - "total": 0 - }, - "power": { - "actual": "idle", - "desired": "idle", - "status": "ready", - "updated_at": 0 - } - }, - "left1nayak": { - "cam_fov": "right", - "detector": { - "actual": "stalled", - "desired": "running", - "health": { - "frame": 0, - "time": 0.0 - }, - "last_change_desired": 1732034348.765598, - "pipefile": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe" - }, - "p1debayerq": { - "processed": 0, - "total": 0 - }, - "power": { - "actual": "idle", - "desired": "idle", - "status": "ready", - "updated_at": 0 - } - }, - "right2nayak": { - "cam_fov": "left", - "detector": { - "actual": "stalled", - "desired": "running", - "health": { - "frame": 0, - "time": 0.0 - }, - "last_change_desired": 1732034348.775121, - "pipefile": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe" - }, - "p1debayerq": { - "processed": 0, - "total": 0 - }, - "power": { - "actual": "idle", - "desired": "idle", - "status": "ready", - "updated_at": 0 - } - }, - "channels": { - "ir": 1, - "rgb": 0, - "uv": 2 - }, "collection_mode": "fixed rate", "detector": { "read_from_nas": false }, - "devices": { - "ir_n0": { - "ip_mode": "fixed", - "mac": "00:11:1c:02:40:46", - "model": "flir_a6750", - "prefer_ip": "192.168.1.50" - }, - "ir_n1": { - "ip_mode": "fixed", - "mac": "00:11:1c:01:ec:f7", - "model": "flir_a6750", - "prefer_ip": "192.168.1.51" - }, - "ir_n2": { - "ip_mode": "fixed", - "mac": "00:11:1c:01:c8:5b", - "model": "flir_a6750", - "prefer_ip": "192.168.1.52" - }, - "ir_nb0": { - "ip_mode": "dhcp", - "mac": "00:11:1c:00:e6:d1", - "model": "flir_a645", - "prefer_ip": "192.168.1.53" - }, - "ir_nb1": { - "ip_mode": "dhcp", - "mac": "00:11:1c:00:bf:6a", - "model": "flir_a645", - "prefer_ip": "192.168.1.54" - }, - "ir_nb2": { - "ip_mode": "dhcp", - "mac": "00:11:1c", - "model": "flir_a645", - "prefer_ip": "192.168.1.55" - }, - "rgb_n0": { - "guid": 145260, - "ip_mode": "fixed", - "label": "PORT", - "mac": "00:0f:31:02:37:6c", - "model": "allied_gt6600_rgb", - "prefer_ip": "169.254.151.51" - }, - "rgb_n1": { - "guid": 180877, - "ip_mode": "fixed", - "label": "unknown", - "mac": "00:0f:31:02:c2:8d", - "model": "allied_gt6600_rgb", - "prefer_ip": "192.168.4.41" - }, - "rgb_n2": { - "guid": 180876, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:c2:8c", - "model": "allied_gt6600_rgb", - "prefer_ip": "192.168.4.42" - }, - "rgb_nb0": { - "guid": 145260, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:37:6c", - "model": "allied_gt6600_rgb", - "prefer_ip": "192.168.4.40" - }, - "rgb_nb1": { - "guid": 180877, - "ip_mode": "fixed", - "label": "unknown", - "mac": "00:0f:31:02:c2:8d", - "model": "allied_gt6600_rgb", - "prefer_ip": "192.168.4.41" - }, - "rgb_nb2": { - "guid": 180876, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:c2:8c", - "model": "allied_gt6600_rgb", - "prefer_ip": "192.168.4.42" - }, - "rgb_p0": { - "guid": 145260, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:37:6c", - "model": "gsm-ix120", - "prefer_ip": "192.168.1.6" - }, - "rgb_p1": { - "guid": 180877, - "ip_mode": "fixed", - "label": "unknown", - "mac": "00:0f:31:02:c2:8d", - "model": "allied_gt6600_rgb", - "prefer_ip": "192.168.4.41" - }, - "rgb_p2": { - "guid": 180876, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:c2:8c", - "model": "allied_gt6600_rgb", - "prefer_ip": "192.168.4.42" - }, - "uv_n0": { - "guid": 222298, - "ip_mode": "linklocal", - "label": "unknown", - "mac": "00:0f:31:03:64:5a", - "model": "allied_gt4907_uv", - "prefer_ip": "192.168.2.60" - }, - "uv_n1": { - "guid": 222672, - "ip_mode": "linklocal", - "label": "unknown", - "mac": "00:0f:31:03:65:d0", - "model": "allied_gt4907_uv", - "prefer_ip": "192.168.2.61" - }, - "uv_n2": { - "guid": 222246, - "ip_mode": "linklocal", - "label": "unknown", - "mac": "00:0f:31:03:64:26", - "model": "allied_gt4907_uv", - "prefer_ip": "192.168.2.62" - } - }, - "effort_metadata_dict": { - "OFF": { - "aircraft": "N56RF", - "delete_old_images_sec": 1, - "field_notes": "OFF effort but still collecting at tails of survey lines or other imagery of interest", - "project_name": "glacial_2024", - "save_every_x_image": 1, - "wait_time_sec": 1 - }, - "ON": { - "aircraft": "N56RF", - "delete_old_images_sec": 1, - "field_notes": "Collecting imagery continuously on glacial harbor seal tracklines via COCOA and LATTE survey techniques", - "project_name": "glacial_2024", - "save_every_x_image": 1, - "wait_time_sec": 1 - }, - "TEST": { - "aircraft": "N56RF", - "delete_old_images_sec": 1, - "field_notes": "Lab testing in Seattle during 11/24 integration.", - "project_name": "SEA_MML_1124", - "save_every_x_image": 1, - "wait_time_sec": 1 - } - }, "effort_metadata_dict": { "default_effort": { "aircraft": "N94S", @@ -520,239 +37,10 @@ "wait_time_sec": 60 } }, - "enabled": { - "center": { - "ir": true, - "rgb": true, - "uv": false - }, - "left": { - "ir": true, - "rgb": true, - "uv": false - }, - "right": { - "ir": true, - "rgb": true, - "uv": false - } - }, "flight_number_str": "02", - "gui_cfg_dir": "/home/user/.config/kamera/gui", - "gui_config": { - "collection_mode": "fixed rate", - "collection_mode_parameter": 1.0, - "effort_metadata_dict": { - "BEAR": { - "aircraft": "N56RF", - "field_notes": "Breaking survey track to conduct flyover of polar bear detected outside the survey swath to collect multispectral imagery of the bear for estimating detection probability.", - "project_name": "jobss_2021" - }, - "CALIBRATION": { - "aircraft": "N56RF", - "field_notes": "Backup calibration image set for ice seal configuration (100mm, 25.5deg) to be used for new camera models or h5 files as needed. flown at 1000 ft, 2000 ft, 3000 ft with heavy overlap.", - "project_name": "jobss_2021" - }, - "IR_max": { - "aircraft": "N56RF", - "field_notes": "Determine the altitude limit of both the existing IR detection model as well as the hotspot integrity within the IR imagery. Mount configuration: 25.5 deg angle with 85 mm lens on color cameras.", - "project_name": "pv_2021_test" - }, - "NUC_temp": { - "aircraft": "N56RF", - "field_notes": "Test whether the NUC control based on temperature provides necessary NUC events when the ambient temperature changes.", - "project_name": "kamera_2021_test" - }, - "NUC_time": { - "aircraft": "N56RF", - "field_notes": "Test whether the NUC clock resets with each time change.", - "project_name": "kamera_2021_test" - }, - "OFF": { - "aircraft": "N56RF", - "field_notes": "Images collected while OFF effort during surveys for glacial harbor seals.", - "project_name": "glacial_2021" - }, - "ON": { - "aircraft": "N56RF", - "field_notes": "Images collected for counting glacial harbor seals.", - "project_name": "glacial_2021" - }, - "TEST": { - "aircraft": "N56RF", - "field_notes": "Test utility of KAMERA system for both coastal and glacial harbor seal surveys.", - "project_name": "pv_2021_test" - }, - "TEST_ON": { - "aircraft": "N56RF", - "field_notes": "test on effort", - "project_name": "test0205" - }, - "UV_test": { - "aircraft": "N56RF", - "field_notes": "", - "project_name": "kamera_2021_test" - }, - "VISUAL_COUNT": { - "aircraft": "N56RF", - "field_notes": "", - "project_name": "glacial_2020" - }, - "aoc_fl_test": { - "aircraft": "N56RF", - "field_notes": "Full system test following revamp of electrical and mechanical design of big kamera system", - "project_name": "aoc_2022_test" - }, - "aoc_fl_test_fixed_overlap": { - "aircraft": "N56RF", - "field_notes": "Full system test following revamp of electrical and mechanical design of big kamera system", - "project_name": "aoc_2022_test" - }, - "compression_NAS": { - "aircraft": "N56RF", - "field_notes": "Test impact of compression on detection output. KAMERA set to run compressed imagery through the detector pipeline by routing images through the NAS. (COMPRESS_IMAGERY=0 and READ_FROM_NAS=1)", - "project_name": "kamera_2021_test" - }, - "compression_jobss": { - "aircraft": "N56RF", - "field_notes": "Test impact of compression on detection output. KAMERA set to run raw imagery through the detector pipeline and only save compressed imagery. (COMPRESS_IMAGERY=0 and READ_FROM_NAS=0)", - "project_name": "kamera_2021_test" - }, - "compression_nexus": { - "aircraft": "N56RF", - "field_notes": "Test impact of compression on detection output. KAMERA set to compress and then uncompress color imagery to achieve the compression artifact in the image for the detector pipeline, while providing the image format the rest of the system is expecting. (COMPRESS_IMAGERY=1 and READ_FROM_NAS=0)", - "project_name": "kamera_2021_test" - }, - "kw_lab": { - "aircraft": "N/A", - "field_notes": "Testing in KHQ lab.", - "project_name": "kw_012023_test" - }, - "test": { - "aircraft": "N56RF", - "field_notes": "Full system test following revamp of electrical and mechanical design of big kamera system", - "project_name": "aoc_2022_test" - } - }, - "effort_selection": 0, - "flight_number_str": "00", - "ir_contrast_strength": 200.0, - "observer": "", - "rgb_vfov": 14, - "shapefile_fname": null, - "show_center": true, - "show_ir": true, - "show_left": true, - "show_rgb": true, - "show_right": true, - "show_uv": true, - "sys_cfg": null, - "sys_config_selection": "cam9" - }, - "interfaces": { - "ir": "mobo_top", - "p1": "pci_bot", - "rgb": "pci_btm", - "uv": "mobo_btm" - }, "ir_contrast_strength": 1000.0, - "kamera_dir": "/home/user/kw/noaa_kamera", "latch_frame_rate_msg": false, - "launch": { - "cam": { - "rgb": { - "GainMode": "Auto", - "GainValue": 0 - }, - "uv": { - "GainMode": "Auto", - "GainValue": 0 - } - } - }, - "local_ssd_mnt": "/mnt/data", - "locations": { - "center": { - "ir": "ir_n0", - "p1": "rgb_p0", - "rgb": "rgb_n0", - "uv": "uv_n0" - }, - "left": { - "ir": "ir_n1", - "p1": "rgb_p1", - "rgb": "rgb_n1", - "uv": "uv_n1" - }, - "right": { - "ir": "ir_n2", - "p1": "rgb_p2", - "rgb": "rgb_n2", - "uv": "uv_n2" - } - }, - "master_host": "center0nayak", - "max_mpix": 200000, - "models": { - "allied_gt4907_uv": { - "mac_prefix": "00:0f:31", - "mfgr": "allied vision", - "nic_mfgr": "", - "specs": { - "height": 3232, - "width": 4864 - }, - "spectrum": "uv" - }, - "allied_gt6600_rgb": { - "mac_prefix": "00:0f:31", - "mfgr": "allied vision", - "nic_mfgr": "", - "specs": { - "height": 4384, - "width": 6576 - }, - "spectrum": "rgb" - }, - "flir_645": { - "mac_prefix": "", - "mfgr": "flir", - "nic_mfgr": "", - "specs": { - "height": 480, - "width": 640 - }, - "spectrum": "ir" - }, - "flir_a6750": { - "mac_prefix": "00:11:1c", - "mfgr": "flir", - "nic_mfgr": "pleora", - "specs": { - "height": 512, - "width": 640 - }, - "spectrum": "ir" - }, - "gsm_ix120": { - "mac_prefix": "", - "mfgr": "phase one", - "nic_mfgr": "", - "specs": { - "height": 9654, - "width": 12768 - }, - "spectrum": "rgb" - } - }, - "nas_mnt": "/mnt/flight_data", "observer": "AR", - "postproc_commands": [ - "flight_summary", - "homography", - "detections" - ], - "redis_host": "center0nayak", "requested_geni_params": { "center0nayak": { "ir": { @@ -761,9 +49,10 @@ }, "rgb": { "ISO": 200, - "ISO_Max": 200, + "ISO_Max": 3200, "ISO_Min": 200, "Sensor_Temperature": 1.0, + "Shutter_Mode": "2", "Shutter_Speed": 0.01, "Shutter_Speed_Max": 6.25e-05, "Shutter_Speed_Min": 0.25 @@ -785,9 +74,10 @@ }, "rgb": { "ISO": 200, - "ISO_Max": 200, + "ISO_Max": 3200, "ISO_Min": 200, "Sensor_Temperature": 1.0, + "Shutter_Mode": "2", "Shutter_Speed": 0.01, "Shutter_Speed_Max": 6.25e-05, "Shutter_Speed_Min": 0.008 @@ -809,10 +99,10 @@ }, "rgb": { "ISO": 200, - "ISO_Max": 200, + "ISO_Max": 3200, "ISO_Min": 200, "Sensor_Temperature": 1.0, - "Shutter_Mode": 0, + "Shutter_Mode": "2", "Shutter_Speed": 0.01, "Shutter_Speed_Max": 6.25e-05, "Shutter_Speed_Min": 0.008 @@ -838,15 +128,5 @@ "show_right": true, "show_saturated_pixels": true, "show_uv": false, - "syscfg_dir": "/mnt/data/glacial_2024/fl02/images_30deg_N68RF/", - "uas0": { - "cam_fov": "center" - }, - "uas1": { - "cam_fov": "right" - }, - "uas2": { - "cam_fov": "left" - }, - "verbosity": 9 + "syscfg_dir": "/mnt/data/glacial_2024/fl02/images_30deg_N68RF/" } diff --git a/src/cfg/taiga/default_system_state.json b/src/cfg/taiga/default_system_state.json index 9cbd900..1d699e7 100755 --- a/src/cfg/taiga/default_system_state.json +++ b/src/cfg/taiga/default_system_state.json @@ -3,46 +3,19 @@ "allow_ir_nuc": 1, "archive_all_ir_images": 0, "base": "/mnt/data", - "base_template": "{base}/{project}/fl{flight}/{sys_cfg}/", "effort": "ON", - "ext_evt": "json", - "ext_ins": "json", - "ext_ir": "tif", - "ext_rgb": "jpg", - "ext_uv": "jpg", "flight": "00", - "hosts": { - "center0taiga": { - "enabled": true, - "fov": "center", - "idx": 0 - }, - "left1taiga": { - "enabled": true, - "fov": "left", - "idx": 1 - }, - "right2taiga": { - "enabled": true, - "fov": "right", - "idx": 2 - } - }, "is_archiving": 0, "jpg": { "quality": 95 }, "load_shapefile": 0, - "max_exposure_ms": 125, "max_fps": 2.5, - "max_frame_rate": 2.0, "min_fps": 0.1, - "min_frame_rate": 0.1, "overlap_percent": 50.0, "project": "default_effort_2019", "rgb_vfov": 14, "sys_cfg": "images_30deg_N68RF", - "template": "{base}/{project}/fl{flight}/{sys_cfg}/{cam_fov}_view/{project}_fl{flight}_{cf}_{time}_{mode}.{ext}", "trigger_freq": 1, "turn_off_nuc_in_shapefile": 1, "use_archive_region": 0, @@ -50,453 +23,24 @@ "use_p1jpeg": 0 }, "base": "/mnt/data", - "camera_cfgs": { - "100mm_25_5deg_DualRegionTrigger": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_C_100mm_0deg.pipe", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_uv.yaml", - "description": "JoBSS configuration: color cameras mounted with 100mm zeiss lenses, side camera mounts set to 25.5 deg, running IR to RGB region trigger model with thresholds set to 1.0", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_L_100mm_25deg.pipe", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_R_100mm_25deg.pipe", - "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_uv.yaml" - }, - "85mm_12_0deg_NoDetectionModel": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_center_rgb.yaml", - "center_sys_pipe": "", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_center_uv.yaml", - "description": "Configuration for 85mm lenses at 12.0* angles. No detectors installed. Intended for glacial mosaic sites.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_left_rgb.yaml", - "left_sys_pipe": "", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_right_rgb.yaml", - "right_sys_pipe": "", - "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_12_0deg/85mm_12deg_right_uv.yaml" - }, - "85mm_21_0deg_IRDetector_P1": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_uv.yaml", - "description": "Configuration for 85mm lenses at 21.0* angles. Placeholder for Phase One cameras, IR-only detectors installed for Nth image saving.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_uv.yaml" - }, - "85mm_21_0deg_NoDetectionModel": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_center_uv.yaml", - "description": "Configuration for 85mm lenses at 21.0* angles. Placeholder for Phase One cameras, IR-only detectors installed for Nth image saving.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", - "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_21_0deg/85mm_21deg_right_uv.yaml" - }, - "85mm_25_5deg_NoDetectionModel": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_center_rgb.yaml", - "center_sys_pipe": "", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_center_uv.yaml", - "description": "Configuration for 85mm lenses at 25.5* angles. No detectors installed. Intended for glacial LATTE sites.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_left_rgb.yaml", - "left_sys_pipe": "", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_right_rgb.yaml", - "right_sys_pipe": "", - "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/85mm_25_5deg/85mm_25_5deg_right_uv.yaml" - }, - "cam1": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_C_100mm_0deg.pipe", - "center_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_uv.yaml", - "description": "JoBSS configuration: color cameras mounted with 100mm zeiss lenses, side camera mounts set to 25.5 deg, running IR to RGB region trigger model with thresholds set to 1.0", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_L_100mm_25deg.pipe", - "left_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_uv.yaml", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/viame-configs/pipelines/embedded_dual_stream/Dual_Region_Trigger_Otter_R_100mm_25deg.pipe", - "right_uv_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_uv.yaml" - }, - "images_21deg_N56RF": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/2024_AOC_Calibration_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "center_uv_yaml_path": "", - "description": "Yaml files from JoBSS other than center color from Florida. These need to be reprocessed with ANC callibration files. IR only model loaded from JoBSS 2021.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "left_uv_yaml_path": "", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "right_uv_yaml_path": "" - }, - "images_25deg_N56RF": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/2024_AOC_Calibration_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "center_uv_yaml_path": "", - "description": "Yaml files from JoBSS other than center color from Florida. These need to be reprocessed with ANC callibration files. IR only model loaded from JoBSS 2021.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "left_uv_yaml_path": "", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "right_uv_yaml_path": "" - }, - "images_30deg_N68RF": { - "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/center_ir.yaml", - "center_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/2024_AOC_Calibration_center_rgb.yaml", - "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "center_uv_yaml_path": "", - "description": "calibration imagery from JoBSS other than center color from Florida. These need to be reprocessed with ANC callibration files. IR only model loaded from JoBSS 2021.", - "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_ir.yaml", - "left_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/left_rgb.yaml", - "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "left_uv_yaml_path": "", - "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_ir.yaml", - "right_rgb_yaml_path": "/mnt/flight_data/detector_models/camera_models/100mm_25_5deg/right_rgb.yaml", - "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/embedded_dual_stream/JoBBS_ir_hotspot_yolo_detector.pipe", - "right_uv_yaml_path": "" - } - }, - "channels": { - "ir": "0", - "rgb": "1" - }, "collection_mode": "fixed rate", "detector": { "read_from_nas": true }, - "devices": { - "ir_n0": { - "ip_mode": "fixed", - "mac": "00:11:1c:02:40:46", - "model": "flir_a6750", - "prefer_ip": "192.168.1.50" - }, - "ir_n1": { - "ip_mode": "fixed", - "mac": "00:11:1c:01:ec:f7", - "model": "flir_a6750", - "prefer_ip": "192.168.1.51" - }, - "ir_n2": { - "ip_mode": "fixed", - "mac": "00:11:1c:01:c8:5b", - "model": "flir_a6750", - "prefer_ip": "192.168.1.52" - }, - "ir_nb0": { - "ip_mode": "dhcp", - "mac": "00:11:1c:00:e6:d1", - "model": "flir_a645", - "prefer_ip": "192.168.1.53" - }, - "ir_nb1": { - "ip_mode": "dhcp", - "mac": "00:11:1c:00:bf:6a", - "model": "flir_a645", - "prefer_ip": "192.168.1.54" - }, - "ir_nb2": { - "ip_mode": "dhcp", - "mac": "00:11:1c", - "model": "flir_a645", - "prefer_ip": "192.168.1.55" - }, - "rgb_n0": { - "guid": 145260, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:37:6c", - "model": "gsm_ix120", - "prefer_ip": "192.168.4.40" - }, - "rgb_n1": { - "guid": 180877, - "ip_mode": "fixed", - "label": "unknown", - "mac": "00:0f:31:02:c2:8d", - "model": "gsm_ix120", - "prefer_ip": "192.168.4.41" - }, - "rgb_n2": { - "guid": 180876, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:c2:8c", - "model": "gsm_ix120", - "prefer_ip": "192.168.4.42" - }, - "rgb_nb0": { - "guid": 145260, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:37:6c", - "model": "allied_gt6600_rgb", - "prefer_ip": "192.168.4.40" - }, - "rgb_nb1": { - "guid": 180877, - "ip_mode": "fixed", - "label": "unknown", - "mac": "00:0f:31:02:c2:8d", - "model": "allied_gt6600_rgb", - "prefer_ip": "192.168.4.41" - }, - "rgb_nb2": { - "guid": 180876, - "ip_mode": "fixed", - "label": "CENTER", - "mac": "00:0f:31:02:c2:8c", - "model": "allied_gt6600_rgb", - "prefer_ip": "192.168.4.42" - }, - "uv_n0": { - "guid": 222298, - "ip_mode": "linklocal", - "label": "unknown", - "mac": "00:0f:31:03:64:5a", - "model": "allied_gt4907_uv", - "prefer_ip": "192.168.2.60" - }, - "uv_n1": { - "guid": 222672, - "ip_mode": "linklocal", - "label": "unknown", - "mac": "00:0f:31:03:65:d0", - "model": "allied_gt4907_uv", - "prefer_ip": "192.168.2.61" - }, - "uv_n2": { - "guid": 222246, - "ip_mode": "linklocal", - "label": "unknown", - "mac": "00:0f:31:03:64:26", - "model": "allied_gt4907_uv", - "prefer_ip": "192.168.2.62" - } - }, "effort_metadata_dict": { - "OFF": { + "default_effort": { "aircraft": "N94S", "delete_old_images_sec": 60, "field_notes": "Default effort, this should be edited", - "project_name": "default_effort_2019", + "project_name": "default_effort", "save_every_x_image": 5, "wait_time_sec": 60 - }, - "ON": { - "aircraft": "N94S", - "delete_old_images_sec": 60, - "field_notes": "Default effort, this should be edited", - "project_name": "default_effort_2019", - "save_every_x_image": 5, - "wait_time_sec": 60 - } - }, - "enabled": { - "center": { - "ir": true, - "rgb": true, - "uv": true - }, - "left": { - "ir": true, - "rgb": true, - "uv": true - }, - "right": { - "ir": true, - "rgb": true, - "uv": true } }, "flight_number_str": "00", - "gui_cfg_dir": "/home/user/.config/kamera/gui", - "interfaces": { - "ir": "mobo_top", - "rgb": "pci_btm", - "uv": "mobo_btm" - }, "ir_contrast_strength": 200, - "kamera_dir": "/home/user/kw/kamera", "latch_frame_rate_msg": false, - "launch": { - "cam": { - "rgb": { - "GainMode": "Auto", - "GainValue": 0 - }, - "uv": { - "GainMode": "Auto", - "GainValue": 0 - } - } - }, - "local_ssd_mnt": "/mnt/data", - "locations": { - "center": { - "ir": "ir_n0", - "rgb": "rgb_n0", - "uv": "uv_n0" - }, - "left": { - "ir": "ir_n1", - "rgb": "rgb_n1", - "uv": "uv_n1" - }, - "right": { - "ir": "ir_n2", - "rgb": "rgb_n2", - "uv": "uv_n2" - } - }, - "master_host": "center0taiga", - "max_mpix": 200000, - "models": { - "allied_gt4907_uv": { - "mac_prefix": "00:0f:31", - "mfgr": "allied vision", - "nic_mfgr": "", - "specs": { - "height": 3232, - "width": 4864 - }, - "spectrum": "uv" - }, - "allied_gt6600_rgb": { - "mac_prefix": "00:0f:31", - "mfgr": "allied vision", - "nic_mfgr": "", - "specs": { - "height": 4384, - "width": 6576 - }, - "spectrum": "rgb" - }, - "flir_645": { - "mac_prefix": "", - "mfgr": "flir", - "nic_mfgr": "", - "specs": { - "height": 480, - "width": 640 - }, - "spectrum": "ir" - }, - "flir_a6750": { - "mac_prefix": "00:11:1c", - "mfgr": "flir", - "nic_mfgr": "pleora", - "specs": { - "height": 512, - "width": 640 - }, - "spectrum": "ir" - }, - "gsm_ix120": { - "mac_prefix": "", - "mfgr": "phase one", - "nic_mfgr": "", - "specs": { - "height": 9654, - "width": 12768 - }, - "spectrum": "rgb" - } - }, - "nas_mnt": "/mnt/flight_data", - "center0taiga": { - "detector": { - "desired": "down", - "health": { - "frame": 0, - "time": 0.0 - }, - "last_change_desired": 0.0, - "pipefile": null - }, - "p1debayerq": { - "processed": 0, - "total": 0 - }, - "power": { - "actual": "idle", - "desired": "idle", - "status": "ready", - "updated_at": 0 - } - }, - "left1taiga": { - "detector": { - "desired": "down", - "health": { - "frame": 0, - "time": 0.0 - }, - "last_change_desired": 0.0, - "pipefile": null - }, - "power": { - "actual": "idle", - "desired": "idle", - "status": "ready", - "updated_at": 0 - } - }, - "right2taiga": { - "detector": { - "desired": "down", - "health": { - "frame": 0, - "time": 0.0 - }, - "last_change_desired": 0.0, - "pipefile": null - }, - "power": { - "actual": "idle", - "desired": "idle", - "status": "ready", - "updated_at": 0 - } - }, "observer": "", - "postproc_commands": [ - "flight_summary", - "homography", - "detections" - ], - "redis_host": "center0taiga", "requested_geni_params": { "center0taiga": { "ir": { @@ -504,14 +48,14 @@ "CorrectionAutoUseDeltaTime": 0 }, "rgb": { - "ISO": 0, - "ISO_Max": 16, - "ISO_Min": 0, - "Sensor_Temperature": 0, - "Shutter_Mode": "ES", - "Shutter_Speed": 0, - "Shutter_Speed_Max": 0.1, - "Shutter_Speed_Min": 0.008 + "ISO": 200, + "ISO_Max": 3200, + "ISO_Min": 200, + "Sensor_Temperature": 1.0, + "Shutter_Mode": "2", + "Shutter_Speed": 0.01, + "Shutter_Speed_Max": 6.25e-05, + "Shutter_Speed_Min": 0.25 }, "uv": { "ExposureAuto": "Continuous", @@ -526,48 +70,46 @@ }, "left1taiga": { "ir": { - "CorrectionAutoEnabled": 1, - "CorrectionAutoUseDeltaTime": 0 + "CorrectionAutoEnabled": 1 }, "rgb": { - "ISO": 0, - "ISO_Max": 16, - "ISO_Min": 0, - "Sensor_Temperature": 0, - "Shutter_Mode": "ES", - "Shutter_Speed": 0, - "Shutter_Speed_Max": 0.1, + "ISO": 200, + "ISO_Max": 3200, + "ISO_Min": 200, + "Sensor_Temperature": 1.0, + "Shutter_Mode": "2", + "Shutter_Speed": 0.01, + "Shutter_Speed_Max": 6.25e-05, "Shutter_Speed_Min": 0.008 }, "uv": { "ExposureAuto": "Continuous", - "ExposureAutoMax": 2400.0, + "ExposureAutoMax": 5760.0, "ExposureAutoMin": 400.0, "ExposureValue": 0, "GainAuto": "Auto", "GainAutoMax": 30, - "GainAutoMin": 0, + "GainAutoMin": 2, "GainValue": 0 } }, "right2taiga": { "ir": { - "CorrectionAutoEnabled": 1, - "CorrectionAutoUseDeltaTime": 0 + "CorrectionAutoEnabled": 1 }, "rgb": { - "ISO": 0, - "ISO_Max": 16, - "ISO_Min": 0, - "Sensor_Temperature": 0, - "Shutter_Mode": "ES", - "Shutter_Speed": 0, - "Shutter_Speed_Max": 0.1, + "ISO": 200, + "ISO_Max": 3200, + "ISO_Min": 200, + "Sensor_Temperature": 1.0, + "Shutter_Mode": "2", + "Shutter_Speed": 0.01, + "Shutter_Speed_Max": 6.25e-05, "Shutter_Speed_Min": 0.008 }, "uv": { "ExposureAuto": "Continuous", - "ExposureAutoMax": 2400.0, + "ExposureAutoMax": 2454.0, "ExposureAutoMin": 400.0, "ExposureValue": 0, "GainAuto": "Auto", @@ -586,6 +128,5 @@ "show_right": true, "show_saturated_pixels": false, "show_uv": false, - "syscfg_dir": "/mnt/data/default_project/fl00/images_30deg_N68RF/", - "verbosity": 9 + "syscfg_dir": "/mnt/data/default_project/fl00/images_30deg_N68RF/" } diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py index 21a7cb9..9db0436 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py @@ -15,7 +15,7 @@ from roskv.impl.redis_envoy import RedisEnvoy as ImplEnvoy from roskv.util import filter_hosts_by_system import wxpython_gui -from wxpython_gui.utils import check_default +import wxpython_gui.utils # bind the submodule for wxpython_gui.utils.make_path() # Figure out relative positions @@ -86,115 +86,121 @@ def update(self, *args, **kwargs): self[key] = other[key] -# =================== LOADING GUI CONFIG ======================= -# This will attempt to load from redis first, and backfill from disk -# Values are placed under "/sys/gui", with sys params under "/sys/gui/arch" -# Location of the system configuration file dictionary. +# =================== CONFIG RESOLUTION ======================= +# SYS_CFG is built by deep_merge-ing tiers low precedence to high; last wins: +# 1. default_system_state.json factory defaults +# 2. /system_state.json last session (the only thing saved back) +# 3. Redis /sys/* live runtime values +# 4. config.yaml (USER_CFG) static truth; ALWAYS WINS for its keys +# camera_configurations.json owns SYS_CFG["camera_cfgs"]. + + +def deep_merge(base, override): + """Recursively merge ``override`` into ``base`` (later wins) and return it.""" + for key, val in override.items(): + if key in base and isinstance(base[key], dict) and isinstance(val, dict): + deep_merge(base[key], val) + else: + base[key] = val + return base + + +# --- Tiers 1 & 2: factory defaults, then the cache (seeded from default) ----- config_filename = os.path.join(USER_CFG["gui_cfg_dir"], "system_state.json") -# create from template if it doesn't exist +default_system_state_file = os.path.join( + REAL_KAM_REPO_DIR, "src/cfg", system_name, "default_system_state.json" +) +try: + with open(default_system_state_file, "r") as infile: + DEFAULT_STATE = json.load(infile) +except Exception as e: + print(e) + DEFAULT_STATE = {} if not os.path.isfile(config_filename): wxpython_gui.utils.make_path(config_filename, from_file=True) - default_system_state_file = os.path.join( - REAL_KAM_REPO_DIR, "src/cfg", system_name, "default_system_state.json" - ) - with open(default_system_state_file, "r") as infile: - with open(config_filename, "w") as outfile: - outfile.write(infile.read()) - print("Created config from scratch: {}".format(config_filename)) + with open(config_filename, "w") as outfile: + json.dump(DEFAULT_STATE, outfile, indent=4, sort_keys=True) + print("Created config from scratch: {}".format(config_filename)) try: - GUI_ARCH_KV = kv.get_dict("/sys") + with open(config_filename, "r") as input_file: + CACHE_STATE = json.load(input_file) except Exception as e: - GUI_ARCH_KV = {} -with open(config_filename, "r") as input_file: - GUI_ARCH_DEFAULT = json.load(input_file) + print(e) + CACHE_STATE = {} -# Since we're grabbing everything, trim out camera configs for insert +# --- Tier 3: live Redis state ------------------------------------------------ try: - kv.delete_dict("/sys/camera_cfgs") -except: - pass -# Fill in any missing value in redis from disk -GUI_ARCH = check_default(GUI_ARCH_KV, GUI_ARCH_DEFAULT) - - -def save_config_settings(): - print("Saving config settings.") - with open(config_filename, "w") as output_file: - json.dump(SYS_CFG, output_file, indent=4, sort_keys=True) - - -# Fill in values that will change more frequently, not ones that are hardcoded -# in the user-config.yml. -# kv.put("/sys", GUI_ARCH) -# =================== FINISHED GUI CONFIG ======================= + REDIS_LIVE = kv.get_dict("/sys") +except Exception as e: + print(e) + REDIS_LIVE = {} +REDIS_LIVE.pop("camera_cfgs", None) # presets come from the file below -# =================== LOADING CAMERA CONFIG ======================= -# This will attempt to load from redis first, and backfill from disk -# Location of the camera configuration file dictionary. +# --- Camera presets (camera_configurations.json is authoritative) ------------ camera_config_filename = os.path.join( USER_CFG["gui_cfg_dir"], "camera_configurations.json" ) -try: - CAMERA_CFGS_KV = kv.get_dict("/sys/camera_cfgs") -except: - CAMERA_CFGS_KV = {} try: with open(camera_config_filename, "r") as input_file: - CAMERA_CFGS_DEFAULT = json.load(input_file) + CAMERA_PRESETS = json.load(input_file) except Exception as e: print(e) - CAMERA_CFGS_DEFAULT = {} -# Fill in any missing value in redis from disk -CAMERA_CFGS = {} -CAMERA_CFGS["camera_cfgs"] = check_default(CAMERA_CFGS_KV, CAMERA_CFGS_DEFAULT) -# kv.put("/sys/camera_cfgs", CAMERA_CFGS) -# =================== FINISHED CAMERA CONFIG ======================= - - -# Tracks conflict paths already reported so the same divergence isn't logged -# once per merge pass (merge_two_dicts is called several times below). -_reported_conflicts = set() - - -def merge_two_dicts(a, b, path=None): - "merges b into a; on a leaf conflict a's value is kept and b's is ignored" - if path is None: - path = [] - for key in b: - if key in a: - if isinstance(a[key], dict) and isinstance(b[key], dict): - merge_two_dicts(a[key], b[key], path + [str(key)]) - elif a[key] == b[key]: - pass # same leaf value - else: - dotted = ".".join(path + [str(key)]) - if dotted not in _reported_conflicts: - _reported_conflicts.add(dotted) - print( - "Warning: config conflict at %s -> keeping %r, ignoring %r" - % (dotted, a[key], b[key]) - ) - else: - a[key] = b[key] - return a - + CAMERA_PRESETS = {} +try: + kv.delete_dict("/sys/camera_cfgs") # clear stale presets from Redis +except Exception: + pass -# Combine entries from user-config.yml, camera_configurations.json, and system_state.json +# --- Resolve, lowest precedence first ---------------------------------------- SYS_ARCH = {} -SYS_ARCH = merge_two_dicts(SYS_ARCH, CAMERA_CFGS) -SYS_ARCH = merge_two_dicts(SYS_ARCH, GUI_ARCH) -# This is required since both files contain "arch" keys and otherwise -# update won't merge properly -USER_CFG["arch"] = merge_two_dicts(USER_CFG["arch"], GUI_ARCH["arch"]) -USER_CFG = merge_two_dicts(USER_CFG, GUI_ARCH) -SYS_ARCH = merge_two_dicts(SYS_ARCH, USER_CFG) -# kv.put("/sys", SYS_ARCH) - -# Get the global configuration combining all 3 configurations above +deep_merge(SYS_ARCH, DEFAULT_STATE) # 1. factory defaults +deep_merge(SYS_ARCH, CACHE_STATE) # 2. operator's last session +deep_merge(SYS_ARCH, REDIS_LIVE) # 3. live runtime values +deep_merge(SYS_ARCH, USER_CFG) # 4. static YAML truth always wins +SYS_ARCH["camera_cfgs"] = CAMERA_PRESETS + +# Publish to Redis under /sys and expose as SYS_CFG. SYS_CFG = Cfg(ns="/sys") SYS_CFG.update(SYS_ARCH) +# Keys excluded from the saved session state: YAML-owned (static), camera +# presets, and live per-host / camera Redis echoes. +_STATIC_TOP_KEYS = set(USER_CFG.keys()) +_STATIC_ARCH_KEYS = set(USER_CFG.get("arch", {}).keys()) +_HOST_KEYS = set(USER_CFG.get("arch", {}).get("hosts", {}).keys()) +_RUNTIME_ONLY_KEYS = {"actual_geni_params", "camera_cfgs"} + + +def extract_state(cfg): + """Return only the operator-mutable session state from ``cfg``.""" + state = {} + for key, val in cfg.items(): + # arch is YAML-owned but mixes static and mutable subkeys, so split it. + if key == "arch" and isinstance(val, dict): + arch_state = {k: v for k, v in val.items() if k not in _STATIC_ARCH_KEYS} + if arch_state: + state["arch"] = arch_state + continue + if key in _STATIC_TOP_KEYS or key in _HOST_KEYS or key in _RUNTIME_ONLY_KEYS: + continue + state[key] = val + return state + + +def save_config_settings(): + """Snapshot the mutable session state to the on-disk cache. + + Live values already stream into Redis via ``Cfg.__setitem__``; this just + persists the subset so it survives a reboot or Redis flush. + """ + state = extract_state(SYS_CFG) + print("Saving config settings (session state).") + with open(config_filename, "w") as output_file: + json.dump(state, output_file, indent=4, sort_keys=True) +# =================== FINISHED CONFIG RESOLUTION ======================= + + # =================== DEFINE GLOBALS =============================== # Need a vanilla one for binary insert ros_immediate = rospy.Duration(nsecs=1) @@ -285,25 +291,15 @@ def get_arch_path(): return tmpl.format(**fmt_dict) -def sync_dicts(truth, sync): - assert len(truth.keys()) == len(sync.keys()) - for k, v in truth.items(): - if isinstance(v, dict): - sync_dicts(truth[k], sync[k]) - if v != sync[k]: - sync[k] = v - - def pull_gui_state(): + """Refresh the in-memory arch state from the live Redis values.""" print("Pulling gui state") try: - d1 = kv.get_dict("/sys/arch") + live_arch = kv.get_dict("/sys/arch") except Exception as e: print(e) - d1 = {} - d2 = SYS_CFG["arch"] - d3 = check_default(d2, d1) - sync_dicts(d3, d2) + return + deep_merge(SYS_CFG["arch"], live_arch) def save_camera_config(curr_cfg=None): From 4ebe2535a82d939049f5ce320a4770d6a7b89d71 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 11:34:55 -0400 Subject: [PATCH 119/139] Remove all old license strings, replace GUI license with Apache 2.0. --- NOTICE | 2 +- kamera/colmap_processing/calibration.py | 32 ----------------- kamera/colmap_processing/geotiff.py | 32 ----------------- .../build_calibration_database_from_colmap.py | 33 ----------------- ...alibrate_static_camera_from_level_lines.py | 33 ----------------- ...calibrate_static_camera_from_llh_points.py | 33 ----------------- .../calibrate_static_camera_from_reference.py | 33 ----------------- kamera/colmap_processing/scripts/cam_view.py | 28 --------------- .../scripts/camera_pair_test.py | 33 ----------------- .../scripts/colmap_manual_registration.py | 33 ----------------- .../scripts/create_geotiff.py | 33 ----------------- .../create_static_camera_from_sfm_images.py | 33 ----------------- .../scripts/explode_drone_videos.py | 33 ----------------- .../scripts/extract_image_pose.py | 33 ----------------- ...calibrate_static_camera_from_llh_points.py | 33 ----------------- .../scripts/georegister_data.py | 33 ----------------- .../scripts/georegister_data_sparse_3d_pts.py | 33 ----------------- .../scripts/image_to_geotiff.py | 33 ----------------- .../scripts/manual_cal_landmark_gui.py | 33 ----------------- .../scripts/reduce_image_set.py | 33 ----------------- .../colmap_processing/scripts/render_view.py | 33 ----------------- .../scripts/split_database.py | 33 ----------------- .../scripts/static_cameras_from_colmap.py | 33 ----------------- .../colmap_processing/scripts/xfm4x4_model.py | 28 --------------- kamera/colmap_processing/slam.py | 32 ----------------- .../colmap_processing/static_camera_model.py | 33 ----------------- .../test/test_camera_models.py | 33 ----------------- kamera/colmap_processing/vtk_util.py | 33 ----------------- kamera/colmap_processing/world_models.py | 33 ----------------- .../scripts/calibrate_from_colmap.py | 32 ----------------- .../scripts/calibrate_ir_from_rgb.py | 32 ----------------- kamera/postflight/scripts/create_geotiffs.py | 32 ----------------- kamera/postflight/scripts/debayer.py | 32 ----------------- .../scripts/fix_left_right_ir_swap.py | 32 ----------------- .../scripts/geocalibrate_cameras.py | 32 ----------------- .../scripts/intercam_homography_from_yaml.py | 32 ----------------- kamera/postflight/scripts/make_small_jpg.py | 32 ----------------- .../postflight/scripts/processing_template.py | 32 ----------------- .../kw_genicam_driver/src/decode_error.cpp | 29 --------------- src/cams/kw_genicam_driver/src/decode_error.h | 29 --------------- .../bag_file_explode/scripts/rosbag_to_png.py | 33 ----------------- .../dynamic_config_ros.cxx | 29 --------------- .../dynamic_config_ros.h | 29 --------------- .../register_algorithms.cxx | 29 --------------- .../scripts/simulate_cameras.py | 33 ----------------- .../sensor_simulator/scripts/simulate_ins.py | 33 ----------------- .../src/sensor_simulator/camera_simulator.py | 32 ----------------- .../rebroadcast_infrequent_detections.py | 33 ----------------- .../scripts/save_detection_chips_to_disk.py | 33 ----------------- .../scripts/save_images_to_disk.py | 33 ----------------- .../src/kw_detector_fusion_adapter.cpp | 5 --- .../src/ros_detector_scaling.cxx | 5 --- .../src/ros_detector_scaling.h | 5 --- .../src/ros_dynamic_config.cxx | 5 --- .../sprokit_adapters/src/ros_dynamic_config.h | 5 --- .../scripts/system_control_panel_node.py | 32 ----------------- .../src/wxpython_gui/camera_models.py | 32 ----------------- .../wxpython_gui/src/wxpython_gui/cfg.py | 35 +++---------------- .../src/wxpython_gui/nav_state.py | 32 ----------------- .../wxpython_gui/system_control_panel/gui.py | 2 +- src/process/nexus/nodes/img_nexus.py | 33 ----------------- src/process/nexus/scripts/simulate_heading.py | 33 ----------------- .../src/view_server/image_view_server.py | 33 ----------------- .../src/view_server/image_view_server.py.bak | 33 ----------------- .../view_server/src/view_server/img_nexus.py | 33 ----------------- 65 files changed, 7 insertions(+), 1892 deletions(-) diff --git a/NOTICE b/NOTICE index 6774501..ed27a5f 100644 --- a/NOTICE +++ b/NOTICE @@ -1,4 +1,4 @@ -Copyright 2024 Kitware, Inc. +KAMERA ============================================================= Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/kamera/colmap_processing/calibration.py b/kamera/colmap_processing/calibration.py index b73c4cd..a5f6d9f 100644 --- a/kamera/colmap_processing/calibration.py +++ b/kamera/colmap_processing/calibration.py @@ -1,41 +1,9 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2020 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling projection operations of a standard camera model. Note: the image coordiante system has its origin at the center of the top left pixel. - """ from __future__ import division, print_function, absolute_import import numpy as np diff --git a/kamera/colmap_processing/geotiff.py b/kamera/colmap_processing/geotiff.py index d8651e2..35cd9bf 100644 --- a/kamera/colmap_processing/geotiff.py +++ b/kamera/colmap_processing/geotiff.py @@ -1,41 +1,9 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2017-2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling projection operations of a standard camera model. Note: the raster coordiante system has its origin at the center of the top left pixel. - """ from __future__ import division, print_function, absolute_import import numpy as np diff --git a/kamera/colmap_processing/scripts/build_calibration_database_from_colmap.py b/kamera/colmap_processing/scripts/build_calibration_database_from_colmap.py index 82c0215..4541598 100644 --- a/kamera/colmap_processing/scripts/build_calibration_database_from_colmap.py +++ b/kamera/colmap_processing/scripts/build_calibration_database_from_colmap.py @@ -1,37 +1,4 @@ #!/usr/bin/env python -""" -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function, absolute_import import numpy as np import matplotlib.pyplot as plt diff --git a/kamera/colmap_processing/scripts/calibrate_static_camera_from_level_lines.py b/kamera/colmap_processing/scripts/calibrate_static_camera_from_level_lines.py index 9e962d0..5d4ccdd 100644 --- a/kamera/colmap_processing/scripts/calibrate_static_camera_from_level_lines.py +++ b/kamera/colmap_processing/scripts/calibrate_static_camera_from_level_lines.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2021 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/calibrate_static_camera_from_llh_points.py b/kamera/colmap_processing/scripts/calibrate_static_camera_from_llh_points.py index 97833fe..16a1ac9 100644 --- a/kamera/colmap_processing/scripts/calibrate_static_camera_from_llh_points.py +++ b/kamera/colmap_processing/scripts/calibrate_static_camera_from_llh_points.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/calibrate_static_camera_from_reference.py b/kamera/colmap_processing/scripts/calibrate_static_camera_from_reference.py index ce4b367..f93f19f 100644 --- a/kamera/colmap_processing/scripts/calibrate_static_camera_from_reference.py +++ b/kamera/colmap_processing/scripts/calibrate_static_camera_from_reference.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/cam_view.py b/kamera/colmap_processing/scripts/cam_view.py index 5003810..159be41 100755 --- a/kamera/colmap_processing/scripts/cam_view.py +++ b/kamera/colmap_processing/scripts/cam_view.py @@ -1,32 +1,4 @@ #!/usr/bin/env python -# ckwg +31 -# Copyright 2021 by Kitware, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither name of Kitware, Inc. nor the names of any contributors may be used -# to endorse or promote products derived from this software without specific -# prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ''' Load and print camera parameters from YAML, and optionally render the view given a 3D model in PLY format. ''' diff --git a/kamera/colmap_processing/scripts/camera_pair_test.py b/kamera/colmap_processing/scripts/camera_pair_test.py index ab0b837..77cac3d 100644 --- a/kamera/colmap_processing/scripts/camera_pair_test.py +++ b/kamera/colmap_processing/scripts/camera_pair_test.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/colmap_manual_registration.py b/kamera/colmap_processing/scripts/colmap_manual_registration.py index b4085ce..c442385 100644 --- a/kamera/colmap_processing/scripts/colmap_manual_registration.py +++ b/kamera/colmap_processing/scripts/colmap_manual_registration.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" import sys import sqlite3 import numpy as np diff --git a/kamera/colmap_processing/scripts/create_geotiff.py b/kamera/colmap_processing/scripts/create_geotiff.py index fd43d4f..25df14b 100644 --- a/kamera/colmap_processing/scripts/create_geotiff.py +++ b/kamera/colmap_processing/scripts/create_geotiff.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/create_static_camera_from_sfm_images.py b/kamera/colmap_processing/scripts/create_static_camera_from_sfm_images.py index e0560fc..7baf447 100644 --- a/kamera/colmap_processing/scripts/create_static_camera_from_sfm_images.py +++ b/kamera/colmap_processing/scripts/create_static_camera_from_sfm_images.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/explode_drone_videos.py b/kamera/colmap_processing/scripts/explode_drone_videos.py index d10af6e..297a531 100644 --- a/kamera/colmap_processing/scripts/explode_drone_videos.py +++ b/kamera/colmap_processing/scripts/explode_drone_videos.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/extract_image_pose.py b/kamera/colmap_processing/scripts/extract_image_pose.py index 95d2b16..79934c3 100644 --- a/kamera/colmap_processing/scripts/extract_image_pose.py +++ b/kamera/colmap_processing/scripts/extract_image_pose.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/from_landmark_registration_gui/calibrate_static_camera_from_llh_points.py b/kamera/colmap_processing/scripts/from_landmark_registration_gui/calibrate_static_camera_from_llh_points.py index bc020c3..ffb922d 100644 --- a/kamera/colmap_processing/scripts/from_landmark_registration_gui/calibrate_static_camera_from_llh_points.py +++ b/kamera/colmap_processing/scripts/from_landmark_registration_gui/calibrate_static_camera_from_llh_points.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/georegister_data.py b/kamera/colmap_processing/scripts/georegister_data.py index 9e5de02..5a4c382 100644 --- a/kamera/colmap_processing/scripts/georegister_data.py +++ b/kamera/colmap_processing/scripts/georegister_data.py @@ -1,36 +1,5 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - This script helps to georegister the 3-D reconstruction coordinate system used by Colmap. We assume that enough of the scene is jointly visible (e.g., enough high-altitude views) so that georegistration is a rigid rotation and isotropic @@ -41,8 +10,6 @@ point superimposed. These images should be loaded into the landmark_registration GUI. The ENU origin should be added as a point with latitude and longitude both zero. - - """ from __future__ import division, print_function, absolute_import import numpy as np diff --git a/kamera/colmap_processing/scripts/georegister_data_sparse_3d_pts.py b/kamera/colmap_processing/scripts/georegister_data_sparse_3d_pts.py index 65574a5..0d97d1e 100644 --- a/kamera/colmap_processing/scripts/georegister_data_sparse_3d_pts.py +++ b/kamera/colmap_processing/scripts/georegister_data_sparse_3d_pts.py @@ -1,36 +1,5 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - This script helps to georegister the 3-D reconstruction coordinate system used by Colmap. We assume that enough of the scene is jointly visible (e.g., enough high-altitude views) so that georegistration is a rigid rotation and isotropic @@ -41,8 +10,6 @@ point superimposed. These images should be loaded into the landmark_registration GUI. The ENU origin should be added as a point with latitude and longitude both zero. - - """ from __future__ import division, print_function, absolute_import import numpy as np diff --git a/kamera/colmap_processing/scripts/image_to_geotiff.py b/kamera/colmap_processing/scripts/image_to_geotiff.py index abf54db..3234ab2 100644 --- a/kamera/colmap_processing/scripts/image_to_geotiff.py +++ b/kamera/colmap_processing/scripts/image_to_geotiff.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/manual_cal_landmark_gui.py b/kamera/colmap_processing/scripts/manual_cal_landmark_gui.py index 376f855..66b12a6 100644 --- a/kamera/colmap_processing/scripts/manual_cal_landmark_gui.py +++ b/kamera/colmap_processing/scripts/manual_cal_landmark_gui.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" import sys import sqlite3 import numpy as np diff --git a/kamera/colmap_processing/scripts/reduce_image_set.py b/kamera/colmap_processing/scripts/reduce_image_set.py index 95bea99..345f1eb 100644 --- a/kamera/colmap_processing/scripts/reduce_image_set.py +++ b/kamera/colmap_processing/scripts/reduce_image_set.py @@ -1,37 +1,4 @@ #!/usr/bin/env python -""" -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function, absolute_import import numpy as np import matplotlib.pyplot as plt diff --git a/kamera/colmap_processing/scripts/render_view.py b/kamera/colmap_processing/scripts/render_view.py index 87c065f..64f884e 100644 --- a/kamera/colmap_processing/scripts/render_view.py +++ b/kamera/colmap_processing/scripts/render_view.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/split_database.py b/kamera/colmap_processing/scripts/split_database.py index 00dbf59..21fb1dd 100644 --- a/kamera/colmap_processing/scripts/split_database.py +++ b/kamera/colmap_processing/scripts/split_database.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2021 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/static_cameras_from_colmap.py b/kamera/colmap_processing/scripts/static_cameras_from_colmap.py index 0657b52..a58467c 100644 --- a/kamera/colmap_processing/scripts/static_cameras_from_colmap.py +++ b/kamera/colmap_processing/scripts/static_cameras_from_colmap.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/scripts/xfm4x4_model.py b/kamera/colmap_processing/scripts/xfm4x4_model.py index 0d9c97e..dff5ccd 100755 --- a/kamera/colmap_processing/scripts/xfm4x4_model.py +++ b/kamera/colmap_processing/scripts/xfm4x4_model.py @@ -1,32 +1,4 @@ #!/usr/bin/env python -# ckwg +31 -# Copyright 2021 by Kitware, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither name of Kitware, Inc. nor the names of any contributors may be used -# to endorse or promote products derived from this software without specific -# prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ============================================================================== ''' Eugene_Borovikov@Kitware.com: read COLMAP model, apply a 4x4 similarity transform and save the transformed model, e.g. geo-registration. diff --git a/kamera/colmap_processing/slam.py b/kamera/colmap_processing/slam.py index aaa4fed..3455bfe 100644 --- a/kamera/colmap_processing/slam.py +++ b/kamera/colmap_processing/slam.py @@ -1,42 +1,10 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2020 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling projection operations of a standard camera model. Note: the image coordiante system has its origin at the center of the top left pixel. - """ from __future__ import division, print_function, absolute_import import numpy as np diff --git a/kamera/colmap_processing/static_camera_model.py b/kamera/colmap_processing/static_camera_model.py index 7de91bc..3bf4d4c 100644 --- a/kamera/colmap_processing/static_camera_model.py +++ b/kamera/colmap_processing/static_camera_model.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os, cv2, yaml, PIL diff --git a/kamera/colmap_processing/test/test_camera_models.py b/kamera/colmap_processing/test/test_camera_models.py index 7079cb8..438c4c0 100644 --- a/kamera/colmap_processing/test/test_camera_models.py +++ b/kamera/colmap_processing/test/test_camera_models.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2020 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/kamera/colmap_processing/vtk_util.py b/kamera/colmap_processing/vtk_util.py index 084c88d..adc8d63 100644 --- a/kamera/colmap_processing/vtk_util.py +++ b/kamera/colmap_processing/vtk_util.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import copy, os, cv2, vtk diff --git a/kamera/colmap_processing/world_models.py b/kamera/colmap_processing/world_models.py index ff85cfa..46353f4 100644 --- a/kamera/colmap_processing/world_models.py +++ b/kamera/colmap_processing/world_models.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2020 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import csv diff --git a/kamera/postflight/scripts/calibrate_from_colmap.py b/kamera/postflight/scripts/calibrate_from_colmap.py index 5d3c4cc..fec90ea 100644 --- a/kamera/postflight/scripts/calibrate_from_colmap.py +++ b/kamera/postflight/scripts/calibrate_from_colmap.py @@ -1,41 +1,9 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling projection operations of a standard camera model. Note: the image coordiante system has its origin at the center of the top left pixel. - """ from __future__ import division, print_function import numpy as np diff --git a/kamera/postflight/scripts/calibrate_ir_from_rgb.py b/kamera/postflight/scripts/calibrate_ir_from_rgb.py index f3292f5..fbf0d96 100644 --- a/kamera/postflight/scripts/calibrate_ir_from_rgb.py +++ b/kamera/postflight/scripts/calibrate_ir_from_rgb.py @@ -1,38 +1,6 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling projection operations of a standard camera model. - """ from __future__ import division, print_function import copy diff --git a/kamera/postflight/scripts/create_geotiffs.py b/kamera/postflight/scripts/create_geotiffs.py index ac75e63..9714743 100644 --- a/kamera/postflight/scripts/create_geotiffs.py +++ b/kamera/postflight/scripts/create_geotiffs.py @@ -1,38 +1,6 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling projection operations of a standard camera model. - """ from __future__ import division, print_function import argparse diff --git a/kamera/postflight/scripts/debayer.py b/kamera/postflight/scripts/debayer.py index 555d497..548b44b 100644 --- a/kamera/postflight/scripts/debayer.py +++ b/kamera/postflight/scripts/debayer.py @@ -1,38 +1,6 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Script to convert Bayered images to deBayered RGB images. - """ from __future__ import division, print_function import argparse diff --git a/kamera/postflight/scripts/fix_left_right_ir_swap.py b/kamera/postflight/scripts/fix_left_right_ir_swap.py index da38c4c..8ec513f 100644 --- a/kamera/postflight/scripts/fix_left_right_ir_swap.py +++ b/kamera/postflight/scripts/fix_left_right_ir_swap.py @@ -1,38 +1,6 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Script to convert Bayered images to deBayered RGB images. - """ from __future__ import division, print_function import numpy as np diff --git a/kamera/postflight/scripts/geocalibrate_cameras.py b/kamera/postflight/scripts/geocalibrate_cameras.py index 013f04d..f2df80d 100644 --- a/kamera/postflight/scripts/geocalibrate_cameras.py +++ b/kamera/postflight/scripts/geocalibrate_cameras.py @@ -1,38 +1,6 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling projection operations of a standard camera model. - """ from __future__ import division, print_function import cv2 diff --git a/kamera/postflight/scripts/intercam_homography_from_yaml.py b/kamera/postflight/scripts/intercam_homography_from_yaml.py index 296fde4..928248b 100644 --- a/kamera/postflight/scripts/intercam_homography_from_yaml.py +++ b/kamera/postflight/scripts/intercam_homography_from_yaml.py @@ -1,38 +1,6 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling projection operations of a standard camera model. - """ from __future__ import division, print_function import cv2 diff --git a/kamera/postflight/scripts/make_small_jpg.py b/kamera/postflight/scripts/make_small_jpg.py index 1df6e16..9e3de20 100644 --- a/kamera/postflight/scripts/make_small_jpg.py +++ b/kamera/postflight/scripts/make_small_jpg.py @@ -1,38 +1,6 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Script to convert Bayered images to deBayered RGB images. - """ from __future__ import division, print_function import numpy as np diff --git a/kamera/postflight/scripts/processing_template.py b/kamera/postflight/scripts/processing_template.py index 224484d..647c12c 100644 --- a/kamera/postflight/scripts/processing_template.py +++ b/kamera/postflight/scripts/processing_template.py @@ -1,38 +1,6 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling projection operations of a standard camera model. - """ from __future__ import division, print_function import os diff --git a/src/cams/kw_genicam_driver/src/decode_error.cpp b/src/cams/kw_genicam_driver/src/decode_error.cpp index 704fa93..5da1e3b 100644 --- a/src/cams/kw_genicam_driver/src/decode_error.cpp +++ b/src/cams/kw_genicam_driver/src/decode_error.cpp @@ -1,32 +1,3 @@ -/*ckwg +29 - * Copyright 2017 by Kitware, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither name of Kitware, Inc. nor the names of any contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ #include "decode_error.h" diff --git a/src/cams/kw_genicam_driver/src/decode_error.h b/src/cams/kw_genicam_driver/src/decode_error.h index 684b080..3dcf126 100644 --- a/src/cams/kw_genicam_driver/src/decode_error.h +++ b/src/cams/kw_genicam_driver/src/decode_error.h @@ -1,32 +1,3 @@ -/*ckwg +29 - * Copyright 2017 by Kitware, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither name of Kitware, Inc. nor the names of any contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ #ifndef GEVLIB_DECODE_ERROR_H diff --git a/src/kitware-ros-pkg/bag_file_explode/scripts/rosbag_to_png.py b/src/kitware-ros-pkg/bag_file_explode/scripts/rosbag_to_png.py index 3ef17ba..b4d013f 100755 --- a/src/kitware-ros-pkg/bag_file_explode/scripts/rosbag_to_png.py +++ b/src/kitware-ros-pkg/bag_file_explode/scripts/rosbag_to_png.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import print_function import argparse diff --git a/src/kitware-ros-pkg/kwiver_ros_param_interface/dynamic_config_ros.cxx b/src/kitware-ros-pkg/kwiver_ros_param_interface/dynamic_config_ros.cxx index 723a629..9eaf87e 100644 --- a/src/kitware-ros-pkg/kwiver_ros_param_interface/dynamic_config_ros.cxx +++ b/src/kitware-ros-pkg/kwiver_ros_param_interface/dynamic_config_ros.cxx @@ -1,32 +1,3 @@ -/*ckwg +29 - * Copyright 2017 by Kitware, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither name of Kitware, Inc. nor the names of any contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ /** * \file diff --git a/src/kitware-ros-pkg/kwiver_ros_param_interface/dynamic_config_ros.h b/src/kitware-ros-pkg/kwiver_ros_param_interface/dynamic_config_ros.h index 1814276..ca38393 100644 --- a/src/kitware-ros-pkg/kwiver_ros_param_interface/dynamic_config_ros.h +++ b/src/kitware-ros-pkg/kwiver_ros_param_interface/dynamic_config_ros.h @@ -1,32 +1,3 @@ -/*ckwg +29 - * Copyright 2017 by Kitware, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither name of Kitware, Inc. nor the names of any contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ /** * \file diff --git a/src/kitware-ros-pkg/kwiver_ros_param_interface/register_algorithms.cxx b/src/kitware-ros-pkg/kwiver_ros_param_interface/register_algorithms.cxx index cc12ee0..eb2cc28 100644 --- a/src/kitware-ros-pkg/kwiver_ros_param_interface/register_algorithms.cxx +++ b/src/kitware-ros-pkg/kwiver_ros_param_interface/register_algorithms.cxx @@ -1,32 +1,3 @@ -/*ckwg +29 - * Copyright 2017 by Kitware, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither name of Kitware, Inc. nor the names of any contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ #include #include diff --git a/src/kitware-ros-pkg/sensor_simulator/scripts/simulate_cameras.py b/src/kitware-ros-pkg/sensor_simulator/scripts/simulate_cameras.py index e313ac5..7488d84 100755 --- a/src/kitware-ros-pkg/sensor_simulator/scripts/simulate_cameras.py +++ b/src/kitware-ros-pkg/sensor_simulator/scripts/simulate_cameras.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np diff --git a/src/kitware-ros-pkg/sensor_simulator/scripts/simulate_ins.py b/src/kitware-ros-pkg/sensor_simulator/scripts/simulate_ins.py index e63eaa2..6e860f9 100755 --- a/src/kitware-ros-pkg/sensor_simulator/scripts/simulate_ins.py +++ b/src/kitware-ros-pkg/sensor_simulator/scripts/simulate_ins.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2017 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import time diff --git a/src/kitware-ros-pkg/sensor_simulator/src/sensor_simulator/camera_simulator.py b/src/kitware-ros-pkg/sensor_simulator/src/sensor_simulator/camera_simulator.py index af6c7fb..5cbcbda 100644 --- a/src/kitware-ros-pkg/sensor_simulator/src/sensor_simulator/camera_simulator.py +++ b/src/kitware-ros-pkg/sensor_simulator/src/sensor_simulator/camera_simulator.py @@ -1,38 +1,6 @@ #!/usr/bin/env python """ -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling imagery simulation. - """ from __future__ import division, print_function import numpy as np diff --git a/src/kitware-ros-pkg/sprokit_adapters/scripts/rebroadcast_infrequent_detections.py b/src/kitware-ros-pkg/sprokit_adapters/scripts/rebroadcast_infrequent_detections.py index 4fc41fd..db0ca42 100755 --- a/src/kitware-ros-pkg/sprokit_adapters/scripts/rebroadcast_infrequent_detections.py +++ b/src/kitware-ros-pkg/sprokit_adapters/scripts/rebroadcast_infrequent_detections.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/src/kitware-ros-pkg/sprokit_adapters/scripts/save_detection_chips_to_disk.py b/src/kitware-ros-pkg/sprokit_adapters/scripts/save_detection_chips_to_disk.py index 3ccc5e3..418f897 100755 --- a/src/kitware-ros-pkg/sprokit_adapters/scripts/save_detection_chips_to_disk.py +++ b/src/kitware-ros-pkg/sprokit_adapters/scripts/save_detection_chips_to_disk.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2017 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/src/kitware-ros-pkg/sprokit_adapters/scripts/save_images_to_disk.py b/src/kitware-ros-pkg/sprokit_adapters/scripts/save_images_to_disk.py index a5f5c9c..902e39b 100755 --- a/src/kitware-ros-pkg/sprokit_adapters/scripts/save_images_to_disk.py +++ b/src/kitware-ros-pkg/sprokit_adapters/scripts/save_images_to_disk.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2017 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np import os diff --git a/src/kitware-ros-pkg/sprokit_adapters/src/kw_detector_fusion_adapter.cpp b/src/kitware-ros-pkg/sprokit_adapters/src/kw_detector_fusion_adapter.cpp index ee25bb7..58ad5e4 100644 --- a/src/kitware-ros-pkg/sprokit_adapters/src/kw_detector_fusion_adapter.cpp +++ b/src/kitware-ros-pkg/sprokit_adapters/src/kw_detector_fusion_adapter.cpp @@ -1,8 +1,3 @@ -/*ckwg +5 - * Copyright 2019 by Kitware, Inc. All Rights Reserved. Please refer to - * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel, - * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065. - */ #include "ros/ros.h" #include "sensor_msgs/Image.h" diff --git a/src/kitware-ros-pkg/sprokit_adapters/src/ros_detector_scaling.cxx b/src/kitware-ros-pkg/sprokit_adapters/src/ros_detector_scaling.cxx index 718ac40..10398e0 100644 --- a/src/kitware-ros-pkg/sprokit_adapters/src/ros_detector_scaling.cxx +++ b/src/kitware-ros-pkg/sprokit_adapters/src/ros_detector_scaling.cxx @@ -1,8 +1,3 @@ -/*ckwg +5 - * Copyright 2017 by Kitware, Inc. All Rights Reserved. Please refer to - * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel, - * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065. - */ #include "ros_detector_scaling.h" diff --git a/src/kitware-ros-pkg/sprokit_adapters/src/ros_detector_scaling.h b/src/kitware-ros-pkg/sprokit_adapters/src/ros_detector_scaling.h index d146a66..5e72b4e 100644 --- a/src/kitware-ros-pkg/sprokit_adapters/src/ros_detector_scaling.h +++ b/src/kitware-ros-pkg/sprokit_adapters/src/ros_detector_scaling.h @@ -1,8 +1,3 @@ -/*ckwg +5 - * Copyright 2017 by Kitware, Inc. All Rights Reserved. Please refer to - * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel, - * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065. - */ #include "ros_detector_scaling_export.h" diff --git a/src/kitware-ros-pkg/sprokit_adapters/src/ros_dynamic_config.cxx b/src/kitware-ros-pkg/sprokit_adapters/src/ros_dynamic_config.cxx index 85eca1f..30e26a5 100644 --- a/src/kitware-ros-pkg/sprokit_adapters/src/ros_dynamic_config.cxx +++ b/src/kitware-ros-pkg/sprokit_adapters/src/ros_dynamic_config.cxx @@ -1,8 +1,3 @@ -/*ckwg +5 - * Copyright 2017 by Kitware, Inc. All Rights Reserved. Please refer to - * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel, - * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065. - */ #include "ros_dynamic_config.h" diff --git a/src/kitware-ros-pkg/sprokit_adapters/src/ros_dynamic_config.h b/src/kitware-ros-pkg/sprokit_adapters/src/ros_dynamic_config.h index c0b4406..8063b30 100644 --- a/src/kitware-ros-pkg/sprokit_adapters/src/ros_dynamic_config.h +++ b/src/kitware-ros-pkg/sprokit_adapters/src/ros_dynamic_config.h @@ -1,8 +1,3 @@ -/*ckwg +5 - * Copyright 2017 by Kitware, Inc. All Rights Reserved. Please refer to - * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel, - * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065. - */ #include "ros_dynamic_config_export.h" diff --git a/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py b/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py index 15dda6e..ea4a030 100755 --- a/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py +++ b/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py @@ -1,38 +1,6 @@ #!/usr/bin/env python3 """ -ckwg +31 -Copyright 2017 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling imagery simulation. - """ from __future__ import division, print_function import os diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py index b2933ef..a8a7494 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py @@ -1,41 +1,9 @@ #!/usr/bin/env python3 """ -ckwg +31 -Copyright 2017-2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling projection operations of a standard camera model. Note: the image coordiante system has its origin at the center of the top left pixel. - """ from __future__ import division, print_function, absolute_import import numpy as np diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py index 9db0436..bfcd3dd 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py @@ -234,36 +234,11 @@ def save_config_settings(): PAT_BRACED = re.compile(r"\{(\w+)\}") -LICENSE_STR = "".join( - [ - "Copyright 2018 by Kitware, Inc.\n", - "All rights reserved.\n\n", - "Redistribution and use in source and binary forms, with or without ", - "modification, are permitted provided that the following conditions are met:", - "\n\n", - "* Redistributions of source code must retain the above copyright notice, ", - "this list of conditions and the following disclaimer.", - "\n\n", - "* Redistributions in binary form must reproduce the above copyright notice, ", - "this list of conditions and the following disclaimer in the documentation ", - "and/or other materials provided with the distribution.", - "\n\n", - "* Neither name of Kitware, Inc. nor the names of any contributors may be ", - "used to endorse or promote products derived from this software without ", - "specific prior written permission.", - "\n\n", - "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ", - "'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ", - "TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ", - "PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE ", - "LIABLE FORANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ", - "CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ", - "SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ", - "INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ", - "CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ", - "ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ", - "POSSIBILITY OF SUCH DAMAGE.", - ] +LICENSE_STR = ( + "Licensed under the Apache License, Version 2.0 (the \"License\"); " + "you may not use this file except in compliance with the License. " + "You may obtain a copy of the License at " + "http://www.apache.org/licenses/LICENSE-2.0" ) # =================== END GLOBALS =============================== diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/nav_state.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/nav_state.py index 1379a5d..0b4adfa 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/nav_state.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/nav_state.py @@ -1,41 +1,9 @@ #!/usr/bin/env python3 """ -ckwg +31 -Copyright 2017-2019 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - Library handling projection operations of a standard camera model. Note: the image coordiante system has its origin at the center of the top left pixel. - """ from __future__ import division, print_function, absolute_import import numpy as np diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index dc1302d..c43ae36 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -2282,7 +2282,7 @@ def on_menu_item_about(self, event): info = wx.adv.AboutDialogInfo() info.Name = "KAMERA System Control Panel" info.Version = "2.0.0" - info.Copyright = "(C) 2023 Kitware" + info.Copyright = "(C) 2026 Kitware" info.Description = wordwrap( "This GUI allows control of the KAMERA system.", 350, diff --git a/src/process/nexus/nodes/img_nexus.py b/src/process/nexus/nodes/img_nexus.py index f33d892..ea0d2db 100755 --- a/src/process/nexus/nodes/img_nexus.py +++ b/src/process/nexus/nodes/img_nexus.py @@ -1,39 +1,6 @@ #! /usr/bin/python # -*- coding: utf-8 -*- -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function, absolute_import import os import sys diff --git a/src/process/nexus/scripts/simulate_heading.py b/src/process/nexus/scripts/simulate_heading.py index b477d71..e66bfa3 100755 --- a/src/process/nexus/scripts/simulate_heading.py +++ b/src/process/nexus/scripts/simulate_heading.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2017 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import numpy as np diff --git a/src/process/view_server/src/view_server/image_view_server.py b/src/process/view_server/src/view_server/image_view_server.py index d3dcc4b..6f5bddd 100755 --- a/src/process/view_server/src/view_server/image_view_server.py +++ b/src/process/view_server/src/view_server/image_view_server.py @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import os import socket diff --git a/src/process/view_server/src/view_server/image_view_server.py.bak b/src/process/view_server/src/view_server/image_view_server.py.bak index db24062..64cf8c7 100755 --- a/src/process/view_server/src/view_server/image_view_server.py.bak +++ b/src/process/view_server/src/view_server/image_view_server.py.bak @@ -1,37 +1,4 @@ #! /usr/bin/python -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function import os import numpy as np diff --git a/src/process/view_server/src/view_server/img_nexus.py b/src/process/view_server/src/view_server/img_nexus.py index 94a73db..425a534 100755 --- a/src/process/view_server/src/view_server/img_nexus.py +++ b/src/process/view_server/src/view_server/img_nexus.py @@ -1,39 +1,6 @@ #! /usr/bin/python # -*- coding: utf-8 -*- -""" -ckwg +31 -Copyright 2018 by Kitware, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Kitware, Inc. nor the names of any contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -============================================================================== - -""" from __future__ import division, print_function, absolute_import import os import sys From 43dd53976e430fc612dff03d904e3e8ad478b884 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Wed, 17 Jun 2026 14:16:30 -0400 Subject: [PATCH 120/139] Make the icons a little prettier --- provision/start_stop/desktop_shortcuts/KAMERA_HALT.desktop | 3 ++- provision/start_stop/desktop_shortcuts/KAMERA_RUN.desktop | 3 ++- provision/start_stop/desktop_shortcuts/kamera_gui.desktop | 3 ++- provision/start_stop/desktop_shortcuts/reboot_all.desktop | 3 ++- .../start_stop/desktop_shortcuts/reboot_center.desktop | 6 ------ provision/start_stop/desktop_shortcuts/reboot_left.desktop | 3 ++- provision/start_stop/desktop_shortcuts/reboot_right.desktop | 3 ++- provision/start_stop/desktop_shortcuts/shutdown_all.desktop | 3 ++- .../start_stop/desktop_shortcuts/shutdown_center.desktop | 6 ------ .../start_stop/desktop_shortcuts/shutdown_left.desktop | 3 ++- .../start_stop/desktop_shortcuts/shutdown_right.desktop | 3 ++- .../desktop_shortcuts/turn_off_physical_shutters.desktop | 6 ------ .../desktop_shortcuts/turn_on_physical_shutters.desktop | 6 ------ 13 files changed, 18 insertions(+), 33 deletions(-) delete mode 100644 provision/start_stop/desktop_shortcuts/reboot_center.desktop mode change 100644 => 100755 provision/start_stop/desktop_shortcuts/reboot_left.desktop mode change 100644 => 100755 provision/start_stop/desktop_shortcuts/reboot_right.desktop delete mode 100644 provision/start_stop/desktop_shortcuts/shutdown_center.desktop mode change 100644 => 100755 provision/start_stop/desktop_shortcuts/shutdown_left.desktop mode change 100644 => 100755 provision/start_stop/desktop_shortcuts/shutdown_right.desktop delete mode 100755 provision/start_stop/desktop_shortcuts/turn_off_physical_shutters.desktop delete mode 100755 provision/start_stop/desktop_shortcuts/turn_on_physical_shutters.desktop diff --git a/provision/start_stop/desktop_shortcuts/KAMERA_HALT.desktop b/provision/start_stop/desktop_shortcuts/KAMERA_HALT.desktop index 3ca9333..bd3d01a 100755 --- a/provision/start_stop/desktop_shortcuts/KAMERA_HALT.desktop +++ b/provision/start_stop/desktop_shortcuts/KAMERA_HALT.desktop @@ -2,5 +2,6 @@ Exec=gnome-terminal -e '/home/user/kw/kamera/scripts/kamera_halt.sh' Name=kamera_gui Terminal=true +Icon=process-stop Type=Application -Name[en_US]=KAMERA_HALT.desktop +Name[en_US]=HALT\nKAMERA diff --git a/provision/start_stop/desktop_shortcuts/KAMERA_RUN.desktop b/provision/start_stop/desktop_shortcuts/KAMERA_RUN.desktop index e945c6e..11e8d68 100755 --- a/provision/start_stop/desktop_shortcuts/KAMERA_RUN.desktop +++ b/provision/start_stop/desktop_shortcuts/KAMERA_RUN.desktop @@ -2,5 +2,6 @@ Exec=gnome-terminal -e '/home/user/kw/kamera/scripts/kamera_run.sh' Name=kamera_gui Terminal=true +Icon=applications-science Type=Application -Name[en_US]=KAMERA_RUN.desktop +Name[en_US]=LAUNCH\nKAMERA diff --git a/provision/start_stop/desktop_shortcuts/kamera_gui.desktop b/provision/start_stop/desktop_shortcuts/kamera_gui.desktop index 7cdf0b8..38b7e59 100755 --- a/provision/start_stop/desktop_shortcuts/kamera_gui.desktop +++ b/provision/start_stop/desktop_shortcuts/kamera_gui.desktop @@ -2,5 +2,6 @@ Exec=gnome-terminal -e '/home/user/kw/kamera/tmux/taiga/start_gui.sh' Name=kamera_gui Terminal=true +Icon=video-display Type=Application -Name[en_US]=kamera_gui.desktop +Name[en_US]=LAUNCH\nKAMERA GUI diff --git a/provision/start_stop/desktop_shortcuts/reboot_all.desktop b/provision/start_stop/desktop_shortcuts/reboot_all.desktop index 298294f..a040e31 100755 --- a/provision/start_stop/desktop_shortcuts/reboot_all.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_all.desktop @@ -3,4 +3,5 @@ Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.s Name=reboot_all Terminal=true Type=Application -Name[en_US]=reboot_all +Icon=system-reboot +Name[en_US]=Reboot\nBoth Systems diff --git a/provision/start_stop/desktop_shortcuts/reboot_center.desktop b/provision/start_stop/desktop_shortcuts/reboot_center.desktop deleted file mode 100644 index 2f4e2ae..0000000 --- a/provision/start_stop/desktop_shortcuts/reboot_center.desktop +++ /dev/null @@ -1,6 +0,0 @@ -[Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.sh reboot center' -Name=reboot_center -Terminal=true -Type=Application -Name[en_US]=reboot_center diff --git a/provision/start_stop/desktop_shortcuts/reboot_left.desktop b/provision/start_stop/desktop_shortcuts/reboot_left.desktop old mode 100644 new mode 100755 index 634f0bd..9110aad --- a/provision/start_stop/desktop_shortcuts/reboot_left.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_left.desktop @@ -3,4 +3,5 @@ Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.s Name=reboot_left Terminal=true Type=Application -Name[en_US]=reboot_left +Icon=system-reboot +Name[en_US]=Reboot\nLeft System diff --git a/provision/start_stop/desktop_shortcuts/reboot_right.desktop b/provision/start_stop/desktop_shortcuts/reboot_right.desktop old mode 100644 new mode 100755 index ef12ed4..ef22552 --- a/provision/start_stop/desktop_shortcuts/reboot_right.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_right.desktop @@ -3,4 +3,5 @@ Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.s Name=reboot_right Terminal=true Type=Application -Name[en_US]=reboot_right +Icon=system-reboot +Name[en_US]=Reboot\nRight System diff --git a/provision/start_stop/desktop_shortcuts/shutdown_all.desktop b/provision/start_stop/desktop_shortcuts/shutdown_all.desktop index e0e883b..dfc7a16 100755 --- a/provision/start_stop/desktop_shortcuts/shutdown_all.desktop +++ b/provision/start_stop/desktop_shortcuts/shutdown_all.desktop @@ -3,4 +3,5 @@ Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.s Name=shutdown_all Terminal=true Type=Application -Name[en_US]=shutdown_all +Icon=system-shutdown +Name[en_US]=Shutdown\nBoth Systems diff --git a/provision/start_stop/desktop_shortcuts/shutdown_center.desktop b/provision/start_stop/desktop_shortcuts/shutdown_center.desktop deleted file mode 100644 index d90c2ff..0000000 --- a/provision/start_stop/desktop_shortcuts/shutdown_center.desktop +++ /dev/null @@ -1,6 +0,0 @@ -[Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.sh shutdown center' -Name=shutdown_center -Terminal=true -Type=Application -Name[en_US]=shutdown_center diff --git a/provision/start_stop/desktop_shortcuts/shutdown_left.desktop b/provision/start_stop/desktop_shortcuts/shutdown_left.desktop old mode 100644 new mode 100755 index 4ab9709..d654116 --- a/provision/start_stop/desktop_shortcuts/shutdown_left.desktop +++ b/provision/start_stop/desktop_shortcuts/shutdown_left.desktop @@ -3,4 +3,5 @@ Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.s Name=shutdown_left Terminal=true Type=Application -Name[en_US]=shutdown_left +Icon=system-shutdown +Name[en_US]=Shutdown\nLeft System diff --git a/provision/start_stop/desktop_shortcuts/shutdown_right.desktop b/provision/start_stop/desktop_shortcuts/shutdown_right.desktop old mode 100644 new mode 100755 index 2c04bd2..34ea00c --- a/provision/start_stop/desktop_shortcuts/shutdown_right.desktop +++ b/provision/start_stop/desktop_shortcuts/shutdown_right.desktop @@ -3,4 +3,5 @@ Exec=gnome-terminal -e '/home/user/kw/kamera/provision/start_stop/kamera_power.s Name=shutdown_right Terminal=true Type=Application -Name[en_US]=shutdown_right +Icon=system-shutdown +Name[en_US]=Shutdown\nRight System diff --git a/provision/start_stop/desktop_shortcuts/turn_off_physical_shutters.desktop b/provision/start_stop/desktop_shortcuts/turn_off_physical_shutters.desktop deleted file mode 100755 index 805a5ad..0000000 --- a/provision/start_stop/desktop_shortcuts/turn_off_physical_shutters.desktop +++ /dev/null @@ -1,6 +0,0 @@ -[Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/noaa_kamera/turn_off_physical_shutters.sh' -Name=turn_off_physical_shutters -Terminal=true -Type=Application -Name[en_US]=TURN_OFF_PHYSICAL_SHUTTERS diff --git a/provision/start_stop/desktop_shortcuts/turn_on_physical_shutters.desktop b/provision/start_stop/desktop_shortcuts/turn_on_physical_shutters.desktop deleted file mode 100755 index 99655e4..0000000 --- a/provision/start_stop/desktop_shortcuts/turn_on_physical_shutters.desktop +++ /dev/null @@ -1,6 +0,0 @@ -[Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/turn_on_physical_shutters.sh' -Name=turn_on_physical_shutters -Terminal=true -Type=Application -Name[en_US]=TURN_ON_PHYSICAL_SHUTTERS From 86eb3f262a60689ef3f297b0850eb4529796a241 Mon Sep 17 00:00:00 2001 From: Adam Romlein Date: Wed, 17 Jun 2026 14:22:22 -0400 Subject: [PATCH 121/139] Make them a little less scary --- provision/start_stop/desktop_shortcuts/KAMERA_HALT.desktop | 2 +- provision/start_stop/desktop_shortcuts/KAMERA_RUN.desktop | 2 +- provision/start_stop/desktop_shortcuts/kamera_gui.desktop | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/provision/start_stop/desktop_shortcuts/KAMERA_HALT.desktop b/provision/start_stop/desktop_shortcuts/KAMERA_HALT.desktop index bd3d01a..14e254d 100755 --- a/provision/start_stop/desktop_shortcuts/KAMERA_HALT.desktop +++ b/provision/start_stop/desktop_shortcuts/KAMERA_HALT.desktop @@ -4,4 +4,4 @@ Name=kamera_gui Terminal=true Icon=process-stop Type=Application -Name[en_US]=HALT\nKAMERA +Name[en_US]=Stop\nKAMERA diff --git a/provision/start_stop/desktop_shortcuts/KAMERA_RUN.desktop b/provision/start_stop/desktop_shortcuts/KAMERA_RUN.desktop index 11e8d68..22002b9 100755 --- a/provision/start_stop/desktop_shortcuts/KAMERA_RUN.desktop +++ b/provision/start_stop/desktop_shortcuts/KAMERA_RUN.desktop @@ -4,4 +4,4 @@ Name=kamera_gui Terminal=true Icon=applications-science Type=Application -Name[en_US]=LAUNCH\nKAMERA +Name[en_US]=Launch\nKAMERA diff --git a/provision/start_stop/desktop_shortcuts/kamera_gui.desktop b/provision/start_stop/desktop_shortcuts/kamera_gui.desktop index 38b7e59..e1a7333 100755 --- a/provision/start_stop/desktop_shortcuts/kamera_gui.desktop +++ b/provision/start_stop/desktop_shortcuts/kamera_gui.desktop @@ -4,4 +4,4 @@ Name=kamera_gui Terminal=true Icon=video-display Type=Application -Name[en_US]=LAUNCH\nKAMERA GUI +Name[en_US]=Launch\nKAMERA GUI From 8fc389b0297e4d98d96b522548beb4ec608f711c Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 16:38:52 -0400 Subject: [PATCH 122/139] Remove seal icon (it was a sea lion :( ) --- scripts/kamera_run.sh | 2 +- src/cfg/seal-icon.png | Bin 27077 -> 0 bytes 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 src/cfg/seal-icon.png diff --git a/scripts/kamera_run.sh b/scripts/kamera_run.sh index 4c0f427..e2ebe6e 100755 --- a/scripts/kamera_run.sh +++ b/scripts/kamera_run.sh @@ -180,7 +180,7 @@ blueprintf "done\n === Starting System Control Panel :D === " set +a gui_splash() { - notify-send -t 5000 -i ~/kw/kamera/src/cfg/seal-icon.png \ + notify-send -t 5000 \ "KAMERA" "Starting KAMERA Control Panel, please wait" || true } gui_splash diff --git a/src/cfg/seal-icon.png b/src/cfg/seal-icon.png deleted file mode 100644 index 1e54e35b48923f5a4d65b6f0c2845050c560d353..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27077 zcmX`T2|SeF`#%26*k+21Eu=6*_Uw@*H1>VZQV~LyC~F9VNkb~KWhdE2kuBMmO0qA> zmZid2Bm3@u=KcBp{`ImA&U2pgoO9pTeO=cr%E&;I?$o(c5CqX_YpIz)5Da_@gAml< z!%eS3C-8yVURP5MIwAkhZYYQcuORPhS$RXyX(sX;3`$LB1259}XzQ!f{5j3cM9n3U z@t7WhxFKz|Yi19}mKy?mn1>UUL#Bevhu(QyLc}yR#W3}L(`)p*!pSd{a^+7;)Ym^L zBj2t>l{siHbJMcbf2J0D)xA7I&>y+o#mIr;#@CBQCF38+D9H3k_MDgcrX3QW#qazQ zdZ}VkYQ8!##T9rl*?MTgd}xa@ypc3R8S%Zk`0vr9Nk8RP#w!#*#>aJ+l`XDcf9)DN zF)=|2K@2(h`P5I=*`NI0gP_{l+Wje)d-pD7x=Ad9e><{XGwt4@kv$|;HMYyH-(wYd z*j?97j(3`z@v+A=R8YH9#qXE8qQ>jZO-C!9f_dNhAUM=4$C`Z8E6Ql|5gvtIagIM; zD?QmSP24@`_6$*FcVLE^LrSrT!|w%3U(9z8wn{_wX+LFu5L=)>UMxM1F78N~I{ND$ zbL9dY=aPCjpetscBo$M3Gql5NQ?_Z3Zb{E2}h?FOTYdf2Z4n6!D zI`7BL?vUZA{)`dB}Pe72`0}8-=F88TKC7Bj>e6m4#}4Y zr9I$eqM6Yfk*IvY`AnnVm%49oQ1uF_S&shRx%CLHL!5XU?ZFqxwsH%bfQzA|41a>7 z6$1_OPHE%5E5l2}2-NFuD%Q4#zga6h8@A5+?oy!Dwo~0okh4@L^P0*70(rIiG7ev# zcSBJ9){h$uYHwr~ZU%1+jfx*O?9HW}%lrP``B`edW83o!!Xbx$xHzx~eZJT&!;?+J zoZW+8^r2ep4h%ta`7YMm9m1tE%0~-^DUS+pgjVV9uBu_18(x#=<-G9XZJ6ij-){O2 znJe-~w#)S%ZYZBrAQsr^(wYVHevFhkRID~0h)U>7+0%2TZ}fS!v8!SUebSeBqTVSx zL(QjzotJ0D9cbAcP~;^*-d~^5cC|YDEB%i;>n*c^&fvY-}Slx0B!BAUL z;Et+4-e1Cd+t|@CGrZ&Q_=vtmRK^lk=mqnNmP(r%Pcnjc>ZYDyUY|{BO12G2G0|~& zo}w`)Y`dp(q7bw-WZ{ceo5>w5)(Qq!{AA)4X<`k7zIRWNry@sUk%{x}iMKu3A5NT& z(WO=W#;!?A)sTA$+@2kLq_ZJF$Q{Ji|e#Ml{$Tt3a2K#pM`>7aX zPXH~$%0l@bICfGjYZ;3%Wv7B>oMSF}*8gj}wz@d#ob?Wco&V4TPQ6(($$|0kjS+2D z=yAX;gz+y+yNgSUi;v<}ZrtFoi}`{;AIW(S>dU5x_I|~qj^rpH9dAC_NG##|rRtxI z0?uc+l-^3U3C);9O0~U|o$wjN`EUL7?q%3}6k`%ixI6i1qdSan*mQEx6jieHo%&?H zKUck9zj+FTlF#KL-O~E+MNW%09eUZ)*ZHs7w6Z-_fTyI3+hHerulUTPz*<}|t^54F z$TXPBXR0w+LX*29p5L%1ZIkBA`P*2+M+dpsRGE9JrA60ub)Uvj9IL6SQq1YPcb5N_ zVLyfL5;V={4Q?C^359S81E1e$$FDc$9v$p_MfJz>#%9R-x(<*wBy?PU!j8iw-0$5R zdW@2&c|M!I@p*G$@M?T>=G7oX-uD!#BJFrS$ETm)GeU?wGX$E^G+*yuqSV38Dp#x& z6Tg8T3x*$Dk1*MH2WgZD^xW>hKfw%pp-01^ z3~g+K(sa`Ls``VUzbb7@Z2FwKzdRx#q>X!(A2sU!<8UCk(M&p9!T&EWK2`_1jYnlC z@HuzAGTu~QnQTZy+h2rGYHDb;)pR*;MJk`K&o4+|2@RPYJ*k(47rtcaaR<33e_Z)6 z4!%d~$)L`YjwFChlA6DDR(IPo^k7^KVZ87PdB?ME<-?n=Bq;>?K~So`;7W#^w^P4= zh1+lm8)nRHGsYs+Q1Kt7LyY;D92TM7lP))?OG_u`1%vLht8PxeFw!YLU-1R68LEdc z7Bmcu^_~nGzgI2T$)3!{*Dx0&6^TbZH5m(9dRKk+k*uN89xnsdj1kM0$1IRH>N1!g z5dEt+^w|6LQf&{L>aAhpLFwafh9Qg_neds>$Bv`!*Q>RgrMqJqu0N=_H~xVEtHpwG z_3F<0c(gr!wbYg~^zZ>6zR*vErnYJ8ohJ+Jyu*vDXZ_z6Nc#VLpxOFDxhJ5?fiL#s z!QZ;mAyb-M!O|E_4G4NF@k7f0?@dFViS3nfB&q%sw0t>muB7g-&hFZign_@~o=p=Q zTGhTwKdxXjX4=zh!0$iZb4VC){o1}N8_6J72UnZH68_e$HY%(hxOjN*#gvi1)j9R! z-3@k#)~d&SsxbqBCSK?a`&`|)^)7tMzccC5kwikp7mrf83Wu*}F!)0I7zrIg5b&Qp zdq$-_&9A(N9Fo?TrKRA7y>e)aVV~(Wz0mw3WRu4!)rmK)+oZD`?`TC15jncQQEG2B z)cEk+P@h8R@uR6U)-+j9CoJKdv&w4INyu<8VQXpFf)V>#^1;9csdsg2$@5R!v(&@M zZM|$#7!BwBqe*>zeFhzui|Efz|NaL3t@%1^U0qX?f{{nnHv9{o@Mj?c1!k7 zrN@LkR`6XJGR|bod$nOls5^y@L&i+Lg^SlYH7za5(duaG2Etg}8G$x`9(S^NxVI5J z+XWU6iMh^%ePzei&er)eaOqtM@7n%Ssp+j@p4yU#k|pe5az0&UO=?Ri1XMozD^kE26R|_K)B#YjX z=guy+C@q2G3Llj%e0j>cL%CJ$w_;7l;Fiw&-e+L|HWfNVG&ja-CH@Sk7RW2nUircq zvTKLIv)KXI_a<4yYT(aY@1!6fKHaABuJJTa;bpfUW^&rx!&8ex#g~z7A#2HupQ_x3 zH8Oa)@mIF`ROz>xN)v@G7w3ZM_%Ha*6NXO$nCl8!*=}GVKl&_~UuCADbfpaxwPh!ftR;s5mV>wdwhPOVJEZt^{ z6sP400GX9Vk#pWsyHhVu*zMh@yc?IH0`~rm{W1y{6P>yrZ>=KGSGnSPhnvnrxVKD)2?HfV z#THMlGkm!JtJM{HZ^&dqc$IK_ndT(*vK#j4uisyu9%w@hm(ZVGNR?Trfd;>oF}pOW z8VP3X%v=nMQ;+oJ%OEzF;Hw?o~#%e;2_WL@ot%3-2PVH^B&$RGGe7c9LtB&BBMHu071Y>OM zAcu^*R#7{U%^9(NjF-cp|GV=3hy2*{D>=QrP_JX~}DC9sO3Ps5&gsc#IDr%+rO%`{SeezItjtJx2%_kq z^yLNV_--fRDinO`>yY!U27=wL zbnjyBco4h*?2SaTc|%YMLUl2+H6W3i+U=*wdFLA-*wqnbZrv5oZ3|jH|Gz)kKPU?w zjZW*1{Zmt8Vo>l~oxBj(gTgL{zo~qrbf8w`FkEtr=uLfIg7&I2=fi2(Gl}cM!-v>m zU)@3JZgE<$*D`|SQ603m2lMqQ8Qhi^RnTg^AOh80>Re0`d2=J_vMX4JoU%X%2Zwhq zsSmVeiY_Sl`FQmxh;(8HrP)b`;R}NWOX&TlR!Qc6IeFE(d864jQkH3pbrdj{W}r4Cp9-Yr5V< z$Ns6$%L$~gsw77Mi3g?o%ird7vFob${PZ2ZRqK+PE7A#`RgR-o0UlLw;TWUfx4b4D zw5dpO7o^g3Z&LeIh5eW4W4b1VzaMkMy=~mA&ff3QN2`6EYzWe|-zqXK_#tnpSmVDs zDe8>j`F(eH{v+vgWAK5F{T9dppAl%D6?Wdd%^3jQD52&`mqGVX=Kat7w+^;fbdz=; zNd#>JZ{@gPm!SLh;s zQ<(ztS(&ICUJ&Cmya_>iYKo%+1CnpO`1m8iDOGk}W|Nnp*6m3dt#DpS&42bXEd*q% zp8R~i)7hn>VG`GKm*k(SVG3QW1Hm@>_7Zt}>Bl=zqFfsOa@*?qYPn{iw-`d)`>wKu${!*4a*OmL(QiP@`CjK*!GWv}h7!8^1FF&9S zzqp$_kY)4PR`Cg?!Fk1pMpiv~DUx~0kzR7yAuftI-;EiMHs=;}A zpLPqCuP?Z!vhYx>qR+h1Brm}Ctq>!GV|sGtf@JVM2Xp(6AJ>iBvx1GOFn$;0eFTid zmC;8j0f%&$FzhPN3*`$CHLj_u>ay{4#u@G~2yD87piNmE0W4PNdUW6e5ZWhkOI}6>kUi531FU1A%)muK`&1`KzW9Er z6k1TUmVw}3NwfXpG}<+9a+DIsbno81O!!z|pEz^~KFzRU{3&-;^Yfo4^jzD_ef#@? zB(3FzIvHtcT8J6)sj8~FsHil>y~e8B`0vkGdJIf#Rb45|08!J&;AS{=S?m0prfWP+ z$#;4K#Q4B7e6+jvzMY+2^%s96VZ?WL?HAqxUXbuSKf$Dptso)u(PB|Sm%Xl^{veU= z6E_PB%WXD|{G1&0Yzkz3r($b$D?eKJO|E#R6 zP}!Q?x;3E%y_XeZ1Yc%qW`YS{U=Z_pzyEK0+pmJqbOnm>pAO_(~K`_YvqNG7Oou*4G({H{MS>H3R0j* zs?^J7O(v{>gPxHN%_WwN(GT~=3HdJO{dW^Ia*Y|H)XD+))MdR&_3(I)M00cQ8sZ;S z2!#9a;R7YcPyV^8XabTkkQ)Z^#y;;$@9jaF1y*nSlf>`D4peO{P?)7B_z+0t%B6cJ4`!iYc?vDT-zETLGZu$1UVE zDENzlncPk;+f+Dp3oU32*u&_AV{ItTUFU9isbV?3qXV}KpE`}iBab%(oKL+}F`%Ww zaPHJ;r&NRy5(X%t`*JrN0f2A((L~cXG^Fn8=JpSi${La>-va{!E#)%|Xc{*AmNt=) z2A;hgPV3rqpQj7V+IM9-lIj?f>j8%XTd6~Hj9DRr$8^UVBF@xt{F~;E`(w##uBG+s zr=rv_{T&@TZ;3?4%a<>oh0WJd*H=`;`}zAEv~V9#n^(zJ>oSdCr6-Oax^_ z#Kcl*L1wrn6}a3bGx0ezEGOE%CpZ1uvm7H>$au(F1Xt``X;-uB*X;ps$PYmmE?lSt zLuM)kr(TTL4gqA!6H(=ECL_l%5lH7^n8>uDHuuw593vPiEN9KXgcQSp6zF7!Z~&{T z6c-g;t9!5GO2esB~J}NC*jy3nb z3!X2M6gtY_my55P5jUUfA`=s)qk%D-FSct-{(z_G@|+Nkf@2X!3k6vvMr`eBK|u!( z)*j4p3{Vd|Fo*e$uh7tI;?dzvOwchc=MrV>$orQPdWD#<4Q}V3G8bMHW5US1l2=b| zf(bW1+tDhRj$Si{EewJzZa#SYO|E(-M#a;`B}(wr9e&)7)RZ`UbaGO(K65V;b_~wu zpj(Ct+q9>rr{TkQObFy5lKqnb3-5i-nJ(_N&UAJkHA`DtTdy9)qs_sici-<=@Ek`O zK7!LUd;|oQj4=Lv1_$5_Vu}!N?%B~)j-=chfnD9ClRS z-Qo-_d8ez|`9&DlOlO$RBGYN)Oi_na_LgL}V@eKC2cmp8Qbu_~oj_LjSu;NGN=HX0 zs8(4F@c>L(xcTQ}PLAE1+~iyR4rwM7i`CY}-*Nlz)`Sx&53lbg>cFoF9qL?!HL-+z z5_eV%n*tnSJ1(U;LC{o@M6MB2+`H^w94;)C)Oj>BgtjDK4&LA7#W-E`R&(Ufe4Ug_ z+Ii%}A)S3q_i_Za^xXhYBSwVvBu4_Jj^HXC7`!v+iE+;^yy>2aichOHe6YY!tX5>I z(j|Uwz6?p2A9I=*e5P{agL{;-WJ3Mnvr^ju2Ib+^>pf=(BIn4-`ARJgK}PD9@?dlYh<=%B47$AmaENE5e% z=OsLMidl$}0JRk$amKe^zIehFVmavBFeXk*P{Z71(|BE0)^9%eXV0KHKR>_2UFJqy zw^Ni$>H_$=hbW|8hJ00$Hzz5b0u$H>eqQAhv&%!I$*WdQvF0Oa``LV3&lMXP?*@uO&xgO@UVw~S+Ga+ z`}gL-9#mJYjNUAE=3>m=Epkx$uuSh<{X!pwSf8QAVa%su*rf{V&zmJ*2s2Q}FvLq- zFJ6+5Yk<{mR0)ek0eyz^(OQe^C^xg-AalBRonbT1?G;NLj*827@WLtcEK`Pjogoq* zw@H4vaJGu+@7~9h=@RD~r~Q?t%DOcSdLRL_t?taL<9x90zes@_;eeHxu&MK=`Ahc@ z@Ekuzq+mUAWg@~`Gx3H(OLcRv5ema#-X`{rLUk2t>TG9rd%4$6$Kux0QxyC~9b=w- z2hYIwg6}O&{lWe5_@J`pAyX3tGsdX&StneeotRgp8NEKJE#;W6T>MJ&QoMAO^c~e0$4pLn8$iIRpaJ!7~uM={5+eDUciP+ zZEamFC^B;&tEl(xec}zP$VRny+ZOU>zd_AEf`^`A(92Y`N`9=OcAX+~tjs~v1C8qU z4aVEC>3yIRvqa3e#244p$en?HNnqP z`4NP$hU!XoI#I!e`}J-#Jr--9G>>Q*4lW)>G}A-x-A5(gBxJrk5K$3)c6IB!sm5*i zLvUp5@v#U9Li66zqJg0MYttlKM?B6w{%)zTnfVRIu)t;t}M5mCcyy0F}4>z|ZHMQQiHj9CiV#oyR@zrEXom;&J z7sE{44kBVziWClJQ&d7KM4qDUEdYy7V(Xa1HQ-SO2w0ot=GL(7aI^=!argJremy>i zHztCq1_c!r&bCF8nbmMMbvdof)-*hwV^-`eXxo0meMfmK?EXNvI?)D)9 zX4)AdOkAt|MUjU#mbb1=RoMs6w*DQmcw2h2@M{2PAVVZ^aYK^HsIS;lrHA%npU1w# z!97vA+~Eu3hyR3avqJY$Fu3e#8nzJ*BT<^oovF~QGpVriR|Cxqc^LyeJ;ihj27dqn zksS zIWRt6ytTRcUJZlx`1mW*XQX#}UfQAm{O(eaimt;dwV#*DF-ebox#&wLo6dskJ)2m4xsq zN4ad~!+<0Tor@ntJ7M}|O+ROG)@xZXZ!4?`TewZIDh!}+w~`v_rnSdncLeh6RoujJ zA&aBmtFedB>f>LdvOjsRqxNX8$YfQoiWY{YO9xq6@qP-#b#ID>J!vc>XL)07cqNZo2GvC(TUkUY`kQj09`MTurGF_57)tf`@) z!PFcK?xNZFalcymc;cHdkVD=G+YBl>O+HaQy5+GyC?y4M1SoGWz2^Wt2Uj(zy6;WKrHE|UBuL?zYxnI zRY?B#Rvs~8qmdhZ^cT&rXz@uUCmXSJ(sh6Ljju4Ai4GNdW;aLm34FHe_~;#kq@Vf?gN^(<4k(NvOYap?Xc`C=hH%X(@)D&#ii*M=C+nXt=z;$ z6EnPxd2miQWqqu7yHM*cz!SR`B!%7Cv8m^17_J{^SeqGAb$%TrPO9$*Pv=C(z_vxmfe9dm}H*NdlLV>XKyg;OXGySlI@ z3~jL6GYZ3=Ax*T$jpSGY-%r5hg0QtL=lsEALI;mZDkJoXgAM26IA%_nu zMT%J&eHjgvU6D2;|;n#{YqJ?>+bQSFns)bo4Y9G>+LjDihY?qo?gP@h5vLb%Rn z5kx>_u<*i0TSsJfBVMW?h)PXDt>WgvHfH!d;yzG51%o7E=J+FtMj;Clo>9XxU?3CQy7zcZb zri&7~{T)nuGD}J~Nd%20SgTcP9(Ms<@zh*QsZcJ9@O4yYxvT!*_t~oHf@=5Cmw*<( z-c|nAI^fbrLHw2ev9WVW#L`#M;_l{IY00LCzVg)CLm0Q_UD>S^#I+%J|2hWheeguwc+f(eI5~EOC@q1YEzTJfTcqmG-fFaT@ti_*!qZTa%8! zM#j~k4+er4zOVuD==3LX5&gkeWJy7zV`(e+ngRs_Alp*%i{t_+tkXB*gLeL!4;715 zm!>b;1bfsC2nB7?`Fg6zhIW_*2Lv)?W=+!y9RO&Qf6DmuQv=8)Y6N z_T^gNB@~0VKTABZd6n%l^LgT^|&IREqc%D+Yi7ec?P zzNNgn(M)ggQ%WmO0KeuNVZjZze1H2I75Yubon%jzKOoxX1P|V0LLktVrQQ%Hwy7X;*_}sBp%FLWQCFgn=<2 zYPfYEZZ8bv0Wqt}!A$WvVOvYlYv7IcgU8dX&>Fu{F~$dkY%_+lCR>7N7_0eImdd;6 zK7Hg^sJsf-!<7kdy4~U9huZoRW!dGcuImO^Bx0^4J#}9*GI26`3 zH8r)e4|#jGBawWqWv1IEIttaEQ#}l2pBVbakW74^S;D5S-z_p>m;+ZdVF)zddaMHv zFbfs}w-|^zeO?ofvG)B^BQvDzHKSD>ot`3d@0|MQ)92;lT|GRM8i1q-gydQ7u*JDK zr?cl^KypzR$TKG(2zME=@@Z*lR8aHZi8?@!RsxBuiX5a^rv2Xvs$LAUCmq_wtCV?% zu<#nq7aCF_nHeKSec?rBI_YlH7Ku{8O^{!H^_A#@S3d!FC3rApQED?`2*;yz1m8_I z1_xbZT&olXGVgOT!};xwmQ31glB4gtTXlYYB`csVEkxN%lYSnD-vZ2_0iG_TRQtl& z-3C5i%W1K-33%3{hrxz+EQ$dkhNQ8-O`X=tG3hCw6ij?}%~wazH8p9ZA!tXiIxBeh z*OSY)hKuPw;k0-$w4df(+}&rwoS^Y)Pgw-o@3&=wi3Pb1sH{Y&DgLrNLus77XTFt4 z{4egBt6N4B#rpJ`3y5O0EIH*%lTSEyKeeYsMp6p}Q7o=c_S{hdzbta|V;=_ZGu{c) zadC8W6W-8=g0`0>1o9r#bl#O{Gq_~iSkLXirT9=>9GQ^4c$)ZMum$f`he%H;;UL%> zGX&C{1o&)oNjontEeS#~elvPxBK_8vkk!ec)hdBJ14hEtlS7cnVU<-?3kfC%mM^5* z48*{dO`FHY#wanF_cPBtG|El{@U0jlVm?H&P-n|0_A((83dw0iQCTzOv0Mb<2)unu zN=gzfJ^ow2VPGJ*5*Gx=n^^w?!f*d;%C*+hV)OXeQ*smU1@b0<%)RsFhY7;xXQv*w znt7H5i=8D=sZZY&W$BbTl0l<(kC6RvF?QB89w!9O(pX+4z ztF##G(aFKoFq?yM!1u504h{a30sPc=>Rgkd%Ii>0|T(bccWYO$yr`m zD*;+}@f_?BiBk2{KJ#56^WYj76`QZ$BkE(tPT0w` zSlV#9G2 z8Rm?)wgk45gZkB8(;gdnYe3C{<~>TlkjIn9%<$m8r%Goz?Ux3aH;diSDVDq22}3Rn zkA<*7DSw#l1xy*_ljLfMN{K?PS0FRe;TED-LUBs;2$3XZ=GapY%AZTL+g}pqy5e{=F<9UL z<;Kr1ot1R`E^uDTiPoz}A4{0vfB!l!?~4%?pzF3{gct>~7ftgpT?LD#XN~BIjqgE3 zt2;`OMBGD-%SgNqoYO4Wt{CyOXdlZD;{xNE;UAj?PddYA7ecSCkviG2?ejolNKTLf0jC69 z4T}J@UGfb`^s&mxy4VTk&JFPdJ%;O^D#H`U;@ZucrH$_c83I>^SkECJF8}vlj${## z)x1X?Qk@>h8XA*%<$-;6`Y5QH^%#-duP^&8kF++xfK^Nby?R!4kLoud?ga8=Z@1(& zifeJ>h^1yMIkx7u-$1oW6f2DG^Nuq#X1rpnaRTpMsDA1NWQ1_kfS~Mx?8=20 zP>v%afe*^ojo$PDcYT?xZ{K)KFpe75V{3q2Qd))K zfH!kutDGjd5wrH! z6Oa+o6~qk|Kk7pBt=Vv~V)!AIRyM1W(CVcK<@4}eHUZ}CE+B)qv2o7zo0Vg;a)v;j`=MAdbp@_(WrT+{ zz!HgwS!adbyC4p%7w*?$DMD)&>7izmA$Jz&Hqd>)rKew0+pPL!t>f7Y(^Mc>zI!j5 zeFkEkIrP1m6CK++J&9vT3|^jb*7UN^HBq0>U#wF}j9yc`tnb*`aL2WsOJ#sbF-nvIhOsIL6)&}F=Iy<)09fJ#cWV216@71SDdaN_}Zpu#ZlaZB8gCO9llmSPi&Qc&|5*P4dpSkFNu_X*cRALdrmJ*fn-hJ!kU^I%A zGA%Ih4G&fEYzB^|H%Rn^mv*+XPB9no*_lYffY&FF>#&cX<*#*9NW;b{o{$5Jv ztjN#~5FFVQh}0v)oEKLZS&-;kz%fzvGvq^F-o<3f1mZrZCiel(Id23?b#XKNHS^#} z?QGhRJYMmT!`(OtRZ$0LU7#BwURnR46e(|bb!A5tN!$?l}+OssK@od*)X)NX`XEWbs{;^&{V3K+oH(0qwx@or%ZdT zXR~zgXp_1g&>oUN-^0Msc*!<<;OG_-)Pdw0U{raP2V~52sQ8u{9B5D4IIqD_mhi|r*;nR_09O9j9x*gB15nZe|$%esix{#lzN==B0j>{^bQ@&A1 zW+pd!>a z)F}!^3P`pEI(Mgj(S0;h&zp@MvLH~J744s*GJ8xcMIj4~wrb*3*bh~c$vH<<&KU^9 zdSDbD)DfV?3@@kc6O)}G*AqBgVK!$6RSj%>;>_Uve~ZYQ?W&e3+_tUvf1`5c0V0AKXUu9 z*s&kpFPZ7;&(&lnrH5T*VZ}n2u?85Dq`19Y(JT37@WjLDVX#l;Rmf4ORdGpfNT~Ja zRVc`hB@;KFQ~jPcWOkaXJYCLfhR`OrIu7x^p^wScd~r7Gc(dR!s`aILDBhcMyeU-K zl=8R-V2;7;`7?Wpbw?clwuB{+;SaWY;+PX*s$xcc92;)y+f%1j${?2&5bYoS>?uR3LWDe47tr11$@32VAWrV#mX(!0Wble#xDe+W17p0 z3^lAy-CR_P5XBS5rcctE_BfcD8)UOD;3 zuRg?@PT664EOqKwQI09zK3nC3=aiBv!Wf;r+bYpsmkba6!!ad3dx=K|Y3BL!qw&U{ z%ErdY7sS##|0gN#nr%JK!EEL(ZWzKHr?Xh5do|(zBdE&j{F}0S%inIATikj~g;ar$ zB-{#zF+`zW2LddSsdf8s_n$oajx_r73!<1flCp@bEB>!=p*G$M;0aqV4E+(N44P)V z21R8YI})r*k2!;u%Lpip=#B8xJpt>W51<2gh4nlG@V-=F3HUqoLij?f#zz6y7++m^ z@cImti+)Ayl|?3){HH3KZBZHH6JIY1>yc+#HC+vyDBarde?Saly%_e4LskRT|AX;9 zTJ1Lg)|||4VhykgEJDGq2=&^p|FwDvuef6ea|XZ{hu5^Yfr{AlziI^|LTf(7%_#6< z{}aXG2W<(X6TREO%*C^Qv^-YjmWw3_aU7;^Oo9Vf+cq}X)^~O1XZ(YovIclm6`)W~ zaO-1W0;KRJUBCsEJ1nTHv!%ZODvZRxUEFw$IBhzV40!1s5PYP_C$EgQ^A|o2MVtQom>8GBQwzf8F z{XwBSp3R>@#ccozQ=9rLAgWc_v9*fR>JD!W0^6Zs%gDiBI^Z510H(ytGRRl?qYhTr ztAGVfhGymEExk|nM%9fFnV{K+tC0gr^*IryQ@fqb%DH|nH~w7C+Us&Ywlx~$xKHUI z(nhwI$4A=TxvXFOvH_;AKWK2t@_qK*Lv0l4^jVR@_aem_GBg*{y)h?EZlKFRn`*GI zLS4Pk1Qce74fMQdOJ^P4F6BJo zTu-3kE!+Tx6btJla~CF@qt#WA;_kd4CRI5 z^Dl{HJ&h$?VrO2ph)BP0_Ou3MBO>At2vpMui}$4CQg`QKLG!Kd3PBfoKt&w-ns(dH zlNd=<~<`J$0w&Ibsm^Dz>)rQ%M zN|}M#08O1>!sn+Qd(d7+Y`0E)-q`q>{9uNV{qrH`0dY?)64kPdbQlTrh zCF}lS&^&AOS^34&v-4$&;aQ$RkO;rC&SZ5e=<$dFIRU2m?EAe}1}|fa7Vpaxzzz?{!j?xX zo;XUT5PjtJfwS$heue+P-(ME&ZT&!Oe4zGLT@5oH5r7HH9$Yrj;x>A08{i|BMh_QA zq&#=-+;4oWbsL+Jj=s)96yT-KUgZo~F8lgB(vGeFE^}`G-T(8Tow*?YSu#b>Q9dJo z!6)@qe#%GC`6X$SW&44e%cYuCSOcC{QWg=56I)BZX8VB=!7YH)IzMEhbI{TR42!*w z?Z_4tpwIK1dln5QenHmbW~~6M9*{cH@!viVE=cRP_4wkC=VY5)BDV}~YEAQQChibTw&*ahcJr-gDZ|D+Kgu(Z@ODi& zDv440#RWO9&x9}bl|*9n@b~Zc>m(3436jvL2yVcrMXZ3k=Y~r{%%R*d^(`U$2;1vF z6I*OQNV$r#_J1}H=YpmIm)6aQy@FxH&QziK4brnSGBPTwtCImgbqve~{U%#|zP`TZ z;zlzAmpX&Y_kfCbQYP|L(SPsg#8z&l!%rsWSX3(Pgo3MzW}}3X?k@0K4r&0e6GbIN zKmbEF8SNTVYMhF=yqd`PMyE@9&pvH@el4L^YK=<7u9apr0<9 z8&lRo1Ke8|lW(>@Ms0u3deGwlDroNLX3rg!B{MACalw5wvSo8>W%BFKt6}2W)3eF8 z`ALrIE0V#T<&;!VA@H8z$PyCbVB`f7Ed;7eeZa^39ZE(dQg$?pjjvtUdr@6oeY*Nt zi+CV~5-?xsAsCj@)|jT#Z?M`vk~mXKPhQQcDi9(5U*Ev2Vy-E2#jtfvhfit4@v$L{YvUaE0dCXtLtsGn#OLoo+gEP3Z4qwCH_Xap!Sdem zzNU|mum=SimG+xF&q>GW1(P_!U0K8s03v`^@VgiWEZIh*oNp6sg7-i%xR|^mQsEZzao$8=(y;u^ zsiqGfWUe6|yi{qK#DRGGK9XRtw)31zIkWD_Jr)RfKyLANI-P*>3Zpp8+oV2!Q|2al zIj|g811mHB?ConunoN$5jmhIExkEiwKnoAAhY_NGaAc%?Be;ZgBaG|ebXW}PHSlaO zfVR#R0FzW<5J=uG5mT|WLqouHY;vzDo^lMNCRMqi4!% zT$e*_%kM<-mHx>k2;fl@-lU${$4XL0o+=<$=ne9MuGxGSKdYq61LYz-o0GU%W3ag^ zzU4M4c9=ryt(ojnPDW%C^(&Cc0pBl8%ah|`{jOx`vp8+Z(*6Ps=fmv6{IC8FvE&Av zoKiU&72Bir$2}9rlDnOLjaHnqMUv)I@rFu*2=oQ$c8Bne5b8lf!lWt8NYg zMD8iTBBJEe;n3%N{WOivX|ZuY2|i($do_@4xKIF`^t6y=kC)OMNh*Aknm1t}Zmr)V zG#Ujb6!QG0BFiS=S}TvFlIfK5j)a|iGvA#?YoIYy5dMV>buQ4ojel^&0&NJ1PQAJU zK-B?o0R~Z=E0^WoqB{gPC!?o%0w*e6lqrHWY(D`k_ZO@-q8IQ6zJi59=y-E9> zEV81o8Yrx^8YQ-U0oaq?KoGgbf)XdXmn)BX?s4~Sb|wgF7a zX#d>5Q)2e*?n)dNBo7)6{~hZ$1Ng&}SNRlW|4lap1KK0i z>UrT05C44y1CGH$hTF0sh}>&{u}_Ym6is+JO@59xVW2>IC2kiE#@c!vUHt#N04o?S zHQy9wc%8vjiyf(YiKhrF&WTOhxe02pcmr4VVlh$*UPe zCGfZcpyT&i**Q5mp`cd}=t6rdo}mh>?!w1GT%RIUe ztXA)9^``^>V=>m_K~e9hKr?*!B}7aB`F(hJsjr}<3h-IW6Lr<|iAO+K(bRFNj-cFR zwRwnMjDj*jk1)AKw|TW#LI5ILjo=I!L2$=whNF>N^R}+{fXZE1Ts+9|56iy`f}P^d z(#MS+g*b^H6wu8di}Pes`3*M=bRl!#C9YpXD%t7wIG%rC7E*yhK~{P1Qhl#blZ6JL$hGZEa;0m6(|LIzPW{ag}a&$@av$;>KfRo&QePsSs6o zZ{znLOuH1KaT8{E9pE^-|A|f(U{IGjq*176^Z$uC0C;r1{Pt!mPb@ep8Eo$j-|kgO z$sp>cDJvDu(3}Y6VWr(^iiX-+>&b5S_2^TuJ^>2XOvF&ns1RGp+(T1r5NuoYO?8B3WPtD zWO-v_;~mC_b1BXUQayH(3&J9nKr_3>a8ZY@SOc?u!Jq~()hzhPD*)N@PQd1W@v13% zyOz0~CZswGjW@y~7_qf?q8dEOY>5Od5BOsX+9GF}$}B~$`Yl_Yi7j9zKaoIdgk6VB zYaF>H*oORQ*{A7YyBkNDtZNh>IT?N!q+jXZ(Yw9#cLMb22%6)Y<$6b^dv!sqC0m*2 zg>@i^;6Cy`r#$_tqk@G-@X$29{5pvTR5l`E+rHBOIIfSaRjgI*~SB>B0nz zt0|v77xU9R&Vhd5HK20;$#=PaN0J@1yh?#C&Sg=h*MPR$=;i@e4YhXAcS zcir86hBhCr(7jSos}tp}1?@14k_nLo&lHXiecB6DfW=@4c@xbJXS;09#JmFaPj(8~Z%jbhQ-b#Gu`JfZ zOlRoBJL@W9hjcgDWUV)-=NS{aVa9IqsdMr9y<@hIKAuUeA8yX?R;!T<#!s8J+A3I_D-6W&)bCS4}!n0@c-M2Z;ke{6^Yl3JJxJ}xQZ)kcYIvo$!vM{D*ME#K%pM#-A|ZskgDfFdP@BNS~~A| zD&PN)AIC9{GL8|I!pTndPR4OUCn02K6_SQoC^O^4iL62*D=R4@WY3V5B4tEY_L1!M zd!Ntu_h;vk``q_^?)$pl*ZcK+y{;N6{qxwEQUFwwUpuqzjxei`)xSJYfmv|j8QSQB z-3{s4=qBykueFi&2W~WVHDM?9j)yYWgeomgd2Ky(V%)sAwgn7ua`BnO8Y#0!#LNX} zH7tPH0ldhkFAk3o%>;wS9o=Q`^HFti>?)m_mpr8`guby=A0SxB&N^7>kt1?Egu%S% z+M~J$?Xd!>UMi)eh+-u%qg%e`QiykQ2d1)P)eW%fc&5L7`hTkAJIiT&$ux(K7+XH$ z7|IG*^OLpD{9JL=TJZj-moENP{v0=&Z12{;KYGI_i6-T7wz`3IGLRwwqxbzkf6V!x z!TObR@{D=l^3nRf?283xJ`M!pd4SXYpma*uxN3c(&+h%Yoe`VCul|V5Ob`9~IOJ`v zPFmGnaueon<$g+u(Adv+)4JV2fYCd4CTd{Z;xCO6y^~q`9{bUTJk1B8Lg$YRVnzxu z<5^h5r-*Y>zodRP<2h!PgjT$>z2aH2{6mthO`8DaZ{}Yv0}mzIZT=w1L4Xf?++EH#2^B_%MpcaN+`>`~)si2pNt!d}Iww;mPcRd588BAZw=i7#TAB>3 z+~Fn`cpkc;17g|7`szPQ_?~G@biK_7k5AiCJ+vn|jS!(#zp%_7yy1PY~kV^iC&W0Q2l97}$5LO;bf zY)V#AznB)|JW0aVcAPylLdP?`tmuE=HPogyvv#-6C>5QO{VY0H{`Su-=VTL($9Udj zPcrPd9s?hfSnEiEF&<-Zhuis`P07r0jC|$%jQPDCN6+VSp9jwU`95+j;Skb)wn&9d zG13WXeQSSr>lp|WtaThc=QdK7d}w>2ppAiZ$}^4toAkof`y&Zl>n}9)T>p(6SofV+ z@OMOJlYVQco)X@?n1ue;-~R*^=nZcePpXSdP>GMc0Wk}Ts}`6KNm`l02hZI{(PPTg z-YYGf;AJ_12xN&BVb~v+KZFQ`Ra~)wJvD8SOps*#vXdYS?dD!LiZTWaZ}QBGD}HxG z!pd>mNn&^8QyH6tznkLJ7EtFEaJnHZwxsi;{yVpyJx4@wE7=c@<-{MUW0ri53d3O9 zV)Cijf}(1ihJRf|bR#!}kI#g8gn;|RS{@|bS++!+CgKSsZ{o2(NS834SP7GOXy?@SmNzwEI zZ_kZ|Ni3ajGz2EPJ7wB2n%S)~3##5cZN4cbH_JTOPUpt3UM5i#@jgh-PVk zv{Zcm<$|5Elu{?PU+??1JFU>g!j=X-QYvt4K%8UX#!J~Z(?=o^ByJ^E z0m(}{`)+*r7C;uCylY@a2wq$0Y0A4PMh^q|5Szwn+DCyDf>&mSC<#R1(4Bx+5e;_I zY&UphmYIu9({hyIL6z`uG&npzKdo0EYr#4i9*2anMi#B8=%ZbZ_n_Y zsbvp~@j3Gs9f_(wvK4XxNz=2{L&xeGZD-3$wy=K5rinykLXU<^I1E-7k$f49{w}a` zc4 zP=7bnhKqlUX4iq0tcUb3;{cneAYZc*8`n878rw(>S9&->gphgl)|5nmPyORdqY`R% zji||#4J`J#OISWA#P}M;6Kehsxe+(_?xeJ#F5XBEqkM@Kpv$=)RJ$-ofoY+he~fNd zAgo8@uZU)4 zpg0Hf^ICH4&<2R3+YU&;_N&a@BE*7gVJ}uauWS!A6M72p0Vzfm{JW8lleSkYwU9x} zrcVb32BvQv(n9n7kMOuwVb>H!IKE3vOc<$c-~^C<*nekHIOLBO{-VFx8mx${F4)d} z%ag+C*pg=if@(u{Z{YfSUJ8SCcl z&$Em=XuixlRg3c9x!ywGmtm68nwUuG#saH5!%1Nm?USd8x8w^xU(~2lxHZ_@BMK_M zRQHxnccov7cSd31rFi;^>h?rSx?g~r^E4hN3t0;8eTBfNEuOR69ijPi9vAkhoN58% z9UeV8nIaWV<*(Mh>>RhLJHY78n}O?LIkNfEaf9|c3DcTrOY&0L-<;T!vI5zv?Cm_f zq`?r3wN$&a6ukdXYLQZlIhdEdcAkUc=5w*$-5RNgb!0Z8kH16S%jc~YZ86N z6(65^_b)n8<$(ONy2lC_rkwh#m?H$g{jN(Ypqxf3MtIZ;eT>H##23oH>IrS z3|GW@j#A91j?jLPY1O(+fRL$1NfPO`bJ#7W*p3H&Hc?V_Q30DxJdL0kCLF=xLs^XJ z(@$YF@P{z^A4*F@M(;0zJ4Xj56^CR05*+4YE8U*{7h2qb#Q5(*=r~~s@8C{3&-32E#Ht>0#4>LUGK*A72 z;{1?(kp8nOMtjJ(i;|4v>CBWoTy?*w<8@>ubHZhePWY5)qnN=EhmwFFyYIB5!h2n= zH@}Svv7IzHoLgphdUw(=7eweR4wb(^JUzdA!+}3UXM2mJj)JhAU})?ltS+;>cl=rE zEXBb*msqS^m~r5#{!(pb=L>I^G8t)f{me|7aly7|7$q}6YZ4$i{c=X;=oGg|Sin#r z!1=dCznN=8M}>G5Kk(L~j9{dNxcFTB2`euD#Nqqgm`fLsr-UvgvzyXuQ6U15<)?67 zW6LNS`={9XiC!8!&A=!0mR=|>pmP4&K@EM+Qi_|=8YDm=0-??RM7=qYd(SAoFRu6g z3{QIe0C2m`>1_2K38yndp5DaKv*2_I&NC3iq=dbvh_pBhB1c7r`pM@Eg?b!RYq@hq zdGsY$?se$!M(68iNA%t<{}s&ZN7vn*(w;MS5j?jPDG^`lG}JylJ^d9rn_1n${OI2|Vsj}im|c-wOI<~a9}!$h;8-d+|{jLxTIY4D&LujLtp zOyw`&g#JgyG=hsQ=tXqORV5?ceop28%$G;D++dw6)DAWo|8yvQOzGJAnCKOom+kiS=rEw`vBx`6)rAQdA;CC5C|cc9>SAav(p z#eBPY1kou$DJx)Yc!CnVlsrkYbB9)Xj(dP$jsh?6JQOFIm?RYhOO5b`G^6?U#%!wY z6}o6>fm=(xnJpXj?QYduLu!i*;D67XNhMru=N~ib=M4Lg&Ew*CrFCyDqUh^fV6@Pg zX{!U^-Du1I9sq72TMoS!GWhZHX9uW)keP9q;Hbmh-0{A|zj+-)2&K_+%YRQ0x7y`wHG(dy&P2c}&hoMn8`~6Jn zgD4+C@chfaG`x9N*0ptTHuMmuuV@Q|K|F=iU!O&I8->s?T<;AGdjk+K{c1t+>LsK= z{&sLK{oeD9XX;2NUME8SA~O#8_v~8q?wK=Zu3GPn_{_XaVd zsg>9w-hE<5Pc}>bKOYQBBq!1u7Q_+AGx$Ki#N5V#z0uygF1m}vC2;Lv z`5VcDrsDDHzKpqGuWEtOdZeI87#$+Au!2L{1s;g?BpHCSLtZkJA5%tddk<9jGbecwDGzvl|!&Htd_ zW1BsFDd?+xmL$b1EfnLFiHS)BIQvgVe=6J`u!R~S5Nfg-fMvjh50OK8FYbI4k=@Gv z9JxRn*l|!-Rq*7=T*c3sl%&e4c?o+}WAKRNoXL&l%#4sF7-SKgb+Yj31hv36a0a0b z8?|ppQsEBM;@EQ=s3LG|oG1ao%gG-!F0qN^=ZC$%ou&2m3Bz9h{-5YR+grDmKfO#^ z-6s!smDPOsUbV69w`MI8VYc9xxT7*NEaNegM7^S1D(De%o-oNCf^43jJD!I6eQ)gv zb1fetH&S`?fZ5rROI3lb>zU(UH&lQtq=D9D8jEJ%ym_fJckO6%E1G19%>pv0wF$e$duc@VUsoKVjq_@=@Ps8G5#?TMwD5o0+yn}bAZSQg0g>DUr zDK|z`Zes;JSxs$H#2f8T4=53P&MOWjC&5uIS%rf%X)P~eqWeO~)dK*s#8 zIxV7fU;vy!TFvTNYVBD4Z&B~ikqRYa^e;O4IWMp#w)S&|N4kod+Hi|E{ut==d|TTV zr=G`+&A>I&6qpp|>&R%_t>@i5e(c!8z~8{d%0yRO!BGyW=!U~znyfgVs>p4}MkFQo zN?-Nk5C~$u>Ua4g{YAI6^Rw8L+g|I%0anj$)VDHOapxwj!%^=pJSIi-GF^EG90bc5%xOq#RxNU7+D6JMfe5WKFMy<$chH zV`J;{uN1Ij#nqc*fBn$!xM{j$hu2!d zOH{`=8M-S?hBi8~i1+IJ^%raJ%q6 zYuVsOo_@Ayyv-I!&%Rt|JK*H zTSOTVW@G+Lww{_DB!yd6HNJ9jdO6uumHFxE8tZFo4iRH9O-9{fa_-E^__wyUb-q>mt@4$U^rT$Hg~i1+h^;D{r&c%YXolCa zYe6XOp|r+-xIAc_kjjz$4KMp|b0V5^WZ1OtH*ioj;J=pGC@e#NKg>^AcI;9b;K+2K zP)s{j(vsRMqwY{73x~x4KwT%`{4|>RF^}yp*sjg>hdOJiU%!9<{*S6MFosIcdRnl? z;P450ISvrwA!z)Ag!V^p%`Pp~np0VehX_Ro1i_VXhOkkkrs?G{VzPr@Syg+xQ9?Oi zFphJ8EdLNMR#kV+#wHCK-sbo>SghzXR3mrejjx}NLkGd_rX!C0DK9BkX<>GDrEcZP zT`oR+pB!=pnpDsB;GzyCE4hxT7qVdavL|^rzZY66%yy5)no_thzp95@?rBMEow@@* zuRldm`cMd4YvIU)4Hz;wZui5jn}S3{Co2<9V&ctPw`4&z@HaC0nmDH2ybpS=N%fVI z@^Xce>+P%;@Dapskc{V`udn|aYAqJGpdD^vuGrmsQq@qDA@o@;7lR@3EA&jD2J?8F z8$m>1w8gEfxoA@B;O{l@d0!H_FCpO@KIG*&cgFExPA@GF4h^|*N?50OP4Hs#;RHI@ z|NR>T$Jf-72qwnM8?IfKteuy{5>5kA$0152f=rtKb{-`#`Iv}9;~MS1B~Wh`ps$aD z2dE(~Ex|C1cn26mw~pI;GLX^$&L8K(nx+lEzkX?D1DdtV-<=CDxOBB9_5jeu_Cs|M zz6+bN)$ouJb63XW(w|?W0T9@QA(C%8JBy@LM-WdfaS$YJxRoHSF2KrrseL{?+AoT# zhyf8SzjPR(*=ZF{tnb{)wX8k|E3k%dEOy^K+#{2g>GwN36`%>pndivj=KpT{39)>5 z@5&v$VT!5HOm4!}e!>-22_hm>+#6XN=XzGNV^^}&1>TCp%DRFA7nFTPD&!UT;@`Mav05d4w|-El##9Yh z0Im1<$`em7ueDFIwW9dyM@db`$c1GGdq5#LUK=w|Vrq&s9T?xM>+QVdu?f&BBvF+a z5?uBDObE_=&Go>QUzGlrQ1;#y++G&+QtZenJXVTJn@mkQskG!Xs?Mb^BFD`cgFrmS z+pCK>WW|r|%ec{~A=FJxP3sH^;jK=w?UU+O-V`;281H_4_}mHNsm&ANwT3s-`LTv4#XD)&fJqMUlJuWn|OKNN{g$#B;G+Ebfq&B3fV!l&0Sj3qgxUVt;ISaDWpeYJ9k?MoN9zSIPnl9K4I23#Pa zC3MEz-*Ds(kGc68 zT7f2nBprU%F`ra@JT*k*c8g{QJ1hC5ny&pP0d~cUA=Fye((0$ z{399ESZ}&!Y|;$ZH652Oyk`O2j0J)%_)hw`jCg$iGM|Key5qZh(CT?goYOS-dskC) z&XVe+h0DCA{{BM4BRaY!wGvoiDdTnZ);DBoKr`P`cGP+IN;*B};QQOedJpH?O#0Z7B=dIkF?#WG?pbl-39WR;* zO_$q#f7;a`jzhw+37txu!@Pf$L`}zZ-6>KN-}wOm{H!F+aHf8&ePiLpEux}hcffcf zjYK?&6feCBfWQmTFL@r4sVc{E9;!0eE;B30$tA6*-G{a%j`iJuG-l){gnN+CBXt3F zo~vKSnll=}E``R|0G{_}^eQJk1Yh3$Kq4vgZ322jDg$ zx4Xk{>p zC{v*k2<)+&kP?y9drCX%m6W5Nj$$R?GI~C*MTm3*l4NXCg62f9AX#f?*Ug z)m1Sx-Y^1^GkNxMC;7>LKT8O`DJx4K;~503UO(tLzB$=IzyKY7tMCM+*N}?TXZ^y> zJtF=IFH44jbuP&@w=9*-_wT3tqYAB3+^TRbvT743GQ>}0EbpW)@5J}a@TK+4zkR@QJA$m^E4p)AA$fWOWF>EbxC7jSYEYqW6#A*%05f!sl`D;UYUqBZH z-<0(;^_aQPQS9CVBnb=wX+lt{@L8RXRV*DiqPHy9It(`Ioze!_c;LY7dnO6vzab?3nxfbhnW!dP55qe!Eebdbx&q;#PM=OS zwhj?Pucye+K*EU#ycDX3e#4(wwtDz!3|!8PIP#GFe$_$0fnfbu)oU&u5oqBkxbbmj z9a52n1pa{&H#o^f)8T+@q<=2qG{^E}dmNEimOjxH4sF?|X-MW1)_j|3zH@m;Z!=Q* z;9kP$N%=d&ic`x6lR|2FOrms--CgX~y8XkRTrzyfstG_>_wmZ(;b$BULN`@mP5?9$c8|Qs^7aJ#X?Qd!X1zivw#z|ikSv0Nv%OP_c zx%s_rKh(lye01f}@{TV^#WJb)!84-9foH!p0F@!?4pcQW<}Qz3$7;EpD}`WUcg26WOZFG1o)(sALPJhw z>V_6UNlONt0XuP!afYU^ryI_VpS5djN+sbs(*z zJS&rO^af9d%rqGWW&V&?wk5r=>&E%B4#>@ox`Q*N17q@=iO@!RR`d5EjBn!>B)aSo zGBbn{BGVz|oAoW8F<5PN@LKfL=N8CGR}sz5f7x`HD7;#;>{mpN+JeLjt!uho@AyKK z_JCwJ`KPxDDg`QB~F1P-5t*)DV_y)uXTh$Ft%A+M>!g zQjQhz_Z#D`Qg#pFz+~fGkf-dJe)-Oyu_NWV7tRcF$^3<{PjX)w^`2lHkJWpM(xO<2 zlH1|Ea5Mp$-!$W>h=Yakm12R(*XuoM&Carj{fw8C?7;U@}I#n5AJ24kCS&g@E60 zVpdC`L3nSB+>f&x$A@l!x|$zIhX^A|GoSm%QU}&*QCT&)fuEfeMKQ|uVFWRDoZlcs z^TR;Y8?*O~T7lZ*{49-{<>QdJ&vnhdU$@>)G3ZkRANGi>2jHcWsqf()yfM2h6%KbV zz<@r8AaVq!4)rP5Df+|A%$ZWOr2}Bb9o8vN+g~rQ6Zr1MMHQGG?^9UDiK>$lEC)wy z+dY#|~~5IQ0rtz1Vf$Y0@Wd=i_^@w~@_)H6wC2@yV1(3GP4~_n@#G)S7)hvl@gXxmNFnxL;gx zbpW_yzw73*wwb$#=rO4Q_JG3Bd}UsA4W_wNP}WV!?2frN2M9fm50zz@_a4prqANp+ zHou_Ynlt0QsSb`VjDH{?*&@2P@iHSndJwsr*9B{R{w1Ew`Z=Pk!W n%m`ax9USE+>_4mo&qD&e?aoklyXtG`${;SB*TcWX*#`d~;0PDK From 300b47b387493241ef6612cc54a792020485c6da Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 16:42:53 -0400 Subject: [PATCH 123/139] Provisioning updates --- provision/ansible/hosts.yml | 2 +- provision/ansible/playbooks/cas/build.yml | 15 ++++++--------- provision/ansible/playbooks/cas/provision.yml | 4 ++-- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/provision/ansible/hosts.yml b/provision/ansible/hosts.yml index 00aaaaf..da28bed 100644 --- a/provision/ansible/hosts.yml +++ b/provision/ansible/hosts.yml @@ -71,7 +71,7 @@ all: follower: True vars: nvidia_cuda: False - cas: + nayak: hosts: center0nayak: redis_host: true diff --git a/provision/ansible/playbooks/cas/build.yml b/provision/ansible/playbooks/cas/build.yml index 85ed2c8..c3cb7c8 100644 --- a/provision/ansible/playbooks/cas/build.yml +++ b/provision/ansible/playbooks/cas/build.yml @@ -1,20 +1,17 @@ # Playbook for properly configuring individual systems - hosts: all tasks: - - name: Make nuvo images + - name: Make leader images command: chdir: "{{ kamera_dir }}" - cmd: make nuvo + cmd: make leader + when: leader - - name: Make viame images + - name: Make follower images command: chdir: "{{ kamera_dir }}" - cmd: make viame - - - name: Make postflight images - command: - chdir: "{{ kamera_dir }}" - cmd: make postflight + cmd: make follower + when: follower - name: Clean dangling images command: diff --git a/provision/ansible/playbooks/cas/provision.yml b/provision/ansible/playbooks/cas/provision.yml index 31c0824..193a3fa 100644 --- a/provision/ansible/playbooks/cas/provision.yml +++ b/provision/ansible/playbooks/cas/provision.yml @@ -78,14 +78,14 @@ - name: Add Tailscale apt key become: True get_url: - url: "https://pkgs.tailscale.com/stable/ubuntu/{{ ansible_lsb.codename }}.noarmor.gpg" + url: "https://pkgs.tailscale.com/stable/ubuntu/{{ ansible_facts['lsb']['codename'] }}.noarmor.gpg" dest: /usr/share/keyrings/tailscale-archive-keyring.gpg mode: '0644' - name: Add Tailscale apt repository become: True get_url: - url: "https://pkgs.tailscale.com/stable/ubuntu/{{ ansible_lsb.codename }}.tailscale-keyring.list" + url: "https://pkgs.tailscale.com/stable/ubuntu/{{ ansible_facts['lsb']['codename'] }}.tailscale-keyring.list" dest: /etc/apt/sources.list.d/tailscale.list mode: '0644' From 6e5dc8b505c2e15a9c3d223b68a1e5ec4f7d0304 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 16:44:01 -0400 Subject: [PATCH 124/139] nayak-specific config, no ir or uv cameras --- src/cfg/nayak/config.yaml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/cfg/nayak/config.yaml b/src/cfg/nayak/config.yaml index 0d9e6ec..724f908 100644 --- a/src/cfg/nayak/config.yaml +++ b/src/cfg/nayak/config.yaml @@ -57,8 +57,6 @@ max_mpix: 200000 # 0.2e6 channels: rgb: 0 - ir: 1 - uv: 2 interfaces: # map channels to ethernet interface names # this is gonna usurp the locations mapping @@ -83,17 +81,17 @@ locations: enabled: center: - ir: true rgb: true - uv: true + ir: false + uv: false left: - ir: true rgb: true - uv: true + ir: false + uv: false right: - ir: true rgb: true - uv: true + ir: false + uv: false # This is configuration information for each physical device # `ir_n0` is a DEV_ID. This is an abstract label and has no absolute correlation From 72dc43c220b84feff48d706eeec285d81ecfb068 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 16:45:00 -0400 Subject: [PATCH 125/139] Add default camera config jsons, change default system state to match --- .../nayak/default_camera_configurations.json | 17 +++++++++++++++++ src/cfg/nayak/default_system_state.json | 13 ++++++++----- .../taiga/default_camera_configurations.json | 17 +++++++++++++++++ src/cfg/taiga/default_system_state.json | 13 ++++++++----- 4 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 src/cfg/nayak/default_camera_configurations.json create mode 100644 src/cfg/taiga/default_camera_configurations.json diff --git a/src/cfg/nayak/default_camera_configurations.json b/src/cfg/nayak/default_camera_configurations.json new file mode 100644 index 0000000..68c8668 --- /dev/null +++ b/src/cfg/nayak/default_camera_configurations.json @@ -0,0 +1,17 @@ +{ + "default_camera_configuration": { + "description": "Default configuration with IR-only detection.", + "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/default/center_ir.yaml", + "center_rgb_yaml_path": "", + "center_uv_yaml_path": "", + "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", + "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/default/left_ir.yaml", + "left_rgb_yaml_path": "", + "left_uv_yaml_path": "", + "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", + "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/default/right_ir.yaml", + "right_rgb_yaml_path": "", + "right_uv_yaml_path": "", + "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe" + } +} diff --git a/src/cfg/nayak/default_system_state.json b/src/cfg/nayak/default_system_state.json index 26bee26..8158cd5 100644 --- a/src/cfg/nayak/default_system_state.json +++ b/src/cfg/nayak/default_system_state.json @@ -15,7 +15,7 @@ "overlap_percent": 25.0, "project": "glacial_2024", "rgb_vfov": 14, - "sys_cfg": "images_30deg_N68RF", + "sys_cfg": "default_camera_configuration", "trigger_freq": 1.0, "turn_off_nuc_in_shapefile": 1, "use_archive_region": 0, @@ -55,7 +55,8 @@ "Shutter_Mode": "2", "Shutter_Speed": 0.01, "Shutter_Speed_Max": 6.25e-05, - "Shutter_Speed_Min": 0.25 + "Shutter_Speed_Min": 0.25, + "Exposure_Comp.": 0 }, "uv": { "ExposureAuto": "Continuous", @@ -80,7 +81,8 @@ "Shutter_Mode": "2", "Shutter_Speed": 0.01, "Shutter_Speed_Max": 6.25e-05, - "Shutter_Speed_Min": 0.008 + "Shutter_Speed_Min": 0.008, + "Exposure_Comp.": 0 }, "uv": { "ExposureAuto": "Continuous", @@ -105,7 +107,8 @@ "Shutter_Mode": "2", "Shutter_Speed": 0.01, "Shutter_Speed_Max": 6.25e-05, - "Shutter_Speed_Min": 0.008 + "Shutter_Speed_Min": 0.008, + "Exposure_Comp.": 0 }, "uv": { "ExposureAuto": "Continuous", @@ -128,5 +131,5 @@ "show_right": true, "show_saturated_pixels": true, "show_uv": false, - "syscfg_dir": "/mnt/data/glacial_2024/fl02/images_30deg_N68RF/" + "syscfg_dir": "/mnt/data/glacial_2024/fl02/default_camera_configuration/" } diff --git a/src/cfg/taiga/default_camera_configurations.json b/src/cfg/taiga/default_camera_configurations.json new file mode 100644 index 0000000..68c8668 --- /dev/null +++ b/src/cfg/taiga/default_camera_configurations.json @@ -0,0 +1,17 @@ +{ + "default_camera_configuration": { + "description": "Default configuration with IR-only detection.", + "center_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/default/center_ir.yaml", + "center_rgb_yaml_path": "", + "center_uv_yaml_path": "", + "center_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", + "left_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/default/left_ir.yaml", + "left_rgb_yaml_path": "", + "left_uv_yaml_path": "", + "left_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe", + "right_ir_yaml_path": "/mnt/flight_data/detector_models/camera_models/default/right_ir.yaml", + "right_rgb_yaml_path": "", + "right_uv_yaml_path": "", + "right_sys_pipe": "/mnt/flight_data/detector_models/VIAME-JoBBS-Models-v2021.01.20/configs/pipelines/detector_ir_yolo.pipe" + } +} diff --git a/src/cfg/taiga/default_system_state.json b/src/cfg/taiga/default_system_state.json index 1d699e7..5307155 100755 --- a/src/cfg/taiga/default_system_state.json +++ b/src/cfg/taiga/default_system_state.json @@ -15,7 +15,7 @@ "overlap_percent": 50.0, "project": "default_effort_2019", "rgb_vfov": 14, - "sys_cfg": "images_30deg_N68RF", + "sys_cfg": "default_camera_configuration", "trigger_freq": 1, "turn_off_nuc_in_shapefile": 1, "use_archive_region": 0, @@ -55,7 +55,8 @@ "Shutter_Mode": "2", "Shutter_Speed": 0.01, "Shutter_Speed_Max": 6.25e-05, - "Shutter_Speed_Min": 0.25 + "Shutter_Speed_Min": 0.25, + "Exposure_Comp.": 0 }, "uv": { "ExposureAuto": "Continuous", @@ -80,7 +81,8 @@ "Shutter_Mode": "2", "Shutter_Speed": 0.01, "Shutter_Speed_Max": 6.25e-05, - "Shutter_Speed_Min": 0.008 + "Shutter_Speed_Min": 0.008, + "Exposure_Comp.": 0 }, "uv": { "ExposureAuto": "Continuous", @@ -105,7 +107,8 @@ "Shutter_Mode": "2", "Shutter_Speed": 0.01, "Shutter_Speed_Max": 6.25e-05, - "Shutter_Speed_Min": 0.008 + "Shutter_Speed_Min": 0.008, + "Exposure_Comp.": 0 }, "uv": { "ExposureAuto": "Continuous", @@ -128,5 +131,5 @@ "show_right": true, "show_saturated_pixels": false, "show_uv": false, - "syscfg_dir": "/mnt/data/default_project/fl00/images_30deg_N68RF/" + "syscfg_dir": "/mnt/data/default_project/fl00/default_camera_configuration/" } From 34ab586980a92b835ed1a6ea357276b0824c0059 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 16:49:23 -0400 Subject: [PATCH 126/139] Add shutter enum mapping for electronic / leaf shutter on phase one cameras --- .../kamcore/scripts/cam_param_monitor_node.py | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/core/kamcore/scripts/cam_param_monitor_node.py b/src/core/kamcore/scripts/cam_param_monitor_node.py index ed04154..ec4652c 100755 --- a/src/core/kamcore/scripts/cam_param_monitor_node.py +++ b/src/core/kamcore/scripts/cam_param_monitor_node.py @@ -21,6 +21,22 @@ setsrv = "set_camera_attr" getsrv = "get_camera_attr" +P1_SHUTTER_MODE_LABELS = {"LS": "1", "ES": "2"} + + +def normalize_p1_shutter_mode(val): + """Map Phase One shutter mode labels and numeric values to '1' or '2'.""" + if val in (None, ""): + return None + s = str(val).strip() + if s in P1_SHUTTER_MODE_LABELS: + return P1_SHUTTER_MODE_LABELS[s] + try: + return str(int(float(s))) + except (TypeError, ValueError): + return s + + class CamParamMonitor(object): """ A class to monitor state that is set in Redis, and the value reported by the cameras, @@ -89,9 +105,12 @@ def get_param_val(self, host, mode, param, requested_val): # Phase one params have the type in the return string getsrv_val = ''.join(getsrv_val.split(' ')[1:]) # A random s is sometimes in shutter speed - if "s" in getsrv_val: + if "s" in getsrv_val and param != "Shutter Mode": getsrv_val = getsrv_val[:-1] - if isinstance(requested_val, float): + if param == "Shutter Mode": + getsrv_val = normalize_p1_shutter_mode(getsrv_val) + requested_val = normalize_p1_shutter_mode(requested_val) + elif isinstance(requested_val, float): try: getsrv_val = float(getsrv_val) except: From 09c39abb3062961b725992e3931e7956bb0eaa6a Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 16:50:45 -0400 Subject: [PATCH 127/139] More configuration updates, move pipefile to within camera_cfgs, --- src/core/kamcore/scripts/seed_redis_config.py | 55 +++++++++++++ src/run_scripts/entry/master.sh | 6 ++ src/run_scripts/entry/viame.sh | 6 +- src/run_scripts/test_pipefile_selector.sh | 79 ------------------- 4 files changed, 66 insertions(+), 80 deletions(-) create mode 100755 src/core/kamcore/scripts/seed_redis_config.py delete mode 100755 src/run_scripts/test_pipefile_selector.sh diff --git a/src/core/kamcore/scripts/seed_redis_config.py b/src/core/kamcore/scripts/seed_redis_config.py new file mode 100755 index 0000000..f964f52 --- /dev/null +++ b/src/core/kamcore/scripts/seed_redis_config.py @@ -0,0 +1,55 @@ +#! /usr/bin/python +"""Seed Redis with the static system config from config.yaml. + +kamcore nodes (cam_param_monitor, fps_monitor, ...) read /sys/arch/* and +/sys/channels straight from Redis, but nothing in the core startup populates +them -- historically that happened only as a side effect of the GUI importing +wxpython_gui.cfg, so the nodes raced (and crashed against) the GUI on a fresh +boot. This seeds the static config up front so they no longer depend on it. + +Only config.yaml (the static deployment truth) is written; operator-mutable +session state (flight, project, effort, ...) stays owned by the GUI. config.yaml +keys are authoritative, so overwriting any stale Redis values here is correct. +""" +import os +import sys + +import yaml + +from roskv.impl.redis_envoy import RedisEnvoy + + +def main(): + if len(sys.argv) > 1: + cfg_file = sys.argv[1] + else: + cfg_file = "/cfg/%s/config.yaml" % os.environ["SYSTEM_NAME"] + + with open(cfg_file, "r") as stream: + config = yaml.safe_load(stream) + + envoy = RedisEnvoy(os.environ["REDIS_HOST"], client_name="config_seeder") + # config.yaml is authoritative for its static keys. Clear each static subtree + # first so keys removed from the yaml (e.g. a dropped channel) don't linger + # in Redis -- put only sets keys, it never deletes. "arch" also carries the + # GUI's mutable session state (flight, project, ...), so only its static + # "hosts" subtree is reset there, never all of /sys/arch. + for key, val in config.items(): + if isinstance(val, dict) and key != "arch": + try: + envoy.delete_dict("/sys/%s" % key) + except Exception: + pass + try: + envoy.delete_dict("/sys/arch/hosts") + except Exception: + pass + # Mirror wxpython_gui.cfg: each top-level config.yaml key is published under + # /sys (RedisEnvoy.put flattens nested dicts into keypaths). + for key, val in config.items(): + envoy.put("/sys/%s" % key, val) + print("Seeded /sys from %s (%d top-level keys)" % (cfg_file, len(config))) + + +if __name__ == "__main__": + main() diff --git a/src/run_scripts/entry/master.sh b/src/run_scripts/entry/master.sh index a07841a..8b20abf 100755 --- a/src/run_scripts/entry/master.sh +++ b/src/run_scripts/entry/master.sh @@ -23,6 +23,12 @@ ping -c1 kameramaster # this is a rolling counter just for fun, and also serves as something any client can always grab REDIS_HOST=${REDIS_HOST:-nuvo0} redis-client -h ${REDIS_HOST} incr term + +# Seed Redis with the static system config before anything starts, so kamcore +# nodes (cam_param_monitor, etc.) read /sys/arch from Redis without depending on +# the GUI. Done before roscore so the --wait monitors can't start until it's up. +rosrun kamcore seed_redis_config.py /cfg/${SYSTEM_NAME}/config.yaml + # Start core and block until it's up, then bootstrap parameters roscore & diff --git a/src/run_scripts/entry/viame.sh b/src/run_scripts/entry/viame.sh index 2f82154..86272ce 100755 --- a/src/run_scripts/entry/viame.sh +++ b/src/run_scripts/entry/viame.sh @@ -70,7 +70,11 @@ fi # Directory to store detection csv files. _DETECTION_CSV_DIR="${DATA_MOUNT_POINT}/$(date +%Y%m%d%H%M%S)" -PIPEFILE=$(redis-cli -h ${REDIS_HOST} -p 6379 get "/sys/${NODE_HOSTNAME}/detector/pipefile") +# Resolve the detector pipefile from the active camera configuration (defined +# per-FOV in camera_cfgs), rather than a duplicated per-host value. +SYS_CFG_NAME=$(redis-cli -h ${REDIS_HOST} -p 6379 get "/sys/arch/sys_cfg") +PIPEFILE=$(redis-cli -h ${REDIS_HOST} -p 6379 get "/sys/camera_cfgs/${SYS_CFG_NAME}/${CAM_FOV}_sys_pipe") +[[ "$PIPEFILE" == "null" ]] && PIPEFILE="" DETECTION_CSV_DIR="$(redis-cli -h ${REDIS_HOST} -p 6379 get "/sys/syscfg_dir")/../detections" DETECTION_DSV_DIR=${DETECTION_DSV_DIR:-$_DETECTION_CSV_DIR} diff --git a/src/run_scripts/test_pipefile_selector.sh b/src/run_scripts/test_pipefile_selector.sh deleted file mode 100755 index 2f8045e..0000000 --- a/src/run_scripts/test_pipefile_selector.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/bash - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -KAM_REPO_DIR=$(~/.config/kamera/repo_dir.bash) - -cd ${KAM_REPO_DIR} -# get configQuery -source ${KAM_REPO_DIR}/src/cfg/cfg-aliases.sh - -set -a # automatically export all variables - -. ${KAM_REPO_DIR}/.env -REDIS_HOST="192.168.88.10" -REDIS_PORT="6379" - -UP_RESET="redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} set /${host}/detector/up False" -DOWN_RESET="redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} set /${host}/detector/down False" - -declare -A PREV - -while true; do - declare -A PIDS - - for host in $(cq '.hosts | keys | join("\n" )') ; do - PIPEFILE=$(redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} get "/${host}/detector/pipefile") - START_DETECTOR=$(redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} get "/${host}/detector/up") - STOP_DETECTOR=$(redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} get "/${host}/detector/down") - - if [ "${PREV["${host}-pipe"]}" != "$PIPEFILE" ] - then - echo "===============================================================" - echo "Loading pipefile for host $host: $PIPEFILE" - PREV["${host}-pipe"]=${PIPEFILE} - ${KAM_REPO_DIR}/src/run_scripts/inpath/ssh_checked.sh $host \ - "${KAM_REPO_DIR}/src/run_scripts/inpath/kamera.detector restart" & - PIDS["${host}-pipe"]=$! - fi - - if [ "${PREV["${host}-start"]}" != "$START_DETECTOR" ] - then - if [ "${START_DETECTOR}" == "True" ] - then - echo "===============================================================" - echo "Starting Detector: $host" - PREV["${host}-start"]=${START_DETECTOR} - ${KAM_REPO_DIR}/src/run_scripts/inpath/ssh_checked.sh $host \ - "${KAM_REPO_DIR}/src/run_scripts/inpath/kamera.detector" & - PIDS["${host}-start"]=$! - # Reset redis parameter, so each "set" triggers a call - RET=$(redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} set "/${host}/detector/up" False) - else - PREV["${host}-start"]=${START_DETECTOR} - fi - fi - - if [ "${PREV["${host}-stop"]}" != "$STOP_DETECTOR" ] - then - if [ "$STOP_DETECTOR" == "True" ] - then - echo "===============================================================" - echo "Stopping Detector: $host" - PREV["${host}-stop"]=${STOP_DETECTOR} - ${KAM_REPO_DIR}/src/run_scripts/inpath/ssh_checked.sh $host \ - "${KAM_REPO_DIR}/src/run_scripts/inpath/kamera.detector down" & - PIDS["${host}-stop"]=$! - RET=$(redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} set "/${host}/detector/down" False) - else - PREV["${host}-stop"]=${STOP_DETECTOR} - fi - fi - done - - for pid in ${PIDS[*]}; do - wait $pid - echo "Finished SSH call." - done - unset PIDS - sleep 0.1 -done From 6209dde464e898b255e48adbc7fd6501786c00f5 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Wed, 17 Jun 2026 17:01:50 -0400 Subject: [PATCH 128/139] Numerous GUI changes, the biggest being dropdowns for phase one shutter speed, gain, and aperture. --- .../scripts/system_control_panel_node.py | 24 +- .../src/wxpython_gui/DetectorState.py | 11 +- .../src/wxpython_gui/camera_models.py | 2 +- .../wxpython_gui/src/wxpython_gui/cfg.py | 81 ++- .../form_builder_output.py | 220 ++++-- .../form_builder_output_imagery_inspection.py | 4 +- .../wxpython_gui/system_control_panel/gui.py | 666 ++++++++++++++---- 7 files changed, 753 insertions(+), 255 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py b/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py index ea4a030..204ce62 100755 --- a/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py +++ b/src/kitware-ros-pkg/wxpython_gui/scripts/system_control_panel_node.py @@ -18,27 +18,25 @@ def main(): name_space = rospy.get_namespace() envoy = RedisEnvoy(os.environ["REDIS_HOST"], client_name=node_name) - channels = envoy.get("/sys/channels").keys() + enabled = envoy.get("/sys/enabled") all_hosts = envoy.get("/sys/arch/hosts") hosts = {h: all_hosts[h] for h in filter_hosts_by_system(all_hosts.keys())} topic_names = {} - # From the camera driver itself + # From the camera driver itself (RGB) and view_server sync node (IR/UV). + # Topic keys must match gui.MainFrame, which gates panels on /sys/enabled, + # not /sys/channels (channels drives driver launch, not GUI visibility). for host, d in hosts.items(): - channel = "rgb" fov = d["fov"] - topic_names["_".join([fov, channel, "srv", "topic"])] = "/".join( - ["", host, channel, "%s_view_service" % channel, "get_image_view"] - ) - - # From the view_server sync node - for host, d in hosts.items(): - channel = "rgb" - for channel in channels: - if channel == "rgb": + fov_enabled = enabled.get(fov, {}) + if fov_enabled.get("rgb"): + topic_names["_".join([fov, "rgb", "srv", "topic"])] = "/".join( + ["", host, "rgb", "rgb_view_service", "get_image_view"] + ) + for channel in ("ir", "uv"): + if not fov_enabled.get(channel): continue - fov = d["fov"] topic_names["_".join([fov, channel, "srv", "topic"])] = "/".join( ["", host, "synched", "%s_view_service" % channel] ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/DetectorState.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/DetectorState.py index 1b5892b..295bc32 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/DetectorState.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/DetectorState.py @@ -1,7 +1,7 @@ from __future__ import division, print_function import time from enum import Enum -from wxpython_gui.cfg import SYS_CFG, kv +from wxpython_gui.cfg import SYS_CFG, kv, get_detector_pipefile from wxpython_gui.utils import diffpair from roskv.util import filter_hosts_by_system @@ -47,7 +47,7 @@ def __init__(self, kv, hosts, short_thresh=15.0, long_thresh=300.0): def set_det_attr_state(self, host, attr, state): # type: (str, str, EPodStatus) -> EPodStatus v = state.value - SYS_CFG[host]["detector"][attr] = v + self.kv.put("/sys/{}/detector/{}".format(host, attr), v) return self.get_det_attr_state(host, attr) def get_det_attr_state(self, host, attr): @@ -63,8 +63,9 @@ def set_desired(self, host, state): # type: (str, EPodStatus) -> EPodStatus status = self.set_det_attr_state(host, "desired", state) self.desired[host] = status - SYS_CFG[host]["detector"]["last_change_desired"] = time.time() - self.last_change_desired = SYS_CFG[host]["detector"]["last_change_desired"] + now = time.time() + self.kv.put("/sys/{}/detector/last_change_desired".format(host), now) + self.last_change_desired = now return status def bump(self, host): @@ -117,9 +118,9 @@ def sync(self): # Reported health from the detectors try: health = self.kv.get("/{}/detector/health//".format(host)) - cmdpipef = SYS_CFG[host]["detector"]["pipefile"] except KeyError as e: continue + cmdpipef = get_detector_pipefile(host) try: health = health[""] except KeyError: diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py index a8a7494..8f513cc 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py @@ -953,7 +953,7 @@ def dist(self): @dist.setter def dist(self, value): - if value is None or value is 0: + if value is None or (np.isscalar(value) and value == 0): value = np.zeros(4) self._dist = np.atleast_1d(value) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py index bfcd3dd..90fe8fc 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py @@ -66,12 +66,16 @@ def __getitem__(self, key): # kv def __setitem__(self, key, val): - # tic = time.time() - kv.put("%s/%s" % (self.ns, key), val) - # toc = time.time() - # print("Time to access was %s" % (toc - tic)) + ns_key = "%s/%s" % (self.ns, key) if isinstance(val, dict): - val = Cfg(val, ns="%s/%s" % (self.ns, key)) + # An empty dict has no leaves to flatten; kv.put would fall back to + # SET-ing a raw dict, which Redis rejects. Skip the write and keep + # the empty namespace in memory only. + if val: + kv.put(ns_key, val) + val = Cfg(val, ns=ns_key) + else: + kv.put(ns_key, val) super(Cfg, self).__setitem__(key, val) def __repr__(self): @@ -137,9 +141,22 @@ def deep_merge(base, override): REDIS_LIVE.pop("camera_cfgs", None) # presets come from the file below # --- Camera presets (camera_configurations.json is authoritative) ------------ +# Mirrors the system_state cache: seed the runtime file from the in-repo default +# the first time the GUI runs, then load it. camera_config_filename = os.path.join( USER_CFG["gui_cfg_dir"], "camera_configurations.json" ) +default_camera_config_file = os.path.join( + REAL_KAM_REPO_DIR, "src/cfg", system_name, "default_camera_configurations.json" +) +if not os.path.isfile(camera_config_filename): + try: + wxpython_gui.utils.make_path(camera_config_filename, from_file=True) + with open(default_camera_config_file, "r") as infile: + with open(camera_config_filename, "w") as outfile: + outfile.write(infile.read()) + except Exception as e: + print(e) try: with open(camera_config_filename, "r") as input_file: CAMERA_PRESETS = json.load(input_file) @@ -156,10 +173,32 @@ def deep_merge(base, override): deep_merge(SYS_ARCH, DEFAULT_STATE) # 1. factory defaults deep_merge(SYS_ARCH, CACHE_STATE) # 2. operator's last session deep_merge(SYS_ARCH, REDIS_LIVE) # 3. live runtime values -deep_merge(SYS_ARCH, USER_CFG) # 4. static YAML truth always wins +# 4. config.yaml OWNS the static keys it declares: replace rather than merge, so +# a key removed from the yaml (e.g. a dropped channel) can't survive from a +# lower tier. "arch" mixes static + mutable session subkeys, so only its +# static subkeys are replaced. +for key, val in USER_CFG.items(): + if key != "arch": + SYS_ARCH[key] = val +SYS_ARCH.setdefault("arch", {}) +for sub, val in USER_CFG.get("arch", {}).items(): + SYS_ARCH["arch"][sub] = val SYS_ARCH["camera_cfgs"] = CAMERA_PRESETS -# Publish to Redis under /sys and expose as SYS_CFG. +# Publish to Redis under /sys. First drop the static subtrees so keys removed +# from config.yaml don't linger (put only sets keys, never deletes); the update +# then republishes the authoritative values. arch.hosts is the only static dict +# under "arch" -- the rest of /sys/arch holds mutable state we must not wipe. +for key, val in USER_CFG.items(): + if key != "arch" and isinstance(val, dict): + try: + kv.delete_dict("/sys/%s" % key) + except Exception: + pass +try: + kv.delete_dict("/sys/arch/hosts") +except Exception: + pass SYS_CFG = Cfg(ns="/sys") SYS_CFG.update(SYS_ARCH) @@ -342,7 +381,13 @@ def format_status( drop_str = "{} dropped".format(num_dropped) else: drop_str = "{:.0e} dropped".format(num_dropped) - gain_str = "Gain: ?" if gain is None else "Gain: {}".format(gain) + gain_str = ( + "ISO: ?" + if chan == "rgb" and gain is None + else "Gain: ?" + if gain is None + else ("ISO: {}" if chan == "rgb" else "Gain: {}").format(gain) + ) fps_str = "? fps" if fps is None else "{:4.2f} fps".format(fps) if total is not None and processed is not None: # display N/N, even if internally it's N-1/N @@ -388,7 +433,7 @@ def channel_format_status(fov, chan, timeval=None, dt=0): elif chan == "rgb": iso = kv.get(param_ns + "/ISO", None) if iso is not None: - gain = int(float(iso) / 50.0) + gain = int(float(iso)) shutter = kv.get(param_ns + "/Shutter_Speed", None) if shutter is not None: # convert float point seconds to us @@ -422,3 +467,21 @@ def host_from_fov(fov): if fov == hosts[host]["fov"]: return host raise KeyError("FOV not found: '{}'".format(fov)) + + +def get_detector_pipefile(host, sys_cfg=None): + # type: (str, Optional[str]) -> Optional[str] + """Resolve a host's detector pipefile from the active camera config. + + The pipefile is defined per-FOV in camera_cfgs as "_sys_pipe"; it is + read from there directly rather than duplicated into per-host state. + Returns None when unset or invalid. + """ + if sys_cfg is None: + sys_cfg = SYS_CFG["arch"].get("sys_cfg") + try: + fov = SYS_CFG["arch"]["hosts"][host]["fov"] + pipe = SYS_CFG["camera_cfgs"][sys_cfg]["{}_sys_pipe".format(fov)] + except KeyError: + return None + return pipe if (pipe and pipe != "null") else None diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py index d7a7063..bfe9210 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output.py @@ -9,7 +9,6 @@ import wx import wx.xrc -import wx.lib.scrolledpanel as scrolledpanel ID_START_DETECTOR_SYS0_CENTER = 1000 ID_START_DETECTOR_SYS1_LEFT = 1001 @@ -37,8 +36,8 @@ def __init__( self, parent ): left_column = wx.BoxSizer( wx.VERTICAL ) bSizer20 = wx.BoxSizer( wx.VERTICAL ) - # Scrollable region for the left control panels; Close stays pinned below. - self.left_scroll_panel = scrolledpanel.ScrolledPanel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + # Left control panels; Close stays pinned below. + self.left_scroll_panel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) self.ins_control_panel = wx.Panel( self.left_scroll_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) bSizer191 = wx.BoxSizer( wx.VERTICAL ) @@ -255,9 +254,46 @@ def __init__( self, parent ): m_staticText14211.Add( bSizer55, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) + m_staticText14211.Add( ( 0, 6 ), 0, 0, 0 ) + self.m_staticline5 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline5, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + self.rgb_shutter_mode_row = wx.BoxSizer( wx.HORIZONTAL ) + + self.rgb_shutter_section = wx.BoxSizer( wx.HORIZONTAL ) + + self.rgb_shutter_mode_label = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Shutter Mode:", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.rgb_shutter_mode_label.Wrap( -1 ) + self.rgb_shutter_mode_label.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) + + self.rgb_shutter_section.Add( self.rgb_shutter_mode_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) + + rgb_shutter_mode_comboChoices = [ u"LS", u"ES" ] + self.rgb_shutter_mode_combo = wx.ComboBox( self.camera_panel, wx.ID_ANY, u"ES", wx.DefaultPosition, wx.Size( 100,-1 ), rgb_shutter_mode_comboChoices, wx.CB_READONLY ) + self.rgb_shutter_mode_combo.SetSelection( 1 ) + self.rgb_shutter_section.Add( self.rgb_shutter_mode_combo, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + + self.rgb_shutter_mode_row.Add( self.rgb_shutter_section, 1, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + + self.rgb_shutter_mode_row.Add( ( 10, 0), 0, wx.RIGHT|wx.LEFT, 5 ) + + self.rgb_exposure_comp_section = wx.BoxSizer( wx.HORIZONTAL ) + + self.rgb_exposure_comp_label = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Exposure Bias:", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.rgb_exposure_comp_label.Wrap( -1 ) + self.rgb_exposure_comp_label.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) + + self.rgb_exposure_comp_section.Add( self.rgb_exposure_comp_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) + + self.rgb_exposure_comp_txt_ctrl = wx.TextCtrl( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 100,-1 ), wx.TE_CENTRE ) + self.rgb_exposure_comp_section.Add( self.rgb_exposure_comp_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + + self.rgb_shutter_mode_row.Add( self.rgb_exposure_comp_section, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.RIGHT|wx.LEFT, 5 ) + + m_staticText14211.Add( self.rgb_shutter_mode_row, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, 5 ) + m_staticText14211.Show( self.rgb_shutter_mode_row, False ) + m_staticText14211.Add( ( 0, 3 ), 0, 0, 0 ) self.m_staticText42 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Auto Exposure (ms)", wx.DefaultPosition, wx.DefaultSize, 0 ) @@ -274,11 +310,15 @@ def __init__( self, parent ): bSizer442.Add( self.m_staticText423, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) - self.exposure_min_value_txt_ctrl = wx.TextCtrl( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 70,-1 ), wx.TE_CENTRE ) - bSizer442.Add( self.exposure_min_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + self.exposure_min_value_txt_ctrl = wx.TextCtrl( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_CENTRE ) + bSizer442.Add( self.exposure_min_value_txt_ctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + exposure_min_comboChoices = [] + self.exposure_min_combo = wx.ComboBox( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, exposure_min_comboChoices, wx.CB_READONLY ) + bSizer442.Add( self.exposure_min_combo, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + bSizer442.Show( self.exposure_min_combo, False ) - bSizer442.Add( ( 40, 0), 0, 0, 5 ) + bSizer442.Add( ( 10, 0), 0, wx.RIGHT|wx.LEFT, 5 ) self.m_staticText4231 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Max:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText4231.Wrap( -1 ) @@ -286,11 +326,15 @@ def __init__( self, parent ): bSizer442.Add( self.m_staticText4231, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) - self.exposure_max_value_txt_ctrl = wx.TextCtrl( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 70,-1 ), wx.TE_CENTRE ) - bSizer442.Add( self.exposure_max_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + self.exposure_max_value_txt_ctrl = wx.TextCtrl( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_CENTRE ) + bSizer442.Add( self.exposure_max_value_txt_ctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + exposure_max_comboChoices = [] + self.exposure_max_combo = wx.ComboBox( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, exposure_max_comboChoices, wx.CB_READONLY ) + bSizer442.Add( self.exposure_max_combo, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + bSizer442.Show( self.exposure_max_combo, False ) - m_staticText14211.Add( bSizer442, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.BOTTOM, 3 ) + m_staticText14211.Add( bSizer442, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, 5 ) self.m_staticline51 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline51, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) @@ -309,11 +353,15 @@ def __init__( self, parent ): bSizer4421.Add( self.m_staticText4232, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) - self.gain_min_value_txt_ctrl = wx.TextCtrl( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 70,-1 ), wx.TE_CENTRE ) - bSizer4421.Add( self.gain_min_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + self.gain_min_value_txt_ctrl = wx.TextCtrl( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_CENTRE ) + bSizer4421.Add( self.gain_min_value_txt_ctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + gain_min_comboChoices = [] + self.gain_min_combo = wx.ComboBox( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, gain_min_comboChoices, wx.CB_READONLY ) + bSizer4421.Add( self.gain_min_combo, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + bSizer4421.Show( self.gain_min_combo, False ) - bSizer4421.Add( ( 40, 0), 0, 0, 5 ) + bSizer4421.Add( ( 10, 0), 0, wx.RIGHT|wx.LEFT, 5 ) self.m_staticText42311 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Max:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText42311.Wrap( -1 ) @@ -321,17 +369,60 @@ def __init__( self, parent ): bSizer4421.Add( self.m_staticText42311, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) - self.gain_max_value_txt_ctrl = wx.TextCtrl( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 70,-1 ), wx.TE_CENTRE ) - bSizer4421.Add( self.gain_max_value_txt_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + self.gain_max_value_txt_ctrl = wx.TextCtrl( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_CENTRE ) + bSizer4421.Add( self.gain_max_value_txt_ctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + + gain_max_comboChoices = [] + self.gain_max_combo = wx.ComboBox( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, gain_max_comboChoices, wx.CB_READONLY ) + bSizer4421.Add( self.gain_max_combo, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + bSizer4421.Show( self.gain_max_combo, False ) + + m_staticText14211.Add( bSizer4421, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, 5 ) + + self.rgb_aperture_label = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Aperture (f-stop)", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.rgb_aperture_label.Wrap( -1 ) + self.rgb_aperture_label.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) + + m_staticText14211.Add( self.rgb_aperture_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT|wx.ALIGN_CENTER_HORIZONTAL, 5 ) + m_staticText14211.Show( self.rgb_aperture_label, False ) + + self.rgb_aperture_row = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText4233 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Min:", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText4233.Wrap( -1 ) + self.m_staticText4233.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) + + self.rgb_aperture_row.Add( self.m_staticText4233, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) + + aperture_min_comboChoices = [] + self.aperture_min_combo = wx.ComboBox( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, aperture_min_comboChoices, wx.CB_READONLY ) + self.rgb_aperture_row.Add( self.aperture_min_combo, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + + self.rgb_aperture_row.Add( ( 10, 0), 0, wx.RIGHT|wx.LEFT, 5 ) + self.m_staticText42331 = wx.StaticText( self.camera_panel, wx.ID_ANY, u"Max:", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText42331.Wrap( -1 ) + self.m_staticText42331.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - m_staticText14211.Add( bSizer4421, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.BOTTOM, 3 ) + self.rgb_aperture_row.Add( self.m_staticText42331, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 5 ) + + aperture_max_comboChoices = [] + self.aperture_max_combo = wx.ComboBox( self.camera_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, aperture_max_comboChoices, wx.CB_READONLY ) + self.rgb_aperture_row.Add( self.aperture_max_combo, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + + m_staticText14211.Add( self.rgb_aperture_row, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, 5 ) + m_staticText14211.Show( self.rgb_aperture_row, False ) self.m_staticline52 = wx.StaticLine( self.camera_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) m_staticText14211.Add( self.m_staticline52, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) bSizer44211 = wx.BoxSizer( wx.HORIZONTAL ) + self.m_manual_ir_nuc = wx.Button( self.camera_panel, wx.ID_ANY, u"Manual IR NUC", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_manual_ir_nuc.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) + + bSizer44211.Add( self.m_manual_ir_nuc, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + self.txtNUC = wx.StaticText( self.camera_panel, wx.ID_ANY, u"IR NUC Time (min):", wx.DefaultPosition, wx.DefaultSize, 0 ) self.txtNUC.Wrap( -1 ) self.txtNUC.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) @@ -342,23 +433,13 @@ def __init__( self, parent ): bSizer44211.Add( self.ir_nuc_time, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - m_staticText14211.Add( bSizer44211, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP, 12 ) - - bSizer442111 = wx.BoxSizer( wx.HORIZONTAL ) - - - m_staticText14211.Add( bSizer442111, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.BOTTOM, 5 ) + m_staticText14211.Add( bSizer44211, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 12 ) self.m_button10 = wx.Button( self.camera_panel, wx.ID_ANY, u"Set Camera Parameter", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_button10.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) m_staticText14211.Add( self.m_button10, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT, 6 ) - self.m_manual_ir_nuc = wx.Button( self.camera_panel, wx.ID_ANY, u"Manual IR NUC", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_manual_ir_nuc.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - - m_staticText14211.Add( self.m_manual_ir_nuc, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.RIGHT|wx.LEFT|wx.BOTTOM, 6 ) - self.camera_panel.SetSizer( m_staticText14211 ) self.camera_panel.Layout() @@ -381,6 +462,38 @@ def __init__( self, parent ): bSizer42 = wx.BoxSizer( wx.VERTICAL ) + bSizer45 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText33 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"Flight:", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText33.Wrap( -1 ) + self.m_staticText33.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) + + bSizer45.Add( self.m_staticText33, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + + self.m_staticText34 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"FL", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText34.Wrap( -1 ) + bSizer45.Add( self.m_staticText34, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + + self.flight_number_text_ctrl = wx.TextCtrl( self.flight_data_panel, wx.ID_ANY, u"00", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer45.Add( self.flight_number_text_ctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + + bSizer45.Add( ( 10, 0), 0, wx.RIGHT|wx.LEFT, 5 ) + + self.m_staticText331 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"Observer", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText331.Wrap( -1 ) + self.m_staticText331.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) + + bSizer45.Add( self.m_staticText331, 0, wx.RIGHT|wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.observer_text_ctrl = wx.TextCtrl( self.flight_data_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer45.Add( self.observer_text_ctrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + + + bSizer42.Add( bSizer45, 1, wx.EXPAND, 5 ) + + self.m_staticline41 = wx.StaticLine( self.flight_data_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) + bSizer42.Add( self.m_staticline41, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + bSizer441 = wx.BoxSizer( wx.HORIZONTAL ) self.m_staticText18171311 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"Effort", wx.DefaultPosition, wx.DefaultSize, 0 ) @@ -410,42 +523,6 @@ def __init__( self, parent ): bSizer42.Add( bSizer43, 1, wx.ALIGN_CENTER_HORIZONTAL, 5 ) - self.m_staticline41 = wx.StaticLine( self.flight_data_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) - bSizer42.Add( self.m_staticline41, 0, wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) - - bSizer45 = wx.BoxSizer( wx.HORIZONTAL ) - - self.m_staticText33 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"Flight:", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_staticText33.Wrap( -1 ) - self.m_staticText33.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - - bSizer45.Add( self.m_staticText33, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) - - self.m_staticText34 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"FL", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_staticText34.Wrap( -1 ) - bSizer45.Add( self.m_staticText34, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) - - self.flight_number_text_ctrl = wx.TextCtrl( self.flight_data_panel, wx.ID_ANY, u"00", wx.DefaultPosition, wx.DefaultSize, 0 ) - bSizer45.Add( self.flight_number_text_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - - - bSizer42.Add( bSizer45, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, 5 ) - - bSizer451 = wx.BoxSizer( wx.HORIZONTAL ) - - self.m_staticText331 = wx.StaticText( self.flight_data_panel, wx.ID_ANY, u"Observer", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_staticText331.Wrap( -1 ) - self.m_staticText331.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) - - bSizer451.Add( self.m_staticText331, 0, wx.RIGHT|wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5 ) - - self.observer_text_ctrl = wx.TextCtrl( self.flight_data_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) - self.observer_text_ctrl.SetMinSize(self.flight_number_text_ctrl.GetBestSize()) - bSizer451.Add( self.observer_text_ctrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5 ) - - - bSizer42.Add( bSizer451, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, 5 ) - bSizer41.Add( bSizer42, 1, wx.EXPAND, 5 ) @@ -507,7 +584,6 @@ def __init__( self, parent ): self.left_scroll_panel.SetSizer( bSizer20 ) self.left_scroll_panel.Layout() - self.left_scroll_panel.SetupScrolling( scroll_x = False, scroll_y = True ) self.m_panel7 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) bSizer17 = wx.BoxSizer( wx.VERTICAL ) @@ -580,7 +656,7 @@ def __init__( self, parent ): self.m_panel_left_rgb = wx.Panel( self.images_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) left_bsizer0 = wx.BoxSizer( wx.VERTICAL ) - self.cueing_left_image_title3 = wx.StaticText( self.m_panel_left_rgb, wx.ID_ANY, u"Left RGB", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.cueing_left_image_title3 = wx.StaticText( self.m_panel_left_rgb, wx.ID_ANY, u"Left View RGB", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_left_image_title3.Wrap( -1 ) self.cueing_left_image_title3.SetFont( wx.Font( 14, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, "Sans" ) ) @@ -607,7 +683,7 @@ def __init__( self, parent ): self.m_panel_center_rgb = wx.Panel( self.images_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) right_bsizer0 = wx.BoxSizer( wx.VERTICAL ) - self.cueing_right_image_title = wx.StaticText( self.m_panel_center_rgb, wx.ID_ANY, u"Center RGB", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.cueing_right_image_title = wx.StaticText( self.m_panel_center_rgb, wx.ID_ANY, u"Center View RGB", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_right_image_title.Wrap( -1 ) self.cueing_right_image_title.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) @@ -639,7 +715,7 @@ def __init__( self, parent ): self.m_panel_right_rgb = wx.Panel( self.images_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) right_bsizer0 = wx.BoxSizer( wx.VERTICAL ) - self.ptz_image_title = wx.StaticText( self.m_panel_right_rgb, wx.ID_ANY, u"Right RGB", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.ptz_image_title = wx.StaticText( self.m_panel_right_rgb, wx.ID_ANY, u"Right View RGB", wx.DefaultPosition, wx.DefaultSize, 0 ) self.ptz_image_title.Wrap( -1 ) self.ptz_image_title.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) @@ -676,7 +752,7 @@ def __init__( self, parent ): self.m_panel_left_ir = wx.Panel( self.images_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) left_bsizer1 = wx.BoxSizer( wx.VERTICAL ) - self.cueing_left_image_title1 = wx.StaticText( self.m_panel_left_ir, wx.ID_ANY, u"Left IR", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.cueing_left_image_title1 = wx.StaticText( self.m_panel_left_ir, wx.ID_ANY, u"Left View IR", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_left_image_title1.Wrap( -1 ) self.cueing_left_image_title1.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) @@ -708,7 +784,7 @@ def __init__( self, parent ): self.m_panel_center_ir = wx.Panel( self.images_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) right_bsizer1 = wx.BoxSizer( wx.VERTICAL ) - self.cueing_right_image_title1 = wx.StaticText( self.m_panel_center_ir, wx.ID_ANY, u"Center IR", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.cueing_right_image_title1 = wx.StaticText( self.m_panel_center_ir, wx.ID_ANY, u"Center View IR", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_right_image_title1.Wrap( -1 ) self.cueing_right_image_title1.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) @@ -740,7 +816,7 @@ def __init__( self, parent ): self.m_panel_right_ir = wx.Panel( self.images_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) ptz_bsizer1 = wx.BoxSizer( wx.VERTICAL ) - self.ptz_image_title1 = wx.StaticText( self.m_panel_right_ir, wx.ID_ANY, u"Right IR", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.ptz_image_title1 = wx.StaticText( self.m_panel_right_ir, wx.ID_ANY, u"Right View IR", wx.DefaultPosition, wx.DefaultSize, 0 ) self.ptz_image_title1.Wrap( -1 ) self.ptz_image_title1.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) @@ -777,7 +853,7 @@ def __init__( self, parent ): self.m_panel_left_uv = wx.Panel( self.images_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) left_bsizer2 = wx.BoxSizer( wx.VERTICAL ) - self.cueing_left_image_title2 = wx.StaticText( self.m_panel_left_uv, wx.ID_ANY, u"Left UV", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.cueing_left_image_title2 = wx.StaticText( self.m_panel_left_uv, wx.ID_ANY, u"Left View UV", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_left_image_title2.Wrap( -1 ) self.cueing_left_image_title2.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) @@ -809,7 +885,7 @@ def __init__( self, parent ): self.m_panel_center_uv = wx.Panel( self.images_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) right_bsizer2 = wx.BoxSizer( wx.VERTICAL ) - self.cueing_right_image_title2 = wx.StaticText( self.m_panel_center_uv, wx.ID_ANY, u"Center UV", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.cueing_right_image_title2 = wx.StaticText( self.m_panel_center_uv, wx.ID_ANY, u"Center View UV", wx.DefaultPosition, wx.DefaultSize, 0 ) self.cueing_right_image_title2.Wrap( -1 ) self.cueing_right_image_title2.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) @@ -841,7 +917,7 @@ def __init__( self, parent ): self.m_panel_right_uv = wx.Panel( self.images_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER|wx.TAB_TRAVERSAL ) ptz_bsizer2 = wx.BoxSizer( wx.VERTICAL ) - self.ptz_image_title2 = wx.StaticText( self.m_panel_right_uv, wx.ID_ANY, u"Right UV", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.ptz_image_title2 = wx.StaticText( self.m_panel_right_uv, wx.ID_ANY, u"Right View UV", wx.DefaultPosition, wx.DefaultSize, 0 ) self.ptz_image_title2.Wrap( -1 ) self.ptz_image_title2.SetFont( wx.Font( 14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, wx.EmptyString ) ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_imagery_inspection.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_imagery_inspection.py index 5af43ea..4c3e6b9 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_imagery_inspection.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_imagery_inspection.py @@ -36,8 +36,8 @@ def __init__( self, parent ): bSizer191.Add( self.m_staticText142, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 ) - image_stream_combo_boxChoices = [ u"Left RGB", u"Center RGB", u"Right RGB", u"Left IR", u"Center IR", u"Right IR", u"Left UV", u"Center UV", u"Right UV" ] - self.image_stream_combo_box = wx.ComboBox( self.image_stream_panel, wx.ID_ANY, u"Left RGB", wx.DefaultPosition, wx.DefaultSize, image_stream_combo_boxChoices, wx.CB_READONLY ) + image_stream_combo_boxChoices = [ u"Left View RGB", u"Center View RGB", u"Right View RGB", u"Left View IR", u"Center View IR", u"Right View IR", u"Left View UV", u"Center View UV", u"Right View UV" ] + self.image_stream_combo_box = wx.ComboBox( self.image_stream_panel, wx.ID_ANY, u"Left View RGB", wx.DefaultPosition, wx.DefaultSize, image_stream_combo_boxChoices, wx.CB_READONLY ) self.image_stream_combo_box.SetSelection( 0 ) bSizer191.Add( self.image_stream_combo_box, 0, wx.ALL|wx.EXPAND, 5 ) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index c43ae36..fbd3098 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -91,6 +91,7 @@ save_config_settings, save_camera_config, get_arch_path, + get_detector_pipefile, host_from_fov, pull_gui_state, format_status, @@ -130,49 +131,81 @@ P1_GAIN_MAX_PARAM = "ISO_Max" P1_EXPOSURE_MAX_PARAM = "Shutter_Speed_Min" P1_EXPOSURE_MIN_PARAM = "Shutter_Speed_Max" -P1_EXPOSURE_STOPS = [ - 0.0625, - 0.125, - 0.2, - 0.25, - 0.3125, - 0.4, - 0.5, - 0.625, - 0.8, - 1.0, - 1.25, - 1.5625, - 2.0, - 2.5, - 3.125, - 4.0, - 5.0, - 6.25, - 8.0, - 10, - 12.5, - 16.7, - 20, - 25, - 33.3, - 40, - 66.7, - 76.9, - 100, +P1_SHUTTER_MODE_PARAM = "Shutter_Mode" +P1_APERTURE_MIN_PARAM = "Aperture_Min" +P1_APERTURE_MAX_PARAM = "Aperture_Max" +P1_EXPOSURE_COMP_PARAM = "Exposure_Comp." +P1_SHUTTER_MODE_LS = "1" +P1_SHUTTER_MODE_ES = "2" +# Shutter Mode (LS/ES) label + dropdown hidden for now; exposure bias stays visible. +_SHOW_RGB_SHUTTER_MODE_CONTROLS = False +P1_LS_SHUTTER_DENOMS = [16000, 13000, 10000, 8000, 6500, 5000] +P1_ES_SHUTTER_DENOMS = [ + 4000, + 3200, + 2500, + 2000, + 1600, + 1250, + 1000, + 800, + 640, + 500, + 400, + 320, + 250, + 200, + 160, 125, - 166.7, + 100, + 80, + 60, + 50, + 40, + 30, + 25, + 20, + 15, + 13, + 10, +] +P1_ISO_STOPS = [ 200, 250, - 333.3, + 320, 400, 500, - 600, + 640, 800, 1000, + 1250, + 1600, + 2000, + 2500, + 3200, + 4000, + 5000, + 6400, +] +P1_APERTURE_STOPS = [ + 4.0, + 4.5, + 5.0, + 5.6, + 6.3, + 7.1, + 8.0, + 9.0, + 10, + 11, + 12, + 14, + 16, + 18, + 20, + 22, ] P1_GAIN_MIN = 0 -# P1_GAIN_MAX = 1600 P1_EXPOSURE_MIN = (1 / 16000.0) * 1e3 @@ -203,14 +236,6 @@ def __init__( self.SetTitle(window_title) # Recompute enlarged title fonts so they are not clipped under Phoenix. wx.CallAfter(gui_utils.unclip_static_text, self) - icon = wx.Icon() - icon.CopyFromBitmap( - wx.Bitmap( - os.path.expanduser("~/kamera/src/cfg/seal-icon.png"), - wx.BITMAP_TYPE_ANY, - ) - ) - self.SetIcon(icon) # self.rc = redis.Redis() @@ -433,7 +458,9 @@ def __init__( # -------------------------------------------------------------------- # ------------------------- Missed Frame -------------------------- + self._setup_rgb_controls() self.camera_setting_rgb_uv_combo.Bind(wx.EVT_COMBOBOX, self.on_modal_selection) + self.rgb_shutter_mode_combo.Bind(wx.EVT_COMBOBOX, self.on_rgb_shutter_mode) # Call once to hide/show proper options self.on_modal_selection(None) @@ -724,49 +751,266 @@ def _set_field_enabled(self, ctrl, enabled): ) ctrl.Refresh() + @staticmethod + def _format_aperture_stop(stop): + if stop == int(stop): + return str(int(stop)) + return "%g" % stop + + @staticmethod + def _shutter_denom_label(denom): + return "1/%d" % denom + + @staticmethod + def _shutter_denom_seconds(denom): + return 1.0 / denom + + @staticmethod + def _p1_shutter_denoms_for_mode(mode): + if mode == P1_SHUTTER_MODE_LS: + return P1_LS_SHUTTER_DENOMS + return P1_ES_SHUTTER_DENOMS + + @staticmethod + def _p1_shutter_mode_from_value(raw): + if raw in (None, ""): + return P1_SHUTTER_MODE_ES + return str(int(float(raw))) + + @staticmethod + def _p1_shutter_mode_label(mode): + return "LS" if mode == P1_SHUTTER_MODE_LS else "ES" + + @staticmethod + def _p1_iso_from_param(raw): + if raw in (None, ""): + return None + return nearest(P1_ISO_STOPS, int(float(raw))) + + @staticmethod + def _set_stop_combo(combo, stops, value): + if value in (None, ""): + combo.SetSelection(wx.NOT_FOUND) + return + stop = nearest(stops, float(value)) + combo.SetSelection(stops.index(stop)) + + @staticmethod + def _get_stop_combo(combo, stops): + sel = combo.GetSelection() + if sel == wx.NOT_FOUND: + return None + return stops[sel] + + def _exposure_input_sizer(self): + return self.exposure_min_value_txt_ctrl.GetContainingSizer() + + def _camera_panel_sizer(self): + return self.exposure_min_value_txt_ctrl.GetParent().GetSizer() + + def _get_p1_shutter_mode(self): + return ( + P1_SHUTTER_MODE_LS + if self.rgb_shutter_mode_combo.GetStringSelection() == "LS" + else P1_SHUTTER_MODE_ES + ) + + def _p1_shutter_stops(self): + denoms = self._p1_shutter_denoms_for_mode(self._get_p1_shutter_mode()) + return [self._shutter_denom_seconds(d) for d in denoms] + + def _populate_p1_shutter_combos(self, preserve=True): + denoms = self._p1_shutter_denoms_for_mode(self._get_p1_shutter_mode()) + labels = [self._shutter_denom_label(d) for d in denoms] + old_min = ( + self._get_stop_combo(self.exposure_min_combo, self._p1_exposure_stops) + if preserve and hasattr(self, "_p1_exposure_stops") + else None + ) + old_max = ( + self._get_stop_combo(self.exposure_max_combo, self._p1_exposure_stops) + if preserve and hasattr(self, "_p1_exposure_stops") + else None + ) + self._p1_exposure_stops = [self._shutter_denom_seconds(d) for d in denoms] + for combo in (self.exposure_min_combo, self.exposure_max_combo): + combo.Clear() + for label in labels: + combo.Append(label) + if old_min is not None: + self._set_stop_combo(self.exposure_min_combo, self._p1_exposure_stops, old_min) + if old_max is not None: + self._set_stop_combo(self.exposure_max_combo, self._p1_exposure_stops, old_max) + + def _setup_rgb_controls(self): + self._suppress_rgb_shutter_mode_confirm = False + self._rgb_shutter_mode_confirmed = self.rgb_shutter_mode_combo.GetStringSelection() + self._p1_exposure_stops = [] + self._populate_p1_shutter_combos(preserve=False) + for combo in (self.gain_min_combo, self.gain_max_combo): + combo.Clear() + for stop in P1_ISO_STOPS: + combo.Append(str(stop)) + combo.SetSelection(wx.NOT_FOUND) + for combo in (self.aperture_min_combo, self.aperture_max_combo): + combo.Clear() + for stop in P1_APERTURE_STOPS: + combo.Append(self._format_aperture_stop(stop)) + combo.SetSelection(wx.NOT_FOUND) + + def _update_camera_setting_widgets(self, mode): + use_rgb = mode == "RGB" + exposure_sizer = self._exposure_input_sizer() + gain_sizer = self.gain_min_value_txt_ctrl.GetContainingSizer() + panel_sizer = self._camera_panel_sizer() + + exposure_sizer.Show(self.exposure_min_value_txt_ctrl, not use_rgb) + exposure_sizer.Show(self.exposure_max_value_txt_ctrl, not use_rgb) + exposure_sizer.Show(self.exposure_min_combo, use_rgb) + exposure_sizer.Show(self.exposure_max_combo, use_rgb) + + gain_sizer.Show(self.gain_min_value_txt_ctrl, not use_rgb) + gain_sizer.Show(self.gain_max_value_txt_ctrl, not use_rgb) + gain_sizer.Show(self.gain_min_combo, use_rgb) + gain_sizer.Show(self.gain_max_combo, use_rgb) + + panel_sizer.Show(self.rgb_shutter_mode_row, use_rgb) + self.rgb_shutter_mode_row.Show( + self.rgb_shutter_section, _SHOW_RGB_SHUTTER_MODE_CONTROLS + ) + panel_sizer.Show(self.rgb_aperture_label, use_rgb) + panel_sizer.Show(self.rgb_aperture_row, use_rgb) + + if use_rgb: + self.m_staticText42.SetLabel("Shutter Speed") + self.m_staticText422.SetLabel("ISO (Gain)") + else: + self.m_staticText42.SetLabel("Auto Exposure (ms)") + self.m_staticText422.SetLabel("Auto Gain (0-32)") + + self.camera_panel.Layout() + + def _set_exposure_min_value(self, value): + mode = self.camera_setting_rgb_uv_combo.GetStringSelection() + if mode == "RGB": + self._set_stop_combo( + self.exposure_min_combo, self._p1_shutter_stops(), value + ) + else: + self.exposure_min_value_txt_ctrl.SetValue( + "" if value in (None, "") else str(value) + ) + + def _set_exposure_max_value(self, value): + mode = self.camera_setting_rgb_uv_combo.GetStringSelection() + if mode == "RGB": + self._set_stop_combo( + self.exposure_max_combo, self._p1_shutter_stops(), value + ) + else: + self.exposure_max_value_txt_ctrl.SetValue( + "" if value in (None, "") else str(value) + ) + + def _set_gain_min_value(self, value): + mode = self.camera_setting_rgb_uv_combo.GetStringSelection() + if mode == "RGB": + self._set_stop_combo(self.gain_min_combo, P1_ISO_STOPS, value) + else: + self.gain_min_value_txt_ctrl.SetValue( + "" if value in (None, "") else str(value) + ) + + def _set_gain_max_value(self, value): + mode = self.camera_setting_rgb_uv_combo.GetStringSelection() + if mode == "RGB": + self._set_stop_combo(self.gain_max_combo, P1_ISO_STOPS, value) + else: + self.gain_max_value_txt_ctrl.SetValue( + "" if value in (None, "") else str(value) + ) + + def _set_aperture_min_value(self, value): + self._set_stop_combo(self.aperture_min_combo, P1_APERTURE_STOPS, value) + + def _set_aperture_max_value(self, value): + self._set_stop_combo(self.aperture_max_combo, P1_APERTURE_STOPS, value) + + def _set_rgb_shutter_mode_selection(self, label): + self._suppress_rgb_shutter_mode_confirm = True + self.rgb_shutter_mode_combo.SetStringSelection(label) + self._rgb_shutter_mode_confirmed = label + self._suppress_rgb_shutter_mode_confirm = False + + def on_rgb_shutter_mode(self, event): + selection = self.rgb_shutter_mode_combo.GetStringSelection() + if ( + not self._suppress_rgb_shutter_mode_confirm + and selection == "LS" + and self._rgb_shutter_mode_confirmed != "LS" + ): + dlg = wx.MessageDialog( + self, + "Enabling the physical shutter greatly increases wear and tear on the camera, are you sure?", + "Confirm Shutter Mode", + wx.YES_NO | wx.ICON_WARNING, + ) + if dlg.ShowModal() != wx.ID_YES: + dlg.Destroy() + self._set_rgb_shutter_mode_selection(self._rgb_shutter_mode_confirmed) + return + dlg.Destroy() + self._rgb_shutter_mode_confirmed = selection + self._populate_p1_shutter_combos(preserve=True) + if event is not None: + event.Skip() + def on_modal_selection(self, event): self.on_camera_setting_subsys_selection(event) mode = self.camera_setting_rgb_uv_combo.GetStringSelection() + self._update_camera_setting_widgets(mode) + rgb_fields = ( + self.exposure_min_combo, + self.exposure_max_combo, + self.gain_min_combo, + self.gain_max_combo, + self.rgb_shutter_mode_combo, + self.aperture_min_combo, + self.aperture_max_combo, + ) if mode == "IR": self._set_field_enabled(self.exposure_max_value_txt_ctrl, False) self._set_field_enabled(self.exposure_min_value_txt_ctrl, False) + for ctrl in rgb_fields: + self._set_field_enabled(ctrl, False) self._set_field_enabled(self.gain_min_value_txt_ctrl, False) self._set_field_enabled(self.gain_max_value_txt_ctrl, False) + self._set_field_enabled(self.rgb_exposure_comp_txt_ctrl, False) self._set_field_enabled(self.ir_nuc_time, True) else: self._set_field_enabled(self.exposure_max_value_txt_ctrl, True) self._set_field_enabled(self.exposure_min_value_txt_ctrl, True) + for ctrl in rgb_fields: + self._set_field_enabled(ctrl, mode == "RGB") self._set_field_enabled(self.gain_min_value_txt_ctrl, True) self._set_field_enabled(self.gain_max_value_txt_ctrl, True) + self._set_field_enabled(self.rgb_exposure_comp_txt_ctrl, mode == "RGB") self._set_field_enabled(self.ir_nuc_time, False) def set_camera_parameter(self, hosts, mode, param, val): mode = mode.lower() if "ISO" in param: - # Scaling for Phase One - val = int(val * 50) - if mode == "rgb" and "Shutter" in param: - print("Casting exposure to phase one stop.") - # Set exposure to stop for Phase One - val = float(val) * 1e3 - if val not in P1_EXPOSURE_STOPS: - newval = nearest(P1_EXPOSURE_STOPS, val) - msg = ( - "Exposure value is not valid for Phase One, rounding %0.4fms to %0.4fms." - % (val, newval) - ) - dlg = wx.MessageDialog(self, msg, "Error", wx.OK | wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() - p1val = newval * 1e-3 - print(val, newval) - val = str(p1val) + val = int(val) + if mode == "rgb" and "Shutter" in param and "Mode" not in param: + val_sec = float(val) + stops = self._p1_shutter_stops() + if val_sec not in stops: + val_sec = nearest(stops, val_sec) if "Max" in param: - self.exposure_min_value_txt_ctrl.SetValue(str(newval)) + self._set_exposure_min_value(val_sec) elif "Min" in param: - self.exposure_max_value_txt_ctrl.SetValue(str(newval)) - else: - val = str(val * 1e-3) + self._set_exposure_max_value(val_sec) + val = str(val_sec) for host in hosts: SYS_CFG["requested_geni_params"][host][mode][param] = val @@ -787,24 +1031,69 @@ def check_box_val(self, val, typ=int): return None return val + @staticmethod + def _param_values_equal(a, b): + if a in (None, "") and b in (None, ""): + return True + if a in (None, "") or b in (None, ""): + return False + try: + return abs(float(a) - float(b)) < 1e-9 + except (TypeError, ValueError): + return str(a) == str(b) + + def _camera_setting_hosts(self, fov): + if fov == "all": + return self.hosts + return [host_from_fov(fov)] + + def _kv_param_unified(self, hosts, mode, param): + values = [] + for host in hosts: + topic_base = "/".join(["", "sys", "actual_geni_params", host, mode, ""]) + values.append(kv.get(topic_base + param, None)) + if not values: + return None + first = values[0] + for val in values[1:]: + if not self._param_values_equal(first, val): + return None + return first + + def _clear_rgb_shutter_mode_selection(self): + self._suppress_rgb_shutter_mode_confirm = True + self.rgb_shutter_mode_combo.SetSelection(wx.NOT_FOUND) + self._rgb_shutter_mode_confirmed = "" + self._suppress_rgb_shutter_mode_confirm = False + def on_camera_setting_subsys_selection(self, event): mode = self.camera_setting_rgb_uv_combo.GetStringSelection().lower() fov = self.camera_setting_subsys.GetString( self.camera_setting_subsys.GetCurrentSelection() ).lower() - if fov == "all": - host = "null" - else: - host = host_from_fov(fov) - topic_base = "/".join(["", "sys", "actual_geni_params", host, mode, ""]) + hosts = self._camera_setting_hosts(fov) if mode == "ir": - nuc_time = kv.get(topic_base + "CorrectionAutoDeltaTime", None) - nuc_time = nuc_time if nuc_time is not None else 0 - self.ir_nuc_time.SetValue(str(nuc_time)) + nuc_time = self._kv_param_unified( + hosts, mode, "CorrectionAutoDeltaTime" + ) + if nuc_time in (None, ""): + self.ir_nuc_time.SetValue("") + else: + self.ir_nuc_time.SetValue(str(nuc_time)) elif mode == "rgb" or mode == "uv": if mode == "rgb": - exp_factor = float(1e-3) - gain_factor = 1 / 50.0 + shutter_mode_raw = self._kv_param_unified( + hosts, mode, P1_SHUTTER_MODE_PARAM + ) + if shutter_mode_raw not in (None, ""): + self._set_rgb_shutter_mode_selection( + self._p1_shutter_mode_label( + self._p1_shutter_mode_from_value(shutter_mode_raw) + ) + ) + else: + self._clear_rgb_shutter_mode_selection() + self._populate_p1_shutter_combos(preserve=False) GAIN_MAX_PARAM = P1_GAIN_MAX_PARAM GAIN_MIN_PARAM = P1_GAIN_MIN_PARAM EXPOSURE_MAX_PARAM = P1_EXPOSURE_MAX_PARAM @@ -816,22 +1105,57 @@ def on_camera_setting_subsys_selection(self, event): GAIN_MIN_PARAM = PR_GAIN_MIN_PARAM EXPOSURE_MAX_PARAM = PR_EXPOSURE_MAX_PARAM EXPOSURE_MIN_PARAM = PR_EXPOSURE_MIN_PARAM - gain_min = kv.get(topic_base + GAIN_MIN_PARAM, None) - gain_max = kv.get(topic_base + GAIN_MAX_PARAM, None) - exp_min = kv.get(topic_base + EXPOSURE_MIN_PARAM, None) - exp_max = kv.get(topic_base + EXPOSURE_MAX_PARAM, None) - gain_min = ( - int(float(gain_min) * gain_factor) if gain_min is not None else "" - ) - gain_max = ( - int(float(gain_max) * gain_factor) if gain_max is not None else "" - ) - exp_max = float(exp_max) / exp_factor if exp_max is not None else "" - exp_min = float(exp_min) / exp_factor if exp_min is not None else "" - self.exposure_min_value_txt_ctrl.SetValue(str(exp_min)) - self.exposure_max_value_txt_ctrl.SetValue(str(exp_max)) - self.gain_min_value_txt_ctrl.SetValue(str(gain_min)) - self.gain_max_value_txt_ctrl.SetValue(str(gain_max)) + gain_min = self._kv_param_unified(hosts, mode, GAIN_MIN_PARAM) + gain_max = self._kv_param_unified(hosts, mode, GAIN_MAX_PARAM) + exp_min = self._kv_param_unified(hosts, mode, EXPOSURE_MIN_PARAM) + exp_max = self._kv_param_unified(hosts, mode, EXPOSURE_MAX_PARAM) + if mode == "rgb": + gain_min = self._p1_iso_from_param(gain_min) + gain_max = self._p1_iso_from_param(gain_max) + exp_min = float(exp_min) if exp_min not in (None, "") else "" + exp_max = float(exp_max) if exp_max not in (None, "") else "" + self._set_exposure_min_value(exp_min) + self._set_exposure_max_value(exp_max) + self._set_gain_min_value(gain_min) + self._set_gain_max_value(gain_max) + aperture_min = self._kv_param_unified( + hosts, mode, P1_APERTURE_MIN_PARAM + ) + aperture_max = self._kv_param_unified( + hosts, mode, P1_APERTURE_MAX_PARAM + ) + aperture_min = ( + float(aperture_min) if aperture_min not in (None, "") else "" + ) + aperture_max = ( + float(aperture_max) if aperture_max not in (None, "") else "" + ) + self._set_aperture_min_value(aperture_min) + self._set_aperture_max_value(aperture_max) + exposure_comp = self._kv_param_unified( + hosts, mode, P1_EXPOSURE_COMP_PARAM + ) + if exposure_comp in (None, ""): + self.rgb_exposure_comp_txt_ctrl.SetValue("") + else: + self.rgb_exposure_comp_txt_ctrl.SetValue(str(float(exposure_comp))) + else: + gain_min = ( + int(float(gain_min) * gain_factor) + if gain_min not in (None, "") + else "" + ) + gain_max = ( + int(float(gain_max) * gain_factor) + if gain_max not in (None, "") + else "" + ) + exp_max = float(exp_max) / exp_factor if exp_max not in (None, "") else "" + exp_min = float(exp_min) / exp_factor if exp_min not in (None, "") else "" + self._set_exposure_min_value(exp_min) + self._set_exposure_max_value(exp_max) + self.gain_min_value_txt_ctrl.SetValue(str(gain_min)) + self.gain_max_value_txt_ctrl.SetValue(str(gain_max)) def on_set_camera_parameter(self, event): mode = self.camera_setting_rgb_uv_combo.GetStringSelection() @@ -876,12 +1200,28 @@ def on_set_camera_parameter(self, event): self.set_camera_parameter(hosts, mode, param, val=nuc_time) elif mode == "RGB" or mode == "UV": if mode == "RGB": - factor = float(1e-3) GAIN_MAX_PARAM = P1_GAIN_MAX_PARAM GAIN_MIN_PARAM = P1_GAIN_MIN_PARAM EXPOSURE_MAX_PARAM = P1_EXPOSURE_MAX_PARAM EXPOSURE_MIN_PARAM = P1_EXPOSURE_MIN_PARAM - EXPOSURE_MIN = P1_EXPOSURE_MIN + shutter_mode = self._get_p1_shutter_mode() + self.set_camera_parameter( + hosts, mode, P1_SHUTTER_MODE_PARAM, val=shutter_mode + ) + exp_min = self._get_stop_combo( + self.exposure_min_combo, self._p1_shutter_stops() + ) + exp_max = self._get_stop_combo( + self.exposure_max_combo, self._p1_shutter_stops() + ) + gain_min = self._get_stop_combo(self.gain_min_combo, P1_ISO_STOPS) + gain_max = self._get_stop_combo(self.gain_max_combo, P1_ISO_STOPS) + aperture_min = self._get_stop_combo( + self.aperture_min_combo, P1_APERTURE_STOPS + ) + aperture_max = self._get_stop_combo( + self.aperture_max_combo, P1_APERTURE_STOPS + ) else: factor = 1e3 GAIN_MAX_PARAM = PR_GAIN_MAX_PARAM @@ -889,13 +1229,16 @@ def on_set_camera_parameter(self, event): EXPOSURE_MAX_PARAM = PR_EXPOSURE_MAX_PARAM EXPOSURE_MIN_PARAM = PR_EXPOSURE_MIN_PARAM EXPOSURE_MIN = PR_EXPOSURE_MIN - # factor = 1e3 Prosilica - exp_min = self.check_box_val( - self.exposure_min_value_txt_ctrl.GetValue(), float - ) - exp_max = self.check_box_val( - self.exposure_max_value_txt_ctrl.GetValue(), float - ) + exp_min = self.check_box_val( + self.exposure_min_value_txt_ctrl.GetValue(), float + ) + exp_max = self.check_box_val( + self.exposure_max_value_txt_ctrl.GetValue(), float + ) + gain_min = self.check_box_val(self.gain_min_value_txt_ctrl.GetValue()) + gain_max = self.check_box_val(self.gain_max_value_txt_ctrl.GetValue()) + aperture_min = None + aperture_max = None if exp_min is None and exp_max is None: pass elif (exp_min is None and exp_max is not None) or ( @@ -906,6 +1249,22 @@ def on_set_camera_parameter(self, event): dlg.ShowModal() dlg.Destroy() pass + elif mode == "RGB": + if exp_max < exp_min: + msg = ( + "Shutter speed maximum must allow equal or longer exposure " + "than the minimum." + ) + dlg = wx.MessageDialog(self, msg, "Error", wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + self.set_camera_parameter( + hosts, mode, EXPOSURE_MIN_PARAM, val=exp_min + ) + self.set_camera_parameter( + hosts, mode, EXPOSURE_MAX_PARAM, val=exp_max + ) elif exp_min < EXPOSURE_MIN or exp_min > SYS_CFG["arch"]["max_exposure_ms"]: msg = "Exposure minimum value must be >= %s and <= %sms." % ( EXPOSURE_MIN, @@ -938,8 +1297,6 @@ def on_set_camera_parameter(self, event): param = EXPOSURE_MAX_PARAM self.set_camera_parameter(hosts, mode, param, val=exp_max_ms) - gain_min = self.check_box_val(self.gain_min_value_txt_ctrl.GetValue()) - gain_max = self.check_box_val(self.gain_max_value_txt_ctrl.GetValue()) if gain_min is None and gain_max is None: pass elif (gain_min is None and gain_max is not None) or ( @@ -950,6 +1307,15 @@ def on_set_camera_parameter(self, event): dlg.ShowModal() dlg.Destroy() pass + elif mode == "RGB": + if gain_max < gain_min: + msg = "ISO maximum must be >= ISO minimum." + dlg = wx.MessageDialog(self, msg, "Error", wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + self.set_camera_parameter(hosts, mode, GAIN_MIN_PARAM, val=gain_min) + self.set_camera_parameter(hosts, mode, GAIN_MAX_PARAM, val=gain_max) elif gain_min < 0 or gain_min > GAIN_MAX: msg = "Gain minimum value must be >= 0 and <= %s." % GAIN_MAX dlg = wx.MessageDialog(self, msg, "Error", wx.OK | wx.ICON_ERROR) @@ -973,6 +1339,38 @@ def on_set_camera_parameter(self, event): else: param = GAIN_MAX_PARAM self.set_camera_parameter(hosts, mode, param, val=gain_max) + + if mode == "RGB": + if (aperture_min is None and aperture_max is not None) or ( + aperture_max is None and aperture_min is not None + ): + msg = "Both aperture min/max value must be set." + dlg = wx.MessageDialog(self, msg, "Error", wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + if aperture_min is not None and aperture_max is not None: + if aperture_max < aperture_min: + msg = "Aperture maximum must be >= aperture minimum." + dlg = wx.MessageDialog( + self, msg, "Error", wx.OK | wx.ICON_ERROR + ) + dlg.ShowModal() + dlg.Destroy() + return + self.set_camera_parameter( + hosts, mode, P1_APERTURE_MIN_PARAM, val=aperture_min + ) + self.set_camera_parameter( + hosts, mode, P1_APERTURE_MAX_PARAM, val=aperture_max + ) + exposure_comp = self.check_box_val( + self.rgb_exposure_comp_txt_ctrl.GetValue(), float + ) + if exposure_comp is not None: + self.set_camera_parameter( + hosts, mode, P1_EXPOSURE_COMP_PARAM, val=exposure_comp + ) else: msg = "Invalid mode selected, must be IR, UV, or RGB." dlg = wx.MessageDialog(self, msg, "Error", wx.OK | wx.ICON_ERROR) @@ -1595,31 +1993,31 @@ def on_cancel_running_jobs(self, event): # -------------------- Launch Image Inspection Frame --------------------- def on_dclick_left_rgb(self, event): - self.open_image_inspection_panel("Left RGB") + self.open_image_inspection_panel("Left View RGB") def on_dclick_center_rgb(self, event): - self.open_image_inspection_panel("Center RGB") + self.open_image_inspection_panel("Center View RGB") def on_dclick_right_rgb(self, event): - self.open_image_inspection_panel("Right RGB") + self.open_image_inspection_panel("Right View RGB") def on_dclick_left_ir(self, event): - self.open_image_inspection_panel("Left IR") + self.open_image_inspection_panel("Left View IR") def on_dclick_center_ir(self, event): - self.open_image_inspection_panel("Center IR") + self.open_image_inspection_panel("Center View IR") def on_dclick_right_ir(self, event): - self.open_image_inspection_panel("Right IR") + self.open_image_inspection_panel("Right View IR") def on_dclick_left_uv(self, event): - self.open_image_inspection_panel("Left UV") + self.open_image_inspection_panel("Left View UV") def on_dclick_center_uv(self, event): - self.open_image_inspection_panel("Center UV") + self.open_image_inspection_panel("Center View UV") def on_dclick_right_uv(self, event): - self.open_image_inspection_panel("Right UV") + self.open_image_inspection_panel("Right View UV") # ------------------------------------------------------------------------ @@ -1874,45 +2272,9 @@ def update_show_hide(self): # ------------------------------------------------------------------------ # ---------------------------- Detection Menu ---------------------------- - def _valid_detector_pipe(self, pipe): - return pipe and pipe != "null" - - def apply_detector_pipefiles(self, sys_cfg_name=None): - """Sync per-host detector pipefiles from the active camera configuration.""" - if sys_cfg_name is None: - sys_cfg_name = self.get_sys_cfg() - try: - cc = SYS_CFG["camera_cfgs"][sys_cfg_name] - except KeyError: - return - fov_pipes = { - "center": cc.get("center_sys_pipe"), - "left": cc.get("left_sys_pipe"), - "right": cc.get("right_sys_pipe"), - } - for host in self.hosts: - fov = SYS_CFG["arch"]["hosts"][host]["fov"] - pipe = fov_pipes.get(fov) - if self._valid_detector_pipe(pipe): - SYS_CFG[host]["detector"]["pipefile"] = pipe - else: - SYS_CFG[host]["detector"]["pipefile"] = None - def resolve_detector_pipefile(self, host): - """Return the detector pipefile for a host, using camera config if needed.""" - pipe = SYS_CFG[host]["detector"].get("pipefile") - if self._valid_detector_pipe(pipe): - return pipe - try: - cc = SYS_CFG["camera_cfgs"][self.get_sys_cfg()] - fov = SYS_CFG["arch"]["hosts"][host]["fov"] - pipe = cc.get("{}_sys_pipe".format(fov)) - except KeyError: - return None - if self._valid_detector_pipe(pipe): - SYS_CFG[host]["detector"]["pipefile"] = pipe - return pipe - return None + """Return the detector pipefile for a host from the active camera config.""" + return get_detector_pipefile(host, self.get_sys_cfg()) def do_start_a_detector(self, event=None, host="unset", log=True): cmdpipef = self.resolve_detector_pipefile(host) @@ -2205,8 +2567,6 @@ def set_camera_config_dict(self, config_dict=None): self.camera_config_combo.SetSelection(0) SYS_CFG["arch"]["sys_cfg"] = self.camera_config_combo.GetStringSelection() - self.apply_detector_pipefiles() - def next_camera_config(self, event=None): ind = self.camera_config_combo.GetSelection() if ind == wx.NOT_FOUND: @@ -2218,7 +2578,7 @@ def next_camera_config(self, event=None): ind = 0 self.camera_config_combo.SetSelection(ind) - self.apply_detector_pipefiles() + SYS_CFG["arch"]["sys_cfg"] = self.get_sys_cfg() def previous_camera_config(self, event=None): ind = self.camera_config_combo.GetSelection() @@ -2231,7 +2591,7 @@ def previous_camera_config(self, event=None): ind = self.camera_config_combo.GetCount() - 1 self.camera_config_combo.SetSelection(ind) - self.apply_detector_pipefiles() + SYS_CFG["arch"]["sys_cfg"] = self.get_sys_cfg() def on_camera_config_combo(self, event=None): """ """ @@ -2242,9 +2602,9 @@ def on_camera_config_combo(self, event=None): syscfg_dir = SYS_CFG["syscfg_dir"] vfov = load_from_file(cc["center_rgb_yaml_path"]).fov()[1] SYS_CFG["rgb_vfov"] = vfov + SYS_CFG["arch"]["sys_cfg"] = curr_str save_camera_config(curr_str) self.update_project_flight_params() - self.apply_detector_pipefiles(curr_str) # ------------------------- END Camera Configuration ------------------------- From 2252b97a3d2fa598b78752bbb82ad90fe9ead2c8 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Thu, 18 Jun 2026 10:04:58 -0400 Subject: [PATCH 129/139] Display speed instead of exposure in ms --- scripts/system.py | 5 +++- .../wxpython_gui/src/wxpython_gui/cfg.py | 23 +++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/scripts/system.py b/scripts/system.py index 00e9cf9..a4abd50 100644 --- a/scripts/system.py +++ b/scripts/system.py @@ -9,13 +9,15 @@ group = SYSTEM_NAME pod = [ "image_manager", - "kamerad", f"{group}:fps_monitor", f"{group}:imageview", f"{group}:cam_rgb", f"{group}:cam_ir", f"{group}:cam_uv", ] +daemon = [ + "kamerad", +] host = sys.argv[1].strip() if host not in hosts: @@ -25,6 +27,7 @@ cluster = sys.argv[3] group2processes = { "pod": pod, + "daemon": daemon, "central": [f"{group}:ins", f"{group}:daq"], "monitor": [ f"{group}:cam_param_monitor", diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py index 90fe8fc..5f44260 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py @@ -346,6 +346,16 @@ def save_camera_config(curr_cfg=None): return camera_config_filename +def _format_shutter_speed_label(exposure_us): + """Render Phase One shutter speed as a fractional stop (e.g. 1/2500).""" + if exposure_us is None: + return "Spd: ?" + seconds = float(exposure_us) * 1e-6 + if seconds <= 0: + return "Spd: ?" + return "Spd: 1/%d" % int(round(1.0 / seconds)) + + def format_status( timeval=None, num_dropped=None, @@ -395,11 +405,14 @@ def format_status( total = total - 1 if total > 0 else total drop_str += " | DB: {}/{}".format(processed, total) processed_str = "" if processed is None else "{}".format(processed) - expo_str = ( - "Exp: ? ms" - if exposure_us is None - else "Exp: {:0.2f} ms".format(float(exposure_us) * 1e-3) - ) + if chan == "rgb": + expo_str = _format_shutter_speed_label(exposure_us) + else: + expo_str = ( + "Exp: ? ms" + if exposure_us is None + else "Exp: {:0.2f} ms".format(float(exposure_us) * 1e-3) + ) if chan == "ir": fmt = "{fps}\n{drop}" out = fmt.format(fps=fps_str, drop=drop_str) From 511206d8a895bfc90cdf26922c00263d5836c2eb Mon Sep 17 00:00:00 2001 From: romleiaj Date: Thu, 18 Jun 2026 10:05:57 -0400 Subject: [PATCH 130/139] If any camera parameter changes, light up the 'set' button so its obvious that has to be pressed. Also make flight number setting more intuitive, don't throw an error at every time --- .../wxpython_gui/system_control_panel/gui.py | 101 ++++++++++++++++-- 1 file changed, 90 insertions(+), 11 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index fbd3098..d6798d6 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -459,6 +459,9 @@ def __init__( # ------------------------- Missed Frame -------------------------- self._setup_rgb_controls() + self._set_camera_param_btn_default_bg = self.m_button10.GetBackgroundColour() + self._set_camera_param_btn_default_fg = self.m_button10.GetForegroundColour() + self._bind_camera_param_dropdown_handlers() self.camera_setting_rgb_uv_combo.Bind(wx.EVT_COMBOBOX, self.on_modal_selection) self.rgb_shutter_mode_combo.Bind(wx.EVT_COMBOBOX, self.on_rgb_shutter_mode) # Call once to hide/show proper options @@ -751,6 +754,52 @@ def _set_field_enabled(self, ctrl, enabled): ) ctrl.Refresh() + def _camera_param_dropdowns(self): + return ( + self.rgb_shutter_mode_combo, + self.exposure_min_combo, + self.exposure_max_combo, + self.gain_min_combo, + self.gain_max_combo, + self.aperture_min_combo, + self.aperture_max_combo, + ) + + def _camera_param_dropdown_state(self): + state = [] + for combo in self._camera_param_dropdowns(): + if not combo.IsEnabled(): + continue + sel = combo.GetSelection() + if sel == wx.NOT_FOUND: + state.append((id(combo), None)) + else: + state.append((id(combo), combo.GetStringSelection())) + return tuple(state) + + def _bind_camera_param_dropdown_handlers(self): + for combo in self._camera_param_dropdowns(): + combo.Bind(wx.EVT_COMBOBOX, self._on_camera_param_dropdown_changed) + + def _on_camera_param_dropdown_changed(self, event): + self._update_set_camera_param_button_highlight() + event.Skip() + + def _save_applied_camera_param_state(self): + self._applied_camera_param_state = self._camera_param_dropdown_state() + self._update_set_camera_param_button_highlight() + + def _update_set_camera_param_button_highlight(self): + applied = getattr(self, "_applied_camera_param_state", ()) + pending = self._camera_param_dropdown_state() != applied + if pending: + self.m_button10.SetBackgroundColour(wx.Colour(*WARN_AMBER)) + self.m_button10.SetForegroundColour(wx.Colour(*TEXTCTRL_DARK)) + else: + self.m_button10.SetBackgroundColour(self._set_camera_param_btn_default_bg) + self.m_button10.SetForegroundColour(self._set_camera_param_btn_default_fg) + self.m_button10.Refresh() + @staticmethod def _format_aperture_stop(stop): if stop == int(stop): @@ -1157,6 +1206,8 @@ def on_camera_setting_subsys_selection(self, event): self.gain_min_value_txt_ctrl.SetValue(str(gain_min)) self.gain_max_value_txt_ctrl.SetValue(str(gain_max)) + self._save_applied_camera_param_state() + def on_set_camera_parameter(self, event): mode = self.camera_setting_rgb_uv_combo.GetStringSelection() host = self.camera_setting_subsys.GetString( @@ -1188,6 +1239,7 @@ def on_set_camera_parameter(self, event): self.set_camera_parameter(hosts, mode, param, val=0) param = "CorrectionAutoUseDeltaTemp" self.set_camera_parameter(hosts, mode, param, val=1) + self._save_applied_camera_param_state() return else: # Received a certain delta T to use, disable delta temp and enable delta time @@ -1381,6 +1433,7 @@ def on_set_camera_parameter(self, event): host = "all" else: host = hosts[0] + self._save_applied_camera_param_state() def on_exp_key_press(self, event): # type: (wx.KeyEvent) -> None @@ -1666,8 +1719,12 @@ def load_config_settings(self): except KeyError as e: print(e) self.flight_number_text_ctrl.Unbind(wx.EVT_TEXT) + self.flight_number_text_ctrl.Unbind(wx.EVT_TEXT_ENTER) + self.flight_number_text_ctrl.Unbind(wx.EVT_KILL_FOCUS) self.flight_number_text_ctrl.SetValue(self.flight_number_str) - self.flight_number_text_ctrl.Bind(wx.EVT_TEXT, self.on_update_flight_number) + self.flight_number_text_ctrl.Bind(wx.EVT_TEXT, self.on_flight_number_text) + self.flight_number_text_ctrl.Bind(wx.EVT_TEXT_ENTER, self.on_flight_number_commit) + self.flight_number_text_ctrl.Bind(wx.EVT_KILL_FOCUS, self.on_flight_number_commit) self.update_collect_colors() print("Loaded config.") @@ -2148,19 +2205,41 @@ def ins_state(self, msg): else: self.gnss_status_flag_txtctrl.SetValue("") - def on_update_flight_number(self, event=None): - flight_number_str = self.flight_number_text_ctrl.GetValue() - try: - test = int(flight_number_str) - except: - self.flight_number_text_ctrl.SetValue(self.flight_number_str) + def on_flight_number_text(self, event=None): + val = self.flight_number_text_ctrl.GetValue() + if val == "": + self.flight_number_text_ctrl.SetForegroundColour(wx.Colour(180, 180, 180)) + elif self._flight_number_valid(val): + self.flight_number_text_ctrl.SetForegroundColour(wx.NullColour) + else: + self.flight_number_text_ctrl.SetForegroundColour(wx.Colour(200, 0, 0)) + self.flight_number_text_ctrl.Refresh() + + def on_flight_number_commit(self, event=None): + val = self.flight_number_text_ctrl.GetValue() + if self._flight_number_valid(val): + self.flight_number_str = val + self.flight_number_text_ctrl.SetForegroundColour(wx.NullColour) + self.flight_number_text_ctrl.Refresh() + self.add_to_console_log(self.flight_number_str, "on_flight_number_commit") + else: msg = "Flight number must be an integer, e.g. 01, 02, 001, etc." - dlg = wx.MessageDialog(self, msg, "Error", wx.OK | wx.ICON_ERROR) + dlg = wx.MessageDialog(self, msg, "Invalid Flight Number", wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy() - return - self.flight_number_str = flight_number_str - self.add_to_console_log(self.flight_number_str, "on_update_flight_number") + self.flight_number_text_ctrl.SetValue(self.flight_number_str) + self.flight_number_text_ctrl.SetForegroundColour(wx.NullColour) + self.flight_number_text_ctrl.Refresh() + if event: + event.Skip() + + @staticmethod + def _flight_number_valid(val): + try: + int(val) + return bool(val) + except (ValueError, TypeError): + return False # ---------------------------- Show/Hide Images -------------------------- def on_show_or_hide_left(self, event): From e529a73f86ecd59ccfd629d72b8362f375b256ac Mon Sep 17 00:00:00 2001 From: romleiaj Date: Thu, 18 Jun 2026 10:23:14 -0400 Subject: [PATCH 131/139] Make kamerad run on startup, and autorestart. Make kamera_run just launch the gui if the system (roscore) is already up - saving the need for a separate gui desktop icon --- scripts/kamera_run.sh | 16 ++++++++++++++++ tmux/nayak/follower/supervisor.conf | 3 ++- tmux/nayak/leader/supervisor.conf | 3 ++- tmux/taiga/follower/supervisor.conf | 3 ++- tmux/taiga/leader/supervisor.conf | 3 ++- 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/scripts/kamera_run.sh b/scripts/kamera_run.sh index e2ebe6e..97e94b3 100755 --- a/scripts/kamera_run.sh +++ b/scripts/kamera_run.sh @@ -41,6 +41,20 @@ if [[ -z "${MODE}" ]]; then exit 1 fi +# If rosmaster is already reachable on a start/up, skip the full startup and +# just open the GUI so config files aren't re-seeded on a live system. +if [[ "${MODE}" == "up" ]]; then + echo "Checking if system is up..." + cd ${KAM_REPO_DIR} && docker compose -f ${KAM_REPO_DIR}/compose/nodelist.yml run --rm nodelist > /dev/null 2>&1 + code=$? + if [[ $code == 0 ]]; then + blueprintf "System already up. Opening GUI only.\n" + xhost +local:root + docker compose -f "${KAM_REPO_DIR}/compose/gui.yml" up + exit $? + fi +fi + ## === === === === === === Env setup === === === === === === === blueprintf "Configuring main KAMERA entrypoint." # Add detector ENV variables to Redis @@ -155,6 +169,8 @@ IFS=$'\n' sorted_hosts=($(sort <<<"${hosts[*]}")) unset IFS for host in "${sorted_hosts[@]}"; do if [[ $(cq ".arch.hosts.${host}.enabled") == 'true' ]]; then + # daemon group (kamerad) is always started and never stopped by normal operations + python3 ${KAM_REPO_DIR}/scripts/system.py $host start daemon python3 ${KAM_REPO_DIR}/scripts/system.py $host "${ARGS[@]}" pod & PIDS[${host}]=$! else diff --git a/tmux/nayak/follower/supervisor.conf b/tmux/nayak/follower/supervisor.conf index 0123889..fc8d80c 100644 --- a/tmux/nayak/follower/supervisor.conf +++ b/tmux/nayak/follower/supervisor.conf @@ -1,7 +1,8 @@ [program:kamerad] command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh kamerad user=user -autostart=false +autostart=true +autorestart=true [program:image_manager] command=/bin/bash /home/user/kw/kamera/tmux/nayak/follower/start_tmux_session.sh image_manager diff --git a/tmux/nayak/leader/supervisor.conf b/tmux/nayak/leader/supervisor.conf index 59e5d5f..932f660 100644 --- a/tmux/nayak/leader/supervisor.conf +++ b/tmux/nayak/leader/supervisor.conf @@ -1,7 +1,8 @@ [program:kamerad] command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh kamerad user=user -autostart=false +autostart=true +autorestart=true [program:image_manager] command=/bin/bash /home/user/kw/kamera/tmux/nayak/leader/start_tmux_session.sh image_manager diff --git a/tmux/taiga/follower/supervisor.conf b/tmux/taiga/follower/supervisor.conf index 626133e..bfb77ad 100644 --- a/tmux/taiga/follower/supervisor.conf +++ b/tmux/taiga/follower/supervisor.conf @@ -1,7 +1,8 @@ [program:kamerad] command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh kamerad user=user -autostart=false +autostart=true +autorestart=true [program:image_manager] command=/bin/bash /home/user/kw/kamera/tmux/taiga/follower/start_tmux_session.sh image_manager diff --git a/tmux/taiga/leader/supervisor.conf b/tmux/taiga/leader/supervisor.conf index 041fa46..a52f86b 100644 --- a/tmux/taiga/leader/supervisor.conf +++ b/tmux/taiga/leader/supervisor.conf @@ -1,7 +1,8 @@ [program:kamerad] command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh kamerad user=user -autostart=false +autostart=true +autorestart=true [program:image_manager] command=/bin/bash /home/user/kw/kamera/tmux/taiga/leader/start_tmux_session.sh image_manager From c2f1833dc4c52bf47d50504d5ae05b2e433cd62f Mon Sep 17 00:00:00 2001 From: romleiaj Date: Thu, 18 Jun 2026 10:26:01 -0400 Subject: [PATCH 132/139] Delete gui icon --- provision/start_stop/desktop_shortcuts/kamera_gui.desktop | 7 ------- 1 file changed, 7 deletions(-) delete mode 100755 provision/start_stop/desktop_shortcuts/kamera_gui.desktop diff --git a/provision/start_stop/desktop_shortcuts/kamera_gui.desktop b/provision/start_stop/desktop_shortcuts/kamera_gui.desktop deleted file mode 100755 index e1a7333..0000000 --- a/provision/start_stop/desktop_shortcuts/kamera_gui.desktop +++ /dev/null @@ -1,7 +0,0 @@ -[Desktop Entry] -Exec=gnome-terminal -e '/home/user/kw/kamera/tmux/taiga/start_gui.sh' -Name=kamera_gui -Terminal=true -Icon=video-display -Type=Application -Name[en_US]=Launch\nKAMERA GUI From 5985234d39b08b3b1179b894f49b718cd0ca4b99 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Thu, 18 Jun 2026 11:20:28 -0400 Subject: [PATCH 133/139] Resolve 2 bugs in phase one camera driver. The 'total' counter is now cache in redis on update, not when an image is processed, removing the 10 frame delay from being present in the display. The 10 frame delay is now emptied when archiving is stopped, also fixing display issues --- .../phase_one/src/phase_one_standalone.cpp | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/cams/phase_one/src/phase_one_standalone.cpp b/src/cams/phase_one/src/phase_one_standalone.cpp index 44d1060..704238e 100755 --- a/src/cams/phase_one/src/phase_one_standalone.cpp +++ b/src/cams/phase_one/src/phase_one_standalone.cpp @@ -550,6 +550,8 @@ namespace phase_one } } total_counter++; + envoy_->put("/sys/" + hostname + "/p1debayerq/total", + std::to_string(total_counter)); } catch (boost::filesystem::filesystem_error &e) { ROS_ERROR("|CAPTURE| Archive Failed [%d]: %s", e.code().value(), e.what()); } catch (const std::ios_base::failure& e) { @@ -676,14 +678,29 @@ namespace phase_one auto tic1 = std::chrono::high_resolution_clock::now(); std::string filename; std::unique_lock lock(mtx); - // Add in (at least) a 1 image delay so that detection can keep up - // This does always leave the last image not debayered, but that's - // generally of the tarmac, so not a serious concern. - int delay = 10; - if ( filename_to_seq_map_.size() > delay ) { - // grab most-recent filename (could make a LIFO queue?) + // Hold back at least "delay" images so the detection callback has time + // to process and skip images with no detections before debayering. + // When archiving stops, flush the remaining tail without the delay so + // the queue drains cleanly and the counter reaches 0 (rather than + // being stuck at delay - 1). + const int delay = 10; + if (filename_to_seq_map_.size() > (size_t)delay) { + filename = filename_to_seq_map_.begin()->first; + filename_to_seq_map_.erase(filename); + } else if (!filename_to_seq_map_.empty()) { + lock.unlock(); + int is_archiving = ArchiverHelper::get_is_archiving(envoy_, "/sys/arch/is_archiving"); + if (is_archiving) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + continue; + } + lock.lock(); + if (filename_to_seq_map_.empty()) { + lock.unlock(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + continue; + } filename = filename_to_seq_map_.begin()->first; - // remove from map filename_to_seq_map_.erase(filename); } else { lock.unlock(); @@ -778,11 +795,8 @@ namespace phase_one } // Throw results into redis for access std::string base = "/sys/" + hostname + "/p1debayerq/"; - std::string total = base + "total"; std::string num_processed = base + "processed"; std::string processed_str = std::to_string(processed_counter); - std::string total_str = std::to_string(total_counter); - envoy_->put(total, total_str); envoy_->put(num_processed, processed_str); toc = std::chrono::high_resolution_clock::now(); dt = toc - tic1; @@ -1389,11 +1403,8 @@ namespace phase_one std::ofstream output(fname); // Throw results into redis for access std::string base = "/sys/" + hostname + "/p1debayerq/"; - std::string total = base + "total"; std::string num_processed = base + "processed"; std::string processed_str = std::to_string(processed_counter); - std::string total_str = std::to_string(total_counter); - envoy_->put(total, total_str); envoy_->put(num_processed, processed_str); } } // else image has detections, so save regardless From 7c91a5ac018fd2b395c9d94306c4c59a88033adf Mon Sep 17 00:00:00 2001 From: romleiaj Date: Thu, 18 Jun 2026 11:21:00 -0400 Subject: [PATCH 134/139] Add more color indicators, properly display debayer frames --- .../wxpython_gui/src/wxpython_gui/cfg.py | 4 +- .../wxpython_gui/system_control_panel/gui.py | 173 ++++++++++++++++-- 2 files changed, 158 insertions(+), 19 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py index 5f44260..1e52325 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py @@ -253,6 +253,7 @@ def save_config_settings(): FLAT_GRAY = (200, 200, 200) DISABLED_GRAY = (150, 150, 150) # Darker fill for disabled input fields COLLECT_GREEN = (55, 120, 25) +COLLECT_ALERT_RED = (215, 65, 65) # alert red while collecting with a fault SHAPE_COLLECT_BLUE = ( 52, 100, @@ -400,9 +401,6 @@ def format_status( ) fps_str = "? fps" if fps is None else "{:4.2f} fps".format(fps) if total is not None and processed is not None: - # display N/N, even if internally it's N-1/N - if processed < total: - total = total - 1 if total > 0 else total drop_str += " | DB: {}/{}".format(processed, total) processed_str = "" if processed is None else "{}".format(processed) if chan == "rgb": diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index d6798d6..903b6d3 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -78,6 +78,7 @@ APP_GRAY, BRIGHT_RED, COLLECT_GREEN, + COLLECT_ALERT_RED, ERROR_RED, FLAT_GRAY, DISABLED_GRAY, @@ -283,6 +284,7 @@ def __init__( # Setting wx.CB_READONLY doesn't allow you to SetEditable(True) later. self.effort_combo_box.SetEditable(False) + self.effort_combo_box.SetBackgroundColour(wx.WHITE) self.camera_config_combo.SetEditable(False) self._collecting = None @@ -299,6 +301,10 @@ def __init__( self._spoof_gps = kv.get("/debug/spoof_gps", False) and self._debug_enable self._spoof_events = int(kv.get("/debug/spoof_events", 0)) self.last_ins_time = 0.0 + self._collect_health_ssd_ok = True + self._collect_health_nas_ok = True + self._collect_health_cameras_ok = True + self._collect_stream_stale_sec = 10.0 if self._spoof_gps: print("SPOOF GPS ENABLED") if self._spoof_events == 1: @@ -708,6 +714,17 @@ def _system_sanity_worker(self, hosts): def _apply_system_sanity(self, results, nas_unmounts): """Apply system_sanity_check results to the UI (main thread only).""" + ssd_ok = True + for host in self.hosts: + entry = results.get(host, {}) + if entry.get("ssd_err") or entry.get("ssd_gb") is None: + ssd_ok = False + break + center_entry = results.get(self.hosts[0], {}) + nas_ok = not nas_unmounts and center_entry.get("nas_gb") is not None + self._collect_health_ssd_ok = ssd_ok + self._collect_health_nas_ok = nas_ok + for host, entry in results.items(): try: fov = SYS_CFG["arch"]["hosts"][host]["fov"] @@ -733,6 +750,119 @@ def _apply_system_sanity(self, results, nas_unmounts): self.nas_disk_space.SetLabel("NAS Err: " + "".join(nas_unmounts)) self.nas_disk_space.SetForegroundColour(ERROR_RED) gui_utils.refit_label(self.nas_disk_space) + self.update_collect_colors() + + def _ins_stream_healthy(self): + if self.last_ins_time <= 0: + return False + return time.time() - self.last_ins_time <= self._collect_stream_stale_sec + + def _collecting_critical_health_ok(self): + if not self._collect_health_ssd_ok: + return False + if not self._collect_health_nas_ok: + return False + if not self._collect_health_cameras_ok: + return False + return True + + def _flight_data_header_widgets(self): + return ( + self.m_staticText14211, + self.m_staticText33, + self.m_staticText34, + self.flight_number_text_ctrl, + self.m_staticText331, + self.observer_text_ctrl, + self.m_staticText18171311, + self.effort_combo_box, + ) + + def _collecting_panel_colour(self): + if not self._collecting_critical_health_ok(): + return wx.Colour(*COLLECT_ALERT_RED) + if self._spoof_events == 1 or not self._ins_stream_healthy(): + return self._spoof_events_colour() + return wx.Colour(*COLLECT_GREEN) + + def _apply_flight_data_header_background(self, colour): + for widget in self._flight_data_header_widgets(): + if widget is self.effort_combo_box: + continue + widget.SetBackgroundColour(colour) + widget.Refresh() + self.effort_combo_box.SetBackgroundColour(wx.WHITE) + self.effort_combo_box.Refresh() + + def _reset_flight_data_header_backgrounds(self): + for widget in self._flight_data_header_widgets(): + if widget in (self.flight_number_text_ctrl, self.observer_text_ctrl): + if widget.IsEditable(): + widget.SetBackgroundColour(wx.WHITE) + else: + widget.SetBackgroundColour(wx.Colour(*DISABLED_GRAY)) + elif widget is self.effort_combo_box: + widget.SetBackgroundColour(wx.WHITE) + else: + widget.SetBackgroundColour(wx.Colour(*APP_GRAY)) + widget.Refresh() + + def _reset_flight_data_panel_child_backgrounds(self): + """Clear collecting-state colours from child widgets.""" + self._reset_flight_data_header_backgrounds() + for child in self.flight_data_panel.GetChildren(): + if child in self._flight_data_header_widgets(): + continue + if child in (self.recording_gauge, self.detectors_gauge): + continue + if isinstance(child, wx.StaticLine): + continue + if isinstance(child, wx.TextCtrl): + if child.IsEditable(): + child.SetBackgroundColour(wx.WHITE) + else: + child.SetBackgroundColour(wx.Colour(*DISABLED_GRAY)) + elif isinstance(child, (wx.Button, wx.ComboBox)): + child.SetBackgroundColour( + wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE) + ) + else: + child.SetBackgroundColour(wx.Colour(*APP_GRAY)) + child.Refresh() + + def _spoof_events_colour(self): + return wx.Colour(*WARN_AMBER) + + def _set_panel_background(self, panel, colour, propagate=False): + panel.SetBackgroundColour(colour) + if propagate: + for child in panel.GetChildren(): + if isinstance(child, wx.StaticLine): + continue + child.SetBackgroundColour(colour) + panel.Refresh() + + def _reset_navigation_panel_background(self): + if self._spoof_gps: + self._set_panel_background( + self.ins_control_panel, self._spoof_events_colour(), propagate=True + ) + return + self._set_panel_background( + self.ins_control_panel, wx.Colour(*APP_GRAY), propagate=True + ) + for child in self.ins_control_panel.GetChildren(): + if isinstance(child, wx.TextCtrl): + child.SetBackgroundColour(wx.WHITE) + + def _apply_event_spoof_panel_style(self, active): + colour = self._spoof_events_colour() + if active: + self._set_panel_background( + self.ins_control_panel, colour, propagate=True + ) + else: + self._reset_navigation_panel_background() def _set_field_enabled(self, ctrl, enabled): """Enable/disable an input field and make the disabled state obvious. @@ -1578,23 +1708,28 @@ def on_timer(self, event): self._did_initial_unclip = True gui_utils.unclip_static_text(self) - self.update_collect_colors() - - # Check to see if imagery has been received recently. + cameras_ok = True + now = time.time() for panel in self.remote_image_panels: # Refresh images if needed panel.update_all_if_needed() - chan = panel.attrs["chan"] if panel.last_update is None: + cameras_ok = False panel.status_static_text.SetLabel(format_status()) panel.status_static_text.SetForegroundColour(BRIGHT_RED) gui_utils.refit_label(panel.status_static_text) else: - dt = time.time() - panel.last_update - if dt > 10: + dt = now - panel.last_update + if dt > self._collect_stream_stale_sec: + cameras_ok = False panel.status_static_text.SetLabel(format_status(dt=dt)) panel.status_static_text.SetForegroundColour(BRIGHT_RED) gui_utils.refit_label(panel.status_static_text) + self._collect_health_cameras_ok = ( + cameras_ok if self.remote_image_panels else True + ) + + self.update_collect_colors() # Check to see if imagery has been received recently. if self._image_inspection_frame: @@ -1669,25 +1804,33 @@ def update_collect_colors(self, is_collecting=None, collect_in_region=None): self.start_collecting() else: self.stop_collecting() + self._reset_flight_data_panel_child_backgrounds() self.last_collecting = is_collecting self._collecting = False if is_collecting is None else is_collecting self._collect_in_region = ( False if collect_in_region is None else collect_in_region ) + self._spoof_events = int(kv.get("/debug/spoof_events", 0)) if is_collecting == True: self.recording_gauge.SetBackgroundColour((0, 255, 0)) - self.flight_data_panel.SetBackgroundColour(COLLECT_GREEN) + panel_colour = self._collecting_panel_colour() + self.flight_data_panel.SetBackgroundColour(panel_colour) + self._apply_flight_data_header_background(panel_colour) elif is_collecting == False: self.recording_gauge.SetBackgroundColour((200, 200, 200)) if collect_in_region is None or collect_in_region is False: - self.flight_data_panel.SetBackgroundColour(APP_GRAY) + self.flight_data_panel.SetBackgroundColour(wx.Colour(*APP_GRAY)) else: - self.flight_data_panel.SetBackgroundColour(SHAPE_COLLECT_BLUE) + self.flight_data_panel.SetBackgroundColour( + wx.Colour(*SHAPE_COLLECT_BLUE) + ) else: raise Exception("invalid value encountered for is_collecting") + self._apply_event_spoof_panel_style(self._spoof_events == 1) + @property def collect_in_region(self): # type: () -> Optional[shapely.geometry.base.BaseGeometry] @@ -2178,17 +2321,15 @@ def ins_state(self, msg): else: self.ins_status_flag_txtctrl.SetValue("") - if self._spoof_gps: - self.ins_control_panel.SetBackgroundColour(WARN_AMBER) - self.gnss_status_flag_txtctrl.SetValue("gps spoofed!") self._spoof_events = int(kv.get("/debug/spoof_events", 0)) if self._spoof_events == 1: - self.ins_control_panel.SetBackgroundColour(WARN_AMBER) + self._apply_event_spoof_panel_style(True) self.gnss_status_flag_txtctrl.SetValue("no fix! event spoof!") return - else: - self.ins_control_panel.SetBackgroundColour(APP_GRAY) - if msg.gnss_status == 0: + self._apply_event_spoof_panel_style(False) + if self._spoof_gps: + self.gnss_status_flag_txtctrl.SetValue("gps spoofed!") + elif msg.gnss_status == 0: self.gnss_status_flag_txtctrl.SetValue("No Fix") elif msg.gnss_status == 1: self.gnss_status_flag_txtctrl.SetValue("SPS Mode") From fc58cbf91f00157d7dc86b289093071ef4b4e9c4 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Thu, 18 Jun 2026 12:49:57 -0400 Subject: [PATCH 135/139] The camera config box was hiding some important elements - stretch it out. Now save does the 'finished making changes' and save in one button. Make the main panel dropdown update when that save is hit --- .../src/wxpython_gui/CameraConfiguration.py | 10 +- .../camera_configuration.fbp | 184 +----------------- ...orm_builder_output_camera_configuration.py | 19 +- .../wxpython_gui/system_control_panel/gui.py | 13 +- 4 files changed, 13 insertions(+), 213 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py index 39f902b..835bfb0 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py @@ -127,7 +127,8 @@ def on_save(self, event): self.curr_cfg = key self.update_combo(select_str=key) - # Refresh current combo in parent in case it changed + # Refresh main panel combo and select the saved configuration. + self.parent.set_camera_config_dict(select_str=key) self.parent.on_camera_config_combo() # Remove a tmp definition if present. @@ -137,6 +138,7 @@ def on_save(self, event): pass self.save_camera_config_dict(SYS_CFG["camera_cfgs"]) + self.Close() def save_camera_config_dict(self, config_dict): # Save camera config to only local config here, saved to /mnt in parent @@ -329,9 +331,3 @@ def on_delete(self, event): .format(self.curr_cfg)) self.save_camera_config_dict(SYS_CFG["camera_cfgs"]) self.parent.set_camera_config_dict() - - def on_done(self, event=None): - """When the 'Cancel' button is selected. - - """ - self.Close() diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/camera_configuration.fbp b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/camera_configuration.fbp index c580c6c..a3d36f2 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/camera_configuration.fbp +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/camera_configuration.fbp @@ -44,7 +44,7 @@ 400,400 MainFrame - 994,969 + 994,1080 wxDEFAULT_FRAME_STYLE System Configuration Editor @@ -738,188 +738,6 @@ - - 5 - wxALIGN_CENTER_HORIZONTAL - 1 - - - bSizer23 - wxHORIZONTAL - none - - 5 - wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Finished Making Changes - - 0 - - - 0 - - 1 - m_button7 - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - on_done - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALL|wxALIGN_CENTER_VERTICAL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Make sure to save changes first - - 0 - - - 0 - - 1 - m_staticText20 - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - - - -1 - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py index 6f4a1ff..3a25739 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/form_builder_output_camera_configuration.py @@ -17,7 +17,7 @@ class MainFrame ( wx.Frame ): def __init__( self, parent ): - wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"System Configuration Editor", pos = wx.DefaultPosition, size = wx.Size( 994,969 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) + wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"System Configuration Editor", pos = wx.DefaultPosition, size = wx.Size( 994,1080 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) self.SetSizeHints( wx.Size( 400,400 ), wx.DefaultSize ) self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, wx.EmptyString ) ) @@ -67,18 +67,6 @@ def __init__( self, parent ): bSizer22.Add( bSizer9, 0, wx.ALIGN_CENTER_HORIZONTAL, 5 ) - bSizer23 = wx.BoxSizer( wx.HORIZONTAL ) - - self.m_button7 = wx.Button( self.m_panel2, wx.ID_ANY, u"Finished Making Changes", wx.DefaultPosition, wx.DefaultSize, 0 ) - bSizer23.Add( self.m_button7, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER_HORIZONTAL, 5 ) - - self.m_staticText20 = wx.StaticText( self.m_panel2, wx.ID_ANY, u"Make sure to save changes first", wx.DefaultPosition, wx.DefaultSize, 0 ) - self.m_staticText20.Wrap( -1 ) - bSizer23.Add( self.m_staticText20, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) - - - bSizer22.Add( bSizer23, 1, wx.ALIGN_CENTER_HORIZONTAL, 5 ) - self.m_panel2.SetSizer( bSizer22 ) self.m_panel2.Layout() @@ -428,7 +416,6 @@ def __init__( self, parent ): self.m_button4.Bind( wx.EVT_BUTTON, self.on_new ) self.m_button41.Bind( wx.EVT_BUTTON, self.on_new_from_current ) self.m_button42.Bind( wx.EVT_BUTTON, self.on_delete ) - self.m_button7.Bind( wx.EVT_BUTTON, self.on_done ) self.m_button18.Bind( wx.EVT_BUTTON, self.on_find_left_rgb_yaml ) self.m_button61.Bind( wx.EVT_BUTTON, self.on_clear_left_rgb_yaml ) self.m_button19.Bind( wx.EVT_BUTTON, self.on_find_left_ir_yaml ) @@ -461,7 +448,6 @@ def __del__( self ): self.m_button4.Unbind( wx.EVT_BUTTON, None ) self.m_button41.Unbind( wx.EVT_BUTTON, None ) self.m_button42.Unbind( wx.EVT_BUTTON, None ) - self.m_button7.Unbind( wx.EVT_BUTTON, None ) self.m_button18.Unbind( wx.EVT_BUTTON, None ) self.m_button61.Unbind( wx.EVT_BUTTON, None ) self.m_button19.Unbind( wx.EVT_BUTTON, None ) @@ -502,9 +488,6 @@ def on_new_from_current( self, event ): def on_delete( self, event ): event.Skip() - def on_done( self, event ): - event.Skip() - def on_find_left_rgb_yaml( self, event ): event.Skip() diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 903b6d3..61d464a 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -2759,11 +2759,14 @@ def on_edit_camera_configuration(self, event=None): self._camera_config_frame = CameraConfiguration( self, SYS_CFG["arch"]["sys_cfg"] ) + else: + self._camera_config_frame.Show() self._camera_config_frame.Raise() + wx.CallAfter(gui_utils.unclip_static_text, self._camera_config_frame) - def set_camera_config_dict(self, config_dict=None): - curr_str = self.get_sys_cfg() + def set_camera_config_dict(self, config_dict=None, select_str=None): + curr_str = select_str if select_str is not None else self.get_sys_cfg() SYS_CFG["arch"]["sys_cfg"] = curr_str self.camera_config_combo.SetEditable(True) @@ -2819,9 +2822,9 @@ def on_camera_config_combo(self, event=None): curr_str = self.get_sys_cfg() self.add_to_event_log("system_config: %s" % curr_str) cc = SYS_CFG["camera_cfgs"][curr_str] - syscfg_dir = SYS_CFG["syscfg_dir"] - vfov = load_from_file(cc["center_rgb_yaml_path"]).fov()[1] - SYS_CFG["rgb_vfov"] = vfov + center_rgb_yaml = (cc.get("center_rgb_yaml_path") or "").strip() + if center_rgb_yaml and os.path.isfile(center_rgb_yaml): + SYS_CFG["rgb_vfov"] = load_from_file(center_rgb_yaml).fov()[1] SYS_CFG["arch"]["sys_cfg"] = curr_str save_camera_config(curr_str) self.update_project_flight_params() From 94f4cc1ef5fbca68756a981b3b2dc55aa980c122 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Thu, 18 Jun 2026 13:37:48 -0400 Subject: [PATCH 136/139] Make sure camera configurations are written to disk on save --- .../src/wxpython_gui/CameraConfiguration.py | 34 ++++++++++++------- .../wxpython_gui/src/wxpython_gui/cfg.py | 20 +++++++---- .../wxpython_gui/system_control_panel/gui.py | 2 +- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py index 835bfb0..b8491d4 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py @@ -1,5 +1,6 @@ from __future__ import division, print_function import copy +import os import wx import yaml import numpy as np @@ -126,25 +127,27 @@ def on_save(self, event): SYS_CFG["camera_cfgs"][key] = tmp self.curr_cfg = key - self.update_combo(select_str=key) - # Refresh main panel combo and select the saved configuration. - self.parent.set_camera_config_dict(select_str=key) - self.parent.on_camera_config_combo() - - # Remove a tmp definition if present. try: del SYS_CFG["camera_cfgs"][''] except KeyError: pass - self.save_camera_config_dict(SYS_CFG["camera_cfgs"]) + self.update_combo(select_str=key) + save_path = save_camera_config(key, camera_cfgs=SYS_CFG["camera_cfgs"]) + self.parent.set_camera_config_dict(select_str=key) + center_rgb_yaml = (tmp.get("center_rgb_yaml_path") or "").strip() + if center_rgb_yaml and os.path.isfile(center_rgb_yaml): + SYS_CFG["rgb_vfov"] = load_from_file(center_rgb_yaml).fov()[1] + SYS_CFG["arch"]["sys_cfg"] = key + self.parent.update_project_flight_params() + self.parent.add_to_event_log( + 'Saved system configurations to {}.'.format(save_path) + ) self.Close() def save_camera_config_dict(self, config_dict): # Save camera config to only local config here, saved to /mnt in parent - dirname = save_camera_config() - self.parent.add_to_event_log('Saved system configurations to {}. ' - .format(dirname)) + return save_camera_config(self.curr_cfg, camera_cfgs=config_dict) def on_combo_select(self, event=None): select_str = self.camera_config_combo.GetStringSelection() @@ -204,16 +207,23 @@ def set_fields_to_camera_config_dict(self, config_dict): txt = config_dict['description'] self.configuration_notes_txt_ctrl.SetValue('' if txt is None else txt) + def _clear_config_combo_selection(self): + self.camera_config_combo.SetEditable(True) + self.camera_config_combo.SetValue('') + self.camera_config_combo.SetSelection(-1) + self.camera_config_combo.SetEditable(False) + def on_new(self, event): self.config_name_txt_ctrl.Enable() tmpl = self.get_template() self.set_fields_to_camera_config_dict(tmpl) self.config_name_txt_ctrl.SetValue('') - self.camera_config_combo.SetSelection(-1) + self._clear_config_combo_selection() def on_new_from_current(self, event): self.config_name_txt_ctrl.Enable() self.config_name_txt_ctrl.SetValue('') + self._clear_config_combo_selection() # ----------------------------- File Pickers ----------------------------- # Left-system pickers @@ -330,4 +340,4 @@ def on_delete(self, event): self.parent.add_to_event_log('Deleted system configuration {}.' .format(self.curr_cfg)) self.save_camera_config_dict(SYS_CFG["camera_cfgs"]) - self.parent.set_camera_config_dict() + self.parent.set_camera_config_dict(select_str=select_str) diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py index 1e52325..c36c0f7 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/cfg.py @@ -317,13 +317,23 @@ def pull_gui_state(): deep_merge(SYS_CFG["arch"], live_arch) -def save_camera_config(curr_cfg=None): +def _plain_dict(val): + """Recursively convert ``Cfg`` wrappers to plain dicts for JSON serialization.""" + if isinstance(val, dict): + return {k: _plain_dict(v) for k, v in val.items()} + return val + + +def save_camera_config(curr_cfg=None, camera_cfgs=None): print("Saving camera configuration") + presets = _plain_dict( + camera_cfgs if camera_cfgs is not None else SYS_CFG["camera_cfgs"] + ) # Save to local cache if not os.path.isfile(camera_config_filename): wxpython_gui.utils.make_path(camera_config_filename, from_file=True) with open(camera_config_filename, "w") as outfile: - json.dump(SYS_CFG["camera_cfgs"], outfile, indent=4, sort_keys=True) + json.dump(presets, outfile, indent=4, sort_keys=True) print("Saved config: {}".format(camera_config_filename)) # Saving specific camera config to dir @@ -334,13 +344,11 @@ def save_camera_config(curr_cfg=None): if dirname is not None: fname = "%s/sys_config.json" % dirname else: - return + return camera_config_filename if not os.path.isfile(fname): wxpython_gui.utils.make_path(fname, from_file=True) with open(fname, "w") as outfile: - json.dump( - SYS_CFG["camera_cfgs"][curr_cfg], outfile, indent=4, sort_keys=True - ) + json.dump(presets[curr_cfg], outfile, indent=4, sort_keys=True) print("Saved sys config: {}".format(fname)) return dirname else: diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 61d464a..3e5ecb4 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -2826,7 +2826,7 @@ def on_camera_config_combo(self, event=None): if center_rgb_yaml and os.path.isfile(center_rgb_yaml): SYS_CFG["rgb_vfov"] = load_from_file(center_rgb_yaml).fov()[1] SYS_CFG["arch"]["sys_cfg"] = curr_str - save_camera_config(curr_str) + save_camera_config(curr_str, camera_cfgs=SYS_CFG["camera_cfgs"]) self.update_project_flight_params() # ------------------------- END Camera Configuration ------------------------- From 918ff64a8d6ae44f587e48412c84b0d4870d1657 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Thu, 18 Jun 2026 16:36:04 -0400 Subject: [PATCH 137/139] Remove OBE camera models file, pivot to kamera one in gui --- docker/gui.dockerfile | 6 + pyproject.toml | 44 +- src/kitware-ros-pkg/wxpython_gui/README.rst | 2 +- .../src/wxpython_gui/CameraConfiguration.py | 2 +- .../src/wxpython_gui/camera_models.py | 1068 ----------------- .../wxpython_gui/system_control_panel/gui.py | 2 +- 6 files changed, 34 insertions(+), 1090 deletions(-) delete mode 100644 src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py diff --git a/docker/gui.dockerfile b/docker/gui.dockerfile index bf25bc5..f46b565 100644 --- a/docker/gui.dockerfile +++ b/docker/gui.dockerfile @@ -36,6 +36,12 @@ RUN mkdir -p /home/user/.config/kamera && \ RUN ln -sv /usr/bin/python3 /usr/bin/python || true RUN find /home/user -not -user user -execdir chown user {} \+ +# Install kamera for wxpython_gui imports (e.g. colmap_processing.camera_models). +# Use --no-deps: base images already provide runtime deps, and a full install +# fails trying to replace distutils-installed PyYAML from ROS/Noetic. +RUN pip install --no-cache-dir matplotlib \ + && pip install --no-cache-dir --no-deps -e $REPO_DIR + # use the exec form of run because we need bash syntax USER user RUN [ "/bin/bash", "-c", "source /entry/project.sh && catkin build wxpython_gui "] diff --git a/pyproject.toml b/pyproject.toml index adddc10..1268c08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,25 +7,31 @@ license = "Apache-2.0" readme = "README.md" [tool.poetry.dependencies] -python = "^3.10" -numpy = "^2.1.1" -scipy = "^1.14.1" -matplotlib = "^3.9.2" -opencv-python = "^4.10.0.84" -pillow = "^10.4.0" -pyyaml = "^6.0.2" -datetime = "^5.5" -exifread = "^3.0.0" -pygeodesy = "^24.9.29" -pyshp = "^2.3.1" -simplekml = "^1.3.6" -shapely = "^2.0.6" -transformations = "^2024.5.24" -scriptconfig = "^0.8.0" -ubelt = "^1.3.6" -rich = "^13.9.1" -gdal = {url = "https://github.com/girder/large_image_wheels/raw/wheelhouse/GDAL-3.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=0ccdfd68893818a86d2225c1efe6b4a64a6d84676f6fb1e7ec5a4138f70d837b"} -ipdb = "^0.13.13" +python = ">=3.8,<4" +numpy = {version = "^2.1.1", markers = "python_version >= '3.10'"} +scipy = {version = "^1.14.1", markers = "python_version >= '3.10'"} +matplotlib = {version = "^3.9.2", markers = "python_version >= '3.10'"} +opencv-python = {version = "^4.10.0.84", markers = "python_version >= '3.10'"} +pillow = {version = "^10.4.0", markers = "python_version >= '3.10'"} +pyyaml = {version = "^6.0.2", markers = "python_version >= '3.10'"} +datetime = {version = "^5.5", markers = "python_version >= '3.10'"} +exifread = {version = "^3.0.0", markers = "python_version >= '3.10'"} +pygeodesy = {version = "^24.9.29", markers = "python_version >= '3.10'"} +pyshp = {version = "^2.3.1", markers = "python_version >= '3.10'"} +simplekml = {version = "^1.3.6", markers = "python_version >= '3.10'"} +shapely = {version = "^2.0.6", markers = "python_version >= '3.10'"} +transformations = {version = "^2024.5.24", markers = "python_version >= '3.9'"} +scriptconfig = {version = "^0.8.0", markers = "python_version >= '3.10'"} +ubelt = {version = "^1.3.6", markers = "python_version >= '3.10'"} +rich = {version = "^13.9.1", markers = "python_version >= '3.10'"} +gdal = [ + { url = "https://github.com/girder/large_image_wheels/raw/wheelhouse/GDAL-3.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=8c150cc85623d136734eb2fad91036933cbb2d6ba58a76095b82ddf53d9bf961", markers = "python_version >= '3.8' and python_version < '3.9'" }, + { url = "https://github.com/girder/large_image_wheels/raw/wheelhouse/GDAL-3.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=7894fddd09d31530d764d5f5e52faafa3585b906c2e49c79fe593af8c6a34c24", markers = "python_version >= '3.9' and python_version < '3.10'" }, + { url = "https://github.com/girder/large_image_wheels/raw/wheelhouse/GDAL-3.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=4a09086631d81808a97c8c7a605aa6230ca045874aa688863cf91794e94880c7", markers = "python_version >= '3.10' and python_version < '3.11'" }, + { url = "https://github.com/girder/large_image_wheels/raw/wheelhouse/GDAL-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=aee8c49c3528b8613ad3fe14a9d0066ad6990e143f277aff5be1143f371258a2", markers = "python_version >= '3.11' and python_version < '3.12'" }, + { url = "https://github.com/girder/large_image_wheels/raw/wheelhouse/GDAL-3.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl#sha256=19cd80ad4bd684e8c7a3f712e5a1c284cce59e5750155f0db0c31d875d3c6321", markers = "python_version >= '3.12' and python_version < '3.13'" }, +] +ipdb = {version = "^0.13.13", markers = "python_version >= '3.10'"} [build-system] diff --git a/src/kitware-ros-pkg/wxpython_gui/README.rst b/src/kitware-ros-pkg/wxpython_gui/README.rst index e756633..d9c6bc7 100644 --- a/src/kitware-ros-pkg/wxpython_gui/README.rst +++ b/src/kitware-ros-pkg/wxpython_gui/README.rst @@ -21,7 +21,7 @@ Python modules for the GUI. The main window lives under ``system_control_panel/``: ``gui.fbp`` is the wxFormBuilder layout, ``form_builder_output*.py`` are the generated frame classes, and ``gui.py`` subclasses them with application logic. Shared helpers -(e.g. ``RemoteImagePanel.py``, ``camera_models.py``) sit alongside +(e.g. ``RemoteImagePanel.py``) sit alongside that directory. Notes diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py index b8491d4..aacaf2c 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/CameraConfiguration.py @@ -5,7 +5,7 @@ import yaml import numpy as np import sys -from wxpython_gui.camera_models import load_from_file +from kamera.colmap_processing.camera_models import load_from_file import wxpython_gui.system_control_panel.form_builder_output_camera_configuration as fbocc from wxpython_gui.cfg import SYS_CFG, save_camera_config from wxpython_gui.system_control_panel.gui_utils import unclip_static_text diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py deleted file mode 100644 index 8f513cc..0000000 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/camera_models.py +++ /dev/null @@ -1,1068 +0,0 @@ -#!/usr/bin/env python3 -""" -Library handling projection operations of a standard camera model. - -Note: the image coordiante system has its origin at the center of the top left -pixel. -""" -from __future__ import division, print_function, absolute_import -import numpy as np -import cv2 -import time -import yaml -from scipy.interpolate import RectBivariateSpline -import threading -import copy - -# ROS imports -import genpy -import rospy -from sensor_msgs.msg import Image, CompressedImage -from cv_bridge import CvBridge, CvBridgeError -from tf.transformations import quaternion_multiply, quaternion_matrix, \ - quaternion_from_euler, quaternion_inverse, euler_matrix -from wxpython_gui.nav_state import NavStateFixed - - -# Instantiate CvBridge -bridge = CvBridge() - -# TODO: there should be a separate lock for each camera. -lock = threading.RLock() - - -def to_str(v): - """Convert numerical values (scalar or float) to string for saving to yaml - - """ - if hasattr(v, "__len__"): - if len(v) > 1: - return repr(list(v)) - else: - v = v[0] - - return repr(v) - - -def load_from_file(filename, nav_state_provider=None): - """Load from configuration yaml for any of the Camera subclasses. - - """ - with open(filename, 'r') as f: - calib = yaml.load(f) - - if calib['model_type'] == 'standard': - return StandardCamera.load_from_file(filename, nav_state_provider) - - if calib['model_type'] == 'ptz': - return PTZCamera.load_from_file(filename, nav_state_provider) - - if calib['model_type'] == 'azel': - return AzelCamera.load_from_file(filename, nav_state_provider) - - -class Camera(object): - """Base class for all imaging sensors. - - The imaging sensor is attached to a navigation coordinate system (i.e., the - frame of the INS), which may move relative to the East/North/Up world - coordinate system. The pose (position and orientation) of this navigation - coordinate system within the ENU coordinate system is provided by the - nav_state_provider attribute, which is an instance of a subclass of - nav_state.NavStateProvider. - - The Camera object captures all of the imaging properties of the sensor. - Intrinsic and derived parameters can be queried, and projection operations - (pixels to world coordinates and vice versa) are provided. - - Most operations require specification of time in order determine values of - any time-varying parameters (e.g., navigation coordinate system state). - - """ - def __init__(self, width, height, image_topic, frame_id=None, - nav_state_provider=None): - """ - :param width: Width of the image provided by the imaging sensor, - :type width: int - - :param height: Height of the image provided by the imaging sensor, - :type height: int - - :param image_topic: The topic that the image is published on. - :type image_topic: str | None - - :param frame_id: Frame ID. If set to None, the fully resolved topic - name wil be used. - :type frame_id: str | None - - :param nav_state_provider: Object that returns the state of the - navigation coordinate system as a function of time. If None is - passed, the navigation coordinate system will always have - its x-axis aligned with world y, its y-axis aligned with world x, - and its z-axis pointing down (negative world z). - :type nav_state_provider: subclass of NavStateProvider - - """ - self._width = width - self._height = height - self._image_topic = image_topic - - # Initialize - self._image_subscriber = None - self._image_publisher = None - self._image_patch_server = None - self._images = [] - self._image_times = np.zeros(0) - - if frame_id is None: - self._frame_id = image_topic - else: - self._frame_id = frame_id - - if nav_state_provider is None: - self._nav_state_provider = NavStateFixed() - else: - self._nav_state_provider = nav_state_provider - - self.publishing_images = False - - @property - def width(self): - return self._width - - @width.setter - def width(self, value): - self._width = int(value) - - @property - def height(self): - return self._height - - @height.setter - def height(self, value): - self._height = int(value) - - @property - def buffer_size(self): - return self._buffer_size - - @buffer_size.setter - def buffer_size(self, value): - self._buffer_size = int(value) - - @property - def image_topic(self): - return self._image_topic - - @image_topic.setter - def image_topic(self, value): - self._image_topic = value - - @property - def image_subscriber(self): - return self._image_subscriber - - @property - def frame_id(self): - return self._frame_id - - @frame_id.setter - def frame_id(self, value): - self._frame_id = value - - @property - def nav_state_provider(self): - """Instance of a subclass of NavStateProvider - - """ - return self._nav_state_provider - - @property - def images(self): - """Current queue of images captured from ROS messages - - """ - return self._images - - @property - def image_times(self): - """Times associated self.images - - """ - return self._image_times - - @property - def image_patch_server(self): - """RequestImagePatches service. - - """ - return self._image_patch_server - - def __str__(self): - string = [''.join(['image_width: ',repr(self._width),'\n'])] - string.append(''.join(['image_height: ',repr(self._height),'\n'])) - string.append(''.join(['image_topic: ',repr(self._image_topic),'\n'])) - string.append(''.join(['frame_id: ',repr(self._frame_id),'\n'])) - string.append(''.join(['nav_state_provider: ', - repr(self._nav_state_provider)])) - - try: - # Some time-dependent cameras may not have a queue of values. - string.append(''.join(['\nifov: ', - '({:.6g},{:.6g})'.format(*self.ifov(np.inf)), - '\n'])) - string.append(''.join(['fov: ', - '({:.6},{:.6},{:.6})'.format(*self.fov(np.inf))])) - except: - pass - - return ''.join(string) - - def __repr__(self): - return self.__str__() - - @classmethod - def load_from_file(cls, filename, nav_state_provider=None): - raise NotImplementedError - - def save_to_file(filename): - raise NotImplementedError - - def get_param_array(self, param_list): - """Return set of parameters as array. - - :param ptype: Parameters. - :type ptype: str or list of str - - :return: Pameters as an array. - :rtype: numpy.ndarray - - """ - params = np.zeros(0) - for param in param_list: - params = np.hstack([params,getattr(self, param)]) - - return params - - def set_param_array(self, param_list, params): - """Return set of parameters as array. - - :param param_list: List of parameter names. - :type param_list: list of str - - :param params: Pameters as an array. - :type params: numpy.ndarray - - """ - ind = 0 - for param in param_list: - p0 = getattr(self, param) - if hasattr(p0, '__len__') and len(p0) > 1: - setattr(self, param, params[ind:ind+len(p0)]) - ind += len(p0) - else: - setattr(self, param, params[ind]) - ind += 1 - - def project(self, points, t=None): - """Project world points into the image at a particular time. - - :param points: Coordinates of a point or points within the world - coordinate system. The coordinate may be Cartesian or homogenous. - :type points: array with shape (3), (4), (3,n), (4,n) - - :param t: Time at which to project the point(s) (time in seconds since - Unix epoch). - :type t: float - - :return: Image coordinates associated with points. - :rtype: numpy.ndarray of size (2,n) - - """ - raise NotImplementedError - - def unproject(self, points, t=None): - """Unproject image points into the world at a particular time. - - :param points: Coordinates of a point or points within the image - coordinate system. The coordinate may be Cartesian or homogenous. - :type points: array with shape (2), (2,N), (3) or (3,N) - - :param t: Time at which to unproject the point(s) (time in seconds - since Unix epoch). - :type t: float - - :return: Ray position and direction corresponding to provided image - points. The direction points from the center of projection to the - points. The direction vectors are not necassarily normalized. - :rtype: [ray_pos, ray_dir] where both of type numpy.ndarry with shape - (3,n). - - """ - raise NotImplementedError - - def ifov(self, t=None): - """Instantaneous field of view (ifov) at the image center. - - ifov is the angular extend spanned by a single pixel. - - :param t: Time at which to calculate the ifov (time in seconds since - Unix epoch). Only relevant for sensors where zoom can change. - :type t: float - - :return: The ifov along the horizontal and vertical directions of the - image, evaluated at the center of the image (radians). - - """ - if t is None: - t = time.time() - - cx = self.width/2 - cy = self.height/2 - ray1 = self.unproject([cx,cy], t)[1] - ray1 /= np.sqrt(np.sum(ray1**2, 0)) - ray2 = self.unproject([cx,cy+1], t)[1] - ray2 /= np.sqrt(np.sum(ray2**2, 0)) - ray3 = self.unproject([cx+1,cy], t)[1] - ray3 /= np.sqrt(np.sum(ray3**2, 0)) - - ifovx = np.arccos(np.dot(ray1.ravel(), ray3.ravel())) - ifovy = np.arccos(np.dot(ray1.ravel(), ray2.ravel())) - - return ifovx, ifovy - - def fov(self, t=None): - """Field of view (fov). - - :param t: Time at which to calculate the ifov (time in seconds since - Unix epoch). Only relevant for sensors where zoom can change. - :type t: float - - :return: The horizontal, vertical, and diagonal field of view of the - camera (degrees). - :rtype: tuple of (ifov_h, ifov_v, ifov_d) - - """ - if t is None: - t = time.time() - - cx = self.width/2 - cy = self.height/2 - - ray1 = self.unproject([cx,0], t)[1] - ray1 /= np.sqrt(np.sum(ray1**2, 0)) - ray2 = self.unproject([cx,self.height], t)[1] - ray2 /= np.sqrt(np.sum(ray2**2, 0)) - fov_v = np.arccos(np.dot(ray1.ravel(), ray2.ravel()))*180/np.pi - - ray1 = self.unproject([0,cy], t)[1] - ray1 /= np.sqrt(np.sum(ray1**2, 0)) - ray2 = self.unproject([self.width, cy], t)[1] - ray2 /= np.sqrt(np.sum(ray2**2, 0)) - fov_h = np.arccos(np.dot(ray1.ravel(), ray2.ravel()))*180/np.pi - - ray1 = self.unproject([0,0], t)[1] - ray1 /= np.sqrt(np.sum(ray1**2, 0)) - ray2 = self.unproject([self.width,self.height], t)[1] - ray2 /= np.sqrt(np.sum(ray2**2, 0)) - fov_d = np.arccos(np.dot(ray1.ravel(), ray2.ravel()))*180/np.pi - - return fov_h, fov_v, fov_d - - def start_collecting_images(self, buffer_size=None, burn_in_metadata=False, - copy=False): - """Start collecting images published on self.image_topic - - :param buffer_size: Number of images to keep in image list. When a new - image would cause the image list to exceed this size, the first - image added is removed to make room. If buffer_size has been - previously set, passing value None will use that previous value. - - :param burn_in_metdata: Burn metadata, such as the timestamp into raw - frames. - :type burn_in_metdata: bool - - :param copy: Copy images on receipt. This is useful to avoid modifying - the source data that the shared pointer references. - - :type copy: bool - - """ - if hasattr(self, '_buffer_size'): - if buffer_size is None: - buffer_size = self._buffer_size - elif self._buffer_size != buffer_size: - raise Exception("""Camera with frame_id %s previously had - buffer_size set to %i (e.g., from a call to - start_publishing_images) and would be - overwritten with the different value %i.""" % \ - (self._frame_id, self._buffer_size, - buffer_size)) - elif buffer_size is None: - raise Exception('Must provide valid buffer_size, one has not been ' - 'previously set.') - else: - self._buffer_size = buffer_size - - self.burn_in_metadata = burn_in_metadata - if burn_in_metadata: - self._copy_images_on_receive = True - else: - self._copy_images_on_receive = copy - - if self.image_topic is not None: - self._image_subscriber = rospy.Subscriber(self.image_topic, Image, - self.image_callback_ros, - queue_size=buffer_size) - - def stop_collecting_images(self): - """Stop collecting images published on self.image_topic - - """ - if self._image_subscriber is not None: - self._image_subscriber.unregister() - - def start_publishing_images(self, topic=None, compressed=False, - buffer_size=None): - """Activates the publisher waiting for calls from - publish_image_from_list. - - :param topic: Topic to publish images on. Defaults to self.image_topic. - :type topic: str - - :param compressed: Publish compressed image. - :type compressed: bool - - :param buffer_size: Number of images to keep in image list. When a new - image would cause the image list to exceed this size, the first - image added is removed to make room. If buffer_size has been - previously set, passing value None will use that previous value. - - """ - if hasattr(self, '_buffer_size'): - if buffer_size is None: - buffer_size = self._buffer_size - elif self._buffer_size != buffer_size: - raise Exception("""Camera with frame_id %s previously had - buffer_size set to %i (e.g., from a call to - start_collecting_images) and would be - overwritten with the different value %i.""" % \ - (self._frame_id, self._buffer_size, - buffer_size)) - elif buffer_size is None: - raise Exception('Must provide valid buffer_size, one has not been ' - 'previously set.') - else: - self._buffer_size = buffer_size - - if topic is None: - topic = self.image_topic - - self.publishing_images = True - if self.image_topic is not None: - if compressed: - self._image_publisher = rospy.Publisher(topic, CompressedImage, - queue_size=100) - else: - self._image_publisher = rospy.Publisher(topic, Image, - queue_size=100) - - self._seq_ind = 0 - - def stop_publishing_images(self): - self.publishing_images = False - if self._image_publisher is not None: - self._image_publisher.unregister() - - def image_callback_ros(self, image_msg): - """Method that receives messages published on self.image_topic - - :param image_msg: ROS image message. - :type image_msg: Image - - """ - try: - # Convert ROS Image message to OpenCV2. - if False: - print('----- image_callback_ros debug -----') - print('Height:', image_msg.height) - print('width:', image_msg.width) - print('encoding:', image_msg.encoding) - print('is_bigendian:', image_msg.is_bigendian) - print('step:', image_msg.step) - print('') - - if image_msg.encoding == 'mono8': - raw_image = bridge.imgmsg_to_cv2(image_msg, 'mono8') - elif image_msg.encoding in ['rgb8','bgr8']: - raw_image = bridge.imgmsg_to_cv2(image_msg, 'rgb8') - elif image_msg.encoding == '32FC1': - raw_image = bridge.imgmsg_to_cv2(image_msg, '32FC1') - raw_image = raw_image.astype(np.float32) - else: - raise Exception('Unhandled image encoding: %s' % - image_msg.encoding) - except CvBridgeError as e: - print(e) - return None - - stamp = image_msg.header.stamp - - if self._copy_images_on_receive: - raw_image = copy.copy(raw_image) - - if self.burn_in_metadata: - x = 20; y = 30 - font = cv2. FONT_HERSHEY_PLAIN - cv2.putText(raw_image, 'Timestamp: ' + str(stamp), org=(x,y), - fontFace=font, fontScale=1, color=(0,0,0), - thickness=2, bottomLeftOrigin=False) - - self.add_image_to_list(raw_image, stamp.to_sec()) - - def add_image_to_list(self, raw_image, t=None): - """Add image to image buffer. - - """ - if t is None: - t = time.time() - - if hasattr(self, '_buffer_size'): - buffer_size = self._buffer_size - else: - buffer_size = np.inf - - with lock: - # Make sure list will not exceed buffer size after addition. - while len(self.images) >= buffer_size: - self.images.pop(0) - self._image_times = np.delete(self.image_times, 0) - - self._images.append(raw_image) - self._image_times = np.hstack([self._image_times,t]) - - def remove_image_from_list(self, t): - """Add image to image buffer. - - """ - with lock: - ind = np.argmin(np.abs(self.image_times - t)) - self.images.pop(ind) - self._image_times = np.delete(self.image_times, ind) - - def get_image_from_list(self, t=None): - """Return image from self.image_list with time closest to t. - - :param t: Nearest time to draw image from (time in seconds since Unix - epoch). If time is None, the current time will be used. - :type t: float - - :return: Image and actual time of the image - :rtype: [numpy.ndarray, float] - - """ - if t is None: - t = time.time() - - if len(self._image_times) == 0: - return None - - with lock: - ind = np.argmin(np.abs(self.image_times - t)) - #ind = len(self.images)-1 - - return self.images[ind], self.image_times[ind] - - def clear_image_list(self): - with lock: - self._images = [] - self._image_times = np.zeros(0) - - def publish_image_from_list(self, t): - """Publish image from self.image_list with time closest to t. - - The image is published on topic self.image_topic. - - :param t: Nearest time to draw image from (time in seconds since Unix - epoch). If time is None, the current time will be used. - :type t: float - - """ - if not self.publishing_images: - raise Exception('Must run method start_publishing_images first.') - - if t is None: - t = time.time() - - img,t = self.get_image_from_list(t) - - if img is None: - return - - if self._image_publisher.data_class == Image: - if img.ndim == 3: - image_message = bridge.cv2_to_imgmsg(img, encoding="rgb8") - else: - image_message = bridge.cv2_to_imgmsg(img, encoding="mono8") - else: - # Compressed image - image_message = CompressedImage() - image_message.format = "jpeg" - image_message.data = np.array(cv2.imencode('.jpg', img)[1]).tobytes() - - image_message.header.frame_id = self._frame_id - image_message.header.stamp = genpy.Time.from_sec(t) - image_message.header.seq = self._seq_ind - self._seq_ind += 1 - self._image_publisher.publish(image_message) - - def add_image_patch_server(self, image_patch_server_topic, - frame_time_window=2): - """Subscribe to image patch server service. - - In cases where this camera's imagery is available on a remote node but - network bandwidth is insufficient to transfer full-resolution images, - an image patch server can be run on the remote node providing the - RequestImagePatches service in order to access windowed or reduced- - resolution versions of the imagery, as is typically needed for - synthetic camera view rendering. - - :param image_patch_server_topic: Topic providing the - RequestImagePatches service. - :type image_patch_server_topic: str - - :parma frame_time_window: If an image with the desired frame time - cannot be found, this defines the maximum acceptable difference in - seconds between the closest available frame time and the desired - frame time. If no images are found within this specified frame time - radius, then a response will be returned with `success` set to - false. - :type frame_time_window: float - - """ - self._image_patch_server_lock =threading.RLock() - with self._image_patch_server_lock: - rospy.loginfo('Subscribing to image patch server \'%s\'' % - image_patch_server_topic) - self._image_server_dt = frame_time_window - self._image_patch_server = rospy.ServiceProxy( - image_patch_server_topic, - RequestImagePatches) - - def get_patches_from_image_server(self, frame_time, homography_list, - patch_heights, patch_widths, - interpolation, antialias): - """Return warped patches from image patch server. - - This method provides homography-warped image patches from source - imagery stored on a remote image server. The primary use case is - providing access to windowed or reduced-resolution versions of a high- - resolution image over a limited-bandwidth connection when sending the - entire image would be prohibitively expensive. - - The image patch server may service multiple camera image streams. To - select this camera's images, this method passes the image topic where - the full-resolution image are published during the image patch request - service call. - - :param frame_time: Desired frame time of the image from which to draw - the patches. - :type frame_time: float - - :param homography_list: Encodes the set of 3x3 homographies to be used - to warp the image patches. An image patch will be returned for each - homography in the list. - :type homography_list: list of 3x3 arrays - - :param patch_heights: List of patch heights, one for each patch to be - returned. - :type patch_heights: list of int - - :param patch_widths: List of patch widths, one for each patch to be - returned. - :type patch_widths: list of int - - :param interpolation: Set the interpolation algorithm: 0 - nearest - neighbor, 1 - linear, 3 - cubic, 4 - Lanczos4. - :type interpolation: int - - :param antialias: Indicates whether anti-aliasing should be done in - cases where image downsampling occurs. The additional processing on - the image server required for the anti-aliasing may substantially - increase response latency in some cases. - :type antialias: bool - - :return: A Boolean indication of whether the request was successfully - serviced. If this is true, the second element is a list of images. - :rtype: [bool,list of Numpy images] - - """ - assert self.image_patch_server is not None, 'No image patch server ' \ - 'specified' - - with self._image_patch_server_lock: - try: - homographies = list(np.array(homography_list).ravel()) - resp = self.image_patch_server(genpy.Time.from_sec(frame_time), - self._image_server_dt, - homographies, patch_heights, - patch_widths, interpolation, - antialias) - ros_image_patches = resp.image_patches - image_patches = [] - for ros_image_patch in ros_image_patches: - if ros_image_patch.encoding == 'mono8': - image_patches.append(bridge.imgmsg_to_cv2(ros_image_patch, - 'mono8')) - elif ros_image_patch.encoding in ['rgb8','bgr8']: - image_patches.append(bridge.imgmsg_to_cv2(ros_image_patch, - 'rgb8')) - else: - raise Exception('Unhandled image encoding: %s' % - ros_image_patch.encoding) - - success = resp.success - except rospy.service.ServiceException as e: - rospy.logwarn(e) - success = False - image_patches = None - - return [success,image_patches] - - -class StandardCamera(Camera): - """Standard camera model. - - This is a model for a camera that is rigidly mounted to the navigation - coordinate system. The camera model specification follows that of Opencv. - - See addition parameter definitions in base class Camera. - - :param K: Camera intrinsic matrix. - :type K: 3x3 numpy.ndarray | None - - :param cam_pos: Position of the camera's center of projection in the - navigation coordinate system. - :type cam_pos: numpy.ndarray | None - - :param cam_quat: Quaternion specifying the orientation of the camera - relative to the navigation coordinate system. The quaternion represents - a coordinate system rotation that takes the navigation coordinate - system and rotates it into the camera coordinate system. - :type cam_quat: numpy.ndarray | None - - :param dist: Input vector of distortion coefficients (k1, k2, p1, p2, k3, - k4, k5, k6) of 4, 5, or 8 elements. - :type dist: numpy.ndarray - - """ - def __init__(self, width, height, K, dist, cam_pos, cam_quat, image_topic, - frame_id=None, nav_state_provider=None): - """ - See additional documentation from base class above. - - - - """ - super(StandardCamera, self).__init__(width, height, image_topic, - frame_id, nav_state_provider) - - self._K = np.array(K, dtype=np.float64) - self._dist = np.atleast_1d(dist).astype(np.float32) - self._cam_pos = np.array(cam_pos) - self._cam_quat = np.array(cam_quat, np.float) - self._cam_quat /= np.linalg.norm(self._cam_quat) - - def __str__(self): - string = ['model_type: standard\n'] - string.append(super(self.__class__, self).__str__()) - string.append('\n') - string.append(''.join(['fx: ',repr(self._K[0,0]),'\n'])) - string.append(''.join(['fy: ',repr(self._K[1,1]),'\n'])) - string.append(''.join(['cx: ',repr(self._K[0,2]),'\n'])) - string.append(''.join(['cy: ',repr(self._K[1,2]),'\n'])) - string.append(''.join(['distortion_coefficients: ', - repr(tuple(self._dist)), - '\n'])) - string.append(''.join(['camera_quaternion: ', - repr(tuple(self._cam_quat)),'\n'])) - string.append(''.join(['camera_position: ',repr(tuple(self._cam_pos)), - '\n'])) - return ''.join(string) - - @classmethod - def load_from_file(cls, filename, nav_state_provider=None): - """See base class Camera documentation. - - """ - with open(filename, 'r') as f: - calib = yaml.load(f) - - assert calib['model_type'] == 'standard' - - # fill in CameraInfo fields - width = calib['image_width'] - height = calib['image_height'] - dist = calib['distortion_coefficients'] - - if dist == 'None': - dist = np.zeros(4) - - fx = calib['fx'] - fy = calib['fy'] - cx = calib['cx'] - cy = calib['cy'] - K = np.array([[fx,0,cx],[0,fy,cy],[0,0,1]]) - - cam_quat = calib['camera_quaternion'] - cam_pos = calib['camera_position'] - image_topic = calib['image_topic'] - frame_id = calib['frame_id'] - - return cls(width, height, K, dist, cam_pos, cam_quat, image_topic, - frame_id, nav_state_provider) - - def save_to_file(self, filename): - """See base class Camera documentation. - - """ - with open(filename, 'w') as f: - f.write(''.join(['# The type of camera model.\n', - 'model_type: standard\n\n', - '# Image dimensions\n'])) - - f.write(''.join(['image_width: ',to_str(self.width),'\n'])) - f.write(''.join(['image_height: ',to_str(self.height),'\n\n'])) - - f.write('# Focal length along the image\'s x-axis.\n') - f.write(''.join(['fx: ',to_str(self._K[0,0]),'\n\n'])) - - f.write('# Focal length along the image\'s y-axis.\n') - f.write(''.join(['fy: ',to_str(self._K[1,1]),'\n\n'])) - - f.write('# Principal point is located at (cx,cy).\n') - f.write(''.join(['cx: ',to_str(self._K[0,2]),'\n'])) - f.write(''.join(['cy: ',to_str(self._K[1,2]),'\n\n'])) - - f.write(''.join(['# Distortion coefficients following OpenCv\'s ', - 'convention\n'])) - - dist = self._dist - if np.all(dist == 0): - dist = 'None' - - f.write(''.join(['distortion_coefficients: ', - to_str(self._dist),'\n\n'])) - - f.write(''.join(['# Quaternion specifying the orientation of the ', - 'camera relative to the\n# navigation coordinate', - ' system. The quaternion represents a coordinate', - ' system\n# rotation that takes the navigation ', - 'coordinate system and rotates it into the\n# ', - 'camera coordinate system.\n', - 'camera_quaternion: ', - to_str(self._cam_quat),'\n\n'])) - - f.write(''.join(['# Position of the camera\'s center of ', - 'projection within the navigation\n# coordinate ', - 'system.\n', - 'camera_position: ',to_str(self._cam_pos), - '\n\n'])) - - f.write('# Topic on which this camera\'s image is published\n') - f.write(''.join(['image_topic: ',self._image_topic,'\n\n'])) - - f.write('# The frame_id embedded in the published image header.\n') - f.write(''.join(['frame_id: ',self._frame_id])) - - @property - def K(self): - return self._K - - @property - def K_no_skew(self): - """Returns a compact version of K assuming no skew. - - """ - K = self.K - return np.array([K[0,0],K[1,1],K[0,2],K[1,2]]) - - @K_no_skew.setter - def K_no_skew(self, value): - """fx, fy, cx, cy - """ - K = np.zeros((3,3), dtype=np.float64) - K[0,0] = value[0] - K[1,1] = value[1] - K[0,2] = value[2] - K[1,2] = value[3] - self._K = K - - @property - def focal_length(self): - return self._K[0,0] - - @focal_length.setter - def focal_length(self, value): - self._K[0,0] = value - self._K[1,1] = value - - @property - def fx(self): - return self._K[0,0] - - @property - def fy(self): - return self._K[1,1] - - @fx.setter - def fx(self, value): - self._K[0,0] = value - - @fy.setter - def fy(self, value): - self._K[1,1] = value - - @property - def cx(self): - return self._K[0,2] - - @property - def cy(self): - return self._K[1,2] - - @cx.setter - def cx(self, value): - self._K[0,2] = value - - @cy.setter - def cy(self, value): - self._K[1,2] = value - - @property - def aspect_ratio(self): - return self._K[0,0]/self._K[1,1] - - @aspect_ratio.setter - def aspect_ratio(self, value): - self._K[1,1] = self._K[0,0]*value - - @property - def dist(self): - return self._dist - - @dist.setter - def dist(self, value): - if value is None or (np.isscalar(value) and value == 0): - value = np.zeros(4) - - self._dist = np.atleast_1d(value) - - @property - def cam_pos(self): - return self._cam_pos - - @property - def cam_quat(self): - return self._cam_quat - - @cam_quat.setter - def cam_quat(self, value): - self._cam_quat = np.atleast_1d(value) - self._cam_quat /= np.linalg.norm(self._cam_quat) - - def update_intrinsics(self, K=None, cam_quat=None, dist=None): - """ - """ - if K is not None: - self._K = K.astype(np.float64) - if cam_quat is not None: - self._cam_quat = cam_quat - if dist is not None: - self._dist = dist - - def get_camera_pose(self, t): - """Returns 3x4 matrix mapping world points to camera vectors. - - :param t: Time at which to query the camera's pose (time in seconds - since Unix epoch). - - :return: A 3x4 matrix that accepts a homogeneous 4-vector defining a - 3-D point in the world and returns a Cartesian 3-vector in the - camera's coordinate system pointing from the camera's center of - projection to the word point (i.e., the negative of the principal - ray coming from this world point). - :rtype: 3x4 array - """ - - ins_pos, ins_quat = self.nav_state_provider.pose(t) - - cam_pos = self._cam_pos - cam_quat = self._cam_quat - - p_ins = rt_from_quat_pos(ins_pos, ins_quat) - p_cam = rt_from_quat_pos(cam_pos, cam_quat) - - return np.dot(p_cam, p_ins)[:3] - - def project(self, points, t=None): - """See Camera.project documentation. - - """ - points = np.array(points, dtype=np.float64) - if points.ndim == 1: - points = np.atleast_2d(points).T - - if t is None: - t = time.time() - - pose_mat = self.get_camera_pose(t) - - # Project rays into camera coordinate system. - rvec = cv2.Rodrigues(pose_mat[:3,:3])[0].ravel() - tvec = pose_mat[:,3] - im_pts = cv2.projectPoints(points.T, rvec, tvec, self._K, - self._dist)[0] - return np.squeeze(im_pts, 1).T - - def unproject(self, points, t=None): - """See Camera.unproject documentation. - - """ - points = np.array(points, dtype=np.float64) - if points.ndim == 1: - points = np.atleast_2d(points).T - points.shape = (2,-1) - - if t is None: - t = time.time() - - ins_pos, ins_quat = self.nav_state_provider.pose(t) - #print('ins_pos', ins_pos) - #print('ins_quat', ins_quat) - - # Unproject rays into the camera coordinate system. - ray_dir = np.ones((3,points.shape[1]), dtype=points.dtype) - ray_dir0 = cv2.undistortPoints(np.expand_dims(points.T, 0), - self._K, self._dist, R=None) - ray_dir[:2] = np.squeeze(ray_dir0, 0).T - - # Rotate rays into the navigation coordinate system. - ray_dir = np.dot(quaternion_matrix(self._cam_quat)[:3,:3], ray_dir) - - # Translate ray positions into their navigation coordinate system - # definition. - ray_pos = np.zeros_like(ray_dir) - ray_pos[0] = self._cam_pos[0] - ray_pos[1] = self._cam_pos[1] - ray_pos[2] = self._cam_pos[2] - - # Rotate and translate rays into the world coordinate system. - R_ins_to_world = quaternion_matrix(ins_quat)[:3,:3] - ray_dir = np.dot(R_ins_to_world, ray_dir) - ray_pos = np.dot(R_ins_to_world, ray_pos) + np.atleast_2d(ins_pos).T - - # Normalize - ray_dir /= np.sqrt(np.sum(ray_dir**2, 0)) - - return ray_pos, ray_dir diff --git a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py index 3e5ecb4..29a2881 100644 --- a/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py +++ b/src/kitware-ros-pkg/wxpython_gui/src/wxpython_gui/system_control_panel/gui.py @@ -59,7 +59,7 @@ RequestImageView, CamSetAttr, ) -from wxpython_gui.camera_models import load_from_file +from kamera.colmap_processing.camera_models import load_from_file # Sibling modules within the system_control_panel package import wxpython_gui.system_control_panel.form_builder_output as form_builder_output From 58dc9aaab53e22e38be994070e724bcfad5ffdc6 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Thu, 18 Jun 2026 16:48:44 -0400 Subject: [PATCH 138/139] Properly label icons --- provision/start_stop/desktop_shortcuts/reboot_all.desktop | 2 +- provision/start_stop/desktop_shortcuts/shutdown_all.desktop | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/provision/start_stop/desktop_shortcuts/reboot_all.desktop b/provision/start_stop/desktop_shortcuts/reboot_all.desktop index a040e31..5887659 100755 --- a/provision/start_stop/desktop_shortcuts/reboot_all.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_all.desktop @@ -4,4 +4,4 @@ Name=reboot_all Terminal=true Type=Application Icon=system-reboot -Name[en_US]=Reboot\nBoth Systems +Name[en_US]=Reboot\All Systems diff --git a/provision/start_stop/desktop_shortcuts/shutdown_all.desktop b/provision/start_stop/desktop_shortcuts/shutdown_all.desktop index dfc7a16..a0dc3c1 100755 --- a/provision/start_stop/desktop_shortcuts/shutdown_all.desktop +++ b/provision/start_stop/desktop_shortcuts/shutdown_all.desktop @@ -4,4 +4,4 @@ Name=shutdown_all Terminal=true Type=Application Icon=system-shutdown -Name[en_US]=Shutdown\nBoth Systems +Name[en_US]=Shutdown\nAll Systems From 080f56e9ff5e6e94acb7e01a012083c095f89693 Mon Sep 17 00:00:00 2001 From: romleiaj Date: Thu, 18 Jun 2026 17:00:41 -0400 Subject: [PATCH 139/139] Need that new line --- provision/start_stop/desktop_shortcuts/reboot_all.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provision/start_stop/desktop_shortcuts/reboot_all.desktop b/provision/start_stop/desktop_shortcuts/reboot_all.desktop index 5887659..1c6d9a2 100755 --- a/provision/start_stop/desktop_shortcuts/reboot_all.desktop +++ b/provision/start_stop/desktop_shortcuts/reboot_all.desktop @@ -4,4 +4,4 @@ Name=reboot_all Terminal=true Type=Application Icon=system-reboot -Name[en_US]=Reboot\All Systems +Name[en_US]=Reboot\nAll Systems