Skip to content
Merged
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
46 changes: 24 additions & 22 deletions fission/src/systems/simulation/wpilib_brain/WPILibBrain.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type MirabufSceneObject from "@/mirabuf/MirabufSceneObject"
import EventSystem from "@/systems/EventSystem.ts"
import World from "@/systems/World"
import { random } from "@/util/Random"
import Brain from "../Brain"
import { SimConfig } from "../SimConfigShared"
import type { SimulationLayer } from "../SimulationSystem"
import SynthesisBrain from "../synthesis_brain/SynthesisBrain"
import { type SimFlow, validate } from "./SimDataFlow"
Expand All @@ -13,7 +13,8 @@ import { SimAnalogInput } from "./sim/SimAI"
import { SimDigitalInput } from "./sim/SimDIO"
import { SimGyroInput } from "./sim/SimGyro"
import { getSimBrain, getSimMap, setConnected, setSimBrain } from "./WPILibState"
import { type DeviceData, SimType, type WSMessage, worker } from "./WPILibTypes"
import { type DeviceData, type SimType, type WSMessage, worker } from "./WPILibTypes"
import SimDriverStation from "./sim/SimDriverStation"

worker.getValue().addEventListener("message", (eventData: MessageEvent) => {
let data: WSMessage | undefined
Expand All @@ -22,10 +23,15 @@ worker.getValue().addEventListener("message", (eventData: MessageEvent) => {
switch (eventData.data.status) {
case "open":
setConnected(true)
SimDriverStation.setDsAttached(true)
break
case "close":
setConnected(false)
SimDriverStation.setDsAttached(false)
break
case "error":
setConnected(false)
SimDriverStation.setDsAttached(false)
break
default:
return
Expand All @@ -39,12 +45,11 @@ worker.getValue().addEventListener("message", (eventData: MessageEvent) => {
try {
data = JSON.parse(eventData.data)
} catch (_e) {
console.error(`Failed to parse data:\n${JSON.stringify(eventData.data)}`)
return
}
}

if (!data?.type || !(Object.values(SimType) as string[]).includes(data.type)) return
if (!data?.type) return

updateSimMap(data.type as SimType, data.device, data.data)
})
Expand All @@ -65,8 +70,6 @@ function updateSimMap(type: SimType, device: string, updateData: DeviceData) {
}

Object.entries(updateData).forEach(([key, value]) => currentData.set(key, value))

EventSystem.dispatch("SimMapUpdateEvent", { internalUpdate: false })
}

class WPILibBrain extends Brain {
Expand All @@ -89,7 +92,6 @@ class WPILibBrain extends Brain {
this._simLayer = World.simulationSystem.getSimulationLayer(this._mechanism)!

if (!this._simLayer) {
console.warn("SimulationLayer is undefined")
return
}

Expand Down Expand Up @@ -130,21 +132,21 @@ class WPILibBrain extends Brain {
const configData = this._assembly.simConfigData
if (!configData) return false

// const flows = SimConfig.Compile(configData, this._assembly)
// if (!flows) {
// console.error(`Failed to compile saved simulation configuration data for '${this.assemblyName}'`)
// return false
// }

// let counter = 0
// flows.forEach(x => {
// if (!this.addSimFlow(x)) {
// console.debug("Failed to validate flow, skipping...")
// } else {
// counter++
// }
// })
// console.debug(`${counter} Flows added!`)
const flows = SimConfig.Compile(configData, this._assembly)
if (!flows) {
console.error(`Failed to compile saved simulation configuration data for '${this.assemblyName}'`)
return false
}

let counter = 0
flows.forEach(x => {
if (!this.addSimFlow(x)) {
console.debug("Failed to validate flow, skipping...")
} else {
counter++
}
})
console.debug(`${counter} Flows added!`)
return true
}

Expand Down
36 changes: 16 additions & 20 deletions fission/src/systems/simulation/wpilib_brain/WPILibWSWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,25 @@ function socketConnecting(): boolean {
}

async function tryConnect(port?: number): Promise<void> {
await connectMutex
.runExclusive(() => {
if ((socket?.readyState ?? WebSocket.CLOSED) == WebSocket.OPEN) {
return
}

socket = new WebSocket(`ws://localhost:${port ?? 3300}/wpilibws`)
await connectMutex.runExclusive(() => {
if ((socket?.readyState ?? WebSocket.CLOSED) == WebSocket.OPEN) {
return
}

socket.addEventListener("open", () => {
console.log("WS Opened")
self.postMessage({ status: "open" })
})
socket.addEventListener("error", () => {
console.log("WS Could not open")
self.postMessage({ status: "error" })
})
socket.addEventListener("close", () => {
self.postMessage({ status: "close" })
})
socket = new WebSocket(`ws://localhost:${port ?? 3300}/wpilibws`)

socket.addEventListener("message", onMessage)
socket.addEventListener("open", () => {
self.postMessage({ status: "open" })
})
.then(() => console.debug("Mutex released"))
socket.addEventListener("error", () => {
self.postMessage({ status: "error" })
})
socket.addEventListener("close", () => {
self.postMessage({ status: "close" })
})

socket.addEventListener("message", onMessage)
})
}

async function tryDisconnect(): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,18 @@ export default class SimDriverStation {
}

public static setMode(mode: RobotSimMode) {
SimGeneric.set<boolean>(SimType.DRIVERS_STATION, "", ">enabled", mode != RobotSimMode.DISABLED)
SimGeneric.set<boolean>(SimType.DRIVERS_STATION, "", ">autonomous", mode == RobotSimMode.AUTO)
const enabled = mode != RobotSimMode.DISABLED
const autonomous = mode == RobotSimMode.AUTO
SimGeneric.set<boolean>(SimType.DRIVERS_STATION, "", ">ds", true)
SimGeneric.set<boolean>(SimType.DRIVERS_STATION, "", ">enabled", enabled)
SimGeneric.set<boolean>(SimType.DRIVERS_STATION, "", ">autonomous", autonomous)
}

public static setStation(station: AllianceStation) {
SimGeneric.set<string>(SimType.DRIVERS_STATION, "", ">station", station)
}

public static setDsAttached(attached: boolean) {
SimGeneric.set<boolean>(SimType.DRIVERS_STATION, "", ">ds", attached)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export default class SimGeneric {
data: selectedData,
},
})

EventSystem.dispatch("SimMapUpdateEvent", { internalUpdate: true })
return true
}
Expand Down
19 changes: 11 additions & 8 deletions simulation/SyntheSimJava/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ repositories {
url "https://maven.revrobotics.com/"
}

// KAUAI
// Studica (NavX)
maven {
url "https://dev.studica.com/maven/release/2024/"
url "https://dev.studica.com/maven/release/2026/"
}
}

def WPI_Version = '2024.3.2'
def REV_Version = '2024.2.4'
def CTRE_Version = '24.3.0'
def KAUAI_Version = '2024.1.0'
def WPI_Version = '2026.2.2'
def REV_Version = '2026.0.5'
def CTRE_Version = '26.3.0'
def STUDICA_Version = '2026.0.0'

dependencies {
// This dependency is exported to consumers, that is to say found on their compile classpath.
Expand All @@ -53,15 +53,18 @@ dependencies {
implementation "edu.wpi.first.wpilibj:wpilibj-java:$WPI_Version"
implementation "edu.wpi.first.wpiutil:wpiutil-java:$WPI_Version"
implementation "edu.wpi.first.hal:hal-java:$WPI_Version"
implementation "edu.wpi.first.wpimath:wpimath-java:$WPI_Version"
implementation "edu.wpi.first.ntcore:ntcore-java:$WPI_Version"
implementation "edu.wpi.first.wpiunits:wpiunits-java:$WPI_Version"

// REVRobotics
implementation "com.revrobotics.frc:REVLib-java:$REV_Version"

// CTRE
implementation "com.ctre.phoenix6:wpiapi-java:$CTRE_Version"

// KAUAI
implementation "com.kauailabs.navx.frc:navx-frc-java:$KAUAI_Version"
// Studica (NavX)
implementation "com.studica.frc:Studica-java:$STUDICA_Version"
}

java {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@

import com.autodesk.synthesis.CANEncoder;
import com.autodesk.synthesis.CANMotor;
import com.ctre.phoenix6.signals.NeutralModeValue;
import com.ctre.phoenix6.StatusSignal;
import com.ctre.phoenix6.configs.TalonFXConfigurator;
import com.ctre.phoenix6.hardware.DeviceIdentifier;

/**
* TalonFX wrapper to add proper WPILib HALSim support.
*
* In Phoenix6 26, set(), setNeutralMode(), getPosition(), and getVelocity() are all
* final and cannot be overridden. Call syncSim() each robot periodic cycle to push
* the current motor output and encoder state into Synthesis.
*/
public class TalonFX extends com.ctre.phoenix6.hardware.TalonFX {
private CANMotor m_motor;
private CANEncoder m_encoder;

/**
* Creates a new TalonFX, wrapped with simulation support.
*
*
* @param deviceNumber CAN Device ID.
*/
public TalonFX(int deviceNumber) {
Expand All @@ -24,66 +27,11 @@ public TalonFX(int deviceNumber) {
}

/**
* Sets the torque of the real and simulated motors
*
* @param percentOutput The torque
*/
@Override
public void set(double percentOutput) {
super.set(percentOutput);
this.m_motor.setPercentOutput(percentOutput);
}

/**
* Sets both the real and simulated motors to neutral mode
*
* @param mode The neutral mode value
*
*/
@Override
public void setNeutralMode(NeutralModeValue mode) {
super.setNeutralMode(mode);

this.m_motor.setBrakeMode(mode == NeutralModeValue.Brake);
}

/**
* Gets and internal configurator for both the simulated and real motors
*
* @return The internal configurator for this Talon motor
*/
@Override
public TalonFXConfigurator getConfigurator() {
DeviceIdentifier id = this.deviceIdentifier;
return new com.autodesk.synthesis.ctre.TalonFXConfigurator(id, this);
}

// called internally by the configurator to set the deadband, not for user use
public void setNeutralDeadband(double deadband) {
this.m_motor.setNeutralDeadband(deadband);
}

/**
* Gets the position of the simulated encoder
*
* @return The motor position in revolutions
*/
@Override
public StatusSignal<Double> getPosition() {
Double pos = this.m_encoder.getPosition();
super.setPosition(pos);
return super.getPosition();
}

/**
* Gets the velocity of the simulated motor according to the simulated encoder
*
* @return The motor velocity in revolutions per second
* Syncs the current motor output and encoder state into Synthesis.
* Call this once per robot periodic cycle (e.g. in robotPeriodic()).
*/
@Override
public StatusSignal<Double> getVelocity() {
Double velocity = this.m_encoder.getVelocity();
super.set(velocity);
return super.getVelocity();
public void syncSim() {
m_motor.setPercentOutput(this.get());
this.setPosition(m_encoder.getPosition());
}
}

This file was deleted.

This file was deleted.

Loading
Loading