coning.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #!/usr/bin/python
  2. from math import *
  3. from pymavlink.rotmat import Vector3, Matrix3
  4. from numpy import linspace
  5. from visual import *
  6. class Quat:
  7. def __init__(self,w=1.0,x=0.0,y=0.0,z=0.0):
  8. self.w = w
  9. self.x = x
  10. self.y = y
  11. self.z = z
  12. def to_euler(self):
  13. roll = (atan2(2.0*(self.w*self.x + self.y*self.z), 1 - 2.0*(self.x*self.x + self.y*self.y)))
  14. pitch = asin(2.0*(self.w*self.y - self.z*self.x))
  15. yaw = atan2(2.0*(self.w*self.z + self.x*self.y), 1 - 2.0*(self.y*self.y + self.z*self.z))
  16. return Vector3(roll,pitch,yaw)
  17. def from_euler(self,euler):
  18. #(roll,pitch,yaw)
  19. cr2 = cos(euler[0]*0.5)
  20. cp2 = cos(euler[1]*0.5)
  21. cy2 = cos(euler[2]*0.5)
  22. sr2 = sin(euler[0]*0.5)
  23. sp2 = sin(euler[1]*0.5)
  24. sy2 = sin(euler[2]*0.5)
  25. self.w = cr2*cp2*cy2 + sr2*sp2*sy2
  26. self.x = sr2*cp2*cy2 - cr2*sp2*sy2
  27. self.y = cr2*sp2*cy2 + sr2*cp2*sy2
  28. self.z = cr2*cp2*sy2 - sr2*sp2*cy2
  29. return self
  30. def from_axis_angle(self, vec):
  31. theta = vec.length()
  32. if theta == 0:
  33. self.w = 1.0
  34. self.x = 0.0
  35. self.y = 0.0
  36. self.z = 0.0
  37. return
  38. vec_normalized = vec.normalized()
  39. st2 = sin(theta/2.0)
  40. self.w = cos(theta/2.0)
  41. self.x = vec_normalized.x * st2
  42. self.y = vec_normalized.y * st2
  43. self.z = vec_normalized.z * st2
  44. def rotate(self, vec):
  45. r = Quat()
  46. r.from_axis_angle(vec)
  47. q = self * r
  48. self.w = q.w
  49. self.x = q.x
  50. self.y = q.y
  51. self.z = q.z
  52. def to_axis_angle(self):
  53. l = sqrt(self.x**2+self.y**2+self.z**2)
  54. (x,y,z) = (self.x,self.y,self.z)
  55. if l != 0:
  56. temp = 2.0*atan2(l,self.w)
  57. if temp > pi:
  58. temp -= 2*pi
  59. elif temp < -pi:
  60. temp += 2*pi
  61. (x,y,z) = (temp*x/l,temp*y/l,temp*z/l)
  62. return Vector3(x,y,z)
  63. def to_rotation_matrix(self):
  64. m = Matrix3()
  65. yy = self.y**2
  66. yz = self.y * self.z
  67. xx = self.x**2
  68. xy = self.x * self.y
  69. xz = self.x * self.z
  70. wx = self.w * self.x
  71. wy = self.w * self.y
  72. wz = self.w * self.z
  73. zz = self.z**2
  74. m.a.x = 1.0-2.0*(yy + zz)
  75. m.a.y = 2.0*(xy - wz)
  76. m.a.z = 2.0*(xz + wy)
  77. m.b.x = 2.0*(xy + wz)
  78. m.b.y = 1.0-2.0*(xx + zz)
  79. m.b.z = 2.0*(yz - wx)
  80. m.c.x = 2.0*(xz - wy)
  81. m.c.y = 2.0*(yz + wx)
  82. m.c.z = 1.0-2.0*(xx + yy)
  83. return m
  84. def inverse(self):
  85. return Quat(self.w,-self.x,-self.y,-self.z)
  86. def __mul__(self,operand):
  87. ret = Quat()
  88. w1=self.w
  89. x1=self.x
  90. y1=self.y
  91. z1=self.z
  92. w2=operand.w
  93. x2=operand.x
  94. y2=operand.y
  95. z2=operand.z
  96. ret.w = w1*w2 - x1*x2 - y1*y2 - z1*z2
  97. ret.x = w1*x2 + x1*w2 + y1*z2 - z1*y2
  98. ret.y = w1*y2 - x1*z2 + y1*w2 + z1*x2
  99. ret.z = w1*z2 + x1*y2 - y1*x2 + z1*w2
  100. return ret
  101. def __str__(self):
  102. return "Quat(%f, %f, %f, %f)" % (self.w,self.x,self.y,self.z)
  103. def vpy_vec(vec):
  104. return vector(vec.y, -vec.z, -vec.x)
  105. def update_arrows(q,x,y,z):
  106. m = q.to_rotation_matrix().transposed()
  107. x.axis = vpy_vec(m*Vector3(1,0,0))
  108. x.up = vpy_vec(m*Vector3(0,1,0))
  109. y.axis = vpy_vec(m*Vector3(0,1,0))
  110. y.up = vpy_vec(m*Vector3(1,0,0))
  111. z.axis = vpy_vec(m*Vector3(0,0,1))
  112. z.up = vpy_vec(m*Vector3(1,0,0))
  113. class Attitude:
  114. def __init__(self,reference=False):
  115. self.labels = []
  116. self.xarrows = []
  117. self.yarrows = []
  118. self.zarrows = []
  119. self.q = Quat()
  120. self.reference = reference
  121. self.update_arrows()
  122. def add_arrows(self, arrowpos = Vector3(0,0,0), labeltext=None):
  123. if labeltext is not None:
  124. self.labels.append(label(pos = vpy_vec(arrowpos), text=labeltext))
  125. sw = .005 if self.reference else .05
  126. self.xarrows.append(arrow(pos=vpy_vec(arrowpos),color=color.red,opacity=1,shaftwidth=sw))
  127. self.yarrows.append(arrow(pos=vpy_vec(arrowpos),color=color.green,opacity=1,shaftwidth=sw))
  128. self.zarrows.append(arrow(pos=vpy_vec(arrowpos),color=color.blue,opacity=1,shaftwidth=sw))
  129. self.update_arrows()
  130. def rotate(self, vec):
  131. self.q.rotate(vec)
  132. def update_arrows(self):
  133. m = self.q.to_rotation_matrix().transposed()
  134. sl = 1.1 if self.reference else 1.0
  135. for i in self.xarrows:
  136. i.axis = vpy_vec(m*Vector3(sl,0,0))
  137. i.up = vpy_vec(m*Vector3(0,1,0))
  138. for i in self.yarrows:
  139. i.axis = vpy_vec(m*Vector3(0,sl,0))
  140. i.up = vpy_vec(m*Vector3(1,0,0))
  141. for i in self.zarrows:
  142. i.axis = vpy_vec(m*Vector3(0,0,sl))
  143. i.up = vpy_vec(m*Vector3(1,0,0))
  144. for i in self.labels:
  145. i.xoffset = scene.width*0.07
  146. i.yoffset = scene.width*0.1
  147. class Tian_integrator:
  148. def __init__(self, integrate_separately=True):
  149. self.alpha = Vector3(0,0,0)
  150. self.beta = Vector3(0,0,0)
  151. self.last_alpha = Vector3(0,0,0)
  152. self.last_delta_alpha = Vector3(0,0,0)
  153. self.last_sample = Vector3(0,0,0)
  154. self.integrate_separately = integrate_separately
  155. def add_sample(self, sample, dt):
  156. delta_alpha = (self.last_sample+sample)*0.5*dt
  157. self.alpha += delta_alpha
  158. delta_beta = 0.5 * (self.last_alpha + (1.0/6.0)*self.last_delta_alpha)%delta_alpha
  159. if self.integrate_separately:
  160. self.beta += delta_beta
  161. else:
  162. self.alpha += delta_beta
  163. self.last_alpha = self.alpha
  164. self.last_delta_alpha = delta_alpha
  165. self.last_sample = sample
  166. def pop_delta_angles(self):
  167. ret = self.alpha + self.beta
  168. self.alpha.zero()
  169. self.beta.zero()
  170. return ret
  171. filter2p_1khz_30hz_data = {}
  172. def filter2p_1khz_30hz(sample, key):
  173. global filter2p_1khz_30hz_data
  174. if not key in filter2p_1khz_30hz_data:
  175. filter2p_1khz_30hz_data[key] = (0.0,0.0)
  176. (delay_element_1, delay_element_2) = filter2p_1khz_30hz_data[key]
  177. sample_freq = 1000
  178. cutoff_freq = 30
  179. fr = sample_freq // cutoff_freq
  180. ohm = tan(pi/fr)
  181. c = 1.0+2.0*cos(pi/4.0)*ohm + ohm**2
  182. b0 = ohm**2/c
  183. b1 = 2.0*b0
  184. b2 = b0
  185. a1 = 2.0*(ohm**2-1.0)/c
  186. a2 = (1.0-2.0*cos(pi/4.0)*ohm+ohm**2)/c
  187. delay_element_0 = sample - delay_element_1 * a1 - delay_element_2 * a2
  188. output = delay_element_0 * b0 + delay_element_1 * b1 + delay_element_2 * b2
  189. filter2p_1khz_30hz_data[key] = (delay_element_0, delay_element_1)
  190. return output
  191. def filter2p_1khz_30hz_vector3(sample, key):
  192. ret = Vector3()
  193. ret.x = filter2p_1khz_30hz(sample.x, "vec3f"+key+"x")
  194. ret.y = filter2p_1khz_30hz(sample.y, "vec3f"+key+"y")
  195. ret.z = filter2p_1khz_30hz(sample.z, "vec3f"+key+"z")
  196. return ret
  197. reference_attitude = Attitude(True)
  198. uncorrected_attitude_low = Attitude()
  199. uncorrected_attitude_high = Attitude()
  200. corrected_attitude = Attitude()
  201. corrected_attitude_combined = Attitude()
  202. corrected_attitude_integrator = Tian_integrator()
  203. corrected_attitude_integrator_combined = Tian_integrator(integrate_separately = False)
  204. reference_attitude.add_arrows(Vector3(0,-3,0))
  205. uncorrected_attitude_low.add_arrows(Vector3(0,-3,0), "no correction\nlow rate integration\n30hz software LPF @ 1khz\n(ardupilot 2015-02-18)")
  206. reference_attitude.add_arrows(Vector3(0,-1,0))
  207. uncorrected_attitude_high.add_arrows(Vector3(0,-1,0), "no correction\nhigh rate integration")
  208. reference_attitude.add_arrows(Vector3(0,1,0))
  209. corrected_attitude.add_arrows(Vector3(0,1,0), "Tian et al\nseparate integration")
  210. reference_attitude.add_arrows(Vector3(0,3,0))
  211. corrected_attitude_combined.add_arrows(Vector3(0,3,0), "Tian et al\ncombined_integration\n(proposed patch)")
  212. #scene.scale = (0.3,0.3,0.3)
  213. scene.fov = 0.001
  214. scene.forward = (-0.5, -0.5, -1)
  215. coning_frequency_hz = 50
  216. coning_magnitude_rad_s = 2
  217. label_text = (
  218. "coning motion frequency %f hz\n"
  219. "coning motion peak amplitude %f deg/s\n"
  220. "thin arrows are reference attitude"
  221. ) % (coning_frequency_hz, degrees(coning_magnitude_rad_s))
  222. label(pos = vpy_vec(Vector3(0,0,2)), text=label_text)
  223. t = 0.0
  224. dt_10000 = 0.0001
  225. dt_1000 = 0.001
  226. dt_333 = 0.003
  227. accumulated_delta_angle = Vector3(0,0,0)
  228. last_gyro_10000 = Vector3(0,0,0)
  229. last_gyro_1000 = Vector3(0,0,0)
  230. last_filtered_gyro_333 = Vector3(0,0,0)
  231. filtered_gyro = Vector3(0,0,0)
  232. while True:
  233. rate(66)
  234. for i in range(5):
  235. for j in range(3):
  236. for k in range(10):
  237. #vvvvvvvvvv 10 kHz vvvvvvvvvv#
  238. #compute angular rate at current time
  239. gyro = Vector3(sin(t*coning_frequency_hz*2*pi), cos(t*coning_frequency_hz*2*pi),0)*coning_magnitude_rad_s
  240. #integrate reference attitude
  241. reference_attitude.rotate((gyro+last_gyro_10000) * dt_10000 * 0.5)
  242. #increment time
  243. t += dt_10000
  244. last_gyro_10000 = gyro
  245. #vvvvvvvvvv 1 kHz vvvvvvvvvv#
  246. #update filter for sim 1
  247. filtered_gyro = filter2p_1khz_30hz_vector3(gyro, "1")
  248. #update integrator for sim 2
  249. accumulated_delta_angle += (gyro+last_gyro_1000) * dt_1000 * 0.5
  250. #update integrator for sim 3
  251. corrected_attitude_integrator.add_sample(gyro, dt_1000)
  252. #update integrator for sim 4
  253. corrected_attitude_integrator_combined.add_sample(gyro, dt_1000)
  254. last_gyro_1000 = gyro
  255. #vvvvvvvvvv 333 Hz vvvvvvvvvv#
  256. #update sim 1 (leftmost)
  257. uncorrected_attitude_low.rotate((filtered_gyro+last_filtered_gyro_333) * dt_333 * 0.5)
  258. #update sim 2
  259. uncorrected_attitude_high.rotate(accumulated_delta_angle)
  260. accumulated_delta_angle.zero()
  261. #update sim 3
  262. corrected_attitude.rotate(corrected_attitude_integrator.pop_delta_angles())
  263. #update sim 4 (rightmost)
  264. corrected_attitude_combined.rotate(corrected_attitude_integrator_combined.pop_delta_angles())
  265. last_filtered_gyro_333 = filtered_gyro
  266. #vvvvvvvvvv 66 Hz vvvvvvvvvv#
  267. reference_attitude.update_arrows()
  268. corrected_attitude.update_arrows()
  269. corrected_attitude_combined.update_arrows()
  270. uncorrected_attitude_low.update_arrows()
  271. uncorrected_attitude_high.update_arrows()