diff --git a/README.md b/README.md index 051ce02..aa113ac 100644 --- a/README.md +++ b/README.md @@ -53,11 +53,23 @@ Supported parameters: Displays the robot's model in rviz, starts joint_state_publisher and robot_state_publisher ```bash #### Load generation 3 model -ros2 launch robotont_description display_simulated_robot.launch.py +ros2 launch robotont_description display_robot_model.launch.py ``` +Displays the robot's model in rviz, with different frame colors (blue, light_blue, purple, yellow, green, dark_green, black, gray): +```bash +#### Load generation 3 model with specific frame color +ros2 launch robotont_description display_robot_model.launch.py primary_color:=light_blue +``` + +Supported formats for `primary_color`: +- color name: primary_color:=lightblue +- RGBA (0..1): primary_color:="0.16 0.65 0.98 1.0" +- RGBA (0..255): primary_color:="41 166 250 255" +- HEX: primary_color:="#29a6faff" + ```bash #### Load generation 2.1 model -ros2 launch robotont_description display_simulated_robot.launch.py generation:=2.1 +ros2 launch robotont_description display_robot_model.launch.py generation:=2.1 ``` #### 2.2. Description Starts joint_state_publisher and robot_state_publisher, robot model is published on /robot_description topic. diff --git a/launch/display_robot_model.launch.py b/launch/display_robot_model.launch.py new file mode 100644 index 0000000..13bc76b --- /dev/null +++ b/launch/display_robot_model.launch.py @@ -0,0 +1,123 @@ +from ament_index_python.packages import get_package_share_path + +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument, OpaqueFunction +from launch.substitutions import LaunchConfiguration, Command +from launch_ros.actions import Node +from launch_ros.parameter_descriptions import ParameterValue + + +def _rgba_string_from_user_value(user_value: str) -> str: + s = (user_value or "").strip() + if not s: + raise ValueError("Empty color string") + + # RGBA numeric input (space or comma separated) + parts = s.replace(",", " ").split() + if len(parts) == 4: + nums = [float(p) for p in parts] + if any(v > 1.0 for v in nums): + nums = [v / 255.0 for v in nums] + nums = [min(1.0, max(0.0, v)) for v in nums] + return f"{nums[0]} {nums[1]} {nums[2]} {nums[3]}" + + # Hex input + if s.startswith("#") and len(s) in (7, 9): + hexv = s[1:] + r = int(hexv[0:2], 16) + g = int(hexv[2:4], 16) + b = int(hexv[4:6], 16) + a = int(hexv[6:8], 16) if len(hexv) == 8 else 255 + return f"{r/255.0} {g/255.0} {b/255.0} {a/255.0}" + + # Color names + name = s.lower().replace("_", "").replace("-", "") + try: + from PIL import ImageColor + r, g, b, a = ImageColor.getcolor(name, "RGBA") + return f"{r/255.0} {g/255.0} {b/255.0} {a/255.0}" + except Exception: + fallback = { + "lightblue": "0.16 0.65 0.98 1.0", + "blue": "0.00 0.35 0.90 1.0", + "yellow": "1.00 1.00 0.00 1.0", + "black": "0.10 0.10 0.10 1.0", + "purple": "0.45 0.20 0.65 1.0", + "gray": "0.75 0.75 0.75 1.0", + "darkgreen": "0.00 0.45 0.25 1.0", + "green": "0.00 0.80 0.30 1.0", + } + if name in fallback: + return fallback[name] + raise ValueError( + f"Unknown color '{user_value}'. Provide RGBA ('0 1 0 1' or '0 255 0 255'), " + f"hex ('#00ff00' or '#00ff00ff'), or install Pillow for CSS color names." + ) + + +def _setup(context, *args, **kwargs): + pkg = get_package_share_path("robotont_description") + + model = LaunchConfiguration("model").perform(context).strip() + generation = LaunchConfiguration("generation").perform(context).strip() + + primary_in = LaunchConfiguration("primary_color").perform(context) + + if model: + robot_model_path = model + else: + if generation == "2.1": + robot_model_path = str(pkg / "urdf/gen2_1/robotont.urdf.xacro") + else: + # Default to gen3 + robot_model_path = str(pkg / "urdf/gen3/robotont.urdf.xacro") + + primary_rgba = _rgba_string_from_user_value(primary_in) + + robot_description = ParameterValue( + Command([ + "xacro ", robot_model_path, + ' main_color:="', primary_rgba, '"', + ]), + value_type=str, + ) + + rsp = Node( + package="robot_state_publisher", + executable="robot_state_publisher", + parameters=[{"robot_description": robot_description}], + ) + + jsp = Node( + package="joint_state_publisher", + executable="joint_state_publisher", + ) + + rviz = Node( + package="rviz2", + executable="rviz2", + name="rviz2", + output="screen", + arguments=[ + "-d", LaunchConfiguration("rviz_config"), + "--fixed-frame", LaunchConfiguration("rviz_fixed_frame"), + ], + ) + + return [jsp, rsp, rviz] + + +def generate_launch_description(): + pkg = get_package_share_path("robotont_description") + default_rviz_config_path = pkg / "config/robotont_description.rviz" + + return LaunchDescription([ + DeclareLaunchArgument("model", default_value=""), + DeclareLaunchArgument("rviz_config", default_value=str(default_rviz_config_path)), + DeclareLaunchArgument("rviz_fixed_frame", default_value="base_link"), + DeclareLaunchArgument("generation", default_value="3"), + + DeclareLaunchArgument("primary_color", default_value="0.16 0.65 0.98 1.0"), + + OpaqueFunction(function=_setup), + ]) diff --git a/launch/display_simulated_robot.launch.py b/launch/display_simulated_robot.launch.py deleted file mode 100644 index 11d7a54..0000000 --- a/launch/display_simulated_robot.launch.py +++ /dev/null @@ -1,65 +0,0 @@ -from ament_index_python.packages import get_package_share_path - -from launch import LaunchDescription -from launch.actions import DeclareLaunchArgument -from launch.substitutions import Command, LaunchConfiguration, PythonExpression -from launch_ros.actions import Node -from launch_ros.parameter_descriptions import ParameterValue - -def generate_launch_description(): - package = get_package_share_path('robotont_description') - default_rviz_config_path = package / 'config/robotont_description.rviz' - - model_decl = DeclareLaunchArgument(name='model', default_value='') - rviz_config_decl = DeclareLaunchArgument(name='rviz_config', default_value=str(default_rviz_config_path)) - rviz_fixed_frame_decl = DeclareLaunchArgument(name='rviz_fixed_frame', default_value='base_link') - generation_decl = DeclareLaunchArgument(name='generation', default_value='3') - - model_arg = LaunchConfiguration('model') - rviz_config_arg = LaunchConfiguration('rviz_config') - rviz_fixed_frame_arg = LaunchConfiguration('rviz_fixed_frame') - generation_arg = LaunchConfiguration('generation') - - robot_model_path = PythonExpression([ - '"" if "', model_arg, - '" else "', str(package / "urdf/"), '" + (', - '"/gen2_1/robotont.urdf.xacro" if "', generation_arg, '" == "2.1" else "/gen3/robotont.urdf.xacro")' - ]) - - robot_description = ParameterValue(Command(['xacro ', robot_model_path]), value_type=str) - - robot_state_publisher_node = Node( - package='robot_state_publisher', - executable='robot_state_publisher', - parameters=[{ 'robot_description': robot_description }] - ) - - joint_state_publisher_node = Node( - package='joint_state_publisher', - executable='joint_state_publisher' - ) - - rviz_node = Node( - package='rviz2', - executable='rviz2', - name='rviz2', - output='screen', - arguments=[ - '-d', - rviz_config_arg, - '--fixed-frame', - rviz_fixed_frame_arg - ] - ) - - return LaunchDescription( - [ - model_decl, - generation_decl, - rviz_config_decl, - rviz_fixed_frame_decl, - joint_state_publisher_node, - robot_state_publisher_node, - rviz_node - ] - ) diff --git a/meshes/gen3/encoder_button.STL b/meshes/gen3/encoder_button.STL new file mode 100644 index 0000000..dc1cb81 Binary files /dev/null and b/meshes/gen3/encoder_button.STL differ diff --git a/meshes/gen3/frame_module_pla.STL b/meshes/gen3/frame_module_pla.STL new file mode 100644 index 0000000..1bcae46 Binary files /dev/null and b/meshes/gen3/frame_module_pla.STL differ diff --git a/meshes/gen3/frame_module_spacers.STL b/meshes/gen3/frame_module_spacers.STL new file mode 100644 index 0000000..a812095 Binary files /dev/null and b/meshes/gen3/frame_module_spacers.STL differ diff --git a/meshes/gen3/motor_module2.STL b/meshes/gen3/motor_module2.STL new file mode 100644 index 0000000..1c029aa Binary files /dev/null and b/meshes/gen3/motor_module2.STL differ diff --git a/meshes/gen3/ssd1306.STL b/meshes/gen3/ssd1306.STL new file mode 100644 index 0000000..806a407 Binary files /dev/null and b/meshes/gen3/ssd1306.STL differ diff --git a/meshes/gen3/wheel_adapter_v05_one_bolt.STL b/meshes/gen3/wheel_adapter_v05_one_bolt.STL new file mode 100644 index 0000000..9e79390 Binary files /dev/null and b/meshes/gen3/wheel_adapter_v05_one_bolt.STL differ diff --git a/meshes/shared/2.75rim.STL b/meshes/shared/2.75rim.STL new file mode 100644 index 0000000..217f5ef Binary files /dev/null and b/meshes/shared/2.75rim.STL differ diff --git a/meshes/shared/2.75roller.STL b/meshes/shared/2.75roller.STL new file mode 100644 index 0000000..0674185 Binary files /dev/null and b/meshes/shared/2.75roller.STL differ diff --git a/urdf/gen3/base.urdf.xacro b/urdf/gen3/base.urdf.xacro index eea4155..65573f3 100644 --- a/urdf/gen3/base.urdf.xacro +++ b/urdf/gen3/base.urdf.xacro @@ -5,6 +5,7 @@ - + @@ -48,7 +49,25 @@ - + + + + + + + + + + + + + + + + + + + @@ -114,6 +133,28 @@ /> + + + + + + + + + + + + + + + + + + + @@ -135,5 +176,27 @@ rpy="${pi / 2} 0 ${pi / 2}" /> + + + + + + + + + + + + + + + + + + + diff --git a/urdf/gen3/motor.urdf.xacro b/urdf/gen3/motor.urdf.xacro index 19850a7..87f90e6 100644 --- a/urdf/gen3/motor.urdf.xacro +++ b/urdf/gen3/motor.urdf.xacro @@ -23,7 +23,7 @@ - + diff --git a/urdf/gen3/robotont.urdf.xacro b/urdf/gen3/robotont.urdf.xacro index 26f2d31..64ddd58 100644 --- a/urdf/gen3/robotont.urdf.xacro +++ b/urdf/gen3/robotont.urdf.xacro @@ -7,6 +7,9 @@ + + + @@ -16,6 +19,7 @@ + @@ -28,7 +32,8 @@ - + @@ -22,7 +22,7 @@ - + @@ -129,6 +129,26 @@ no_of_roller="6" prefix="${prefix}" /> + + + + diff --git a/urdf/shared/roller.urdf.xacro b/urdf/shared/roller.urdf.xacro index 3953d2c..f8bd66c 100644 --- a/urdf/shared/roller.urdf.xacro +++ b/urdf/shared/roller.urdf.xacro @@ -16,7 +16,7 @@ - + @@ -35,8 +35,8 @@