diff --git a/doc/images/autoexpgain.drawio.svg b/doc/images/autoexpgain.drawio.svg
new file mode 100644
index 000000000..84eb8c87f
--- /dev/null
+++ b/doc/images/autoexpgain.drawio.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="600px" height="374px" viewBox="-0.5 -0.5 600 374" content="&lt;mxfile host=&quot;app.diagrams.net&quot; modified=&quot;2022-05-18T11:34:31.416Z&quot; agent=&quot;5.0 (X11)&quot; etag=&quot;lviUBxbUCX1CSFnUuSq4&quot; version=&quot;18.0.6&quot; type=&quot;device&quot;&gt;&lt;diagram name=&quot;Page-1&quot; id=&quot;58cdce13-f638-feb5-8d6f-7d28b1aa9fa0&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><path d="M 463 62 L 423.03 62 L 389.37 62" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 384.12 62 L 391.12 58.5 L 389.37 62 L 391.12 65.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 64px; margin-left: 424px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">DARK</div></div></div></foreignObject><text x="424" y="68" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">DARK</text></switch></g><path d="M 463 107 L 385.85 261.3" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 383.5 266 L 383.5 258.17 L 385.85 261.3 L 389.76 261.3 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 137px; margin-left: 443px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div>BRIGHT</div><div><font style="font-size: 8px;">overshoot++</font></div></div></div></div></foreignObject><text x="443" y="141" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">BRIGHT...</text></switch></g><path d="M 472.96 46.46 L 473.03 27.03 L 63.03 27.03 L 63 150.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 63 155.88 L 59.5 148.88 L 63 150.63 L 66.5 148.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="463" y="47" width="120" height="60" rx="9" ry="9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 77px; margin-left: 464px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div><font style="font-size: 18px;" face="Lucida Console">STOP</font></div><div><font style="font-size: 18px;" face="Lucida Console">BRIGHTEN</font></div></div></div></div></foreignObject><text x="523" y="81" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">STOP...</text></switch></g><path d="M 123 157 L 123.03 77.03 L 256.63 77" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 261.88 77 L 254.88 80.5 L 256.63 77 L 254.88 73.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 75px; margin-left: 186px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">DARK</div></div></div></foreignObject><text x="186" y="79" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">DARK</text></switch></g><path d="M 123 217 L 123.03 297.03 L 256.63 297" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 261.88 297 L 254.88 300.5 L 256.63 297 L 254.88 293.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 299px; margin-left: 184px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">BRIGHT</div></div></div></foreignObject><text x="184" y="303" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">BRIGHT</text></switch></g><path d="M 63 172 L 23.03 172 L 23.03 202 L 56.63 202" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 61.88 202 L 54.88 205.5 L 56.63 202 L 54.88 198.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 173px; margin-left: 36px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 8px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><font style="font-size: 11px;">GOOD</font></div></div></div></foreignObject><text x="36" y="176" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="8px" text-anchor="middle">GOOD</text></switch></g><rect x="63" y="157" width="120" height="60" rx="9" ry="9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 187px; margin-left: 64px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div><font style="font-size: 18px;" face="Lucida Console">IDLE</font></div></div></div></div></foreignObject><text x="123" y="191" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">IDLE</text></switch></g><path d="M 383 92 L 456.63 92" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 461.88 92 L 454.88 95.5 L 456.63 92 L 454.88 88.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 95px; margin-left: 423px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">GOOD</div></div></div></foreignObject><text x="423" y="99" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">GOOD</text></switch></g><path d="M 323 107 L 313.03 107.03 L 313.03 260.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 313.03 265.88 L 309.53 258.88 L 313.03 260.63 L 316.53 258.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 207px; margin-left: 303px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div>BRIGHT</div><div style="font-size: 8px;">overshoot++</div></div></div></div></foreignObject><text x="303" y="211" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">BRIGHT...</text></switch></g><rect x="263" y="47" width="120" height="60" rx="9" ry="9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 77px; margin-left: 264px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div><font style="font-size: 18px;" face="Lucida Console">BRIGHTEN</font></div></div></div></div></foreignObject><text x="323" y="81" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">BRIGHTEN</text></switch></g><path d="M 493 267 L 493.03 247.03 L 553.03 247.03 L 553.01 260.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 553 265.88 L 549.51 258.88 L 553.01 260.63 L 556.51 258.89 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><path d="M 463 267 L 385.85 112.7" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 383.5 108 L 389.76 112.7 L 385.85 112.7 L 383.5 115.83 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 237px; margin-left: 445px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div>DARK</div><div><font style="font-size: 8px;">overshoot++</font><br /></div></div></div></div></foreignObject><text x="445" y="241" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">DARK...</text></switch></g><path d="M 475 326.46 L 475.03 347.03 L 63.03 347.03 L 63 223.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 63 218.12 L 66.5 225.12 L 63 223.37 L 59.5 225.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 345px; margin-left: 421px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 7px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div style="font-size: 8px;"><font style="font-size: 11px;">GOOD</font></div><div style="font-size: 8px;"><font style="font-size: 8px;">--wait = 0<br /></font></div></div></div></div></foreignObject><text x="421" y="347" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="7px" text-anchor="middle">GOOD...</text></switch></g><path d="M 463 282 L 389.37 282" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 384.12 282 L 391.12 278.5 L 389.37 282 L 391.12 285.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 282px; margin-left: 424px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">BRIGHT</div></div></div></foreignObject><text x="424" y="286" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">BRIGHT</text></switch></g><rect x="463" y="267" width="120" height="60" rx="9" ry="9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 297px; margin-left: 464px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div><font style="font-size: 18px;" face="Lucida Console">STOP</font></div><div><font style="font-size: 18px;" face="Lucida Console">DARKEN</font></div></div></div></div></foreignObject><text x="523" y="301" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">STOP...</text></switch></g><path d="M 383 312 L 456.63 312" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 461.88 312 L 454.88 315.5 L 456.63 312 L 454.88 308.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 312px; margin-left: 423px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">GOOD</div></div></div></foreignObject><text x="423" y="316" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">GOOD</text></switch></g><path d="M 332.24 266.46 L 332.97 113.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 332.99 108.12 L 336.46 115.13 L 332.97 113.37 L 329.46 115.1 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 157px; margin-left: 343px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div>DARK</div><div style="font-size: 8px;">overshoot++<br /></div></div></div></div></foreignObject><text x="343" y="161" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">DARK...</text></switch></g><rect x="263" y="267" width="120" height="60" rx="9" ry="9" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 297px; margin-left: 264px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><div><font style="font-size: 18px;" face="Lucida Console">DARKEN</font></div></div></div></div></foreignObject><text x="323" y="301" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">DARKEN</text></switch></g><path d="M 493 107 L 493.03 127.03 L 553.03 127.03 L 553.01 113.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 553 108.12 L 556.51 115.11 L 553.01 113.37 L 549.51 115.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 128px; margin-left: 524px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 8px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div><font style="font-size: 11px;">GOOD</font></div><div>--wait <font style="font-size: 8px;"><span class="ILfuVd"><span class="hgKElc"><b>≠</b></span></span></font> 0<br /></div></div></div></div></foreignObject><text x="524" y="131" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="8px" text-anchor="middle">GOOD...</text></switch></g><path d="M 263 92 L 243.03 92 L 243.03 127.03 L 293.03 127.03 L 293.01 113.37" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 293 108.12 L 296.51 115.11 L 293.01 113.37 L 289.51 115.12 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 125px; margin-left: 258px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">DARK</div></div></div></foreignObject><text x="258" y="129" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">DARK</text></switch></g><path d="M 263 282 L 243.03 282 L 243.03 247.03 L 293.03 247.03 L 293.01 260.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 293 265.88 L 289.51 258.88 L 293.01 260.63 L 296.51 258.89 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 248px; margin-left: 263px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 11px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">BRIGHT</div></div></div></foreignObject><text x="263" y="252" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="11px" text-anchor="middle">BRIGHT</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 247px; margin-left: 523px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 8px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div><font style="font-size: 11px;">GOOD</font></div><div>--wait <font style="font-size: 8px;"><span class="ILfuVd"><span class="hgKElc"><b>≠</b></span></span></font> 0<br /></div></div></div></div></foreignObject><text x="523" y="250" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="8px" text-anchor="middle">GOOD...</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 27px; margin-left: 413px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "><div style="display: inline-block; font-size: 8px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;"><div><font style="font-size: 11px;">GOOD</font></div><div>--wait <b>=</b> 0<br /></div></div></div></div></foreignObject><text x="413" y="30" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="8px" text-anchor="middle">GOOD...</text></switch></g><rect x="463" y="97" width="120" height="10" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 102px; margin-left: 523px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 7px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">On exit sets wait=MAX_WAIT</div></div></div></foreignObject><text x="523" y="104" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="7px" text-anchor="middle">On exit sets wait=MAX_WAIT</text></switch></g><rect x="463" y="317" width="120" height="10" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 322px; margin-left: 523px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 7px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">On exit sets wait=MAX_WAIT</div></div></div></foreignObject><text x="523" y="324" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="7px" text-anchor="middle">On exit sets wait=MAX_WAIT</text></switch></g><rect x="68" y="207" width="110" height="10" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 212px; margin-left: 123px;"><div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: rgb(0, 0, 0); "><div style="display: inline-block; font-size: 7px; font-family: Lucida Console; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: nowrap;">On enter sets overshoot=0</div></div></div></foreignObject><text x="123" y="214" fill="rgb(0, 0, 0)" font-family="Lucida Console" font-size="7px" text-anchor="middle">On enter sets overshoot=0</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg>
\ No newline at end of file
diff --git a/doc/images/autoexpgain.drawio.svg.license b/doc/images/autoexpgain.drawio.svg.license
new file mode 100644
index 000000000..8704c1f1c
--- /dev/null
+++ b/doc/images/autoexpgain.drawio.svg.license
@@ -0,0 +1,3 @@
+Copyright 2022, Collabora, Ltd.
+
+SPDX-License-Identifier: BSL-1.0
diff --git a/src/xrt/auxiliary/util/u_autoexpgain.c b/src/xrt/auxiliary/util/u_autoexpgain.c
index 359af0f1b..96778f8d8 100644
--- a/src/xrt/auxiliary/util/u_autoexpgain.c
+++ b/src/xrt/auxiliary/util/u_autoexpgain.c
@@ -39,18 +39,48 @@ DEBUG_GET_ONCE_LOG_OPTION(aeg_log, "AEG_LOG", U_LOGGING_WARN)
 
 #define LEVELS 256 //!< Possible pixel intensity values, only 8-bit supported
 #define INITIAL_BRIGHTNESS 0.5
