Skip to content

Commit

Permalink
Autonomy fixes and cleanups (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
Levi-Lesches authored Feb 9, 2024
1 parent 1ca815c commit 66a19dd
Show file tree
Hide file tree
Showing 15 changed files with 151 additions and 151 deletions.
2 changes: 1 addition & 1 deletion lib/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export "src/models/rover/metrics.dart";
export "src/models/rover/rover.dart";

// View models
export "src/models/view/autonomy.dart";
export "src/models/view/map.dart";
export "src/models/view/logs.dart";
export "src/models/view/mars.dart";
export "src/models/view/science.dart";
Expand Down
2 changes: 1 addition & 1 deletion lib/pages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/// This library may depend on the data, services, models, and widgets libraries.
library pages;

export "src/pages/autonomy.dart";
export "src/pages/map.dart";
export "src/pages/home.dart";
export "src/pages/science.dart";
export "src/pages/logs.dart";
Expand Down
2 changes: 1 addition & 1 deletion lib/src/models/data/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class HomeModel extends Model {

/// Sets a new message that will disappear in 3 seconds.
void setMessage({required Severity severity, required String text, bool permanent = false}) {
if (_hasError) return; // Don't replace error messages
if (_hasError && severity != Severity.critical) return; // Don't replace critical messages
_messageTimer?.cancel(); // the new message might be cleared if the old one were about to
message = TaskbarMessage(severity: severity, text: text);
notifyListeners();
Expand Down
8 changes: 3 additions & 5 deletions lib/src/models/data/sockets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ class Sockets extends Model {
data.destination = settings.subsystemsSocket.copyWith(address: addressOverride);
video.destination = settings.videoSocket.copyWith(address: addressOverride);
autonomy.destination = settings.autonomySocket.copyWith(address: addressOverride);
await reset();
}

/// Resets all the sockets.
Expand All @@ -101,20 +100,19 @@ class Sockets extends Model {
/// Resetting the sockets will bypass these errors.
Future<void> reset() async {
for (final socket in sockets) {
// Sockets lose their destination when disposed, so we save it and restore it.
final destination = socket.destination;
await socket.dispose();
socket.destination = destination;
await socket.init();
}
// Sockets lose their destination when disposed, so we restore it.
await updateSockets();
}

/// Change which rover is being used.
Future<void> setRover(RoverType? value) async {
if (value == null) return;
rover = value;
models.home.setMessage(severity: Severity.info, text: "Using: ${rover.name}");
await updateSockets();
await reset();
notifyListeners();
}
}
10 changes: 0 additions & 10 deletions lib/src/models/data/views.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,8 @@ class DashboardView {
static final List<DashboardView> uiViews = [
DashboardView(name: Routes.science, builder: (context) => SciencePage()),
DashboardView(name: Routes.autonomy, builder: (context) => MapPage()),
logView,
];

/// The [LogsPage] view.
static final logView = DashboardView(name: Routes.logs, builder: (context) => LogsPage());

/// A blank view.
static final blank = DashboardView(
name: Routes.blank,
Expand Down Expand Up @@ -142,10 +138,4 @@ class ViewsModel extends Model {
}
notifyListeners();
}

/// Opens the log page in a full-screen view.
void openLogs() {
views = [DashboardView.logView];
notifyListeners();
}
}
6 changes: 3 additions & 3 deletions lib/src/models/view/builders/autonomy_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class AutonomyCommandBuilder extends ValueBuilder<AutonomyCommand> {
if (_handshake != null) {
models.home.setMessage(severity: Severity.info, text: "Command received");
} else {
models.home.setMessage(severity: Severity.error, text: "The rover did not receive that command");
models.home.setMessage(severity: Severity.error, text: "Command not received");
}
isLoading = false;
notifyListeners();
Expand All @@ -72,12 +72,12 @@ class AutonomyCommandBuilder extends ValueBuilder<AutonomyCommand> {
models.sockets.autonomy.sendMessage(message);
models.sockets.autonomy.sendMessage(message);
models.sockets.autonomy.sendMessage(message);
models.home.setMessage(severity: Severity.info, text: "Aborting autonomy...");
models.home.setMessage(severity: Severity.info, text: "Aborting...");
await Future<void>.delayed(const Duration(seconds: 1));
if (_handshake != null) {
models.home.setMessage(severity: Severity.info, text: "Command received");
} else {
models.home.setMessage(severity: Severity.critical, text: "The rover did not receive that command");
models.home.setMessage(severity: Severity.critical, text: "Command not received");
}
isLoading = false;
notifyListeners();
Expand Down
15 changes: 10 additions & 5 deletions lib/src/models/view/logs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,21 @@ class LogsViewModel with ChangeNotifier {

/// Disables [LogsOptionsViewModel.autoscroll] when the user scrolls manually.
void onScroll() {
final enableAutoscroll = scrollController.position.pixels == scrollController.position.maxScrollExtent;
final enableAutoscroll = scrollController.position.pixels == 0;
options.setAutoscroll(input: enableAutoscroll);
}

/// Scrolls to the bottom when a new log appears (if [LogsOptionsViewModel.autoscroll] is true).
void onNewLog() {
notifyListeners();
if (options.autoscroll && scrollController.hasClients) {
scrollController.jumpTo(scrollController.position.maxScrollExtent);
}
if (!scrollController.hasClients) return;
scrollController.jumpTo(options.autoscroll ? 0 : scrollController.offset + 64);
}

/// Jumps to the bottom of the logs.
void jumpToBottom() {
if (!scrollController.hasClients) return;
scrollController.animateTo(0, duration: const Duration(milliseconds: 500), curve: Curves.easeOutBack);
}

/// Updates the UI.
Expand All @@ -106,6 +111,6 @@ class LogsViewModel with ChangeNotifier {
if (log.level.value > options.levelFilter.value) continue;
result.add(log);
}
return result;
return result.reversed.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class AutonomyModel with ChangeNotifier {
],
];

/// A list of markers maanually placed by the user. Useful for the Extreme Retrieval Mission.
/// A list of markers manually placed by the user. Useful for the Extreme Retrieval Mission.
List<GpsCoordinates> markers = [];
/// The view model to edit the coordinate of the marker.
GpsBuilder markerBuilder = GpsBuilder();
Expand All @@ -92,8 +92,6 @@ class AutonomyModel with ChangeNotifier {
/// The grid of size [gridSize] with the rover in the center, ready to draw on the UI.
List<List<AutonomyCell>> get grid {
final result = empty;
markCell(result, data.destination, AutonomyCell.destination);
markCell(result, roverPosition, AutonomyCell.rover);
for (final obstacle in data.obstacles) {
markCell(result, obstacle, AutonomyCell.obstacle);
}
Expand All @@ -103,6 +101,9 @@ class AutonomyModel with ChangeNotifier {
for (final marker in markers) {
markCell(result, marker, AutonomyCell.marker);
}
// Marks the rover and destination -- these should be last
if (data.hasDestination()) markCell(result, data.destination, AutonomyCell.destination);
markCell(result, roverPosition, AutonomyCell.rover);
return result;
}

Expand Down Expand Up @@ -151,7 +152,7 @@ class AutonomyModel with ChangeNotifier {

/// A handler to call when new data arrives. Updates [data] and the UI.
void onNewData(AutonomyData value) {
data.mergeFromMessage(value);
data = value;
services.files.logData(value);
notifyListeners();
}
Expand Down
4 changes: 1 addition & 3 deletions lib/src/pages/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,9 @@ class HomePageState extends State<HomePage>{
icon: const Icon(Icons.menu),
onPressed: () => setState(() => showSidebar = !showSidebar),
),),

],

),
bottomNavigationBar: Footer(),
bottomNavigationBar: const Footer(),
body: Row(
children: [
const Expanded(child: ViewsWidget()),
Expand Down
100 changes: 50 additions & 50 deletions lib/src/pages/logs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import "package:flutter/material.dart";

import "package:rover_dashboard/data.dart";
import "package:rover_dashboard/models.dart";
import "package:rover_dashboard/pages.dart";
import "package:rover_dashboard/widgets.dart";

/// A widget to show the options for the logs page.
Expand Down Expand Up @@ -65,6 +64,7 @@ class LogsOptions extends ReactiveWidget<LogsOptionsViewModel> {
value: model.autoscroll,
onChanged: (input) {
model.setAutoscroll(input: input);
if (input ?? false) viewModel.jumpToBottom();
viewModel.update();
},
),),
Expand All @@ -86,57 +86,56 @@ class LogsState extends State<LogsPage> {
final model = LogsViewModel();

@override
Widget build(BuildContext context) => Stack(
children: [
Column(children: [
const SizedBox(height: 50),
LogsOptions(model),
const Divider(),
Expanded(child: LogsBody(model)),
],),
Container(
color: context.colorScheme.surface,
height: 50,
child: Row(children: [
const SizedBox(width: 8),
Text("Logs", style: context.textTheme.headlineMedium),
const Spacer(),
IconButton(
icon: const Icon(Icons.delete_forever),
onPressed: models.logs.clear,
tooltip: "Clear logs",
),
IconButton(
icon: const Icon(Icons.help),
tooltip: "Help",
onPressed: () => showDialog<void>(
context: context,
builder: (context) => AlertDialog(
title: const Text("Logs help"),
content: Column(mainAxisSize: MainAxisSize.min, children: [
const Text("This page contains all logs received by the dashboard.\nSelecting a level means that only messages of that level or higher will be shown.", textAlign: TextAlign.center,),
const SizedBox(height: 4),
ListTile(leading: criticalWidget, title: const Text("Critical"), subtitle: const Text("The rover is in a broken state and may shutdown")),
const ListTile(leading: errorWidget, title: Text("Error"), subtitle: Text("Something you tried didn't work, but the rover can still function")),
const ListTile(leading: warningWidget, title: Text("Warning"), subtitle: Text("Something may have gone wrong, you should check it out")),
ListTile(leading: infoWidget, title: const Text("Info"), subtitle: const Text("The rover is functioning normally")),
const ListTile(leading: debugWidget, title: Text("Debug"), subtitle: Text("Extra information that shows what the rover's thinking")),
const ListTile(leading: traceWidget, title: Text("Trace"), subtitle: Text("Values from the code to debug specific issues")),
const SizedBox(height: 12),
],),
actions: [
ElevatedButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text("Close"),
),
],
),
Widget build(BuildContext context) => Scaffold(
body: Column(children: [
const SizedBox(height: 12),
LogsOptions(model),
const Divider(),
Expanded(child: LogsBody(model)),
],),
appBar: AppBar(
title: const Text("Logs"),
actions: [
IconButton(
icon: const Icon(Icons.help),
tooltip: "Help",
onPressed: () => showDialog<void>(
context: context,
builder: (context) => AlertDialog(
title: const Text("Logs help"),
content: Column(mainAxisSize: MainAxisSize.min, children: [
const Text("This page contains all logs received by the dashboard.\nSelecting a level means that only messages of that level or higher will be shown.", textAlign: TextAlign.center,),
const SizedBox(height: 4),
ListTile(leading: criticalWidget, title: const Text("Critical"), subtitle: const Text("The rover is in a broken state and may shutdown")),
const ListTile(leading: errorWidget, title: Text("Error"), subtitle: Text("Something you tried didn't work, but the rover can still function")),
const ListTile(leading: warningWidget, title: Text("Warning"), subtitle: Text("Something may have gone wrong, you should check it out")),
ListTile(leading: infoWidget, title: const Text("Info"), subtitle: const Text("The rover is functioning normally")),
const ListTile(leading: debugWidget, title: Text("Debug"), subtitle: Text("Extra information that shows what the rover's thinking")),
const ListTile(leading: traceWidget, title: Text("Trace"), subtitle: Text("Values from the code to debug specific issues")),
const SizedBox(height: 12),
],),
actions: [
ElevatedButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text("Close"),
),
],
),
),
const ViewsSelector(currentView: Routes.logs),
],),
),
],
),
IconButton(
icon: const Icon(Icons.vertical_align_bottom),
onPressed: model.jumpToBottom,
tooltip: "Jump to bottom",
),
IconButton(
icon: const Icon(Icons.delete_forever),
onPressed: models.logs.clear,
tooltip: "Clear logs",
),
],
),
bottomNavigationBar: const Footer(showLogs: false),
);
}

Expand All @@ -158,6 +157,7 @@ class LogsBody extends ReactiveWidget<LogsViewModel> {
: ListView.builder(
itemCount: model.logs.length,
controller: model.scrollController,
reverse: true,
itemBuilder: (context, index) => LogWidget(model.logs[index]),
);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/src/pages/autonomy.dart → lib/src/pages/map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class MapPage extends StatelessWidget {
builder: (model) => Stack(children: [
Column(children: [
const SizedBox(height: 48),
for (final row in model.grid) Expanded(
for (final row in model.grid.reversed) Expanded(
child: Row(children: [
for (final cell in row) Expanded(
child: Container(
Expand All @@ -88,7 +88,7 @@ class MapPage extends StatelessWidget {
child: cell != AutonomyCell.rover ? null : ProviderConsumer<PositionMetrics>.value(
value: models.rover.metrics.position,
builder: (position) => Transform.rotate(
angle: position.angle * pi / 180,
angle: -position.angle * pi / 180,
child: const Icon(Icons.arrow_upward, size: 24),
),
),
Expand Down
10 changes: 5 additions & 5 deletions lib/src/services/socket.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import "package:rover_dashboard/data.dart";
/// - Check [connectionStrength] or [isConnected] for the connection to the given [device].
/// - To send a message, call [sendMessage].
/// - Call [dispose] to close the socket.
class DashboardSocket extends ProtoSocket {
class DashboardSocket extends BurtUdpProtocol {
/// A callback to run when the [device] has connected.
void Function(Device device) onConnect;
/// A callback to run when the [device] has disconnected.
Expand All @@ -33,9 +33,11 @@ class DashboardSocket extends ProtoSocket {
}) : super(
port: null,
quiet: true,
heartbeatInterval: const Duration(milliseconds: 200),
);

@override
Duration get heartbeatInterval => const Duration(milliseconds: 200);

/// The connection strength, as a percentage to this [device].
final connectionStrength = ValueNotifier<double>(0);

Expand All @@ -46,11 +48,9 @@ class DashboardSocket extends ProtoSocket {
bool _isChecking = false;

/// Whether this socket has a stable connection to the [device].
@override
bool get isConnected => connectionStrength.value > 0;

@override
void updateSettings(UpdateSetting settings) { }

@override
void onMessage(WrappedMessage wrapper) => messageHandler(wrapper);

Expand Down
Loading

0 comments on commit 66a19dd

Please sign in to comment.