Carma-platform v4.2.0
CARMA Platform is built on robot operating system (ROS) and utilizes open source software (OSS) that enables Cooperative Driving Automation (CDA) features to allow Automated Driving Systems to interact and cooperate with infrastructure and other vehicles through communication.
extract_rpy_from_quat.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2
3# Copyright (C) 2020-2021 LEIDOS.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16
17import rospy
18import rostopic
19import rosgraph
20import sys
21import numpy as np
22from geometry_msgs.msg import Pose
23from geometry_msgs.msg import PoseArray
24from geometry_msgs.msg import Quaternion
25from geometry_msgs.msg import Vector3
26from tf.transformations import euler_from_quaternion, quaternion_from_euler
27
28# USAGE:
29# This script converts geometry_msgs/Quaternion into extrinsic Roll Pitch Yaw values
30# The output is a PoseArray message where the position x,y,z fields are actually set to the RPY values in radians and the orientation field is set to the original quaternion.
31#
32# python extract_rpy_from_quat.py <fully namespaced input topic> <fully namespaced output topic> <string describing the address of quaternion> <optional: string describing address of list which should be used as base reference for element address>
33#
34# Examples:
35# If someone is publishing a PoseStamped topic I would call this like
36# python extract_rpy_from_quat.py /my_in_topic /my_out_topic pose.orientation
37#
38# Or if there was a PoseArray being published I would call it using the list optional arg like
39# python extract_rpy_from_quat.py /my_in_topic /my_out_topic orientation poses
40#
41# To be more specific this is what it would look like for /guidance/base_waypoints running inside carma exec where I copied the script to /opt/carma/maps
42# python extract_rpy_from_quat.py /guidance/base_waypoints /base_waypoint_rpy pose.pose.orientation waypoints
43#
44
46 def __init__(self, pub, element_attr, list_attr=''):
47 self.element_attr_array = element_attr.split('.')
48 self.list_attr_array = list_attr.split('.')
49 self.pub = pub
50
51 def getElementFromAttributeArray(self, attr_array, data):
52 attr_list = []
53 for attr in attr_array:
54 if len(attr_list) == 0:
55 attr_list.append(getattr(data, attr))
56 else:
57 attr_list.append(getattr(attr_list[-1], attr))
58
59 return attr_list[-1]
60
61 def normalize(self, array):
62 """
63 Normalize a 4 element array/list/numpy.array for use as a quaternion
64 :param quat_array: 4 element list/array
65 :returns: normalized array
66 :rtype: numpy array
67 """
68 quat = np.array(array)
69 return quat / np.sqrt(np.dot(quat, quat))
70
71 def convertQuatToVector3(self, quat):
72 orientation_list = [quat.x, quat.y, quat.z, quat.w]
73 orientation_list = self.normalize(orientation_list)
74 (roll, pitch, yaw) = euler_from_quaternion (orientation_list, axes='sxyz')
75 vector_msg = Vector3()
76 vector_msg.x = roll
77 vector_msg.y = pitch
78 vector_msg.z = yaw
79 return vector_msg
80
81 def handle_list(self, msg):
82 list_ele = self.getElementFromAttributeArray(self.list_attr_array, msg)
83
84 pose_array_msg = PoseArray()
85 for e in list_ele:
87 fake_pose = Pose()
88 fake_pose.position = self.convertQuatToVector3(quat)
89 fake_pose.orientation = quat
90 pose_array_msg.poses.append(fake_pose)
91
92 self.pub.publish(pose_array_msg)
93
94 def handle_individual(self, msg):
96
97 pose_array_msg = PoseArray()
98
99 fake_pose = Pose()
100 fake_pose.position = self.convertQuatToVector3(quat)
101 fake_pose.orientation = quat
102 pose_array_msg.poses.append(fake_pose)
103
104 self.pub.publish(pose_array_msg)
105
106
107
108def run(args):
109 rospy.init_node('extract_rpy_from_quat')
110
111 in_topic = args[1]
112 out_topic = args[2]
113 element_accessor = args[3]
114
115 pub = rospy.Publisher(out_topic, PoseArray, queue_size=10)
116
117
118 converter = Converter(pub, element_accessor)
119 callback = converter.handle_individual
120
121 if len(args) == 5:
122 converter = Converter(pub, element_accessor, args[4])
123 callback = converter.handle_list
124
125 print(in_topic)
126 msg_class, _, _ = rostopic.get_topic_class(in_topic, True)
127
128 sub = rospy.Subscriber(in_topic, msg_class, callback)
129
130 r = rospy.Rate(20)
131 while not rospy.is_shutdown():
132 r.sleep()
133
134
135if __name__ == '__main__':
136 try:
137 if (len(sys.argv) < 4 or len(sys.argv) > 5):
138 print('At one-two arguments required extract_rpy_from_quat <in topic> <out topic> <element path> <list path>')
139
140 run(sys.argv)
141 except rospy.ROSInterruptException:
142 print("ROS Exception")
143 pass
144
def getElementFromAttributeArray(self, attr_array, data)
def __init__(self, pub, element_attr, list_attr='')