Commit da0fc1ee authored by Jake Read's avatar Jake Read
Browse files

more tuning scaffolding

parent 95764efa
......@@ -147,7 +147,7 @@ loopQueryBtn.onClick(() => {
let runBtn = new Button(10, 130, 94, 14, 'run')
runBtn.onClick(() => {
vm.setMode("pid").then(() =>{
vm.setMode("pid").then(() => {
runBtn.good("ok", 500)
}).catch((err) => {
console.error(err)
......@@ -157,7 +157,7 @@ runBtn.onClick(() => {
let stopBtn = new Button(10, 160, 94, 14, 'stop')
stopBtn.onClick(() => {
vm.setMode("noop").then(() =>{
vm.setMode("noop").then(() => {
stopBtn.good("ok", 500)
}).catch((err) => {
console.error(err)
......@@ -165,77 +165,45 @@ stopBtn.onClick(() => {
})
})
// -------------------------------------------------------- MOTION FEED
// -------------------------------------------------------- PID
let PIDController = (xPlace, yPlace) => {
let pVal = new TextInput(xPlace, yPlace + 120, 110, 20, '-0.1')
let iVal = new TextInput(xPlace, yPlace + 150, 110, 20, '0.0')
let dVal = new TextInput(xPlace, yPlace + 180, 110, 20, '0.1')
let pidSetBtn = new Button(xPlace, yPlace + 210, 104, 14, 'set PID')
pidSetBtn.onClick(() => {
let p = parseFloat(pVal.value)
let i = parseFloat(iVal.value)
let d = parseFloat(dVal.value)
if (Number.isNaN(p) || Number.isNaN(i) || Number.isNaN(d)) {
pidSetBtn.bad("bad parse", 1000)
return
}
tvm.setPIDTerms([p, i, d]).then(() => {
pidSetBtn.good("ok", 500)
}).catch((err) => {
console.error(err)
pidSetBtn.bad("err", 1000)
})
// -------------------------------------------------------- PID Values
let pVal = new TextInput(10, 190, 100, 20, '-0.002')
let iVal = new TextInput(10, 220, 100, 20, '0.0')
let dVal = new TextInput(10, 250, 100, 20, '0.0')
let aVal = new TextInput(10, 280, 100, 20, '0.01')
let aDotVal = new TextInput(10, 310, 100, 20, '0.1')
let pidSetBtn = new Button(10, 340, 94, 14, 'set PID / a')
pidSetBtn.onClick(() => {
let p = parseFloat(pVal.value)
let i = parseFloat(iVal.value)
let d = parseFloat(dVal.value)
let a = parseFloat(aVal.value)
let ad = parseFloat(aDotVal.value)
if (Number.isNaN(p) || Number.isNaN(i) || Number.isNaN(d)) {
pidSetBtn.bad("bad parse", 1000)
return
}
vm.setPIDTerms([p, i, d]).then(() => {
return vm.setAlphas([a, ad])
}).then(() => {
pidSetBtn.good("ok", 500)
}).catch((err) => {
console.error(err)
pidSetBtn.bad("err", 1000)
})
})
let tempPlot = new AutoPlot(xPlace + 120, yPlace, 420, 230)
tempPlot.setHoldCount(500)
//tempPlot.setYDomain(0, 100)
tempPlot.redraw()
let effortPlot = new AutoPlot(xPlace + 120, yPlace + 240, 420, 150)
effortPlot.setHoldCount(500)
//effortPlot.setYDomain(-10, 10)
effortPlot.redraw()
let tempLpBtn = new Button(xPlace, yPlace + 90, 104, 14, 'plot temp')
let tempLp = false
let tempLpCount = 0
tempLpBtn.onClick(() => {
if (tempLp) {
tempLp = false
tempLpBtn.good("stopped", 500)
} else {
let poll = () => {
if (!tempLp) return
tvm.getExtruderTemp().then((temp) => {
//console.log(temp)
tempLpCount++
tempPlot.pushPt([tempLpCount, temp])
tempPlot.redraw()
return tvm.getExtruderTempOutput()
}).then((effort) => {
//console.log(effort)
effortPlot.pushPt([tempLpCount, effort])
effortPlot.redraw()
setTimeout(poll, 200)
}).catch((err) => {
tempLp = false
console.error(err)
tempLpBtn.bad("err", 500)
})
}
tempLp = true
poll()
}
let angleRandoBtn = new Button(10, 370, 94, 14, 'targ')
angleRandoBtn.onClick(() => {
let targ = Math.random() * 360
vm.setTarget(targ).then(() => {
angleRandoBtn.good(`${targ.toFixed(3)}`, 250)
}).catch((err) => {
console.error(err)
angleRandoBtn.bad("err", 500)
})
}
//PIDController(240, 10)
})
// -------------------------------------------------------- STARTUP LOCAL
......
......@@ -75,6 +75,18 @@ export default function ClStepVM(osap, route) {
// ------------------------------------------------------ 3: SET POSITION TARGET
let angleTargetEP = osap.endpoint()
angleTargetEP.addRoute(route, TS.endpoint(0, 3), 512)
this.setTarget = (targ) => {
return new Promise((resolve, reject) => {
let datagram = new Uint8Array(4)
TS.write('float32', targ, datagram, 0, true)
angleTargetEP.write(datagram).then(() => {
resolve()
}).catch((err) => { reject(err) })
})
}
// ------------------------------------------------------ 4: POSITION QUERY
let positionQuery = osap.query(route, TS.endpoint(0, 4), 512)
......@@ -105,6 +117,37 @@ export default function ClStepVM(osap, route) {
})
}
// ------------------------------------------------------ 6: SET PID TERMS
let pidEP = osap.endpoint()
pidEP.addRoute(route, TS.endpoint(0, 6), 512)
this.setPIDTerms = (vals) => {
return new Promise((resolve, reject) => {
let datagram = new Uint8Array(12)
TS.write('float32', vals[0], datagram, 0, true)
TS.write('float32', vals[1], datagram, 4, true)
TS.write('float32', vals[2], datagram, 8, true)
pidEP.write(datagram).then(() => {
resolve()
}).catch((err) => { reject(err) })
})
}
// ------------------------------------------------------ 7: SET ALPHA TERMS
let alphaEP = osap.endpoint()
alphaEP.addRoute(route, TS.endpoint(0, 7), 512)
this.setAlphas = (vals) => {
return new Promise((resolve, reject) => {
let datagram = new Uint8Array(8)
TS.write('float32', vals[0], datagram, 0, true)
TS.write('float32', vals[1], datagram, 4, true)
alphaEP.write(datagram).then(() => {
resolve()
}).catch((err) => { reject(err) })
})
}
/*
// ------------------------------------------------------ POS
// ok: we make an 'endpoint' that will transmit moves,
......
......@@ -147,10 +147,25 @@ float Step_CL::get_angle_target(void){
// PIDs
volatile float pTerm = -0.2F;
volatile float dTerm = -0.0F;
volatile float pTerm = -0.004F;
volatile float iTerm = 0.0F;
volatile float dTerm = -0.001F;
volatile float effort = 0.0F;
void Step_CL::set_pid_values(float p, float i, float d){
pTerm = p;
iTerm = i;
dTerm = d;
}
volatile float a_alpha = 0.01F; // trust in measurement
volatile float a_dot_alpha = 0.1F;
void Step_CL::set_alpha_values(float a, float adot){
a_alpha = a;
a_dot_alpha = adot;
}
// the control loop
void Step_CL::run_torque_loop(void){
if(is_calibrating) return;
......@@ -170,10 +185,8 @@ volatile float a_reading = 0.0F;
volatile float last_measurement = 0.0F;
volatile float a_est = 0.0F;
volatile float a_last_est = 0.0F;
volatile float a_alpha = 0.01F; // trust in measurement
volatile float a_dot = 0.0f;
volatile float a_dot_last = 0.0f;
volatile float a_dot_alpha = 0.1F;
volatile float _pa; // phase angle
......
......@@ -36,6 +36,9 @@ class Step_CL {
void set_angle_target(float ta);
float get_angle_target(void);
float get_output_effort(void);
// pid set
void set_pid_values(float p, float i, float d);
void set_alpha_values(float a, float adot);
// read stat
uint16_t get_last_enc_reading(void);
float get_last_pos_reading(void);
......
......@@ -66,6 +66,8 @@ boolean onPositionTargetPut(uint8_t* data, uint16_t len);
Endpoint* positionTargetEP = osap->endpoint(onPositionTargetPut);
boolean onPositionTargetPut(uint8_t* data, uint16_t len){
chunk_float32 tac = { .bytes = { data[0], data[1], data[2], data[3] }};
step_cl->set_angle_target(tac.f);
return true;
}
......@@ -117,6 +119,31 @@ boolean onSpecQuery(void){
return true;
}
// -------------------------------------------------------- 6: PID Settings
boolean onPIDPut(uint8_t* data, uint16_t len){
uint16_t ptr = 0;
chunk_float32 pc = { .bytes = { data[ptr ++], data[ptr ++], data[ptr ++], data[ptr ++] }};
chunk_float32 ic = { .bytes = { data[ptr ++], data[ptr ++], data[ptr ++], data[ptr ++] }};
chunk_float32 dc = { .bytes = { data[ptr ++], data[ptr ++], data[ptr ++], data[ptr ++] }};
step_cl->set_pid_values(pc.f, ic.f, dc.f);
return true;
}
Endpoint* pidEP = osap->endpoint(onPIDPut);
// -------------------------------------------------------- 7: Filter Settings
boolean onAlphaPut(uint8_t* data, uint16_t len){
uint16_t ptr = 0;
chunk_float32 ac = { .bytes = { data[ptr ++], data[ptr ++], data[ptr ++], data[ptr ++] }};
chunk_float32 adc = { .bytes = { data[ptr ++], data[ptr ++], data[ptr ++], data[ptr ++] }};
step_cl->set_alpha_values(ac.f, adc.f);
return true;
}
Endpoint* alphaEP = osap->endpoint(onAlphaPut);
// -------------------------------------------------------- SETUP / RUNTIME
void setup() {
......
......@@ -1275,6 +1275,14 @@ Alright, here's day on PID then... still have some interface to build for PID re
![video](2021-02-15_cl-step-pid-start.mp4)
## 2021 02 16
Alright so I'm back with this, have PID remote-set done, now doing alpha (filtering) terms remote-set, then I'll finish with the position target update, to bump it around randomly for testing.
It occurs to me also that this particular case (motor on desk, nothing else) is extremly un-damped, meaning that the motor is going to be very unstable, irregardless of what I do. I think I might print out a rotary axis for testing, then.
Yeah, tuning will be hard, have the subsystems now though. I am suspicious of the heavy filtering - especially as I think it might be shifting the d-term signal phase to be 180' or so out of phase, making for oscillations. In any case, tomorrow, a serious tuning / pid-mastery-attempt session.
So, next would do:
- PID remote-set
- target-pos remote-set
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment