Advertisement
Guest User

Untitled

a guest
May 24th, 2015
192
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.50 KB | None | 0 0
  1. package org.team2168.PID.sensors;
  2.  
  3. import java.nio.ByteBuffer;
  4. import java.nio.ByteOrder;
  5. import java.util.BitSet;
  6. import java.util.TimerTask;
  7.  
  8. import edu.wpi.first.wpilibj.SPI;
  9. import edu.wpi.first.wpilibj.SPI.Port;
  10. import edu.wpi.first.wpilibj.Timer;
  11.  
  12. /**
  13. * @author Kevin Harrilal (kevin@team2168.org)
  14. */
  15. public class ADXRS453Gyro {
  16.  
  17. static final int DATA_SIZE = 4; //4 bytes = 32 bits
  18. static final byte PARITY_BIT = (byte) 0x01; //parity check on first bit
  19. static final byte STATUS_MASK = (byte) 0x0C;
  20. static final byte FIRST_BYTE_DATA_MASK = (byte) 0x03; //mask to find sensor data bits on first byte
  21. static final byte THIRD_BYTE_DATA_MASK = (byte) 0xFC; //mask to find sensor data bits on third byte
  22. static final byte READ_COMMAND = (byte) 0x20; //0010 0000
  23.  
  24. //different register values available
  25. static final byte ADXRS453_REG_RATE = (byte) 0x00;
  26. static final byte ADXRS453_REG_TEM = (byte) 0x02;
  27. static final byte ADXRS453_REG_LOCST = (byte) 0x04;
  28. static final byte ADXRS453_REG_HICST = (byte) 0x06;
  29. static final byte ADXRS453_REG_QUAD = (byte) 0x08;
  30. static final byte ADXRS453_REG_FAULT = (byte) 0x0A;
  31. static final byte ADXRS453_REG_PID = (byte) 0x0C;
  32. static final byte ADXRS453_REG_SN_HIGH = (byte) 0x0E;
  33. static final byte ADXRS453_REG_SN_LOW = (byte) 0x10;
  34.  
  35. //angle integration
  36. public volatile double currentRate;
  37. private volatile double lastRate;
  38. public volatile double deltaTime;
  39. public volatile double currentTime;
  40. private volatile double lastTime;
  41. private volatile double angle;
  42. public volatile double driftRate;
  43. public volatile double accumulatedRate;
  44.  
  45. //other gyro register data
  46. private volatile int id;
  47. private volatile double temp;
  48. private volatile int status;
  49.  
  50. //calibration loop
  51. private volatile boolean calibrate;
  52. private volatile boolean stopCalibrating;
  53. private volatile boolean firstLoop;
  54. public volatile double timeElapsed;
  55. private volatile boolean calCompleted;
  56. private static double CALIBRATION_PERIOD = 10.0; //seconds
  57.  
  58. private SPI spi;
  59.  
  60. //debugging binary messages
  61. String binRate;
  62. String binMessage;
  63.  
  64. //thread executor
  65. private java.util.Timer executor;
  66. private long period;
  67.  
  68. public ADXRS453Gyro() {
  69. //run at 333Hz loop
  70. this.period = (long)3;
  71.  
  72. spi = new SPI(Port.kOnboardCS0);
  73. spi.setClockRate(4000000); //4 MHz (rRIO max, gyro can go high)
  74. spi.setClockActiveHigh();
  75. spi.setChipSelectActiveLow();
  76. spi.setMSBFirst();
  77.  
  78. currentRate = 0.0;
  79. driftRate = 0.0;
  80.  
  81. lastTime = 0;
  82. currentTime = 0;
  83. lastRate = 0;
  84. deltaTime = 0;
  85. accumulatedRate = 0;
  86.  
  87. calibrate();
  88.  
  89. temp = 0;
  90. id = 0;
  91.  
  92. reset();
  93. }
  94.  
  95. public void startThread() {
  96. this.executor = new java.util.Timer();
  97. this.executor.schedule(new GyroUpdateTask(this), 0L, this.period);
  98. }
  99.  
  100. public String getMessageBin() {
  101. return binMessage;
  102. }
  103.  
  104. public String getRateBin() {
  105. return binRate;
  106. }
  107.  
  108. /**
  109. * Called to begin the gyros calibration sequence.
  110. * This should only be called during a time when the robot will be
  111. * stationary for a duration of time (~10 sec). Robot motion during
  112. * the calibration sequence will cause significant steady state drift.
  113. */
  114. public final void calibrate() {
  115. calibrate = true;
  116. firstLoop = true;
  117. stopCalibrating = false;
  118. calCompleted = false;
  119. }
  120.  
  121. /**
  122. * @return true if the calibration sequence is active.
  123. */
  124. public final boolean isCalibrating() {
  125. return calibrate;
  126. }
  127.  
  128. /**
  129. * @return true if the this gyro has successfully completed the last calibration sequence.
  130. */
  131. public final boolean hasCompletedCalibration() {
  132. return calCompleted;
  133. }
  134.  
  135. /**
  136. * Stop the calibration sequence prematurely.
  137. * e.g. if the match is starting
  138. */
  139. public final void stopCalibrating() {
  140. stopCalibrating = true;
  141. }
  142.  
  143. /**
  144. * Zero the gyro heading.
  145. */
  146. public final void reset() {
  147. angle = 0;
  148. }
  149.  
  150. public double getRate() {
  151. return currentRate;
  152. }
  153.  
  154. public int getStatus() {
  155. return status;
  156. }
  157. public double getAngle() {
  158. return angle;
  159. }
  160.  
  161. public double getPos() {
  162. return getAngle();
  163. }
  164.  
  165. public double getDeltatime() {
  166. return deltaTime;
  167. }
  168.  
  169. public int getID() {
  170. return id;
  171. }
  172.  
  173. public double getTemp() {
  174. return temp;
  175. }
  176.  
  177. public short getRegisterValue(byte registerAddress) {
  178. byte[] command = new byte[DATA_SIZE];
  179. byte[] data = new byte[DATA_SIZE];
  180. command[0] = 0;
  181. command[1] = 0;
  182. command[2] = 0;
  183. command[3] = 0;
  184. data[0] = 0;
  185. data[1] = 0;
  186. data[2] = 0;
  187. data[3] = 0;
  188.  
  189. command[0] = (byte) ((0x01 << 7) | (registerAddress >> 7));
  190. command[1] = (byte) (registerAddress << 1);
  191.  
  192. checkParity(command);
  193. spi.write(command,DATA_SIZE);
  194. spi.read(false, data, DATA_SIZE);
  195.  
  196. short registerValue = 0;
  197. registerValue = (short) (((short)(data[1]) << 11) |
  198. ((short)data[2] << 3) |
  199. ((short)(data[3] >> 5)));
  200.  
  201. return registerValue;
  202. }
  203.  
  204. public static String getBinaryFromByte(byte[] bytes) {
  205. String temp = "";;
  206. for (byte b : bytes)
  207. temp += Integer.toBinaryString(b & 255 | 256).substring(1) + " ";
  208.  
  209. return temp;
  210. }
  211.  
  212. ////////// PRIVATE FUNCTIONS ////////////////
  213.  
  214. private void checkParity(byte[] data) {
  215. if(BitSet.valueOf(data).cardinality() % 2 == 0)
  216. data[3] |= PARITY_BIT;
  217. }
  218.  
  219. /**
  220. *
  221. * @return gyro rate in deg/s
  222. */
  223. private double getSensorData() {
  224. byte[] command = new byte[DATA_SIZE];
  225. byte[] data = new byte[DATA_SIZE];
  226. command[0] = READ_COMMAND;
  227. command[1] = 0;
  228. command[2] = 0;
  229. command[3] = 0;
  230. data[0] = 0;
  231. data[1] = 0;
  232. data[2] = 0;
  233. data[3] = 0;
  234.  
  235. checkParity(command);
  236. spi.write(command,DATA_SIZE);
  237. spi.read(false, data, DATA_SIZE);
  238.  
  239. return sensorDataMask(data);
  240. }
  241.  
  242. private double sensorDataMask(byte[] data) {
  243. //returns full binary from gyro for debugging
  244. binMessage = getBinaryFromByte(data);
  245.  
  246. //00 Invalid data for sensor data response 01 Valid sensor data
  247. //01 Valid data
  248. //10 Sensor self-test data
  249. //11 Read/write response
  250. status = (short)(data[0] & STATUS_MASK) >> 2;
  251.  
  252. //Pull out bytes 25-10 as data bytes for gyro rate
  253. byte[] rateByte = new byte[2];
  254. rateByte[0] = (byte) ((byte) ((data[1] >> 2) & 0x3F) | ((data[0] & FIRST_BYTE_DATA_MASK) << 6));
  255. rateByte[1] = (byte) ((byte) ((data[1] << 6) & 0xC0) | (data[2] & THIRD_BYTE_DATA_MASK) >> 2 & 0x3F);
  256.  
  257. //convert to 2's compo
  258. short value = ByteBuffer.wrap(rateByte).order(ByteOrder.BIG_ENDIAN).getShort();
  259.  
  260. //view 16 bits in data for debugging purposes
  261. byte[] newB = new byte[2];
  262. newB[0] = (byte)((value >> 8) & 0xff);
  263. newB[1] = (byte)(value);
  264. binRate = getBinaryFromByte(newB);
  265.  
  266. //data has 80 LSB
  267. return value / 80.0;
  268. }
  269.  
  270. private int GetID() {
  271. short id = getRegisterValue(ADXRS453_REG_PID);
  272. return id >> 8;
  273. }
  274.  
  275. private double GetTemperature() {
  276. //TODO: reverify calc, not sure this works
  277. short registerValue = 0;
  278. short temperature = 0;
  279.  
  280. registerValue = getRegisterValue(ADXRS453_REG_TEM);
  281. registerValue = (short) ( (registerValue >> 6) - 0x31F);
  282. temperature = (short) (registerValue / 5);
  283.  
  284. return temperature;
  285. }
  286.  
  287. /**
  288. * Periodically executed to update the gyro state data.
  289. */
  290. private void update() {
  291. if(lastTime == 0) {
  292. lastTime = Timer.getFPGATimestamp();
  293. }
  294.  
  295. currentRate = getSensorData();
  296. currentTime = Timer.getFPGATimestamp();
  297. deltaTime = currentTime - lastTime;
  298.  
  299. //TODO: see if we can fix low-pass filter to stop drift
  300. //low-pass filter
  301. //remove until it can be further tested. Yields incorrect results
  302. //if(Math.abs(currentRate) < 2)
  303. // currentRate = 0;
  304.  
  305. angle += (currentRate - driftRate) * deltaTime;
  306.  
  307. /*
  308. * Periodically update our drift rate by normalizing out drift
  309. * while the robot is not moving.
  310. * This code is re-entrant and can be stopped at any time
  311. * (e.g. if a match starts).
  312. */
  313. if(calibrate) {
  314. if(firstLoop) {
  315. driftRate = 0.0;
  316. accumulatedRate = 0.0;
  317. timeElapsed = 0.0;
  318. firstLoop = false;
  319. }
  320.  
  321. timeElapsed += deltaTime;
  322. accumulatedRate += currentRate * deltaTime;
  323. driftRate = accumulatedRate / timeElapsed; //angle/S
  324.  
  325. if (timeElapsed >= CALIBRATION_PERIOD || stopCalibrating) {
  326. //finish calibration sequence
  327. calibrate = false;
  328. reset();
  329.  
  330. calCompleted = true;
  331. System.out.println("Accumulated Offset: " + driftRate
  332. + "\tDelta Time: " + timeElapsed);
  333. }
  334. }
  335.  
  336. lastRate = currentRate;
  337. lastTime = currentTime;
  338.  
  339. //Get all other Gyro data here
  340. temp = GetTemperature();
  341. id = GetID();
  342. }
  343.  
  344. private class GyroUpdateTask extends TimerTask {
  345. private ADXRS453Gyro gyro;
  346.  
  347. private GyroUpdateTask(ADXRS453Gyro gyro) {
  348. if (gyro == null) {
  349. throw new NullPointerException("Gyro pointer null");
  350. }
  351. this.gyro = gyro;
  352. }
  353.  
  354. /**
  355. * Called periodically in its own thread
  356. */
  357. public void run() {
  358. gyro.update();
  359. }
  360. }
  361. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement