├── trac_ik_python
├── COLCON_IGNORE
├── src
│ └── trac_ik_python
│ │ ├── __init__.py
│ │ └── trac_ik.py
├── setup.py
├── package.xml
├── README.md
├── scripts
│ ├── test_pkg.py
│ └── test_wrapper.py
├── CMakeLists.txt
└── swig
│ └── trac_ik_wrap.i
├── trac_ik_kinematics_plugin
├── COLCON_IGNORE
├── trac_ik_kinematics_description.xml
├── package.xml
├── CMakeLists.txt
├── README.md
├── include
│ └── trac_ik
│ │ └── trac_ik_kinematics_plugin.hpp
└── src
│ └── trac_ik_kinematics_plugin.cpp
├── .gitignore
├── trac_ik
├── CMakeLists.txt
└── package.xml
├── trac_ik_examples
├── README.md
├── package.xml
├── CMakeLists.txt
├── launch
│ └── pr2_arm.launch.py
└── src
│ └── ik_tests.cpp
├── .github
├── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
└── workflows
│ └── trac_ik_ci.yml
├── README.md
├── trac_ik_lib
├── package.xml
├── include
│ └── trac_ik
│ │ ├── visibility_control.hpp
│ │ ├── nlopt_ik.hpp
│ │ ├── kdl_tl.hpp
│ │ ├── trac_ik.hpp
│ │ ├── dual_quaternion.h
│ │ └── math3d.h
├── CMakeLists.txt
├── README.md
└── src
│ ├── kdl_tl.cpp
│ ├── trac_ik.cpp
│ └── nlopt_ik.cpp
└── LICENSE.txt
/trac_ik_python/COLCON_IGNORE:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/trac_ik_kinematics_plugin/COLCON_IGNORE:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/trac_ik_python/src/trac_ik_python/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | trac_ik_python/src/trac_ik_python/trac_ik.pyc
--------------------------------------------------------------------------------
/trac_ik/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.5)
2 | project(trac_ik)
3 |
4 | find_package(ament_cmake REQUIRED)
5 | ament_package()
6 |
--------------------------------------------------------------------------------
/trac_ik_python/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from distutils.core import setup
4 | from catkin_pkg.python_setup import generate_distutils_setup
5 |
6 | d = generate_distutils_setup(
7 | packages=['trac_ik_python'],
8 | package_dir={'': 'src'}
9 | )
10 |
11 | setup(**d)
12 |
--------------------------------------------------------------------------------
/trac_ik_examples/README.md:
--------------------------------------------------------------------------------
1 | ## trac_ik_examples
2 |
3 | This package provides examples programs to use the standalone TRAC-IK solver and related code.
4 |
5 | Currently, there only exists an `ik_tests` program that compares KDL's Pseudoinverse Jacobian IK solver with TRAC-IK.
6 | The [`pr2_arm.launch.py`](./pr2_arm.launch.py) files runs this test on the default PR2 robot's 7-DOF right arm chain.
7 |
--------------------------------------------------------------------------------
/trac_ik_kinematics_plugin/trac_ik_kinematics_description.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | A implementation of kinematics as a plugin based on TRAC-IK.
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: aprotyas
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Implementation considerations**
20 | Please share - if possible - relevant information on how the feature could be implemented and pros and cons of the different solutions.
21 |
22 | **Additional context**
23 | Add any other context or screenshots about the feature request here.
24 |
--------------------------------------------------------------------------------
/trac_ik/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | trac_ik
4 | 0.1.0
5 |
6 | The ROS packages in this repository have been forked from TRACLABS' source
7 | tree, to provide - in ROS 2 - an improved alternative Inverse Kinematics
8 | solver to the popular inverse Jacobian methods in KDL
9 |
10 | Abrar Rahman Protyasha
11 | Patrick Beeson
12 | Barrett Ames
13 | BSD
14 |
15 | https://github.com/aprotyas/trac_ik
16 |
17 | ament_cmake
18 |
19 | trac_ik_examples
20 | trac_ik_kinematics_plugin
21 | trac_ik_lib
22 | trac_ik_python
23 |
24 |
25 | ament_cmake
26 |
27 |
28 |
--------------------------------------------------------------------------------
/trac_ik_examples/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | trac_ik_examples
4 | 0.1.0
5 | This package contains the source code for testing and comparing trac_ik
6 | Abrar Rahman Protyasha
7 | Patrick Beeson
8 | BSD
9 |
10 | ament_cmake
11 |
12 | libnlopt-cxx-dev
13 | orocos_kdl
14 | rclcpp
15 | trac_ik_lib
16 |
17 | libnlopt0
18 | libnlopt-cxx-dev
19 | orocos_kdl
20 | rclcpp
21 | trac_ik_lib
22 |
23 | ament_lint_auto
24 | ament_lint_common
25 |
26 |
27 | ament_cmake
28 |
29 |
30 |
--------------------------------------------------------------------------------
/trac_ik_python/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | trac_ik_python
4 | 1.6.6
5 | The trac_ik_python package contains a python wrapper using SWIG
6 | for trac_ik_lib
7 | Abrar Rahman Protyasha
8 | Sam Pfeiffer
9 | BSD
10 |
11 | catkin
12 |
13 | rospy
14 | swig
15 | trac_ik_lib
16 | tf_conversions
17 | libnlopt-dev
18 | libnlopt-cxx-dev
19 |
20 | rospy
21 | swig
22 | trac_ik_lib
23 | tf_conversions
24 | tf
25 | libnlopt-dev
26 | libnlopt0
27 |
28 |
29 |
--------------------------------------------------------------------------------
/trac_ik_kinematics_plugin/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | trac_ik_kinematics_plugin
4 | 1.6.6
5 | A MoveIt! Kinematics plugin using TRAC-IK
6 | Abrar Rahman Protyasha
7 | Patrick Beeson
8 | BSD
9 |
10 | catkin
11 |
12 | moveit_core
13 | pluginlib
14 | roscpp
15 | tf_conversions
16 | trac_ik_lib
17 | libnlopt-dev
18 | libnlopt-cxx-dev
19 |
20 | moveit_core
21 | pluginlib
22 | roscpp
23 | tf_conversions
24 | trac_ik_lib
25 | libnlopt-dev
26 | libnlopt0
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create an issue highlighting a bug
4 | title: ''
5 | labels: bug
6 | assignees: aprotyas
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **Required Info:**
14 | - Package:
15 | -
16 | - Operating System:
17 | -
18 | - Installation type:
19 | -
20 | - Version or commit hash:
21 | -
22 | - DDS implementation (if applicable):
23 | -
24 | - ROS 2 library (if applicable):
25 | -
26 |
27 | **To Reproduce**
28 | Steps to reproduce the behavior:
29 | 1. Go to '...'
30 | 2. Click on '....'
31 | 3. Scroll down to '....'
32 | 4. See error
33 |
34 | **Expected behavior**
35 | A clear and concise description of what you expected to happen.
36 |
37 | **Actual behavior**
38 | A clear and concise description of what has actually been observed.
39 |
40 | **Additional context**
41 | Add any other context about the problem here.
42 |
--------------------------------------------------------------------------------
/.github/workflows/trac_ik_ci.yml:
--------------------------------------------------------------------------------
1 | name: trac_ik CI
2 |
3 | on:
4 | pull_request:
5 | paths-ignore: ['**.md']
6 | push:
7 | branches:
8 | - ros2
9 | paths-ignore: ['**.md']
10 | schedule:
11 | # Triggers the workflow at 00:00 UTC every day
12 | - cron: '0 0 * * *'
13 |
14 | jobs:
15 | trac_ik-CI:
16 | runs-on: ${{ matrix.os }}
17 | strategy:
18 | fail-fast: false
19 | matrix:
20 | os: [ubuntu-20.04]
21 | ros_distribution: [foxy, galactic, rolling]
22 | steps:
23 | - uses: actions/checkout@v2.3.4
24 |
25 | - name: Setup ROS2
26 | uses: ros-tooling/setup-ros@v0.2
27 | with:
28 | use-ros2-testing: true
29 | required-ros-distributions: ${{ matrix.ros_distribution }}
30 |
31 | - name: Build and test trac_ik
32 | uses: ros-tooling/action-ros-ci@v0.2
33 | id: action_ros_ci
34 | with:
35 | package-name: |
36 | trac_ik
37 | trac_ik_examples
38 | trac_ik_lib
39 | target-ros2-distro: ${{ matrix.ros_distribution }}
40 |
41 | - name: Upload Logs
42 | uses: actions/upload-artifact@v2
43 | with:
44 | name: colcon_logs
45 | path: ${{ steps.action_ros_ci.outputs.ros-workspace-directory-name }}/log
46 | if: always()
47 |
--------------------------------------------------------------------------------
/trac_ik_kinematics_plugin/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(trac_ik_kinematics_plugin)
3 |
4 | if(CMAKE_COMPILER_IS_GNUCXX OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang"))
5 | set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")
6 | endif()
7 |
8 | find_package(PkgConfig REQUIRED)
9 | pkg_check_modules(pkg_nlopt REQUIRED nlopt)
10 |
11 | find_package(catkin REQUIRED
12 | COMPONENTS
13 | moveit_core
14 | pluginlib
15 | roscpp
16 | tf_conversions
17 | trac_ik_lib
18 | )
19 |
20 | include_directories(
21 | include
22 | ${catkin_INCLUDE_DIRS}
23 | ${pkg_nlopt_INCLUDE_DIRS}
24 | )
25 |
26 | catkin_package(
27 | INCLUDE_DIRS
28 | include
29 | CATKIN_DEPENDS
30 | moveit_core
31 | pluginlib
32 | roscpp
33 | tf_conversions
34 | trac_ik_lib
35 | )
36 |
37 | set(TRAC_IK_LIBRARY_NAME trac_ik_kinematics_plugin)
38 |
39 | add_library(${TRAC_IK_LIBRARY_NAME} src/trac_ik_kinematics_plugin.cpp)
40 | target_link_libraries(${TRAC_IK_LIBRARY_NAME} ${catkin_LIBRARIES} ${pkg_nlopt_LIBRARIES})
41 |
42 | install(DIRECTORY include/
43 | DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION}
44 | )
45 |
46 | install(TARGETS ${TRAC_IK_LIBRARY_NAME}
47 | LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION})
48 |
49 | install(
50 | FILES
51 | trac_ik_kinematics_description.xml
52 | DESTINATION
53 | ${CATKIN_PACKAGE_SHARE_DESTINATION}
54 | )
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # trac_ik
2 |
3 | ROS 2 port of `trac_ik`, an alternative Inverse Kinematics solver to the popular inverse Jacobian methods in KDL.
4 |
5 | This repo contains 5 ROS 2 pacakges:
6 | - [`trac_ik`](https://github.com/aprotyas/trac_ik/tree/ros2/trac_ik): A "metapackage" for the examples, C++/Python libraries, and the MoveIt! plugin.
7 | - [`trac_ik_examples`](https://github.com/aprotyas/trac_ik/tree/ros2/trac_ik_examples): Contains an example on how to use the standalone TRAC-IK C++ library.
8 | - [`trac_ik_lib`](https://github.com/aprotyas/trac_ik/tree/ros2/trac_ik_lib): The TRAC-IK kinematics code, builds a .so library that can be used as a drop in replacement for KDL's IK functions for KDL chains.
9 | Details for use are in [`trac_ik_lib/README.md`](https://github.com/aprotyas/trac_ik/tree/ros2/trac_ik_lib/README.md).
10 | - [`trac_ik_kinematics_plugin`](https://github.com/aprotyas/trac_ik/tree/ros2/trac_ik_kinematics_plugin): Provides a MoveIt! plugin that can replace the default KDL plugin for MoveIt! with TRAC-IK for use in planning.
11 | Details for use are in [`trac_ik_kinematics_plugin/README.md`](https://github.com/aprotyas/trac_ik/tree/ros2/trac_ik_kinematics_plugin/README.md).
12 | - [`trac_ik_python`](https://github.com/aprotyas/trac_ik/tree/ros2/trac_ik_python): SWIG based Python wrapper to use TRAC-IK.
13 | Details for use are in [`trac_ik_python/README.md`](https://github.com/aprotyas/trac_ik/tree/ros2/trac_ik_python/README.md).
14 |
15 | Link to the original repository: https://bitbucket.org/traclabs/trac_ik/src/master/
16 |
--------------------------------------------------------------------------------
/trac_ik_lib/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | trac_ik_lib
4 | 0.1.0
5 |
6 | TRAC-IK is a faster, significantly more reliable drop-in replacement for
7 | KDL's pseudoinverse Jacobian solver.
8 |
9 | The TRAC-IK library has a very similar API to KDL's IK solver calls,
10 | except that the user passes a maximum time instead of a maximum number of
11 | search iterations. Additionally, TRAC-IK allows for error tolerances to
12 | be set independently for each Cartesian dimension (x,y,z,roll,pitch.yaw).
13 |
14 | Abrar Rahman Protyasha
15 | Patrick Beeson
16 | Barrett Ames
17 |
18 | BSD
19 |
20 | ament_cmake
21 | eigen3_cmake_module
22 |
23 | eigen
24 | kdl_parser
25 | libnlopt-cxx-dev
26 | rclcpp
27 | urdf
28 |
29 | kdl_parser
30 | libnlopt0
31 | libnlopt-cxx-dev
32 | rclcpp
33 | urdf
34 |
35 | ament_lint_auto
36 | ament_lint_common
37 |
38 |
39 | ament_cmake
40 |
41 |
42 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2008-2021, TRACLabs, Inc.
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/trac_ik_examples/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.12)
2 | project(trac_ik_examples)
3 |
4 | # Default to C99
5 | if(NOT CMAKE_C_STANDARD)
6 | set(CMAKE_C_STANDARD 99)
7 | endif()
8 |
9 | # Default to C++17
10 | if(NOT CMAKE_CXX_STANDARD)
11 | set(CMAKE_CXX_STANDARD 17)
12 | endif()
13 |
14 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
15 | add_compile_options(-Wall -Wextra -Wpedantic -Wshadow -Werror)
16 | endif()
17 |
18 | find_package(ament_cmake REQUIRED)
19 | find_package(NLopt REQUIRED)
20 | find_package(rclcpp REQUIRED)
21 | find_package(orocos_kdl REQUIRED)
22 | find_package(trac_ik_lib REQUIRED)
23 |
24 | add_executable(ik_tests src/ik_tests.cpp)
25 |
26 | # C++20 standard guarantees `std::chrono::system_clock` measures Unix Time
27 | # i.e. `std::chrono::{duration, time_point}` can then replace
28 | # `boost::posix_time::{time_duration, ptime}`
29 | set_target_properties(ik_tests PROPERTIES
30 | CXX_STANDARD 20
31 | CXX_STANDARD_REQUIRED YES
32 | CXX_EXTENSIONS NO
33 | )
34 |
35 | target_include_directories(ik_tests PUBLIC
36 | ${NLOPT_INCLUDE_DIRS}
37 | )
38 |
39 | # Needed since NLopt is not an ament package
40 | target_link_libraries(ik_tests
41 | ${NLOPT_LIBRARIES}
42 | )
43 |
44 | ament_target_dependencies(ik_tests
45 | ament_cmake
46 | rclcpp
47 | orocos_kdl
48 | trac_ik_lib
49 | )
50 |
51 | install(TARGETS ik_tests
52 | ARCHIVE DESTINATION lib
53 | LIBRARY DESTINATION lib
54 | RUNTIME DESTINATION lib/${PROJECT_NAME}
55 | )
56 |
57 | install(DIRECTORY launch
58 | DESTINATION share/${PROJECT_NAME}
59 | )
60 |
61 | if(BUILD_TESTING)
62 | find_package(ament_lint_auto REQUIRED)
63 | ament_lint_auto_find_test_dependencies()
64 | endif()
65 |
66 | ament_package()
67 |
--------------------------------------------------------------------------------
/trac_ik_lib/include/trac_ik/visibility_control.hpp:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Abrar Rahman Protyasha
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 |
16 | #ifndef TRAC_IK__VISIBILITY_CONTROL_HPP_
17 | #define TRAC_IK__VISIBILITY_CONTROL_HPP_
18 |
19 | // This logic was borrowed (then namespaced) from the examples on the gcc wiki:
20 | // https://gcc.gnu.org/wiki/Visibility
21 |
22 | #if defined _WIN32 || defined __CYGWIN__
23 | #ifdef __GNUC__
24 | #define TRAC_IK_EXPORT __attribute__ ((dllexport))
25 | #define TRAC_IK_IMPORT __attribute__ ((dllimport))
26 | #else
27 | #define TRAC_IK_EXPORT __declspec(dllexport)
28 | #define TRAC_IK_IMPORT __declspec(dllimport)
29 | #endif
30 | #ifdef TRAC_IK_BUILDING_LIBRARY
31 | #define TRAC_IK_PUBLIC TRAC_IK_EXPORT
32 | #else
33 | #define TRAC_IK_PUBLIC TRAC_IK_IMPORT
34 | #endif
35 | #define TRAC_IK_PUBLIC_TYPE TRAC_IK_PUBLIC
36 | #define TRAC_IK_LOCAL
37 | #else
38 | #define TRAC_IK_EXPORT __attribute__ ((visibility("default")))
39 | #define TRAC_IK_IMPORT
40 | #if __GNUC__ >= 4
41 | #define TRAC_IK_PUBLIC __attribute__ ((visibility("default")))
42 | #define TRAC_IK_LOCAL __attribute__ ((visibility("hidden")))
43 | #else
44 | #define TRAC_IK_PUBLIC
45 | #define TRAC_IK_LOCAL
46 | #endif
47 | #define TRAC_IK_PUBLIC_TYPE
48 | #endif
49 |
50 | #endif // TRAC_IK__VISIBILITY_CONTROL_HPP_
51 |
--------------------------------------------------------------------------------
/trac_ik_lib/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.12)
2 | project(trac_ik_lib)
3 |
4 | # Default to C99
5 | if(NOT CMAKE_C_STANDARD)
6 | set(CMAKE_C_STANDARD 99)
7 | endif()
8 |
9 | # Default to C++17
10 | if(NOT CMAKE_CXX_STANDARD)
11 | set(CMAKE_CXX_STANDARD 17)
12 | endif()
13 |
14 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
15 | add_compile_options(-Wall -Wextra -Wpedantic -Wshadow -Werror)
16 | endif()
17 |
18 | find_package(ament_cmake REQUIRED)
19 | find_package(eigen3_cmake_module REQUIRED)
20 | find_package(Eigen3 REQUIRED)
21 | find_package(kdl_parser REQUIRED)
22 | find_package(NLopt REQUIRED)
23 | find_package(rclcpp REQUIRED)
24 | find_package(urdf REQUIRED)
25 |
26 | add_library(${PROJECT_NAME} SHARED
27 | src/kdl_tl.cpp
28 | src/nlopt_ik.cpp
29 | src/trac_ik.cpp)
30 |
31 | # C++20 standard guarantees `std::chrono::system_clock` measures Unix Time
32 | # i.e. `std::chrono::{duration, time_point}` can then replace
33 | # `boost::posix_time::{time_duration, ptime}`
34 | set_target_properties(${PROJECT_NAME} PROPERTIES
35 | CXX_STANDARD 20
36 | CXX_STANDARD_REQUIRED YES
37 | CXX_EXTENSIONS NO
38 | )
39 |
40 | target_include_directories(${PROJECT_NAME} PUBLIC
41 | $
42 | $
43 | ${NLOPT_INCLUDE_DIRS}
44 | )
45 |
46 | target_compile_definitions(${PROJECT_NAME} PRIVATE "TRAC_IK_BUILDING_LIBRARY")
47 |
48 | # Needed since NLopt is not an ament package
49 | target_link_libraries(${PROJECT_NAME}
50 | ${NLOPT_LIBRARIES}
51 | )
52 |
53 | ament_target_dependencies(${PROJECT_NAME}
54 | ament_cmake
55 | Eigen3
56 | kdl_parser
57 | rclcpp
58 | urdf
59 | )
60 |
61 | ament_export_targets(export_${PROJECT_NAME} HAS_LIBRARY_TARGET)
62 |
63 | ament_export_dependencies(
64 | ament_cmake
65 | kdl_parser
66 | NLopt
67 | rclcpp
68 | urdf
69 | )
70 |
71 | install(DIRECTORY include/
72 | DESTINATION include
73 | )
74 |
75 | install(TARGETS ${PROJECT_NAME}
76 | EXPORT export_${PROJECT_NAME}
77 | ARCHIVE DESTINATION lib
78 | LIBRARY DESTINATION lib
79 | RUNTIME DESTINATION lib/${PROJECT_NAME})
80 |
81 | if(BUILD_TESTING)
82 | find_package(ament_lint_auto REQUIRED)
83 | list(APPEND AMENT_LINT_AUTO_EXCLUDE
84 | ament_cmake_cppcheck
85 | ament_cmake_uncrustify
86 | )
87 |
88 | ament_lint_auto_find_test_dependencies()
89 |
90 | # Else there are erroneous results for `.h` headers
91 | ament_cppcheck(LANGUAGE "c++")
92 | ament_uncrustify(LANGUAGE "C++")
93 | endif()
94 |
95 | ament_package()
96 |
--------------------------------------------------------------------------------
/trac_ik_examples/launch/pr2_arm.launch.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 Abrar Rahman Protyasha
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import os
16 |
17 | from launch import LaunchDescription
18 | from launch.actions import DeclareLaunchArgument
19 | from launch.substitutions import LaunchConfiguration
20 | from launch_ros.actions import Node
21 | from launch_ros.substitutions import FindPackageShare
22 |
23 |
24 | def generate_launch_description():
25 | num_samples = LaunchConfiguration('num_samples')
26 | chain_start = LaunchConfiguration('chain_start')
27 | chain_end = LaunchConfiguration('chain_end')
28 | timeout = LaunchConfiguration('timeout')
29 |
30 | pkg_share = FindPackageShare('trac_ik_examples').find('trac_ik_examples')
31 | urdf_file = os.path.join(pkg_share, 'launch', 'pr2.urdf')
32 | with open(urdf_file, 'r') as infp:
33 | robot_desc = infp.read()
34 |
35 | return LaunchDescription(
36 | [
37 | DeclareLaunchArgument('num_samples', default_value='1000'),
38 | DeclareLaunchArgument('chain_start', default_value='torso_lift_link'),
39 | DeclareLaunchArgument('chain_end', default_value='r_wrist_roll_link'),
40 | DeclareLaunchArgument('timeout', default_value='0.005'),
41 | Node(
42 | package='trac_ik_examples',
43 | executable='ik_tests',
44 | output='screen',
45 | parameters=[
46 | {
47 | 'robot_description': robot_desc,
48 | 'num_samples': num_samples,
49 | 'chain_start': chain_start,
50 | 'chain_end': chain_end,
51 | 'timeout': timeout,
52 | }
53 | ],
54 | ),
55 | ]
56 | )
57 |
58 |
59 | """
60 | Alternative ways to obtain the robot description:
61 |
62 | 1. Using `xacro` with command substitution:
63 | xacro_file = os.path.join(urdf_dir, 'test.urdf.xacro')
64 | robot_desc = launch.substitutions.Command(f'xacro {xacro_file}')
65 |
66 | 2. Using `xacro` API:
67 | xacro_file = os.path.join(urdf_dir, 'test.urdf.xacro')
68 | robot_desc = xacro.process_file(xacro_file).toprettyxml(indent=' ')
69 |
70 | 3. Using `xacro` with `subprocess` utils:
71 | xacro_file = os.path.join(urdf_dir, 'test.urdf.xacro')
72 | p = subprocess.Popen(['xacro', xacro_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
73 | robot_desc, stderr = p.communicate()
74 | """
75 |
--------------------------------------------------------------------------------
/trac_ik_kinematics_plugin/README.md:
--------------------------------------------------------------------------------
1 | This package provides is a MoveIt! kinematics plugin that replaces the KDL IK
2 | solver with the TRAC-IK solver. Currently mimic joints are *not* supported.
3 |
4 | ###As of v1.4.3, this package is part of the ROS Indigo/Jade binaries: `sudo apt-get install ros-jade-trac-ik-kinematics-plugin`
5 |
6 | To use:
7 |
8 | - Add this package and trac_ik_lib package to your catkin workspace.
9 | - Find the MoveIt! [kinematics.yaml](http://docs.ros.org/indigo/api/pr2_moveit_tutorials/html/kinematics/src/doc/kinematics_configuration.html) file created for your robot.
10 | - Replace
11 | ```kinematics_solver: kdl_kinematics_plugin/KDLKinematicsPlugin```
12 | (or similar) with
13 | ```kinematics_solver: trac_ik_kinematics_plugin/TRAC_IKKinematicsPlugin```
14 | - Set parameters as desired:
15 | - _kinematics\_solver\_timeout_ (timeout in seconds, e.g., 0.005) and _position\_only\_ik_ **ARE** supported.
16 | - _solve\_type_ can be Speed, Distance, Manipulation1, Manipulation2 (see trac\_ik\_lib documentation for details). Default is Speed.
17 | - _kinematics\_solver\_attempts_ parameter is unneeded: unlike KDL, TRAC-IK solver already restarts when it gets stuck
18 | - _kinematics\_solver\_search\_resolution_ is not applicable here.
19 | - Note: The Cartesian error distance used to determine a valid solution is _1e-5_, as that is what is hard-coded into MoveIt's KDL plugin.
20 |
21 |
22 | ###NOTE: My understanding of how MoveIt! works from user experience and looking at the source code (though I am NOT a MoveIt! developer):
23 |
24 | For normal operations, MoveIt! only really calls an IK solver for one pose
25 | (maybe multiple times if the first result is invalid due to self collisions or
26 | the like). This IK solution provides a joint configuration for the
27 | goal. MoveIt! already knows the _current_ joint configuration from encoder
28 | info. All planning at that point is done in _JOINT SPACE_. Collision
29 | detection and constraint checking may use Forward Kinematics to determine the
30 | pose of any subgoal joint configuration, but the planning _IS NOT_ being done
31 | in Cartesian space. After a joint trajectory is found, MoveIt! tries to smooth
32 | the trajectory to make it less "crazy looking", but this does not always
33 | result in a path that is pleasing to human users.
34 |
35 | If you don't have obstacles in your space, you may want to try the Cartesian
36 | planning API in MoveIt! to get "straight-line" motion. MoveIt's Cartesian
37 | planner _IS_ "planning" in Cartesian space (doing lots of IK calls). Though
38 | really it is just performing linear interpolation in x,y,z,roll,pitch,yaw
39 | between the current and desired poses -- it isn't really "searching" for a
40 | solution. That is, MoveIt's Cartesian capability is not doing collision
41 | avoidance or replanning -- if a collision is detected, the linear
42 | interpolation "planning" immediately stops. Unfortunately, in MoveIt! this
43 | scenario still returns _True_ that a trajectory was found. This is not ideal,
44 | and needs to be fixed -- I may write a new Cartesian capability plugin for
45 | MoveIt! that addresses this, but that would be outside the scope of Inverse
46 | Kinematics.
47 |
--------------------------------------------------------------------------------
/trac_ik_lib/include/trac_ik/nlopt_ik.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015, TRACLabs, Inc.
2 | //
3 | // Redistribution and use in source and binary forms, with or without
4 | // modification, are permitted provided that the following conditions are met:
5 | //
6 | // * Redistributions of source code must retain the above copyright
7 | // notice, this list of conditions and the following disclaimer.
8 | //
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // * Neither the name of the {copyright_holder} nor the names of its
14 | // contributors may be used to endorse or promote products derived from
15 | // this software without specific prior written permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | // POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
30 | #ifndef TRAC_IK__NLOPT_IK_HPP_
31 | #define TRAC_IK__NLOPT_IK_HPP_
32 |
33 | #include
34 | #include
35 |
36 | #include "nlopt.hpp"
37 | #include "trac_ik/kdl_tl.hpp"
38 |
39 |
40 | namespace NLOPT_IK
41 | {
42 |
43 | enum OptType { Joint, DualQuat, SumSq, L2 };
44 |
45 |
46 | class NLOPT_IK
47 | {
48 | friend class TRAC_IK::TRAC_IK;
49 |
50 | public:
51 | NLOPT_IK(
52 | const KDL::Chain & chain, const KDL::JntArray & q_min, const KDL::JntArray & q_max,
53 | double maxtime = 0.005, double eps = 1e-3, OptType type = SumSq);
54 |
55 | ~NLOPT_IK() {}
56 | int CartToJnt(
57 | const KDL::JntArray & q_init, const KDL::Frame & p_in, KDL::JntArray & q_out,
58 | const KDL::Twist bounds = KDL::Twist::Zero(),
59 | const KDL::JntArray & q_desired = KDL::JntArray());
60 |
61 | double minJoints(const std::vector & x, std::vector & grad);
62 | // void cartFourPointError(const std::vector& x, double error[]);
63 | void cartSumSquaredError(const std::vector & x, double error[]);
64 | void cartDQError(const std::vector & x, double error[]);
65 | void cartL2NormError(const std::vector & x, double error[]);
66 |
67 | inline void setMaxtime(double t)
68 | {
69 | maxtime = std::chrono::duration(t);
70 | }
71 |
72 | private:
73 | inline void abort()
74 | {
75 | aborted = true;
76 | }
77 |
78 | inline void reset()
79 | {
80 | aborted = false;
81 | }
82 |
83 |
84 | std::vector lb;
85 | std::vector ub;
86 |
87 | const KDL::Chain chain;
88 | std::vector des;
89 |
90 |
91 | KDL::ChainFkSolverPos_recursive fksolver;
92 |
93 | std::chrono::duration maxtime;
94 | double eps;
95 | int iter_counter;
96 | OptType TYPE;
97 |
98 | KDL::Frame targetPose;
99 | KDL::Frame z_up;
100 | KDL::Frame x_out;
101 | KDL::Frame y_out;
102 | KDL::Frame z_target;
103 | KDL::Frame x_target;
104 | KDL::Frame y_target;
105 |
106 | std::vector types;
107 |
108 | nlopt::opt opt;
109 |
110 | KDL::Frame currentPose;
111 |
112 | std::vector best_x;
113 | int progress;
114 | bool aborted;
115 |
116 | KDL::Twist bounds;
117 |
118 | inline static double fRand(double min, double max)
119 | {
120 | double f = static_cast(rand()) / RAND_MAX; // NOLINT
121 | return min + f * (max - min);
122 | }
123 | };
124 |
125 | } // namespace NLOPT_IK
126 |
127 | #endif // TRAC_IK__NLOPT_IK_HPP_
128 |
--------------------------------------------------------------------------------
/trac_ik_lib/README.md:
--------------------------------------------------------------------------------
1 | ## trac_ik_lib
2 |
3 | ### API change (WIP)
4 |
5 | Previously, the `TracIK` class could be constructed with a `std::string URDF_param="/robot_description"` argument.
6 | This `URDF_param` argument contained the name of the parameter which housed the robot description URDF string in the global parameter server.
7 | Since ROS 2 does not have "global" parameters, I've decided that the onus of obtaining a robot description XML falls on the `TracIK` callee.
8 | More specifically, this is the new constructor that can ingest a URDF:
9 |
10 | ```c++
11 | TRAC_IK::TRAC_IK ik_solver(
12 | string base_link,
13 | string tip_link,
14 | string urdf_param=std::string(),
15 | double timeout_in_secs=0.005,
16 | double error=1e-5,
17 | TRAC_IK::SolveType type=TRAC_IK::Speed);
18 | ```
19 |
20 | And here is a diff of the change:
21 |
22 | ```diff
23 | < string URDF_param="/robot_description",
24 | ---
25 | > string urdf_param=std::string(),
26 | ```
27 |
28 | **This entails that `urdf_param` is now the entire URDF XML file** (as a string, of course).
29 | Ways to obtain `urdf_param`:
30 | - Subscribing to the `robot_description` topic if there is a `robot_state_publisher` instance in the ROS graph.
31 | - Progammatically read a URDF XML file.
32 | - Have the XML string saved in a parameter for the callee node through a launch script (and `xacro`, if desired...).
33 |
34 | ### Usage
35 |
36 | The TRAC-IK kinematics solver is built in `trac_ik_lib` as a .so library.
37 | The headers and shared objects in this package can be linked against by user programs.
38 |
39 | This requires the Ubuntu packages for NLOpt Libraries to be installed.
40 | This can be done by running `sudo apt-get install libnlopt-dev` on the standard Ubuntu distros.
41 | Alternatively, you can run `rosdep update && rosdep install trac_ik_lib`.
42 |
43 | KDL IK:
44 |
45 | ```c++
46 | KDL::ChainFkSolverPos_recursive fk_solver(chain);
47 | KDL::ChainIkSolverVel_pinv vik_solver(chain);
48 | KDL::ChainJntToJacSolver jac_solver(chain);
49 |
50 | KDL::ChainIkSolverPos_NR_JL ik_solver(
51 | KDL::Chain chain,
52 | KDL::JntArray lower_joint_limits,
53 | KDL::JntArray upper_joint_limits,
54 | fk_solver, vik_solver,
55 | int num_iterations,
56 | double error);
57 |
58 | int rc =
59 | ik_solver.CartToJnt(
60 | KDL::JntArray joint_seed,
61 | KDL::Frame desired_end_effector_pose,
62 | KDL::JntArray& return_joints);
63 |
64 | // NOTE: CartToJnt succeeded if rc >=0
65 | //
66 | // NOTE: to use a timeout in seconds (e.g., 0.005), the iterations can be set to 1, and this can be called in a loop with your own timer.
67 | //
68 | // NOTE: error == 1e-5 is acceptable for most purposes
69 | ```
70 |
71 | TRAC-IK:
72 |
73 | ```c++
74 | #include
75 |
76 | TRAC_IK::TRAC_IK ik_solver(
77 | KDL::Chain chain,
78 | KDL::JntArray lower_joint_limits,
79 | KDL::JntArray upper_joint_limits,
80 | double timeout_in_secs=0.005,
81 | double error=1e-5,
82 | TRAC_IK::SolveType type=TRAC_IK::Speed);
83 |
84 | // OR
85 |
86 | TRAC_IK::TRAC_IK ik_solver(
87 | string base_link,
88 | string tip_link,
89 | string urdf_param=std::string(),
90 | double timeout_in_secs=0.005,
91 | double error=1e-5,
92 | TRAC_IK::SolveType type=TRAC_IK::Speed);
93 |
94 | // NOTE: The last arguments to the constructors are optional.
95 | // The type can be one of the following:
96 | // Speed: returns very quickly the first solution found
97 | // Distance: runs for the full timeout_in_secs, then returns the solution that minimizes SSE from the seed
98 | // Manip1: runs for full timeout, returns solution that maximizes sqrt(det(J*J^T)) (the product of the singular values of the Jacobian)
99 | // Manip2: runs for full timeout, returns solution that minimizes the ratio of min to max singular values of the Jacobian.
100 |
101 | int rc =
102 | ik_solver.CartToJnt(
103 | KDL::JntArray joint_seed,
104 | KDL::Frame desired_end_effector_pose,
105 | KDL::JntArray& return_joints,
106 | KDL::Twist tolerances);
107 |
108 | // NOTE: CartToJnt succeeded if rc >=0
109 |
110 | // NOTE: tolerances on the end effector pose are optional, and if not
111 | // provided, then by default are 0. If given, the ABS() of the
112 | // values will be used to set tolerances at -tol..0..+tol for each of
113 | // the 6 Cartesian dimensions of the end effector pose.
114 | ```
115 |
--------------------------------------------------------------------------------
/trac_ik_lib/include/trac_ik/kdl_tl.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015, TRACLabs, Inc.
2 | //
3 | // Redistribution and use in source and binary forms, with or without
4 | // modification, are permitted provided that the following conditions are met:
5 | //
6 | // * Redistributions of source code must retain the above copyright
7 | // notice, this list of conditions and the following disclaimer.
8 | //
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // * Neither the name of the {copyright_holder} nor the names of its
14 | // contributors may be used to endorse or promote products derived from
15 | // this software without specific prior written permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | // POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
30 | #ifndef TRAC_IK__KDL_TL_HPP_
31 | #define TRAC_IK__KDL_TL_HPP_
32 |
33 | #include
34 | #include
35 |
36 | #include "kdl/chainfksolverpos_recursive.hpp"
37 | #include "kdl/chainiksolvervel_pinv.hpp"
38 |
39 | namespace TRAC_IK
40 | {
41 | class TRAC_IK;
42 | }
43 |
44 | namespace KDL
45 | {
46 |
47 | enum BasicJointType { RotJoint, TransJoint, Continuous };
48 |
49 | class ChainIkSolverPos_TL
50 | {
51 | friend class TRAC_IK::TRAC_IK;
52 |
53 | public:
54 | ChainIkSolverPos_TL(
55 | const Chain & chain, const JntArray & q_min, const JntArray & q_max,
56 | double maxtime = 0.005, double eps = 1e-3, bool random_restart = false,
57 | bool try_jl_wrap = false);
58 |
59 | ~ChainIkSolverPos_TL();
60 |
61 | int CartToJnt(
62 | const KDL::JntArray & q_init, const KDL::Frame & p_in, KDL::JntArray & q_out,
63 | const KDL::Twist bounds = KDL::Twist::Zero());
64 |
65 | inline void setMaxtime(double t)
66 | {
67 | maxtime = std::chrono::duration(t);
68 | }
69 |
70 | private:
71 | const Chain chain;
72 | JntArray q_min;
73 | JntArray q_max;
74 |
75 | KDL::Twist bounds;
76 |
77 | KDL::ChainIkSolverVel_pinv vik_solver;
78 | KDL::ChainFkSolverPos_recursive fksolver;
79 | JntArray delta_q;
80 | std::chrono::duration maxtime;
81 |
82 | double eps;
83 |
84 | bool rr;
85 | bool wrap;
86 |
87 | std::vector types;
88 |
89 | inline void abort()
90 | {
91 | aborted = true;
92 | }
93 |
94 | inline void reset()
95 | {
96 | aborted = false;
97 | }
98 |
99 | bool aborted;
100 |
101 | Frame f;
102 | Twist delta_twist;
103 |
104 | inline static double fRand(double min, double max)
105 | {
106 | double f = static_cast(rand()) / RAND_MAX; // NOLINT
107 | return min + f * (max - min);
108 | }
109 | };
110 |
111 | /**
112 | * determines the rotation axis necessary to rotate from frame b1 to the
113 | * orientation of frame b2 and the vector necessary to translate the origin
114 | * of b1 to the origin of b2, and stores the result in a Twist
115 | * datastructure. The result is w.r.t. frame b1.
116 | * \param F_a_b1 frame b1 expressed with respect to some frame a.
117 | * \param F_a_b2 frame b2 expressed with respect to some frame a.
118 | * \warning The result is not a real Twist!
119 | * \warning In contrast to standard KDL diff methods, the result of
120 | * diffRelative is w.r.t. frame b1 instead of frame a.
121 | */
122 | IMETHOD Twist diffRelative(const Frame & F_a_b1, const Frame & F_a_b2, double dt = 1)
123 | {
124 | return Twist(
125 | F_a_b1.M.Inverse() * diff(F_a_b1.p, F_a_b2.p, dt),
126 | F_a_b1.M.Inverse() * diff(F_a_b1.M, F_a_b2.M, dt));
127 | }
128 |
129 | } // namespace KDL
130 |
131 | #endif // TRAC_IK__KDL_TL_HPP_
132 |
--------------------------------------------------------------------------------
/trac_ik_python/README.md:
--------------------------------------------------------------------------------
1 | # trac_ik_python
2 |
3 | Python wrapper for TRAC IK library using SWIG to generate the bindings.
4 | Please send any questions to [Sam Pfeiffer](mailto:Sammy.Pfeiffer@student.uts.edu.au)
5 |
6 | # Example usage
7 | Upload a robot to the param server:
8 |
9 | roslaunch pr2_description upload_pr2.launch
10 |
11 | Now you can get IK's:
12 |
13 | ```python
14 | #!/usr/bin/env python
15 |
16 | from trac_ik_python.trac_ik import IK
17 |
18 | ik_solver = IK("torso_lift_link",
19 | "r_wrist_roll_link")
20 |
21 | seed_state = [0.0] * ik_solver.number_of_joints
22 |
23 | ik_solver.get_ik(seed_state,
24 | 0.45, 0.1, 0.3, # X, Y, Z
25 | 0.0, 0.0, 0.0, 1.0) # QX, QY, QZ, QW
26 | # Returns:
27 | # (0.537242808640495,
28 | # 0.04673341230604478,
29 | # -0.053508394352190486,
30 | # -1.5099959208163785,
31 | # 2.6007509004432596,
32 | # -1.506431092603137,
33 | # -3.040949079090651)
34 | ```
35 |
36 |
37 | You can also play with the bounds of the IK call:
38 | ```python
39 | #!/usr/bin/env python
40 |
41 | from trac_ik_python.trac_ik import IK
42 |
43 | ik_solver = IK("torso_lift_link",
44 | "r_wrist_roll_link")
45 |
46 | seed_state = [0.0] * ik_solver.number_of_joints
47 |
48 | ik_solver.get_ik(seed_state,
49 | 0.45, 0.1, 0.3,
50 | 0.0, 0.0, 0.0, 1.0,
51 | 0.01, 0.01, 0.01, # X, Y, Z bounds
52 | 0.1, 0.1, 0.1) # Rotation X, Y, Z bounds
53 | )
54 | # Returns:
55 | # (0.5646018385887146,
56 | # 0.04759637706046231,
57 | # 0.026629718805901908,
58 | # -1.5106828886580062,
59 | # 2.5541685245726535,
60 | # -1.4663448384900402,
61 | # -3.104163452483634)
62 | ```
63 |
64 | The coordinate frame of the given poses must be in the base frame, you can check the links/joints being used:
65 | ```python
66 | #!/usr/bin/env python
67 |
68 | from trac_ik_python.trac_ik import IK
69 |
70 | ik_solver = IK("torso_lift_link",
71 | "r_wrist_roll_link")
72 |
73 | ik_solver.base_link
74 | # 'torso_lift_link'
75 |
76 | ik_solver.tip_link
77 | # 'r_wrist_roll_link'
78 |
79 | ik_solver.joint_names
80 | # ('r_shoulder_pan_joint', 'r_shoulder_lift_joint', 'r_upper_arm_roll_joint', 'r_elbow_flex_joint', 'r_forearm_roll_joint', 'r_wrist_flex_joint', 'r_wrist_roll_joint')
81 |
82 | ik_solver.link_names
83 | # ('r_shoulder_pan_link', 'r_shoulder_lift_link', 'r_upper_arm_roll_link', 'r_upper_arm_link', 'r_elbow_flex_link', 'r_forearm_roll_link', 'r_forearm_link', 'r_wrist_flex_link', 'r_wrist_roll_link')
84 | ```
85 |
86 | You can also initialize the IK from a string containing the URDF (by default it takes it from the `/robot_description` parameter in the param server):
87 | ```python
88 | #!/usr/bin/env python
89 |
90 | from trac_ik_python.trac_ik import IK
91 |
92 | # Get your URDF from somewhere
93 | urdf_str = rospy.get_param('/robot_description')
94 |
95 | ik_solver = IK("torso_lift_link",
96 | "r_wrist_roll_link",
97 | urdf_string=urdf_str)
98 | ```
99 |
100 |
101 | You can also check and modify the joint limits:
102 | ```python
103 | #!/usr/bin/env python
104 |
105 | from trac_ik_python.trac_ik import IK
106 |
107 | ik_solver = IK("torso_lift_link",
108 | "r_wrist_roll_link")
109 |
110 | lower_bound, upper_bound = ik_solver.get_joint_limits()
111 | # lower_bound: (-2.1353981494903564, -0.35359999537467957, -3.75, -2.121299982070923, -3.4028234663852886e+38, -2.0, -3.4028234663852886e+38)
112 | # upper_bound: (0.5646018385887146, 1.2963000535964966, 0.6499999761581421, -0.15000000596046448, 3.4028234663852886e+38, -0.10000000149011612, 3.4028234663852886e+38)
113 | ik_solver.set_joint_limits([0.0]* ik_solver.number_of_joints, upper_bound)
114 | ```
115 |
116 | # Extra notes
117 | Given that the Python wrapper is made using [SWIG](http://www.swig.org/) it could be extended to other languages.
118 |
119 | You'll get extra output when instantiating the class that comes from C++:
120 | ```
121 | [ WARN] [1486091331.089974163]: The root link base_footprint has an inertia specified in the URDF, but KDL does not support a root link with an inertia. As a workaround, you can add an extra dummy link to your URDF.
122 | ```
123 |
124 | When finishing the program you'll also get this error (which [is OK apparently](https://github.com/ros-planning/moveit/issues/331)):
125 | ```
126 | terminate called after throwing an instance of 'boost::exception_detail::clone_impl >'
127 | what(): boost: mutex lock failed in pthread_mutex_lock: Invalid argument
128 | Aborted (core dumped)
129 | ```
130 |
131 | And as a final note I didn't simplify even more letting Pose/PoseStamped messages as input, or transforming using TF coordinate frames, adding forward kinematics, etc. to keep it simple.
132 |
--------------------------------------------------------------------------------
/trac_ik_python/scripts/test_pkg.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from trac_ik_python.trac_ik import IK
4 | from numpy.random import random
5 | import time
6 |
7 |
8 | if __name__ == '__main__':
9 | # roslaunch pr2_description upload_pr2.launch
10 | # Needed beforehand
11 |
12 | ik_solver = IK("torso_lift_link",
13 | "r_wrist_roll_link")
14 |
15 | print("IK solver uses link chain:")
16 | print(ik_solver.link_names)
17 |
18 | print("IK solver base frame:")
19 | print(ik_solver.base_link)
20 |
21 | print("IK solver tip link:")
22 | print(ik_solver.tip_link)
23 |
24 | print("IK solver for joints:")
25 | print(ik_solver.joint_names)
26 |
27 | print("IK solver using joint limits:")
28 | lb, up = ik_solver.get_joint_limits()
29 | print("Lower bound: " + str(lb))
30 | print("Upper bound: " + str(up))
31 |
32 | qinit = [0.] * ik_solver.number_of_joints
33 | x = y = z = 0.0
34 | rx = ry = rz = 0.0
35 | rw = 1.0
36 | bx = by = bz = 0.001
37 | brx = bry = brz = 0.1
38 |
39 | # Generate a set of random coords in the arm workarea approx
40 | NUM_COORDS = 200
41 | rand_coords = []
42 | for _ in range(NUM_COORDS):
43 | x = random() * 0.5
44 | y = random() * 0.6 + -0.3
45 | z = random() * 0.7 + -0.35
46 | rand_coords.append((x, y, z))
47 |
48 | # Check some random coords with fixed orientation
49 | avg_time = 0.0
50 | num_solutions_found = 0
51 | for x, y, z in rand_coords:
52 | ini_t = time.time()
53 | sol = ik_solver.get_ik(qinit,
54 | x, y, z,
55 | rx, ry, rz, rw,
56 | bx, by, bz,
57 | brx, bry, brz)
58 | fin_t = time.time()
59 | call_time = fin_t - ini_t
60 | # print("IK call took: " + str(call_time))
61 | avg_time += call_time
62 | if sol:
63 | # print("X, Y, Z: " + str( (x, y, z) ))
64 | # print("SOL: " + str(sol))
65 | num_solutions_found += 1
66 | avg_time = avg_time / NUM_COORDS
67 |
68 | print()
69 | print("Found " + str(num_solutions_found) + " of 200 random coords")
70 | print("Average IK call time: " + str(avg_time))
71 | print()
72 |
73 | # Check if orientation bounds work
74 | avg_time = 0.0
75 | num_solutions_found = 0
76 | brx = bry = brz = 9999.0 # We don't care about orientation
77 | for x, y, z in rand_coords:
78 | ini_t = time.time()
79 | sol = ik_solver.get_ik(qinit,
80 | x, y, z,
81 | rx, ry, rz, rw,
82 | bx, by, bz,
83 | brx, bry, brz)
84 | fin_t = time.time()
85 | call_time = fin_t - ini_t
86 | # print("IK call took: " + str(call_time))
87 | avg_time += call_time
88 | if sol:
89 | # print("X, Y, Z: " + str( (x, y, z) ))
90 | # print("SOL: " + str(sol))
91 | num_solutions_found += 1
92 |
93 | avg_time = avg_time / NUM_COORDS
94 | print()
95 | print("Found " + str(num_solutions_found) + " of 200 random coords ignoring orientation")
96 | print("Average IK call time: " + str(avg_time))
97 | print()
98 |
99 | # Check if big position and orientation bounds work
100 | avg_time = 0.0
101 | num_solutions_found = 0
102 | bx = by = bz = 9999.0
103 | brx = bry = brz = 9999.0
104 | for x, y, z in rand_coords:
105 | ini_t = time.time()
106 | sol = ik_solver.get_ik(qinit,
107 | x, y, z,
108 | rx, ry, rz, rw,
109 | bx, by, bz,
110 | brx, bry, brz)
111 | fin_t = time.time()
112 | call_time = fin_t - ini_t
113 | # print("IK call took: " + str(call_time))
114 | avg_time += call_time
115 | if sol:
116 | # print("X, Y, Z: " + str( (x, y, z) ))
117 | # print("SOL: " + str(sol))
118 | num_solutions_found += 1
119 |
120 | avg_time = avg_time / NUM_COORDS
121 |
122 | print()
123 | print("Found " + str(num_solutions_found) + " of 200 random coords ignoring everything")
124 | print("Average IK call time: " + str(avg_time))
125 | print()
126 |
127 | # std::vector CartToJnt(const std::vector q_init,
128 | # const double x, const double y, const double z,
129 | # const double rx, const double ry, const double rz, const double rw,
130 | # // bounds x y z
131 | # const double boundx=0.0, const double boundy=0.0, const double boundz=0.0,
132 | # // bounds on rotation x y z
133 | # const double boundrx=0.0, const double boundry=0.0, const double
134 | # boundrz=0.0){
135 |
--------------------------------------------------------------------------------
/trac_ik_python/src/trac_ik_python/trac_ik.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Author: Sammy Pfeiffer
4 | # Convenience code to wrap TRAC IK
5 |
6 | from trac_ik_python.trac_ik_wrap import TRAC_IK
7 | import rospy
8 |
9 |
10 | class IK(object):
11 | def __init__(self, base_link, tip_link,
12 | timeout=0.005, epsilon=1e-5, solve_type="Speed",
13 | urdf_string=None):
14 | """
15 | Create a TRAC_IK instance and keep track of it.
16 |
17 | :param str base_link: Starting link of the chain.
18 | :param str tip_link: Last link of the chain.
19 | :param float timeout: Timeout in seconds for the IK calls.
20 | :param float epsilon: Error epsilon.
21 | :param solve_type str: Type of solver, can be:
22 | Speed (default), Distance, Manipulation1, Manipulation2
23 | :param urdf_string str: Optional arg, if not given URDF is taken from
24 | the param server at /robot_description.
25 | """
26 | if urdf_string is None:
27 | urdf_string = rospy.get_param('/robot_description')
28 | self._urdf_string = urdf_string
29 | self._timeout = timeout
30 | self._epsilon = epsilon
31 | self._solve_type = solve_type
32 | self.base_link = base_link
33 | self.tip_link = tip_link
34 | self._ik_solver = TRAC_IK(self.base_link,
35 | self.tip_link,
36 | self._urdf_string,
37 | self._timeout,
38 | self._epsilon,
39 | self._solve_type)
40 | self.number_of_joints = self._ik_solver.getNrOfJointsInChain()
41 | self.joint_names = self._ik_solver.getJointNamesInChain(
42 | self._urdf_string)
43 | self.link_names = self._ik_solver.getLinkNamesInChain()
44 |
45 | def get_ik(self, qinit,
46 | x, y, z,
47 | rx, ry, rz, rw,
48 | bx=1e-5, by=1e-5, bz=1e-5,
49 | brx=1e-3, bry=1e-3, brz=1e-3):
50 | """
51 | Do the IK call.
52 |
53 | :param list of float qinit: Initial status of the joints as seed.
54 | :param float x: X coordinates in base_frame.
55 | :param float y: Y coordinates in base_frame.
56 | :param float z: Z coordinates in base_frame.
57 | :param float rx: X quaternion coordinate.
58 | :param float ry: Y quaternion coordinate.
59 | :param float rz: Z quaternion coordinate.
60 | :param float rw: W quaternion coordinate.
61 | :param float bx: X allowed bound.
62 | :param float by: Y allowed bound.
63 | :param float bz: Z allowed bound.
64 | :param float brx: rotation over X allowed bound.
65 | :param float bry: rotation over Y allowed bound.
66 | :param float brz: rotation over Z allowed bound.
67 |
68 | :return: joint values or None if no solution found.
69 | :rtype: tuple of float.
70 | """
71 | if len(qinit) != self.number_of_joints:
72 | raise Exception("qinit has length %i and it should have length %i" % (
73 | len(qinit), self.number_of_joints))
74 | solution = self._ik_solver.CartToJnt(qinit,
75 | x, y, z,
76 | rx, ry, rz, rw,
77 | bx, by, bz,
78 | brx, bry, brz)
79 | if solution:
80 | return solution
81 | else:
82 | return None
83 |
84 | def get_joint_limits(self):
85 | """
86 | Return lower bound limits and upper bound limits for all the joints
87 | in the order of the joint names.
88 | """
89 | lb = self._ik_solver.getLowerBoundLimits()
90 | ub = self._ik_solver.getUpperBoundLimits()
91 | return lb, ub
92 |
93 | def set_joint_limits(self, lower_bounds, upper_bounds):
94 | """
95 | Set joint limits for all the joints.
96 |
97 | :arg list lower_bounds: List of float of the lower bound limits for
98 | all joints.
99 | :arg list upper_bounds: List of float of the upper bound limits for
100 | all joints.
101 | """
102 | if len(lower_bounds) != self.number_of_joints:
103 | raise Exception("lower_bounds array size mismatch, it's size %i, should be %i" % (
104 | len(lower_bounds),
105 | self.number_of_joints))
106 |
107 | if len(upper_bounds) != self.number_of_joints:
108 | raise Exception("upper_bounds array size mismatch, it's size %i, should be %i" % (
109 | len(upper_bounds),
110 | self.number_of_joints))
111 | self._ik_solver.setKDLLimits(lower_bounds, upper_bounds)
112 |
--------------------------------------------------------------------------------
/trac_ik_python/scripts/test_wrapper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from trac_ik_python.trac_ik_wrap import TRAC_IK
4 | import rospy
5 | from numpy.random import random
6 | import time
7 |
8 |
9 | if __name__ == '__main__':
10 | # roslaunch pr2_description upload_pr2.launch
11 | # Needed beforehand
12 | urdf = rospy.get_param('/robot_description')
13 | # params of constructor:
14 | # base_link, tip_link, urdf_string, timeout, epsilon, solve_type="Speed"
15 | # solve_type can be: Distance, Speed, Manipulation1, Manipulation2
16 | ik_solver = TRAC_IK("torso_lift_link",
17 | "r_wrist_roll_link",
18 | urdf,
19 | 0.005, # default seconds
20 | 1e-5, # default epsilon
21 | "Speed")
22 | print("Number of joints:")
23 | print(ik_solver.getNrOfJointsInChain())
24 | print("Joint names:")
25 | print(ik_solver.getJointNamesInChain(urdf))
26 | print("Link names:")
27 | print(ik_solver.getLinkNamesInChain())
28 |
29 | qinit = [0.] * 7
30 | x = y = z = 0.0
31 | rx = ry = rz = 0.0
32 | rw = 1.0
33 | bx = by = bz = 0.001
34 | brx = bry = brz = 0.1
35 |
36 | # Generate a set of random coords in the arm workarea approx
37 | NUM_COORDS = 200
38 | rand_coords = []
39 | for _ in range(NUM_COORDS):
40 | x = random() * 0.5
41 | y = random() * 0.6 + -0.3
42 | z = random() * 0.7 + -0.35
43 | rand_coords.append((x, y, z))
44 |
45 | # Check some random coords with fixed orientation
46 | avg_time = 0.0
47 | num_solutions_found = 0
48 | for x, y, z in rand_coords:
49 | ini_t = time.time()
50 | sol = ik_solver.CartToJnt(qinit,
51 | x, y, z,
52 | rx, ry, rz, rw,
53 | bx, by, bz,
54 | brx, bry, brz)
55 | fin_t = time.time()
56 | call_time = fin_t - ini_t
57 | # print "IK call took: " + str(call_time)
58 | avg_time += call_time
59 | if sol:
60 | # print "X, Y, Z: " + str( (x, y, z) )
61 | # print "SOL: " + str(sol)
62 | num_solutions_found += 1
63 | avg_time = avg_time / NUM_COORDS
64 |
65 | print()
66 | print("Found " + str(num_solutions_found) + " of 200 random coords")
67 | print("Average IK call time: " + str(avg_time))
68 | print()
69 |
70 | # Check if orientation bounds work
71 | avg_time = 0.0
72 | num_solutions_found = 0
73 | brx = bry = brz = 9999.0 # We don't care about orientation
74 | for x, y, z in rand_coords:
75 | ini_t = time.time()
76 | sol = ik_solver.CartToJnt(qinit,
77 | x, y, z,
78 | rx, ry, rz, rw,
79 | bx, by, bz,
80 | brx, bry, brz)
81 | fin_t = time.time()
82 | call_time = fin_t - ini_t
83 | # print("IK call took: " + str(call_time))
84 | avg_time += call_time
85 | if sol:
86 | # print("X, Y, Z: " + str( (x, y, z) ))
87 | # print("SOL: " + str(sol))
88 | num_solutions_found += 1
89 |
90 | avg_time = avg_time / NUM_COORDS
91 | print()
92 | print("Found " + str(num_solutions_found) + " of 200 random coords ignoring orientation")
93 | print("Average IK call time: " + str(avg_time))
94 | print()
95 |
96 | # Check if big position and orientation bounds work
97 | avg_time = 0.0
98 | num_solutions_found = 0
99 | bx = by = bz = 9999.0
100 | brx = bry = brz = 9999.0
101 | for x, y, z in rand_coords:
102 | ini_t = time.time()
103 | sol = ik_solver.CartToJnt(qinit,
104 | x, y, z,
105 | rx, ry, rz, rw,
106 | bx, by, bz,
107 | brx, bry, brz)
108 | fin_t = time.time()
109 | call_time = fin_t - ini_t
110 | # print("IK call took: " + str(call_time))
111 | avg_time += call_time
112 | if sol:
113 | # print("X, Y, Z: " + str( (x, y, z) ))
114 | # print("SOL: " + str(sol))
115 | num_solutions_found += 1
116 |
117 | avg_time = avg_time / NUM_COORDS
118 |
119 | print()
120 | print("Found " + str(num_solutions_found) + " of 200 random coords ignoring everything")
121 | print("Average IK call time: " + str(avg_time))
122 | print()
123 |
124 | # std::vector CartToJnt(const std::vector q_init,
125 | # const double x, const double y, const double z,
126 | # const double rx, const double ry, const double rz, const double rw,
127 | # // bounds x y z
128 | # const double boundx=0.0, const double boundy=0.0, const double boundz=0.0,
129 | # // bounds on rotation x y z
130 | # const double boundrx=0.0, const double boundry=0.0, const double
131 | # boundrz=0.0){
132 |
--------------------------------------------------------------------------------
/trac_ik_python/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(trac_ik_python)
3 |
4 | add_compile_options(-std=c++11 -Wno-deprecated)
5 |
6 | ## Find catkin macros and libraries
7 | ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
8 | ## is used, also find other catkin packages
9 | find_package(catkin REQUIRED COMPONENTS
10 | rospy
11 | trac_ik_lib
12 | tf_conversions
13 | )
14 |
15 | find_package(PkgConfig REQUIRED)
16 | pkg_check_modules(pkg_nlopt REQUIRED nlopt)
17 |
18 | find_package(SWIG REQUIRED)
19 |
20 | if(DEFINED ENV{ROS_PYTHON_VERSION} AND ENV{ROS_PYTHON_VERSION} EQUAL 3)
21 | # Python 3
22 | find_package(Python3 COMPONENTS Development)
23 | else()
24 | # Python 2
25 | find_package(PythonLibs REQUIRED)
26 | endif()
27 |
28 | catkin_python_setup()
29 |
30 | ###################################
31 | ## catkin specific configuration ##
32 | ###################################
33 | catkin_package()
34 |
35 | ###########
36 | ## Build ##
37 | ###########
38 |
39 | #set(CMAKE_VERBOSE_MAKEFILE ON)
40 |
41 | # SWIG stuff
42 | include(${SWIG_USE_FILE})
43 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/swig)
44 |
45 | # To add trac_ik_lib headers (from this ros answers: http://answers.ros.org/question/201977/include-header-file-from-another-package-indigo/)
46 | include_directories(${catkin_INCLUDE_DIRS} ${pkg_nlopt_INCLUDE_DIRS})
47 |
48 |
49 | # Python trac_ik wrapper using SWIG
50 | # Based on: https://github.com/kdhansen/Aseta/blob/36a7a104f3430ff8b54416a07062234673a73762/src/gatsp/CMakeLists.txt
51 | SET_SOURCE_FILES_PROPERTIES(
52 | swig/trak_ik_wrap.i PROPERTIES CPLUSPLUS ON
53 | )
54 |
55 | if(DEFINED ENV{ROS_PYTHON_VERSION} AND ENV{ROS_PYTHON_VERSION} EQUAL 3)
56 | include_directories(
57 | ${Python3_INCLUDE_DIRS}
58 | ${Boost_INCLUDE_DIRS}
59 | ${pkg_nlopt_INCLUDE_DIRS}
60 | )
61 | else()
62 | include_directories(
63 | ${PYTHON_INCLUDE_DIRS} # This solved Python.h: No such file or directory
64 | ${Boost_INCLUDE_DIRS}
65 | )
66 | endif()
67 |
68 |
69 |
70 | # To overcome (took me hours to notice):
71 | # /opt/ros/indigo/include/kdl/utilities/utility.h:27:19: fatal error: cstdlib: No such file or directory
72 | # ...build/trac_ik_lib/swig/trac_ik_wrapPYTHON_wrap.c:2977:21: fatal error: stdexcept: No such file or directory
73 | set(CMAKE_C_COMPILER ${CMAKE_CXX_COMPILER})
74 |
75 | # To force SWIG on generating a C++ file-wrapper so we overcome
76 | # error: expected primary-expression before ‘=’ token
77 | # TRAC_IK_ns = *((namespace *)(argp));
78 | set(CMAKE_SWIG_FLAGS "-c++")
79 |
80 | # This actually makes the compilation of the generated trac_ik_wrapPYTHON_wrap.c happen
81 | if(${CMAKE_VERSION} VERSION_LESS "3.8.0")
82 | # SWIG_ADD_MODULE is deprecated from 3.8.0
83 | SWIG_ADD_MODULE(trac_ik_wrap python
84 | swig/trac_ik_wrap.i
85 | )
86 | else()
87 | SWIG_ADD_LIBRARY(trac_ik_wrap
88 | LANGUAGE python
89 | SOURCES swig/trac_ik_wrap.i
90 | )
91 | endif()
92 |
93 | # Link the wrapper with the actual library
94 |
95 | if(DEFINED ENV{ROS_PYTHON_VERSION} AND ENV{ROS_PYTHON_VERSION} EQUAL 3)
96 | SWIG_LINK_LIBRARIES(trac_ik_wrap ${Python3_LIBRARIES} ${catkin_LIBRARIES})
97 | else()
98 | SWIG_LINK_LIBRARIES(trac_ik_wrap ${PYTHON_LIBRARIES} ${catkin_LIBRARIES})
99 | endif()
100 |
101 | # The name '_trac_ik_wrap' is given by SWIG, haven't found how to change it
102 | set_target_properties(_trac_ik_wrap
103 | PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}
104 | )
105 |
106 |
107 | #############
108 | ## Install ##
109 | #############
110 |
111 | add_custom_command(TARGET _trac_ik_wrap POST_BUILD
112 | COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/trac_ik_wrap.py ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}
113 | )
114 |
115 | add_custom_command(TARGET _trac_ik_wrap POST_BUILD
116 | COMMAND touch ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}/__init__.py
117 | )
118 |
119 | # Install the trac_ik_wrap.py generated file
120 | # Needs to be done after creating the python wrapper (usually this is done at the top)
121 |
122 |
123 | install(FILES ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}/trac_ik_wrap.py ${CATKIN_DEVEL_PREFIX}/${CATKIN_PACKAGE_PYTHON_DESTINATION}/_trac_ik_wrap.so
124 | src/trac_ik_python/trac_ik.py
125 | src/trac_ik_python/__init__.py
126 | DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION}
127 | )
128 |
129 | catkin_install_python(PROGRAMS scripts/test_pkg.py scripts/test_wrapper.py
130 | DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
131 |
132 |
133 | #############
134 | ## Testing ##
135 | #############
136 |
137 | # TODO
138 |
139 | ## Add gtest based cpp test target and link libraries
140 | # catkin_add_gtest(${PROJECT_NAME}-test test/test_trac_ik_python.cpp)
141 | # if(TARGET ${PROJECT_NAME}-test)
142 | # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
143 | # endif()
144 |
145 | ## Add folders to be run by python nosetests
146 | # catkin_add_nosetests(test)
147 |
--------------------------------------------------------------------------------
/trac_ik_lib/include/trac_ik/trac_ik.hpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015, TRACLabs, Inc.
2 | //
3 | // Redistribution and use in source and binary forms, with or without
4 | // modification, are permitted provided that the following conditions are met:
5 | //
6 | // * Redistributions of source code must retain the above copyright
7 | // notice, this list of conditions and the following disclaimer.
8 | //
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // * Neither the name of the {copyright_holder} nor the names of its
14 | // contributors may be used to endorse or promote products derived from
15 | // this software without specific prior written permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | // POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
30 | #ifndef TRAC_IK__TRAC_IK_HPP_
31 | #define TRAC_IK__TRAC_IK_HPP_
32 |
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 |
41 | #include "kdl/chainjnttojacsolver.hpp"
42 | #include "trac_ik/nlopt_ik.hpp"
43 | #include "trac_ik/visibility_control.hpp"
44 |
45 | namespace TRAC_IK
46 | {
47 |
48 | enum SolveType { Speed, Distance, Manip1, Manip2 };
49 |
50 | class TRAC_IK_PUBLIC TRAC_IK
51 | {
52 | public:
53 | TRAC_IK_PUBLIC
54 | TRAC_IK(
55 | const KDL::Chain & _chain, const KDL::JntArray & _q_min, const KDL::JntArray & _q_max,
56 | double _maxtime = 0.005, double _eps = 1e-5, SolveType _type = Speed);
57 |
58 | TRAC_IK_PUBLIC
59 | TRAC_IK(
60 | const std::string & base_link, const std::string & tip_link,
61 | const std::string & urdf_xml = "", double _maxtime = 0.005, double _eps = 1e-5,
62 | SolveType _type = Speed);
63 |
64 | TRAC_IK_PUBLIC
65 | ~TRAC_IK();
66 |
67 | TRAC_IK_PUBLIC
68 | bool getKDLChain(KDL::Chain & chain_)
69 | {
70 | chain_ = chain;
71 | return initialized;
72 | }
73 |
74 | TRAC_IK_PUBLIC
75 | bool getKDLLimits(KDL::JntArray & lb_, KDL::JntArray & ub_)
76 | {
77 | lb_ = lb;
78 | ub_ = ub;
79 | return initialized;
80 | }
81 |
82 | TRAC_IK_PUBLIC
83 | // Requires a previous call to CartToJnt()
84 | bool getSolutions(std::vector & solutions_)
85 | {
86 | solutions_ = solutions;
87 | return initialized && !solutions.empty();
88 | }
89 |
90 | TRAC_IK_PUBLIC
91 | bool getSolutions(
92 | std::vector & solutions_, std::vector> & errors_)
94 | {
95 | errors_ = errors;
96 | return getSolutions(solutions_);
97 | }
98 |
99 | TRAC_IK_PUBLIC
100 | bool setKDLLimits(KDL::JntArray & lb_, KDL::JntArray & ub_)
101 | {
102 | lb = lb_;
103 | ub = ub_;
104 | nl_solver.reset(new NLOPT_IK::NLOPT_IK(chain, lb, ub, maxtime.count(), eps, NLOPT_IK::SumSq));
105 | iksolver.reset(new KDL::ChainIkSolverPos_TL(chain, lb, ub, maxtime.count(), eps, true, true));
106 | return true;
107 | }
108 |
109 | TRAC_IK_PUBLIC
110 | static double JointErr(const KDL::JntArray & arr1, const KDL::JntArray & arr2)
111 | {
112 | double err = 0;
113 | for (uint i = 0; i < arr1.data.size(); i++) {
114 | err += pow(arr1(i) - arr2(i), 2);
115 | }
116 |
117 | return err;
118 | }
119 |
120 | TRAC_IK_PUBLIC
121 | int CartToJnt(
122 | const KDL::JntArray & q_init, const KDL::Frame & p_in, KDL::JntArray & q_out,
123 | const KDL::Twist & bounds = KDL::Twist::Zero());
124 |
125 | inline void SetSolveType(SolveType _type)
126 | {
127 | solvetype = _type;
128 | }
129 |
130 | inline SolveType GetSolveType() const
131 | {
132 | return solvetype;
133 | }
134 |
135 | private:
136 | bool initialized;
137 | KDL::Chain chain;
138 | KDL::JntArray lb, ub;
139 | std::unique_ptr jacsolver;
140 | double eps;
141 | std::chrono::duration maxtime;
142 | SolveType solvetype;
143 |
144 | std::unique_ptr nl_solver;
145 | std::unique_ptr iksolver;
146 |
147 | std::chrono::time_point> start_time;
148 |
149 | template
150 | bool runSolver(
151 | T1 & solver, T2 & other_solver,
152 | const KDL::JntArray & q_init,
153 | const KDL::Frame & p_in);
154 |
155 | bool runKDL(const KDL::JntArray & q_init, const KDL::Frame & p_in);
156 | bool runNLOPT(const KDL::JntArray & q_init, const KDL::Frame & p_in);
157 |
158 | void normalize_seed(const KDL::JntArray & seed, KDL::JntArray & solution);
159 | void normalize_limits(const KDL::JntArray & seed, KDL::JntArray & solution);
160 |
161 | std::vector types;
162 |
163 | std::mutex mtx_;
164 | std::vector solutions;
165 | std::vector> errors;
166 |
167 | std::thread task1, task2;
168 | KDL::Twist bounds;
169 |
170 | bool unique_solution(const KDL::JntArray & sol);
171 |
172 | inline static double fRand(double min, double max)
173 | {
174 | double f = static_cast(rand()) / RAND_MAX; // NOLINT
175 | return min + f * (max - min);
176 | }
177 |
178 | /* @brief Manipulation metrics and penalties taken from "Workspace
179 | Geometric Characterization and Manipulability of Industrial Robots",
180 | Ming-June, Tsia, PhD Thesis, Ohio State University, 1986.
181 | https://etd.ohiolink.edu/!etd.send_file?accession=osu1260297835
182 | */
183 | double manipPenalty(const KDL::JntArray &);
184 | double ManipValue1(const KDL::JntArray &);
185 | double ManipValue2(const KDL::JntArray &);
186 |
187 | inline bool myEqual(const KDL::JntArray & a, const KDL::JntArray & b)
188 | {
189 | return (a.data - b.data).isZero(1e-4);
190 | }
191 |
192 | void initialize();
193 | };
194 |
195 | inline bool TRAC_IK::runKDL(const KDL::JntArray & q_init, const KDL::Frame & p_in)
196 | {
197 | return runSolver(*iksolver.get(), *nl_solver.get(), q_init, p_in);
198 | }
199 |
200 | inline bool TRAC_IK::runNLOPT(const KDL::JntArray & q_init, const KDL::Frame & p_in)
201 | {
202 | return runSolver(*nl_solver.get(), *iksolver.get(), q_init, p_in);
203 | }
204 |
205 | } // namespace TRAC_IK
206 |
207 | #endif // TRAC_IK__TRAC_IK_HPP_
208 |
--------------------------------------------------------------------------------
/trac_ik_lib/src/kdl_tl.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015, TRACLabs, Inc.
2 | //
3 | // Redistribution and use in source and binary forms, with or without
4 | // modification, are permitted provided that the following conditions are met:
5 | //
6 | // * Redistributions of source code must retain the above copyright
7 | // notice, this list of conditions and the following disclaimer.
8 | //
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // * Neither the name of the {copyright_holder} nor the names of its
14 | // contributors may be used to endorse or promote products derived from
15 | // this software without specific prior written permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | // POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
30 | #include "trac_ik/kdl_tl.hpp"
31 |
32 | #include
33 | #include
34 | #include
35 |
36 | namespace KDL
37 | {
38 | ChainIkSolverPos_TL::ChainIkSolverPos_TL(
39 | const Chain & _chain, const JntArray & _q_min,
40 | const JntArray & _q_max, double _maxtime, double _eps,
41 | bool _random_restart, bool _try_jl_wrap)
42 | : chain(_chain), q_min(_q_min), q_max(_q_max), vik_solver(chain), fksolver(chain), delta_q(
43 | chain.getNrOfJoints()),
44 | maxtime(std::chrono::duration(_maxtime)), eps(_eps), rr(_random_restart), wrap(
45 | _try_jl_wrap)
46 | {
47 | assert(chain.getNrOfJoints() == _q_min.data.size());
48 | assert(chain.getNrOfJoints() == _q_max.data.size());
49 |
50 | reset();
51 |
52 | for (uint i = 0; i < chain.segments.size(); i++) {
53 | std::string type = chain.segments[i].getJoint().getTypeName();
54 | if (type.find("Rot") != std::string::npos) {
55 | if (_q_max(types.size()) >= std::numeric_limits::max() &&
56 | _q_min(types.size()) <= std::numeric_limits::lowest())
57 | {
58 | types.push_back(KDL::BasicJointType::Continuous);
59 | } else {types.push_back(KDL::BasicJointType::RotJoint);}
60 | } else if (type.find("Trans") != std::string::npos) {
61 | types.push_back(KDL::BasicJointType::TransJoint);
62 | }
63 | }
64 |
65 | assert(types.size() == static_cast(_q_max.data.size())); // NOLINT
66 | }
67 |
68 |
69 | int ChainIkSolverPos_TL::CartToJnt(
70 | const KDL::JntArray & q_init, const KDL::Frame & p_in,
71 | KDL::JntArray & q_out, const KDL::Twist _bounds)
72 | {
73 | if (aborted) {
74 | return -3;
75 | }
76 |
77 | std::chrono::duration timediff;
78 | std::chrono::time_point> start_time(
79 | std::chrono::system_clock::now());
80 | q_out = q_init;
81 | bounds = _bounds;
82 |
83 | do {
84 | fksolver.JntToCart(q_out, f);
85 | delta_twist = diffRelative(p_in, f);
86 |
87 | if (std::abs(delta_twist.vel.x()) <= std::abs(bounds.vel.x())) {
88 | delta_twist.vel.x(0);
89 | }
90 |
91 | if (std::abs(delta_twist.vel.y()) <= std::abs(bounds.vel.y())) {
92 | delta_twist.vel.y(0);
93 | }
94 |
95 | if (std::abs(delta_twist.vel.z()) <= std::abs(bounds.vel.z())) {
96 | delta_twist.vel.z(0);
97 | }
98 |
99 | if (std::abs(delta_twist.rot.x()) <= std::abs(bounds.rot.x())) {
100 | delta_twist.rot.x(0);
101 | }
102 |
103 | if (std::abs(delta_twist.rot.y()) <= std::abs(bounds.rot.y())) {
104 | delta_twist.rot.y(0);
105 | }
106 |
107 | if (std::abs(delta_twist.rot.z()) <= std::abs(bounds.rot.z())) {
108 | delta_twist.rot.z(0);
109 | }
110 |
111 | if (Equal(delta_twist, Twist::Zero(), eps)) {
112 | return 1;
113 | }
114 |
115 | delta_twist = diff(f, p_in);
116 |
117 | vik_solver.CartToJnt(q_out, delta_twist, delta_q);
118 | KDL::JntArray q_curr;
119 |
120 | Add(q_out, delta_q, q_curr);
121 |
122 | for (unsigned int j = 0; j < q_min.data.size(); j++) {
123 | if (types[j] == KDL::BasicJointType::Continuous) {
124 | continue;
125 | }
126 | if (q_curr(j) < q_min(j)) {
127 | if (!wrap || types[j] == KDL::BasicJointType::TransJoint) {
128 | // KDL's default
129 | q_curr(j) = q_min(j);
130 | } else {
131 | // Find actual wrapped angle between limit and joint
132 | double diffangle = fmod(q_min(j) - q_curr(j), 2 * M_PI);
133 | // Subtract that angle from limit and go into the range by a
134 | // revolution
135 | double curr_angle = q_min(j) - diffangle + 2 * M_PI;
136 | if (curr_angle > q_max(j)) {
137 | q_curr(j) = q_min(j);
138 | } else {
139 | q_curr(j) = curr_angle;
140 | }
141 | }
142 | }
143 | }
144 |
145 | for (unsigned int j = 0; j < q_max.data.size(); j++) {
146 | if (types[j] == KDL::BasicJointType::Continuous) {
147 | continue;
148 | }
149 |
150 | if (q_curr(j) > q_max(j)) {
151 | if (!wrap || types[j] == KDL::BasicJointType::TransJoint) {
152 | // KDL's default
153 | q_curr(j) = q_max(j);
154 | } else {
155 | // Find actual wrapped angle between limit and joint
156 | double diffangle = fmod(q_curr(j) - q_max(j), 2 * M_PI);
157 | // Add that angle to limit and go into the range by a revolution
158 | double curr_angle = q_max(j) + diffangle - 2 * M_PI;
159 | if (curr_angle < q_min(j)) {
160 | q_curr(j) = q_max(j);
161 | } else {
162 | q_curr(j) = curr_angle;
163 | }
164 | }
165 | }
166 | }
167 |
168 | Subtract(q_out, q_curr, q_out);
169 |
170 | if (q_out.data.isZero(std::numeric_limits::epsilon())) {
171 | if (rr) {
172 | for (unsigned int j = 0; j < q_out.data.size(); j++) {
173 | if (types[j] == KDL::BasicJointType::Continuous) {
174 | q_curr(j) = fRand(q_curr(j) - 2 * M_PI, q_curr(j) + 2 * M_PI);
175 | } else {
176 | q_curr(j) = fRand(q_min(j), q_max(j));
177 | }
178 | }
179 | }
180 |
181 | // Below would be an optimization to the normal KDL, where when it
182 | // gets stuck, it returns immediately. Don't use to compare KDL with
183 | // random restarts or TRAC-IK to plain KDL.
184 |
185 | // else {
186 | // q_out=q_curr;
187 | // return -3;
188 | // }
189 | }
190 |
191 | q_out = q_curr;
192 |
193 | timediff = std::chrono::system_clock::now() - start_time;
194 | } while (timediff < maxtime && !aborted);
195 |
196 | return -3;
197 | }
198 |
199 | ChainIkSolverPos_TL::~ChainIkSolverPos_TL()
200 | {
201 | }
202 |
203 |
204 | } // namespace KDL
205 |
--------------------------------------------------------------------------------
/trac_ik_lib/include/trac_ik/dual_quaternion.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015, TRACLabs, Inc.
2 | //
3 | // Redistribution and use in source and binary forms, with or without
4 | // modification, are permitted provided that the following conditions are met:
5 | //
6 | // * Redistributions of source code must retain the above copyright
7 | // notice, this list of conditions and the following disclaimer.
8 | //
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // * Neither the name of the {copyright_holder} nor the names of its
14 | // contributors may be used to endorse or promote products derived from
15 | // this software without specific prior written permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | // POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
30 | #ifndef TRAC_IK__DUAL_QUATERNION_H_
31 | #define TRAC_IK__DUAL_QUATERNION_H_
32 |
33 | #include "trac_ik/math3d.h"
34 |
35 | using math3d::point3d;
36 | using math3d::matrix;
37 | using math3d::quaternion;
38 |
39 |
40 | template
41 | inline int sign(T v)
42 | {
43 | return (v < 0) ? -1 : 1;
44 | }
45 |
46 | void set_quaternion_matrix(
47 | matrix & M, const quaternion & q, int i = 0,
48 | int j = 0, double w = 1.0)
49 | {
50 | // {{a, -b, -c, -d}, {b, a, -d, c}, {c, d, a, -b}, {d, -c, b, a}}
51 | M(i, j) = w * q.w;
52 | M(i, j + 1) = -w * q.i;
53 | M(i, j + 2) = -w * q.j;
54 | M(i, j + 3) = -w * q.k;
55 | M(i + 1, j) = w * q.i;
56 | M(i + 1, j + 1) = w * q.w;
57 | M(i + 1, j + 2) = -w * q.k;
58 | M(i + 1, j + 3) = w * q.j;
59 | M(i + 2, j) = w * q.j;
60 | M(i + 2, j + 1) = w * q.k;
61 | M(i + 2, j + 2) = w * q.w;
62 | M(i + 2, j + 3) = -w * q.i;
63 | M(i + 3, j) = w * q.k;
64 | M(i + 3, j + 1) = -w * q.j;
65 | M(i + 3, j + 2) = w * q.i;
66 | M(i + 3, j + 3) = w * q.w;
67 | }
68 |
69 | struct dual_quaternion
70 | {
71 | quaternion R, tR_2;
72 |
73 | explicit dual_quaternion(double v = 1.0)
74 | : R(v), tR_2(0)
75 | {
76 | }
77 |
78 | static constexpr double dq_epsilon = 1e-8;
79 |
80 | static dual_quaternion rigid_transformation(const quaternion & r, const point3d & t)
81 | {
82 | dual_quaternion result;
83 | result.R = r;
84 | result.tR_2 = (quaternion::convert(t) * r) *= 0.5;
85 | return result;
86 | }
87 | static dual_quaternion convert(const double * p)
88 | {
89 | dual_quaternion result;
90 | result.R = quaternion::convert(p);
91 | result.tR_2 = quaternion::convert(p + 4);
92 | return result;
93 | }
94 |
95 | dual_quaternion & normalize()
96 | {
97 | double n = norm(R) * sign(R.w);
98 | R *= 1.0 / n;
99 | tR_2 *= 1.0 / n;
100 | double d = dot(R, tR_2);
101 | // tR_2 += (-d)*R;
102 | quaternion r2 = R;
103 | r2 *= -d;
104 | tR_2 += r2;
105 | return *this;
106 | }
107 |
108 | point3d get_translation()
109 | {
110 | quaternion t = tR_2 * ~R;
111 | point3d result;
112 | result.x = 2 * t.i;
113 | result.y = 2 * t.j;
114 | result.z = 2 * t.k;
115 | return result;
116 | }
117 |
118 | void to_vector(double * p)
119 | {
120 | R.to_vector(p);
121 | tR_2.to_vector(p + 4);
122 | }
123 |
124 | dual_quaternion & operator+=(const dual_quaternion & a)
125 | {
126 | R += a.R;
127 | tR_2 += a.tR_2;
128 | return *this;
129 | }
130 |
131 | dual_quaternion & operator*=(double a)
132 | {
133 | R *= a;
134 | tR_2 *= a;
135 | return *this;
136 | }
137 |
138 | dual_quaternion & log() // computes log map tangent at identity
139 | {
140 | // assumes qual_quaternion is unitary
141 | const double h0 = std::acos(R.w);
142 | if (h0 * h0 < dq_epsilon) { // small angle approximation: sin(h0)=h0, cos(h0)=1
143 | R.w = 0.0;
144 | R *= 0.5;
145 | tR_2.w = 0.0;
146 | tR_2 *= 0.5;
147 | } else {
148 | R.w = 0.0;
149 | const double ish0 = 1.0 / norm(R);
150 | // R *= ish0;
151 | math3d::normalize(R); // R=s0
152 | const double he = -tR_2.w * ish0;
153 | tR_2.w = 0.0;
154 |
155 | quaternion Rp(R);
156 | Rp *= -dot(R, tR_2) / dot(R, R);
157 | tR_2 += Rp;
158 | tR_2 *= ish0; // tR_2=se
159 |
160 | tR_2 *= h0;
161 | Rp = R;
162 | Rp *= he;
163 | tR_2 += Rp;
164 | tR_2 *= 0.5;
165 | R *= h0 * 0.5;
166 | }
167 |
168 | return *this;
169 | }
170 |
171 | dual_quaternion & exp() // computes exp map tangent at identity
172 | {
173 | // assumes qual_quaternion is on tangent space
174 | const double h0 = 2.0 * norm(R);
175 |
176 | if (h0 * h0 < dq_epsilon) { // small angle approximation: sin(h0)=h0, cos(h0)=1
177 | R *= 2.0;
178 | R.w = 1.0;
179 | tR_2 *= 2.0;
180 | // normalize();
181 | } else {
182 | const double he = 4.0 * math3d::dot(tR_2, R) / h0;
183 | const double sh0 = sin(h0), ch0 = cos(h0);
184 | quaternion Rp(R);
185 | Rp *= -dot(R, tR_2) / dot(R, R);
186 | tR_2 += Rp;
187 | tR_2 *= 2.0 / h0; // tR_2=se
188 |
189 |
190 | tR_2 *= sh0;
191 | Rp = R;
192 | Rp *= he * ch0 * 2.0 / h0;
193 | tR_2 += Rp;
194 | tR_2.w = -he * sh0;
195 |
196 | R *= sh0 * 2.0 / h0;
197 | R.w = ch0;
198 | }
199 | normalize();
200 | return *this;
201 | }
202 | };
203 |
204 |
205 | dual_quaternion operator*(const dual_quaternion & a, const dual_quaternion & b)
206 | {
207 | dual_quaternion result;
208 | result.R = a.R * b.R;
209 | result.tR_2 = a.R * b.tR_2 + a.tR_2 * b.R;
210 | return result;
211 | }
212 |
213 | dual_quaternion operator~(const dual_quaternion & a)
214 | {
215 | dual_quaternion result;
216 | result.R = ~a.R;
217 | result.tR_2 = ((~a.tR_2) *= -1);
218 | return result;
219 | }
220 |
221 | dual_quaternion operator!(const dual_quaternion & a)
222 | {
223 | dual_quaternion result;
224 | result.R = ~a.R;
225 | result.tR_2 = ~a.tR_2;
226 | return result;
227 | }
228 |
229 | double dot(const dual_quaternion & a, const dual_quaternion & b)
230 | {
231 | return dot(a.R, b.R) + dot(a.tR_2, b.tR_2);
232 | }
233 |
234 | void set_dual_quaternion_matrix(
235 | matrix & M, const dual_quaternion & dq, int i = 0,
236 | int j = 0, double w = 1.0)
237 | {
238 | set_quaternion_matrix(M, dq.R, i, j, w);
239 | M(i, j + 4) = M(i, j + 5) = M(i, j + 6) = M(i, j + 7) = 0;
240 | M(i + 1, j + 4) = M(i + 1, j + 5) = M(i + 1, j + 6) = M(i + 1, j + 7) = 0;
241 | M(i + 2, j + 4) = M(i + 2, j + 5) = M(i + 2, j + 6) = M(i + 2, j + 7) = 0;
242 | M(i + 3, j + 4) = M(i + 3, j + 5) = M(i + 3, j + 6) = M(i + 3, j + 7) = 0;
243 | set_quaternion_matrix(M, dq.tR_2, i + 4, j, w);
244 | set_quaternion_matrix(M, dq.R, i + 4, j + 4, w);
245 | }
246 |
247 | dual_quaternion log(dual_quaternion a)
248 | {
249 | return a.log();
250 | }
251 | dual_quaternion exp(dual_quaternion a)
252 | {
253 | return a.exp();
254 | }
255 |
256 |
257 | std::ostream & operator<<(std::ostream & out, const dual_quaternion & dq)
258 | {
259 | return out << "( " << dq.R.w << ", " << dq.R.i << ", " << dq.R.j << ", " << dq.R.k << ", " <<
260 | dq.tR_2.w << ", " << dq.tR_2.i << ", " << dq.tR_2.j << ", " << dq.tR_2.k << " )";
261 | }
262 |
263 | #endif // TRAC_IK__DUAL_QUATERNION_H_
264 |
--------------------------------------------------------------------------------
/trac_ik_examples/src/ik_tests.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015, TRACLabs, Inc.
2 | //
3 | // Redistribution and use in source and binary forms, with or without
4 | // modification, are permitted provided that the following conditions are met:
5 | //
6 | // * Redistributions of source code must retain the above copyright
7 | // notice, this list of conditions and the following disclaimer.
8 | //
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // * Neither the name of the {copyright_holder} nor the names of its
14 | // contributors may be used to endorse or promote products derived from
15 | // this software without specific prior written permission.
16 | //
17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | // POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
30 | #include
31 | #include