00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 import roslib
00036 roslib.load_manifest('simulated_quadrotor')
00037 import rospy
00038 import numpy as np
00039 from math import sin, cos, radians, degrees
00040 import tf.transformations as tft
00041 from tf import TransformListener
00042
00043 from nav_msgs.msg import Odometry
00044 from geometry_msgs.msg import TransformStamped
00045 from std_msgs.msg import Bool
00046 from flyer_controller.msg import control_mode_output
00047
00048 from starmac_roslib.pid import PidController
00049
00050 from simulated_quadrotor.models.simple_nonlinear import SimpleNonlinearModel
00051 from simulated_quadrotor.models.linear import LinearModel
00052
00053 class SimAdapter(object):
00054
00055 def __init__(self):
00056 pass
00057
00058 def start(self):
00059 rospy.init_node('sim_adapter')
00060 self.init_params()
00061 self.init_state()
00062 self.init_vars()
00063 self.init_publishers()
00064 self.init_subscribers()
00065 self.init_timers()
00066 rospy.spin()
00067
00068 def init_params(self):
00069 self.param_model = rospy.get_param("~model", "simple_nonlinear")
00070 self.rate = rospy.get_param("~rate", 40)
00071 self.publish_state_estimate = rospy.get_param("~publish_state_estimate", True)
00072 self.publish_odometry_messages = rospy.get_param("~publish_odometry", True)
00073 self.sim_odom_topic = rospy.get_param("~sim_odom_topic", "odom")
00074
00075 def init_state(self):
00076 if self.param_model == "simple_nonlinear":
00077 self.model = SimpleNonlinearModel()
00078 elif self.param_model == "linear":
00079 self.model = LinearModel()
00080 else:
00081 rospy.logerror("Model type '%s' unknown" % self.model)
00082 raise Exception("Model type '%s' unknown" % self.model)
00083
00084 def init_vars(self):
00085 self.latest_cmd_msg = control_mode_output()
00086 self.motor_enable = False
00087 self.thrust_cmd = 0.0
00088 self.tfl = TransformListener()
00089 self.T_vicon_imu = None
00090 self.T_imu_vicon = None
00091 self.T_enu_ned = None
00092
00093 def init_publishers(self):
00094
00095 if self.publish_odometry_messages:
00096 self.pub_odom = rospy.Publisher(self.sim_odom_topic, Odometry)
00097 if self.publish_state_estimate:
00098 self.pub_state = rospy.Publisher('state', TransformStamped)
00099
00100 def init_subscribers(self):
00101
00102 self.control_input_sub = rospy.Subscriber('controller_mux/output', control_mode_output, self.control_input_callback)
00103 self.motor_enable_sub = rospy.Subscriber('teleop_flyer/motor_enable', Bool, self.motor_enable_callback)
00104
00105 def init_timers(self):
00106 self.simulation_timer = rospy.Timer(rospy.Duration(1.0/self.rate), self.simulation_timer_callback)
00107
00108
00109 def control_input_callback(self, msg):
00110 rospy.logdebug('Current command is: ' + str(msg))
00111 self.latest_cmd_msg = msg
00112
00113 def motor_enable_callback(self, msg):
00114 if msg.data != self.motor_enable:
00115
00116 self.motor_enable = msg.data
00117
00118
00119 def simulation_timer_callback(self, event):
00120 if False:
00121 print event.__dict__
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131 if event.last_real is None:
00132 dt = 0.0
00133 else:
00134 dt = (event.current_real - event.last_real).to_sec()
00135 self.update_controller(dt)
00136 self.update_state(dt)
00137
00138 if self.publish_odometry_messages:
00139 self.publish_odometry()
00140 if self.publish_state_estimate:
00141 self.publish_state(event.current_real)
00142
00143 def update_state(self, dt):
00144
00145
00146
00147 self.model.update(dt)
00148
00149 def update_controller(self, dt):
00150 lcm = self.latest_cmd_msg
00151 self.model.set_input(lcm.motors_on, lcm.roll_cmd, lcm.pitch_cmd, lcm.direct_yaw_rate_commands,
00152 lcm.yaw_cmd, lcm.yaw_rate_cmd, lcm.direct_thrust_commands, lcm.alt_cmd, lcm.thrust_cmd)
00153
00154
00155 def publish_odometry(self):
00156 odom_msg = Odometry()
00157 odom_msg.header.stamp = rospy.Time.now()
00158 odom_msg.header.frame_id = "/ned"
00159 odom_msg.child_frame_id = "/simflyer1/flyer_imu"
00160 oppp = odom_msg.pose.pose.position
00161 oppp.x, oppp.y, oppp.z = self.model.get_position()
00162 ottl = odom_msg.twist.twist.linear
00163 ottl.x, ottl.y, ottl.z = self.model.get_velocity()
00164 oppo = odom_msg.pose.pose.orientation
00165 oppo.x, oppo.y, oppo.z, oppo.w = self.model.get_orientation()
00166 otta = odom_msg.twist.twist.angular
00167 otta.x, otta.y, otta.z = self.model.get_angular_velocity()
00168 self.pub_odom.publish(odom_msg)
00169
00170 def publish_state(self, t):
00171 state_msg = TransformStamped()
00172 t_ned_imu = tft.translation_matrix(self.model.get_position())
00173 R_ned_imu = tft.quaternion_matrix(self.model.get_orientation())
00174 T_ned_imu = tft.concatenate_matrices(t_ned_imu, R_ned_imu)
00175
00176 if self.T_imu_vicon is None:
00177
00178 frames = rospy.get_param("frames", None)
00179 ypr = frames['vicon_to_imu']['rotation']
00180 q_vicon_imu = tft.quaternion_from_euler(*[radians(x) for x in ypr], axes='rzyx')
00181 R_vicon_imu = tft.quaternion_matrix(q_vicon_imu)
00182 t_vicon_imu = tft.translation_matrix(frames['vicon_to_imu']['translation'])
00183
00184
00185 self.T_vicon_imu = tft.concatenate_matrices(t_vicon_imu, R_vicon_imu)
00186 self.T_imu_vicon = tft.inverse_matrix(self.T_vicon_imu)
00187 self.T_enu_ned = tft.euler_matrix(radians(90), 0, radians(180), 'rzyx')
00188 rospy.loginfo(str(self.T_enu_ned))
00189 rospy.loginfo(str(self.T_imu_vicon))
00190
00191
00192 T_enu_vicon = tft.concatenate_matrices(self.T_enu_ned, T_ned_imu, self.T_imu_vicon )
00193 state_msg.header.stamp = t
00194 state_msg.header.frame_id = "/enu"
00195 state_msg.child_frame_id = "/simflyer1/flyer_vicon"
00196 stt = state_msg.transform.translation
00197 stt.x, stt.y, stt.z = T_enu_vicon[:3,3]
00198 stro = state_msg.transform.rotation
00199 stro.x, stro.y, stro.z, stro.w = tft.quaternion_from_matrix(T_enu_vicon)
00200
00201 self.pub_state.publish(state_msg)
00202
00203 def get_transform(self, tgt, src):
00204 t = self.tfl.getLatestCommonTime(tgt, src)
00205 t_src_tgt, q_src_tgt = self.tfl.lookupTransform(tgt, src, t)
00206 T_src_tgt =self.tfl.fromTranslationRotation(t_src_tgt, q_src_tgt)
00207 return T_src_tgt
00208
00209 if __name__ == "__main__":
00210 self = SimAdapter()
00211 self.start()