001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.wpilibj.counter; 006 007import edu.wpi.first.hal.CounterJNI; 008import edu.wpi.first.hal.HAL; 009import edu.wpi.first.util.sendable.Sendable; 010import edu.wpi.first.util.sendable.SendableBuilder; 011import edu.wpi.first.util.sendable.SendableRegistry; 012 013/** 014 * Tachometer. 015 * 016 * <p>The Tachometer class measures the time between digital pulses to determine the rotation speed 017 * of a mechanism. Examples of devices that could be used with the tachometer class are a hall 018 * effect sensor, break beam sensor, or optical sensor detecting tape on a shooter wheel. Unlike 019 * encoders, this class only needs a single digital input. 020 */ 021public class Tachometer implements Sendable, AutoCloseable { 022 private final int m_handle; 023 private int m_edgesPerRevolution = 1; 024 025 /** 026 * Constructs a new tachometer. 027 * 028 * @param channel The channel of the Tachometer. 029 * @param configuration The edge configuration 030 */ 031 @SuppressWarnings("this-escape") 032 public Tachometer(int channel, EdgeConfiguration configuration) { 033 m_handle = CounterJNI.initializeCounter(channel, configuration.rising); 034 035 HAL.reportUsage("IO", channel, "Tachometer"); 036 SendableRegistry.add(this, "Tachometer", channel); 037 } 038 039 @Override 040 public void close() { 041 SendableRegistry.remove(this); 042 CounterJNI.freeCounter(m_handle); 043 } 044 045 /** 046 * Gets the tachometer period. 047 * 048 * @return Current period (in seconds). 049 */ 050 public double getPeriod() { 051 return CounterJNI.getCounterPeriod(m_handle); 052 } 053 054 /** 055 * Gets the tachometer frequency. 056 * 057 * @return Current frequency (in hertz). 058 */ 059 public double getFrequency() { 060 double period = getPeriod(); 061 if (period == 0) { 062 return 0; 063 } 064 return 1 / period; 065 } 066 067 /** 068 * Gets the number of edges per revolution. 069 * 070 * @return Edges per revolution. 071 */ 072 public int getEdgesPerRevolution() { 073 return m_edgesPerRevolution; 074 } 075 076 /** 077 * Sets the number of edges per revolution. 078 * 079 * @param edgesPerRevolution Edges per revolution. 080 */ 081 public void setEdgesPerRevolution(int edgesPerRevolution) { 082 m_edgesPerRevolution = edgesPerRevolution; 083 } 084 085 /** 086 * Gets the current tachometer revolutions per second. 087 * 088 * <p>setEdgesPerRevolution must be set with a non 0 value for this to return valid values. 089 * 090 * @return Current RPS. 091 */ 092 public double getRevolutionsPerSecond() { 093 double period = getPeriod(); 094 if (period == 0) { 095 return 0; 096 } 097 int edgesPerRevolution = getEdgesPerRevolution(); 098 if (edgesPerRevolution == 0) { 099 return 0; 100 } 101 return (1.0 / edgesPerRevolution) / period; 102 } 103 104 /** 105 * Gets the current tachometer revolutions per minute. 106 * 107 * <p>setEdgesPerRevolution must be set with a non 0 value for this to return valid values. 108 * 109 * @return Current RPM. 110 */ 111 public double getRevolutionsPerMinute() { 112 return getRevolutionsPerSecond() * 60; 113 } 114 115 /** 116 * Gets if the tachometer is stopped. 117 * 118 * @return True if the tachometer is stopped. 119 */ 120 public boolean getStopped() { 121 return CounterJNI.getCounterStopped(m_handle); 122 } 123 124 /** 125 * Sets the maximum period before the tachometer is considered stopped. 126 * 127 * @param maxPeriod The max period (in seconds). 128 */ 129 public void setMaxPeriod(double maxPeriod) { 130 CounterJNI.setCounterMaxPeriod(m_handle, maxPeriod); 131 } 132 133 @Override 134 public void initSendable(SendableBuilder builder) { 135 builder.setSmartDashboardType("Tachometer"); 136 builder.addDoubleProperty("RPS", this::getRevolutionsPerSecond, null); 137 builder.addDoubleProperty("RPM", this::getRevolutionsPerMinute, null); 138 } 139}