Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Controllers Page #177

Merged
merged 17 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/gamesir_controller.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions lib/pages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class Routes {

/// The name of the logs page.
static const String logs = "Logs";

/// The name of the controllers page
static const String controllers = "Controllers";

/// The name of the rocks page.
static const String rocks = "Rocks";
Expand Down
1 change: 1 addition & 0 deletions lib/src/models/rover/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,6 @@ class Controller extends Model {
// print(message.toProto3Json());
models.messages.sendMessage(message);
}
notifyListeners();
}
}
14 changes: 7 additions & 7 deletions lib/src/models/rover/controls/arm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,21 @@ class ArmControls extends RoverControls {
@override
List<Message> parseInputs(GamepadState state) => [
// Manual control
if (state.normalRightX.abs() > state.normalRightY.abs() && state.normalRightX != 0)
if (state.normalRightX.abs() > state.normalRightJoystickY.abs() && state.normalRightX != 0)
ArmCommand(swivel: MotorCommand(moveRadians: state.normalRightX * settings.swivel)),
if (state.normalRightY.abs() > state.normalRightX.abs() && state.normalRightY != 0)
ArmCommand(shoulder: MotorCommand(moveRadians: state.normalRightY * settings.shoulder)),
if (state.normalRightJoystickY.abs() > state.normalRightX.abs() && state.normalRightJoystickY != 0)
ArmCommand(shoulder: MotorCommand(moveRadians: state.normalRightJoystickY * settings.shoulder)),
if (state.normalLeftY != 0) ArmCommand(elbow: MotorCommand(moveRadians: state.normalLeftY * settings.elbow)),
// The bumpers should be pseudo-IK: Move the shoulder and elbow in sync.
if (state.normalShoulder != 0) ArmCommand(
shoulder: MotorCommand(moveRadians: state.normalShoulder * settings.shoulder * -1),
elbow: MotorCommand(moveRadians: state.normalShoulder * settings.elbow),
if (state.normalShoulders != 0) ArmCommand(
shoulder: MotorCommand(moveRadians: state.normalShoulders * settings.shoulder * -1),
elbow: MotorCommand(moveRadians: state.normalShoulders * settings.elbow),
),

// Gripper
if (state.normalDpadY != 0) GripperCommand(lift: MotorCommand(moveRadians: state.normalDpadY * settings.lift)),
if (state.normalDpadX != 0) GripperCommand(rotate: MotorCommand(moveRadians: state.normalDpadX * settings.rotate)),
if (state.normalTrigger != 0) GripperCommand(pinch: MotorCommand(moveRadians: state.normalTrigger * settings.pinch)),
if (state.normalTriggers != 0) GripperCommand(pinch: MotorCommand(moveRadians: state.normalTriggers * settings.pinch)),

// Custom actions
if (state.buttonA && !isAPressed) () { isAPressed = true; return GripperCommand(open: true); }(),
Expand Down
2 changes: 1 addition & 1 deletion lib/src/models/rover/controls/camera.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class CameraControls extends RoverControls {
final newFrontSwivel = state.normalLeftX;
final newFrontTilt = state.normalLeftY;
final newRearSwivel = state.normalRightX;
final newRearTilt = -1 * state.normalRightY;
final newRearTilt = -1 * state.normalRightJoystickY;
if (newFrontSwivel.abs() >= 0.05 || newFrontTilt.abs() >= 0.05) {
// Update the front camera. Now, choose which axis
if (newFrontSwivel.abs() > newFrontTilt.abs()) {
Expand Down
4 changes: 2 additions & 2 deletions lib/src/models/rover/controls/modern_drive.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class ModernDriveControls extends RoverControls {

/// Gets all commands for the wheels based on the gamepad state.
List<DriveCommand> getWheelCommands(GamepadState state) {
final speed = state.normalTrigger; // sum of both triggers, [-1, 1]
final speed = state.normalTriggers; // sum of both triggers, [-1, 1]
if (speed == 0) {
final left = state.normalLeftX;
final right = state.normalLeftX;
Expand Down Expand Up @@ -99,7 +99,7 @@ class ModernDriveControls extends RoverControls {
final newFrontSwivel = state.normalDpadX;
final newFrontTilt = state.normalDpadY;
final newRearSwivel = state.normalRightX;
final newRearTilt = state.normalRightY;
final newRearTilt = state.normalRightJoystickY;
if (newFrontSwivel.abs() >= 0.05 || newFrontTilt.abs() >= 0.05) {
// Update the front camera. Now, choose which axis
if (newFrontSwivel.abs() > newFrontTilt.abs()) {
Expand Down
2 changes: 1 addition & 1 deletion lib/src/models/rover/controls/tank_drive.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class DriveControls extends RoverControls {
List<Message> parseInputs(GamepadState state) => [
DriveCommand(throttle: throttle, setThrottle: true),
DriveCommand(setLeft: true, left: state.normalLeftY),
DriveCommand(setRight: true, right: -1*state.normalRightY),
DriveCommand(setRight: true, right: -1*state.normalRightJoystickY),
];

@override
Expand Down
90 changes: 90 additions & 0 deletions lib/src/pages/controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import "package:flutter/material.dart";
import "package:rover_dashboard/models.dart";
import "package:rover_dashboard/widgets.dart";

import "controllers/controller.dart";

/// A view model to select and listen to a gamepad.
class ControllersViewModel with ChangeNotifier {
/// The gamepad to listen to.
Controller selectedController = models.rover.controller1;

/// Starts listening to the gamepad.
ControllersViewModel() {
selectedController.addListener(notifyListeners);
}

@override
void dispose() {
selectedController.removeListener(notifyListeners);
super.dispose();
}

/// Changes which controller is being listened to.
void setController(Controller? value) {
if (value == null) return;
selectedController.removeListener(notifyListeners);
selectedController = value;
selectedController.addListener(notifyListeners);
notifyListeners();
}
}

/// The UI Page to display the controller status
class ControllersPage extends ReactiveWidget<ControllersViewModel> {
/// The index of this view.
final int index;

/// Const constructor for [ControllersPage]
const ControllersPage({required this.index, super.key});

@override
ControllersViewModel createModel() => ControllersViewModel();

@override
Widget build(BuildContext context, ControllersViewModel model) => Column(
children: [
const SizedBox(height: 16),
Row(
children: [
const Spacer(),
const Text("Controller: "),
DropdownButton<Controller>(
value: model.selectedController,
onChanged: model.setController,
items: [
DropdownMenuItem(
value: models.rover.controller1,
child: const Text("Controller 1"),
),
DropdownMenuItem(
value: models.rover.controller2,
child: const Text("Controller 2"),
),
DropdownMenuItem(
value: models.rover.controller3,
child: const Text("Controller 3"),
),
],
),
const SizedBox(width: 8),
FilledButton(
onPressed: model.selectedController.isConnected
? model.selectedController.gamepad.pulse : null,
child: const Text("Vibrate"),
),
const Spacer(),
ViewsSelector(index: index),
],
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10),
child: Center(
child: ControllerWidget(model.selectedController),
),
),
),
],
);
}
35 changes: 35 additions & 0 deletions lib/src/pages/controllers/button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import "package:flutter/material.dart";

/// Represents a button that is pressed or not.
class ControllerButton extends StatelessWidget {
/// The radius with which to draw this button.
final double radius;

/// How thick the border should be.
final double borderWidth;

/// Whether the button is pressed or not.
final bool isPressed;

/// The color of the button.
final Color color;

/// Draws a small circle to represent a button that can be pressed.
const ControllerButton({
required this.isPressed,
required this.radius,
required this.borderWidth,
required this.color,
});

@override
Widget build(BuildContext context) => Container(
width: radius,
height: radius,
decoration: BoxDecoration(
color: isPressed ? color : null,
shape: BoxShape.circle,
border: Border.all(color: color, width: borderWidth),
),
);
}
73 changes: 73 additions & 0 deletions lib/src/pages/controllers/constants.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import "package:flutter/material.dart";

/// The color to fill in all gamepad buttons with.
const gamepadColor = Colors.blue;

/// The size of the controller image. Useful for overlaying elements on the picture.
const Size imageSize = Size(905, 568);

/// The radius for a button.
const double normalButtonRadius = 40;

/// The radius for a joystick.
const double normalJoystickRadius = 70;

/// The furthest a joystick can be off its center.
const double joystickMaxOffset = 40;

/// The width of the trigger bars.
const double normalTriggerWidth = 30;

/// The height of hte trigger bars.
const double normalTriggerHeight = 80;

/// The thickness of the trigger bars.
const double normalTriggerOutline = 10;

/// The position of the A button on the image.
const Offset buttonA = Offset(727, 230);

/// The position of the B button on the image.
const Offset buttonB = Offset(784, 173);

/// The position of the X button on the image.
const Offset buttonX = Offset(670, 173);

/// The position of the Y button on the image.
const Offset buttonY = Offset(727, 117);

/// The position of the left bumper/shoulder on the image.
const Offset leftBumper = Offset(186, 16);

/// The position of the right bumper/shoulder on the image.
const Offset rightBumper = Offset(726, 16);

/// The position of the left trigger on the image.
const Offset leftTrigger = Offset(40, 35);

/// The position of the right trigger on the image.
const Offset rightTrigger = Offset(872, 35);

/// The position of the select button on the image.
const Offset select = Offset(349, 112);

/// The position of the start button on the image.
const Offset start = Offset(558, 112);

/// The position of the up arrow button on the image.
const Offset dPadUp = Offset(180, 122);

/// The position of the down arrow button on the image.
const Offset dPadDown = Offset(180, 221);

/// The position of the left arrow button on the image.
const Offset dPadLeft = Offset(125, 175);

/// The position of the right arrow button on the image.
const Offset dPadRight = Offset(227, 175);

/// The position of the left joystick on the image.
const Offset leftStick = Offset(289, 295);

/// The position of the right joystic on the image.
const Offset rightStick = Offset(616, 295);
Loading
Loading