-#define INITIAL_MAX_BRIGHTNESS_STEP 0.05 //!< 0.1 is faster but introduces oscillations more often
+#define INITIAL_MAX_BRIGHTNESS_STEP 0.1
 #define INITIAL_THRESHOLD 0.1
 #define GRID_COLS 40 //!< Amount of columns for the histogram sample grid
 
+//! AEG State machine states
+enum u_aeg_state
+{
+	IDLE,
+	BRIGHTEN,
+	STOP_BRIGHTEN, //!< Avoid oscillations by
+	DARKEN,
+	STOP_DARKEN, //!< Similar to STOP_BRIGHTEN
+};
+
+//! This actions are triggered when the image is too dark, bright or good enough
+enum u_aeg_action
+{
+	GOOD,
+	DARK,
+	BRIGHT,
+};
+
 //! Auto exposure and gain (AEG) adjustment algorithm state.
 struct u_autoexpgain
 {
 	bool enable; //!< Whether to enable auto exposure and gain adjustment
 
+	//! AEG is a finite state machine. @see set_state.
+	enum u_aeg_state state;
+
 	enum u_logging_level log_level;
 
-	//! Algorithm strategy that affects how score and brightness are computed
+	//! Counts how many times we've overshooted in the last brightness change.
+	//! It's then used for exponential backoff of the brightness step.
+	int overshoots;
+
+	//! There are buffer states that wait `frame_delay` frames to ensure we are
+	//! not overshooting. This field counts the remaining frames to wait.
+	//! @see set_state
+	int wait;
+
+	//! The selected strategy affects various targets of the algorithm.
 	enum u_aeg_strategy strategy;
 	struct u_var_combo strategy_combo; //!< UI combo box for selecting `strategy`
 
@@ -70,20 +100,146 @@ struct u_autoexpgain
 	//! images with a good enough `brightness` value.
 	float current_score;
 
-	//! Scores further than `threshold` from zero will trigger a `brightness` update.
+	//! Scores further than `threshold` from the target score will trigger a
+	//! `brightness` update.
 	float threshold;
 
-	uint32_t frame_counter; //!< Number of frames received
-
-	//! Every how many frames should we update `brightness`. Some cameras take a
-	//! couple of frames until the new exposure/gain sets in and a new score can
-	//! be recomputed properly.
-	uint8_t update_every;
+	//! A camera might take a couple of frames until the new exposure/gain sets in
+	//! the image. Knowing how many (this variable) helps in avoiding overshooting
+	//! brightness changes.
+	int frame_delay;
 
 	float exposure; //!< Currently computed exposure value to use
 	float gain;     //!< Currently computed gain value to use
 };
 
