mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-08-18 09:29:03 +08:00
Added "hooks" to wizard choices to allow for computation as part of a config choice
Added page-scope components for wizard pages
This commit is contained in:
@@ -2,6 +2,12 @@ import odriveEnums from "../odriveEnums.json";
|
||||
|
||||
// wizard is an object of pages.
|
||||
// each page has a number, title, vue component name, next destination, back destination, and array of choices
|
||||
// certain choices require a hook - for example, hall effect encoder cpr is 6 * motor.config.pole_pairs
|
||||
// each hook takes a config object, modifies it, and returns it after running appropriate calculations.
|
||||
// see choiceHandler() in Wizard.vue for how this happens
|
||||
|
||||
// Pages can also have custom components displayed below the choice tiles
|
||||
// Example - on motor pages, there are buttons to run motor calibration and clear errors.
|
||||
export let pages = {
|
||||
ODrive: {
|
||||
number: 0,
|
||||
@@ -15,13 +21,16 @@ export let pages = {
|
||||
{
|
||||
imageURL: require("../images/24v_300x300.png"),
|
||||
text: "ODrive v3.6 24V",
|
||||
hooks: [],
|
||||
},
|
||||
{
|
||||
imageURL: require("../images/56v_300x300.png"),
|
||||
text: "ODrive v3.6 56V",
|
||||
hooks: [],
|
||||
},
|
||||
],
|
||||
customComponents: [],
|
||||
pageComponents: [],
|
||||
},
|
||||
Motor_0: {
|
||||
number: 1,
|
||||
@@ -35,14 +44,16 @@ export let pages = {
|
||||
{
|
||||
imageURL: require("../images/D5065_300x300.png"),
|
||||
text: "ODrive D5065",
|
||||
hooks: [],
|
||||
configStub: {
|
||||
axis0: {
|
||||
motor: {
|
||||
config: {
|
||||
pole_pairs: 7,
|
||||
torque_constant: 8.27 / 270,
|
||||
phase_resistance: 0.039, // from test rig
|
||||
phase_inductance: 1.57e-5,
|
||||
// R and L come from "Calibrate Motor" button on page
|
||||
//phase_resistance: 0.039, // from test rig
|
||||
//phase_inductance: 1.57e-5,
|
||||
motor_type: odriveEnums.MOTOR_TYPE_HIGH_CURRENT, // MOTOR_TYPE_HIGH_CURRENT
|
||||
},
|
||||
},
|
||||
@@ -52,14 +63,16 @@ export let pages = {
|
||||
{
|
||||
imageURL: require("../images/D6374_300x300.png"),
|
||||
text: "ODrive D6374",
|
||||
hooks: [],
|
||||
configStub: {
|
||||
axis0: {
|
||||
motor: {
|
||||
config: {
|
||||
pole_pairs: 7,
|
||||
torque_constant: 8.27 / 150,
|
||||
phase_resistance: 0.041, // measurement from PJ
|
||||
phase_inductance: 2.23e-5,
|
||||
// R and L come from "Calibrate Motor" button on page
|
||||
//phase_resistance: 0.041, // measurement from PJ
|
||||
//phase_inductance: 2.23e-5,
|
||||
motor_type: odriveEnums.MOTOR_TYPE_HIGH_CURRENT, // MOTOR_TYPE_HIGH_CURRENT,
|
||||
},
|
||||
},
|
||||
@@ -76,6 +89,22 @@ export let pages = {
|
||||
}
|
||||
},
|
||||
],
|
||||
pageComponents: [
|
||||
{
|
||||
component: "wizardMotorMeasure",
|
||||
id: 0,
|
||||
data: {
|
||||
axis: "axis0",
|
||||
}
|
||||
},
|
||||
{
|
||||
component: "wizardClearErrors",
|
||||
id: 1,
|
||||
data: {
|
||||
axis: "axis0"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
Encoder_0: {
|
||||
number: 2,
|
||||
@@ -89,6 +118,7 @@ export let pages = {
|
||||
{
|
||||
imageURL: require("../images/amt102-v_300x300.png"),
|
||||
text: "CUI AMT102V",
|
||||
hooks: [],
|
||||
configStub: {
|
||||
axis0: {
|
||||
encoder: {
|
||||
@@ -104,11 +134,18 @@ export let pages = {
|
||||
{
|
||||
imageURL: require("../images/hall_effect_300x300.png"),
|
||||
text: "Hall Effect",
|
||||
hooks: [
|
||||
// hook takes a config object (normally this.wizardConfig in Wizard.vue), creates and returns a copy
|
||||
(configObj) => {
|
||||
let newConfig = configObj;
|
||||
newConfig.axis0.encoder.config.cpr = 6 * newConfig.axis0.motor.config.pole_pairs;
|
||||
return newConfig;
|
||||
},
|
||||
],
|
||||
configStub: {
|
||||
axis0: {
|
||||
encoder: {
|
||||
config: {
|
||||
cpr: 8192,
|
||||
use_index: false,
|
||||
mode: odriveEnums.ENCODER_MODE_HALL,
|
||||
}
|
||||
@@ -133,6 +170,7 @@ export let pages = {
|
||||
}
|
||||
},
|
||||
],
|
||||
pageComponents: [],
|
||||
},
|
||||
Misc_0: {
|
||||
number: 3,
|
||||
@@ -152,6 +190,7 @@ export let pages = {
|
||||
}
|
||||
},
|
||||
],
|
||||
pageComponents: [],
|
||||
},
|
||||
Motor_1: {
|
||||
number: 4,
|
||||
@@ -165,6 +204,7 @@ export let pages = {
|
||||
{
|
||||
imageURL: require("../images/D5065_300x300.png"),
|
||||
text: "ODrive D5065",
|
||||
hooks: [],
|
||||
configStub: {
|
||||
axis1: {
|
||||
motor: {
|
||||
@@ -182,6 +222,7 @@ export let pages = {
|
||||
{
|
||||
imageURL: require("../images/D6374_300x300.png"),
|
||||
text: "ODrive D6374",
|
||||
hooks: [],
|
||||
configStub: {
|
||||
axis1: {
|
||||
motor: {
|
||||
@@ -206,6 +247,7 @@ export let pages = {
|
||||
}
|
||||
},
|
||||
],
|
||||
pageComponents: [],
|
||||
},
|
||||
Encoder_1: {
|
||||
number: 5,
|
||||
@@ -219,6 +261,7 @@ export let pages = {
|
||||
{
|
||||
imageURL: require("../images/amt102-v_300x300.png"),
|
||||
text: "CUI AMT102V",
|
||||
hooks: [],
|
||||
configStub: {
|
||||
axis0: {
|
||||
encoder: {
|
||||
@@ -234,11 +277,18 @@ export let pages = {
|
||||
{
|
||||
imageURL: require("../images/hall_effect_300x300.png"),
|
||||
text: "Hall Effect",
|
||||
hooks: [
|
||||
// hook takes a config object, creates and returns a copy
|
||||
(configObj) => {
|
||||
let newConfig = configObj;
|
||||
newConfig.axis1.encoder.config.cpr = 6 * newConfig.axis1.motor.config.pole_pairs;
|
||||
return newConfig;
|
||||
},
|
||||
],
|
||||
configStub: {
|
||||
axis0: {
|
||||
encoder: {
|
||||
config: {
|
||||
cpr: 8192,
|
||||
use_index: false,
|
||||
mode: odriveEnums.ENCODER_MODE_HALL, // ENCODER_MODE_INCREMENTAL
|
||||
}
|
||||
@@ -263,6 +313,7 @@ export let pages = {
|
||||
}
|
||||
},
|
||||
],
|
||||
pageComponents: [],
|
||||
},
|
||||
Misc_1: {
|
||||
number: 6,
|
||||
@@ -282,6 +333,7 @@ export let pages = {
|
||||
}
|
||||
},
|
||||
],
|
||||
pageComponents: [],
|
||||
},
|
||||
End: {
|
||||
number: 7,
|
||||
@@ -297,6 +349,7 @@ export let pages = {
|
||||
component: "wizardEnd",
|
||||
id: 0,
|
||||
}
|
||||
]
|
||||
],
|
||||
pageComponents: [],
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ export default {
|
||||
this.$emit("choice", {
|
||||
choice: "Incremental",
|
||||
configStub: configStub,
|
||||
hooks: [],
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -54,6 +54,7 @@ export default {
|
||||
this.$emit("choice", {
|
||||
choice: "IncrementalIndex",
|
||||
configStub: configStub,
|
||||
hooks: [],
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
export default {
|
||||
name: "wizardMisc",
|
||||
props: {
|
||||
data: Object
|
||||
data: Object,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
@@ -27,7 +27,13 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
velocityLimit: function () {
|
||||
let keys = ["odrive0", this.data.axis, "controller", "config", "vel_limit"];
|
||||
let keys = [
|
||||
"odrive0",
|
||||
this.data.axis,
|
||||
"controller",
|
||||
"config",
|
||||
"vel_limit",
|
||||
];
|
||||
let odriveObj = this.$store.state.odrives;
|
||||
for (const key of keys) {
|
||||
odriveObj = odriveObj[key];
|
||||
@@ -45,7 +51,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
sendConfig() {
|
||||
if ((this.vel_set == true && this.current_set == true)) {
|
||||
if (this.vel_set == true && this.current_set == true) {
|
||||
console.log("emitting choice event from limits page");
|
||||
this.$emit("choice", {
|
||||
choice: "Limits " + this.data.axis,
|
||||
@@ -53,6 +59,44 @@ export default {
|
||||
vel_limit: this.vel_limit,
|
||||
current_lim: this.current_lim,
|
||||
},
|
||||
hooks: [],
|
||||
});
|
||||
let configStub = undefined;
|
||||
if (this.data.axis == "axis0") {
|
||||
configStub = {
|
||||
axis0: {
|
||||
controller: {
|
||||
config: {
|
||||
vel_limit: this.vel_limit,
|
||||
}
|
||||
},
|
||||
motor: {
|
||||
config: {
|
||||
current_lim: this.current_lim,
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
} else if (this.data.axis == "axis1") {
|
||||
configStub = {
|
||||
axis1: {
|
||||
controller: {
|
||||
config: {
|
||||
vel_limit: this.vel_limit,
|
||||
}
|
||||
},
|
||||
motor: {
|
||||
config: {
|
||||
current_lim: this.current_lim,
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
this.$emit("choice", {
|
||||
choice: "Misc " + this.data.axis,
|
||||
configStub: configStub,
|
||||
hooks: [],
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -10,13 +10,12 @@
|
||||
</div>
|
||||
<div class="left">
|
||||
<span>Phase Resistance =</span>
|
||||
<span>{{" " + resistance}}</span>
|
||||
<span>{{" " + resistance}} R</span>
|
||||
</div>
|
||||
<div class="left">
|
||||
<span>Phase Inductace =</span>
|
||||
<span>{{" " + inductance}}</span>
|
||||
<span>{{" " + inductance}} H</span>
|
||||
</div>
|
||||
<button class="measure-button card" @click="measure">Measure Resistance and Inductance</button>
|
||||
<span class="name">Other Motor</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -174,6 +173,7 @@ export default {
|
||||
this.$emit("choice", {
|
||||
choice: "Other motor",
|
||||
configStub: configStub,
|
||||
hooks: [],
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div>
|
||||
<button class="measure-button card" @click="calibrate">Calibrate Motor</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const axios = require("axios");
|
||||
import odriveEnums from "../../assets/odriveEnums.json";
|
||||
|
||||
export default {
|
||||
name: "wizardMotorMeasure",
|
||||
props: {
|
||||
data: Object,
|
||||
},
|
||||
methods: {
|
||||
calibrate() {
|
||||
// ask ODrive to measure resistance and inductance
|
||||
var params = new URLSearchParams();
|
||||
let keys = ["odrive0", this.data.axis, "requested_state"];
|
||||
for (const key of keys) {
|
||||
params.append("key", key);
|
||||
}
|
||||
params.append("val", odriveEnums.AXIS_STATE_MOTOR_CALIBRATION);
|
||||
params.append("type", "number");
|
||||
console.log(params.toString());
|
||||
let request = {
|
||||
params: params,
|
||||
};
|
||||
console.log(request);
|
||||
axios.put(
|
||||
this.$store.state.odriveServerAddress + "/api/property",
|
||||
null,
|
||||
request
|
||||
);
|
||||
this.$emit('page-comp-event', {data: "motor calibration", axis: this.data.axis});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.measure-button:active {
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -9,7 +9,7 @@
|
||||
:key="choice.id"
|
||||
:imageUrl="choice.imageURL"
|
||||
:text="choice.text"
|
||||
v-on:click.native="selectedChoice=choice.text;$emit('choice', {title: title, choice: choice.text, configStub: choice.configStub})"
|
||||
v-on:click.native="selectedChoice=choice.text;$emit('choice', {title: title, choice: choice.text, configStub: choice.configStub, hooks: choice.hooks})"
|
||||
/>
|
||||
<template v-for="customComponent in customComponents">
|
||||
<component
|
||||
@@ -24,6 +24,16 @@
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
<div class="page-components">
|
||||
<template v-for="pageComponent in pageComponents">
|
||||
<component
|
||||
v-bind:is="pageComponent.component"
|
||||
v-bind:data="pageComponent.data"
|
||||
v-bind:key="pageComponent.id"
|
||||
v-on:page-comp-event="pageCompEvent"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -34,6 +44,8 @@ import wizardMotor from "./wizardMotor.vue";
|
||||
import wizardEncoderIncremental from "./wizardEncoderIncremental.vue";
|
||||
import wizardEncoderIncrementalIndex from "./wizardEncoderIncrementalIndex.vue";
|
||||
import wizardEnd from "./wizardEnd.vue";
|
||||
import wizardClearErrors from "./wizardClearErrors.vue";
|
||||
import wizardMotorMeasure from "./wizardMotorMeasure.vue";
|
||||
|
||||
export default {
|
||||
name: "wizardPage",
|
||||
@@ -43,6 +55,7 @@ export default {
|
||||
customComponents: Array,
|
||||
axis: String,
|
||||
config: Object,
|
||||
pageComponents: Array,
|
||||
},
|
||||
components: {
|
||||
wizardChoice,
|
||||
@@ -51,6 +64,8 @@ export default {
|
||||
wizardEncoderIncremental,
|
||||
wizardEncoderIncrementalIndex,
|
||||
wizardEnd,
|
||||
wizardClearErrors,
|
||||
wizardMotorMeasure,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
@@ -60,7 +75,10 @@ export default {
|
||||
methods: {
|
||||
handleCustomChoice(e) {
|
||||
console.log(e);
|
||||
this.$emit('choice', e);
|
||||
this.$emit("choice", e);
|
||||
},
|
||||
pageCompEvent(e) {
|
||||
this.$emit('page-comp-event',e);
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -79,6 +97,12 @@ export default {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.page-components {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.chosen {
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
@@ -8,22 +8,28 @@
|
||||
:key="page.number"
|
||||
class="wizard-link"
|
||||
v-bind:class="{'active-link': currentStep == page}"
|
||||
@click="currentStep=page"
|
||||
@click="currentStep = page; choiceMade = false"
|
||||
>{{page.link}}</span>
|
||||
</div>
|
||||
<div class="wizard-page">
|
||||
<wizardPage
|
||||
:choices="currentStep.choices"
|
||||
:customComponents="currentStep.customComponents"
|
||||
:pageComponents="currentStep.pageComponents"
|
||||
:title="currentStep.title"
|
||||
:config="wizardConfig"
|
||||
v-on:choice="choiceHandler"
|
||||
v-on:page-comp-event="pageEventHandler"
|
||||
/>
|
||||
<div class="wizard-controls">
|
||||
<!-- show breadcrumbs, back, apply, next buttons -->
|
||||
<button class="wizard-button card" @click="back">Back</button>
|
||||
<button class="wizard-button card" @click="finish">Finish</button>
|
||||
<button class="wizard-button card" @click="next">Next</button>
|
||||
<button
|
||||
class="wizard-button card"
|
||||
v-bind:class="{'next-green': choiceMade}"
|
||||
@click="next"
|
||||
>Next</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -48,6 +54,7 @@ export default {
|
||||
return {
|
||||
currentStep: pages.ODrive,
|
||||
wizardConfig: configTemplate,
|
||||
choiceMade: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -56,8 +63,83 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
pageEventHandler(e) {
|
||||
this.choiceMade = false;
|
||||
if (e.data == "motor calibration") {
|
||||
// set a timeout to grab axis resistance and inductance values
|
||||
setTimeout(() => {
|
||||
let configStub = undefined;
|
||||
let inductance;
|
||||
let resistance;
|
||||
let keys_L = [
|
||||
"odrive0",
|
||||
e.axis,
|
||||
"motor",
|
||||
"config",
|
||||
"phase_inductance",
|
||||
];
|
||||
let keys_R = [
|
||||
"odrive0",
|
||||
e.axis,
|
||||
"motor",
|
||||
"config",
|
||||
"phase_resistance",
|
||||
];
|
||||
let odriveObj = this.$store.state.odrives;
|
||||
for (const key of keys_L) {
|
||||
odriveObj = odriveObj[key];
|
||||
}
|
||||
inductance = parseFloat(odriveObj["val"]);
|
||||
|
||||
odriveObj = this.$store.state.odrives;
|
||||
for (const key of keys_R) {
|
||||
odriveObj = odriveObj[key];
|
||||
}
|
||||
resistance = parseFloat(odriveObj["val"]);
|
||||
if (e.axis == "axis0") {
|
||||
configStub = {
|
||||
axis0: {
|
||||
motor: {
|
||||
config: {
|
||||
phase_resistance: resistance,
|
||||
phase_inductance: inductance,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
} else if (e.axis == "axis1") {
|
||||
configStub = {
|
||||
axis1: {
|
||||
motor: {
|
||||
config: {
|
||||
phase_resistance: resistance,
|
||||
phase_inductance: inductance,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
this.choiceHandler({
|
||||
choice: "Motor Calibration",
|
||||
configStub: configStub,
|
||||
hooks: [],
|
||||
})
|
||||
}, 6000);
|
||||
}
|
||||
},
|
||||
choiceHandler(e) {
|
||||
// apply static configStub
|
||||
this.updateConfig(this.wizardConfig, e.configStub);
|
||||
|
||||
// run hooks
|
||||
for (const fn of e.hooks) {
|
||||
this.wizardConfig = fn(this.wizardConfig);
|
||||
}
|
||||
|
||||
// ugly, but a special case.
|
||||
if (e.choice != "ODrive D5065" && e.choice != "ODrive D6374" && e.choice != "Other motor"){
|
||||
this.choiceMade = true;
|
||||
}
|
||||
console.log(JSON.parse(JSON.stringify(this.wizardConfig)));
|
||||
},
|
||||
updateConfig(config, configStub) {
|
||||
@@ -75,6 +157,7 @@ export default {
|
||||
next() {
|
||||
console.log("next");
|
||||
this.currentStep = pages[this.currentStep.next];
|
||||
this.choiceMade = false;
|
||||
},
|
||||
finish() {
|
||||
console.log("finish");
|
||||
@@ -83,6 +166,7 @@ export default {
|
||||
back() {
|
||||
console.log("back");
|
||||
this.currentStep = pages[this.currentStep.back];
|
||||
this.choiceMade = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -147,4 +231,9 @@ export default {
|
||||
.wizard-button:active {
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
.next-green {
|
||||
color: green;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user