001/*----------------------------------------------------------------------------*/ 002/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */ 003/* Open Source Software - may be modified and shared by FRC teams. The code */ 004/* must be accompanied by the FIRST BSD license file in the root directory of */ 005/* the project. */ 006/*----------------------------------------------------------------------------*/ 007 008package edu.wpi.first.wpilibj; 009 010import java.nio.ByteBuffer; 011import java.nio.ByteOrder; 012 013import edu.wpi.first.networktables.NetworkTableEntry; 014import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances; 015import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType; 016import edu.wpi.first.wpilibj.hal.HAL; 017import edu.wpi.first.wpilibj.interfaces.Accelerometer; 018import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder; 019 020/** 021 * ADXL345 I2C Accelerometer. 022 */ 023@SuppressWarnings({"TypeName", "PMD.UnusedPrivateField"}) 024public class ADXL345_I2C extends SensorBase implements Accelerometer, Sendable { 025 private static final byte kAddress = 0x1D; 026 private static final byte kPowerCtlRegister = 0x2D; 027 private static final byte kDataFormatRegister = 0x31; 028 private static final byte kDataRegister = 0x32; 029 private static final double kGsPerLSB = 0.00390625; 030 private static final byte kPowerCtl_Link = 0x20; 031 private static final byte kPowerCtl_AutoSleep = 0x10; 032 private static final byte kPowerCtl_Measure = 0x08; 033 private static final byte kPowerCtl_Sleep = 0x04; 034 035 private static final byte kDataFormat_SelfTest = (byte) 0x80; 036 private static final byte kDataFormat_SPI = 0x40; 037 private static final byte kDataFormat_IntInvert = 0x20; 038 private static final byte kDataFormat_FullRes = 0x08; 039 private static final byte kDataFormat_Justify = 0x04; 040 041 public enum Axes { 042 kX((byte) 0x00), 043 kY((byte) 0x02), 044 kZ((byte) 0x04); 045 046 /** 047 * The integer value representing this enumeration. 048 */ 049 @SuppressWarnings("MemberName") 050 public final byte value; 051 052 Axes(byte value) { 053 this.value = value; 054 } 055 } 056 057 @SuppressWarnings("MemberName") 058 public static class AllAxes { 059 public double XAxis; 060 public double YAxis; 061 public double ZAxis; 062 } 063 064 protected I2C m_i2c; 065 066 /** 067 * Constructs the ADXL345 Accelerometer with I2C address 0x1D. 068 * 069 * @param port The I2C port the accelerometer is attached to 070 * @param range The range (+ or -) that the accelerometer will measure. 071 */ 072 public ADXL345_I2C(I2C.Port port, Range range) { 073 this(port, range, kAddress); 074 } 075 076 /** 077 * Constructs the ADXL345 Accelerometer over I2C. 078 * 079 * @param port The I2C port the accelerometer is attached to 080 * @param range The range (+ or -) that the accelerometer will measure. 081 * @param deviceAddress I2C address of the accelerometer (0x1D or 0x53) 082 */ 083 public ADXL345_I2C(I2C.Port port, Range range, int deviceAddress) { 084 m_i2c = new I2C(port, deviceAddress); 085 086 // Turn on the measurements 087 m_i2c.write(kPowerCtlRegister, kPowerCtl_Measure); 088 089 setRange(range); 090 091 HAL.report(tResourceType.kResourceType_ADXL345, tInstances.kADXL345_I2C); 092 setName("ADXL345_I2C", port.value); 093 } 094 095 @Override 096 public void free() { 097 super.free(); 098 m_i2c.free(); 099 } 100 101 @Override 102 public void setRange(Range range) { 103 final byte value; 104 105 switch (range) { 106 case k2G: 107 value = 0; 108 break; 109 case k4G: 110 value = 1; 111 break; 112 case k8G: 113 value = 2; 114 break; 115 case k16G: 116 value = 3; 117 break; 118 default: 119 throw new IllegalArgumentException(range + " unsupported range type"); 120 } 121 122 // Specify the data format to read 123 m_i2c.write(kDataFormatRegister, kDataFormat_FullRes | value); 124 } 125 126 @Override 127 public double getX() { 128 return getAcceleration(Axes.kX); 129 } 130 131 @Override 132 public double getY() { 133 return getAcceleration(Axes.kY); 134 } 135 136 @Override 137 public double getZ() { 138 return getAcceleration(Axes.kZ); 139 } 140 141 /** 142 * Get the acceleration of one axis in Gs. 143 * 144 * @param axis The axis to read from. 145 * @return Acceleration of the ADXL345 in Gs. 146 */ 147 public double getAcceleration(Axes axis) { 148 ByteBuffer rawAccel = ByteBuffer.allocate(2); 149 m_i2c.read(kDataRegister + axis.value, 2, rawAccel); 150 151 // Sensor is little endian... swap bytes 152 rawAccel.order(ByteOrder.LITTLE_ENDIAN); 153 return rawAccel.getShort(0) * kGsPerLSB; 154 } 155 156 /** 157 * Get the acceleration of all axes in Gs. 158 * 159 * @return An object containing the acceleration measured on each axis of the ADXL345 in Gs. 160 */ 161 public AllAxes getAccelerations() { 162 AllAxes data = new AllAxes(); 163 ByteBuffer rawData = ByteBuffer.allocate(6); 164 m_i2c.read(kDataRegister, 6, rawData); 165 166 // Sensor is little endian... swap bytes 167 rawData.order(ByteOrder.LITTLE_ENDIAN); 168 data.XAxis = rawData.getShort(0) * kGsPerLSB; 169 data.YAxis = rawData.getShort(2) * kGsPerLSB; 170 data.ZAxis = rawData.getShort(4) * kGsPerLSB; 171 return data; 172 } 173 174 @Override 175 public void initSendable(SendableBuilder builder) { 176 builder.setSmartDashboardType("3AxisAccelerometer"); 177 NetworkTableEntry entryX = builder.getEntry("X"); 178 NetworkTableEntry entryY = builder.getEntry("Y"); 179 NetworkTableEntry entryZ = builder.getEntry("Z"); 180 builder.setUpdateTable(() -> { 181 AllAxes data = getAccelerations(); 182 entryX.setDouble(data.XAxis); 183 entryY.setDouble(data.YAxis); 184 entryZ.setDouble(data.ZAxis); 185 }); 186 } 187}