Rhoban / onshape-to-robot

Converting OnShape assembly to robot definition (SDF or URDF) through OnShape API
MIT License
231 stars 49 forks source link

How to generate more joint types? #99

Open Bozenton opened 1 year ago

Bozenton commented 1 year ago

Hi there,

Thanks for your sharing of work!

As far as I know that there are many joint types in urdf, I wonder if there is a way to generate the 'continuous' or other types by your tool? Maybe I should do something in the config.json?

Hope for your reply.

atticusrussell commented 1 year ago

I agree that continuous joints would be great to integrate into onshape-to-robot by some mechanism like looking for the string "continuous" in the joint name, but I came up with a workaround for now:

I wrote a bash script that I used in the postImporCommands to change joints with the word "wheel" in them to continuous joints, among other things (moving and renaming meshes, formatting URDF, etc.).

moveMeshes.sh

 #!/bin/bash

robot_name="catbot"

# Source and destination directories
src_dir="./$robot_name"
dest_dir="../meshes"

# Create destination directory if it doesn't exist
mkdir -p "$dest_dir"

# Create subdirectories for "collision" and "visual" if they don't exist
mkdir -p "$dest_dir/collision"
mkdir -p "$dest_dir/visual"

# Find all STL files with "assm" in the name
find "$src_dir" -name '*assm*.stl' -print0 | while IFS= read -r -d '' file; do
    # Check if filename contains "collision" or "visual" and copy to corresponding subdirectory
    if [[ $file == *"collision"* ]]; then
        cp "$file" "$dest_dir/collision"
    elif [[ $file == *"visual"* ]]; then
        cp "$file" "$dest_dir/visual"
    else
        cp "$file" "$dest_dir"
    fi
done

# new name for urdf file
urdf_path="../urdf/$robot_name/"
urdf_suffix="_macro.xacro"
urdf_file="$robot_name$urdf_suffix"
urdf_file_path="$urdf_path$urdf_file"

# Copy robot.urdf to the appropriate subdirectory
mkdir -p "$urdf_path"
cp "$src_dir/robot.urdf" "$urdf_file_path"

# Change paths in copied URDF file to match new directory structure
sed -i 's#<mesh filename="package://\(.*\)/\(.*\)_visual.stl"/>#<mesh filename="package://\1/visual/\2_visual.stl"/>#' "$urdf_file_path"
sed -i 's#<mesh filename="package://\(.*\)/\(.*\)_collision.stl"/>#<mesh filename="package://\1/collision/\2_collision.stl"/>#' "$urdf_file_path"

# Replace "revolute" type joints with "continuous" in joints where the name contains "wheel"
sed -i '/<joint name=".*wheel.*" type="revolute">/s/revolute/continuous/' "$urdf_file_path"

# Replace the first line of the file with the specified content
sed -i '1c <?xml version="1.0" encoding="UTF-8"?>\n<robot xmlns:xacro="http://wiki.ros.org/xacro">\n\n  <xacro:macro name="catbot" params="prefix parent *origin">\n\n    <!-- base_joint fixes base_link to the environment -->\n\n    <joint name="${prefix}base_joint" type="fixed">\n      <xacro:insert_block name="origin" />\n      <parent link="${parent}" />\n      <child link="${prefix}base_link" />\n    </joint>' "$urdf_file_path"

# Remove the last three lines
head -n -3 "$urdf_file_path" > temp_file && mv temp_file "$urdf_file_path"

# Append the specified content to the end of the file
echo "  </xacro:macro>" >> "$urdf_file_path"
echo "</robot>" >> "$urdf_file_path"
echo "" >> "$urdf_file_path"

# format the URDF file
# indent
tidy -xml -i -quiet -o $urdf_file_path $urdf_file_path
# re-add  newlines
python3 urdf_newlines.py $urdf_file_path

urdf_newlines.py

 import argparse
import re

def format_urdf(input_file_name, output_file_name=None):
    """
    Take an input file and formats the file content.

    Adds a new line before each <link name> and <joint name> element.

    :param input_file_name: str, name of the input file
    :param output_file_name: str, name of the output file. If None,
    modifies the input file in place.
    """
    with open(input_file_name) as file:
        content = file.read()

    # Add a new line before each <link name> and <joint name> element using regex substitution
    formatted_content = re.sub(r'(\s*<link name)', r'\n\1', content)
    formatted_content = re.sub(r'(\s*<joint name)', r'\n\1', formatted_content)

    # If output_file_name is None, modify the input file in place
    if output_file_name is None:
        output_file_name = input_file_name

    with open(output_file_name, 'w') as file:
        file.write(formatted_content)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Process URDF files.')
    parser.add_argument('input_file', type=str, help='Input URDF file name')
    parser.add_argument('output_file', type=str, nargs='?', default=None,
                        help='Output URDF file name (optional)')

    args = parser.parse_args()

    format_urdf(args.input_file, args.output_file)

catbot/config.json

{
        "documentId": "495ae85c292c3ab6d645bdf9",
        "versionID": "dbc41dc96b1adb2ff43c4047",
        "outputFormat": "urdf",
        "addDummyBaseLink": "true",
        "packageName": "catbot_description/meshes",
        "mergeSTLs": "all",
        "assemblyName": "robot_assm",
        "robotName": "catbot",
        "postImportCommands": [
                "./moveMeshes.sh"
        ]
}