diff --git a/src/components/3d-viewport/SafetyZonesRenderer.tsx b/src/components/3d-viewport/SafetyZonesRenderer.tsx
index fff5a035..1223e3c3 100644
--- a/src/components/3d-viewport/SafetyZonesRenderer.tsx
+++ b/src/components/3d-viewport/SafetyZonesRenderer.tsx
@@ -1,8 +1,8 @@
-import type { SafetySetupSafetyZone } from "@wandelbots/wandelbots-js"
+import { type GroupProps } from "@react-three/fiber"
import type { Geometry } from "@wandelbots/wandelbots-api-client"
+import type { SafetySetupSafetyZone } from "@wandelbots/wandelbots-js"
import * as THREE from "three"
import { ConvexGeometry } from "three-stdlib"
-import { type GroupProps } from "@react-three/fiber"
export type SafetyZonesRendererProps = {
safetyZones: SafetySetupSafetyZone[]
@@ -89,21 +89,19 @@ export function SafetyZonesRenderer({
return null
}
return (
- <>
-
-
-
- >
+
+
+
)
})
})}
diff --git a/src/components/jogging/JoggingActivationRequired.tsx b/src/components/jogging/JoggingActivationRequired.tsx
deleted file mode 100644
index 627ffef6..00000000
--- a/src/components/jogging/JoggingActivationRequired.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import { Button, Stack, useTheme } from "@mui/material"
-import { observer } from "mobx-react-lite"
-import type React from "react"
-import { useTranslation } from "react-i18next"
-import { LoadingCover } from "../LoadingCover"
-import { TransparentOverlay } from "../TransparentOverlay"
-import type { JoggingStore } from "./JoggingStore"
-
-export const JoggingActivationRequired = observer(
- ({ store, children }: { store: JoggingStore; children: React.ReactNode }) => {
- const { t } = useTranslation()
- const theme = useTheme()
-
- function renderOverlay() {
- if (store.activationState === "inactive" && !store.activationError) {
- return (
-
-
-
- )
- } else if (store.activationState === "loading" || store.activationError) {
- return (
-
-
-
- )
- }
- }
-
- return (
-
- {renderOverlay()}
- {children}
-
- )
- },
-)
diff --git a/src/components/jogging/JoggingCartesianTab.tsx b/src/components/jogging/JoggingCartesianTab.tsx
index 5294b4f5..57cd89f2 100644
--- a/src/components/jogging/JoggingCartesianTab.tsx
+++ b/src/components/jogging/JoggingCartesianTab.tsx
@@ -13,7 +13,6 @@ import YAxisIcon from "../../icons/axis-y.svg"
import ZAxisIcon from "../../icons/axis-z.svg"
import RotationIcon from "../../icons/rotation.svg"
import { useReaction } from "../utils/hooks"
-import { JoggingActivationRequired } from "./JoggingActivationRequired"
import { JoggingCartesianAxisControl } from "./JoggingCartesianAxisControl"
import { JoggingJointLimitDetector } from "./JoggingJointLimitDetector"
import { JoggingOptions } from "./JoggingOptions"
@@ -67,11 +66,11 @@ export const JoggingCartesianTab = observer(
opts: JoggingCartesianOpts,
increment: DiscreteIncrementOption,
) {
- const tcpPose =
- store.jogger.motionStream.rapidlyChangingMotionState.tcp_pose
+ const jogger = await store.activate()
+
+ const tcpPose = jogger.motionStream.rapidlyChangingMotionState.tcp_pose
const jointPosition =
- store.jogger.motionStream.rapidlyChangingMotionState.state
- .joint_position
+ jogger.motionStream.rapidlyChangingMotionState.state.joint_position
if (!tcpPose) return
await store.withMotionLock(async () => {
@@ -100,6 +99,7 @@ export const JoggingCartesianTab = observer(
})
} finally {
store.setCurrentIncrementJog(null)
+ await store.deactivate()
}
})
}
@@ -107,6 +107,7 @@ export const JoggingCartesianTab = observer(
async function startCartesianJogging(opts: JoggingCartesianOpts) {
if (store.isLocked) return
+ const jogger = await store.activate()
if (store.activeDiscreteIncrement) {
return runIncrementalCartesianJog(opts, store.activeDiscreteIncrement)
}
@@ -133,7 +134,7 @@ export const JoggingCartesianTab = observer(
return
}
- await store.jogger.stop()
+ await store.deactivate()
}
const axisList = [
@@ -183,109 +184,112 @@ export const JoggingCartesianTab = observer(
justifyContent="center"
sx={{ flexGrow: "1" }}
>
- {/* Translate or rotate toggle */}
-
-
- {t("Jogging.Cartesian.Translation.bt")}
-
-
- {t("Jogging.Cartesian.Rotation.bt")}
-
-
+ {/* Translate or rotate toggle */}
+
+
+ {t("Jogging.Cartesian.Translation.bt")}
+
+
+ {t("Jogging.Cartesian.Rotation.bt")}
+
+
-
-
- {/* Cartesian translate jogging */}
- {store.selectedCartesianMotionType === "translate" &&
- axisList.map((axis) => (
-
- {axis.icon}
-
- {axis.id.toUpperCase()}
-
- >
- }
- getDisplayedValue={() =>
- formatMM(
- store.jogger.motionStream.rapidlyChangingMotionState
- .tcp_pose?.position[axis.id] || 0,
- )
- }
- startJogging={(direction: "-" | "+") =>
- startCartesianJogging({
- axis: axis.id,
- motionType: "translate",
- direction,
- })
- }
- stopJogging={stopJogging}
- />
- ))}
+ {/* Cartesian translate jogging */}
+ {store.selectedCartesianMotionType === "translate" &&
+ axisList.map((axis) => (
+
+ {axis.icon}
+
+ {axis.id.toUpperCase()}
+
+ >
+ }
+ getDisplayedValue={() =>
+ formatMM(
+ store.jogger.motionStream.rapidlyChangingMotionState
+ .tcp_pose?.position[axis.id] || 0,
+ )
+ }
+ startJogging={(direction: "-" | "+") =>
+ startCartesianJogging({
+ axis: axis.id,
+ motionType: "translate",
+ direction,
+ })
+ }
+ stopJogging={stopJogging}
+ />
+ ))}
- {/* Cartesian rotate jogging */}
- {store.selectedCartesianMotionType === "rotate" &&
- axisList.map((axis) => (
-
-
-
- {axis.id.toUpperCase()}
-
- >
- }
- getDisplayedValue={() =>
- formatDegrees(
- store.jogger.motionStream.rapidlyChangingMotionState
- .tcp_pose?.orientation?.[axis.id] || 0,
- )
- }
- startJogging={(direction: "-" | "+") =>
- startCartesianJogging({
- axis: axis.id,
- motionType: "rotate",
- direction,
- })
- }
- stopJogging={stopJogging}
- />
- ))}
-
-
+ {/* Cartesian rotate jogging */}
+ {store.selectedCartesianMotionType === "rotate" &&
+ axisList.map((axis) => (
+
+
+
+ {axis.id.toUpperCase()}
+
+ >
+ }
+ getDisplayedValue={() =>
+ formatDegrees(
+ store.jogger.motionStream.rapidlyChangingMotionState
+ .tcp_pose?.orientation?.[axis.id] || 0,
+ )
+ }
+ startJogging={(direction: "-" | "+") =>
+ startCartesianJogging({
+ axis: axis.id,
+ motionType: "rotate",
+ direction,
+ })
+ }
+ stopJogging={stopJogging}
+ />
+ ))}
+
{/* Show message if joint limits reached */}
diff --git a/src/components/jogging/JoggingJointRotationControl.tsx b/src/components/jogging/JoggingJointRotationControl.tsx
index 5c05738d..6fca3e64 100644
--- a/src/components/jogging/JoggingJointRotationControl.tsx
+++ b/src/components/jogging/JoggingJointRotationControl.tsx
@@ -136,7 +136,7 @@ export const JoggingJointRotationControl = externalizeComponent(
>
@@ -231,7 +231,7 @@ export const JoggingJointRotationControl = externalizeComponent(
>
diff --git a/src/components/jogging/JoggingJointTab.tsx b/src/components/jogging/JoggingJointTab.tsx
index 59fab1ac..a10ae8a9 100644
--- a/src/components/jogging/JoggingJointTab.tsx
+++ b/src/components/jogging/JoggingJointTab.tsx
@@ -2,7 +2,6 @@ import { Divider, Stack } from "@mui/material"
import { radiansToDegrees } from "@wandelbots/wandelbots-js"
import { observer } from "mobx-react-lite"
import type { ReactNode } from "react"
-import { JoggingActivationRequired } from "./JoggingActivationRequired"
import { JoggingJointLimitDetector } from "./JoggingJointLimitDetector"
import { JoggingJointRotationControl } from "./JoggingJointRotationControl"
import type { JoggingStore } from "./JoggingStore"
@@ -14,6 +13,8 @@ export const JoggingJointTab = observer(
joint: number
direction: "-" | "+"
}) {
+ await store.activate()
+
await store.jogger.startJointRotation({
joint: opts.joint,
direction: opts.direction,
@@ -36,46 +37,44 @@ export const JoggingJointTab = observer(
sx={{ flexGrow: "1" }}
id="JointControls"
>
-
-
- {store.jogger.motionStream.joints.map((joint) => {
- const jointLimits =
- store.motionGroupSpec.mechanical_joint_limits?.[joint.index]
- const lowerLimitDegs =
- jointLimits?.lower_limit !== undefined
- ? radiansToDegrees(jointLimits.lower_limit)
- : undefined
- const upperLimitDegs =
- jointLimits?.upper_limit !== undefined
- ? radiansToDegrees(jointLimits.upper_limit)
- : undefined
+
+ {store.jogger.motionStream.joints.map((joint) => {
+ const jointLimits =
+ store.motionGroupSpec.mechanical_joint_limits?.[joint.index]
+ const lowerLimitDegs =
+ jointLimits?.lower_limit !== undefined
+ ? radiansToDegrees(jointLimits.lower_limit)
+ : undefined
+ const upperLimitDegs =
+ jointLimits?.upper_limit !== undefined
+ ? radiansToDegrees(jointLimits.upper_limit)
+ : undefined
- return (
- {
- const value =
- store.jogger.motionStream.rapidlyChangingMotionState
- .state.joint_position.joints[joint.index]
- return value !== undefined
- ? radiansToDegrees(value)
- : undefined
- }}
- startJogging={(direction: "-" | "+") =>
- startJointJogging({
- joint: joint.index,
- direction,
- })
- }
- stopJogging={stopJointJogging}
- />
- )
- })}
-
-
+ return (
+ {
+ const value =
+ store.jogger.motionStream.rapidlyChangingMotionState.state
+ .joint_position.joints[joint.index]
+ return value !== undefined
+ ? radiansToDegrees(value)
+ : undefined
+ }}
+ startJogging={(direction: "-" | "+") =>
+ startJointJogging({
+ joint: joint.index,
+ direction,
+ })
+ }
+ stopJogging={stopJointJogging}
+ />
+ )
+ })}
+
diff --git a/src/components/jogging/JoggingPanel.tsx b/src/components/jogging/JoggingPanel.tsx
index 12fa2720..2e989e9a 100644
--- a/src/components/jogging/JoggingPanel.tsx
+++ b/src/components/jogging/JoggingPanel.tsx
@@ -6,7 +6,6 @@ import { observer, useLocalObservable } from "mobx-react-lite"
import { useEffect } from "react"
import { externalizeComponent } from "../../externalizeComponent"
import { LoadingCover } from "../LoadingCover"
-import { useReaction } from "../utils/hooks"
import { JoggingCartesianTab } from "./JoggingCartesianTab"
import { JoggingJointTab } from "./JoggingJointTab"
import { JoggingStore } from "./JoggingStore"
@@ -121,38 +120,6 @@ const JoggingPanelInner = observer(
children?: React.ReactNode
childrenJoint?: React.ReactNode
}) => {
- // Jogger is only active as long as the tab is focused
- useEffect(() => {
- function deactivate() {
- store.deactivate()
- }
-
- function activate() {
- store.activate()
- }
-
- window.addEventListener("blur", deactivate)
- window.addEventListener("focus", activate)
-
- return () => {
- window.removeEventListener("blur", deactivate)
- window.removeEventListener("focus", activate)
- }
- })
-
- // Update jogging mode on jogger based on user selections
- useReaction(
- () => [
- store.currentTab.id,
- store.selectedTcpId,
- store.activeCoordSystemId,
- store.activeDiscreteIncrement,
- ],
- () => {
- if (store.activationState !== "inactive") store.activate()
- },
- )
-
function renderTabContent() {
if (store.currentTab.id === "cartesian") {
return (
diff --git a/src/components/jogging/JoggingStore.ts b/src/components/jogging/JoggingStore.ts
index d7bcac3a..7acda07a 100644
--- a/src/components/jogging/JoggingStore.ts
+++ b/src/components/jogging/JoggingStore.ts
@@ -8,12 +8,7 @@ import { tryParseJson } from "@wandelbots/wandelbots-js"
import { countBy } from "lodash-es"
import keyBy from "lodash-es/keyBy"
import uniqueId from "lodash-es/uniqueId"
-import {
- autorun,
- makeAutoObservable,
- runInAction,
- type IReactionDisposer,
-} from "mobx"
+import { autorun, makeAutoObservable, type IReactionDisposer } from "mobx"
const discreteIncrementOptions = [
{ id: "0.1", mm: 0.1, degrees: 0.05 },
@@ -44,12 +39,6 @@ export type IncrementJogInProgress = {
export class JoggingStore {
selectedTabId: "cartesian" | "joint" | "debug" = "cartesian"
- /**
- * Whether the user must manually interact to activate jogging, or
- * if it can be done automatically
- */
- manualActivationRequired: boolean = true
-
/**
* State of the jogging panel. Starts as "inactive"
*/
@@ -141,6 +130,18 @@ export class JoggingStore {
),
])
+ // Setting mode control makes jogging startup slightly faster
+ // on physical robots
+ // https://wandelbots.slack.com/archives/C06VA4J59PF/p1725523765976109?thread_ts=1725464963.859559&cid=C06VA4J59PF
+ try {
+ await jogger.nova.api.controller.setDefaultMode(
+ jogger.motionStream.controllerId,
+ "MODE_CONTROL",
+ )
+ } catch (err) {
+ console.error(err)
+ }
+
return new JoggingStore(
jogger,
motionGroupSpec,
@@ -187,54 +188,18 @@ export class JoggingStore {
return countBy(this.coordSystems, (cs) => cs.name)
}
- async deactivate(opts: { requireManualReactivation?: boolean } = {}) {
- if (this.activationState === "inactive") return
+ async deactivate() {
const websocket = this.jogger.activeWebsocket
- this.activationState = "inactive"
this.jogger.setJoggingMode("increment")
if (websocket) {
await websocket.closed()
}
-
- // Closing websocket sometimes isn't enough to stop interference
- try {
- await this.jogger.nova.api.motionGroupJogging.stopJogging(
- this.jogger.motionGroupId,
- )
- } catch (err) {
- console.error(err)
- }
-
- if (opts.requireManualReactivation) {
- runInAction(() => {
- this.manualActivationRequired = true
- })
- }
}
/** Activate the jogger with current settings */
- async activate(opts: { manual?: boolean } = {}) {
- if (this.manualActivationRequired && !opts.manual) return
-
- runInAction(() => {
- this.activationState = "loading"
- this.activationError = null
- })
-
- // Setting mode control makes jogging startup slightly faster
- // on physical robots
- // https://wandelbots.slack.com/archives/C06VA4J59PF/p1725523765976109?thread_ts=1725464963.859559&cid=C06VA4J59PF
- try {
- await this.jogger.nova.api.controller.setDefaultMode(
- this.jogger.motionStream.controllerId,
- "MODE_CONTROL",
- )
- } catch (err) {
- console.error(err)
- }
-
+ async activate() {
if (this.currentTab.id === "cartesian") {
const cartesianJoggingOpts = {
tcpId: this.selectedTcpId,
@@ -250,25 +215,7 @@ export class JoggingStore {
this.jogger.setJoggingMode("joint")
}
- if (this.jogger.activeWebsocket) {
- try {
- this.jogger.stop()
- await this.jogger.activeWebsocket.nextMessage()
- } catch (err) {
- runInAction(() => {
- this.activationState = "inactive"
- this.activationError = err
- })
- return
- }
- }
-
- runInAction(() => {
- this.activationState = "active"
- if (opts.manual) {
- this.manualActivationRequired = false
- }
- })
+ return this.jogger
}
loadFromLocalStorage() {
diff --git a/src/i18n/locales/de/translations.json b/src/i18n/locales/de/translations.json
index aafa4b5e..bf8f4b72 100644
--- a/src/i18n/locales/de/translations.json
+++ b/src/i18n/locales/de/translations.json
@@ -10,8 +10,6 @@
"Jogging.Joints.JointValues.lb": "Gelenkwerte",
"Jogging.Increment.Continuous.dd": "Fortlaufend",
"Jogging.Cartesian.Orientation.lb": "Orientierung",
- "Jogging.Activate.bt": "Jogging aktivieren",
- "Jogging.Activating.lb": "Jogging wird aktiviert",
"Jogging.JointLimitsReached.lb": "Joint-Limit für Joint {{jointNumbers}} erreicht",
"Jogging.Orientation.coordsys": "Base",
"Jogging.Orientation.tool": "Tool"
diff --git a/src/i18n/locales/en/translations.json b/src/i18n/locales/en/translations.json
index 911b5442..d4ffbe53 100644
--- a/src/i18n/locales/en/translations.json
+++ b/src/i18n/locales/en/translations.json
@@ -10,7 +10,6 @@
"Jogging.Joints.JointValues.lb": "Joint values",
"Jogging.Increment.Continuous.dd": "Continuous",
"Jogging.Cartesian.Orientation.lb": "Orientation",
- "Jogging.Activate.bt": "Activate jogging",
"Jogging.Activating.lb": "Activating jogging",
"Jogging.JointLimitsReached.lb": "Joint limit reached for joint {{jointNumbers}}",
"Jogging.Orientation.coordsys": "Base",