https://github.com/kuo-lab/simplelocomotionmodel
Tip revision: fc46ca7f88d6f91ec43bb77f0d8809df2eb73ee8 authored by Art Kuo on 14 February 2023, 22:04:04 UTC
extra readme about cloning and downloading
extra readme about cloning and downloading
Tip revision: fc46ca7
uneventerrain.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
<meta charset="utf-8">
<meta name="generator" content="quarto-1.1.251">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>Dynamic optimization of walking on uneven terrain</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { color: #008000; } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { color: #008000; font-weight: bold; } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
div.csl-bib-body { }
div.csl-entry {
clear: both;
}
.hanging div.csl-entry {
margin-left:2em;
text-indent:-2em;
}
div.csl-left-margin {
min-width:2em;
float:left;
}
div.csl-right-inline {
margin-left:2em;
padding-left:1em;
}
div.csl-indent {
margin-left: 2em;
}
</style>
<script src="uneventerrain_files/libs/clipboard/clipboard.min.js"></script>
<script src="uneventerrain_files/libs/quarto-html/quarto.js"></script>
<script src="uneventerrain_files/libs/quarto-html/popper.min.js"></script>
<script src="uneventerrain_files/libs/quarto-html/tippy.umd.min.js"></script>
<script src="uneventerrain_files/libs/quarto-html/anchor.min.js"></script>
<link href="uneventerrain_files/libs/quarto-html/tippy.css" rel="stylesheet">
<link href="uneventerrain_files/libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles">
<script src="uneventerrain_files/libs/bootstrap/bootstrap.min.js"></script>
<link href="uneventerrain_files/libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="uneventerrain_files/libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light">
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script>
</head>
<body class="fullcontent">
<div id="quarto-content" class="page-columns page-rows-contents page-layout-article">
<main class="content" id="quarto-document-content">
<header id="title-block-header" class="quarto-title-block default">
<div class="quarto-title">
<h1 class="title">Dynamic optimization of walking on uneven terrain</h1>
</div>
<div class="quarto-title-meta">
</div>
</header>
<p>A simple walking model is optimized to walk over uneven terrain. The objective is to minimize energy expenditure, quantified by the push-off work performed with each step. The optimization here seeks to traverse a stretch of terrain, starting and ending at level walking, and taking the same amount of time as level walking.</p>
<section id="walk-over-a-single-upward-step" class="level2">
<h2 class="anchored" data-anchor-id="walk-over-a-single-upward-step">Walk over a single upward step</h2>
<p>The optimal compensation for a single upward step is to speed up beforehand, lose speed stepping upward, and then speed up again afterward. The optimal speed-ups both occur over several steps but have different shapes: the first one increases nearly exponentially with time, and the second one resembles a saturating exponential. The optimization is described by Darici et al. <span class="citation" data-cites="darici2020AnticipatoryControlMomentum">(<a href="#ref-darici2020AnticipatoryControlMomentum" role="doc-biblioref">2020</a>)</span>, and tested with human subjects experiment <span class="citation" data-cites="darici2022HumansOptimallyAnticipate">(<a href="#ref-darici2022HumansOptimallyAnticipate" role="doc-biblioref">Darici and Kuo 2022</a>)</span>.</p>
<div class="cell" data-execution_count="1">
<details>
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">using</span> <span class="bu">DynLoco</span>, <span class="bu">Plots; </span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>wstar4s <span class="op">=</span> <span class="fu">findgait</span>(<span class="fu">WalkRW2l</span>(α<span class="op">=</span><span class="fl">0.4102</span>,safety<span class="op">=</span><span class="cn">true</span>), target<span class="op">=:</span>speed<span class="op">=></span><span class="fl">0.4789</span>, varying<span class="op">=:</span>P)</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>nsteps <span class="op">=</span> <span class="fl">15</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>bumpHeightDimless <span class="op">=</span> <span class="fl">0.075</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>B <span class="op">=</span> <span class="fu">asin</span>(bumpHeightDimless <span class="op">/</span> (<span class="fl">2</span><span class="fu">*sin</span>(wstar4s.α)))</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>δs <span class="op">=</span> <span class="fu">zeros</span>(nsteps); δs[<span class="fu">Int</span>((nsteps<span class="op">+</span><span class="fl">1</span>)<span class="op">/</span><span class="fl">2</span>)] <span class="op">=</span> B <span class="co"># one bump</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>upstepresult <span class="op">=</span> <span class="fu">optwalk</span>(wstar4s, nsteps, boundarywork<span class="op">=</span><span class="cn">false</span>, δs<span class="op">=</span>δs)</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>p <span class="op">=</span> <span class="fu">multistepplot</span>(upstepresult, boundarywork<span class="op">=</span><span class="cn">false</span>, legend<span class="op">=</span><span class="cn">false</span>) <span class="co"># plot speed, push-off, terrain heights</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(p)</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>p <span class="op">=</span> <span class="fu">plot</span>(<span class="fu">cumsum</span>(upstepresult.steps.tf), upstepresult.steps.vm,xlabel<span class="op">=</span><span class="st">"time"</span>,ylabel<span class="op">=</span><span class="st">"midstance speed"</span>,legend<span class="op">=</span><span class="cn">false</span>)</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(p)</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="co"># step timings, per step</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="fu">plot</span>(<span class="fu">cumsum</span>(upstepresult.steps.tf),upstepresult.steps.tf, xlabel<span class="op">=</span><span class="st">"time"</span>,ylabel<span class="op">=</span><span class="st">"step time"</span>, legend<span class="op">=</span><span class="cn">false</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output cell-output-display">
<p><img src="uneventerrain_files/figure-html/cell-2-output-1.svg" class="img-fluid"></p>
</div>
<div class="cell-output cell-output-display">
<p><img src="uneventerrain_files/figure-html/cell-2-output-2.svg" class="img-fluid"></p>
</div>
<div class="cell-output cell-output-display" data-execution_count="30">
<p><img src="uneventerrain_files/figure-html/cell-2-output-3.svg" class="img-fluid"></p>
</div>
</div>
<p>The optimization is performed with <code>optwalk</code>, which computes the minimum-work trajectory for <code>nsteps</code> of walking. A terrain may be provided by an array of height/angle changes <code>δs</code>.</p>
<p>All quantities are plotted in dimensionless form, with base units of body mass <span class="math inline">\(M\)</span>, leg length <span class="math inline">\(L\)</span>, and gravitational acceleration <span class="math inline">\(g\)</span>. Thus speed is normalized by <span class="math inline">\(\sqrt(gL)\)</span> and time by <span class="math inline">\(\sqrt(L/g)\)</span>. For a typical leg length of <span class="math inline">\(L = 1\,\mathrm{m}\)</span>, the equivalent dimensional speed is about 1.25 m/s, and step time about 0.55 s.</p>
</section>
<section id="use-varying-step-lengths-to-walk-over-a-single-upward-step" class="level2">
<h2 class="anchored" data-anchor-id="use-varying-step-lengths-to-walk-over-a-single-upward-step">Use varying step lengths to walk over a single upward step</h2>
<p>The model above uses fixed step lengths, whereas humans adjust step length with speed. The model can also be constrained to step at the preferred step length vs speed relationship of human, resulting in a different amplitude of speed fluctuations, but a similarly-shaped speed profile.</p>
<div class="cell" data-execution_count="2">
<details>
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># WalkRW2ls has varying step lengths according to preferred human</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>wstar4ls <span class="op">=</span> <span class="fu">findgait</span>(<span class="fu">WalkRW2ls</span>(α<span class="op">=</span><span class="fl">0.4102</span>,safety<span class="op">=</span><span class="cn">true</span>), target<span class="op">=:</span>speed<span class="op">=></span><span class="fl">0.4789</span>, varying<span class="op">=:</span>P, cstep<span class="op">=</span><span class="fl">0.35</span>, vmstar<span class="op">=</span>wstar4s.vm)</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>varyingresult <span class="op">=</span> <span class="fu">optwalk</span>(wstar4ls, nsteps, boundarywork<span class="op">=</span><span class="cn">false</span>,δs<span class="op">=</span>δs)</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="fu">plotvees</span>(upstepresult,boundaryvels<span class="op">=</span>upstepresult.boundaryvels, speedtype<span class="op">=:</span>midstance)</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="fu">plotvees!</span>(varyingresult,boundaryvels<span class="op">=</span>upstepresult.boundaryvels, speedtype<span class="op">=:</span>midstance)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output cell-output-display" data-execution_count="31">
<p><img src="uneventerrain_files/figure-html/cell-3-output-1.svg" class="img-fluid"></p>
</div>
</div>
</section>
<section id="walk-over-a-bunch-of-terrains" class="level2">
<h2 class="anchored" data-anchor-id="walk-over-a-bunch-of-terrains">Walk over a bunch of terrains</h2>
<p>The terrain is specified as a series of angle/height changes each step. The task is to start and end with nominal level walking, and to traverse the terrain in minimum energy, in the same amount of time as for level walking.</p>
<p>Note that terrain profile is not plotted to scale.</p>
<div class="cell" data-execution_count="3">
<details>
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb3"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">## plot bumps and speed trajectories of all 8 terrains</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>numStepsBefore <span class="op">=</span> <span class="fl">6</span>; numStepsAfter <span class="op">=</span> <span class="fl">6</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="co"># all terrain trajectories</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>wstar4s <span class="op">=</span> <span class="fu">findgait</span>(<span class="fu">WalkRW2l</span>(α<span class="op">=</span><span class="fl">0.4102</span>,safety<span class="op">=</span><span class="cn">true</span>), target<span class="op">=:</span>speed<span class="op">=></span><span class="fl">0.4789</span>, varying<span class="op">=:</span>P)</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>δs <span class="op">=</span> ( <span class="co"># terrain defined a sequence of height or angle changes from previous step</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> <span class="st">"level"</span> <span class="op">=></span>[<span class="fu">zeros</span>(numStepsBefore); [<span class="fl">0</span>] <span class="op">.*</span> B; <span class="fu">zeros</span>(numStepsAfter)], <span class="co"># level </span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> <span class="st">"U"</span> <span class="op">=></span> [<span class="fu">zeros</span>(numStepsBefore); [<span class="fl">1</span>] <span class="op">.*</span> B; <span class="fu">zeros</span>(numStepsAfter)], <span class="co"># Up</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a> <span class="st">"D"</span> <span class="op">=></span> [<span class="fu">zeros</span>(numStepsBefore); [<span class="op">-</span><span class="fl">1</span>] <span class="op">.*</span> B; <span class="fu">zeros</span>(numStepsAfter)], <span class="co"># Down</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a> <span class="st">"UD"</span> <span class="op">=></span> [<span class="fu">zeros</span>(numStepsBefore); [<span class="fl">1</span>, <span class="op">-</span><span class="fl">1</span>] <span class="op">.*</span> B; <span class="fu">zeros</span>(numStepsAfter)], <span class="co"># Up-Down</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a> <span class="st">"DnUD"</span> <span class="op">=></span> [<span class="fu">zeros</span>(numStepsBefore); [<span class="op">-</span><span class="fl">1</span>, <span class="fl">0</span>, <span class="fl">5</span><span class="op">/</span><span class="fl">3</span>, <span class="op">-</span><span class="fl">5</span><span class="op">/</span><span class="fl">3</span>] <span class="op">.*</span> B; <span class="fu">zeros</span>(numStepsAfter)] , <span class="co"># Down & Up-Down</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a> <span class="st">"P"</span> <span class="op">=></span> [<span class="fu">zeros</span>(numStepsBefore); [ <span class="fl">1</span>, <span class="fl">1</span>, <span class="fl">1</span>, <span class="fl">0</span>, <span class="fl">0</span>, <span class="fl">0</span>, <span class="op">-</span><span class="fl">1</span>, <span class="op">-</span><span class="fl">1</span>, <span class="op">-</span><span class="fl">1</span>] <span class="op">.*</span> B; <span class="fu">zeros</span>(numStepsAfter)], <span class="co"># Pyramid</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a> <span class="st">"C1"</span> <span class="op">=></span> [<span class="fu">zeros</span>(numStepsBefore); [ <span class="fl">3</span>, <span class="fl">2</span>, <span class="op">-</span><span class="fl">3</span>, <span class="fl">2</span>, <span class="op">-</span><span class="fl">1</span>, <span class="fl">3</span>, <span class="fl">1</span>, <span class="op">-</span><span class="fl">3</span>, <span class="op">-</span><span class="fl">2</span>, <span class="fl">3</span>, <span class="op">-</span><span class="fl">1</span>, <span class="op">-</span><span class="fl">2</span>, <span class="op">-</span><span class="fl">1</span>, <span class="fl">3</span>, <span class="op">-</span><span class="fl">2</span>, <span class="op">-</span><span class="fl">2</span>] <span class="op">.*</span> B<span class="op">/</span><span class="fl">3</span>; <span class="fu">zeros</span>(numStepsAfter)], <span class="co"># Complex 1</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a> <span class="st">"C2"</span> <span class="op">=></span> [<span class="fu">zeros</span>(numStepsBefore); [ <span class="fl">2</span>, <span class="fl">2</span>, <span class="op">-</span><span class="fl">3</span>, <span class="fl">1</span>, <span class="fl">2</span>, <span class="fl">1</span>, <span class="op">-</span><span class="fl">3</span>, <span class="fl">2</span>, <span class="fl">3</span>, <span class="op">-</span><span class="fl">1</span>, <span class="op">-</span><span class="fl">3</span>, <span class="fl">1</span>, <span class="op">-</span><span class="fl">2</span>, <span class="fl">3</span>, <span class="op">-</span><span class="fl">2</span>, <span class="op">-</span><span class="fl">3</span>] <span class="op">.*</span> B<span class="op">/</span><span class="fl">3</span>; <span class="fu">zeros</span>(numStepsAfter)], <span class="co"># Complex 2</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>)</span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>p <span class="op">=</span> <span class="fu">plot</span>(layout<span class="op">=</span>(<span class="fl">4</span>,<span class="fl">4</span>), legend<span class="op">=</span><span class="cn">false</span>); </span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a><span class="fu">pslotnum</span>(n) <span class="op">=</span> n <span class="op">+</span> (n<span class="op">></span><span class="fl">4</span> ? <span class="fl">4</span> <span class="op">:</span> <span class="fl">0</span>) <span class="co"># plot in slots 1 - 4, 9 - 12</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> (i,(terrainname, terrainbumps)) <span class="kw">in</span> <span class="fu">enumerate</span>(δs)</span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a> <span class="co"># plot the terrain profile in space (not to scale)</span></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a> <span class="fu">plotterrain!</span>(p[<span class="fu">pslotnum</span>(i)], <span class="fu">cumsum</span>(terrainbumps)<span class="op">./</span>B <span class="op">.*</span> bumpHeightDimless, setfirstbumpstep<span class="op">=</span><span class="cn">true</span>,ylims<span class="op">=</span>(<span class="op">-</span><span class="fl">0.1</span>,<span class="fl">0.2</span>),showaxis<span class="op">=</span><span class="cn">false</span>,grid<span class="op">=</span><span class="cn">false</span>)</span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a> <span class="co"># minimum-work strategy for terrain</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a> results <span class="op">=</span> <span class="fu">optwalk</span>(wstar4s, <span class="fu">length</span>(terrainbumps), δs<span class="op">=</span>terrainbumps, boundarywork <span class="op">=</span> <span class="cn">false</span>) <span class="co"># optimizing push-offs (boundarywork=false means start from nominal walking)</span></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a> <span class="fu">plotvees!</span>(p[<span class="fu">pslotnum</span>(i)<span class="op">+</span><span class="fl">4</span>], results, boundaryvels<span class="op">=</span>results.boundaryvels, speedtype<span class="op">=:</span>midstance, setfirstbumpstep<span class="op">=</span><span class="cn">true</span>,title<span class="op">=</span>terrainname, tchange <span class="op">=</span> <span class="fl">0</span>, ylims<span class="op">=</span>(<span class="fl">0.3</span>,<span class="fl">0.575</span>))</span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a> <span class="fu">vline!</span>(p[<span class="fu">pslotnum</span>(i)<span class="op">+</span><span class="fl">4</span>], [<span class="fl">0</span>]) <span class="co"># mark where the first uneven step is</span></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a><span class="cf">end</span></span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(p)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output cell-output-display">
<p><img src="uneventerrain_files/figure-html/cell-4-output-1.svg" class="img-fluid"></p>
</div>
</div>
</section>
<section id="walk-over-a-simple-bump-with-no-compensation" class="level2">
<h2 class="anchored" data-anchor-id="walk-over-a-simple-bump-with-no-compensation">Walk over a simple bump with no compensation</h2>
<p>Model walks with constant push-offs for steady walking, and encounters the up-step without any compensation. As a result of the unexpected upward step, the model loses speed, and with repeated constant push-offs, will eventually regain nominal speed. The number of regaining steps is described by the persistence distance. This model expends the same energy as level walking, but accumulates a time deficit compared to minimum-work compensation. Walking over a bump generally requires more time or more work. More detail is available from <span class="citation" data-cites="darici2020AnticipatoryControlMomentum">Darici, Temeltas, and Kuo (<a href="#ref-darici2020AnticipatoryControlMomentum" role="doc-biblioref">2020</a>)</span>.</p>
<div class="cell" data-execution_count="4">
<details>
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>upstep <span class="op">=</span> δs[<span class="fl">2</span>][<span class="fl">2</span>] <span class="co"># up-step terrain, get the terrain array</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>nsteps <span class="op">=</span> <span class="fu">length</span>(upstep)</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>nocompresult <span class="op">=</span> <span class="fu">multistep</span>(wstar4s, Ps<span class="op">=</span><span class="fu">fill</span>(wstar4s.P,nsteps),δangles<span class="op">=</span>upstep,boundaryvels<span class="op">=</span>(wstar4s.vm,wstar4s.vm))</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="fu">println</span>(<span class="st">"No compensation total work cost = "</span>, nocompresult.totalcost)</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="fu">println</span>(<span class="st">"Min-work compensation total work cost = "</span>, upstepresult.totalcost)</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>p <span class="op">=</span> <span class="fu">multistepplot</span>(nocompresult, legend<span class="op">=</span><span class="cn">false</span>, boundarywork<span class="op">=</span><span class="cn">false</span>)</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(p)</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="fu">plot</span>(<span class="fu">cumsum</span>(upstepresult.steps.tf),label<span class="op">=</span><span class="st">"min work"</span>)</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="fu">plot!</span>(<span class="fu">cumsum</span>(nocompresult.steps.tf), xlabel<span class="op">=</span><span class="st">"step"</span>,ylabel<span class="op">=</span><span class="st">"accumulated time"</span>, label<span class="op">=</span><span class="st">"no compensation"</span>)</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="fu">println</span>(<span class="st">"Final time deficit = "</span>, <span class="fu">-sum</span>(upstepresult.steps.tf)<span class="fu">+sum</span>(nocompresult.steps.tf))</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>No compensation total work cost = 0.4433306466750797
Min-work compensation total work cost = 0.5538343313152624</code></pre>
</div>
<div class="cell-output cell-output-display">
<p><img src="uneventerrain_files/figure-html/cell-5-output-2.svg" class="img-fluid"></p>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Final time deficit = -1.2734506601085016</code></pre>
</div>
</div>
</section>
<section id="walk-over-a-single-bump-with-a-reactive-compensation" class="level2">
<h2 class="anchored" data-anchor-id="walk-over-a-single-bump-with-a-reactive-compensation">Walk over a single bump with a reactive compensation</h2>
<p>Here the model does not anticipate the up-step and loses speed and time upon first contact with it. Thereafter, the model compensates and catches up to the level ground model by looking ahead and adjusting the trajectory of push-offs. This strategy therefore actually anticipates and optimally compensates for all steps other the first uneven one. It is almost impossible to regain time without some knowledge and goal for the terrain ahead. More detail is available from <span class="citation" data-cites="darici2020AnticipatoryControlMomentum">Darici, Temeltas, and Kuo (<a href="#ref-darici2020AnticipatoryControlMomentum" role="doc-biblioref">2020</a>)</span>.</p>
<div class="cell" data-execution_count="5">
<details>
<summary>Code</summary>
<div class="sourceCode cell-code" id="cb7"><pre class="sourceCode julia code-with-copy"><code class="sourceCode julia"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>nbump <span class="op">=</span> <span class="fu">Int</span>(<span class="fu">floor</span>((nsteps<span class="op">+</span><span class="fl">1</span>)<span class="op">/</span><span class="fl">2</span>))</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>reactresults1 <span class="op">=</span> <span class="fu">multistep</span>(wstar4s, Ps<span class="op">=</span><span class="fu">fill</span>(wstar4s.P,nbump),δangles<span class="op">=</span>upstep[<span class="fl">1</span><span class="op">:</span>nbump],boundaryvels<span class="op">=</span>(wstar4s.vm,wstar4s.vm))</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>reactresults2 <span class="op">=</span> <span class="fu">optwalk</span>(wstar4s, <span class="fu">length</span>(upstepresult.steps)<span class="op">-</span>nbump, totaltime <span class="op">=</span> upstepresult.totaltime <span class="op">-</span> reactresults1.totaltime,boundaryvels<span class="op">=</span>(reactresults1.steps[<span class="kw">end</span>].vm,wstar4s.vm), boundarywork<span class="op">=</span>(<span class="cn">false</span>,<span class="cn">false</span>))</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>reactresult <span class="op">=</span> <span class="fu">cat</span>(reactresults1, reactresults2)</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="fu">println</span>(<span class="st">"Reactive contrl total work cost = "</span>, reactresult.totalcost)</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="fu">println</span>(<span class="st">"Up-step min-work control total work cost = "</span>, upstepresult.totalcost)</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>p <span class="op">=</span> <span class="fu">multistepplot</span>(reactresult,boundarywork<span class="op">=</span><span class="cn">false</span>) <span class="co"># plot concatenation of two simulations</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(p)</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>p <span class="op">=</span> <span class="fu">plot</span>(<span class="fu">cumsum</span>(upstepresult.steps.tf),label<span class="op">=</span><span class="st">"up-step min-work"</span>)</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="fu">plot!</span>(p, <span class="fu">cumsum</span>(reactresult.steps.tf), xlabel<span class="op">=</span><span class="st">"step"</span>,ylabel<span class="op">=</span><span class="st">"accumulated time"</span>, label<span class="op">=</span><span class="st">"reactive"</span>)</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a><span class="fu">display</span>(p)</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a><span class="fu">println</span>(<span class="st">"Final time deficit = "</span>, <span class="fu">-sum</span>(upstepresult.steps.tf)<span class="fu">+sum</span>(reactresult.steps.tf))</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</details>
<div class="cell-output cell-output-stdout">
<pre><code>Reactive contrl total work cost = 0.5756333115295249
Up-step min-work control total work cost = 0.5538343313152624</code></pre>
</div>
<div class="cell-output cell-output-display">
<p><img src="uneventerrain_files/figure-html/cell-6-output-2.svg" class="img-fluid"></p>
</div>
<div class="cell-output cell-output-display">
<p><img src="uneventerrain_files/figure-html/cell-6-output-3.svg" class="img-fluid"></p>
</div>
<div class="cell-output cell-output-stdout">
<pre><code>Final time deficit = 2.1316282072803006e-14</code></pre>
</div>
</div>
</section>
<section id="julia-code" class="level1">
<h1>Julia code</h1>
<p>This page is viewable as <a href="uneventerrain.ipynb">Jupyter notebook</a>, <a href="uneventerrain.jl">plain Julia</a> text, or <a href="uneventerrain.html">HTML</a>.</p>
</section>
<section id="matlab-code" class="level1">
<h1>Matlab code</h1>
<p>There is also extensive Matlab code for an earlier implementation of the same model. See <a href="../matlab">Matlab directory</a>. There is very limited documentation of this code.</p>
<section id="experimental-data" class="level2">
<h2 class="anchored" data-anchor-id="experimental-data">Experimental data</h2>
<p>The data from accompanying human subjects experiment are available in a <a href="https://github.com/kuo-lab/uneventerrainexperiment/">separate data and code repository</a>. The code is in Matlab, and the data files are in .mat format, which is compatible with HDF5.</p>
</section>
<section id="references" class="level2">
</section>
</section>
<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" role="doc-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent" role="doc-bibliography">
<div id="ref-darici2022HumansOptimallyAnticipate" class="csl-entry" role="doc-biblioentry">
Darici, Osman, and Arthur D. Kuo. 2022. <span>“Humans Optimally Anticipate and Compensate for an Uneven Step During Walking.”</span> Edited by Lena H Ting. <em>eLife</em> 11 (January): e65402. <a href="https://doi.org/10.7554/eLife.65402">https://doi.org/10.7554/eLife.65402</a>.
</div>
<div id="ref-darici2020AnticipatoryControlMomentum" class="csl-entry" role="doc-biblioentry">
Darici, Osman, Hakan Temeltas, and Arthur D. Kuo. 2020. <span>“Anticipatory Control of Momentum for Bipedal Walking on Uneven Terrain.”</span> <em>Scientific Reports</em> 10 (1): 540. <a href="https://doi.org/10.1038/s41598-019-57156-6">https://doi.org/10.1038/s41598-019-57156-6</a>.
</div>
</div></section></div></main>
<!-- /main column -->
<script id="quarto-html-after-body" type="application/javascript">
window.document.addEventListener("DOMContentLoaded", function (event) {
const toggleBodyColorMode = (bsSheetEl) => {
const mode = bsSheetEl.getAttribute("data-mode");
const bodyEl = window.document.querySelector("body");
if (mode === "dark") {
bodyEl.classList.add("quarto-dark");
bodyEl.classList.remove("quarto-light");
} else {
bodyEl.classList.add("quarto-light");
bodyEl.classList.remove("quarto-dark");
}
}
const toggleBodyColorPrimary = () => {
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
if (bsSheetEl) {
toggleBodyColorMode(bsSheetEl);
}
}
toggleBodyColorPrimary();
const icon = "";
const anchorJS = new window.AnchorJS();
anchorJS.options = {
placement: 'right',
icon: icon
};
anchorJS.add('.anchored');
const clipboard = new window.ClipboardJS('.code-copy-button', {
target: function(trigger) {
return trigger.previousElementSibling;
}
});
clipboard.on('success', function(e) {
// button target
const button = e.trigger;
// don't keep focus
button.blur();
// flash "checked"
button.classList.add('code-copy-button-checked');
var currentTitle = button.getAttribute("title");
button.setAttribute("title", "Copied!");
setTimeout(function() {
button.setAttribute("title", currentTitle);
button.classList.remove('code-copy-button-checked');
}, 1000);
// clear code selection
e.clearSelection();
});
function tippyHover(el, contentFn) {
const config = {
allowHTML: true,
content: contentFn,
maxWidth: 500,
delay: 100,
arrow: false,
appendTo: function(el) {
return el.parentElement;
},
interactive: true,
interactiveBorder: 10,
theme: 'quarto',
placement: 'bottom-start'
};
window.tippy(el, config);
}
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
for (var i=0; i<noterefs.length; i++) {
const ref = noterefs[i];
tippyHover(ref, function() {
// use id or data attribute instead here
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
try { href = new URL(href).hash; } catch {}
const id = href.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
return note.innerHTML;
});
}
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
for (var i=0; i<bibliorefs.length; i++) {
const ref = bibliorefs[i];
const cites = ref.parentNode.getAttribute('data-cites').split(' ');
tippyHover(ref, function() {
var popup = window.document.createElement('div');
cites.forEach(function(cite) {
var citeDiv = window.document.createElement('div');
citeDiv.classList.add('hanging-indent');
citeDiv.classList.add('csl-entry');
var biblioDiv = window.document.getElementById('ref-' + cite);
if (biblioDiv) {
citeDiv.innerHTML = biblioDiv.innerHTML;
}
popup.appendChild(citeDiv);
});
return popup.innerHTML;
});
}
});
</script>
</div> <!-- /content -->
</body></html>