Skip to content

Commit 3e1e9d0

Browse files
added C++ version of amr_core with one to one match
1 parent bdd84ba commit 3e1e9d0

30 files changed

+3665
-0
lines changed

.clang-format

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
2+
BasedOnStyle: Google
3+
AccessModifierOffset: -2
4+
ConstructorInitializerIndentWidth: 2
5+
AlignEscapedNewlinesLeft: false
6+
AlignTrailingComments: true
7+
AllowAllParametersOfDeclarationOnNextLine: false
8+
AllowShortIfStatementsOnASingleLine: false
9+
AllowShortLoopsOnASingleLine: false
10+
AllowShortFunctionsOnASingleLine: None
11+
AlwaysBreakTemplateDeclarations: true
12+
AlwaysBreakBeforeMultilineStrings: false
13+
BreakBeforeBinaryOperators: false
14+
BreakBeforeTernaryOperators: false
15+
BreakConstructorInitializersBeforeComma: true
16+
BinPackParameters: true
17+
ColumnLimit: 120
18+
ConstructorInitializerAllOnOneLineOrOnePerLine: true
19+
DerivePointerBinding: false
20+
PointerBindsToType: true
21+
ExperimentalAutoDetectBinPacking: false
22+
IndentCaseLabels: true
23+
MaxEmptyLinesToKeep: 1
24+
NamespaceIndentation: None
25+
ObjCSpaceBeforeProtocolList: true
26+
PenaltyBreakBeforeFirstCallParameter: 19
27+
PenaltyBreakComment: 60
28+
PenaltyBreakString: 1
29+
PenaltyBreakFirstLessLess: 1000
30+
PenaltyExcessCharacter: 1000
31+
PenaltyReturnTypeOnItsOwnLine: 90
32+
SpacesBeforeTrailingComments: 2
33+
Cpp11BracedListStyle: false
34+
Standard: Auto
35+
IndentWidth: 2
36+
TabWidth: 2
37+
UseTab: Never
38+
IndentFunctionDeclarationAfterType: false
39+
SpacesInParentheses: false
40+
SpacesInAngles: false
41+
SpaceInEmptyParentheses: false
42+
SpacesInCStyleCastParentheses: false
43+
SpaceAfterControlStatementKeyword: true
44+
SpaceBeforeAssignmentOperators: true
45+
ContinuationIndentWidth: 4
46+
SortIncludes: false
47+
SpaceAfterCStyleCast: false
48+
49+
# Configure each individual brace in BraceWrapping
50+
BreakBeforeBraces: Custom
51+
52+
# Control of individual brace wrapping cases
53+
BraceWrapping: {
54+
AfterClass: 'true'
55+
AfterControlStatement: 'true'
56+
AfterEnum : 'true'
57+
AfterFunction : 'true'
58+
AfterNamespace : 'true'
59+
AfterStruct : 'true'
60+
AfterUnion : 'true'
61+
BeforeCatch : 'true'
62+
BeforeElse : 'true'
63+
IndentBraces : 'false'
64+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#!/usr/bin/env python3
2+
3+
# Run and send “goto Goal2” once:
4+
# ros2 run amr_core unified_action_client --ros-args -p command_type:=goto_goal -p goal_name:=Goal2 -p exit_on_result:=true
5+
#
6+
# Subscribe to goal poses and send gotoPoint on messages:
7+
# ros2 run amr_core unified_action_client --ros-args -p enable_goal_pose_sub:=true -p goal_pose_topic:=goal_pose
8+
#
9+
# Subscribe to initial poses and send localizeAtPoint on messages:
10+
# ros2 run amr_core unified_action_client --ros-args -p enable_initialpose_sub:=true -p initialpose_topic:=initialpose
11+
#
12+
# Execute a macro or dock:
13+
# ros2 run amr_core unified_action_client --ros-args -p command_type:=execute_macro -p macro_name:=Macro4
14+
# ros2 run amr_core unified_action_client --ros-args -p command_type:=dock -p exit_on_result:=true
15+
16+
17+
import math
18+
import rclpy
19+
from rclpy.node import Node
20+
from rclpy.action import ActionClient
21+
from amr_msgs.action import Action
22+
from geometry_msgs.msg import PoseStamped, PoseWithCovarianceStamped
23+
24+
GOTO_POINT_COMMAND = "doTask gotoPoint "
25+
LOCALIZE_TO_POINT_COMMAND = "localizetopoint "
26+
DEFAULT_GOAL_POSE_TOPIC = "goal_pose"
27+
DEFAULT_INITIAL_POSE_TOPIC = "initialpose"
28+
29+
30+
class UnifiedAmrActionClient(Node):
31+
def __init__(self):
32+
super().__init__("amr_unified_action_client")
33+
# Action client
34+
self._ac = ActionClient(self, Action, "action_server")
35+
36+
# Parameters
37+
self.declare_parameter("enable_goal_pose_sub", False)
38+
self.declare_parameter("enable_initialpose_sub", False)
39+
self.declare_parameter("goal_pose_topic", DEFAULT_GOAL_POSE_TOPIC)
40+
self.declare_parameter("initialpose_topic", DEFAULT_INITIAL_POSE_TOPIC)
41+
self.declare_parameter("command_type", "none") # none|goto_goal|execute_macro|dock
42+
self.declare_parameter("goal_name", "Goal1")
43+
self.declare_parameter("macro_name", "Macro1")
44+
self.declare_parameter("exit_on_result", False)
45+
46+
# Subscriptions (optional)
47+
if self.get_parameter("enable_goal_pose_sub").get_parameter_value().bool_value:
48+
topic = self.get_parameter("goal_pose_topic").get_parameter_value().string_value
49+
self.create_subscription(PoseStamped, topic, self._on_goal_pose, 10)
50+
self.get_logger().info(f"Subscribed to goal pose: {topic}")
51+
52+
if self.get_parameter("enable_initialpose_sub").get_parameter_value().bool_value:
53+
topic = self.get_parameter("initialpose_topic").get_parameter_value().string_value
54+
self.create_subscription(PoseWithCovarianceStamped, topic, self._on_initial_pose, 10)
55+
self.get_logger().info(f"Subscribed to initial pose: {topic}")
56+
57+
# Fire a one-shot command from params if requested
58+
cmd = self.get_parameter("command_type").get_parameter_value().string_value
59+
if cmd == "goto_goal":
60+
name = self.get_parameter("goal_name").get_parameter_value().string_value
61+
self.goto_goal(name)
62+
elif cmd == "execute_macro":
63+
name = self.get_parameter("macro_name").get_parameter_value().string_value
64+
self.execute_macro(name)
65+
elif cmd == "dock":
66+
self.dock()
67+
68+
# ========== High-level commands ==========
69+
def goto_goal(self, name: str):
70+
goal = Action.Goal()
71+
goal.command = "goto " + name
72+
goal.identifier = [f"Arrived at {name}"]
73+
self._send_goal(goal)
74+
75+
def execute_macro(self, name: str):
76+
goal = Action.Goal()
77+
goal.command = "executeMacro " + name
78+
goal.identifier = [f"Completed macro {name}"]
79+
self._send_goal(goal)
80+
81+
def dock(self):
82+
goal = Action.Goal()
83+
goal.command = "dock"
84+
goal.identifier = ["Arrived at dock"]
85+
self._send_goal(goal)
86+
87+
# Pose-based commands (from subscriptions)
88+
def _on_goal_pose(self, msg: PoseStamped):
89+
x = int(msg.pose.position.x * 1000.0)
90+
y = int(msg.pose.position.y * 1000.0)
91+
deg = self._yaw_deg(msg.pose.orientation.w, msg.pose.orientation.x,
92+
msg.pose.orientation.y, msg.pose.orientation.z)
93+
if deg > 180:
94+
deg -= 360
95+
coords = f"{x} {y} {int(deg)}"
96+
goal = Action.Goal()
97+
goal.command = GOTO_POINT_COMMAND + coords
98+
goal.identifier = ["Going to point"]
99+
self._send_goal(goal)
100+
101+
def _on_initial_pose(self, msg: PoseWithCovarianceStamped):
102+
p = msg.pose.pose.position
103+
q = msg.pose.pose.orientation
104+
x = int(p.x * 1000.0)
105+
y = int(p.y * 1000.0)
106+
deg = self._yaw_deg(q.w, q.x, q.y, q.z)
107+
if deg > 180:
108+
deg -= 360
109+
coords = f"{x} {y} {int(deg)} 0 0" # xySpread=0 angleSpread=0
110+
goal = Action.Goal()
111+
goal.command = LOCALIZE_TO_POINT_COMMAND + coords
112+
goal.identifier = ["Localizing at point"]
113+
self._send_goal(goal)
114+
115+
# ========== Action helpers ==========
116+
def _send_goal(self, goal: Action.Goal):
117+
self._ac.wait_for_server()
118+
fut = self._ac.send_goal_async(goal, feedback_callback=self._on_feedback)
119+
fut.add_done_callback(self._on_goal_response)
120+
121+
def _on_goal_response(self, future):
122+
gh = future.result()
123+
if not gh.accepted:
124+
self.get_logger().info("Goal Rejected!")
125+
return
126+
self.get_logger().info(f"Goal: {gh.goal_request.goal.command}")
127+
res_fut = gh.get_result_async()
128+
res_fut.add_done_callback(self._on_result)
129+
130+
def _on_result(self, future):
131+
result = future.result().result
132+
self.get_logger().info(result.res_msg)
133+
if self.get_parameter("exit_on_result").get_parameter_value().bool_value:
134+
rclpy.shutdown()
135+
136+
def _on_feedback(self, fb_msg):
137+
self.get_logger().info(fb_msg.feedback.feed_msg)
138+
139+
# ========== Math ==========
140+
def _yaw_deg(self, rw, rx, ry, rz) -> float:
141+
t3 = +2.0 * (rw * rz + rx * ry)
142+
t4 = +1.0 - 2.0 * (ry * ry + rz * rz)
143+
yaw = round(math.atan2(t3, t4), 5) # radians
144+
return yaw * 57.296 # degrees (approx 180/pi)
145+
146+
147+
def main(args=None):
148+
rclpy.init(args=args)
149+
node = UnifiedAmrActionClient()
150+
rclpy.spin(node)
151+
rclpy.shutdown()
152+
153+
154+
if __name__ == "__main__":
155+
main()

amr_core_cpp/.clang-format

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
2+
BasedOnStyle: Google
3+
AccessModifierOffset: -2
4+
ConstructorInitializerIndentWidth: 2
5+
AlignEscapedNewlinesLeft: false
6+
AlignTrailingComments: true
7+
AllowAllParametersOfDeclarationOnNextLine: false
8+
AllowShortIfStatementsOnASingleLine: false
9+
AllowShortLoopsOnASingleLine: false
10+
AllowShortFunctionsOnASingleLine: None
11+
AlwaysBreakTemplateDeclarations: true
12+
AlwaysBreakBeforeMultilineStrings: false
13+
BreakBeforeBinaryOperators: false
14+
BreakBeforeTernaryOperators: false
15+
BreakConstructorInitializersBeforeComma: true
16+
BinPackParameters: true
17+
ColumnLimit: 120
18+
ConstructorInitializerAllOnOneLineOrOnePerLine: true
19+
DerivePointerBinding: false
20+
PointerBindsToType: true
21+
ExperimentalAutoDetectBinPacking: false
22+
IndentCaseLabels: true
23+
MaxEmptyLinesToKeep: 1
24+
NamespaceIndentation: None
25+
ObjCSpaceBeforeProtocolList: true
26+
PenaltyBreakBeforeFirstCallParameter: 19
27+
PenaltyBreakComment: 60
28+
PenaltyBreakString: 1
29+
PenaltyBreakFirstLessLess: 1000
30+
PenaltyExcessCharacter: 1000
31+
PenaltyReturnTypeOnItsOwnLine: 90
32+
SpacesBeforeTrailingComments: 2
33+
Cpp11BracedListStyle: false
34+
Standard: Auto
35+
IndentWidth: 2
36+
TabWidth: 2
37+
UseTab: Never
38+
IndentFunctionDeclarationAfterType: false
39+
SpacesInParentheses: false
40+
SpacesInAngles: false
41+
SpaceInEmptyParentheses: false
42+
SpacesInCStyleCastParentheses: false
43+
SpaceAfterControlStatementKeyword: true
44+
SpaceBeforeAssignmentOperators: true
45+
ContinuationIndentWidth: 4
46+
SortIncludes: false
47+
SpaceAfterCStyleCast: false
48+
49+
# Configure each individual brace in BraceWrapping
50+
BreakBeforeBraces: Custom
51+
52+
# Control of individual brace wrapping cases
53+
BraceWrapping: {
54+
AfterClass: 'true'
55+
AfterControlStatement: 'true'
56+
AfterEnum : 'true'
57+
AfterFunction : 'true'
58+
AfterNamespace : 'true'
59+
AfterStruct : 'true'
60+
AfterUnion : 'true'
61+
BeforeCatch : 'true'
62+
BeforeElse : 'true'
63+
IndentBraces : 'false'
64+
}

amr_core_cpp/CMakeLists.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
cmake_minimum_required(VERSION 3.8)
2+
project(amr_core_cpp)
3+
4+
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
5+
add_compile_options(-Wall -Wextra -Wpedantic)
6+
endif()
7+
8+
# find dependencies
9+
find_package(ament_cmake REQUIRED)
10+
# uncomment the following section in order to fill in
11+
# further dependencies manually.
12+
# find_package(<dependency> REQUIRED)
13+
14+
if(BUILD_TESTING)
15+
find_package(ament_lint_auto REQUIRED)
16+
# the following line skips the linter which checks for copyrights
17+
# comment the line when a copyright and license is added to all source files
18+
set(ament_cmake_copyright_FOUND TRUE)
19+
# the following line skips cpplint (only works in a git repo)
20+
# comment the line when this package is in a git repo and when
21+
# a copyright and license is added to all source files
22+
set(ament_cmake_cpplint_FOUND TRUE)
23+
ament_lint_auto_find_test_dependencies()
24+
endif()
25+
26+
ament_package()

0 commit comments

Comments
 (0)