Skip to content

Commit 5568e56

Browse files
UPDATE v1.0.1: Critical MVLib fixes and minor MotionView UI changes
1 parent 37184e9 commit 5568e56

23 files changed

Lines changed: 500 additions & 143 deletions

‎.github/workflows/build-tauri-artifacts.yaml‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,9 @@ jobs:
8181
RAW_VERSION="${GITHUB_REF#refs/tags/}"
8282
fi
8383
84-
# 2. STRICT REGEX CHECK: Must be exactly vX.Y.Z
84+
# 2. Should be exactly vX.Y.Z, but allow for something like v.X.Y.Z-alpha
8585
if [[ ! "$RAW_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
86-
echo "::error::Invalid version format: $RAW_VERSION. Must be a 3-point version like v0.9.1"
87-
exit 1
86+
echo "::warning::Invalid version format: $RAW_VERSION. Must be a 3-point version like v0.9.1"
8887
fi
8988
9089
# 3. Strip the 'v' to inject into Tauri (e.g., 0.9.1)

‎Docs/MotionView/HowToLog.md‎

Whitespace-only changes.

‎Docs/MotionView/MotionViewAPI.md‎

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
# MotionView API
2+
This doc covers what types of data MotionView can consume, what behavior that will lead to, and examples. See also [MVLib](../Guides/MVLib/README.md) for a working implementation example.
3+
4+
### Notes for this doc
5+
- Anything before the type tag is parsed and removed by MotionView.
6+
- The type is decided by the first occurrence of a tag in a log. As of MotionView v1.0.0, the following tags are supported:
7+
```json
8+
[POSE] # This data is interpreted by MotionView as the current location of the robot.
9+
[WATCH] # This data is interpreted by MotionView as watch log.
10+
[LOG] # This data is interpreted by MotionView as a log message
11+
[WPOINT] # This data is interpreted by MotionView as a waypoint.
12+
```
13+
14+
15+
### [POSE] Data
16+
Expected format:
17+
18+
```log
19+
[POSE],uptime,x,y,theta,l_vel,r_vel
20+
```
21+
22+
- `uptime`: The time since the robot booted in milliseconds
23+
- `x`: The x position of the robot in any supported unit
24+
- `y`: The y position of the robot in any supported unit
25+
- `theta`: The angle of the robot in degrees
26+
- `l_vel`: The velocity of the left drivetrain. Expected to be (±127), however the user can manually set the speed normalization range
27+
- `r_vel`: Same as `l_vel`, but for the right drivetrain
28+
29+
Example:
30+
31+
```log
32+
[12.43] [INFO]: [POSE],12342,0,0,90,10,-10
33+
```
34+
35+
Parsed as:
36+
```json
37+
{
38+
"t": 12432,
39+
"x": 0,
40+
"y": 0,
41+
"theta": 90,
42+
"l_vel": 10,
43+
"r_vel": -10
44+
}
45+
```
46+
47+
This type of data is used by MotionView to draw the robot.
48+
49+
### [WATCH] Data
50+
Expected format:
51+
52+
```log
53+
[WATCH],uptime,level,label,value
54+
```
55+
56+
- `uptime`: The time since the robot booted in milliseconds
57+
- `level`: The log level of the watch (DEBUG, INFO, WARN, ERROR, FATAL)
58+
- `label`: The label/name of the watch
59+
- `value`: The value of the watch
60+
61+
Example:
62+
63+
```log
64+
[12.43] [INFO]: [WATCH],12342,INFO,"Tongue mech state",true
65+
```
66+
67+
Parsed as:
68+
```json
69+
{
70+
"t": 12432,
71+
"level": "INFO",
72+
"label": "Tongue mech state",
73+
"value": "true"
74+
}
75+
```
76+
77+
MotionView will format the data, and then add the watch to the Watches list of the Viewing mode sidebar.
78+
79+
### [LOG] Data
80+
Expected format:
81+
82+
```log
83+
[LOG],uptime,level,message
84+
```
85+
86+
- `uptime`: The time since the robot booted in milliseconds
87+
- `level`: The log level of the log (DEBUG, INFO, WARN, ERROR, FATAL)
88+
- `message`: The message of the log
89+
90+
The message of the log can contain commas, as anything after the 3rd comma is considered part of the message and parsed as so.
91+
92+
Example:
93+
94+
```log
95+
[12.43] [INFO]: [LOG],12342,INFO,This is a log message
96+
```
97+
98+
Parsed as:
99+
```json
100+
{
101+
"t": 12432,
102+
"level": "INFO",
103+
"message": "This is a log message"
104+
}
105+
```
106+
107+
MotionView will format the data, and then add the log to the Logs list of the Viewing mode sidebar.
108+
109+
### [WPOINT] Data
110+
Waypoints are stateful. Unlike `[POSE]`, `[WATCH]`, or `[LOG]`, MotionView does not treat each waypoint line as an isolated record. Instead, all `[WPOINT]` lines with the same `id` are grouped into one waypoint object, and MotionView keeps track of that waypoint's current state, event history, field marker, and click-to-jump behavior.
111+
112+
Expected format:
113+
114+
```log
115+
[WPOINT],uptime,eventType,id,wpointName,params...
116+
```
117+
118+
- `uptime`: The time since the robot booted in milliseconds
119+
- `eventType`: One of `CREATED`, `OFFSET`, `REACHED`, or `TIMEDOUT`
120+
- `id`: The integer waypoint ID
121+
- `wpointName`: The human-readable waypoint name. This must not contain commas.
122+
- `params...`: Event-specific parameters described below
123+
124+
If the line does not contain the required comma structure, MotionView treats it as malformed, ignores it for parsing, and leaves it in the live console with the red error prefix.
125+
126+
#### `CREATED`
127+
128+
Expected format:
129+
130+
```log
131+
[WPOINT],uptime,CREATED,id,wpointName,targetX,targetY,targetT|NA,timeoutMs|NA,linearTolerance,thetaTolerance|NA,retriggerable
132+
```
133+
134+
- `targetX`: Target x position
135+
- `targetY`: Target y position
136+
- `targetT`: Target heading in degrees, or `NA`
137+
- `timeoutMs`: Timeout in milliseconds, or `NA`
138+
- `linearTolerance`: Linear tolerance
139+
- `thetaTolerance`: Angular tolerance in degrees, or `NA`
140+
- `retriggerable`: `0` or `1`
141+
142+
Example:
143+
144+
```log
145+
[12.32] [INFO]: [WPOINT],12342,CREATED,4,Park Zone,60,0,180,NA,2,5,1
146+
```
147+
148+
Parsed as:
149+
150+
```json
151+
{
152+
"t": 12342,
153+
"type": "CREATED",
154+
"id": 4,
155+
"name": "Park Zone",
156+
"params": {
157+
"tarX": 60,
158+
"tarY": 0,
159+
"tarT": 180,
160+
"timeoutMs": null,
161+
"linearTol": 2,
162+
"thetaTol": 5,
163+
"retriggerable": true
164+
}
165+
}
166+
```
167+
168+
MotionView uses `CREATED` to create or replace the waypoint with that `id`. The waypoint is placed on the field immediately at its target location and remains there until cleared. If the same `id` appears later with a new `CREATED` event, MotionView treats that as a new session for that waypoint and drops the old waypoint state and history.
169+
170+
#### `OFFSET`
171+
172+
Expected format:
173+
174+
```log
175+
[WPOINT],uptime,OFFSET,id,wpointName,offsetX,offsetY,offsetT|NA,remainingTime|NA
176+
```
177+
178+
- `offsetX`: Current x error from the waypoint target
179+
- `offsetY`: Current y error from the waypoint target
180+
- `offsetT`: Current angular error, or `NA`
181+
- `remainingTime`: Remaining timeout in milliseconds, or `NA`
182+
183+
Example:
184+
185+
```log
186+
[15.80] [INFO]: [WPOINT],15800,OFFSET,4,Park Zone,1.25,-0.50,3.0,420
187+
```
188+
189+
MotionView stores the event in the waypoint's event history and shows it in the sidebar. It does not move the field marker, because field markers always stay at the original target location from `CREATED`.
190+
191+
#### `REACHED`
192+
193+
Expected format:
194+
195+
```log
196+
[WPOINT],uptime,REACHED,id,wpointName,offsetX,offsetY,offsetT|NA,remainingTime|NA
197+
```
198+
199+
Example:
200+
201+
```log
202+
[16.59] [INFO]: [WPOINT],16585,REACHED,4,Park Zone,0.10,0.00,1.0,150
203+
```
204+
205+
MotionView stores the event and marks the waypoint as reached. For normal waypoints, `REACHED` is terminal and deactivates the waypoint. For retriggerable waypoints (`retriggerable = 1`), `REACHED` does not deactivate the waypoint, so it can continue receiving future `OFFSET` or `REACHED` events.
206+
207+
#### `TIMEDOUT`
208+
209+
Expected format:
210+
211+
```log
212+
[WPOINT],uptime,TIMEDOUT,id,wpointName,offsetX,offsetY,offsetT|NA,remainingTime|NA
213+
```
214+
215+
Example:
216+
217+
```log
218+
[19.25] [INFO]: [WPOINT],19250,TIMEDOUT,4,Park Zone,4.40,1.20,NA,0
219+
```
220+
221+
MotionView stores the event and always treats `TIMEDOUT` as terminal. This deactivates the waypoint even if it was retriggerable.
222+
223+
#### How MotionView handles waypoint state
224+
225+
- All events are grouped by `id`
226+
- The field marker is drawn at the target position from the `CREATED` event
227+
- Active waypoints are shown with the active state pill and active field marker styling
228+
- Inactive waypoints stay visible on the field, but are greyed out
229+
- Retriggerable waypoints use the `RETRIGGERABLE` state pill instead of `ACTIVE` or `INACTIVE`
230+
- If a retriggerable waypoint times out, the `RETRIGGERABLE` state pill uses a dark grey background to reflect that terminal state
231+
- The sidebar shows all waypoint events in chronological order with `CREATED` at the top
232+
- The filter menu supports `All`, `Active`, and individual waypoint names
233+
- Selecting `Active` filters both the sidebar list and field markers to only active waypoints
234+
235+
#### Clicking and jumping behavior
236+
237+
- Clicking a waypoint in the sidebar or on the field selects and highlights that waypoint
238+
- MotionView jumps to the closest logged pose that occurred while the waypoint was active
239+
- The active interval is `CREATED.time <= pose.time <= terminalEvent.time`
240+
- For retriggerable waypoints that have not timed out, the active interval continues indefinitely
241+
- If there are no poses during the active interval, MotionView highlights the waypoint but does not move the robot
242+
243+
#### Notes
244+
245+
- `NA` values are accepted where shown above and are stored as unset values
246+
- Fields with unset values are omitted from MotionView's formatted waypoint details
247+
- Unknown waypoint IDs on non-`CREATED` events are ignored
248+
- Waypoint names must not contain commas

‎Docs/MotionView/SetupLivestreaming.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@ The **PROS-CLI Path** is the path to your `pros` executable file. It's what allo
4141
PROS is needed because of the terminal interface. Because `pros terminal`, run anywhere, always does the same action, it is very easy to get consistent connections and behavior using it. While it may be possible to use VEXCode (or any non-PROS platform), piping the terminal into MotionView is not easily done.
4242

4343
## Live Streaming
44-
Once you have a connection between MotionView and your computer, the easiest way to bridge your robot and MotionView is to use [MVLib](../../MVLib/README.md). Using MVLib ensures full functionality and accurate logging. If you don't want to use MVLib, you may need help setting up a bridge. A guide for making your own Robot -> MotionView bridge is in the works.
44+
Once you have a connection between MotionView and your computer, the easiest way to bridge your robot and MotionView is to use [MVLib](../../MVLib/README.md). Using MVLib ensures full functionality and accurate logging. If you don't want to use MVLib, you may need help setting up a bridge. If you want to make your own logger, see [here](./MotionViewAPI.md).md.

‎MVLib/Makefile‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ IS_LIBRARY:=1
2929
# Be sure that your header files are in the include directory inside of a folder with the
3030
# same name as what you set LIBNAME to below.
3131
LIBNAME:=libmvlib
32-
VERSION:=1.0.0
32+
VERSION:=1.0.1
3333
# EXCLUDE_SRC_FROM_LIB= $(SRCDIR)/unpublishedfile.c
3434
# this line excludes opcontrol.c and similar files
3535
EXCLUDE_SRC_FROM_LIB+=$(foreach file, $(SRCDIR)/main,$(foreach cext,$(CEXTS),$(file).$(cext)) $(foreach cxxext,$(CXXEXTS),$(file).$(cxxext)))

‎MVLib/include/mvlib/config.hpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include "literals.hpp"
1212

1313
namespace mvlib {
14-
#define __MVLIB_CONFIGURABLE static constexpr auto
14+
#define __MVLIB_CONFIGURABLE static constexpr uint32_t
1515

1616
namespace detail {
1717
using namespace mvlib::literals;

‎MVLib/include/mvlib/private/forwardLogMacros.h‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,35 @@
22
* @file forwardLogMacros.h
33
* @brief Forward log macros to the logger. These macros
44
* should not be used by the user. Instead use
5-
* LOG_INFO/WARN/etc,
5+
* LOG_INFO/WARN/etc macros,
66
* mvlib::Logger::getInstance().info/warn/etc, or
77
* mvlib::Logger::getInstance().logMessage().
88
*/
99

1010
#ifndef _MVLIB_FORWARD_LOG_MACROS
1111
#define _MVLIB_FORWARD_LOG_MACROS
1212
#define _MVLIB_FORWARD_DEBUG(fmt, ...) \
13-
do { if (m_config.logSystemInfo.load()) \
14-
Logger::getInstance().debug("[MVLIB]: " fmt, ##__VA_ARGS__); \
13+
do { if (m_config.logSystemInfo.load()) \
14+
Logger::getInstance().debug("[MVLIB] " fmt, ##__VA_ARGS__); \
1515
} while (false)
1616

1717
#define _MVLIB_FORWARD_INFO(fmt, ...) \
18-
do { if (m_config.logSystemInfo.load()) \
19-
Logger::getInstance().info("[MVLIB]: " fmt, ##__VA_ARGS__); \
18+
do { if (m_config.logSystemInfo.load()) \
19+
Logger::getInstance().info("[MVLIB] " fmt, ##__VA_ARGS__); \
2020
} while (false)
2121

2222
#define _MVLIB_FORWARD_WARN(fmt, ...) \
23-
do { if (m_config.logSystemInfo.load()) \
24-
Logger::getInstance().warn("[MVLIB]: " fmt, ##__VA_ARGS__); \
23+
do { if (m_config.logSystemInfo.load()) \
24+
Logger::getInstance().warn("[MVLIB] " fmt, ##__VA_ARGS__); \
2525
} while (false)
2626

2727
#define _MVLIB_FORWARD_ERROR(fmt, ...) \
28-
do { if (m_config.logSystemInfo.load()) \
29-
Logger::getInstance().error("[MVLIB]: " fmt, ##__VA_ARGS__); \
28+
do { if (m_config.logSystemInfo.load()) \
29+
Logger::getInstance().error("[MVLIB] " fmt, ##__VA_ARGS__); \
3030
} while (false)
3131

3232
#define _MVLIB_FORWARD_FATAL(fmt, ...) \
33-
do { if (m_config.logSystemInfo.load()) \
34-
Logger::getInstance().fatal("[MVLIB]: " fmt, ##__VA_ARGS__); \
33+
do { if (m_config.logSystemInfo.load()) \
34+
Logger::getInstance().fatal("[MVLIB] " fmt, ##__VA_ARGS__); \
3535
} while (false)
3636
#endif

‎MVLib/src/mvlib/core.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "pros/rtos.hpp"
22
#include "mvlib/core.hpp"
3-
#include "mvlib/logMacros.h"
43
#include "mvlib/config.hpp"
54
#include "mvlib/private/forwardLogMacros.h"
65
#include <cmath>
@@ -103,7 +102,8 @@ void Logger::start() {
103102
// Update loop
104103
try { this->Update(); }
105104
catch (std::exception &e) {
106-
_MVLIB_FORWARD_FATAL("%s", e.what());
105+
_MVLIB_FORWARD_FATAL("MVLib Update loop exception: %s", e.what());
106+
return;
107107
}
108108

109109
// Flush stdout buffer, and wait appropriate time

0 commit comments

Comments
 (0)