diff --git a/RELEASE.md b/RELEASE.md index dea20defdf..fab3e92e4b 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,5 +1,11 @@ # Releases +# Release 0.17.3 + + * Comms bridge added rate feature + * Bug fixes + * User feedback improvements + # Release 0.17.2 * Adding Generic comms bridge diff --git a/astrobee.doxyfile b/astrobee.doxyfile index 7bb0ffe858..d7f71e82f3 100644 --- a/astrobee.doxyfile +++ b/astrobee.doxyfile @@ -39,7 +39,7 @@ PROJECT_NAME = "NASA Astrobee Robot Software" # control system is used. -PROJECT_NUMBER = 0.17.2 +PROJECT_NUMBER = 0.17.3 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/astrobee/CMakeLists.txt b/astrobee/CMakeLists.txt index e47ad4b0b5..dfb9b085fb 100644 --- a/astrobee/CMakeLists.txt +++ b/astrobee/CMakeLists.txt @@ -18,7 +18,7 @@ cmake_minimum_required(VERSION 3.0) project(astrobee) -set(ASTROBEE_VERSION 0.17.2) +set(ASTROBEE_VERSION 0.17.3) ## Compile as C++14, supported in ROS Kinetic and newer add_compile_options(-std=c++14) diff --git a/debian/changelog b/debian/changelog index 41f219a17f..e514f8a194 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +astrobee (0.17.3) testing; urgency=medium + + * Comms bridge added rate feature + * Bug fixes + * User feedback improvements + + -- Astrobee Flight Software Thu, 09 May 2024 11:50:34 -0700 + astrobee (0.17.2) UNRELEASED; urgency=medium * Adding Generic comms bridge diff --git a/scripts/setup/install_desktop_packages.sh b/scripts/setup/install_desktop_packages.sh index 163e42f148..9b280a96a4 100755 --- a/scripts/setup/install_desktop_packages.sh +++ b/scripts/setup/install_desktop_packages.sh @@ -50,13 +50,13 @@ then if [ "${NO_TUNNEL}" -eq 1 ]; then echo "Getting the custom Debian without tunnel" - sudo /bin/bash -c "echo \"deb [arch=amd64] http://astrobee.ndc.nasa.gov/software_new ${DIST} main\" > $arssrc" || exit 1 - sudo /bin/bash -c "echo \"deb-src http://astrobee.ndc.nasa.gov/software_new ${DIST} main\" >> $arssrc" || exit 1 + sudo /bin/bash -c "echo \"deb [arch=amd64] https://astrobee.ndc.nasa.gov/software_new ${DIST} main\" > $arssrc" || exit 1 + sudo /bin/bash -c "echo \"deb-src https://astrobee.ndc.nasa.gov/software_new ${DIST} main\" >> $arssrc" || exit 1 else echo "Tunnelling to get the custom Debian" - sudo /bin/bash -c "echo \"deb [arch=amd64] http://127.0.0.1:8765/software_new ${DIST} main\" > $arssrc" || exit 1 - sudo /bin/bash -c "echo \"deb-src http://127.0.0.1:8765/software_new ${DIST} main\" >> $arssrc" || exit 1 - ssh -N -L 127.0.0.1:8765:astrobee.ndc.nasa.gov:80 ${username}m.ndc.nasa.gov & + sudo /bin/bash -c "echo \"deb [arch=amd64] https://127.0.0.1:8765/software_new ${DIST} main\" > $arssrc" || exit 1 + sudo /bin/bash -c "echo \"deb-src https://127.0.0.1:8765/software_new ${DIST} main\" >> $arssrc" || exit 1 + ssh -N -L 127.0.0.1:8765:astrobee.ndc.nasa.gov:443 ${username}m.ndc.nasa.gov & fi trap "kill $! 2> /dev/null; sudo truncate -s 0 $arssrc; wait $!" 0 HUP QUIT ILL ABRT FPE SEGV PIPE TERM INT diff --git a/simulation/CMakeLists.txt b/simulation/CMakeLists.txt index 2c37703890..1ad7b83ee1 100644 --- a/simulation/CMakeLists.txt +++ b/simulation/CMakeLists.txt @@ -19,8 +19,8 @@ cmake_minimum_required(VERSION 3.0) project(astrobee_gazebo) if (ENABLE_GAZEBO) -## Compile as C++14, supported in ROS Kinetic and newer -add_compile_options(-std=c++14) +## Compile as C++17 +add_compile_options(-std=c++17) ## Find catkin macros and libraries find_package(catkin2 REQUIRED COMPONENTS diff --git a/tools/bag_processing/src/bag_processing/pixel_utils.py b/tools/bag_processing/src/bag_processing/pixel_utils.py index c937d99b87..75fdb8a750 100644 --- a/tools/bag_processing/src/bag_processing/pixel_utils.py +++ b/tools/bag_processing/src/bag_processing/pixel_utils.py @@ -65,7 +65,7 @@ RgbImage = np.ndarray # RGB image with array shape (H, W, 3), dtype=np.uint8. BayerImage = np.ndarray # Raw Bayer image with array shape (H, W), dtype=np.uint8 BayerImagePatch = BayerImage # A really small BayerImage ;) -ImageMask = np.ndarray # An image with array shape (H, W), dtype=np.bool +ImageMask = np.ndarray # An image with array shape (H, W), dtype=bool Kernel = np.ndarray # An NxN kernel with N odd MonoImage = np.ndarray # Image with array shape (H, W), dtype=np.uint8 FloatImage = np.ndarray # Image with array shape (H, W), dtype=np.float64 @@ -197,12 +197,12 @@ def median_filter( assert out.dtype == np.uint8 if compute_mask is None: - compute_mask = np.ones(im.shape, dtype=np.bool) + compute_mask = np.ones(im.shape, dtype=bool) else: assert compute_mask.shape == im.shape # edges - slower due to use of np.ma.median() to exclude out-of-bounds neighbors - edge_mask = np.zeros(im.shape, dtype=np.bool) + edge_mask = np.zeros(im.shape, dtype=bool) edge_mask[:2, :] = compute_mask[:2, :] edge_mask[-2:, :] = compute_mask[-2:, :] edge_mask[:, :2] = compute_mask[:, :2] @@ -228,7 +228,7 @@ def median_filter( times.append(time.time()) # 6 # middle - runs faster using np.median() - middle_mask = np.zeros(im.shape, dtype=np.bool) + middle_mask = np.zeros(im.shape, dtype=bool) middle_mask[2:-2, 2:-2] = compute_mask[2:-2, 2:-2] middle_y, middle_x = np.nonzero(middle_mask) y = y0[np.newaxis, middle_y, middle_x] + y_off[:, np.newaxis, np.newaxis] @@ -801,7 +801,7 @@ def __init__(self, image_shape: ArrayShape, bad_coords: CoordArray, note: str = def _init_filter(self, bad_coords: CoordArray) -> None: "Initialize self.bad_pixels for interpolation." - bad_image = np.zeros(self.image_shape, dtype=np.bool) + bad_image = np.zeros(self.image_shape, dtype=bool) bad_image[tuple(bad_coords)] = True for y, x in zip(*bad_coords): kernel = get_bayer_neighbor_kernel( diff --git a/tools/gnc_visualizer/scripts/communications/com_manager.py b/tools/gnc_visualizer/scripts/communications/com_manager.py index 4a1ebdd54a..d758c88957 100644 --- a/tools/gnc_visualizer/scripts/communications/com_manager.py +++ b/tools/gnc_visualizer/scripts/communications/com_manager.py @@ -93,15 +93,17 @@ def set_com_method(self, com_method, args=None): partition_name, given_peer, domain, public_ip ): # Print result - print >> sys.stderr, ( - self.config.get_all_warnings() + self.config.get_all_info() + print( + self.config.get_all_warnings() + self.config.get_all_info(), + file=sys.stderr, ) else: # Print result and exit - print >> sys.stderr, ( + print( self.config.get_all_errors() + self.config.get_all_warnings() - + self.config.get_all_info() + + self.config.get_all_info(), + file=sys.stderr, ) return False diff --git a/tools/gnc_visualizer/scripts/communications/configuration_support.py b/tools/gnc_visualizer/scripts/communications/configuration_support.py index 4b89e014e0..f79dd6ecb2 100644 --- a/tools/gnc_visualizer/scripts/communications/configuration_support.py +++ b/tools/gnc_visualizer/scripts/communications/configuration_support.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import configparser import datetime import socket import string @@ -8,8 +9,6 @@ from os import path as osPath from os import remove -import ConfigParser - filepath = osPath.dirname(osPath.realpath(__file__)) BASE_DDS_PROFILE_FILE = filepath + "/dds_types/BaseDDSProfile.xml" @@ -21,7 +20,7 @@ class Preferences: def __init__( self, partition_name=None, given_peer=None, domain=None, public_ip=None ): - self.config = ConfigParser.ConfigParser() + self.config = configparser.ConfigParser() self.dom = None self.partition_name = partition_name self.initial_peers = dict() @@ -154,7 +153,7 @@ def clear_node_list(self, node_list, sub_tag_name): peer.unlink() def write_node_list(self, node_list, sub_tag_name, children): - children = [children] if isinstance(children, basestring) else children + children = [children] if isinstance(children, str) else children for child in children: new_node = node_list.ownerDocument.createElement(sub_tag_name) new_node.appendChild( diff --git a/tools/gnc_visualizer/scripts/plot_types.py b/tools/gnc_visualizer/scripts/plot_types.py index e8ddaf9ffc..a7764ab8cb 100644 --- a/tools/gnc_visualizer/scripts/plot_types.py +++ b/tools/gnc_visualizer/scripts/plot_types.py @@ -21,7 +21,8 @@ import numpy as np import pyqtgraph as pg -from pyqtgraph.Qt import QtCore, QtGui +from PyQt5 import QtCore +from PyQt5.QtWidgets import QGraphicsPathItem DISPLAY_TIME = 10 @@ -72,10 +73,10 @@ def update_plot(self, data): self.setLimits(xMin=max(0, t - DISPLAY_TIME), xMax=t) -class PathItem(pg.QtGui.QGraphicsPathItem): +class PathItem(QGraphicsPathItem): def __init__(self, pen): self.path = pg.arrayToQPath(np.zeros(0), np.zeros(0), "all") - pg.QtGui.QGraphicsPathItem.__init__(self, self.path) + QGraphicsPathItem.__init__(self, self.path) self.setPen(pen) self.last_time = None diff --git a/tools/gnc_visualizer/scripts/visualizer.py b/tools/gnc_visualizer/scripts/visualizer.py index 80adeeb6d6..a13605c58b 100755 --- a/tools/gnc_visualizer/scripts/visualizer.py +++ b/tools/gnc_visualizer/scripts/visualizer.py @@ -32,6 +32,13 @@ import numpy as np import pyqtgraph as pg +from PyQt5.QtWidgets import ( + QApplication, + QGraphicsScene, + QGraphicsTextItem, + QGraphicsView, + QMainWindow, +) from pyqtgraph.Qt import QtCore, QtGui filepath = os.path.dirname(os.path.realpath(__file__)) @@ -254,7 +261,7 @@ def mahal_filter(dists): ] -class TerminalView(QtGui.QGraphicsTextItem): +class TerminalView(QGraphicsTextItem): def __init__(self, graphics_view): super(TerminalView, self).__init__("") self.graphics_view = graphics_view @@ -274,11 +281,11 @@ def paint(self, painter, o, w): super(TerminalView, self).paint(painter, o, w) -class TerminalGraphicsView(QtGui.QGraphicsView): +class TerminalGraphicsView(QGraphicsView): def __init__(self, parent): super(TerminalGraphicsView, self).__init__() - self.connect(parent, QtCore.SIGNAL("resize"), self.resize) - self.setScene(QtGui.QGraphicsScene()) + # self.connect(parent, QtCore.SIGNAL("resize"), self.resize) + self.setScene(QGraphicsScene()) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setAttribute(QtCore.Qt.WA_TranslucentBackground) @@ -292,17 +299,19 @@ def resize(self, event): class ParentGraphicsView(pg.GraphicsView): + resized = QtCore.pyqtSignal(QtCore.QEvent) + def __init__(self): super(ParentGraphicsView, self).__init__() self.setAntialiasing(False) def resizeEvent(self, event): super(ParentGraphicsView, self).resizeEvent(event) - if event != None: - self.emit(QtCore.SIGNAL("resize"), event) + if event is not None: + self.resized.emit(event) -class Visualizer(QtGui.QMainWindow): +class Visualizer(QMainWindow): def __init__(self, launch_command=None, plan=None, com_method=com.DDS_COM): super(Visualizer, self).__init__() self.com_method = com_method @@ -362,10 +371,10 @@ def __init__(self, launch_command=None, plan=None, com_method=com.DDS_COM): self.setWindowTitle("GNC Visualizer") self.settings = QtCore.QSettings("NASA", "gnc_visualizer") - self.restoreGeometry(self.settings.value("geometry", "").toByteArray()) - self.restoreState(self.settings.value("windowState", "").toByteArray()) + self.restoreGeometry(self.settings.value("geometry", "").encode()) + self.restoreState(self.settings.value("windowState", "").encode()) - QtGui.qApp.installEventFilter(self) + QApplication.instance().installEventFilter(self) # make sure initial window size includes menubar QtCore.QTimer.singleShot(0, self.menuBar().hide) @@ -403,7 +412,7 @@ def stopProcess(self): def eventFilter(self, source, event): # do not hide menubar when menu shown - if QtGui.qApp.activePopupWidget() is None: + if QApplication.instance().activePopupWidget() is None: if event.type() == QtCore.QEvent.MouseMove: if self.menuBar().isHidden(): rect = self.geometry() @@ -420,7 +429,7 @@ def eventFilter(self, source, event): self.menuBar().hide() elif event.type() == QtCore.QEvent.Leave and source is self: self.menuBar().hide() - return QtGui.QMainWindow.eventFilter(self, source, event) + return super().eventFilter(source, event) def delete_plot(self, col, row): del self.columns[col][row] @@ -711,7 +720,7 @@ def log_callback(self, data): def sigint_handler(*args): - QtGui.QApplication.quit() + QApplication.quit() def main(): @@ -797,7 +806,7 @@ def main(): if args.com_method in (com.DDS_COM, com.ROS_COM): com_method = args.com_method else: - print >> sys.stderr, "Invalid communication method. Must be dds or ros" + print("Invalid communication method. Must be dds or ros", file=sys.stderr) return launch_command = None @@ -806,11 +815,12 @@ def main(): if com_method == com.DDS_COM and ( args.launch_command != None or args.disable_pmcs or args.plan != None ): - print >> sys.stderr, ( + print( "\n###\n" + "\nAdditional arguments (--gantry --granite --bag --sim --plan --disable_pmcs) " + 'will not be processed when using DDS mode. You may use "--comm ros" or do not include this ' - + "argument at all in order to use additional arguments.\n\n###\n" + + "argument at all in order to use additional arguments.\n\n###\n", + file=sys.stderr, ) return # Exclude DDS commands when using ROS communication @@ -820,18 +830,19 @@ def main(): or args.public_ip != None or args.domain != None ): - print >> sys.stderr, ( + print( "\n###\n" + "\nAdditional arguments (--use_ip --robot_name --public_ip) " + 'will not be processed when using ROS mode. You may include "--comm dds" ' - + "argument in order to use these additional arguments.\n\n###\n" + + "argument in order to use these additional arguments.\n\n###\n", + file=sys.stderr, ) return else: if args.launch_command == None: args.launch_command = [] if len(args.launch_command) > 1: - print >> sys.stderr, "Can only specify one launch command." + print("Can only specify one launch command.", file=sys.stderr) return if len(args.launch_command) == 1: launch_command = args.launch_command[0] @@ -849,7 +860,7 @@ def main(): if not com_manager.set_com_method(com_method, dds_args): return - app = QtGui.QApplication([]) + app = QApplication([]) signal.signal(signal.SIGINT, sigint_handler) v = Visualizer(launch_command, args.plan, com_manager.current_com_method)