+static const char *
+state_to_string(enum u_aeg_state state)
+{
+	if (state == IDLE) {
+		return "IDLE";
+	} else if (state == BRIGHTEN) {
+		return "BRIGHTEN";
+	} else if (state == STOP_BRIGHTEN) {
+		return "STOP_BRIGHTEN";
+	} else if (state == DARKEN) {
+		return "DARKEN";
+	} else if (state == STOP_DARKEN) {
+		return "STOP_DARKEN";
+	} else {
+		AEG_ASSERT_(false);
+	}
+	return NULL;
+}
+
+static const char *
+action_to_string(enum u_aeg_action action)
+{
+	if (action == DARK) {
+		return "DARK";
+	} else if (action == BRIGHT) {
+		return "BRIGHT";
+	} else if (action == GOOD) {
+		return "GOOD";
+	} else {
+		AEG_ASSERT_(false);
+	}
+	return NULL;
+}
+
+/*!
+ * Defines the AEG state machine transitions.
+ * The main idea is that if brightness needs to change then we go from `IDLE` to
+ * `BRIGHTEN`/`DARKEN`. To avoid oscillations we detect overshootings
+ * and exponentially backoff our brightness step. We only reset our `overshoots`
+ * counter after the image have been good for `frame_delay` frames, this delay
+ * is counted during `STOP_DARKEN`/`STOP_BRIGHTEN` states.
+ *
+ * A diagram of the state machine is below:
+ * ![AEG state machine](images/autoexpgain.drawio.svg)
+ */
+static void
+set_state(struct u_autoexpgain *aeg, enum u_aeg_action action)
+{
+	enum u_aeg_state new_state;
+	if (aeg->state == IDLE) {
+		if (action == DARK) {
+			new_state = BRIGHTEN;
+		} else if (action == BRIGHT) {
+			new_state = DARKEN;
+		} else if (action == GOOD) {
+			new_state = IDLE;
+		} else {
+			AEG_ASSERT_(false);
+		}
+	} else if (aeg->state == BRIGHTEN) {
+		if (action == DARK) {
+			new_state = BRIGHTEN;
+		} else if (action == BRIGHT) {
+			aeg->overshoots++;
+			new_state = DARKEN;
+		} else if (action == GOOD) {
+			new_state = STOP_BRIGHTEN;
+		} else {
+			AEG_ASSERT_(false);
+		}
+	} else if (aeg->state == STOP_BRIGHTEN) {
+		if (action == DARK) {
+			new_state = BRIGHTEN;
+		} else if (action == BRIGHT) {
+			aeg->overshoots++;
+			new_state = DARKEN;
+		} else if (action == GOOD) {
+			aeg->wait--;
+			new_state = aeg->wait == 0 ? IDLE : STOP_BRIGHTEN;
+		} else {
+			AEG_ASSERT_(false);
+		}
+
+		if (new_state != STOP_BRIGHTEN) {
+			aeg->wait = aeg->frame_delay;
+		}
+	} else if (aeg->state == DARKEN) {
+		if (action == DARK) {
+			aeg->overshoots++;
+			new_state = BRIGHTEN;
+		} else if (action == BRIGHT) {
+			new_state = DARKEN;
+		} else if (action == GOOD) {
+			new_state = STOP_DARKEN;
+		} else {
+			AEG_ASSERT_(false);
+		}
+	} else if (aeg->state == STOP_DARKEN) {
+		if (action == DARK) {
+			aeg->overshoots++;
+			new_state = BRIGHTEN;
+		} else if (action == BRIGHT) {
+			new_state = DARKEN;
+		} else if (action == GOOD) {
+			aeg->wait--;
+			new_state = aeg->wait == 0 ? IDLE : STOP_DARKEN;
+		} else {
+			AEG_ASSERT_(false);
+		}
+
+		if (new_state != STOP_DARKEN) {
+			aeg->wait = aeg->frame_delay;
+		}
+	} else {
+		AEG_ASSERT_(false);
+	}
+	if (new_state == IDLE) {
+		aeg->overshoots = 0;
+	}
+	aeg->overshoots = CLAMP(aeg->overshoots, 0, 3);
+
+	AEG_TRACE("[%s] ---%s--> [%s] (overshoots=%d, wait=%d)", state_to_string(aeg->state), action_to_string(action),
+	          state_to_string(new_state), aeg->overshoots, aeg->wait);
+
+	aeg->state = new_state;
+}
+
 //! Maps a `brightness` in [0, 1] to a pair of exposure and gain values based on
 //! a piecewise function.
 static void
