Merge branch 'main' of https://demerso.net/pls5618/2023/robot
This commit is contained in:
		| @@ -18,6 +18,8 @@ public class Constants { | |||||||
|      public static int actuateur = 2; |      public static int actuateur = 2; | ||||||
|      public static int brakedroit = 3; |      public static int brakedroit = 3; | ||||||
|      public static int brakegauche = 4; |      public static int brakegauche = 4; | ||||||
|  |      public static int brakewinchf = 5; | ||||||
|  |      public static int brakewinchb = 5; | ||||||
|     // DIO |     // DIO | ||||||
|     public static int limitbd = 0; |     public static int limitbd = 0; | ||||||
|     public static int limitbg = 2; |     public static int limitbg = 2; | ||||||
|   | |||||||
| @@ -32,6 +32,12 @@ import frc.robot.commands.bras.PivotBrasRentre; | |||||||
| import frc.robot.commands.bras.PivoteBrasBas; | import frc.robot.commands.bras.PivoteBrasBas; | ||||||
| import frc.robot.commands.bras.PivoteBrasHaut; | import frc.robot.commands.bras.PivoteBrasHaut; | ||||||
| import frc.robot.commands.bras.PivoteBrasMilieux; | import frc.robot.commands.bras.PivoteBrasMilieux; | ||||||
|  | import frc.robot.commands.bras.PivotChercheBas; | ||||||
|  | import frc.robot.commands.bras.PivotChercheHaut; | ||||||
|  | import edu.wpi.first.apriltag.AprilTag; | ||||||
|  | import frc.robot.commands.Cube; | ||||||
|  | import frc.robot.commands.Cone; | ||||||
|  | import frc.robot.commands.Tape; | ||||||
|  |  | ||||||
| public class RobotContainer { | public class RobotContainer { | ||||||
| CommandXboxController manette1 = new CommandXboxController(0); | CommandXboxController manette1 = new CommandXboxController(0); | ||||||
| @@ -69,8 +75,20 @@ public RobotContainer() { | |||||||
|     manette1.a().toggleOnTrue(Commands.startEnd(pince::ouvrir, pince::fermer,pince)); |     manette1.a().toggleOnTrue(Commands.startEnd(pince::ouvrir, pince::fermer,pince)); | ||||||
|     manette1.x().toggleOnTrue(Commands.startEnd(basePilotable::BrakeFerme,basePilotable::BrakeOuvre,basePilotable)); |     manette1.x().toggleOnTrue(Commands.startEnd(basePilotable::BrakeFerme,basePilotable::BrakeOuvre,basePilotable)); | ||||||
|     manette1.y().whileTrue(gyro); |     manette1.y().whileTrue(gyro); | ||||||
|  | <<<<<<< HEAD | ||||||
|     // manette1.b().toggleOnTrue(Commands.startEnd(gratte::baiser, gratte::Lever,gratte)); |     // manette1.b().toggleOnTrue(Commands.startEnd(gratte::baiser, gratte::Lever,gratte)); | ||||||
|  | ======= | ||||||
|  | >>>>>>> 4b22cac30fd2b3c5e7b1af3c7f890c4def2d21f7 | ||||||
|     manette1.start().toggleOnTrue(Commands.startEnd(basePilotable::resetGyro, basePilotable::resetGyro, basePilotable)); |     manette1.start().toggleOnTrue(Commands.startEnd(basePilotable::resetGyro, basePilotable::resetGyro, basePilotable)); | ||||||
|  |     manette1.b().toggleOnTrue(Commands.startEnd(gratte::baiser, gratte::Lever,gratte)); | ||||||
|  |     manette2.a().toggleOnTrue(Commands.startEnd(brasTelescopique::pivoteBrasHaut, brasTelescopique::pivoteBrasHaut)); | ||||||
|  |     manette2.b().toggleOnTrue(Commands.startEnd(brasTelescopique::pivoteBrasBas, brasTelescopique::pivoteBrasBas, brasTelescopique)); | ||||||
|  |     manette2.x().toggleOnTrue(Commands.startEnd(brasTelescopique::pivoteBrasMilieux, brasTelescopique::pivoteBrasMilieux, brasTelescopique)); | ||||||
|  |     manette2.y().toggleOnTrue(Commands.startEnd(brasTelescopique::pivotBrasRentre, brasTelescopique::pivotBrasRentre, brasTelescopique)); | ||||||
|  |     manette2.povRight().toggleOnTrue(Commands.startEnd(brasTelescopique::PivotChercheBas, brasTelescopique::PivotChercheBas, brasTelescopique)); | ||||||
|  |     manette2.povLeft().toggleOnTrue(Commands.startEnd(brasTelescopique::PivotChercheHaut, brasTelescopique::PivotChercheHaut, brasTelescopique)); | ||||||
|  |     manette2.rightBumper().toggleOnTrue(Commands.startEnd(null, null, null)); | ||||||
|  |     manette2.leftBumper().toggleOnTrue(Commands.startEnd(null, null, null)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public Command getAutonomousCommand() { |   public Command getAutonomousCommand() { | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ public class PivotBrasRentre extends CommandBase { | |||||||
|   public void execute() { |   public void execute() { | ||||||
|     if(brasTelescopique.distance()>1){ |     if(brasTelescopique.distance()>1){ | ||||||
|       brasTelescopique.AvanceRecule(0.5); |       brasTelescopique.AvanceRecule(0.5); | ||||||
|  |       brasTelescopique.fermer(); | ||||||
|     } |     } | ||||||
|     if (pivot.distance()>1){ |     if (pivot.distance()>1){ | ||||||
|       pivot.monteDescendre(0.5); |       pivot.monteDescendre(0.5); | ||||||
| @@ -36,9 +37,10 @@ public class PivotBrasRentre extends CommandBase { | |||||||
|     else if(brasTelescopique.photocell()){ |     else if(brasTelescopique.photocell()){ | ||||||
|       brasTelescopique.Reset(); |       brasTelescopique.Reset(); | ||||||
|       brasTelescopique.AvanceRecule(0); |       brasTelescopique.AvanceRecule(0); | ||||||
|  |       brasTelescopique.ouvrir(); | ||||||
|     } |     } | ||||||
|     else{ |     else{ | ||||||
|       brasTelescopique.AvanceRecule(.5); |       brasTelescopique.AvanceRecule(0.5); | ||||||
|     } |     } | ||||||
|     if(pivot.limitpivot()){ |     if(pivot.limitpivot()){ | ||||||
|       pivot.Reset(); |       pivot.Reset(); | ||||||
|   | |||||||
| @@ -29,12 +29,14 @@ public class PivotChercheBas extends CommandBase { | |||||||
|   public void execute() { |   public void execute() { | ||||||
|     if(brasTelescopique.distance()<10){ |     if(brasTelescopique.distance()<10){ | ||||||
|       brasTelescopique.AvanceRecule(0.5); |       brasTelescopique.AvanceRecule(0.5); | ||||||
|  |       brasTelescopique.fermer(); | ||||||
|     } |     } | ||||||
|   else if(brasTelescopique.distance()>11) { |   else if(brasTelescopique.distance()>11) { | ||||||
|     brasTelescopique.AvanceRecule(-0.5); |     brasTelescopique.AvanceRecule(-0.5); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|       brasTelescopique.AvanceRecule(0); |       brasTelescopique.AvanceRecule(0); | ||||||
|  |       brasTelescopique.ouvrir(); | ||||||
|     } |     } | ||||||
|     if (pivot.distance()<10){ |     if (pivot.distance()<10){ | ||||||
|       pivot.monteDescendre(0.5); |       pivot.monteDescendre(0.5); | ||||||
|   | |||||||
| @@ -29,12 +29,14 @@ public class PivotChercheHaut extends CommandBase { | |||||||
|   public void execute() { |   public void execute() { | ||||||
|     if(brasTelescopique.distance()<10){ |     if(brasTelescopique.distance()<10){ | ||||||
|       brasTelescopique.AvanceRecule(0.5); |       brasTelescopique.AvanceRecule(0.5); | ||||||
|  |       brasTelescopique.fermer(); | ||||||
|     } |     } | ||||||
|   else if(brasTelescopique.distance()>11) { |   else if(brasTelescopique.distance()>11) { | ||||||
|     brasTelescopique.AvanceRecule(-0.5); |     brasTelescopique.AvanceRecule(-0.5); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|       brasTelescopique.AvanceRecule(0); |       brasTelescopique.AvanceRecule(0); | ||||||
|  |       brasTelescopique.ouvrir(); | ||||||
|     } |     } | ||||||
|     if (pivot.distance()<10){ |     if (pivot.distance()<10){ | ||||||
|       pivot.monteDescendre(0.5); |       pivot.monteDescendre(0.5); | ||||||
|   | |||||||
| @@ -31,12 +31,14 @@ public class PivoteBrasBas extends CommandBase { | |||||||
|   public void execute() { |   public void execute() { | ||||||
|     if(brasTelescopique.distance()<10){ |     if(brasTelescopique.distance()<10){ | ||||||
|       brasTelescopique.AvanceRecule(0.5); |       brasTelescopique.AvanceRecule(0.5); | ||||||
|  |       brasTelescopique.fermer(); | ||||||
|     } |     } | ||||||
|   else if(brasTelescopique.distance()>11) { |   else if(brasTelescopique.distance()>11) { | ||||||
|     brasTelescopique.AvanceRecule(-0.5); |     brasTelescopique.AvanceRecule(-0.5); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|       brasTelescopique.AvanceRecule(0); |       brasTelescopique.AvanceRecule(0); | ||||||
|  |       brasTelescopique.ouvrir(); | ||||||
|     } |     } | ||||||
|     if (pivot.distance()<10){ |     if (pivot.distance()<10){ | ||||||
|       pivot.monteDescendre(0.5); |       pivot.monteDescendre(0.5); | ||||||
|   | |||||||
| @@ -29,12 +29,14 @@ public class PivoteBrasHaut extends CommandBase { | |||||||
|   public void execute() { |   public void execute() { | ||||||
|     if(brasTelescopique.distance()<10){ |     if(brasTelescopique.distance()<10){ | ||||||
|       brasTelescopique.AvanceRecule(0.5); |       brasTelescopique.AvanceRecule(0.5); | ||||||
|  |       brasTelescopique.fermer(); | ||||||
|     } |     } | ||||||
|   else if(brasTelescopique.distance()>11) { |   else if(brasTelescopique.distance()>11) { | ||||||
|     brasTelescopique.AvanceRecule(-0.5); |     brasTelescopique.AvanceRecule(-0.5); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|       brasTelescopique.AvanceRecule(0); |       brasTelescopique.AvanceRecule(0); | ||||||
|  |       brasTelescopique.ouvrir(); | ||||||
|     } |     } | ||||||
|     if (pivot.distance()<10){ |     if (pivot.distance()<10){ | ||||||
|       pivot.monteDescendre(0.5); |       pivot.monteDescendre(0.5); | ||||||
|   | |||||||
| @@ -29,12 +29,14 @@ public class PivoteBrasMilieux extends CommandBase { | |||||||
|   public void execute() { |   public void execute() { | ||||||
|     if(brasTelescopique.distance()<10){ |     if(brasTelescopique.distance()<10){ | ||||||
|       brasTelescopique.AvanceRecule(0.5); |       brasTelescopique.AvanceRecule(0.5); | ||||||
|  |       brasTelescopique.fermer(); | ||||||
|     } |     } | ||||||
|   else if(brasTelescopique.distance()>11) { |   else if(brasTelescopique.distance()>11) { | ||||||
|     brasTelescopique.AvanceRecule(-0.5); |     brasTelescopique.AvanceRecule(-0.5); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|       brasTelescopique.AvanceRecule(0); |       brasTelescopique.AvanceRecule(0); | ||||||
|  |       brasTelescopique.ouvrir(); | ||||||
|     } |     } | ||||||
|     if (pivot.distance()<10){ |     if (pivot.distance()<10){ | ||||||
|       pivot.monteDescendre(0.5); |       pivot.monteDescendre(0.5); | ||||||
|   | |||||||
| @@ -76,5 +76,7 @@ public void resetGyro(){ | |||||||
|     teb .add("encodeurarrieredroit",0.1); |     teb .add("encodeurarrieredroit",0.1); | ||||||
|     teb .add("encodeuravantgauche",0.1);   |     teb .add("encodeuravantgauche",0.1);   | ||||||
|     teb .add("distance",0.1); |     teb .add("distance",0.1); | ||||||
|  |     teb .add("brakedroit",0.1); | ||||||
|  |     teb .add("brakegauche", 0.1); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -8,9 +8,11 @@ import edu.wpi.first.wpilibj2.command.SubsystemBase; | |||||||
| import com.ctre.phoenix.motorcontrol.can.WPI_TalonSRX; | import com.ctre.phoenix.motorcontrol.can.WPI_TalonSRX; | ||||||
| import edu.wpi.first.wpilibj.DigitalInput; | import edu.wpi.first.wpilibj.DigitalInput; | ||||||
| import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; | import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; | ||||||
|  | import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab; | ||||||
| import frc.robot.Constants; | import frc.robot.Constants; | ||||||
|  |  | ||||||
| public class Gratte extends SubsystemBase { | public class Gratte extends SubsystemBase { | ||||||
|  |   ShuffleboardTab teb = Shuffleboard.getTab("teb"); | ||||||
|   private WPI_TalonSRX Gratted = new WPI_TalonSRX(Constants.leverGratte);   |   private WPI_TalonSRX Gratted = new WPI_TalonSRX(Constants.leverGratte);   | ||||||
|   private WPI_TalonSRX Gratteg = new WPI_TalonSRX(Constants.baisserGratte); |   private WPI_TalonSRX Gratteg = new WPI_TalonSRX(Constants.baisserGratte); | ||||||
|   private DigitalInput limithd = new DigitalInput(Constants.limithd); |   private DigitalInput limithd = new DigitalInput(Constants.limithd); | ||||||
| @@ -44,9 +46,9 @@ public class Gratte extends SubsystemBase { | |||||||
|   } |   } | ||||||
|   @Override |   @Override | ||||||
|   public void periodic() { |   public void periodic() { | ||||||
|     Shuffleboard.getTab("SmartDashBoard") .add("limithd",0.1); |     teb .add("limithd", 0.1); | ||||||
|     Shuffleboard.getTab("SmartDashBoard") .add("limitbd",0.1); |     teb .add("limithg", 0.1); | ||||||
|     Shuffleboard.getTab("SmartDashBoard") .add("limithg",0.1); |     teb .add("limitbd", 0.1); | ||||||
|     Shuffleboard.getTab("SmartDashBoard") .add("limitbg",0.1); |     teb .add("limitbg", 0.1); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,6 +6,8 @@ package frc.robot.subsystems; | |||||||
|  |  | ||||||
| import edu.wpi.first.cameraserver.CameraServer; | import edu.wpi.first.cameraserver.CameraServer; | ||||||
| import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; | import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; | ||||||
|  | import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab; | ||||||
|  |  | ||||||
| import org.photonvision.PhotonCamera; | import org.photonvision.PhotonCamera; | ||||||
| import org.photonvision.common.hardware.VisionLEDMode; | import org.photonvision.common.hardware.VisionLEDMode; | ||||||
|  |  | ||||||
| @@ -15,6 +17,7 @@ import edu.wpi.first.wpilibj2.command.SubsystemBase; | |||||||
|  |  | ||||||
|  |  | ||||||
| public class Limelight extends SubsystemBase { | public class Limelight extends SubsystemBase { | ||||||
|  |   ShuffleboardTab teb = Shuffleboard.getTab("teb"); | ||||||
|   PhotonCamera limelight = new PhotonCamera("limelight"); |   PhotonCamera limelight = new PhotonCamera("limelight"); | ||||||
|   /** Creates a new Limelight. */ |   /** Creates a new Limelight. */ | ||||||
|   public Limelight() { |   public Limelight() { | ||||||
| @@ -56,6 +59,6 @@ public class Limelight extends SubsystemBase { | |||||||
|   @Override |   @Override | ||||||
|   public void periodic() { |   public void periodic() { | ||||||
|     CameraServer.startAutomaticCapture(); |     CameraServer.startAutomaticCapture(); | ||||||
|     Shuffleboard.getTab("SmartDashBoard") .add("limelight",0.1); |     teb .add("limelight", 0.1); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,15 +9,21 @@ import com.revrobotics.CANSparkMax; | |||||||
| import com.revrobotics.CANSparkMaxLowLevel.MotorType; | import com.revrobotics.CANSparkMaxLowLevel.MotorType; | ||||||
|  |  | ||||||
| import edu.wpi.first.wpilibj.DigitalInput; | import edu.wpi.first.wpilibj.DigitalInput; | ||||||
|  | import edu.wpi.first.wpilibj.DoubleSolenoid; | ||||||
|  | import edu.wpi.first.wpilibj.PneumaticsModuleType; | ||||||
|  | import edu.wpi.first.wpilibj.DoubleSolenoid.Value; | ||||||
| import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; | import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; | ||||||
|  | import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab; | ||||||
| import edu.wpi.first.wpilibj2.command.SubsystemBase; | import edu.wpi.first.wpilibj2.command.SubsystemBase; | ||||||
| import frc.robot.Constants; | import frc.robot.Constants; | ||||||
|  |  | ||||||
| public class BrasTelescopique extends SubsystemBase { | public class BrasTelescopique extends SubsystemBase { | ||||||
|  |   ShuffleboardTab teb = Shuffleboard.getTab("teb"); | ||||||
|   /** Creates a new BrasTelescopique. */ |   /** Creates a new BrasTelescopique. */ | ||||||
|   public BrasTelescopique() {} |   public BrasTelescopique() {} | ||||||
|   final CANSparkMax Winch = new CANSparkMax(Constants.BrasTelescopique,MotorType.kBrushless); |   final CANSparkMax Winch = new CANSparkMax(Constants.BrasTelescopique,MotorType.kBrushless); | ||||||
|   private DigitalInput photocell = new DigitalInput(Constants.photocell); |   private DigitalInput photocell = new DigitalInput(Constants.photocell); | ||||||
|  |   private DoubleSolenoid brakewinch = new DoubleSolenoid(PneumaticsModuleType.CTREPCM,Constants.brakewinchf, Constants.brakewinchb); | ||||||
|   public void AvanceRecule(double vitesse) { |   public void AvanceRecule(double vitesse) { | ||||||
|     Winch.set(vitesse); |     Winch.set(vitesse); | ||||||
|   } |   } | ||||||
| @@ -30,9 +36,17 @@ public class BrasTelescopique extends SubsystemBase { | |||||||
|   public boolean photocell(){ |   public boolean photocell(){ | ||||||
|     return photocell.get();  |     return photocell.get();  | ||||||
|   } |   } | ||||||
|  |   public void fermer() { | ||||||
|  |     brakewinch.set(Value.kReverse); | ||||||
|  |     } | ||||||
|  |     public void ouvrir() { | ||||||
|  |       brakewinch.set(Value.kForward); | ||||||
|  |     } | ||||||
|   @Override |   @Override | ||||||
|   public void periodic() { |   public void periodic() { | ||||||
|     Shuffleboard.getTab("SmartDashBoard") .add("photocell",0.1); |     teb .add("``photocell``",0.1); | ||||||
|     Shuffleboard.getTab("SmartDashBoard") .add("winch",0.1); |     teb .add("winch",0.1); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |    | ||||||
| } | } | ||||||
|   | |||||||
| @@ -8,9 +8,12 @@ import edu.wpi.first.wpilibj.DoubleSolenoid; | |||||||
| import edu.wpi.first.wpilibj.PneumaticsModuleType; | import edu.wpi.first.wpilibj.PneumaticsModuleType; | ||||||
| import edu.wpi.first.wpilibj2.command.SubsystemBase; | import edu.wpi.first.wpilibj2.command.SubsystemBase; | ||||||
| import edu.wpi.first.wpilibj.DoubleSolenoid.Value; | import edu.wpi.first.wpilibj.DoubleSolenoid.Value; | ||||||
|  | import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; | ||||||
|  | import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab; | ||||||
| import frc.robot.Constants; | import frc.robot.Constants; | ||||||
|  |  | ||||||
| public class Pince extends SubsystemBase { |  | ||||||
|  | public class Pince extends SubsystemBase{ | ||||||
|   private DoubleSolenoid pistonPince = new DoubleSolenoid(PneumaticsModuleType.CTREPCM,Constants.pistonpinceouvre, Constants.pistonpinceferme); |   private DoubleSolenoid pistonPince = new DoubleSolenoid(PneumaticsModuleType.CTREPCM,Constants.pistonpinceouvre, Constants.pistonpinceferme); | ||||||
|   /** Creates a new Pince. */ |   /** Creates a new Pince. */ | ||||||
|   public Pince() { |   public Pince() { | ||||||
| @@ -23,6 +26,5 @@ public class Pince extends SubsystemBase { | |||||||
|    } |    } | ||||||
|   @Override |   @Override | ||||||
|   public void periodic() { |   public void periodic() { | ||||||
|      |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ package frc.robot.subsystems.bras; | |||||||
|  |  | ||||||
| import edu.wpi.first.wpilibj.DigitalInput; | import edu.wpi.first.wpilibj.DigitalInput; | ||||||
| import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; | import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; | ||||||
|  | import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab; | ||||||
| import edu.wpi.first.wpilibj2.command.SubsystemBase; | import edu.wpi.first.wpilibj2.command.SubsystemBase; | ||||||
| import frc.robot.Constants; | import frc.robot.Constants; | ||||||
|  |  | ||||||
| @@ -13,6 +14,7 @@ import com.revrobotics.CANSparkMax; | |||||||
| import com.revrobotics.CANSparkMaxLowLevel.MotorType; | import com.revrobotics.CANSparkMaxLowLevel.MotorType; | ||||||
|  |  | ||||||
| public class Pivot extends SubsystemBase { | public class Pivot extends SubsystemBase { | ||||||
|  |   ShuffleboardTab teb = Shuffleboard.getTab("teb"); | ||||||
|   // moteur |   // moteur | ||||||
|   private CANSparkMax pivot = new CANSparkMax(Constants.pivot,MotorType.kBrushless); |   private CANSparkMax pivot = new CANSparkMax(Constants.pivot,MotorType.kBrushless); | ||||||
|   private DigitalInput limitpivot = new DigitalInput(Constants.limitpivot); |   private DigitalInput limitpivot = new DigitalInput(Constants.limitpivot); | ||||||
| @@ -34,8 +36,6 @@ public class Pivot extends SubsystemBase { | |||||||
|   } |   } | ||||||
|   @Override |   @Override | ||||||
|   public void periodic() { |   public void periodic() { | ||||||
|     Shuffleboard.getTab("SmartDashBoard") .add("limitpivot",0.1); |     teb .add("encodeur", 0.1); | ||||||
|     Shuffleboard.getTab("SmartDashBoard") .add("pivot encodeur",0.1); |  | ||||||
|   } |   } | ||||||
|  } | } | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user