PageRenderTime 59ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/9dofAhrs/RazorAhrs.cs

#
C# | 490 lines | 239 code | 70 blank | 181 comment | 24 complexity | d403f8d448718f71ee7b6cd002d4dd88 MD5 | raw file
  1. /*
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License as published by
  4. * the Free Software Foundation; either version 2 of the License, or
  5. * (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful, but
  8. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  9. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  10. * for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License along
  13. * with this program; if not, write to the Free Software Foundation, Inc.,
  14. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. *
  16. *
  17. * Project: 9dof: Razor 9DoF AHRS firmware and NETMF drivers
  18. * Description: This is a collection of files that allows for easy
  19. * NETMf integration with the * Sparkfun 9DoF Razor IMU.
  20. *
  21. * Author(s):
  22. * Chris Seto <chris@chrisseto.com>
  23. * Christian Völlinger <zerov83@googlemail.com>
  24. *
  25. */
  26. using System;
  27. using System.IO.Ports;
  28. using Microsoft.SPOT;
  29. using Microsoft.SPOT.Hardware;
  30. using NineDofAhrs.Extensions;
  31. namespace NineDofAhrs
  32. {
  33. /// <summary>
  34. /// Class to parse serial output of Sparkfun 9DOF Razor AHRS
  35. /// Call ParseData() before you want to use new data!
  36. /// </summary>
  37. public class RazorAhrs : IAhrs
  38. {
  39. /// <summary>
  40. /// Serial port handle for the 9DoF
  41. /// </summary>
  42. private readonly SerialPort serialHandle;
  43. /// <summary>
  44. /// USed to reset the 9DoF
  45. /// </summary>
  46. private readonly Cpu.Pin dtr;
  47. /// <summary>
  48. ///
  49. /// </summary>
  50. private readonly byte[] receiveBuffer = new byte[80];
  51. /// <summary>
  52. ///
  53. /// </summary>
  54. private readonly char[] receivedChars = new char[80];
  55. /// <summary>
  56. ///
  57. /// </summary>
  58. private readonly char[] parseBuffer = new char[80];
  59. /// <summary>
  60. ///
  61. /// </summary>
  62. private int receiveIndex = 0;
  63. /// <summary>
  64. ///
  65. /// </summary>
  66. private bool haveToParse = false;
  67. /// <summary>
  68. ///
  69. /// </summary>
  70. private ParserState imuState = ParserState.FindPre;
  71. /// <summary>
  72. ///
  73. /// </summary>
  74. private static readonly char[] pree = { '!', 'A', 'N', 'G', ':' };
  75. /// <summary>
  76. ///
  77. /// </summary>
  78. private int preeIndex = 0;
  79. /// <summary>
  80. ///
  81. /// </summary>
  82. private const string analogsPree = ",AN:";
  83. /// <summary>
  84. ///
  85. /// </summary>
  86. private const string productSring = "Sparkfun 9DOF Razor AHRS";
  87. /// <summary>
  88. ///
  89. /// </summary>
  90. public bool HasValidData = false;
  91. /// <summary>
  92. ///
  93. /// </summary>
  94. public float Roll;
  95. /// <summary>
  96. ///
  97. /// </summary>
  98. public float Pitch;
  99. /// <summary>
  100. ///
  101. /// </summary>
  102. public float Yaw;
  103. /// <summary>
  104. /// AccX, AccY, AccZ, AnX, AnY, AnZ
  105. /// </summary>
  106. public int[] Offsets = new int[6];
  107. /// <summary>
  108. ///
  109. /// </summary>
  110. public int AccX;
  111. /// <summary>
  112. ///
  113. /// </summary>
  114. public int AccY;
  115. /// <summary>
  116. ///
  117. /// </summary>
  118. public int AccZ;
  119. /// <summary>
  120. ///
  121. /// </summary>
  122. public int AnX;
  123. /// <summary>
  124. ///
  125. /// </summary>
  126. public int AnY;
  127. /// <summary>
  128. ///
  129. /// </summary>
  130. public int AnZ;
  131. /// <summary>
  132. ///
  133. /// </summary>
  134. public int MagX;
  135. /// <summary>
  136. ///
  137. /// </summary>
  138. public int MagY;
  139. /// <summary>
  140. ///
  141. /// </summary>
  142. public int MagZ;
  143. /// <summary>
  144. /// Are we going to parse analog outputs?
  145. /// </summary>
  146. private readonly bool ParseAnalogs = false;
  147. /// <summary>
  148. /// Parser phases
  149. /// </summary>
  150. private enum ParserState
  151. {
  152. Start,
  153. FindOffsets,
  154. FindPre,
  155. ParseEuler
  156. }
  157. /// <summary>
  158. ///
  159. /// </summary>
  160. public int dataReceived { get; set; }
  161. /// <summary>
  162. ///
  163. /// </summary>
  164. private bool ApplyOffsets = true;
  165. /// <summary>
  166. ///
  167. /// </summary>
  168. /// <param name="comPort">Com port. "COM1"</param>
  169. /// <param name="parseAnalogs">true, if the analogdata of the gyros should also be parsed</param>
  170. public RazorAhrs(string comPort, bool parseAnalogs)
  171. {
  172. ParseAnalogs = parseAnalogs;
  173. serialHandle = new SerialPort(comPort, 57600, Parity.None, 8, StopBits.One);
  174. Initialize();
  175. }
  176. /// <summary>
  177. ///
  178. /// </summary>
  179. /// <param name="com"></param>
  180. /// <param name="parseAnalogs"></param>
  181. /// <param name="dtr"></param>
  182. public RazorAhrs(string com, bool parseAnalogs, Cpu.Pin dtr) : this(com, parseAnalogs)
  183. {
  184. dtr = dtr;
  185. }
  186. /// <summary>
  187. ///
  188. /// </summary>
  189. /// <param name="reset"></param>
  190. private void Initialize(bool reset = true)
  191. {
  192. serialHandle.ReadTimeout = 0;
  193. if (reset)
  194. Reset();
  195. // If you open the port after you set the event you will endup with problems
  196. serialHandle.Open();
  197. serialHandle.DiscardInBuffer();
  198. // Subscribe to RX events
  199. serialHandle.DataReceived += PortDataReceived;
  200. serialHandle.ErrorReceived += PortErrorReceived;
  201. }
  202. /// <summary>
  203. /// Reset the 9DoF
  204. /// </summary>
  205. private void Reset()
  206. {
  207. OutputPort dtr = new OutputPort(dtr, false);
  208. System.Threading.Thread.Sleep(1);
  209. dtr.Write(true);
  210. dtr.Dispose();
  211. }
  212. /// <summary>
  213. /// Parse recived data
  214. /// </summary>
  215. /// <param name="sender"></param>
  216. /// <param name="e"></param>
  217. void PortDataReceived(object sender, SerialDataReceivedEventArgs e)
  218. {
  219. int bufferIndex = 0;
  220. byte offsetIndex = 0;
  221. int dataReceived;
  222. dataReceived = serialHandle.Read(receiveBuffer, 0, receiveBuffer.Length);
  223. while (bufferIndex < dataReceived)
  224. {
  225. switch (imuState)
  226. {
  227. // Looking for IMU startup
  228. case ParserState.Start:
  229. if (this.receiveBuffer[bufferIndex] == productSring[preeIndex])
  230. {
  231. preeIndex++;
  232. if (this.preeIndex >= productSring.Length)
  233. {
  234. imuState = ParserState.FindOffsets;
  235. preeIndex = 0;
  236. }
  237. }
  238. break;
  239. //
  240. case ParserState.FindOffsets:
  241. receivedChars[receiveIndex] = (char)receiveBuffer[bufferIndex];
  242. if (this.receivedChars[receiveIndex] == '\r' || receivedChars[receiveIndex] == '\n')
  243. {
  244. // Full line
  245. // More than \r\n ?
  246. if (this.receiveIndex > 2)
  247. {
  248. Debug.Print("X: " + receivedChars[receiveIndex]);
  249. Array.Copy(receivedChars, parseBuffer, receiveIndex);
  250. ParseOffset(out Offsets[offsetIndex++], parseBuffer);
  251. receiveIndex = 0;
  252. // Received all 6 offsets
  253. if (offsetIndex >= 6)
  254. imuState = ParserState.FindPre;
  255. }
  256. }
  257. else
  258. receiveIndex++;
  259. break;
  260. //
  261. case ParserState.FindPre:
  262. if (receiveBuffer[bufferIndex] == pree[preeIndex])
  263. {
  264. preeIndex++;
  265. if (preeIndex >= pree.Length)
  266. {
  267. imuState = ParserState.ParseEuler;
  268. preeIndex = 0;
  269. }
  270. }
  271. else
  272. preeIndex = 0;
  273. break;
  274. //
  275. case ParserState.ParseEuler:
  276. receivedChars[receiveIndex] = (char)receiveBuffer[bufferIndex];
  277. if (receivedChars[receiveIndex] == '\r' || receivedChars[receiveIndex] == '\n')
  278. {
  279. // Full Line
  280. if (receiveIndex > 10)
  281. {
  282. // Parse the Data!
  283. lock (parseBuffer)
  284. {
  285. Array.Copy(receivedChars, parseBuffer, receiveIndex);
  286. HasValidData = true;
  287. }
  288. haveToParse = true;
  289. }
  290. receiveIndex = 0;
  291. imuState = ParserState.FindPre;
  292. }
  293. else
  294. {
  295. receiveIndex++;
  296. if (receiveIndex >= receivedChars.Length)
  297. {
  298. Debug.Print("Sentence is too long!");
  299. receiveIndex = 0;
  300. imuState = ParserState.FindPre;
  301. }
  302. }
  303. break;
  304. }
  305. bufferIndex++;
  306. }
  307. }
  308. /// <summary>
  309. ///
  310. /// </summary>
  311. /// <param name="sender"></param>
  312. /// <param name="e"></param>
  313. private static void PortErrorReceived(object sender, SerialErrorReceivedEventArgs e)
  314. {
  315. Debug.Print("COM Error: " + e.EventType);
  316. }
  317. private static void ParseOffset(out int offsetVar, char[] data)
  318. {
  319. int i = 0;
  320. offsetVar = FastNumberParse.ParseInt(data, ref i);
  321. }
  322. /// <summary>
  323. /// Parses the received data
  324. /// Call it just before you use the data
  325. /// </summary>
  326. public void ParseData()
  327. {
  328. if (!haveToParse)
  329. return;
  330. lock (parseBuffer)
  331. {
  332. haveToParse = false;
  333. int i = 0;
  334. Roll = FastNumberParse.ParseFloat(parseBuffer, ref i);
  335. i++;
  336. Pitch = FastNumberParse.ParseFloat(parseBuffer, ref i);
  337. i++;
  338. Yaw = FastNumberParse.ParseFloat(parseBuffer, ref i);
  339. if (ParseAnalogs)
  340. {
  341. // + ',AN:'
  342. i += analogsPree.Length;
  343. if (ApplyOffsets)
  344. {
  345. AnX = FastNumberParse.ParseInt(parseBuffer, ref i) - Offsets[0];
  346. i++;
  347. AnY = FastNumberParse.ParseInt(parseBuffer, ref i) - Offsets[1];
  348. i++;
  349. AnZ = FastNumberParse.ParseInt(parseBuffer, ref i) - Offsets[2];
  350. i++;
  351. AccX = FastNumberParse.ParseInt(parseBuffer, ref i) - Offsets[3];
  352. i++;
  353. AccY = FastNumberParse.ParseInt(parseBuffer, ref i) - Offsets[4];
  354. i++;
  355. AccZ = FastNumberParse.ParseInt(parseBuffer, ref i) - Offsets[5];
  356. }
  357. else
  358. {
  359. AnX = FastNumberParse.ParseInt(parseBuffer, ref i);
  360. i++;
  361. AnY = FastNumberParse.ParseInt(parseBuffer, ref i);
  362. i++;
  363. AnZ = FastNumberParse.ParseInt(parseBuffer, ref i);
  364. i++;
  365. AccX = FastNumberParse.ParseInt(parseBuffer, ref i);
  366. i++;
  367. AccY = FastNumberParse.ParseInt(parseBuffer, ref i);
  368. i++;
  369. AccZ = FastNumberParse.ParseInt(parseBuffer, ref i);
  370. }
  371. i++;
  372. MagX = FastNumberParse.ParseInt(parseBuffer, ref i);
  373. i++;
  374. MagY = FastNumberParse.ParseInt(parseBuffer, ref i);
  375. i++;
  376. MagZ = FastNumberParse.ParseInt(parseBuffer, ref i);
  377. }
  378. }
  379. }
  380. /// <summary>
  381. /// Get compensated attitude output
  382. /// </summary>
  383. /// <param name="roll"></param>
  384. /// <param name="pitch"></param>
  385. /// <param name="yaw"></param>
  386. void IAhrs.GetAttitude(out double roll, out double pitch, out double yaw)
  387. {
  388. ParseData();
  389. roll = Roll;
  390. pitch = Pitch;
  391. yaw = Yaw;
  392. }
  393. /// <summary>
  394. /// Get analog output
  395. /// </summary>
  396. /// <param name="x"></param>
  397. /// <param name="y"></param>
  398. /// <param name="z"></param>
  399. void IAhrs.GetAnalogs(out double x, out double y, out double z)
  400. {
  401. ParseData();
  402. x = AnX;
  403. y = AnY;
  404. z = AnZ;
  405. }
  406. /// <summary>
  407. /// Get accelerometer output
  408. /// </summary>
  409. /// <param name="x"></param>
  410. /// <param name="y"></param>
  411. /// <param name="z"></param>
  412. void IAhrs.GetAcc(out double x, out double y, out double z)
  413. {
  414. ParseData();
  415. x = AccX;
  416. y = AccY;
  417. z = AccZ;
  418. }
  419. }
  420. }