001/*----------------------------------------------------------------------------*/ 002/* Copyright (c) FIRST 2008-2017. 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 edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType; 011import edu.wpi.first.wpilibj.hal.HAL; 012import edu.wpi.first.wpilibj.livewindow.LiveWindow; 013import edu.wpi.first.wpilibj.tables.ITable; 014import edu.wpi.first.wpilibj.tables.ITableListener; 015 016/** 017 * Standard hobby style servo. 018 * 019 * <p>The range parameters default to the appropriate values for the Hitec HS-322HD servo provided 020 * in the FIRST Kit of Parts in 2008. 021 */ 022public class Servo extends PWM { 023 024 private static final double kMaxServoAngle = 180.0; 025 private static final double kMinServoAngle = 0.0; 026 027 protected static final double kDefaultMaxServoPWM = 2.4; 028 protected static final double kDefaultMinServoPWM = .6; 029 030 /** 031 * Constructor.<br> 032 * 033 * <p>By default {@value #kDefaultMaxServoPWM} ms is used as the maxPWM value<br> By default 034 * {@value #kDefaultMinServoPWM} ms is used as the minPWM value<br> 035 * 036 * @param channel The PWM channel to which the servo is attached. 0-9 are on-board, 10-19 are on 037 * the MXP port 038 */ 039 public Servo(final int channel) { 040 super(channel); 041 setBounds(kDefaultMaxServoPWM, 0, 0, 0, kDefaultMinServoPWM); 042 setPeriodMultiplier(PeriodMultiplier.k4X); 043 044 LiveWindow.addActuator("Servo", getChannel(), this); 045 HAL.report(tResourceType.kResourceType_Servo, getChannel()); 046 } 047 048 049 /** 050 * Set the servo position. 051 * 052 * <p>Servo values range from 0.0 to 1.0 corresponding to the range of full left to full right. 053 * 054 * @param value Position from 0.0 to 1.0. 055 */ 056 public void set(double value) { 057 setPosition(value); 058 } 059 060 /** 061 * Get the servo position. 062 * 063 * <p>Servo values range from 0.0 to 1.0 corresponding to the range of full left to full right. 064 * 065 * @return Position from 0.0 to 1.0. 066 */ 067 public double get() { 068 return getPosition(); 069 } 070 071 /** 072 * Set the servo angle. 073 * 074 * <p>Assume that the servo angle is linear with respect to the PWM value (big assumption, need to 075 * test). 076 * 077 * <p>Servo angles that are out of the supported range of the servo simply "saturate" in that 078 * direction In other words, if the servo has a range of (X degrees to Y degrees) than angles of 079 * less than X result in an angle of X being set and angles of more than Y degrees result in an 080 * angle of Y being set. 081 * 082 * @param degrees The angle in degrees to set the servo. 083 */ 084 public void setAngle(double degrees) { 085 if (degrees < kMinServoAngle) { 086 degrees = kMinServoAngle; 087 } else if (degrees > kMaxServoAngle) { 088 degrees = kMaxServoAngle; 089 } 090 091 setPosition(((degrees - kMinServoAngle)) / getServoAngleRange()); 092 } 093 094 /** 095 * Get the servo angle. 096 * 097 * <p>Assume that the servo angle is linear with respect to the PWM value (big assumption, need to 098 * test). 099 * 100 * @return The angle in degrees to which the servo is set. 101 */ 102 public double getAngle() { 103 return getPosition() * getServoAngleRange() + kMinServoAngle; 104 } 105 106 private double getServoAngleRange() { 107 return kMaxServoAngle - kMinServoAngle; 108 } 109 110 /* 111 * Live Window code, only does anything if live window is activated. 112 */ 113 public String getSmartDashboardType() { 114 return "Servo"; 115 } 116 117 private ITable m_table; 118 private ITableListener m_tableListener; 119 120 @Override 121 public void initTable(ITable subtable) { 122 m_table = subtable; 123 updateTable(); 124 } 125 126 @Override 127 public void updateTable() { 128 if (m_table != null) { 129 m_table.putNumber("Value", get()); 130 } 131 } 132 133 @Override 134 public void startLiveWindowMode() { 135 m_tableListener = new ITableListener() { 136 public void valueChanged(ITable itable, String key, Object value, boolean bln) { 137 set(((Double) value).doubleValue()); 138 } 139 }; 140 m_table.addTableListener("Value", m_tableListener, true); 141 } 142 143 @Override 144 public void stopLiveWindowMode() { 145 // TODO: Broken, should only remove the listener from "Value" only. 146 m_table.removeTableListener(m_tableListener); 147 } 148}