Files
moonshot_franka_description/scripts/create_urdf.py
2025-02-22 22:37:34 +09:00

192 lines
6.4 KiB
Python

# Copyright (c) 2024 Franka Robotics GmbH
#
# 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
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import os
import xacro
def str_to_bool(s):
return s.lower() in ["true", "1", "yes", "y"]
def convert_xacro_to_urdf(xacro_file, only_ee, with_sc, ee_id, hand, no_prefix, robot):
"""Convert xacro file into a URDF file."""
mappings = {
"with_sc": str(with_sc),
"ee_id": str(ee_id),
"hand": str(hand),
"no_prefix": str(no_prefix),
"arm_id": str(robot),
}
if only_ee and robot == "":
mappings["connection"] = ""
urdf = xacro.process_file(xacro_file, mappings=mappings)
urdf_file = urdf.toprettyxml(indent=" ")
return urdf_file
def convert_package_name_to_absolute_path(package_name, package_path, urdf_file):
"""Replace a ROS package names with the absolute paths."""
urdf_file = urdf_file.replace("package://{}".format(package_name), package_path)
return urdf_file
def urdf_generation(
package_path, xacro_file, file_name, ONLY_EE, WITH_SC, EE, HAND, NO_PREFIX, robot
):
"""Generate URDF file and save it."""
xacro_file = os.path.join(package_path, xacro_file)
urdf_file = convert_xacro_to_urdf(xacro_file, ONLY_EE, WITH_SC, EE, HAND, NO_PREFIX, robot)
if ABSOLUTE_PATHS and (HOST_DIR is None or HOST_DIR == ""):
urdf_file = convert_package_name_to_absolute_path(
package_name, package_path, urdf_file
)
elif ABSOLUTE_PATHS:
urdf_file = convert_package_name_to_absolute_path(
package_name, HOST_DIR, urdf_file
)
save_urdf_to_file(package_path, urdf_file, file_name)
def save_urdf_to_file(package_path, urdf_file, robot):
"""Save URDF into a file."""
# Check if the folder exists, and if not, create it
folder_path = f"{package_path}/urdfs"
if not os.path.exists(folder_path):
os.makedirs(folder_path)
with open(f"{package_path}/urdfs/{robot}.urdf", "w") as f:
f.write(urdf_file)
if __name__ == "__main__":
package_name = "franka_description"
if os.getcwd().split("/")[-1] != package_name:
print("Call the script from franka_description root folder")
exit()
ROBOTS = ["multi_arm", "fr3", "fp3", "fer"]
END_EFFECTORS = ["none", "franka_hand", "cobot_pump"]
parser = argparse.ArgumentParser(
description="""
Generate franka robots urdf models.
Script to be executed from franka_description root folder!
"""
)
robots_str = ", ".join([f"{item}" for item in ROBOTS])
parser.add_argument(
"robot_model",
type=str,
nargs='?',
default="",
help="id of the robot model (accepted values are: {})".format(robots_str),
)
parser.add_argument(
"--no-ee",
help="Disable loading of end-effector.",
action="store_const",
const=True,
)
ee_str = ", ".join([f"{item}" for item in END_EFFECTORS])
parser.add_argument(
"--robot-ee",
type=str,
default="franka_hand",
help="id of the robot end effector (accepted values are: {})".format(ee_str),
)
parser.add_argument(
"--with-sc",
help="Include self-collision volumes in the urdf model.",
action="store_const",
const=True,
)
parser.add_argument(
"--abs-path", help="Use absolute paths.", action="store_const", const=True
)
parser.add_argument(
"--host-dir", help="Provide a host directory for the absolute path."
)
parser.add_argument(
"--only-ee",
help="Get urdf with solely end-effector data.",
action="store_const",
const=True,
)
parser.add_argument(
"--no-prefix",
help="Override the robot prefix of links, joints and visuals in the urdf file.",
action="store_const",
const=True,
)
args = parser.parse_args()
ROBOT_MODEL = args.robot_model.lower()
HAND = not args.no_ee
EE = args.robot_ee.lower() if args.robot_ee is not None else "franka_hand"
WITH_SC = args.with_sc if args.with_sc is not None else False
ABSOLUTE_PATHS = args.abs_path if args.abs_path is not None else False
HOST_DIR = args.host_dir
ONLY_EE = args.only_ee if args.only_ee is not None else False
NO_PREFIX = args.no_prefix if args.no_prefix is not None else 'false'
assert ROBOT_MODEL in ROBOTS or ROBOT_MODEL == "all" or \
ROBOT_MODEL == "none" or ROBOT_MODEL == ""
if ROBOT_MODEL != "all" and ROBOT_MODEL != "none":
ROBOTS = [ROBOT_MODEL]
package_path = os.getcwd()
if ONLY_EE:
print(f"\n*** Creating URDF for {EE} ***")
xacro_file = f"end_effectors/{EE}/{EE}.urdf.xacro"
file_name = f"{EE}"
if ROBOT_MODEL == "all" or ROBOT_MODEL == "none" or ROBOT_MODEL == "":
robot_prefix = ""
else:
robot_prefix = ROBOT_MODEL
urdf_generation(
package_path, xacro_file, file_name, ONLY_EE, WITH_SC,
EE, HAND, NO_PREFIX, robot_prefix,
)
else:
if ROBOT_MODEL == "none" or ROBOT_MODEL == "":
print("\n*** Robot model must be specified ***")
else:
for robot in ROBOTS:
xacro_file = f"robots/{robot}/{robot}.urdf.xacro"
if HAND and EE != "none":
print(f"\n*** Creating URDF for {robot} and {EE} ***")
file_name = f"{robot}_{EE}"
else:
if not HAND:
print(
"\n*** WARNING: --no-ee argument will be removed in future releases, "
"introducing none as ee id***"
)
print(f"\n*** Creating URDF for {robot} ***")
file_name = f"{robot}"
urdf_generation(
package_path, xacro_file, file_name,
ONLY_EE, WITH_SC, EE, HAND, NO_PREFIX, robot,
)