You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am Jerry Zhang from the FRC 8214 programming group. When we rendered mechanism-level actions in Advantage Scope, we had some new ideas, which we wish to discuss with you to improve the development of Advantage Kit.
To display the animation of the Mechanism level in Advantage Scope, you need to add models to the Assets Folder, update config.json, and then send an ordered Pose3d[] to NT4, see docs
However, this is not friendly to the forward kinematics of cascaded components. In the open-source code of 24 years, your robot has only one degree of freedom, which avoids the problem of solving cascaded components. While 254 build their sequence list in RobotState.java in a highly coupled way, which is obviously not conducive to code maintenance.
We understand that NT4 currently has better support for formatted data, and there is no TF tree maintenance in Advantage Scope. Based on this, our team has implemented two compromise methods. We hope we can jointly promote the development of the Advantage Kit.
Solution1: Implement a singleton class in lib
Source code
packagecom.nextinnovation.team8214;
importedu.wpi.first.math.geometry.Pose3d;
importedu.wpi.first.math.geometry.Transform3d;
importjava.util.ArrayList;
importjava.util.Comparator;
importjava.util.List;
importjava.util.function.Supplier;
importorg.littletonrobotics.junction.Logger;
/// Class helps visualize the motion of the components in *Advantage Scope*./// It maintains a TF tree and stores it in a sorted list./// @author [ZhangzrJerry](https://github.com/zhangzrjerry)publicclassAkitViz {
/** * @param componentId the id of the component, ∈[0,N] * @param parentId the id of the parent component, ∈[-1,componentId), -1 means robot frame * @param transformSupplier the supplier of the transform matrix, which contains the relative pose * from the parent component to the current component */publicrecordAkitVizComponent(
intcomponentId, intparentId, Supplier<Transform3d> transformSupplier) {
publicAkitVizComponent {
// check the validity of the parametersif (componentId < 0) {
thrownewIllegalArgumentException("componentId out of index");
}
if (parentId < -1) {
thrownewIllegalArgumentException("parentId out of index");
}
if (isStrictBigEndian && parentId >= componentId) {
thrownewIllegalArgumentException(
"componentId should not greater than or equal to parentId");
}
if (transformSupplier == null) {
thrownewIllegalArgumentException("transformSupplier should not be null");
}
}
}
/** * Register the component to the AkitViz * * @param akitVizComponent the component to be registered, should be declared in the constructor * of the subsystem * @usage see {@link AkitViz} */publicvoidregister(AkitVizComponentakitVizComponent) {
components.add(akitVizComponent);
isSort = false;
}
/** * Should be called periodically to update the poses of the components * * @usage see {@link AkitViz} */publicvoidperiodic() {
Pose3d[] poses = newPose3d[components.size()];
Transform3d[] tfs = newTransform3d[components.size()];
if (isStrictBigEndian) {
if (!isSort) {
components.sort(Comparator.comparingInt(AkitVizComponent::componentId));
isSort = true;
}
// check the validity of registered idfor (inti = 0; i < components.size(); i++) {
if (components.get(i).componentId != i) {
++waitRegFailCount;
if (waitRegFailCount > 50) {
thrownewRuntimeException(
"Timed out waiting for component registration. "
+ "The component ID should be continuous from 0 to n-1. "
+ "Please check if there is any gap in the middle. ");
}
return;
}
}
for (inti = 0; i < components.size(); ++i) {
// get transform matrix from suppliertfs[i] = components.get(i).transformSupplier.get();
// propagate the transform matrixif (components.get(i).parentId != -1) {
tfs[i] = components.get(components.get(i).parentId).transformSupplier.get().plus(tfs[i]);
}
poses[i] = newPose3d().plus(tfs[i]);
}
} else {
}
Logger.recordOutput(TOPIC_NAME, poses);
}
privatestaticBooleanisSort = true;
privatestaticIntegerwaitRegFailCount = 0;
privatestaticList<AkitVizComponent> components = newArrayList<>();
privatestaticfinalBooleanisStrictBigEndian = true;
privatestaticfinalStringTOPIC_NAME = "Visualize/Component";
privatestaticAkitVizinstance;
privateAkitViz() {}
publicstaticAkitVizgetInstance() {
if (instance == null) {
instance = newAkitViz();
}
returninstance;
}
}
Best practice
Update robot models and config.json in AScope, see docs
Maintain Ids in Config.java:
publicConfig {
// from 0 to n-1publicstaticfinalclassIds {
publicstaticfinalclassExampleSubsystem {
publicstaticfinalintEXAMPLE_COMPONENT_1 = 0;
publicstaticfinalintEXAMPLE_COMPONENT_2 = 1;
}
}
}
Call AkitViz.getInstance().periodic() periodically in Robot.java:
packagecom.nextinnovation.team8214.util;
importedu.wpi.first.math.geometry.Pose3d;
importedu.wpi.first.math.geometry.Transform3d;
importjava.util.ArrayList;
importjava.util.Comparator;
importjava.util.List;
importjava.util.function.Supplier;
importorg.littletonrobotics.junction.Logger;
/// Class that helps visualize the motion of the components in *Advantage Scope*./// It maintains a TF tree and stores it in a sorted list./// @author [ZhangzrJerry](https://github.com/zhangzrjerry)publicabstractclassVisualizer {
privatestaticBooleanisSort = true;
privatestaticIntegerwaitRegFailCount = 0;
privatestaticList<AkitVizComponent> components = newArrayList<>();
privatestaticfinalBooleanisStrictBigEndian = true;
privatestaticfinalStringTOPIC_NAME = "Visualize/Component";
/** * @param componentId the id of the component, ∈[0,N] * @param parentId the id of the parent component, ∈[-1,componentId) * @param transformSupplier the supplier of the transform matrix, which contains the relative pose * from the parent component to the current component */publicrecordAkitVizComponent(
intcomponentId, intparentId, Supplier<Transform3d> transformSupplier) {
publicAkitVizComponent {
// check the validity of the parametersif (componentId < 0) {
thrownewIllegalArgumentException("componentId out of index");
}
if (parentId < -1) {
thrownewIllegalArgumentException("parentId out of index");
}
if (isStrictBigEndian && parentId >= componentId) {
thrownewIllegalArgumentException(
"componentId should not greater than or equal to parentId");
}
if (transformSupplier == null) {
thrownewIllegalArgumentException("transformSupplier should not be null");
}
}
}
/** * Register the component to the AkitViz * * @param akitVizComponent the component to be registered, should be declared in the constructor * of the subsystem * @usage see {@link Visualizer} */publicvoidregister(AkitVizComponentakitVizComponent) {
components.add(akitVizComponent);
isSort = false;
}
/** * Should be called periodically to update the poses of the components * * @usage see {@link Visualizer} */publicvoidperiodic() {
Pose3d[] poses = newPose3d[components.size()];
Transform3d[] tfs = newTransform3d[components.size()];
if (isStrictBigEndian) {
if (!isSort) {
components.sort(Comparator.comparingInt(AkitVizComponent::componentId));
isSort = true;
}
// check the validity of registered idfor (inti = 0; i < components.size(); i++) {
if (components.get(i).componentId != i) {
++waitRegFailCount;
if (waitRegFailCount > 50) {
thrownewRuntimeException(
"Timed out waiting for component registration. "
+ "The component ID should be continuous from 0 to n-1. "
+ "Please check if there is any gap in the middle. ");
}
return;
}
}
for (inti = 0; i < components.size(); ++i) {
// get transform matrix from suppliertfs[i] = components.get(i).transformSupplier.get();
// propagate the transform matrixif (components.get(i).parentId != -1) {
tfs[i] = components.get(components.get(i).parentId).transformSupplier.get().plus(tfs[i]);
}
poses[i] = newPose3d().plus(tfs[i]);
}
} else {
}
Logger.recordOutput(TOPIC_NAME, poses);
}
}
Best practice
Update robot models and config.json in AScope, see docs
Implement AkitViz:
packagecom.nextinnovation.team8214;
importcom.nextinnovation.team8214.util.Visualizer;
/*** AkitViz is a singleton class that extends TfTree * and provides a centralized way to manage visualization components.** @see Visualizer*/publicclassAkitVizextendsVisualizer {
// you can also define it in Config.javapublicstaticfinalclassIds {
// example usagepublicstaticfinalclassExampleSubsystem {
publicstaticfinalintEXAMPLE_COMPONENT_1 = 0;
publicstaticfinalintEXAMPLE_COMPONENT_2 = 1;
}
}
publicstaticAkitVizinstance;
privateAkitViz() {}
publicstaticAkitVizgetInstance() {
if (instance == null) {
instance = newAkitViz();
}
returninstance;
}
}
Call AkitViz.getInstance().periodic() periodically in Robot.java:
Dear Advantage Kit development team,
I am Jerry Zhang from the FRC 8214 programming group. When we rendered mechanism-level actions in Advantage Scope, we had some new ideas, which we wish to discuss with you to improve the development of Advantage Kit.
To display the animation of the Mechanism level in Advantage Scope, you need to add models to the Assets Folder, update
config.json
, and then send an orderedPose3d[]
to NT4, see docsHowever, this is not friendly to the forward kinematics of cascaded components. In the open-source code of 24 years, your robot has only one degree of freedom, which avoids the problem of solving cascaded components. While 254 build their sequence list in
RobotState.java
in a highly coupled way, which is obviously not conducive to code maintenance.We understand that NT4 currently has better support for formatted data, and there is no TF tree maintenance in Advantage Scope. Based on this, our team has implemented two compromise methods. We hope we can jointly promote the development of the Advantage Kit.
Solution1: Implement a singleton class in lib
Source code
Best practice
Update robot models and config.json in AScope, see docs
Maintain Ids in
Config.java
:Call
AkitViz.getInstance().periodic()
periodically inRobot.java
:Define the zeroed transform matrix in
SubsystemConfig.java
:Register a
record
object in the constructor ofSubsystem.java
:Solution2: Implement an abstract class in lib
Source code
Best practice
Update robot models and config.json in AScope, see docs
Implement
AkitViz
:Call
AkitViz.getInstance().periodic()
periodically inRobot.java
:Define the zeroed transform matrix in
SubsystemConfig.java
:Register a
record
object in the constructor ofSubsystem.java
:The text was updated successfully, but these errors were encountered: