add arm actions
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
build/**
|
||||
install/**
|
||||
log/**
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
sudo apt-get install ros-humble-realtime-tools
|
||||
sudo apt-get install ros-humble-moveit
|
||||
sudo apt install ros-humble-ros2-control ros-humble-ros2-controllers
|
||||
|
||||
16
src/hc_dual_arm_bringup/CMakeLists.txt
Normal file
16
src/hc_dual_arm_bringup/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(hc_dual_arm_bringup)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
# 依赖
|
||||
find_package(ament_cmake REQUIRED)
|
||||
|
||||
# 安装启动文件和世界文件
|
||||
install(DIRECTORY launch
|
||||
DESTINATION share/${PROJECT_NAME}/
|
||||
)
|
||||
|
||||
ament_package()
|
||||
202
src/hc_dual_arm_bringup/LICENSE
Normal file
202
src/hc_dual_arm_bringup/LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
43
src/hc_dual_arm_bringup/launch/main.launch.py
Normal file
43
src/hc_dual_arm_bringup/launch/main.launch.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from launch import LaunchDescription
|
||||
from launch.actions import IncludeLaunchDescription
|
||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||
from launch_ros.substitutions import FindPackageShare
|
||||
from launch.substitutions import PathJoinSubstitution
|
||||
|
||||
from launch_ros.actions import Node
|
||||
from launch.actions import DeclareLaunchArgument
|
||||
|
||||
def generate_launch_description():
|
||||
|
||||
dual_arm_moveit_config_pkg_share = FindPackageShare(package="hc_dual_arm_moveit_config")
|
||||
dual_arm_moveit_config_pkg_launch_path = PathJoinSubstitution(
|
||||
[dual_arm_moveit_config_pkg_share, "launch", "demo.launch.py"]
|
||||
)
|
||||
|
||||
dual_arm_motion_share = FindPackageShare(package="hc_dual_arm_motion")
|
||||
dual_arm_motion_launch_path = PathJoinSubstitution(
|
||||
[dual_arm_motion_share, "launch", "hc_dual_arm_motion.launch.py"]
|
||||
)
|
||||
|
||||
dual_arm_moveit_config = IncludeLaunchDescription(
|
||||
PythonLaunchDescriptionSource(dual_arm_moveit_config_pkg_launch_path),
|
||||
)
|
||||
|
||||
dual_arm_motion = IncludeLaunchDescription(
|
||||
PythonLaunchDescriptionSource(dual_arm_motion_launch_path),
|
||||
)
|
||||
|
||||
joy_node = Node(
|
||||
package="joy", # 包名
|
||||
executable="joy_node", # 可执行文件(joy包的核心节点)
|
||||
name="joy_node", # 节点名(自定义)
|
||||
output="screen", # 日志输出到终端
|
||||
)
|
||||
|
||||
return LaunchDescription([
|
||||
joy_node,
|
||||
|
||||
dual_arm_moveit_config, # 启动控制子launch
|
||||
|
||||
dual_arm_motion # 启动手柄控制子launch
|
||||
])
|
||||
15
src/hc_dual_arm_bringup/package.xml
Normal file
15
src/hc_dual_arm_bringup/package.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>hc_dual_arm_bringup</name>
|
||||
<version>1.0.0</version>
|
||||
<description>hc dual arm bringup package</description>
|
||||
<maintainer email="Ray@email.com">Ray</maintainer>
|
||||
<license>Apache-2.0</license>
|
||||
|
||||
<build_depend>ament_cmake</build_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
44
src/hc_dual_arm_interfaces/CMakeLists.txt
Normal file
44
src/hc_dual_arm_interfaces/CMakeLists.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
if(POLICY CMP0148)
|
||||
cmake_policy(SET CMP0148 OLD)
|
||||
endif()
|
||||
|
||||
project(hc_dual_arm_interfaces)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
# find dependencies
|
||||
find_package(ament_cmake REQUIRED)
|
||||
find_package(rosidl_default_generators REQUIRED)
|
||||
find_package(std_msgs REQUIRED)
|
||||
find_package(geometry_msgs REQUIRED)
|
||||
|
||||
set(action_files
|
||||
action/HcDualArm.action
|
||||
)
|
||||
|
||||
set(message_files
|
||||
msg/ArmMotionParams.msg
|
||||
)
|
||||
|
||||
rosidl_generate_interfaces(${PROJECT_NAME}
|
||||
${action_files}
|
||||
${message_files}
|
||||
|
||||
DEPENDENCIES
|
||||
std_msgs
|
||||
geometry_msgs
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_lint_auto REQUIRED)
|
||||
set(ament_cmake_copyright_FOUND TRUE)
|
||||
set(ament_cmake_cpplint_FOUND TRUE)
|
||||
ament_lint_auto_find_test_dependencies()
|
||||
endif()
|
||||
|
||||
ament_export_dependencies(rosidl_default_runtime)
|
||||
ament_package()
|
||||
202
src/hc_dual_arm_interfaces/LICENSE
Normal file
202
src/hc_dual_arm_interfaces/LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
27
src/hc_dual_arm_interfaces/action/HcDualArm.action
Normal file
27
src/hc_dual_arm_interfaces/action/HcDualArm.action
Normal file
@@ -0,0 +1,27 @@
|
||||
# HcDualArm.action
|
||||
uint8 STATUS_PLANNING = 0 # 规划中
|
||||
uint8 STATUS_EXECUTING = 1 # 执行中
|
||||
uint8 STATUS_DONE = 2 # 完成
|
||||
|
||||
uint8 ARM_LEFT = 0 # 左臂
|
||||
uint8 ARM_RIGHT = 1 # 右臂
|
||||
uint8 ARM_DUAL = 2 # 双臂
|
||||
|
||||
uint8 arm_type # 运动臂类型 | ARM_LEFT/ARM_RIGHT/ARM_DUAL
|
||||
ArmMotionParams[] arm_motion_params # 机械臂运动参数
|
||||
float64 velocity_scaling # 速度缩放因子 [0,1]
|
||||
float64 acceleration_scaling # 加速度缩放因子 [0,1]
|
||||
float64 cartesian_step # MOVEL步长 m [0,0.5]
|
||||
|
||||
---
|
||||
|
||||
bool success # 执行是否成功
|
||||
string message # 结果描述
|
||||
float64 final_progress # 最终进度 [0,1]
|
||||
|
||||
---
|
||||
|
||||
float64 progress # 实时进度 [0,1]
|
||||
uint8 status # 实时状态 STATUS_PLANNING/STATUS_EXECUTING/STATUS_DONE
|
||||
float64[] joints_left # 左臂当前关节角(弧度)
|
||||
float64[] joints_right # 右臂当前关节角(弧度)
|
||||
11
src/hc_dual_arm_interfaces/msg/ArmMotionParams.msg
Normal file
11
src/hc_dual_arm_interfaces/msg/ArmMotionParams.msg
Normal file
@@ -0,0 +1,11 @@
|
||||
# ArmMotionParams.msg - 单臂运动参数
|
||||
uint8 MOVEJ = 0
|
||||
uint8 MOVEL = 1
|
||||
|
||||
uint8 ARM_LEFT = 0
|
||||
uint8 ARM_RIGHT = 1
|
||||
|
||||
uint8 arm_id # 机械臂ID | 0/1
|
||||
uint8 motion_type # 运动模式 | MOVEJ/MOVEL
|
||||
geometry_msgs/Pose target_pose # 笛卡尔目标位姿 | 仅MOVEL生效
|
||||
float64[] target_joints # 目标关节角(弧度) | 仅MOVEJ生效
|
||||
23
src/hc_dual_arm_interfaces/package.xml
Normal file
23
src/hc_dual_arm_interfaces/package.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>hc_dual_arm_interfaces</name>
|
||||
<version>0.0.0</version>
|
||||
<description>hivecore dual arm related internal interfaces</description>
|
||||
<maintainer email="ray@hivecore.cn">ray</maintainer>
|
||||
<license>Apache-2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
<buildtool_depend>rosidl_default_generators</buildtool_depend>
|
||||
|
||||
<depend>std_msgs</depend>
|
||||
<depend>geometry_msgs</depend>
|
||||
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
<member_of_group>rosidl_interface_packages</member_of_group>
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
56
src/hc_dual_arm_motion/CMakeLists.txt
Normal file
56
src/hc_dual_arm_motion/CMakeLists.txt
Normal file
@@ -0,0 +1,56 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
cmake_policy(SET CMP0167 NEW)
|
||||
add_compile_options(-Wall -Wextra -Wpedantic -Wno-dev)
|
||||
|
||||
project(hc_dual_arm_motion)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
# 依赖
|
||||
find_package(ament_cmake REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
find_package(rclcpp_action REQUIRED)
|
||||
find_package(sensor_msgs REQUIRED)
|
||||
find_package(hc_dual_arm_interfaces REQUIRED)
|
||||
find_package(moveit_ros_planning_interface REQUIRED)
|
||||
find_package(geometry_msgs REQUIRED)
|
||||
find_package(rosidl_default_generators REQUIRED)
|
||||
|
||||
# 包含头文件
|
||||
include_directories(include)
|
||||
|
||||
# 编译节点
|
||||
add_executable(hc_dual_arm_motion_server
|
||||
src/main.cpp
|
||||
src/hc_dual_arm_motion_server.cpp
|
||||
)
|
||||
ament_target_dependencies(hc_dual_arm_motion_server
|
||||
rclcpp
|
||||
rclcpp_action
|
||||
sensor_msgs
|
||||
moveit_ros_planning_interface
|
||||
geometry_msgs
|
||||
hc_dual_arm_interfaces
|
||||
)
|
||||
|
||||
# 安装可执行文件
|
||||
install(TARGETS
|
||||
hc_dual_arm_motion_server
|
||||
DESTINATION lib/${PROJECT_NAME})
|
||||
|
||||
install(DIRECTORY launch
|
||||
DESTINATION share/${PROJECT_NAME}/
|
||||
)
|
||||
|
||||
install(DIRECTORY config/
|
||||
DESTINATION share/${PROJECT_NAME}/config)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_lint_auto REQUIRED)
|
||||
ament_lint_auto_find_test_dependencies()
|
||||
endif()
|
||||
|
||||
ament_package()
|
||||
202
src/hc_dual_arm_motion/LICENSE
Normal file
202
src/hc_dual_arm_motion/LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
0
src/hc_dual_arm_motion/README.md
Normal file
0
src/hc_dual_arm_motion/README.md
Normal file
15
src/hc_dual_arm_motion/config/hc_dual_arm_motion_config.yaml
Normal file
15
src/hc_dual_arm_motion/config/hc_dual_arm_motion_config.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
# 注意:根节点名必须和Launch中Node的name参数完全一致(hc_dual_arm_motion)
|
||||
hc_dual_arm_motion_server:
|
||||
ros__parameters:
|
||||
dual_arm_move_group: "dual_arm"
|
||||
right_arm_move_group: "arm_right"
|
||||
left_arm_move_group: "arm_left"
|
||||
action_name: "hc_dual_arm"
|
||||
joy_topic: "joy"
|
||||
preset_movej_joints: [0.0, -0.785398, 0.0, -1.570796, 0.0, 0.785398]
|
||||
velocity_scaling: 0.3
|
||||
cartesian_step: 0.01
|
||||
max_velocity_scaling: 1.0
|
||||
max_acceleration_scaling: 1.0
|
||||
planning_time: 3.0
|
||||
num_planning_attempts: 5
|
||||
126
src/hc_dual_arm_motion/include/hc_dual_arm_motion_server.hpp
Normal file
126
src/hc_dual_arm_motion/include/hc_dual_arm_motion_server.hpp
Normal file
@@ -0,0 +1,126 @@
|
||||
#ifndef MOTION_ACTION_SERVER_HPP_
|
||||
#define MOTION_ACTION_SERVER_HPP_
|
||||
|
||||
#include <rclcpp/rclcpp.hpp>
|
||||
#include <rclcpp_action/rclcpp_action.hpp>
|
||||
#include <sensor_msgs/msg/joy.hpp>
|
||||
#include <moveit_msgs/msg/robot_trajectory.hpp>
|
||||
#include <moveit/move_group_interface/move_group_interface.h>
|
||||
#include <moveit/planning_scene_interface/planning_scene_interface.h>
|
||||
#include "hc_dual_arm_interfaces/action/hc_dual_arm.hpp"
|
||||
#include "hc_dual_arm_interfaces/msg/arm_motion_params.hpp"
|
||||
|
||||
using namespace rclcpp_action;
|
||||
using namespace rclcpp;
|
||||
using namespace std;
|
||||
using namespace moveit_msgs::msg;
|
||||
using namespace hc_dual_arm_interfaces::action;
|
||||
using namespace hc_dual_arm_interfaces::msg;
|
||||
|
||||
using HcDualArmAction = hc_dual_arm_interfaces::action::HcDualArm;
|
||||
using GoalHandleRobotMotion = ServerGoalHandle<HcDualArmAction>;
|
||||
using HcDualArmGoal = HcDualArmAction::Goal;
|
||||
using HcDualArmResult = HcDualArmAction::Result;
|
||||
using HcDualArmFeedback = HcDualArmAction::Feedback;
|
||||
using MoveGroupInterface = moveit::planning_interface::MoveGroupInterface;
|
||||
using PlanningSceneInterface = moveit::planning_interface::PlanningSceneInterface;
|
||||
|
||||
// 封装Action常量
|
||||
enum class ArmType : uint8_t {
|
||||
LEFT = HcDualArmAction::Goal::ARM_LEFT,
|
||||
RIGHT = HcDualArmAction::Goal::ARM_RIGHT,
|
||||
DUAL = HcDualArmAction::Goal::ARM_DUAL
|
||||
};
|
||||
|
||||
enum class MotionStatus : uint8_t{
|
||||
PLANNING = HcDualArmAction::Goal::STATUS_PLANNING,
|
||||
EXECUTING = HcDualArmAction::Goal::STATUS_EXECUTING,
|
||||
DONE = HcDualArmAction::Goal::STATUS_DONE
|
||||
};
|
||||
|
||||
// 封装Msg常量
|
||||
enum class MotionType : uint8_t {
|
||||
MOVEJ = ArmMotionParams::MOVEJ,
|
||||
MOVEL = ArmMotionParams::MOVEL
|
||||
};
|
||||
|
||||
class HcDualArmMotionServer : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
explicit HcDualArmMotionServer(const rclcpp::NodeOptions& options = rclcpp::NodeOptions());
|
||||
~HcDualArmMotionServer() = default;
|
||||
|
||||
private:
|
||||
// 预设参数
|
||||
string dual_arm_planning_group_;
|
||||
string left_arm_planning_group_;
|
||||
string right_arm_planning_group_;
|
||||
|
||||
|
||||
string action_name_;
|
||||
string joy_topic_;
|
||||
|
||||
vector<double> preset_movej_joints_;
|
||||
float velocity_scaling_;
|
||||
float cartesian_step_;
|
||||
float max_velocity_scaling_;
|
||||
float max_acceleration_scaling_;
|
||||
float planning_time_;
|
||||
int num_planning_attempts_;
|
||||
|
||||
// 暂存变量
|
||||
vector<string> end_effector_links_;
|
||||
string base_link_;
|
||||
vector<string> left_arm_joint_names_;
|
||||
vector<string> right_arm_joint_names_;
|
||||
|
||||
// 状态变量
|
||||
bool is_moving;
|
||||
|
||||
// moveit move group 指针
|
||||
shared_ptr<MoveGroupInterface> dual_arm_move_group_ptr_;
|
||||
shared_ptr<MoveGroupInterface> left_arm_move_group_ptr_;
|
||||
shared_ptr<MoveGroupInterface> right_arm_move_group_ptr_;
|
||||
shared_ptr<MoveGroupInterface> current_move_group_ptr_;
|
||||
|
||||
// moveit planning scene 指针
|
||||
shared_ptr<PlanningSceneInterface> planning_scene_interface_ptr_;
|
||||
|
||||
// dual arm action server and client.
|
||||
rclcpp_action::Server<HcDualArmAction>::SharedPtr action_server_ptr_;
|
||||
rclcpp_action::Client<HcDualArmAction>::SharedPtr action_client_ptr_;
|
||||
|
||||
// jog subscription 指针
|
||||
Subscription<sensor_msgs::msg::Joy>::SharedPtr joy_sub_ptr_;
|
||||
|
||||
// 加载参数
|
||||
void load_parameters();
|
||||
|
||||
// 初始化函数
|
||||
void initPlanningGroups();
|
||||
void initSingleMoveGroup( shared_ptr<moveit::planning_interface::MoveGroupInterface>& move_group_ptr_, const string& planning_group);
|
||||
|
||||
// 显示函数
|
||||
void show_pose(const shared_ptr<moveit::planning_interface::MoveGroupInterface>& move_group, const string& end_effector_link);
|
||||
|
||||
// Action回调
|
||||
GoalResponse handle_goal(const GoalUUID& uuid, shared_ptr<const HcDualArmAction::Goal> goal);
|
||||
CancelResponse handle_cancel(const shared_ptr<GoalHandleRobotMotion> goal_handle);
|
||||
|
||||
void handle_accepted(const shared_ptr<GoalHandleRobotMotion> goal_handle);
|
||||
void execute(const shared_ptr<GoalHandleRobotMotion> goal_handle);
|
||||
bool execute_arm_motion(const std::shared_ptr<const HcDualArmAction::Goal> goal, std::shared_ptr<HcDualArmAction::Feedback> feedback, std::shared_ptr<HcDualArmAction::Result> result);
|
||||
|
||||
MoveGroupInterface::Plan single_arm_plan(MoveGroupInterface& move_group, ArmMotionParams motion_Params, double step_value);
|
||||
RobotTrajectory mergeTrajectories(const moveit_msgs::msg::RobotTrajectory& left_traj,const moveit_msgs::msg::RobotTrajectory& right_traj);
|
||||
RobotTrajectory scaleTrajectoryTime(const moveit_msgs::msg::RobotTrajectory& traj, double target_duration);
|
||||
|
||||
// 运动执行函数
|
||||
bool execute_single_arm_motion(const shared_ptr<const HcDualArmAction::Goal> goal, shared_ptr<HcDualArmAction::Feedback> feedback, shared_ptr<HcDualArmAction::Result> result, ArmType arm_type);
|
||||
bool execute_dual_arm_motion(const shared_ptr<const HcDualArmAction::Goal> goal, shared_ptr<HcDualArmAction::Feedback> feedback, shared_ptr<HcDualArmAction::Result> result);
|
||||
|
||||
// 遥控器回调
|
||||
void joy_callback(const sensor_msgs::msg::Joy::SharedPtr msg);
|
||||
};
|
||||
|
||||
#endif // MOTION_ACTION_SERVER_HPP_
|
||||
33
src/hc_dual_arm_motion/launch/hc_dual_arm_motion.launch.py
Normal file
33
src/hc_dual_arm_motion/launch/hc_dual_arm_motion.launch.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import os
|
||||
from launch import LaunchDescription
|
||||
from launch_ros.actions import Node
|
||||
from launch.actions import TimerAction
|
||||
from ament_index_python.packages import get_package_share_directory
|
||||
|
||||
|
||||
def generate_launch_description():
|
||||
|
||||
config_path = os.path.join(
|
||||
get_package_share_directory("hc_dual_arm_motion"), # 替换为你的功能包名
|
||||
"config",
|
||||
"hc_dual_arm_motion_config.yaml"
|
||||
)
|
||||
|
||||
# 创建节点启动描述
|
||||
hc_dual_arm_motion_node = Node(
|
||||
package='hc_dual_arm_motion',
|
||||
executable='hc_dual_arm_motion_server',
|
||||
name='hc_dual_arm_motion_server',
|
||||
output='screen',
|
||||
parameters=[config_path , {"use_sim_time": True}]
|
||||
)
|
||||
|
||||
start_hc_dual_arm_motion_node = TimerAction(
|
||||
period=1.0,
|
||||
actions=[hc_dual_arm_motion_node],
|
||||
)
|
||||
|
||||
# 组装launch描述
|
||||
return LaunchDescription([
|
||||
start_hc_dual_arm_motion_node
|
||||
])
|
||||
27
src/hc_dual_arm_motion/package.xml
Normal file
27
src/hc_dual_arm_motion/package.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>hc_dual_arm_motion</name>
|
||||
<version>1.0.0</version>
|
||||
<description>hivecore dual arm motion control package</description>
|
||||
<maintainer email="ray@hivecore.cn">ray</maintainer>
|
||||
<license>Apache-2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
<buildtool_depend>rosidl_default_generators</buildtool_depend>
|
||||
|
||||
<depend>rclcpp</depend>
|
||||
<depend>hc_dual_arm_interfaces</depend>
|
||||
<depend>sensor_msgs</depend>
|
||||
<depend>moveit_ros_planning_interface</depend>
|
||||
<depend>geometry_msgs</depend>
|
||||
<depend>std_msgs</depend>
|
||||
<depend>moveit_core</depend>
|
||||
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
808
src/hc_dual_arm_motion/src/hc_dual_arm_motion_server.cpp
Normal file
808
src/hc_dual_arm_motion/src/hc_dual_arm_motion_server.cpp
Normal file
@@ -0,0 +1,808 @@
|
||||
#include "hc_dual_arm_motion_server.hpp"
|
||||
#include <thread>
|
||||
#include <moveit_msgs/msg/constraints.hpp>
|
||||
#include <moveit_msgs/msg/joint_constraint.hpp>
|
||||
#include <moveit_msgs/msg/position_constraint.hpp>
|
||||
#include <moveit_msgs/msg/orientation_constraint.hpp>
|
||||
#include <shape_msgs/msg/solid_primitive.hpp>
|
||||
#include <tf2_ros/transform_listener.h>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
HcDualArmMotionServer::HcDualArmMotionServer(const rclcpp::NodeOptions& options)
|
||||
: Node("hc_dual_arm_motion_server", options)
|
||||
{
|
||||
// 1. 加载配置参数
|
||||
load_parameters();
|
||||
|
||||
// 2. 初始化MoveGroupInterface(MoveIt2需要多线程执行器,提前初始化)
|
||||
initPlanningGroups();
|
||||
|
||||
// 3. 初始化Action服务端
|
||||
action_server_ptr_ = rclcpp_action::create_server<HcDualArmAction>(
|
||||
this,
|
||||
action_name_,
|
||||
std::bind(&HcDualArmMotionServer::handle_goal, this, std::placeholders::_1, std::placeholders::_2),
|
||||
std::bind(&HcDualArmMotionServer::handle_cancel, this, std::placeholders::_1),
|
||||
std::bind(&HcDualArmMotionServer::handle_accepted, this, std::placeholders::_1));
|
||||
RCLCPP_INFO(this->get_logger(), "Action server started: %s", action_name_.c_str());
|
||||
|
||||
// 4. 初始化Action客户端(关键:用于Joy回调发送Goal)
|
||||
action_client_ptr_ = rclcpp_action::create_client<HcDualArmAction>(this, action_name_);
|
||||
while (!action_client_ptr_->wait_for_action_server(5s) && rclcpp::ok())
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(), "Waiting for action server %s...", action_name_.c_str());
|
||||
}
|
||||
RCLCPP_INFO(this->get_logger(), "Action client connected to %s", action_name_.c_str());
|
||||
|
||||
// 5. 订阅遥控器Joy话题
|
||||
joy_sub_ptr_ = this->create_subscription<sensor_msgs::msg::Joy>(joy_topic_,10,std::bind(&HcDualArmMotionServer::joy_callback, this, std::placeholders::_1));
|
||||
RCLCPP_INFO(this->get_logger(), "Subscribed to joy topic: %s", joy_topic_.c_str());
|
||||
RCLCPP_INFO(this->get_logger(), "Joy mapping: A(btn0)=MoveJ, B(btn1)=MoveL, X(btn2)=Cancel");
|
||||
|
||||
// 6. 初始化状态标志位
|
||||
is_moving = false; // 初始状态为静止
|
||||
}
|
||||
|
||||
void HcDualArmMotionServer::load_parameters()
|
||||
{
|
||||
// 字符串参数定义及初始化
|
||||
this->declare_parameter<std::string>("dual_arm_planning_group", "dual_arm");
|
||||
this->declare_parameter<std::string>("right_arm_planning_group", "arm_right");
|
||||
this->declare_parameter<std::string>("left_arm_planning_group", "arm_left");
|
||||
this->declare_parameter<std::string>("action_name", "hc_dual_arm");
|
||||
this->declare_parameter<std::string>("joy_topic", "joy");
|
||||
std::vector<double> default_joints = {0.0, -M_PI/4, 0.0, -M_PI/2, 0.0, M_PI/4};
|
||||
this->declare_parameter<std::vector<double>>("preset_movej_joints", default_joints);
|
||||
this->declare_parameter<float>("velocity_scaling", 0.3f);
|
||||
this->declare_parameter<float>("cartesian_step", 0.01f);
|
||||
this->declare_parameter<float>("max_velocity_scaling", 1.0f);
|
||||
this->declare_parameter<float>("max_acceleration_scaling", 1.0f);
|
||||
this->declare_parameter<float>("planning_time", 3.0f);
|
||||
this->declare_parameter<int>("num_planning_attempts", 5);
|
||||
|
||||
// 字符串参数获取与赋值
|
||||
this->get_parameter("dual_arm_planning_group", dual_arm_planning_group_);
|
||||
this->get_parameter("right_arm_planning_group", right_arm_planning_group_);
|
||||
this->get_parameter("left_arm_planning_group", left_arm_planning_group_);
|
||||
this->get_parameter("action_name", action_name_);
|
||||
this->get_parameter("joy_topic", joy_topic_);
|
||||
this->get_parameter("preset_movej_joints", preset_movej_joints_);
|
||||
this->get_parameter("velocity_scaling", velocity_scaling_);
|
||||
this->get_parameter("cartesian_step", cartesian_step_);
|
||||
this->get_parameter("max_velocity_scaling", max_velocity_scaling_);
|
||||
this->get_parameter("max_acceleration_scaling", max_acceleration_scaling_);
|
||||
this->get_parameter("planning_time", planning_time_);
|
||||
this->get_parameter("num_planning_attempts", num_planning_attempts_);
|
||||
}
|
||||
|
||||
void HcDualArmMotionServer::initPlanningGroups()
|
||||
{
|
||||
initSingleMoveGroup(dual_arm_move_group_ptr_, dual_arm_planning_group_);
|
||||
initSingleMoveGroup(right_arm_move_group_ptr_, right_arm_planning_group_);
|
||||
initSingleMoveGroup(left_arm_move_group_ptr_, left_arm_planning_group_);
|
||||
|
||||
end_effector_links_.push_back(left_arm_move_group_ptr_->getEndEffectorLink());
|
||||
end_effector_links_.push_back(right_arm_move_group_ptr_->getEndEffectorLink());
|
||||
|
||||
show_pose(left_arm_move_group_ptr_, end_effector_links_[0]);
|
||||
show_pose(right_arm_move_group_ptr_, end_effector_links_[1]);
|
||||
|
||||
left_arm_joint_names_ = left_arm_move_group_ptr_->getJointNames();
|
||||
right_arm_joint_names_ = right_arm_move_group_ptr_->getJointNames();
|
||||
|
||||
// 设置当前MoveGroup 为双臂MoveGroup
|
||||
current_move_group_ptr_ = dual_arm_move_group_ptr_;
|
||||
base_link_ = current_move_group_ptr_->getPlanningFrame();
|
||||
}
|
||||
|
||||
void HcDualArmMotionServer::initSingleMoveGroup( std::shared_ptr<moveit::planning_interface::MoveGroupInterface>& move_group_ptr_,const std::string& planning_group)
|
||||
{
|
||||
move_group_ptr_ = std::make_shared<moveit::planning_interface::MoveGroupInterface>(std::shared_ptr<rclcpp::Node>(this, [](auto*) {}), planning_group);
|
||||
move_group_ptr_->setMaxVelocityScalingFactor(max_velocity_scaling_);
|
||||
move_group_ptr_->setMaxAccelerationScalingFactor(max_acceleration_scaling_);
|
||||
move_group_ptr_->setPlanningTime(planning_time_);
|
||||
move_group_ptr_->setNumPlanningAttempts(num_planning_attempts_);
|
||||
}
|
||||
|
||||
void HcDualArmMotionServer::show_pose(const std::shared_ptr<moveit::planning_interface::MoveGroupInterface>& move_group,
|
||||
const std::string& end_effector_link)
|
||||
{
|
||||
// 获取指定末端连杆的当前位姿
|
||||
geometry_msgs::msg::Pose current_pose = move_group->getCurrentPose(end_effector_link).pose;
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "位姿信息:");
|
||||
RCLCPP_INFO(this->get_logger(), "位置(x=%.3f, y=%.3f, z=%.3f)",current_pose.position.x, current_pose.position.y, current_pose.position.z);
|
||||
RCLCPP_INFO(this->get_logger(), "姿态(x=%.3f, y=%.3f, z=%.3f, w=%.3f)",
|
||||
current_pose.orientation.x, current_pose.orientation.y,
|
||||
current_pose.orientation.z, current_pose.orientation.w);
|
||||
}
|
||||
|
||||
// Action Goal校验
|
||||
rclcpp_action::GoalResponse HcDualArmMotionServer::handle_goal(
|
||||
const rclcpp_action::GoalUUID& uuid,
|
||||
std::shared_ptr<const HcDualArmAction::Goal> goal)
|
||||
{
|
||||
(void)uuid;
|
||||
(void)goal;
|
||||
|
||||
if (is_moving)
|
||||
{
|
||||
RCLCPP_WARN(this->get_logger(), "Robot is already moving");
|
||||
return rclcpp_action::GoalResponse::REJECT;
|
||||
}
|
||||
|
||||
return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
|
||||
}
|
||||
|
||||
// Action Cancel处理
|
||||
rclcpp_action::CancelResponse HcDualArmMotionServer::handle_cancel(
|
||||
const std::shared_ptr<GoalHandleRobotMotion> goal_handle)
|
||||
{
|
||||
RCLCPP_WARN(this->get_logger(), "Received cancel request");
|
||||
current_move_group_ptr_->stop();
|
||||
(void)goal_handle;
|
||||
return rclcpp_action::CancelResponse::ACCEPT;
|
||||
}
|
||||
|
||||
// Action Goal接受后执行
|
||||
void HcDualArmMotionServer::handle_accepted(const std::shared_ptr<GoalHandleRobotMotion> goal_handle)
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(), "handle_accepted");
|
||||
// 异步执行,避免阻塞回调线程
|
||||
std::thread{std::bind(&HcDualArmMotionServer::execute, this, std::placeholders::_1), goal_handle}.detach();
|
||||
}
|
||||
|
||||
// Action核心执行逻辑
|
||||
void HcDualArmMotionServer::execute(const std::shared_ptr<GoalHandleRobotMotion> goal_handle)
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(), "Starting motion execution");
|
||||
const auto goal = goal_handle->get_goal();
|
||||
auto feedback = std::make_shared<HcDualArmAction::Feedback>();
|
||||
auto result = std::make_shared<HcDualArmAction::Result>();
|
||||
|
||||
bool success = execute_arm_motion(goal, feedback, result);
|
||||
|
||||
// 设置Action结果
|
||||
if (rclcpp::ok())
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
goal_handle->succeed(result);
|
||||
RCLCPP_INFO(this->get_logger(), "Motion executed successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
goal_handle->abort(result);
|
||||
RCLCPP_ERROR(this->get_logger(), "Motion execution failed: %s", result->message.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HcDualArmMotionServer::execute_arm_motion(
|
||||
const std::shared_ptr<const HcDualArmAction::Goal> goal,
|
||||
std::shared_ptr<HcDualArmAction::Feedback> feedback,
|
||||
std::shared_ptr<HcDualArmAction::Result> result)
|
||||
{
|
||||
bool success = false;
|
||||
const auto arm_type = static_cast<ArmType>(goal->arm_type);
|
||||
|
||||
switch (arm_type)
|
||||
{
|
||||
case ArmType::LEFT:
|
||||
success = execute_single_arm_motion(goal, feedback, result, arm_type);
|
||||
break;
|
||||
case ArmType::RIGHT:
|
||||
current_move_group_ptr_ = right_arm_move_group_ptr_;
|
||||
success = execute_single_arm_motion(goal, feedback, result, arm_type);
|
||||
break;
|
||||
case ArmType::DUAL:
|
||||
current_move_group_ptr_ = dual_arm_move_group_ptr_;
|
||||
success = execute_dual_arm_motion(goal, feedback, result);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// 执行MoveL
|
||||
bool HcDualArmMotionServer::execute_single_arm_motion(
|
||||
const std::shared_ptr<const HcDualArmAction::Goal> goal,
|
||||
std::shared_ptr<HcDualArmAction::Feedback> feedback,
|
||||
std::shared_ptr<HcDualArmAction::Result> result,
|
||||
ArmType arm_type)
|
||||
{
|
||||
if (goal -> arm_motion_params.size() != 1)
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "invalid arm_motion_params size");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arm_type == ArmType::LEFT)
|
||||
{
|
||||
current_move_group_ptr_ = left_arm_move_group_ptr_;
|
||||
}
|
||||
else if (arm_type == ArmType::RIGHT)
|
||||
{
|
||||
current_move_group_ptr_ = right_arm_move_group_ptr_;
|
||||
}
|
||||
|
||||
current_move_group_ptr_->setMaxVelocityScalingFactor(goal->velocity_scaling);
|
||||
current_move_group_ptr_->setMaxAccelerationScalingFactor(goal->velocity_scaling);
|
||||
|
||||
auto temp_motion_param = goal->arm_motion_params[0];
|
||||
|
||||
auto motion_type = static_cast<MotionType>(temp_motion_param.motion_type);
|
||||
|
||||
if (motion_type == MotionType::MOVEJ)
|
||||
{
|
||||
feedback->progress = 0.0;
|
||||
feedback->status = static_cast<uint8_t>(MotionStatus::PLANNING);
|
||||
|
||||
if (current_move_group_ptr_->getActiveJoints().size() != temp_motion_param.target_joints.size())
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "invalid target_joints size compared with active joints size");
|
||||
return false;
|
||||
}
|
||||
|
||||
current_move_group_ptr_->setJointValueTarget(temp_motion_param.target_joints);
|
||||
|
||||
// TODO: 保留根据笛卡尔空间点进行规划的功能
|
||||
//current_move_group_ptr_->setPoseTarget(goal->target_poses[0]);
|
||||
|
||||
// 3. 规划运动
|
||||
MoveGroupInterface::Plan plan;
|
||||
bool plan_success = (current_move_group_ptr_->plan(plan) == moveit::core::MoveItErrorCode::SUCCESS);
|
||||
if (!plan_success) {
|
||||
result->success = false;
|
||||
result->message = "MoveJ planning failed";
|
||||
result->final_progress = 0.0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 执行运动
|
||||
feedback->progress = 0.5;
|
||||
feedback->status = static_cast<uint8_t>(MotionStatus::EXECUTING);
|
||||
|
||||
current_move_group_ptr_->execute(plan);
|
||||
|
||||
// 5. 设置结果
|
||||
feedback->progress = 1.0;
|
||||
feedback->status = static_cast<uint8_t>(MotionStatus::DONE);
|
||||
|
||||
result->success = true;
|
||||
result->message = "MoveJ executed successfully";
|
||||
result->final_progress = 1.0;
|
||||
return true;
|
||||
}
|
||||
else if (motion_type == MotionType::MOVEL)
|
||||
{
|
||||
feedback->progress = 0.0;
|
||||
feedback->status = static_cast<uint8_t>(MotionStatus::PLANNING);
|
||||
|
||||
// 1. 设置目标位姿
|
||||
geometry_msgs::msg::Pose start_pose = current_move_group_ptr_->getCurrentPose().pose;
|
||||
geometry_msgs::msg::Pose end_pose = temp_motion_param.target_pose;
|
||||
std::vector<geometry_msgs::msg::Pose> waypoints;
|
||||
waypoints.push_back(start_pose);
|
||||
waypoints.push_back(end_pose);
|
||||
|
||||
// 3. 生成笛卡尔路径
|
||||
moveit_msgs::msg::RobotTrajectory trajectory;
|
||||
const double jump_threshold = 0.0;
|
||||
double fraction = current_move_group_ptr_->computeCartesianPath(
|
||||
waypoints, goal->cartesian_step, jump_threshold, trajectory);
|
||||
|
||||
if (fraction < 0.9) {
|
||||
result->success = false;
|
||||
result->message = "MoveL path failed (fraction=" + std::to_string(fraction) + ")";
|
||||
result->final_progress = fraction;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 执行运动
|
||||
feedback->progress = 0.5;
|
||||
feedback->status = static_cast<uint8_t>(MotionStatus::EXECUTING);
|
||||
|
||||
MoveGroupInterface::Plan plan;
|
||||
plan.trajectory_ = trajectory;
|
||||
current_move_group_ptr_->execute(plan);
|
||||
|
||||
// 5. 设置结果
|
||||
feedback->progress = 1.0;
|
||||
feedback->status = static_cast<uint8_t>(MotionStatus::DONE);
|
||||
|
||||
result->success = true;
|
||||
result->message = "MoveL executed successfully (fraction=" + std::to_string(fraction) + ")";
|
||||
result->final_progress = 1.0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HcDualArmMotionServer::execute_dual_arm_motion(const shared_ptr<const HcDualArmAction::Goal> goal, shared_ptr<HcDualArmAction::Feedback> feedback, shared_ptr<HcDualArmAction::Result> result)
|
||||
{
|
||||
current_move_group_ptr_ = dual_arm_move_group_ptr_;
|
||||
|
||||
current_move_group_ptr_->setMaxVelocityScalingFactor(goal->velocity_scaling);
|
||||
current_move_group_ptr_->setMaxAccelerationScalingFactor(goal->velocity_scaling);
|
||||
|
||||
if (goal->arm_motion_params.size() != 2)
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "invalid arm_motion_params size");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (goal->arm_motion_params[0].arm_id != 0 || goal->arm_motion_params[1].arm_id != 1)
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "invalid arm_id");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (goal->arm_motion_params[0].motion_type != goal->arm_motion_params[1].motion_type)
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "invalid motion_type");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto motion_type = static_cast<MotionType>(goal->arm_motion_params[0].motion_type);
|
||||
|
||||
if (motion_type == MotionType::MOVEJ)
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(), "---------------------- execute dual arm motion movej -------------------");
|
||||
feedback->progress = 0.0;
|
||||
feedback->status = static_cast<uint8_t>(MotionStatus::PLANNING);
|
||||
|
||||
auto total_target_joints = goal->arm_motion_params[0].target_joints;
|
||||
total_target_joints.insert(total_target_joints.end(), goal->arm_motion_params[1].target_joints.begin(), goal->arm_motion_params[1].target_joints.end());
|
||||
|
||||
if (total_target_joints.size() != current_move_group_ptr_->getActiveJoints().size())
|
||||
{
|
||||
RCLCPP_ERROR(this->get_logger(), "invalid target_joints size compared with active joints size");
|
||||
return false;
|
||||
}
|
||||
|
||||
current_move_group_ptr_->setJointValueTarget(total_target_joints);
|
||||
|
||||
// 3. 规划运动
|
||||
MoveGroupInterface::Plan plan;
|
||||
bool plan_success = (current_move_group_ptr_->plan(plan) == moveit::core::MoveItErrorCode::SUCCESS);
|
||||
if (!plan_success) {
|
||||
result->success = false;
|
||||
result->message = "MoveJ planning failed";
|
||||
result->final_progress = 0.0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 执行运动
|
||||
feedback->progress = 0.5;
|
||||
feedback->status = static_cast<uint8_t>(MotionStatus::EXECUTING);
|
||||
current_move_group_ptr_->execute(plan);
|
||||
feedback->progress = 1.0;
|
||||
feedback->status = static_cast<uint8_t>(MotionStatus::DONE);
|
||||
result->success = true;
|
||||
result->message = "MoveJ executed successfully";
|
||||
result->final_progress = 1.0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (motion_type == MotionType::MOVEL)
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(), "---------------------- execute dual arm motion moveL -------------------");
|
||||
feedback->progress = 0.0;
|
||||
feedback->status = static_cast<uint8_t>(MotionStatus::PLANNING);
|
||||
|
||||
// 左手臂规划组(需在SRDF中配置left_arm规划组)
|
||||
left_arm_move_group_ptr_ -> setMaxVelocityScalingFactor(goal->velocity_scaling);
|
||||
left_arm_move_group_ptr_ -> setMaxAccelerationScalingFactor(goal->acceleration_scaling);
|
||||
left_arm_move_group_ptr_ -> setPlanningTime(10.0); // 增加规划时间
|
||||
|
||||
// 右手臂规划组(需在SRDF中配置right_arm规划组)
|
||||
right_arm_move_group_ptr_ -> setMaxVelocityScalingFactor(goal->velocity_scaling);
|
||||
right_arm_move_group_ptr_ -> setMaxAccelerationScalingFactor(goal->acceleration_scaling);
|
||||
right_arm_move_group_ptr_ -> setPlanningTime(10.0); // 增加规划时间
|
||||
|
||||
left_arm_move_group_ptr_ -> clearPoseTargets();
|
||||
left_arm_move_group_ptr_ -> clearPathConstraints();
|
||||
right_arm_move_group_ptr_ -> clearPoseTargets();
|
||||
right_arm_move_group_ptr_ -> clearPathConstraints();
|
||||
|
||||
// 1. 等待TF变换就绪(base_link → 左右末端)
|
||||
tf2_ros::Buffer tf_buffer(this->get_clock());
|
||||
tf2_ros::TransformListener tf_listener(tf_buffer);
|
||||
bool tf_ready = true;
|
||||
try {
|
||||
// 等待左末端TF(超时5秒)
|
||||
tf_buffer.lookupTransform("base_link", end_effector_links_[0], tf2::TimePointZero, tf2::durationFromSec(5.0));
|
||||
// 等待右末端TF
|
||||
tf_buffer.lookupTransform("base_link", end_effector_links_[1], tf2::TimePointZero, tf2::durationFromSec(5.0));
|
||||
} catch (tf2::TransformException &ex) {
|
||||
RCLCPP_ERROR(this->get_logger(), "TF lookup failed: %s", ex.what());
|
||||
tf_ready = false;
|
||||
}
|
||||
if (!tf_ready) {
|
||||
result->success = false;
|
||||
result->message = "TF transform not ready (dirty robot state)";
|
||||
result->final_progress = 0.0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 强制初始化机器人状态
|
||||
moveit::core::RobotStatePtr left_state = left_arm_move_group_ptr_ -> getCurrentState(10.0); // 超时10秒
|
||||
moveit::core::RobotStatePtr right_state = right_arm_move_group_ptr_ -> getCurrentState(10.0);
|
||||
if (!left_state || !right_state || !left_state->satisfiesBounds() || !right_state->satisfiesBounds()) {
|
||||
RCLCPP_ERROR(this->get_logger(), "Invalid/dirty robot state (NaN joint angles)");
|
||||
result->success = false;
|
||||
result->message = "Dirty robot state (invalid joint/transform)";
|
||||
result->final_progress = 0.0;
|
||||
return false;
|
||||
}
|
||||
// 更新状态变换
|
||||
left_state->updateLinkTransforms();
|
||||
right_state->updateLinkTransforms();
|
||||
left_arm_move_group_ptr_ -> setStartState(*left_state);
|
||||
right_arm_move_group_ptr_ -> setStartState(*right_state);
|
||||
|
||||
// 左手臂设置目标位姿
|
||||
left_arm_move_group_ptr_ -> setPoseTarget(goal->arm_motion_params[0].target_pose);
|
||||
moveit::planning_interface::MoveGroupInterface::Plan left_plan;
|
||||
bool left_plan_success = (left_arm_move_group_ptr_ -> plan(left_plan) == moveit::core::MoveItErrorCode::SUCCESS);
|
||||
|
||||
// 右手臂设置目标位姿
|
||||
right_arm_move_group_ptr_ -> setPoseTarget(goal->arm_motion_params[1].target_pose);
|
||||
moveit::planning_interface::MoveGroupInterface::Plan right_plan;
|
||||
bool right_plan_success = (right_arm_move_group_ptr_ -> plan(right_plan) == moveit::core::MoveItErrorCode::SUCCESS);
|
||||
|
||||
// 检查规划结果
|
||||
if (!left_plan_success || !right_plan_success) {
|
||||
RCLCPP_ERROR(this->get_logger(), "MoveL planning failed: left=%d, right=%d", left_plan_success, right_plan_success);
|
||||
result->success = false;
|
||||
result->message = "MoveL planning failed (left/right arm)";
|
||||
result->final_progress = 0.0;
|
||||
return false;
|
||||
}
|
||||
|
||||
feedback->progress = 0.5;
|
||||
feedback->status = static_cast<uint8_t>(MotionStatus::EXECUTING);
|
||||
|
||||
|
||||
// 方式2:精准同步(合并轨迹,需整体规划组,可选)
|
||||
moveit_msgs::msg::RobotTrajectory merged_traj = mergeTrajectories(left_plan.trajectory_, right_plan.trajectory_);
|
||||
dual_arm_move_group_ptr_ -> execute(merged_traj);
|
||||
|
||||
// ========== 设置最终结果 ==========
|
||||
feedback->progress = 1.0;
|
||||
feedback->status = static_cast<uint8_t>(MotionStatus::DONE);
|
||||
|
||||
result->success = true;
|
||||
result->message = "MoveL executed successfully";
|
||||
result->final_progress = 1.0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
MoveGroupInterface::Plan HcDualArmMotionServer::single_arm_plan(MoveGroupInterface& move_group, ArmMotionParams motion_Params, double step_value)
|
||||
{
|
||||
// 初始化路点列表
|
||||
std::vector<geometry_msgs::msg::Pose> waypoints;
|
||||
geometry_msgs::msg::Pose current_pose = move_group.getCurrentPose().pose;
|
||||
waypoints.push_back(current_pose);
|
||||
waypoints.push_back(motion_Params.target_pose);
|
||||
|
||||
// 路径规划参数
|
||||
double plan_fraction = 0.0; // 路径覆盖率(1.0=完全覆盖)
|
||||
const int max_attempts = 10; // 最大规划尝试次数
|
||||
int attempts = 0;
|
||||
|
||||
// 设置起始状态为当前机械臂状态
|
||||
move_group.setStartStateToCurrentState();
|
||||
|
||||
MoveGroupInterface::Plan plan;
|
||||
|
||||
// 循环尝试规划笛卡尔路径
|
||||
while(plan_fraction < 1.0 && attempts < max_attempts)
|
||||
{
|
||||
plan_fraction = move_group.computeCartesianPath(
|
||||
waypoints, // 路点列表
|
||||
step_value, // 终端步进值(米)
|
||||
0.0, // 跳跃阈值(禁用)
|
||||
plan.trajectory_,// 输出轨迹
|
||||
true); // 启用避障
|
||||
|
||||
attempts++;
|
||||
// 每10次打印一次进度
|
||||
if(attempts % 5 == 0)
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(), "尝试次数: %d, 覆盖率: %f", attempts, plan_fraction);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 检查规划结果
|
||||
if(plan_fraction == 1.0)
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(),"笛卡尔路径规划成功!");
|
||||
}
|
||||
else
|
||||
{
|
||||
RCLCPP_INFO(this->get_logger(), "路径规划失败,最终覆盖率: %f", plan_fraction);
|
||||
}
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
||||
moveit_msgs::msg::RobotTrajectory HcDualArmMotionServer::mergeTrajectories(
|
||||
const moveit_msgs::msg::RobotTrajectory& left_traj,
|
||||
const moveit_msgs::msg::RobotTrajectory& right_traj)
|
||||
{
|
||||
moveit_msgs::msg::RobotTrajectory merged_traj;
|
||||
// 1. 合并关节名(左+右)
|
||||
merged_traj.joint_trajectory.joint_names = left_traj.joint_trajectory.joint_names;
|
||||
merged_traj.joint_trajectory.joint_names.insert(
|
||||
merged_traj.joint_trajectory.joint_names.end(),
|
||||
right_traj.joint_trajectory.joint_names.begin(),
|
||||
right_traj.joint_trajectory.joint_names.end()
|
||||
);
|
||||
|
||||
// 2. 对齐时间戳(取最长轨迹时长)
|
||||
double left_duration = left_traj.joint_trajectory.points.back().time_from_start.sec;
|
||||
double right_duration = right_traj.joint_trajectory.points.back().time_from_start.sec;
|
||||
double max_duration = std::max(left_duration, right_duration);
|
||||
|
||||
// 3. 缩放轨迹时间(使左右臂轨迹时长一致)
|
||||
moveit_msgs::msg::RobotTrajectory scaled_left = scaleTrajectoryTime(left_traj, max_duration);
|
||||
moveit_msgs::msg::RobotTrajectory scaled_right = scaleTrajectoryTime(right_traj, max_duration);
|
||||
|
||||
// 4. 合并轨迹点(逐点拼接关节值)
|
||||
for (size_t i = 0; i < scaled_left.joint_trajectory.points.size(); ++i) {
|
||||
trajectory_msgs::msg::JointTrajectoryPoint merged_point;
|
||||
// 左手臂关节值
|
||||
merged_point.positions = scaled_left.joint_trajectory.points[i].positions;
|
||||
merged_point.velocities = scaled_left.joint_trajectory.points[i].velocities;
|
||||
merged_point.accelerations = scaled_left.joint_trajectory.points[i].accelerations;
|
||||
// 右手臂关节值
|
||||
merged_point.positions.insert(
|
||||
merged_point.positions.end(),
|
||||
scaled_right.joint_trajectory.points[i].positions.begin(),
|
||||
scaled_right.joint_trajectory.points[i].positions.end()
|
||||
);
|
||||
merged_point.velocities.insert(
|
||||
merged_point.velocities.end(),
|
||||
scaled_right.joint_trajectory.points[i].velocities.begin(),
|
||||
scaled_right.joint_trajectory.points[i].velocities.end()
|
||||
);
|
||||
merged_point.accelerations.insert(
|
||||
merged_point.accelerations.end(),
|
||||
scaled_right.joint_trajectory.points[i].accelerations.begin(),
|
||||
scaled_right.joint_trajectory.points[i].accelerations.end()
|
||||
);
|
||||
// 时间戳
|
||||
merged_point.time_from_start = scaled_left.joint_trajectory.points[i].time_from_start;
|
||||
merged_traj.joint_trajectory.points.push_back(merged_point);
|
||||
}
|
||||
|
||||
return merged_traj;
|
||||
}
|
||||
|
||||
moveit_msgs::msg::RobotTrajectory HcDualArmMotionServer::scaleTrajectoryTime(
|
||||
const moveit_msgs::msg::RobotTrajectory& traj, double target_duration)
|
||||
{
|
||||
moveit_msgs::msg::RobotTrajectory scaled_traj = traj;
|
||||
double original_duration = traj.joint_trajectory.points.back().time_from_start.sec;
|
||||
double scale = target_duration / original_duration;
|
||||
|
||||
for (auto& point : scaled_traj.joint_trajectory.points) {
|
||||
point.time_from_start = rclcpp::Duration::from_seconds(point.time_from_start.sec * scale);
|
||||
for (auto& vel : point.velocities) vel /= scale;
|
||||
for (auto& acc : point.accelerations) acc /= (scale * scale);
|
||||
}
|
||||
return scaled_traj;
|
||||
}
|
||||
|
||||
|
||||
void HcDualArmMotionServer::joy_callback(const sensor_msgs::msg::Joy::SharedPtr msg)
|
||||
{
|
||||
// 按键映射:btn0=A, btn1=B, btn2=X
|
||||
static bool last_btn0 = false; // 防抖:避免重复触发
|
||||
static bool last_btn1 = false;
|
||||
static bool last_btn2 = false;
|
||||
static bool last_btn3 = false;
|
||||
|
||||
bool trigger_movej = (msg->buttons[0] == 1) && !last_btn0;
|
||||
bool trigger_movel = (msg->buttons[1] == 1) && !last_btn1;
|
||||
bool trigger_movel2 = (msg->buttons[3] == 1) && !last_btn3;
|
||||
bool trigger_cancel = (msg->buttons[2] == 1) && !last_btn2;
|
||||
|
||||
|
||||
|
||||
// 更新防抖状态
|
||||
last_btn0 = (msg->buttons[0] == 1);
|
||||
last_btn1 = (msg->buttons[1] == 1);
|
||||
last_btn2 = (msg->buttons[2] == 1);
|
||||
last_btn3 = (msg->buttons[3] == 1);
|
||||
|
||||
// 取消运动(简化版)
|
||||
if (trigger_cancel) {
|
||||
RCLCPP_INFO(this->get_logger(), "Joy trigger: cancel motion");
|
||||
current_move_group_ptr_->stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// 触发MoveJ:通过Action Client发送Goal
|
||||
if (trigger_movej) {
|
||||
RCLCPP_INFO(this->get_logger(), "Joy trigger: execute MoveJ");
|
||||
|
||||
ArmMotionParams tempParam;
|
||||
tempParam.motion_type = static_cast<uint8_t>(MotionType::MOVEJ);
|
||||
tempParam.arm_id = 0;
|
||||
tempParam.target_joints = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
|
||||
|
||||
ArmMotionParams tempParam2;
|
||||
tempParam2.motion_type = static_cast<uint8_t>(MotionType::MOVEJ);
|
||||
tempParam2.arm_id = 1;
|
||||
tempParam2.target_joints = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
|
||||
|
||||
auto goal_msg = HcDualArmAction::Goal();
|
||||
goal_msg.arm_type = static_cast<uint8_t>(ArmType::DUAL);
|
||||
goal_msg.arm_motion_params.push_back(tempParam);
|
||||
goal_msg.arm_motion_params.push_back(tempParam2);
|
||||
goal_msg.velocity_scaling = velocity_scaling_;
|
||||
goal_msg.cartesian_step = cartesian_step_;
|
||||
|
||||
// 配置Goal发送选项(可选:添加回调监听结果)
|
||||
auto send_goal_options = rclcpp_action::Client<HcDualArmAction>::SendGoalOptions();
|
||||
send_goal_options.goal_response_callback = [this](const rclcpp_action::ClientGoalHandle<HcDualArmAction>::SharedPtr& goal_handle) {
|
||||
if (!goal_handle) {
|
||||
RCLCPP_ERROR(this->get_logger(), "MoveJ Goal rejected by server");
|
||||
} else {
|
||||
RCLCPP_INFO(this->get_logger(), "MoveJ Goal accepted by server");
|
||||
}
|
||||
};
|
||||
send_goal_options.result_callback = [this](const rclcpp_action::ClientGoalHandle<HcDualArmAction>::WrappedResult& result) {
|
||||
switch (result.code) {
|
||||
case rclcpp_action::ResultCode::SUCCEEDED:
|
||||
RCLCPP_INFO(this->get_logger(), "MoveJ executed successfully");
|
||||
break;
|
||||
case rclcpp_action::ResultCode::ABORTED:
|
||||
RCLCPP_ERROR(this->get_logger(), "MoveJ aborted: %s", result.result->message.c_str());
|
||||
break;
|
||||
case rclcpp_action::ResultCode::CANCELED:
|
||||
RCLCPP_WARN(this->get_logger(), "MoveJ canceled");
|
||||
break;
|
||||
default:
|
||||
RCLCPP_ERROR(this->get_logger(), "MoveJ unknown result code");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// 发送Goal(框架会自动调用handle_goal→handle_accepted→execute)
|
||||
action_client_ptr_->async_send_goal(goal_msg, send_goal_options);
|
||||
}
|
||||
|
||||
// 触发MoveL:通过Action Client发送Goal
|
||||
if (trigger_movel) {
|
||||
RCLCPP_INFO(this->get_logger(), "Joy trigger: execute MoveL");
|
||||
ArmMotionParams tempParam;
|
||||
tempParam.motion_type = static_cast<uint8_t>(MotionType::MOVEL);
|
||||
tempParam.arm_id = 0;
|
||||
current_move_group_ptr_ = dual_arm_move_group_ptr_;
|
||||
auto current_pose = current_move_group_ptr_->getCurrentPose(end_effector_links_[0]).pose;
|
||||
current_pose.position.z += 0.2;
|
||||
tempParam.target_pose = current_pose;
|
||||
|
||||
ArmMotionParams tempParam2;
|
||||
tempParam2.motion_type = static_cast<uint8_t>(MotionType::MOVEL);
|
||||
tempParam2.arm_id = 1;
|
||||
current_move_group_ptr_ = dual_arm_move_group_ptr_;
|
||||
auto current_pose2 = current_move_group_ptr_->getCurrentPose(end_effector_links_[1]).pose;
|
||||
current_pose2.position.z += 0.3;
|
||||
tempParam2.target_pose = current_pose2;
|
||||
|
||||
auto goal_msg = HcDualArmAction::Goal();
|
||||
try
|
||||
{
|
||||
goal_msg.arm_type = static_cast<uint8_t>(ArmType::DUAL);
|
||||
goal_msg.arm_motion_params.push_back(tempParam);
|
||||
goal_msg.arm_motion_params.push_back(tempParam2);
|
||||
} catch (const std::exception& e) {
|
||||
RCLCPP_ERROR(this->get_logger(), "Failed to get current pose: %s", e.what());
|
||||
return;
|
||||
}
|
||||
goal_msg.velocity_scaling = velocity_scaling_;
|
||||
goal_msg.cartesian_step = cartesian_step_;
|
||||
|
||||
// 配置Goal发送选项
|
||||
auto send_goal_options = rclcpp_action::Client<HcDualArmAction>::SendGoalOptions();
|
||||
send_goal_options.goal_response_callback = [this](const rclcpp_action::ClientGoalHandle<HcDualArmAction>::SharedPtr& goal_handle) {
|
||||
if (!goal_handle) {
|
||||
RCLCPP_ERROR(this->get_logger(), "MoveL Goal rejected by server");
|
||||
} else {
|
||||
RCLCPP_INFO(this->get_logger(), "MoveL Goal accepted by server");
|
||||
}
|
||||
};
|
||||
send_goal_options.result_callback = [this](const rclcpp_action::ClientGoalHandle<HcDualArmAction>::WrappedResult& result) {
|
||||
switch (result.code) {
|
||||
case rclcpp_action::ResultCode::SUCCEEDED:
|
||||
RCLCPP_INFO(this->get_logger(), "MoveL executed successfully");
|
||||
break;
|
||||
case rclcpp_action::ResultCode::ABORTED:
|
||||
RCLCPP_ERROR(this->get_logger(), "MoveL aborted: %s", result.result->message.c_str());
|
||||
break;
|
||||
case rclcpp_action::ResultCode::CANCELED:
|
||||
RCLCPP_WARN(this->get_logger(), "MoveL canceled");
|
||||
break;
|
||||
default:
|
||||
RCLCPP_ERROR(this->get_logger(), "MoveL unknown result code");
|
||||
break;
|
||||
}
|
||||
};
|
||||
// 发送Goal
|
||||
action_client_ptr_->async_send_goal(goal_msg, send_goal_options);
|
||||
}
|
||||
|
||||
if (trigger_movel2) {
|
||||
RCLCPP_INFO(this->get_logger(), "Joy trigger: execute MoveL");
|
||||
ArmMotionParams tempParam;
|
||||
tempParam.motion_type = static_cast<uint8_t>(MotionType::MOVEL);
|
||||
tempParam.arm_id = 0;
|
||||
current_move_group_ptr_ = dual_arm_move_group_ptr_;
|
||||
auto current_pose = current_move_group_ptr_->getCurrentPose(end_effector_links_[0]).pose;
|
||||
current_pose.position.z -= 0.2;
|
||||
tempParam.target_pose = current_pose;
|
||||
|
||||
ArmMotionParams tempParam2;
|
||||
tempParam2.motion_type = static_cast<uint8_t>(MotionType::MOVEL);
|
||||
tempParam2.arm_id = 1;
|
||||
current_move_group_ptr_ = dual_arm_move_group_ptr_;
|
||||
auto current_pose2 = current_move_group_ptr_->getCurrentPose(end_effector_links_[1]).pose;
|
||||
current_pose2.position.z -= 0.3;
|
||||
tempParam2.target_pose = current_pose2;
|
||||
|
||||
auto goal_msg = HcDualArmAction::Goal();
|
||||
try
|
||||
{
|
||||
goal_msg.arm_type = static_cast<uint8_t>(ArmType::DUAL);
|
||||
goal_msg.arm_motion_params.push_back(tempParam);
|
||||
goal_msg.arm_motion_params.push_back(tempParam2);
|
||||
} catch (const std::exception& e) {
|
||||
RCLCPP_ERROR(this->get_logger(), "Failed to get current pose: %s", e.what());
|
||||
return;
|
||||
}
|
||||
goal_msg.velocity_scaling = velocity_scaling_;
|
||||
goal_msg.cartesian_step = cartesian_step_;
|
||||
|
||||
// 配置Goal发送选项
|
||||
auto send_goal_options = rclcpp_action::Client<HcDualArmAction>::SendGoalOptions();
|
||||
send_goal_options.goal_response_callback = [this](const rclcpp_action::ClientGoalHandle<HcDualArmAction>::SharedPtr& goal_handle) {
|
||||
if (!goal_handle) {
|
||||
RCLCPP_ERROR(this->get_logger(), "MoveL Goal rejected by server");
|
||||
} else {
|
||||
RCLCPP_INFO(this->get_logger(), "MoveL Goal accepted by server");
|
||||
}
|
||||
};
|
||||
send_goal_options.result_callback = [this](const rclcpp_action::ClientGoalHandle<HcDualArmAction>::WrappedResult& result) {
|
||||
switch (result.code) {
|
||||
case rclcpp_action::ResultCode::SUCCEEDED:
|
||||
RCLCPP_INFO(this->get_logger(), "MoveL executed successfully");
|
||||
break;
|
||||
case rclcpp_action::ResultCode::ABORTED:
|
||||
RCLCPP_ERROR(this->get_logger(), "MoveL aborted: %s", result.result->message.c_str());
|
||||
break;
|
||||
case rclcpp_action::ResultCode::CANCELED:
|
||||
RCLCPP_WARN(this->get_logger(), "MoveL canceled");
|
||||
break;
|
||||
default:
|
||||
RCLCPP_ERROR(this->get_logger(), "MoveL unknown result code");
|
||||
break;
|
||||
}
|
||||
};
|
||||
// 发送Goal
|
||||
action_client_ptr_->async_send_goal(goal_msg, send_goal_options);
|
||||
}
|
||||
}
|
||||
18
src/hc_dual_arm_motion/src/main.cpp
Normal file
18
src/hc_dual_arm_motion/src/main.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <rclcpp/rclcpp.hpp>
|
||||
#include "hc_dual_arm_motion_server.hpp"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
rclcpp::init(argc, argv);
|
||||
|
||||
rclcpp::executors::MultiThreadedExecutor executor;
|
||||
|
||||
auto node = std::make_shared<HcDualArmMotionServer>();
|
||||
executor.add_node(node);
|
||||
|
||||
RCLCPP_INFO(node->get_logger(), "Motion Action Server Node started");
|
||||
executor.spin();
|
||||
|
||||
rclcpp::shutdown();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user