Skip to content
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
7 changes: 7 additions & 0 deletions autonomy/.github/pubspec_overrides.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
resolution:

dependency_overrides:
burt_network:
git:
url: https://github.com/BinghamtonRover/Networking
ref: 2.3.1
41 changes: 41 additions & 0 deletions autonomy/.github/workflows/analyze.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Dart Analyzer

on:
push:
branches: [ "main" ]
pull_request:

jobs:
analyze:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

# Note: This workflow uses the latest stable version of the Dart SDK.
# You can specify other versions if desired, see documentation here:
# https://github.com/dart-lang/setup-dart/blob/main/README.md
- uses: dart-lang/setup-dart@v1
with:
sdk: 3.6.0

# This package is part of a Pub Workspace. However, CI still needs to
# run on this repo by itself, so we want to override burt_network to use
# a Git dependency ONLY on GitHub Actions.
#
# To get around this, we commit the overrides to the .github folder where
# Dart can't find them, then copy them as part of the CI workflow.
- name: Install dependencies
run: |
mv .github/pubspec_overrides.yaml .
dart pub get

- name: Analyze project source
run: dart analyze --fatal-infos

# Your project will need to have tests in test/ and a dependency on
# package:test for this step to succeed. Note that Flutter projects will
# want to change this to 'flutter test'.
# FIXME: Disabling tests for now
# - name: Run tests
# run: dart test
55 changes: 55 additions & 0 deletions autonomy/.github/workflows/documentation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Generate Dart Documentation

on:
push:
branches: [ "main" ]

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Git Setup
run: |
git config user.name "GitHub Actions Bot"
git config user.email "<>"
git branch --all
git switch --track origin/documentation
git reset --hard origin/main

- name: Install Dart
uses: dart-lang/setup-dart@v1
with:
sdk: 3.5.2

- name: Install dependencies
run: dart pub get

- name: Analyze Dart code
run: dart analyze --fatal-infos

- name: Output error
if: failure()
run: echo "::error The code or is missing documentation. Run flutter analyze --dartdocs"

- name: Generate documentation
run: dart doc --output=docs

# Your project will need to have tests in test/ and a dependency on
# package:test for this step to succeed. Note that Flutter projects will
# want to change this to 'flutter test'.
- name: Run tests
run: dart test

- name: Commit and push files
run: |
cd docs
cd ..
git status
git stage --force docs
git commit -a -m "Generated documentation"
git push --force
16 changes: 16 additions & 0 deletions autonomy/bin/arcuo.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import "package:autonomy/autonomy.dart";

void main() async {
final rover = RoverAutonomy();
rover.drive = RoverDrive(collection: rover, useImu: false, useGps: false);
await rover.init();
//await rover.waitForValue();
final didSeeAruco = await rover.drive.spinForAruco();
if (didSeeAruco) {
rover.logger.info("Found aruco");
await rover.drive.approachAruco();
} else {
rover.logger.warning("COuld not find aruco");
}
rover.logger.info("Done");
}
63 changes: 63 additions & 0 deletions autonomy/bin/sensorless.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import "package:burt_network/logging.dart";
import "package:burt_network/protobuf.dart";

import "package:autonomy/simulator.dart";
import "package:autonomy/rover.dart";

void main() async {
Logger.level = LogLevel.debug;
final simulator = AutonomySimulator();
simulator.drive = SensorlessDrive(collection: simulator, useGps: false, useImu: false);
await simulator.init();
await simulator.server.waitForConnection();

final message = AutonomyData(
destination: GpsCoordinates(latitude: 0, longitude: 0),
state: AutonomyState.DRIVING,
task: AutonomyTask.GPS_ONLY,
obstacles: [],
path: [
for (double x = 0; x < 3; x++)
for (double y = 0; y < 3; y++)
GpsCoordinates(latitude: y, longitude: x),
],
);
simulator.server.sendMessage(message);

// "Snakes" around a 3x3 meter box. (0, 0), North
await simulator.drive.goForward(); // (1, 0), North
await simulator.drive.goForward(); // (2, 0), North
await simulator.drive.turnRight(); // (2, 0), East
await simulator.drive.goForward(); // (2, 1), East
await simulator.drive.turnRight(); // (2, 1), South
await simulator.drive.goForward(); // (1, 1), South
await simulator.drive.goForward(); // (0, 1), South
await simulator.drive.turnLeft(); // (0, 1), East
await simulator.drive.goForward(); // (0, 2), East
await simulator.drive.turnLeft(); // (0, 2), North
await simulator.drive.goForward(); // (1, 2), North
await simulator.drive.goForward(); // (2, 2), North
await simulator.drive.turnLeft(); // (2, 2), West
await simulator.drive.goForward(); // (2, 1), West
await simulator.drive.goForward(); // (2, 0), West
await simulator.drive.turnLeft(); // (2, 0), South
await simulator.drive.goForward(); // (1, 0), South
await simulator.drive.goForward(); // (0, 0), South
await simulator.drive.turnLeft(); // (0, 0), East
await simulator.drive.turnLeft(); // (0, 0), North

final message2 = AutonomyData(
state: AutonomyState.AT_DESTINATION,
task: AutonomyTask.AUTONOMY_TASK_UNDEFINED,
obstacles: [],
path: [
for (double x = 0; x < 3; x++)
for (double y = 0; y < 3; y++)
GpsCoordinates(latitude: y, longitude: x),
],
);
simulator.server.sendMessage(message2);
simulator.server.sendMessage(message2);

await simulator.dispose();
}
23 changes: 23 additions & 0 deletions autonomy/bin/test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import "package:autonomy/autonomy.dart";
import "package:burt_network/logging.dart";
import "package:autonomy/src/rover/gps.dart";
import "package:autonomy/src/rover/imu.dart";

