Skip to content

Commit

Permalink
Rearrange menu and improve info page
Browse files Browse the repository at this point in the history
  • Loading branch information
rbonghi committed Jan 20, 2025
1 parent 1bb8b5a commit 61bdfd4
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 86 deletions.
140 changes: 67 additions & 73 deletions src/nanosaur/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,9 @@ def info(platform, params: Params, args):
robot_data = robot.RobotList.get_robot(params)
robot_data.verbose()
# Print other robots if they exist
if len(robot_list.robots) > 1:
print("\nOther robots:")
for i, rb in enumerate(robot_list.robots):
if i != params.get('robot_idx', 0):
print(f"{i}. {rb}")

if len(robot_list.robots) > 1 or args.verbose:
print()
robot_list.print_all_robots(params.get('robot_idx', 0))
# Print simulation tools if they exist
if 'simulation_tool' in params:
print(f"\n{TerminalFormatter.color_text('Simulation Tool:', bold=True)} {params['simulation_tool']}")
Expand All @@ -86,13 +83,8 @@ def info(platform, params: Params, args):

# Print all robot configurations
if args.verbose:
# Print configuration parameters
print("\nConfiguration:")
for key, value in params.items():
if value: # Only print if value is not empty
print(f" {key}: {value}")
# Print device information
print("\nPlatform Information:")
print(TerminalFormatter.color_text("\nPlatform Information:", bold=True))
for key, value in platform.items():
print(f" {key}: {value}")
# Print version information
Expand Down Expand Up @@ -155,6 +147,51 @@ def parser_simulation_menu(subparsers: argparse._SubParsersAction, params: Param
parser_simulation_set.set_defaults(func=simulation.simulation_set)
return parser_simulation

def parser_robot_menu(subparsers: argparse._SubParsersAction, params: Params) -> argparse.ArgumentParser:
robot_data = robot.RobotList.get_robot(params)
parser_robot = subparsers.add_parser('robot', help=f"Manage the Nanosaur robot [{robot_data.name}]")
robot_subparsers = parser_robot.add_subparsers(dest='robot_type', help="Robot operations")
# Add robot display subcommand
parser_robot_display = robot_subparsers.add_parser('display', help="Display the robot configuration")
parser_robot_display.set_defaults(func=robot.robot_display)
# Add robot drive subcommand
parser_robot_drive = robot_subparsers.add_parser('drive', help="Drive the robot")
parser_robot_drive.set_defaults(func=robot.control_keyboard)
# Add robot start subcommand
parser_robot_start = robot_subparsers.add_parser('start', help="Start the robot")
parser_robot_start.add_argument(
'--container', action='store_true', help="Run from container")
parser_robot_start.add_argument(
'--build', action='store_true', help="Rebuild docker before starting")
parser_robot_start.set_defaults(func=robot.robot_start)
# Add robot stop subcommand
parser_robot_stop = robot_subparsers.add_parser('stop', help="Stop the robot")
parser_robot_stop.set_defaults(func=robot.robot_stop)
# Add robot name subcommand
parser_robot_name = robot_subparsers.add_parser('name', help=f"Set the robot name [{robot_data.name}]")
parser_robot_name.add_argument('name', type=str, nargs='?', help="Name of the robot (default: nanosaur)")
parser_robot_name.set_defaults(func=robot.robot_set_name)
# Add robot domain id subcommand
parser_robot_domain_id = robot_subparsers.add_parser('domain_id', help=f"Set the robot domain ID [{robot_data.domain_id}]")
parser_robot_domain_id.add_argument('domain_id', type=int, nargs='?', help="Domain ID of the robot (default: 0)")
parser_robot_domain_id.set_defaults(func=robot.robot_set_domain_id)
# Add robot camera subcommand
parser_robot_camera = robot_subparsers.add_parser('camera', help=f"Set the robot camera type [{robot_data.camera_type}]")
parser_robot_camera.add_argument('--new-camera', type=str, help=f"Specify the new camera configuration (options: {', '.join(CAMERA_CHOICES)})")
parser_robot_camera.set_defaults(func=robot.robot_set_camera)
# Add robot lidar subcommand
parser_robot_lidar = robot_subparsers.add_parser('lidar', help=f"Set the robot lidar type [{robot_data.lidar_type}]")
parser_robot_lidar.add_argument('--new-lidar', type=str, choices=LIDAR_CHOICES, help=f"Specify the new lidar configuration (options: {', '.join(LIDAR_CHOICES)})")
parser_robot_lidar.set_defaults(func=robot.robot_set_lidar)
# Add robot engines subcommand
parser_robot_engines = robot_subparsers.add_parser('engines', help=f"Configure the robot engines [{', '.join(robot_data.engines)}]")
parser_robot_engines.add_argument('--new-engine', type=str, help="Specify the new engine configuration")
parser_robot_engines.set_defaults(func=robot.robot_configure_engines)
# Add robot reset subcommand
parser_robot_reset = robot_subparsers.add_parser('reset', help="Reset the robot configuration")
parser_robot_reset.set_defaults(func=robot.robot_reset)

return parser_robot

def parser_swarm_menu(subparsers: argparse._SubParsersAction, params: Params) -> argparse.ArgumentParser:
# Get the robot index from the parameters
Expand All @@ -170,6 +207,10 @@ def parser_swarm_menu(subparsers: argparse._SubParsersAction, params: Params) ->
parser_robot_set = swarm_subparsers.add_parser('set', help=f"Set which robot to control [{idx_swarm}]")
parser_robot_set.add_argument('robot_name', type=str, nargs='?', help="Name of the robot to control")
parser_robot_set.set_defaults(func=swarm.robot_idx_set)
# Add robot remove subcommand
parser_robot_remove = swarm_subparsers.add_parser('remove', help="Remove a robot from the swarm")
parser_robot_remove.add_argument('robot_name', type=str, nargs='?', help="Name of the robot to remove")
parser_robot_remove.set_defaults(func=swarm.robot_remove)
# Add robot list subcommand
parser_robot_list = swarm_subparsers.add_parser('list', help="List all robots in the swarm")
parser_robot_list.set_defaults(func=swarm.robot_list)
Expand Down Expand Up @@ -226,51 +267,8 @@ def main():
# Add simulation subcommand
parser_simulation = parser_simulation_menu(subparsers, params)

# Subcommand: robot (with a sub-menu for robot operations)
robot_data = robot.RobotList.get_robot(params)
parser_robot = subparsers.add_parser('robot', help=f"Manage the Nanosaur robot [{robot_data.name}]")
robot_subparsers = parser_robot.add_subparsers(dest='robot_type', help="Robot operations")

# Add robot display subcommand
parser_robot_display = robot_subparsers.add_parser('display', help="Display the robot configuration")
parser_robot_display.set_defaults(func=robot.robot_display)
# Add robot drive subcommand
parser_robot_drive = robot_subparsers.add_parser('drive', help="Drive the robot")
parser_robot_drive.set_defaults(func=robot.control_keyboard)
# Add robot start subcommand
parser_robot_start = robot_subparsers.add_parser('start', help="Start the robot")
parser_robot_start.add_argument(
'--container', action='store_true', help="Run from container")
parser_robot_start.add_argument(
'--build', action='store_true', help="Rebuild docker before starting")
parser_robot_start.set_defaults(func=robot.robot_start)
# Add robot stop subcommand
parser_robot_stop = robot_subparsers.add_parser('stop', help="Stop the robot")
parser_robot_stop.set_defaults(func=robot.robot_stop)

# Add robot name subcommand
parser_robot_name = robot_subparsers.add_parser('name', help=f"Set the robot name [{robot_data.name}]")
parser_robot_name.add_argument('name', type=str, nargs='?', help="Name of the robot (default: nanosaur)")
parser_robot_name.set_defaults(func=robot.robot_set_name)
# Add robot domain id subcommand
parser_robot_domain_id = robot_subparsers.add_parser('domain_id', help=f"Set the robot domain ID [{robot_data.domain_id}]")
parser_robot_domain_id.add_argument('domain_id', type=int, nargs='?', help="Domain ID of the robot (default: 0)")
parser_robot_domain_id.set_defaults(func=robot.robot_set_domain_id)
# Add robot camera subcommand
parser_robot_camera = robot_subparsers.add_parser('camera', help=f"Set the robot camera type [{robot_data.camera_type}]")
parser_robot_camera.add_argument('--new-camera', type=str, help=f"Specify the new camera configuration (options: {', '.join(CAMERA_CHOICES)})")
parser_robot_camera.set_defaults(func=robot.robot_set_camera)
# Add robot lidar subcommand
parser_robot_lidar = robot_subparsers.add_parser('lidar', help=f"Set the robot lidar type [{robot_data.lidar_type}]")
parser_robot_lidar.add_argument('--new-lidar', type=str, choices=LIDAR_CHOICES, help=f"Specify the new lidar configuration (options: {', '.join(LIDAR_CHOICES)})")
parser_robot_lidar.set_defaults(func=robot.robot_set_lidar)
# Add robot engines subcommand
parser_robot_engines = robot_subparsers.add_parser('engines', help=f"Configure the robot engines [{', '.join(robot_data.engines)}]")
parser_robot_engines.add_argument('--new-engine', type=str, help="Specify the new engine configuration")
parser_robot_engines.set_defaults(func=robot.robot_configure_engines)
# Add robot reset subcommand
parser_robot_reset = robot_subparsers.add_parser('reset', help="Reset the robot configuration")
parser_robot_reset.set_defaults(func=robot.robot_reset)
# Add robot subcommand
parser_robot = parser_robot_menu(subparsers, params)

if device_type == 'desktop':
# Subcommand: swarm (with a sub-menu for swarm operations)
Expand All @@ -282,22 +280,18 @@ def main():
# Parse the arguments
args = parser.parse_args()

# Handle workspace subcommand without a workspace_type
if args.command in ['workspace', 'ws'] and args.workspace_type is None:
parser_workspace.print_help()
sys.exit(1)

# Handle install subcommand without an install_type
if args.command in ['simulation', 'sim'] and args.simulation_type is None:
parser_simulation.print_help()
sys.exit(1)

if args.command in ['robot'] and args.robot_type is None:
parser_robot.print_help()
sys.exit(1)

if args.command in ['swarm'] and args.swarm_type is None:
parser_swarm.print_help()
# Handle subcommands without a specific type
subcommand_map = {
'workspace': parser_workspace,
'ws': parser_workspace,
'simulation': parser_simulation,
'sim': parser_simulation,
'robot': parser_robot,
'swarm': parser_swarm
}

if args.command in subcommand_map and getattr(args, f"{args.command}_type", None) is None:
subcommand_map[args.command].print_help()
sys.exit(1)

# Execute the corresponding function based on the subcommand
Expand Down
22 changes: 16 additions & 6 deletions src/nanosaur/swarm.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,23 @@ def robot_idx_set(platform, params: Params, args):
print(f"Current robot index: {params.get('robot_idx', 0)} name: {robot.name}")


def robot_remove(platform, params: Params, args):
"""Remove a robot configuration."""
if args.robot_name is None:
robot = RobotList.load(params)._get_robot_by_idx(params.get('robot_idx', 0))
args.robot_name = robot.name

confirmation = input(f"Are you sure you want to {TerminalFormatter.color_text('**remove**', color='red', bold=True)} the robot configuration for {TerminalFormatter.color_text(args.robot_name, color='green', bold=True)}? (yes/no): ")
if confirmation.lower() == 'yes':
RobotList.remove_robot(params, params.get('robot_idx', 0))
print(TerminalFormatter.color_text("Robot configuration removed", color='green'))
return True
else:
print(TerminalFormatter.color_text("Robot configuration removal canceled", color='yellow'))


def robot_list(platform, params: Params, args):
"""List the robot configurations."""
robot_list = RobotList.load(params)
for i, robot in enumerate(robot_list.robots):
if i == params.get('robot_idx', 0):
print(TerminalFormatter.color_text(f"{i}. {robot}", color='green'))
else:
print(f"{i}. {robot}")
RobotList.load(params).print_all_robots(params.get('robot_idx', 0))
return True
# EOF
25 changes: 18 additions & 7 deletions src/nanosaur/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,13 @@ def __init__(self, robot_config=None, name=None):
setattr(self, key, value)

def __repr__(self):
attributes = ', '.join(f"{key}={value}" for key, value in self.__dict__.items() if key not in ['name', 'domain_id', 'simulation'] and value)
attributes = ', '.join(
f"{key}={value}" for key, value in self.__dict__.items()
if key not in ['name', 'domain_id', 'simulation'] and value
)
sim_prefix = "(sim) " if self.simulation else ""
return f"{sim_prefix}{self.name}[DID={self.domain_id}]({attributes})"
base_repr = f"{sim_prefix}{self.name}[DID={self.domain_id}]"
return f"{base_repr}({attributes})" if attributes else base_repr

def to_dict(self) -> dict:
return self.__dict__
Expand Down Expand Up @@ -119,9 +123,9 @@ def add_robot(cls, params, robot) -> bool:
return False

@classmethod
def remove_robot(cls, params):
def remove_robot(cls, params, robot_idx=None):
robot_list = cls.load(params)
idx = params.get('robot_idx', 0)
idx = robot_idx if robot_idx is not None else params.get('robot_idx', 0)
if idx == 0:
if 'robots' in params:
del params['robots']
Expand Down Expand Up @@ -197,9 +201,16 @@ def __repr__(self):
def to_dict(self) -> list:
return [robot.to_dict() for robot in self.robots]

def print_all_robots(self):
for robot in self.robots:
print(robot)
def print_all_robots(self, robot_idx=None):
if robot_idx is not None:
print(TerminalFormatter.color_text(f"All robots: (selected: {robot_idx})", bold=True))
else:
print(TerminalFormatter.color_text("All robots:", bold=True))
for idx, robot in enumerate(self.robots):
if idx == robot_idx:
print(f" {TerminalFormatter.color_text(f'Robot {idx}:', bold=True)} {TerminalFormatter.color_text(robot, color='green')}")
else:
print(f" {TerminalFormatter.color_text(f'Robot {idx}:', bold=True)} {robot}")


class Params:
Expand Down

0 comments on commit 61bdfd4

Please sign in to comment.