Skip to content

Commit 51ff162

Browse files
authored
Merge pull request #8 from VU-ASE/chore/verify-service
add docs folder
2 parents 5542619 + df6dc71 commit 51ff162

2 files changed

Lines changed: 104 additions & 0 deletions

File tree

docs/01-overview.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Overview
2+
The `controller` service takes pre-processed track edge data and transforms it into actuator decision commands based on a simple PID controller.
3+
4+
### A PID controller?
5+
6+
PID stands for Proportional Integral Derivative, and in context of this application, it aims to remain as close as possible to the calculated center of the track. Before making the decision which way to turn, the controller takes into consideration all 3 terms with equal weight and acts based on the result. Below is a short description of each of the terms:
7+
8+
**Proportional** - considers the current error, i.e. the distance between the observed center of the track and where the car currently is.
9+
10+
**Integral** - takes the cummulative error over time, not just the current one like the **Proportional** term. It would try to steer the car towards the center also if it observes a small error present over a longer period of time, whereas **Proportional** would not make a significant enough adjustment.
11+
12+
**Derivative** - works by taking the difference between the measured errors and divides it by the change in time. This allows it to see how fast the error is changing. While **Proportional** term takes into account the current value, **Integral** - past, **Derivative** tries to predict the future errors.
13+
14+
Each of the terms can, of course, be used as a standalone controller by itself, but it is unlikely to yield a better result. You can find a more detailed description of the mechanism [here](https://www.integrasources.com/blog/basics-of-pid-controllers-design-applications/#:~:text=A%20PID%20controller%20calculates%20the,the%20whole%20term%20becomes%20zero.), or a very detailed description [here](https://en.wikipedia.org/wiki/Proportional–integral–derivative_controller).

docs/02-usage.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Usage
2+
3+
`controller` takes `path` stream from `imaging` service as input and produces a `decision` output stream.
4+
5+
## Input
6+
7+
`path` stream has the following format:
8+
```
9+
pb_output.SensorOutput{
10+
SensorId: 25,
11+
Timestamp: uint64(time.Now().UnixMilli()),
12+
SensorOutput: &pb_output.SensorOutput_CameraOutput{
13+
CameraOutput: &pb_output.CameraSensorOutput{
14+
DebugFrame: &pb_output.CameraSensorOutput_DebugFrame{
15+
Jpeg: imgBytes.GetBytes(),
16+
Canvas: &canvas,
17+
},
18+
Trajectory: &pb_output.CameraSensorOutput_Trajectory{
19+
Points: trajectory_points,
20+
Width: uint32(imgWidth),
21+
Height: uint32(imgHeight),
22+
},
23+
},
24+
},
25+
}
26+
```
27+
28+
`SensorOutput_CameraOutput` object contains a `CameraSensorOutput` object with 2 main fields:
29+
1. `CameraSensorOutput_DebugFrame` containing:
30+
- `Jpeg`, a (prerpocessed) acquired frame transmitted as a raw byte array of a JPEG image and the
31+
- `canvas`, contains a `width` and `height` fields, as well as an array of `CanvasObject`s, which are either a `Line`, `Rectangle` or `Circle`. It can be used for example to overlay these shapes on top of the JPEG image.
32+
33+
2. `CameraSensorOutput_Trajecotry` is composed of:
34+
- `trajectory_points` array of points supplied by the imaging (default implementation only passes 1 point to the array).
35+
- `Width` of the acquired image.
36+
- `Height` of the acquired image
37+
38+
### Processing input
39+
40+
Taken from `src/main.go`:
41+
```
42+
imagingData := data.GetCameraOutput()
43+
```
44+
This unmarshals the `SensorOutput` object and returns a `CameraSensorOutput` object
45+
46+
47+
```
48+
trajectory := imagingData.GetTrajectory()
49+
```
50+
Next, we further process the input to extract a `CameraSensorOutput_Trajectory` object to further work with.
51+
52+
### how to use first point
53+
54+
The first point in the array of trajectory points is the identified middle of the visible part of the track. (see image below). You can, for example, compare value of its `x` coordinate to the middle of the frame to see if the car is offset towards the left or right side of the track.
55+
56+
![blob_with_line](https://github.com/user-attachments/assets/6422e01d-f1f1-4e45-9493-b642b90b4adc)
57+
58+
## Controller
59+
60+
The default implementation of the `controller` service uses a PID algorithm to make a decision on where to go ([What is a PID controller?](https://en.wikipedia.org/wiki/Proportional–integral–derivative_controller)). It is very much the core of this service and is the primary part you would want to replace, should you decide to implement your own algorithm.
61+
62+
## Output
63+
64+
`controller` outputs the `decision` stream (see example below), which is later read and interpreted by the `actuator`.
65+
66+
```
67+
actuatorOutput.Write(
68+
&pb_outputs.SensorOutput{
69+
SensorId: 2,
70+
Timestamp: uint64(time.Now().UnixMilli()),
71+
SensorOutput: &pb_outputs.SensorOutput_ControllerOutput{
72+
ControllerOutput: &pb_outputs.ControllerOutput{
73+
SteeringAngle: float32(steerValue),
74+
LeftThrottle: float32(speed),
75+
RightThrottle: float32(speed),
76+
FrontLights: false,
77+
},
78+
},
79+
},
80+
)
81+
```
82+
83+
`SensorOutput_ControllerOutput` contains a `ControllerOutput` object, composed of the following fields:
84+
85+
1. `SteeringAngle`, a `float32` value between -1 (left) and 1 (right)
86+
2. `LeftThrottle`, a `float32` value between -1 (full reverse) and 1 (full forward)
87+
3. `RightThrottle`, a `float32` value between -1 (full reverse) and 1 (full forward)
88+
4. `FrontLights`, a `boolean` value previously used to turn on the front lights in the dark, currently not used
89+
90+
For seeing an example of using `decision` stream, please look at `actuator documentation`

0 commit comments

Comments
 (0)