void main() async {
Logger.level = LogLevel.all;
final rover = RoverAutonomy();
rover.gps = RoverGps(collection: rover);
rover.imu = RoverImu(collection: rover);
rover.drive = RoverDrive(collection: rover, useGps: false);

await rover.init();
// await rover.waitForReadings();
// await rover.waitForConnection();

rover.logger.info("Starting");
await rover.drive.turnLeft();
await rover.drive.turnRight();

rover.logger.info("Done");
await rover.dispose();
}
66 changes: 66 additions & 0 deletions autonomy/lib/src/interfaces/a_star.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import "package:a_star/a_star.dart";

import "package:burt_network/protobuf.dart";
import "package:autonomy/interfaces.dart";

class AutonomyAStarState extends AStarState<AutonomyAStarState> {
final DriveDirection direction;
final DriveOrientation orientation;
final GpsCoordinates position;
final GpsCoordinates goal;
final AutonomyInterface collection;

AutonomyAStarState({
required this.position,
required this.goal,
required this.collection,
required this.direction,
required this.orientation,
required super.depth,
});

factory AutonomyAStarState.start({
required AutonomyInterface collection,
required GpsCoordinates goal,
}) => AutonomyAStarState(
position: collection.gps.coordinates,
goal: goal,
collection: collection,
direction: DriveDirection.stop,
orientation: collection.imu.orientation!,
depth: 0,
);

@override
String toString() => switch(direction) {
DriveDirection.forward => "Go forward to ${position.prettyPrint()}",
DriveDirection.left => "Turn left to face $direction",
DriveDirection.right => "Turn right to face $direction",
DriveDirection.stop => "Start/Stop at ${position.prettyPrint()}",
};

@override
double heuristic() => position.manhattanDistance(goal);

@override
String hash() => "${position.prettyPrint()} ($orientation)";

@override
bool isGoal() => position.isNear(goal);

AutonomyAStarState copyWith({required DriveDirection direction, required DriveOrientation orientation, required GpsCoordinates position}) => AutonomyAStarState(
collection: collection,
position: position,
orientation: orientation,
direction: direction,
goal: goal,
depth: direction == DriveDirection.forward ? depth + 1 : depth + 2,
);

@override
Iterable<AutonomyAStarState> expand() => [
copyWith(direction: DriveDirection.forward, orientation: orientation, position: position.goForward(orientation)),
copyWith(direction: DriveDirection.left, orientation: orientation.turnLeft(), position: position),
copyWith(direction: DriveDirection.right, orientation: orientation.turnRight(), position: position),
].where((state) => !collection.pathfinder.isObstacle(state.position));
}
66 changes: 66 additions & 0 deletions autonomy/lib/src/interfaces/autonomy.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import "package:burt_network/burt_network.dart";

import "package:autonomy/interfaces.dart";

abstract class AutonomyInterface extends Service with Receiver {
BurtLogger get logger;
GpsInterface get gps;
ImuInterface get imu;
DriveInterface get drive;
RoverSocket get server;
PathfindingInterface get pathfinder;
DetectorInterface get detector;
VideoInterface get video;
OrchestratorInterface get orchestrator;

@override
Future<bool> init() async {
var result = true;
result &= await gps.init();
result &= await imu.init();
result &= await drive.init();
result &= await server.init();
result &= await pathfinder.init();
result &= await detector.init();
result &= await video.init();
logger.info("Init orchestrator");
await orchestrator.init();
logger.info("Init orchestrator done");
if (result) {
logger.info("Autonomy initialized");
} else {
logger.warning("Autonomy could not initialize");
}
return result;
}

@override
Future<void> dispose() async {
await gps.dispose();
await imu.dispose();
await drive.dispose();
await pathfinder.dispose();
await detector.dispose();
await video.dispose();
await orchestrator.dispose();
logger.info("Autonomy disposed");
await server.dispose();
}

Future<void> restart() async {
await dispose();
await init();
}

@override
Future<void> waitForValue() async {
logger.info("Waiting for readings...");
await gps.waitForValue();
await imu.waitForValue();
await video.waitForValue();
logger.info("Received GPS and IMU values");
}

@override
bool get hasValue => gps.hasValue && imu.hasValue && video.hasValue;
}
10 changes: 10 additions & 0 deletions autonomy/lib/src/interfaces/detector.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import "package:autonomy/interfaces.dart";

abstract class DetectorInterface extends Service {
AutonomyInterface collection;
DetectorInterface({required this.collection});

bool findObstacles();
bool canSeeAruco();
bool isOnSlope();
}
Loading
Loading