innosim_vtol_bridge.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 import rospy
4 from sensor_msgs.msg import NavSatFix
5 from geometry_msgs.msg import QuaternionStamped
6 from sensor_msgs.msg import Joy
7 from pyquaternion import Quaternion
8 
9 FRD_FLU = Quaternion(w=0, x=1, y=0, z=0)
10 NED_TO_ENU = Quaternion(w=0, x=0.70711, y=0.70711, z=0)
11 
13  def __init__(self):
14  self.attitude_pub = rospy.Publisher('/sim/attitude', QuaternionStamped, queue_size = 1)
15  self.joy_pub = rospy.Publisher('/sim/actuators', Joy, queue_size = 1)
16  self.gps_pub = rospy.Publisher('/sim/gps_position', NavSatFix, queue_size = 1)
17 
18  rospy.Subscriber('/uav/gps_point', NavSatFix, self.gps_callback)
19  rospy.Subscriber('/uav/attitude', QuaternionStamped, self.attitude_callback)
20  rospy.Subscriber('/uav/actuators', Joy, self.actuators_callback)
21 
22  self.gps_msg = NavSatFix()
23  self.joy = Joy()
24  self.joy.axes = [0] * 9
25 
26  def gps_callback(self, in_msg):
27  self.gps_msg.header.stamp = in_msg.header.stamp
28  self.gps_msg.latitude = in_msg.latitude * 1e-08
29  self.gps_msg.longitude = in_msg.longitude * 1e-08
30  self.gps_msg.altitude = in_msg.altitude * 1e-03 + 6.5
31  self.gps_pub.publish(self.gps_msg)
32 
33  def attitude_callback(self, msg):
34  # We receive altitude in PX4 notation, but we need to publish in ROS notation
35  # So, at first we convert NED to baselink
36  # After that we convert baselink to ENU
37  q = Quaternion(w=msg.quaternion.w,
38  x=msg.quaternion.x,
39  y=msg.quaternion.y,
40  z=msg.quaternion.z)
41 
42  q = NED_TO_ENU * q * FRD_FLU
43 
44  msg.quaternion.w = q.w
45  msg.quaternion.x = q.x
46  msg.quaternion.y = q.y
47  msg.quaternion.z = q.z
48 
49  self.attitude_pub.publish(msg)
50 
51  def actuators_callback(self, actuators):
52  try:
53  if len(actuators.axes) < 4:
54  rospy.logerr_throttle(5, "InnosimUavcanBridge: wrong actuators msg len(axes) < 4")
55  return
56  elif len(actuators.axes) != 8:
57  rospy.logwarn_throttle(5, "InnosimUavcanBridge: wrong airframe. Let it be MC.")
58  except:
59  rospy.logerr_throttle(5, "InnosimUavcanBridge: wrong actuators msg. There is no axes")
60  return
61 
62  MIXER_MIN_MAX = [
63  (0, 1), # 0. FR is normalized into [0, +1], where 0 means turn off
64  (0, 1), # 1. RL is normalized into [0, +1], where 0 means turn off
65  (0, 1), # 2. FL motor is normalized into [0, +1], where 0 means turn off
66  (0, 1), # 3. RR motor is normalized into [0, +1], where 0 means turn off
67  (0, 1), # 4. Aileron is normalized into [0, +1], where 0.5 is a middle position
68  (-1, 1),# 5. Elevator is normalized into [-1, +1], where 0 is a middle position
69  (-1, 1),# 6. Rudder is normalized into [-1, +1], where 0 is a middle position
70  (0, 1), # 7. Pusher is normalized into [0, +1], where 0 means turn off
71  ]
72 
73  # 1. Clamp input data and convert it to the px4 control group format (from -1 to +1)
74  mixer = [0] * min(len(MIXER_MIN_MAX), len(actuators.axes))
75  for idx in range(len(mixer)):
76  mixer[idx] = max(MIXER_MIN_MAX[idx][0], min(actuators.axes[idx], MIXER_MIN_MAX[idx][1]))
77  if len(mixer) == 8:
78  mixer[4] = (mixer[4] - 0.5) * 2
79 
80  # 2. Convert them to the sim format
81  SIM_MAX_VALUES = [
82  15500, # FR, cw, rate, rpm (Front right motor speed)
83  15500, # RL, cw, rate, rpm (Rear left motor speed)
84  15500, # FL, ccw, rate, rpm (Front left motor speed)
85  15500, # RR, ccw, rate, rpm (Rear right motor speed)
86  70, # aileron left, cw, deg
87  70, # aileron right, cw, deg
88  70, # elevator, cw, deg
89  70, # rudder, cw, deg
90  15500 # thrust, pusher, rate, rpm
91  ]
92 
93  for idx in range(min(4, len(mixer))):
94  self.joy.axes[idx] = mixer[idx] * SIM_MAX_VALUES[idx]
95  if len(mixer) == 8:
96  self.joy.axes[4] = mixer[4] * SIM_MAX_VALUES[4]
97  self.joy.axes[5] = -mixer[4] * SIM_MAX_VALUES[5]
98  self.joy.axes[6] = mixer[5] * SIM_MAX_VALUES[6]
99  self.joy.axes[7] = mixer[6] * SIM_MAX_VALUES[7]
100  self.joy.axes[8] = mixer[7] * SIM_MAX_VALUES[8]
101 
102  self.joy_pub.publish(self.joy)
103 
104 
105 if __name__ == '__main__':
106  try:
107  rospy.init_node('innosim_relay', anonymous=True)
108  inno_sim_bridge = InnoSimBridge()
109  rospy.spin()
110  except rospy.ROSInterruptException:
111  pass
112 


inno_sim_interface
Author(s):
autogenerated on Wed Feb 8 2023 03:27:19