Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Commit 571e209

Browse files
Autonomy and new streams-based networking (#12)
Co-authored-by: Binghamton Rover <[email protected]>
1 parent 5d2717b commit 571e209

22 files changed

+357
-420
lines changed

.github/workflows/analyzer.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ jobs:
1616
# You can specify other versions if desired, see documentation here:
1717
# https://github.com/dart-lang/setup-dart/blob/main/README.md
1818
- uses: dart-lang/setup-dart@v1
19-
with:
20-
sdk: 3.2.2
19+
with:
20+
sdk: 3.5.2
2121

2222
- name: Install dependencies
2323
run: dart pub get
24-
24+
2525
- name: Analyze project source
2626
run: dart analyze --fatal-infos
2727

bin/data.dart

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import "dart:math";
22

33
import "package:burt_network/burt_network.dart";
4-
import "package:subsystems/subsystems.dart";
54

65
class SwingingIterator implements Iterator<double> {
76
final double min;
@@ -26,7 +25,7 @@ class SwingingIterator implements Iterator<double> {
2625
}
2726

2827
Future<void> main() async {
29-
final server = SubsystemsServer(port: 8001);
28+
final server = RoverSocket(port: 8001, device: Device.SUBSYSTEMS);
3029
await server.init();
3130
final throttle = SwingingIterator(0, 1, 0.01);
3231
final voltage = SwingingIterator(24, 30, 0.1);
@@ -36,6 +35,8 @@ Future<void> main() async {
3635
final roll = SwingingIterator(-45, 45, 1);
3736
final pitch = SwingingIterator(-45, 45, 1);
3837
final yaw = SwingingIterator(-45, 45, 1);
38+
final color = SwingingIterator(0, 1, 0.01);
39+
final gps = SwingingIterator(-1, 1, 0.01);
3940
while (true) {
4041
throttle.moveNext();
4142
voltage.moveNext();
@@ -45,33 +46,43 @@ Future<void> main() async {
4546
roll.moveNext();
4647
pitch.moveNext();
4748
yaw.moveNext();
49+
color.moveNext();
50+
gps.moveNext();
4851
final data = DriveData(
49-
left: 1,
50-
setLeft: true,
51-
right: -1,
52-
setRight: true,
53-
throttle: throttle.current,
54-
setThrottle: true,
55-
batteryVoltage: voltage.current,
52+
left: 1,
53+
setLeft: true,
54+
right: -1,
55+
setRight: true,
56+
throttle: throttle.current,
57+
setThrottle: true,
58+
batteryVoltage: voltage.current,
5659
batteryCurrent: current.current,
5760
version: Version(major: 1),
58-
);
61+
color: color.current < 0.25 ? ProtoColor.UNLIT
62+
: color.current < 0.5 ? ProtoColor.BLUE
63+
: color.current < 0.75 ? ProtoColor.RED
64+
: ProtoColor.GREEN,
65+
);
5966
server.sendMessage(data);
6067
final data2 = ArmData(
61-
base: MotorData(angle: motor2.current),
62-
shoulder: MotorData(angle: motor.current),
68+
base: MotorData(angle: motor2.current),
69+
shoulder: MotorData(angle: motor.current),
6370
elbow: MotorData(angle: motor.current),
6471
version: Version(major: 1),
6572
);
6673
server.sendMessage(data2);
67-
final data3 = GripperData(lift: MotorData(angle: motor.current), version: Version(major: 1));
74+
final data3 = GripperData(lift: MotorData(angle: pi + -1 * 2 * motor.current), version: Version(major: 1));
6875
server.sendMessage(data3);
6976
final data4 = RoverPosition(
7077
orientation: Orientation(
7178
x: roll.current,
72-
y: pitch.current,
79+
y: pitch.current,
7380
z: yaw.current,
7481
),
82+
gps: GpsCoordinates(
83+
latitude: gps.current,
84+
longitude: gps.current,
85+
),
7586
version: Version(major: 1),
7687
);
7788
server.sendMessage(data4);

bin/imu.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import "package:subsystems/subsystems.dart";
2+
3+
void main() async {
4+
final reader = ImuReader();
5+
await reader.init();
6+
}

bin/motor.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import "package:burt_network/logging.dart";
44
const speed = [0, 0, 0x9, 0xc4];
55

66
void main() async {
7+
final can = CanSocket.forPlatform();
78
Logger.level = LogLevel.info;
8-
await collection.init();
9+
if (!await can.init()) logger.critical("Could not initialize CAN");
910
while (true) {
10-
collection.can.can.sendMessage(id: 0x304, data: speed);
11+
can.sendMessage(id: 0x304, data: speed);
1112
await Future<void>.delayed(const Duration(milliseconds: 500));
1213
}
1314
}

bin/serial.dart

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import "dart:io";
22
import "dart:typed_data";
33
import "package:burt_network/burt_network.dart";
4-
import "package:collection/collection.dart";
54
import "package:libserialport/libserialport.dart";
65

76
final logger = BurtLogger();
@@ -11,7 +10,7 @@ bool ascii = false;
1110
Future<void> listenToDevice(String port) async {
1211
logger.info("Connecting to $port...");
1312
final device = SerialDevice(
14-
portName: port,
13+
portName: port,
1514
readInterval: const Duration(milliseconds: 100),
1615
logger: logger,
1716
);
@@ -20,22 +19,29 @@ Future<void> listenToDevice(String port) async {
2019
return;
2120
}
2221
logger.info("Connected. Listening...");
23-
device.stream.listen(process);
22+
device.stream.listen(processAscii);
2423
device.startListening();
2524
}
2625

2726
Future<void> listenToFirmware(String port) async {
2827
logger.info("Connecting to $port...");
2928
final device = BurtFirmwareSerial(
30-
port: port,
29+
port: port,
3130
logger: logger,
3231
);
3332
if (!await device.init()) {
3433
logger.critical("Could not connect to $port");
34+
await device.dispose();
3535
return;
3636
}
3737
logger.info("Connected? ${device.isReady}. Listening...");
38-
device.stream?.listen(process);
38+
constructor = getDataConstructor(device.device);
39+
if (constructor == null) {
40+
logger.error("Unsupported serial device: ${device.device.name}");
41+
await device.dispose();
42+
return;
43+
}
44+
device.rawStream.listen(processFirmware);
3945
}
4046

4147
typedef ProtoConstructor = Message Function(List<int> data);
@@ -55,18 +61,7 @@ void main(List<String> args) async {
5561
logger.info("Ports: ${SerialPort.availablePorts}");
5662
return;
5763
} else if (args.contains("-h") || args.contains("--help")) {
58-
logger.info("Usage: dart run -r :serial [-a | --ascii] [port device]");
59-
return;
60-
}
61-
final deviceName = args.last;
62-
final device = Device.values.firstWhereOrNull((d) => d.name.toLowerCase() == deviceName.toLowerCase());
63-
if (device == null) {
64-
logger.error("Enter a device name as the last argument. Unrecognized device: $deviceName");
65-
return;
66-
}
67-
constructor = getDataConstructor(device);
68-
if (constructor == null) {
69-
logger.error("Unsupported serial device: $deviceName");
64+
logger.info("Usage: dart run -r :serial [-a | --ascii] [port]");
7065
return;
7166
}
7267
var port = args.first;
@@ -82,16 +77,16 @@ void main(List<String> args) async {
8277
}
8378
}
8479

85-
void process(Uint8List buffer) {
86-
if (ascii) {
87-
final s = String.fromCharCodes(buffer).trim();
88-
logger.debug("Got string: $s");
89-
} else {
90-
try {
91-
final data = constructor!(buffer);
92-
logger.debug("Got data: ${data.toProto3Json()}");
93-
} catch (error) {
94-
logger.error("Could not decode DriveData: $error\n Buffer: $buffer");
95-
}
80+
void processFirmware(Uint8List buffer) {
81+
try {
82+
final data = constructor!(buffer);
83+
logger.debug("Got data: ${data.toProto3Json()}");
84+
} catch (error) {
85+
logger.error("Could not decode DriveData: $error\n Buffer: $buffer");
9686
}
9787
}
88+
89+
void processAscii(Uint8List buffer) {
90+
final s = String.fromCharCodes(buffer).trim();
91+
logger.debug("Got string: $s");
92+
}

ffigen-can.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# Run with `dart run ffigen --config can-ffigen.yaml -v severe`.
22
name: CanBindings
3-
description: |
3+
description: |-
44
Bindings for `src/burt_can`.
55
66
Regenerate bindings with `dart run ffigen --config ffigen-can.yaml -v severe`.
7-
output: "./lib/src/generated/can_ffi_bindings.dart"
7+
output: lib/src/generated/can_ffi_bindings.dart
88
headers:
99
entry-points:
1010
- 'src/burt_can/burt_can.h'
1111
include-directives:
12-
- 'src/burt_can/burt_can.h'
12+
- '**/src/burt_can/burt_can.h'
1313
comments:
1414
style: any
1515
length: full
@@ -22,6 +22,6 @@ type-map:
2222
'dart-type': 'Utf8'
2323

2424
functions:
25-
symbol-address:
26-
include:
25+
symbol-address:
26+
include:
2727
- ".+_free"

lib/src/can/ffi.dart

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,24 @@ export "package:ffi/ffi.dart";
66
export "package:subsystems/src/generated/can_ffi_bindings.dart";
77

88
/// The native SocketCAN-based library.
9-
///
9+
///
1010
/// See `src/can.h` in this repository. Only supported on Linux.
1111
final nativeLib = CanBindings(DynamicLibrary.open("burt_can.so"));
1212

13-
/// These values come from the [BurtCanStatus] enum.
14-
String? getCanError(int value) => switch (value) {
15-
1 => null,
16-
2 => "Could not create socket",
17-
3 => "Could not parse interface",
18-
4 => "Could not bind to socket",
19-
5 => "Could not close socket",
20-
6 => "Invalid MTU",
21-
7 => "CAN FD is not supported",
22-
8 => "Could not switch to CAN FD",
23-
9 => "Could not write data",
24-
10 => "Could not read data",
25-
11 => "Frame was not fully read",
26-
_ => throw ArgumentError.value(value, "CanStatus", "Unknown CAN status"),
27-
};
13+
/// Helpful methods on [BurtCanStatus].
14+
extension BurtCanStatusUtils on BurtCanStatus {
15+
/// A human-readable string representing this error, if any.
16+
String? get stringError => switch (this) {
17+
BurtCanStatus.OK => null,
18+
BurtCanStatus.SOCKET_CREATE_ERROR => "Could not create socket",
19+
BurtCanStatus.INTERFACE_PARSE_ERROR => "Could not parse interface",
20+
BurtCanStatus.BIND_ERROR => "Could not bind to socket",
21+
BurtCanStatus.CLOSE_ERROR => "Could not close socket",
22+
BurtCanStatus.MTU_ERROR => "Invalid MTU",
23+
BurtCanStatus.CANFD_NOT_SUPPORTED => "CAN FD is not supported",
24+
BurtCanStatus.FD_MISC_ERROR => "Could not switch to CAN FD",
25+
BurtCanStatus.WRITE_ERROR => "Could not write data",
26+
BurtCanStatus.READ_ERROR => "Could not read data",
27+
BurtCanStatus.FRAME_NOT_FULLY_READ => "Frame was not fully read",
28+
};
29+
}

lib/src/can/socket_ffi.dart

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ const canType = BurtCanType.CAN;
1414
const canTimeout = 1;
1515

1616
/// The CAN interface, backed by the native SocketCAN library on Linux.
17-
///
17+
///
1818
/// - Access [incomingMessages] to handle messages as they are received
1919
/// - Call [sendMessage] to send a new [CanMessage]
2020
/// - Be sure to call [dispose] when you're done to avoid memory leaks
21-
///
21+
///
2222
/// Note that [CanMessage]s are natively allocated and need to be manually disposed of. Since this
2323
/// class sends them through the [incomingMessages] stream, you are responsible for disposing them
2424
/// if you listen to it. The stream gives you pointers so you can call [CanMessage.dispose].
25-
class CanFFI implements CanSocket {
25+
class CanFFI extends CanSocket {
2626
/// How often to poll CAN messages.
27-
///
27+
///
2828
/// This should be small enough to catch incoming messages but large enough to
2929
/// not block other code from running.
3030
static const readInterval = Duration(milliseconds: 100);
@@ -51,7 +51,7 @@ class CanFFI implements CanSocket {
5151
Timer? _timer;
5252

5353
@override
54-
Future<bool> init() async {
54+
Future<bool> init() async {
5555
_can = nativeLib.BurtCan_create(canInterface.toNativeUtf8(), canTimeout, canType);
5656
await Process.run("sudo", ["ip", "link", "set", "can0", "down"]);
5757
final result = await Process.run("sudo", ["ip", "link", "set", "can0", "up", "type", "can", "bitrate", "500000"]);
@@ -60,13 +60,13 @@ class CanFFI implements CanSocket {
6060
hasError = true;
6161
return false;
6262
}
63-
final error = getCanError(nativeLib.BurtCan_open(_can!));
63+
final error = nativeLib.BurtCan_open(_can!).stringError;
6464
if (error != null) {
6565
hasError = true;
6666
logger.critical("Could not start the CAN bus", body: error);
6767
return false;
6868
}
69-
_startListening();
69+
_startListening();
7070
logger.info("Listening on CAN interface $canInterface");
7171
return true;
7272
}
@@ -86,7 +86,7 @@ class CanFFI implements CanSocket {
8686
void sendMessage({required int id, required List<int> data}) {
8787
if (hasError || _can == null) return;
8888
final message = CanMessage(id: id, data: data);
89-
final error = getCanError(nativeLib.BurtCan_send(_can!, message.pointer));
89+
final error = nativeLib.BurtCan_send(_can!, message.pointer).stringError;
9090
if (error != null) logger.warning("Could not send CAN message", body: "ID=$id, Data=$data, Error: $error");
9191
message.dispose();
9292
}
@@ -97,7 +97,7 @@ class CanFFI implements CanSocket {
9797
int count = 0;
9898
while (true) {
9999
final pointer = nativeLib.NativeCanMessage_create();
100-
final error = getCanError(nativeLib.BurtCan_receive(_can!, pointer));
100+
final error = nativeLib.BurtCan_receive(_can!, pointer).stringError;
101101
if (error != null) logger.warning("Could not read the CAN bus", body: error);
102102
if (pointer.ref.length == 0) break;
103103
count++;

0 commit comments

Comments
 (0)