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

Stream science data without running tests #158

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
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
3 changes: 2 additions & 1 deletion lib/src/data/protobuf.dart
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ extension ScienceStateUtils on ScienceState {
switch (this) {
case ScienceState.SCIENCE_STATE_UNDEFINED: return "Unknown";
case ScienceState.STOP_COLLECTING: return "Idle";
case ScienceState.COLLECT_DATA: return "Collecting data";
case ScienceState.COLLECT_DATA: return "Start test";
case ScienceState.STREAM_DATA: return "Stream data";
}
// Do not use default or else you'll lose exhaustiveness checking.
throw ArgumentError("Unrecognized task: $this");
Expand Down
10 changes: 5 additions & 5 deletions lib/src/models/rover/controls/modern_drive.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import "package:rover_dashboard/models.dart";
import "package:rover_dashboard/services.dart";

/// Modern drive controls, similar to most racing video games.
///
///
/// Triggers are for acceleration, left stick for steering.
/// Also includes camera controls on the D-pad and right stick.
class ModernDriveControls extends RoverControls {
Expand Down Expand Up @@ -103,15 +103,15 @@ class ModernDriveControls extends RoverControls {
if (newFrontSwivel.abs() >= 0.05 || newFrontTilt.abs() >= 0.05) {
// Update the front camera. Now, choose which axis
if (newFrontSwivel.abs() > newFrontTilt.abs()) {
frontSwivel += newFrontSwivel * cameraSwivelIncrement;
frontSwivel += newFrontSwivel * cameraSwivelIncrement;
} else {
frontTilt += newFrontTilt * cameraTiltIncrement;
frontTilt += newFrontTilt * cameraTiltIncrement;
}
} else if (newRearSwivel.abs() >= 0.05 || newRearTilt.abs() >= 0.05) {
if (newRearSwivel.abs() > newRearTilt.abs()) {
rearSwivel += newRearSwivel * cameraSwivelIncrement;
rearSwivel += newRearSwivel * cameraSwivelIncrement;
} else {
rearTilt += newRearTilt * cameraTiltIncrement * -1;
rearTilt += newRearTilt * cameraTiltIncrement * -1;
}
}
// Clamp cameras
Expand Down
2 changes: 1 addition & 1 deletion lib/src/models/view/builders/science_command.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "package:rover_dashboard/data.dart";
import "package:rover_dashboard/models.dart";

/// A [ValueBuilder] to modify and send an [AutonomyCommand].
/// A [ValueBuilder] to modify and send an [ScienceCommand].
class ScienceCommandBuilder extends ValueBuilder<ScienceCommand> {
/// The sample number being tested.
final sample = NumberBuilder<int>(1, min: 1, max: 3);
Expand Down
29 changes: 22 additions & 7 deletions lib/src/models/view/science.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ class ScienceAnalysis {
final SampleData data = SampleData();

/// Passes the overriden data to the sensor's test to determine signs of life.
ScienceResult get testResult => data.readings.isEmpty
ScienceResult get testResult => data.readings.isEmpty
? ScienceResult.loading : sensor.test(SampleData()
..min = testBuilder.min.value
..average = testBuilder.average.value
..max = testBuilder.max.value,
);

/// Clears all readings from this analysis.
void clear() {
void clear() {
data.clear();
testBuilder.update(data);
}
Expand All @@ -87,7 +87,7 @@ class ScienceModel with ChangeNotifier {
/// A list of all the samples for all the sensors.
Map<ScienceSensor, List<ScienceAnalysis>> allSamples = {
for (final sensor in sensors) sensor: [
for (int i = 0; i < models.settings.science.numSamples; i++)
for (int i = 0; i < models.settings.science.numSamples; i++)
ScienceAnalysis(sensor),
],
};
Expand Down Expand Up @@ -140,11 +140,14 @@ class ScienceModel with ChangeNotifier {
/// Whether the page is currently loading.
bool isLoading = false;

/// Whether the pump command has just been sent.
bool isPumping = false;

/// The error, if any, that occurred while loading the data.
String? errorText;

/// Adds a value to the correct analysis for the sensor and sample.
void addReading(ScienceSensor sensor, int sample, Timestamp timestamp, double value) =>
void addReading(ScienceSensor sensor, int sample, Timestamp timestamp, double value) =>
allSamples[sensor]![sample].addReading(timestamp, value);

/// Adds a [WrappedMessage] containing a [ScienceData] to the UI.
Expand All @@ -154,9 +157,9 @@ class ScienceModel with ChangeNotifier {
final sample = data.sample;
if (!wrapper.hasTimestamp()) { throw ArgumentError("Data is missing a timestamp"); }
if (sample >= numSamples) throw RangeError("Got data for sample #${sample + 1}, but there are only $numSamples samples.\nChange the number of samples in the settings and reload.");
if (data.co2 != 0) addReading(co2, sample, wrapper.timestamp, data.co2);
if (data.humidity != 0) addReading(humidity, sample, wrapper.timestamp, data.humidity);
if (data.temperature != 0) addReading(temperature, sample, wrapper.timestamp, data.temperature);
if (data.co2 != 0) addReading(co2, sample, wrapper.timestamp, data.co2);
if (data.humidity != 0) addReading(humidity, sample, wrapper.timestamp, data.humidity);
if (data.temperature != 0) addReading(temperature, sample, wrapper.timestamp, data.temperature);
}

/// Clears all the readings from all the samples.
Expand All @@ -170,6 +173,18 @@ class ScienceModel with ChangeNotifier {
models.home.setMessage(severity: Severity.info, text: "Science UI will update on new data");
}

/// Sends a [ScienceCommand] to fill the pumps
Future<void> fillPumps() async{
isPumping = true;
notifyListeners();
models.messages.sendMessage(ScienceCommand(pumps: PumpState.PUMP_ON));
models.home.setMessage(severity: Severity.info, text: "Science command submitted. Check the video feed to confirm");
await Future<void>.delayed(const Duration(seconds: 3));
isPumping = false;
notifyListeners();
return;
}

/// Calls [addMessage] for each message in the picked file.
Future<void> loadFile() async {
// Pick a file
Expand Down
40 changes: 23 additions & 17 deletions lib/src/pages/science.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import "package:rover_dashboard/widgets.dart";
/// Allows desktop users to scroll with their mouse or other device.
class DesktopScrollBehavior extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
PointerDeviceKind.stylus,
Expand All @@ -30,12 +30,12 @@ class ScrollingRow extends ReusableReactiveWidget<SettingsModel> {

@override
Widget build(BuildContext context, SettingsModel model) => SizedBox(
height: height,
height: height,
child: model.science.scrollableGraphs
? ScrollConfiguration(
behavior: DesktopScrollBehavior(),
child: ListView(
scrollDirection: Axis.horizontal,
scrollDirection: Axis.horizontal,
children: [for (final child in children) SizedBox(width: 400, child: child)],
),
)
Expand All @@ -53,17 +53,17 @@ class ChartsRow extends StatelessWidget {
/// The height of this row.
final double height;

/// The data for these charts.
/// The data for these charts.
final List<ScienceAnalysis> analyses;

/// The chart to show for each piece of data.
final Widget Function(ScienceAnalysis) builder;

/// A const constructor.
const ChartsRow({
required this.title,
required this.analyses,
required this.builder,
required this.title,
required this.analyses,
required this.builder,
this.height = 300,
});

Expand Down Expand Up @@ -95,29 +95,29 @@ class SciencePage extends ReactiveWidget<ScienceModel> {
static final red = HSVColor.fromColor(Colors.red);
/// Purple, used as the color for the last sample.
static final purple = HSVColor.fromColor(Colors.purple);
/// Gets a color between red and purple
/// Gets a color between red and purple
///
/// [value] must be between 0.0 and 1.0.
/// [value] must be between 0.0 and 1.0.
Color getColor(double value) => HSVColor.lerp(red, purple, value)!.toColor();

/// The `package:fl_chart` helper class for the details charts.
LineChartData getDetailsData(ScienceAnalysis analysis, Color color) => LineChartData(
lineBarsData: [
LineChartBarData(
spots: [
for (final reading in analysis.data.readings)
for (final reading in analysis.data.readings)
FlSpot(reading.time, reading.value),
],
],
color: color,
preventCurveOverShooting: true,
isCurved: true,
),
],
],
titlesData: FlTitlesData(
topTitles: const AxisTitles(),
topTitles: const AxisTitles(),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
showTitles: true,
getTitlesWidget: (double value, TitleMeta meta) => SideTitleWidget(
axisSide: AxisSide.bottom,
space: 3,
Expand All @@ -140,10 +140,10 @@ class SciencePage extends ReactiveWidget<ScienceModel> {
BarChartGroupData(x: 2, barRods: [BarChartRodData(color: color, fromY: 0, toY: analysis.data.max ?? 0)]),
],
titlesData: FlTitlesData(
topTitles: const AxisTitles(),
topTitles: const AxisTitles(),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
showTitles: true,
getTitlesWidget: (double value, TitleMeta meta) => SideTitleWidget(
axisSide: AxisSide.bottom,
space: 3,
Expand All @@ -167,10 +167,16 @@ class SciencePage extends ReactiveWidget<ScienceModel> {
Widget build(BuildContext context, ScienceModel model) => Column(children: [
Row(children: [ // The header at the top
const SizedBox(width: 8),
Text("Science Analysis", style: context.textTheme.headlineMedium),
Text("Science Analysis", style: context.textTheme.headlineMedium),
const SizedBox(width: 12),
if (model.isLoading) const SizedBox(height: 20, width: 20, child: CircularProgressIndicator()),
const Spacer(),
ElevatedButton(
onPressed: model.isPumping ? null : model.fillPumps,
style: ElevatedButton.styleFrom(backgroundColor: Colors.green),
child: const Text("Fill Pumps"),
),
const SizedBox(width: 12),
DropdownButton(
value: model.sample,
onChanged: model.updateSample,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/widgets/atomic/science_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class ScienceCommandEditor extends ReactiveWidget<ScienceCommandBuilder> {
name: "State: ",
value: model.state,
onChanged: model.updateState,
items: const [ScienceState.STOP_COLLECTING, ScienceState.COLLECT_DATA],
items: const [ScienceState.STOP_COLLECTING, ScienceState.COLLECT_DATA, ScienceState.STREAM_DATA],
humanName: (state) => state.humanName,
),),
const SizedBox(width: 12),
Expand Down
28 changes: 14 additions & 14 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: HEAD
resolved-ref: ae18e281f3b327a7d3fbfe0e64e6078189f6dddc
ref: scienceStream
resolved-ref: b27c8f9e8269b7e7324bb13dc3c643255f0f2ec9
url: "https://github.com/BinghamtonRover/Networking.git"
source: git
version: "1.1.0"
Expand Down Expand Up @@ -301,18 +301,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev"
source: hosted
version: "10.0.4"
version: "10.0.5"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
version: "3.0.5"
leak_tracker_testing:
dependency: transitive
description:
Expand Down Expand Up @@ -349,18 +349,18 @@ packages:
dependency: transitive
description:
name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.8.0"
version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev"
source: hosted
version: "1.12.0"
version: "1.15.0"
msix:
dependency: "direct dev"
description:
Expand Down Expand Up @@ -554,10 +554,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev"
source: hosted
version: "0.7.0"
version: "0.7.2"
typed_data:
dependency: transitive
description:
Expand Down Expand Up @@ -666,10 +666,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
url: "https://pub.dev"
source: hosted
version: "14.2.1"
version: "14.2.5"
web:
dependency: transitive
description:
Expand Down
Loading