@@ -227,19 +383,33 @@ update_brightness(struct u_autoexpgain *aeg, struct xrt_frame *xf)
 		return;
 	}
 
-	aeg->frame_counter++;
-	if (aeg->frame_counter % aeg->update_every != 0) {
-		return;
+	float target_score;
+	if (aeg->strategy == U_AEG_STRATEGY_TRACKING) {
+		target_score = -aeg->threshold; // Makes 0 the right bound of our "good enugh" range
+	} else if (aeg->strategy == U_AEG_STRATEGY_DYNAMIC_RANGE) {
+		target_score = 0;
+	} else {
+		AEG_ASSERT(false, "Unexpected strategy=%d", aeg->strategy);
 	}
 
-	bool score_is_high = fabsf(score) > aeg->threshold;
-	if (!score_is_high) {
+	enum u_aeg_action action; // State machine input action
+	if (score > target_score + aeg->threshold) {
+		action = BRIGHT;
+	} else if (score < target_score - aeg->threshold) {
+		action = DARK;
+	} else {
+		action = GOOD;
+	}
+
+	set_state(aeg, action);
+
+	if (aeg->state != BRIGHTEN && aeg->state != DARKEN) {
 		return;
 	}
 
 	float max_step = aeg->max_brightness_step;
-	float step = CLAMP(max_step * score, -max_step, max_step);
-	aeg->brightness.val -= step;
+	float step = max_step * score / powf(2.0f, aeg->overshoots);
+	aeg->brightness.val -= CLAMP(step, -max_step, max_step);
 	aeg->brightness.val = CLAMP(aeg->brightness.val, 0, 1);
 }
 
@@ -250,12 +420,15 @@ update_brightness(struct u_autoexpgain *aeg, struct xrt_frame *xf)
  */
 
 struct u_autoexpgain *
-u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, uint8_t update_every)
+u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, int frame_delay)
 {
 	struct u_autoexpgain *aeg = U_TYPED_CALLOC(struct u_autoexpgain);
 
 	aeg->enable = enabled_from_start;
 	aeg->log_level = debug_get_log_option_aeg_log();
+	aeg->state = IDLE;
+	aeg->wait = frame_delay;
+	aeg->overshoots = 0;
 	aeg->strategy = strategy;
 	aeg->strategy_combo.count = U_AEG_STRATEGY_COUNT;
 	aeg->strategy_combo.options = "Tracking\0Dynamic Range\0\0";
@@ -272,8 +445,7 @@ u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, uint
 	aeg->max_brightness_step = INITIAL_MAX_BRIGHTNESS_STEP;
 
 	aeg->threshold = INITIAL_THRESHOLD;
-	aeg->frame_counter = 0;
-	aeg->update_every = update_every;
+	aeg->frame_delay = frame_delay;
 
 	brightness_to_expgain(aeg, INITIAL_BRIGHTNESS, &aeg->exposure, &aeg->gain);
 
@@ -284,7 +456,7 @@ void
 u_autoexpgain_add_vars(struct u_autoexpgain *aeg, void *root)
 {
 	u_var_add_bool(root, &aeg->enable, "Update brightness automatically");
-	u_var_add_u8(root, &aeg->update_every, "Update every X frames");
+	u_var_add_i32(root, &aeg->frame_delay, "Frame update delay");
 	u_var_add_combo(root, &aeg->strategy_combo, "Strategy");
 	u_var_add_draggable_f32(root, &aeg->brightness, "Brightness");
 	u_var_add_f32(root, &aeg->threshold, "Score threshold");
diff --git a/src/xrt/auxiliary/util/u_autoexpgain.h b/src/xrt/auxiliary/util/u_autoexpgain.h
index 6871a0f1f..bf8373b1e 100644
--- a/src/xrt/auxiliary/util/u_autoexpgain.h
+++ b/src/xrt/auxiliary/util/u_autoexpgain.h
@@ -31,11 +31,11 @@ struct u_autoexpgain;
  *
  * @param strategy What objective is preferred for the algorithm.
  * @param enabled_from_start Update exposure/gain from the start.
- * @param update_every Every how many frames should we update exposure/gain
+ * @param frame_delay About how many frames does it take for exp and gain to settle in.
  * @return struct u_autoexpgain* Created object
  */
 struct u_autoexpgain *
-u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, uint8_t update_every);
+u_autoexpgain_create(enum u_aeg_strategy strategy, bool enabled_from_start, int frame_delay);
 
 //! Setup UI for the AEG algorithm
 void
diff --git a/src/xrt/drivers/wmr/wmr_camera.c b/src/xrt/drivers/wmr/wmr_camera.c
index daa332db2..618c93a45 100644
--- a/src/xrt/drivers/wmr/wmr_camera.c
+++ b/src/xrt/drivers/wmr/wmr_camera.c
@@ -447,8 +447,8 @@ wmr_camera_open(struct xrt_prober_device *dev_holo,
 	}
 
 	bool enable_aeg = debug_get_bool_option_wmr_autoexposure();
-	int aeg_update_every = 3; // WMR takes about three frames until the cmd changes the image
-	cam->aeg = u_autoexpgain_create(U_AEG_STRATEGY_TRACKING, enable_aeg, aeg_update_every);
+	int frame_delay = 3; // WMR takes about three frames until the cmd changes the image
+	cam->aeg = u_autoexpgain_create(U_AEG_STRATEGY_TRACKING, enable_aeg, frame_delay);
 
 	cam->exposure_ui.val = &cam->exposure;
 	cam->exposure_ui.max = WMR_MAX_EXPOSURE;
diff --git a/src/xrt/drivers/wmr/wmr_protocol.h b/src/xrt/drivers/wmr/wmr_protocol.h
index 428d6ec8f..45323d11a 100644
--- a/src/xrt/drivers/wmr/wmr_protocol.h
+++ b/src/xrt/drivers/wmr/wmr_protocol.h
@@ -55,7 +55,7 @@ extern "C" {
 #define STR_TO_U32(s) ((uint32_t)(((s)[0]) | ((s)[1] << 8) | ((s)[2] << 16) | ((s)[3] << 24)))
 #define WMR_MAGIC STR_TO_U32("Dlo+")
 
-#define WMR_MIN_EXPOSURE 120
+#define WMR_MIN_EXPOSURE 60
 #define WMR_MAX_OBSERVED_EXPOSURE 6000
 #define WMR_MAX_EXPOSURE 9000
 #define WMR_MIN_GAIN 16