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;
006
007import edu.wpi.first.hal.HAL;
008import edu.wpi.first.wpilibj.event.BooleanEvent;
009import edu.wpi.first.wpilibj.event.EventLoop;
010
011/**
012 * Handle input from Flight Joysticks connected to the Driver Station.
013 *
014 * <p>This class handles standard input that comes from the Driver Station. Each time a value is
015 * requested the most recent value is returned. There is a single class instance for each joystick
016 * and the mapping of ports to hardware buttons depends on the code in the Driver Station.
017 */
018public class Joystick extends GenericHID {
019  /** Default X axis channel. */
020  public static final byte kDefaultXChannel = 0;
021
022  /** Default Y axis channel. */
023  public static final byte kDefaultYChannel = 1;
024
025  /** Default Z axis channel. */
026  public static final byte kDefaultZChannel = 2;
027
028  /** Default twist axis channel. */
029  public static final byte kDefaultTwistChannel = 2;
030
031  /** Default throttle axis channel. */
032  public static final byte kDefaultThrottleChannel = 3;
033
034  /** Represents an analog axis on a joystick. */
035  public enum AxisType {
036    /** X axis. */
037    kX(0),
038    /** Y axis. */
039    kY(1),
040    /** Z axis. */
041    kZ(2),
042    /** Twist axis. */
043    kTwist(3),
044    /** Throttle axis. */
045    kThrottle(4);
046
047    /** AxisType value. */
048    public final int value;
049
050    AxisType(int value) {
051      this.value = value;
052    }
053  }
054
055  /** Represents a digital button on a joystick. */
056  public enum ButtonType {
057    /** kTrigger. */
058    kTrigger(1),
059    /** kTop. */
060    kTop(2);
061
062    /** ButtonType value. */
063    public final int value;
064
065    ButtonType(int value) {
066      this.value = value;
067    }
068  }
069
070  private final byte[] m_axes = new byte[AxisType.values().length];
071
072  /**
073   * Construct an instance of a joystick.
074   *
075   * @param port The port index on the Driver Station that the joystick is plugged into.
076   */
077  public Joystick(final int port) {
078    super(port);
079
080    m_axes[AxisType.kX.value] = kDefaultXChannel;
081    m_axes[AxisType.kY.value] = kDefaultYChannel;
082    m_axes[AxisType.kZ.value] = kDefaultZChannel;
083    m_axes[AxisType.kTwist.value] = kDefaultTwistChannel;
084    m_axes[AxisType.kThrottle.value] = kDefaultThrottleChannel;
085
086    HAL.reportUsage("HID", port, "Joystick");
087  }
088
089  /**
090   * Set the channel associated with the X axis.
091   *
092   * @param channel The channel to set the axis to.
093   */
094  public void setXChannel(int channel) {
095    m_axes[AxisType.kX.value] = (byte) channel;
096  }
097
098  /**
099   * Set the channel associated with the Y axis.
100   *
101   * @param channel The channel to set the axis to.
102   */
103  public void setYChannel(int channel) {
104    m_axes[AxisType.kY.value] = (byte) channel;
105  }
106
107  /**
108   * Set the channel associated with the Z axis.
109   *
110   * @param channel The channel to set the axis to.
111   */
112  public void setZChannel(int channel) {
113    m_axes[AxisType.kZ.value] = (byte) channel;
114  }
115
116  /**
117   * Set the channel associated with the throttle axis.
118   *
119   * @param channel The channel to set the axis to.
120   */
121  public void setThrottleChannel(int channel) {
122    m_axes[AxisType.kThrottle.value] = (byte) channel;
123  }
124
125  /**
126   * Set the channel associated with the twist axis.
127   *
128   * @param channel The channel to set the axis to.
129   */
130  public void setTwistChannel(int channel) {
131    m_axes[AxisType.kTwist.value] = (byte) channel;
132  }
133
134  /**
135   * Get the channel currently associated with the X axis.
136   *
137   * @return The channel for the axis.
138   */
139  public int getXChannel() {
140    return m_axes[AxisType.kX.value];
141  }
142
143  /**
144   * Get the channel currently associated with the Y axis.
145   *
146   * @return The channel for the axis.
147   */
148  public int getYChannel() {
149    return m_axes[AxisType.kY.value];
150  }
151
152  /**
153   * Get the channel currently associated with the Z axis.
154   *
155   * @return The channel for the axis.
156   */
157  public int getZChannel() {
158    return m_axes[AxisType.kZ.value];
159  }
160
161  /**
162   * Get the channel currently associated with the twist axis.
163   *
164   * @return The channel for the axis.
165   */
166  public int getTwistChannel() {
167    return m_axes[AxisType.kTwist.value];
168  }
169
170  /**
171   * Get the channel currently associated with the throttle axis.
172   *
173   * @return The channel for the axis.
174   */
175  public int getThrottleChannel() {
176    return m_axes[AxisType.kThrottle.value];
177  }
178
179  /**
180   * Get the X value of the joystick. This depends on the mapping of the joystick connected to the
181   * current port. On most joysticks, positive is to the right.
182   *
183   * @return The X value of the joystick.
184   */
185  public final double getX() {
186    return getRawAxis(m_axes[AxisType.kX.value]);
187  }
188
189  /**
190   * Get the Y value of the joystick. This depends on the mapping of the joystick connected to the
191   * current port. On most joysticks, positive is to the back.
192   *
193   * @return The Y value of the joystick.
194   */
195  public final double getY() {
196    return getRawAxis(m_axes[AxisType.kY.value]);
197  }
198
199  /**
200   * Get the z position of the HID.
201   *
202   * @return the z position
203   */
204  public final double getZ() {
205    return getRawAxis(m_axes[AxisType.kZ.value]);
206  }
207
208  /**
209   * Get the twist value of the current joystick. This depends on the mapping of the joystick
210   * connected to the current port.
211   *
212   * @return The Twist value of the joystick.
213   */
214  public final double getTwist() {
215    return getRawAxis(m_axes[AxisType.kTwist.value]);
216  }
217
218  /**
219   * Get the throttle value of the current joystick. This depends on the mapping of the joystick
220   * connected to the current port.
221   *
222   * @return The Throttle value of the joystick.
223   */
224  public final double getThrottle() {
225    return getRawAxis(m_axes[AxisType.kThrottle.value]);
226  }
227
228  /**
229   * Read the state of the trigger on the joystick.
230   *
231   * @return The state of the trigger.
232   */
233  public boolean getTrigger() {
234    return getRawButton(ButtonType.kTrigger.value);
235  }
236
237  /**
238   * Whether the trigger was pressed since the last check.
239   *
240   * @return Whether the button was pressed since the last check.
241   */
242  public boolean getTriggerPressed() {
243    return getRawButtonPressed(ButtonType.kTrigger.value);
244  }
245
246  /**
247   * Whether the trigger was released since the last check.
248   *
249   * @return Whether the button was released since the last check.
250   */
251  public boolean getTriggerReleased() {
252    return getRawButtonReleased(ButtonType.kTrigger.value);
253  }
254
255  /**
256   * Constructs an event instance around the trigger button's digital signal.
257   *
258   * @param loop the event loop instance to attach the event to.
259   * @return an event instance representing the trigger button's digital signal attached to the
260   *     given loop.
261   */
262  public BooleanEvent trigger(EventLoop loop) {
263    return button(ButtonType.kTrigger.value, loop);
264  }
265
266  /**
267   * Read the state of the top button on the joystick.
268   *
269   * @return The state of the top button.
270   */
271  public boolean getTop() {
272    return getRawButton(ButtonType.kTop.value);
273  }
274
275  /**
276   * Whether the top button was pressed since the last check.
277   *
278   * @return Whether the button was pressed since the last check.
279   */
280  public boolean getTopPressed() {
281    return getRawButtonPressed(ButtonType.kTop.value);
282  }
283
284  /**
285   * Whether the top button was released since the last check.
286   *
287   * @return Whether the button was released since the last check.
288   */
289  public boolean getTopReleased() {
290    return getRawButtonReleased(ButtonType.kTop.value);
291  }
292
293  /**
294   * Constructs an event instance around the top button's digital signal.
295   *
296   * @param loop the event loop instance to attach the event to.
297   * @return an event instance representing the top button's digital signal attached to the given
298   *     loop.
299   */
300  public BooleanEvent top(EventLoop loop) {
301    return button(ButtonType.kTop.value, loop);
302  }
303
304  /**
305   * Get the magnitude of the vector formed by the joystick's current position relative to its
306   * origin.
307   *
308   * @return The magnitude of the direction vector
309   */
310  public double getMagnitude() {
311    return Math.hypot(getX(), getY());
312  }
313
314  /**
315   * Get the direction of the vector formed by the joystick and its origin in radians. 0 is forward
316   * and clockwise is positive. (Straight right is π/2.)
317   *
318   * @return The direction of the vector in radians
319   */
320  public double getDirectionRadians() {
321    // https://docs.wpilib.org/en/stable/docs/software/basic-programming/coordinate-system.html#joystick-and-controller-coordinate-system
322    // A positive rotation around the X axis moves the joystick right, and a
323    // positive rotation around the Y axis moves the joystick backward. When
324    // treating them as translations, 0 radians is measured from the right
325    // direction, and angle increases clockwise.
326    //
327    // It's rotated 90 degrees CCW (y is negated and the arguments are reversed)
328    // so that 0 radians is forward.
329    return Math.atan2(getX(), -getY());
330  }
331
332  /**
333   * Get the direction of the vector formed by the joystick and its origin in degrees. 0 is forward
334   * and clockwise is positive. (Straight right is 90.)
335   *
336   * @return The direction of the vector in degrees
337   */
338  public double getDirectionDegrees() {
339    return Math.toDegrees(getDirectionRadians());
340  }
341}