Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RSDK-6164] Mimo pid updates #4290

Merged
merged 27 commits into from
Oct 9, 2024
Merged

[RSDK-6164] Mimo pid updates #4290

merged 27 commits into from
Oct 9, 2024

Conversation

mariapatni
Copy link
Contributor

@mariapatni mariapatni commented Aug 16, 2024

Added Multi Input Output Functionality to the PID Controller Block of the Controls Package.

Tested on hardware that the MIMO code will work with tuning single signals, and unit tests cover the expected behavior for multi signals

ticket: https://viam.atlassian.net/browse/RSDK-6164

@CLAassistant
Copy link

CLAassistant commented Aug 16, 2024

CLA assistant check
All committers have signed the CLA.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@viambot viambot added the safe to test This pull request is marked safe to test from a trusted zone label Aug 16, 2024
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Aug 16, 2024
Copy link
Member

@JohnN193 JohnN193 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heres some thoughts/notes I had for the first half, looking thru the rest of the code now!

control/control_block.go Outdated Show resolved Hide resolved
@@ -20,14 +23,31 @@ func makeSignal(name string, blockType controlBlockType) *Signal {
s.time = make([]int, dimension)
s.name = name
s.blockType = blockType
fmt.Printf("made signal %s\n", s.name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove before merging. running make lint-go should also help catch these

control/pid.go Outdated
if p.useMulti {

// For each PID Set and its respective Tuner Object, Step through an iteration of tuning until done.
for i := 0; i < len(p.PIDSets); i++ {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a comment that this attempts to tune multiple signals simultaneously

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just as an fyi I don't think tuning simultaneously would work for the base. or if you wanted to tune motors and a base? although maybe this change will allow it to do so

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i kinda agree with you. I think I might try changing this to tune signals one at a time

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the code to tune one signal at a time. the tests are alittle weird with this change(have to turn off tuning after we reach the "end" of the test) but otherwise i think this should work the way we want

control/pid.go Outdated Show resolved Hide resolved
control/pid.go Outdated Show resolved Hide resolved
control/pid.go Outdated
if p.useMulti {

for i := 0; i < len(p.PIDSets); i++ {
output := calculateSignalValue(p, x, dt, i)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this function be used for the single input case?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not going to expand this for the single input case. will hold off on making large changes to the single input case

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eventually I think yes and just index 0 any time it's single input. but that does seem like a problem for a future PR

control/pid.go Outdated Show resolved Hide resolved
Copy link
Member

@JohnN193 JohnN193 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few other notes. wondering if we should add a constructor funciton or anything to PIDConfig since we added a new function to it.

Also just noticed the change in setup_control, so if ya want to test this on hardware then we can

control/pid.go Outdated
Comment on lines 217 to 243
var ssrVal float64
if p.cfg.Attribute["tune_ssr_value"] != nil {
ssrVal = p.cfg.Attribute["tune_ssr_value"].(float64)
}

tuneMethod := tuneMethodZiegerNicholsPID
if p.cfg.Attribute.Has("tune_method") {
tuneMethod = tuneCalcMethod(p.cfg.Attribute["tune_method"].(string))
}
tuneStepPct := 0.35
if p.cfg.Attribute.Has("tune_step_pct") {
tuneStepPct = p.cfg.Attribute["tune_step_pct"].(float64)
}

p.tuner = pidTuner{
limUp: p.limUp,
limLo: p.limLo,
ssRValue: ssrVal,
tuneMethod: tuneMethod,
stepPct: tuneStepPct,
}
err := p.tuner.reset()
if err != nil {
return err
tuneMethod := tuneMethodZiegerNicholsPID
if p.cfg.Attribute.Has("tune_method") {
tuneMethod = tuneCalcMethod(p.cfg.Attribute["tune_method"].(string))
}

// Create a Tuner object for our PID set. Across all Tuner objects, they share global
// values (limUp, limLo, ssR, tuneMethod, stepPct). The only values that differ are P,I,D.
p.tuners[i] = &pidTuner{
limUp: p.limUp,
limLo: p.limLo,
ssRValue: ssrVal,
tuneMethod: tuneMethod,
stepPct: tuneStepPct,
kP: p.PIDSets[i].P,
kI: p.PIDSets[i].I,
kD: p.PIDSets[i].D,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be worth making a helper function for this code? since both the mimo and single input/output code use it. no is an okay answer since we eventually only want one code path

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leaving this code as is, as we will eventually remove the single input/output path once MIMO is ready

control/pid_test.go Show resolved Hide resolved
control/setup_control.go Outdated Show resolved Hide resolved
control/setup_control.go Show resolved Hide resolved
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Aug 20, 2024
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Aug 20, 2024
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Aug 20, 2024
control/pid.go Outdated
Comment on lines 45 to 50
func (p *basicPID) GetTuning() bool {
return p.tuning
// using locks so we do not check for tuning mid reconfigure or mid tune
p.mu.Lock()
defer p.mu.Unlock()
return p.getTuning()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be able to remove the locks from this. I added them because I was worried a reconfigure was breaking some logic, but i also don't hate keeping it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can leave it if it's not causing issues. better to be safe

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay thinking about this more, if we are locking here and then waiting one level up because of the locking, maybe we can safely get rid of both? if not it's definitely fine but something to maybe try? because the motor is always rebuild so it seems less important to lock in case of reconfigure issues but that might be a bad opinion. we can discuss it further but if you feel strongly towards keeping both, fine by me

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thinking about it more I want to keep the locks. since both the PID block and whoever is using Get/MonitorTuning are trying to access the same variables at the same, we need the lock to prevent race conditions.

@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Aug 20, 2024
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Aug 20, 2024
break
// 100 Hz is probably faster than we need, but we needed at least a small delay because
// GetTuning will lock the PID block
if utils.SelectContextOrWait(ctx, 10*time.Millisecond) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can try to remove these if ya want. Was worried that calling GetTuning was affecting things at the time when I added this.

Copy link
Contributor

@martha-johnston martha-johnston Sep 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is fine and probably safer. happy with leaving it.

control/pid.go Outdated
for i := 0; i < len(p.PIDSets); i++ {
if p.PIDSets[i].NeedsAutoTuning() {
var ssrVal float64
if p.cfg.Attribute["tune_ssr_value"] != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so in this case all pid's in a MIMO block need to use the same values? (excluding P, I, and D). otherwise how would it know which "tune_ssr_value" to use?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jk I see it in a comment below

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional nit to move that comment from line 254 to line ~239, but nbd

// PID block specific values
// these are integral sum and signalErr for the pid signal
int float64
signalErr float64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what are these used for in setup?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they are not used in setup, they are used within the PID loop. we made them private members so implementers will not try to use them

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah my bad I thought this was part of the PIDLoop struct so I was confused what their purpose was but this makes more sense

Copy link
Contributor

@martha-johnston martha-johnston left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left a couple minor questions and comments, but lgtm! excited to have this!

@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Oct 3, 2024
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Oct 3, 2024
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Oct 3, 2024
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Oct 3, 2024
@JohnN193
Copy link
Member

JohnN193 commented Oct 3, 2024

code is updated to use the MIMO configuration for the PID block everywhere!

@martha-johnston
Copy link
Contributor

still lgtm but I do have one test question. can you check the case that you tune your pid and then you try and move it without copying the values? make sure that error looks right and doesn't move the motors and everything. for 1 and for multiple signals? (if that's supported right now)

@JohnN193
Copy link
Member

JohnN193 commented Oct 4, 2024

yeah i tested on app. the errors look good and you can copy/paste them directly into the config. the doCommand looks a lil weird but its obvious what to modify (need to remove backslashes on the quotes")

@martha-johnston
Copy link
Contributor

Yeah I couldn’t figure out how to get rid of those ticks when it was a string. Fine with leaving for now, I think external users are probably less likely to use DoCommand rather than just see the error and copy from there.

@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Oct 9, 2024
@viambot viambot added safe to test This pull request is marked safe to test from a trusted zone and removed safe to test This pull request is marked safe to test from a trusted zone labels Oct 9, 2024
@JohnN193 JohnN193 changed the title Mimo pid updates [RSDK-6164] Mimo pid updates Oct 9, 2024
@@ -352,11 +352,25 @@ func (sb *sensorBase) determineHeadingFunc(ctx context.Context,
// if loop is tuning, return an error
// if loop has been tuned but the values haven't been added to the config, error with tuned values.
func (sb *sensorBase) checkTuningStatus() error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function is now effectively the same for both controlled motor and sensorbase, but going to wait until the refactor ticket to turn them into one function in case there are any other optimizations we can find wrt determining if tuning was completed. @martha-johnston

@@ -352,11 +352,25 @@ func (sb *sensorBase) determineHeadingFunc(ctx context.Context,
// if loop is tuning, return an error
// if loop has been tuned but the values haven't been added to the config, error with tuned values.
func (sb *sensorBase) checkTuningStatus() error {
if sb.loop != nil && sb.loop.GetTuning(context.Background()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turns out the loop is always nil at this point because we do not set the loop until tuning completes.

@JohnN193 JohnN193 merged commit fd3f342 into main Oct 9, 2024
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
safe to test This pull request is marked safe to test from a trusted zone
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants