robossembler.org/docs/slides/2023-ros-meetup/ros-meetup-slides.html

244 lines
91 KiB
HTML
Raw Normal View History

2023-02-19 13:04:59 +03:00
<!DOCTYPE html><html lang="ru-RU"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,height=device-height,initial-scale=1.0"><meta name="apple-mobile-web-app-capable" content="yes"><meta http-equiv="X-UA-Compatible" content="ie=edge"><meta property="og:type" content="website"><meta name="twitter:card" content="summary"><style>@media screen{body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button{-webkit-tap-highlight-color:transparent;-webkit-appearance:none;appearance:none;background-color:initial;border:0;color:inherit;cursor:pointer;font-size:inherit;opacity:.8;outline:none;padding:0;transition:opacity .2s linear}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button:disabled,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button:disabled,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button:disabled,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button:disabled{cursor:not-allowed;opacity:.15!important}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button:hover,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button:hover,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button:hover,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button:hover{opacity:1}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button:hover:active,body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button:hover:active,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button:hover:active,body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button:hover:active{opacity:.6}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button:hover:not(:disabled),body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button:hover:not(:disabled),body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button:hover:not(:disabled),body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-note-container button:hover:not(:disabled){transition:none}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=prev],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=prev],body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button.bespoke-marp-presenter-info-page-prev{background:#0000 url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSI1IiBkPSJNNjggOTAgMjggNTBsNDAtNDAiLz48L3N2Zz4=") no-repeat 50%;background-size:contain;overflow:hidden;text-indent:100%;white-space:nowrap}body[data-bespoke-view=""] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=next],body[data-bespoke-view=next] .bespoke-marp-parent>.bespoke-marp-osc>button[data-bespoke-marp-osc=next],body[data-bespoke-view=presenter] .bespoke-marp-presenter-container .bespoke-marp-presenter-info-container button.bespoke-marp-presenter-info-page-next{background:#0000 url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2
/*!
* Marp / Marpit Uncover theme
*
* @theme uncover
* @author Yuki Hattori
*
* @auto-scaling true
* @size 16:9 1280px 720px
* @size 4:3 960px 720px
*/div#p>svg>foreignObject>section{word-wrap:break-word;--color-background:#fdfcff;--color-background-code:#f2f1f4;--color-background-paginate:rgba(32,34,40,.05);--color-foreground:#202228;--color-highlight:#009dd5;--color-highlight-hover:#087eaa;--color-highlight-heading:#33b1dd;--color-header:rgba(32,34,40,.4);--color-header-shadow:rgba(253,252,255,.8);background:var(--color-background);flex-flow:column nowrap;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;font-size:40px;height:720px;justify-content:center;letter-spacing:3px;line-height:1.4;padding:30px 70px;position:relative;text-align:center;width:1280px;z-index:0}div#p>svg>foreignObject>section{--marpit-root-font-size:40px}div#p>svg>foreignObject>section,div#p>svg>foreignObject>section:after{color:var(--color-foreground);display:flex}div#p>svg>foreignObject>section:after{align-items:flex-end;background:linear-gradient(-45deg,var(--color-background-paginate) 50%,transparent 50%);background-size:cover;font-size:.6em;height:80px;justify-content:flex-end;padding:30px;text-align:right;text-shadow:0 0 5px var(--color-background);width:80px}div#p>svg>foreignObject>section:after{--marpit-root-font-size:.6em}div#p>svg>foreignObject>section:where(:not(.invert)) :is(pre,marp-pre) code.hljs{display:block;overflow-x:auto;padding:1em}div#p>svg>foreignObject>section:where(:not(.invert)) code.hljs{padding:3px 5px}div#p>svg>foreignObject>section:where(:not(.invert)) .hljs{background:#fff;color:#000}div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-addition,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-meta,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-string,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-symbol,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-template-tag,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-template-variable{color:#756bb1}div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-comment,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-quote{color:#636363}div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-bullet,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-link,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-literal,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-number,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-regexp{color:#31a354}div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-deletion,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-variable{color:#88f}div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-built_in,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-doctag,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-keyword,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-name,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-section,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-selector-class,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-selector-id,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-selector-tag,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-strong,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-tag,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-title,div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-type{color:#3182bd}div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-emphasis{font-style:italic}div#p>svg>foreignObject>section:where(:not(.invert)) .hljs-attribute{color:#e6550d}div#p>svg>foreignObject>section:where(.invert){--color-background:#202228;--color-background-code:#2b2d33;--color-background-paginate:hsla(0,0%,100%,.05);--color-foreground:#fff;--color-highlight:#60d0f0;--color-highlight-hover:#88dcf4;--color-highlight-heading:#80d9f3;--color-header:hsla(0,0%,100%,.4);--color-header-shadow:rgba(32,34,40,.8)}div#p>svg>foreignObject>section:where(.invert) :is(pre,marp-pre) code.hljs{display:block;overflow-x:auto;padding:1em}div#p>svg>foreignObject>section:where(.invert)
<h1>Nix/Nixos</h1>
<p>ОС-независимая сборка пакетов ROS</p>
<p>|</p>
<p>Брылёв Игорь<br />
robossembler.org</p>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="2" data-marpit-fragments="5" data-paginate="true" data-theme="uncover" data-marpit-pagination="2" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>Что же такое ROS?</h1>
<ul>
<li data-marpit-fragment="1">Стандарт</li>
<li data-marpit-fragment="2">Фреймворк</li>
<li data-marpit-fragment="3">Набор форматов</li>
<li data-marpit-fragment="4">...</li>
<li data-marpit-fragment="5">Система сборки и дистрибьюции ПО</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="3" data-marpit-fragments="4" data-paginate="true" data-theme="uncover" data-marpit-pagination="3" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h3>Проблемы пакетных менеджеров</h3>
<ul>
<li data-marpit-fragment="1">Апгрейд конфигурации безвозвратно изменяет состояние системы</li>
<li data-marpit-fragment="2">Сборки не детерминированы</li>
<li data-marpit-fragment="3">Не поддерживаются разные версии бинарников и библиотек</li>
<li data-marpit-fragment="4">Конфликты пакетов</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="4" data-marpit-fragments="3" data-paginate="true" data-theme="uncover" data-marpit-pagination="4" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h4>Проблемы управления зависимостями в ROS</h4>
<ul>
<li data-marpit-fragment="1">Зависимость от Ubuntu и её системных зависимостей (apt-пакеты)</li>
<li data-marpit-fragment="2">Сложность интеграции с ПО вне ROS-экосистемы</li>
<li data-marpit-fragment="3">Подготовить для удобного запуска сложный ROS-проект - трудоёмкая задача</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="5" data-marpit-fragments="2" data-paginate="true" data-theme="uncover" data-marpit-pagination="5" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>Тренды</h1>
<ul>
<li data-marpit-fragment="1">Из набора библиотек для одного робота ROS становится стандартом для роботизированных кибер-физических систем</li>
<li data-marpit-fragment="2">В робототехнику проникают инструменты из других ниш: web, машинное обучение, DevOps</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="6" data-paginate="true" data-theme="uncover" data-marpit-pagination="6" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>А как же Docker?</h1>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="7" data-paginate="true" data-theme="uncover" data-marpit-pagination="7" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<p><img src="reproducible-testing.jpg" alt="" /></p>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="8" data-paginate="true" data-theme="uncover" data-marpit-pagination="8" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>&quot;В&quot;</h1>
<p>воспроизводимость</p>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="9" data-paginate="true" data-theme="uncover" data-marpit-pagination="9" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>Теория</h1>
<p>Dockerfile -&gt; Image</p>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="10" data-paginate="true" data-theme="uncover" data-marpit-pagination="10" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>Реальность</h1>
<p>Dockerfile -&gt; Image1 || Image2 ... ImageN</p>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="11" data-paginate="true" data-theme="uncover" data-marpit-pagination="11" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>Типичный Dockerfile для ROS</h1>
<pre is="marp-pre" data-auto-scaling="downscale-only"><code>FROM ros:foxy-ros-base-focal
...
RUN rosdep update &amp;&amp; apt-get update
...
RUN apk add --no-cache python g++ make
...
RUN curl -sSL http://get.gazebosim.org | sh
...
CMD [ &quot;ros2&quot;, &quot;launch&quot;, &quot;app&quot;, &quot;app_bringup.launch.py&quot; ]
</code></pre>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="12" data-paginate="true" data-theme="uncover" data-marpit-pagination="12" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>Ключевая идея nix</h1>
<p>Описывать сборку в виде <em>чистой функции</em> или уравнения(derivation), результат исполнения строго детерминирован входными параметрами.</p>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="13" data-paginate="true" data-theme="uncover" data-marpit-pagination="13" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<p><img src="eelco.jpeg" alt="" /><br />
Eelco Dolstra</p>
<h2>The Purely Functional Software Deployment Model</h2>
<p>PhD Thesis'2006<br />
<a href="https://edolstra.github.io/pubs/phd-thesis.pdf">https://edolstra.github.io/pubs/phd-thesis.pdf</a></p>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="14" data-marpit-fragments="2" data-paginate="true" data-theme="uncover" data-marpit-pagination="14" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>Парадигмы программирования</h1>
<ul>
<li data-marpit-fragment="1">Императивная (как?) - C, C++, Java</li>
<li data-marpit-fragment="2">Декларативная (что?) - Lisp, Prolog, Nix</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="15" data-marpit-fragments="2" data-paginate="true" data-theme="uncover" data-marpit-pagination="15" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>Парадигмы конфигурации</h1>
<ul>
<li data-marpit-fragment="1">Императивная конфигурация (apt)
<ul>
<li>Изменение состояния (dependency hell, неконсистентные состояния)</li>
</ul>
</li>
<li data-marpit-fragment="2">Декларативная конфигурация (nix)
<ul>
<li>Пакеты = иммутабельные переменные (нельзя изменить напрямую, только через функцию)</li>
<li>Одно и то же nix-выражение даёт всегда один и тот же результат</li>
</ul>
</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="16" data-paginate="true" data-theme="uncover" data-marpit-pagination="16" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;"><pre is="marp-pre" data-auto-scaling="downscale-only"><code>{
pname = &quot;hello&quot;;
version = &quot;2.12.1&quot;;
src = fetchurl {
url = &quot;http://github.com/hello-${version}.tar.bz2&quot;;
sha256 = &quot;0x2g1jqy...&quot;;
};
buildInputs = [ libbar perl ncurses ];
buildPhase = ''gcc hello.c -o hello'';
installPhase = ''mkdir -p $out/bin &amp;&amp; cp hello $out/bin'';
}
</code></pre>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="17" data-paginate="true" data-theme="uncover" data-marpit-pagination="17" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<pre is="marp-pre" data-auto-scaling="downscale-only"><code>{
&quot;builder&quot;: &quot;/nix/store/561wgc73s0x1250hrgp7jm22hhv7yfln-bash-5.2-p15/bin/bash&quot;,
&quot;env&quot;: {
&quot;builder&quot;: &quot;/nix/store/561wgc73s0x1250hrgp7jm22hhv7yfln-bash-5.2-p15/bin/bash&quot;,
&quot;out&quot;: &quot;/nix/store/260q5867crm1xjs4khgqpl6vr9kywql1-hello-2.12.1&quot;,
&quot;src&quot;: &quot;/nix/store/pa10z4ngm0g83kx9mssrqzz30s84vq7k-hello-2.12.1.tar.gz&quot;,
&quot;stdenv&quot;: &quot;/nix/store/b09v23lirgvci3wzszh22mbkdfj0h0yq-stdenv-linux&quot;,
&quot;version&quot;: &quot;2.12.1&quot;
},
&quot;inputDrvs&quot;: {
&quot;/nix/store/0hnjp6s8k71xm62157v37zg3qzwvl8lx-bash-5.2-p15.drv&quot;: [ &quot;out&quot; ],
&quot;/nix/store/8n3ib41pb90nkq3vv49z520qinf4q9c0-hello-2.12.1.tar.gz.drv&quot;: [ &quot;out&quot; ],
&quot;/nix/store/r2h029bx2fbyxxj84s5hf1abp2vfkah2-stdenv-linux.drv&quot;: [ &quot;out&quot; ]
},
&quot;inputSrcs&quot;: [ &quot;/nix/store/6xg259477c90a229xwmb53pdfkn6ig3g-default-builder.sh&quot; ],
&quot;outputs&quot;: {
&quot;out&quot;: { &quot;path&quot;: &quot;/nix/store/260q5867crm1xjs4khgqpl6vr9kywql1-hello-2.12.1&quot; }
},
&quot;system&quot;: &quot;x86_64-linux&quot;
}
}
</code></pre>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="18" data-paginate="true" data-theme="uncover" data-marpit-pagination="18" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;"><pre is="marp-pre" data-auto-scaling="downscale-only"><code>$ ls /nix/store/ | grep humble
00z4hg8q0cxhsl5jq4s7iq81zz54j8vy-ros-humble-ament-lint-common-0.12.5-r1
01nvrmwbf0zbchb3d25kb49rl8jzspv6-ros-humble-ament-cmake-cppcheck-0.12.5-r1
02gdrzn2yrngmqih4hq0j17vj2hgiiz3-ros-humble-unique-identifier-msgs-2.2.1-r3
08s5gvg7gaypllyxvzd17w21ijqx3hgd-ros-humble-tf2-msgs-0.25.2-r1
0hwva9zk3250hd6spwq11ayk0aq4flnm-ros-humble-control-msgs-4.1.0-r1
</code></pre>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="19" data-paginate="true" data-theme="uncover" data-marpit-pagination="19" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<p><img src="drv-cryptohash.png" alt="" style="width:900px;" /></p>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="20" data-marpit-fragments="5" data-paginate="true" data-theme="uncover" data-marpit-pagination="20" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>Что это даёт для ROS?</h1>
<ul>
<li data-marpit-fragment="1">Возможность запустить проект ROS на любой ОС, даже без apt</li>
<li data-marpit-fragment="2">Контролируемое управление зависимостями</li>
<li data-marpit-fragment="3">Возможность использования разных версий одних и тех же пакетов и библиотек</li>
<li data-marpit-fragment="4">Детерминированные сборки одной командой</li>
<li data-marpit-fragment="5">CACHE!!!</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="21" data-marpit-fragments="4" data-paginate="true" data-theme="uncover" data-marpit-pagination="21" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>Основные компоненты nix</h1>
<ul>
<li data-marpit-fragment="1">Nix (менеджер пакетов и язык программирования)</li>
<li data-marpit-fragment="2">Nixpkgs (репозиторий пакетов и стандартная библиотека)</li>
<li data-marpit-fragment="3">NixOS (операционная система)</li>
<li data-marpit-fragment="4">NixOps (DevOps инструмент)</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="22" data-paginate="true" data-theme="uncover" data-marpit-pagination="22" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<p><img src="map_repo_size_fresh-2018-06-08.svg" alt="" style="width:1000px;" /></p>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="23" data-paginate="true" data-theme="uncover" data-marpit-pagination="23" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h2>Nix ROS Overlay</h2>
<p><a href="https://github.com/lopsided98/nix-ros-overlay">https://github.com/lopsided98/nix-ros-overlay</a></p>
<p>Автоматическая генерация nix-выражений для сборки пакетов ROS из официальных репозиториев (github:ros/rosdistro).</p>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="24" data-paginate="true" data-theme="uncover" data-marpit-pagination="24" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<pre is="marp-pre" data-auto-scaling="downscale-only"><code>{ lib, buildRosPackage, fetchurl, ament-cmake ... }:
buildRosPackage {
pname = &quot;ros-rolling-std-msgs&quot;;
version = &quot;4.6.1-r1&quot;;
src = fetchurl {
url = &quot;https://github.com/ros2-gbp/common_interfaces/std_msgs/4.6.1-1.tar.gz&quot;;
name = &quot;4.6.1-1.tar.gz&quot;;
sha256 = &quot;87eee895c2c60a8335ae2a63b05f99773f0897e451e5bf7f45a14a6c36295640&quot;;
};
buildType = &quot;ament_cmake&quot;;
buildInputs = [ ament-cmake rosidl-default-generators ];
checkInputs = [ ament-lint-common ];
propagatedBuildInputs = [ builtin-interfaces rosidl-default-runtime ];
nativeBuildInputs = [ ament-cmake rosidl-default-generators ];
meta = {
description = ''A package containing some standard message definitions.'';
license = with lib.licenses; [ asl20 ];
};
}
</code></pre>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="25" data-marpit-fragments="4" data-paginate="true" data-theme="uncover" data-marpit-pagination="25" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>Недостатки</h1>
<ul>
<li data-marpit-fragment="1">Пологая кривая обучения</li>
<li data-marpit-fragment="2">Некоторая разрозненность документации</li>
<li data-marpit-fragment="3">Не все пакеты ROS адаптированы в nix</li>
<li data-marpit-fragment="4">Необходимость сборки мусора</li>
</ul>
</section>
</foreignObject></svg><svg data-marpit-svg="" viewBox="0 0 1280 720"><foreignObject width="1280" height="720"><section id="26" data-paginate="true" data-theme="uncover" data-marpit-pagination="26" data-marpit-pagination-total="26" style="--paginate:true;--theme:uncover;">
<h1>Полезные ресурсы</h1>
<p><img src="nix-snowflake.svg" alt="" style="width:200px;" /><br />
Русскоязычное сообщество Telegram<br />
@ru_nixos</p>
<p>Туториал для новичков<br />
zero-to-nix.com</p>
</section>
<script>!function(){"use strict";const t={h1:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"1"},style:"display: block; font-size: 2em; margin-block-start: 0.67em; margin-block-end: 0.67em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h2:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"2"},style:"display: block; font-size: 1.5em; margin-block-start: 0.83em; margin-block-end: 0.83em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h3:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"3"},style:"display: block; font-size: 1.17em; margin-block-start: 1em; margin-block-end: 1em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h4:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"4"},style:"display: block; margin-block-start: 1.33em; margin-block-end: 1.33em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h5:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"5"},style:"display: block; font-size: 0.83em; margin-block-start: 1.67em; margin-block-end: 1.67em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},h6:{proto:()=>HTMLHeadingElement,attrs:{role:"heading","aria-level":"6"},style:"display: block; font-size: 0.67em; margin-block-start: 2.33em; margin-block-end: 2.33em; margin-inline-start: 0px; margin-inline-end: 0px; font-weight: bold;"},span:{proto:()=>HTMLSpanElement},pre:{proto:()=>HTMLElement,style:"display: block; font-family: monospace; white-space: pre; margin: 1em 0; --marp-auto-scaling-white-space: pre;"}},e="data-marp-auto-scaling-wrapper",i="data-marp-auto-scaling-svg",n="data-marp-auto-scaling-container";class s extends HTMLElement{constructor(){super(),this.svgPreserveAspectRatio="xMinYMid meet";const t=t=>([e])=>{const{width:i,height:n}=e.contentRect;this[t]={width:i,height:n},this.updateSVGRect()};this.attachShadow({mode:"open"}),this.containerObserver=new ResizeObserver(t("containerSize")),this.wrapperObserver=new ResizeObserver(((...e)=>{t("wrapperSize")(...e),this.flushSvgDisplay()}))}static get observedAttributes(){return["data-downscale-only"]}connectedCallback(){var t,s,o,r,a;this.shadowRoot.innerHTML=`\n<style>\n svg[${i}] { display: block; width: 100%; height: auto; vertical-align: top; }\n span[${n}] { display: table; white-space: var(--marp-auto-scaling-white-space, nowrap); width: max-content; }\n</style>\n<div ${e}>\n <svg part="svg" ${i}>\n <foreignObject><span ${n}><slot></slot></span></foreignObject>\n </svg>\n</div>\n `.split(/\n\s*/).join(""),this.wrapper=null!==(t=this.shadowRoot.querySelector(`div[${e}]`))&&void 0!==t?t:void 0;const l=this.svg;this.svg=null!==(o=null===(s=this.wrapper)||void 0===s?void 0:s.querySelector(`svg[${i}]`))&&void 0!==o?o:void 0,this.svg!==l&&(this.svgComputedStyle=this.svg?window.getComputedStyle(this.svg):void 0),this.container=null!==(a=null===(r=this.svg)||void 0===r?void 0:r.querySelector(`span[${n}]`))&&void 0!==a?a:void 0,this.observe()}disconnectedCallback(){this.svg=void 0,this.svgComputedStyle=void 0,this.wrapper=void 0,this.container=void 0,this.observe()}attributeChangedCallback(){this.observe()}flushSvgDisplay(){const{svg:t}=this;t&&(t.style.display="inline",requestAnimationFrame((()=>{t.style.display=""})))}observe(){this.containerObserver.disconnect(),this.wrapperObserver.disconnect(),this.wrapper&&this.wrapperObserver.observe(this.wrapper),this.container&&this.containerObserver.observe(this.container),this.svgComputedStyle&&this.observeSVGStyle(this.svgComputedStyle)}observeSVGStyle(t){const e=()=>{const i=(()=>{const e=t.getPropertyValue("--preserve-aspect-ratio");if(e)return e.trim();return`x${(({textAlign:t,direction:e})=>{if(t.endsWith("left"))return"Min";if(t.endsWith("right"))return"Max";if("start"===t||"end"===t){let i="rtl"===e;return"end"===t&&(i=!i),i?"Max":"Min"}return"Mid"})(t)}YMid meet`})();i!==this.svgPreserveAspectRatio&&(this.svgPreserveAspectRatio=i,this.updateSVGRect()),t===this.svgComputedStyle&&requestAnimationFrame(e)};e()
</script></foreignObject></svg></div><div class="bespoke-marp-note" data-index="0" tabindex="0"><p>Чтобы сгенерировать из этого файла презентацию в pdf, html или pptx, нужно воспользоваться утилитой Marp https://marp.app/ или одноимённым расширением VSCode https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode.</p></div><div class="bespoke-marp-note" data-index="1" tabindex="0"><p>В сообществе часто спорят по поводу того чем является или не является ROS. ROS звучит буквально как операционная система для роботов, однако де-факто операционной системой не является. Как правило, все сходятся на том, что ROS включает в себя много разных сущностей - это и стандарт, и фреймворк, и формат взаимодействия приложений, и непосредственно программное обеспечение - стандартная библиотека, если хотите. Но конкретно в этом докладе я бы хотел поговорить о ROS в немного другом свете - как о системе сборки и дистрибьюции программного обеспечения, что тоже имеет место быть. Причём этот аспект я считаю весьма важным, потому что почти любое ROS-приложение в среднем на 95% состоит из подгруженного из пакетных репозиториев кода, из которых на долю ROS-экосистемы приходится меньшая часть.</p></div><div class="bespoke-marp-note" data-index="2" tabindex="0"><p>Итак метод сборки и дострибьюции пакетов в ROS в значительной опирается на пакетных менеджер apt и пакетные базы debian/ubuntu (по статистике ros index 2100 пакетов представляют собой системные зависимости, предоставляемые операционной системой), а следовательно зависит от них. Многие пакеты ROS-экосистемы представляют в качестве рекомендуемого способа установки именно установку из своих репозиториев собранных заранее бинарных пакетов. Компиляция проектов их исходников редко практикуется и достаточно сложна. В целом, apt свойственны следующие проблемы.</p></div><div class="bespoke-marp-note" data-index="5" tabindex="0"><p>Когда рассказываешь про nix часто у инженеров возникает прочная ассциация с Docker. А не решает ли Docker ту же самую проблему? Да, действительно, эти инструменты решают одну и ту же проблему, которую можно было бы кратко сформулировать так</p></div><div class="bespoke-marp-note" data-index="6" tabindex="0"><p>С проблемой сталкиваются нууууу почти все - от первой линии службы технической поддержки до программистов. Это проблема состояния окружения - если ваша программа или приложение в какой-то степени опирается на него, то неизбежно будут возникать проблемы с его корректной работы на ком<D0BE>
1. hub.docker.com
2. apt-репозиторий
3. rosdep-репозиторий
3. файл, взятый по имени
Но есть другие недостатки:
1. Возможность комбинировать зависимости (docker позволяет создавать контейнеры только наследуя от одного базового - нельзя добавить несколько базовых контейнеров)
2. Необходимость тянуть с собой все зависимости, даже если они представлены в системе</p></div><div class="bespoke-marp-note" data-index="11" tabindex="0"><p># Что предлагает Nix?</p></div><div class="bespoke-marp-note" data-index="12" tabindex="0"><p>Именно эта идея и легла в основу диссертации автора nix под названием ___, где как раз и описывались недостатки классической системы использования динамических библиотек в unix-подобных системах. Данный подход получил название декларативным в противовес императивного.</p></div><div class="bespoke-marp-note" data-index="14" tabindex="0"><p>nix использует функциональный язык программирования для описания процесса сборки. Тут можно сделать некоторое отступление о том, что ROS создан робототехниками для робототехников, а у них по прежнему был и остаётся доминирующим императивный подход к программированию, что обусловлено высокими требованиями к производительности и реальному времени исполнения. Собственно, императивная парадигма распространилась не только на сферу низкоуровневых программ, но и на управление операционной системой. Однако, сфера сборки ПО не требует гарантий реального времени или высокой производительности, в ней куда важнее как раз воспроизводимость, отсутствие неявных обращений к состоянию системы.</p></div><div class="bespoke-marp-note" data-index="15" tabindex="0"><p>как выглядит типичное Nix-выражение. Это уравнение превращается в такой json-образный файл, где и прописаны все версии с хэшами конкретных зависимостей. Этот файл и является по сути инструкцией или чистой функцией, на выходе которой мы получаем конкретные артефакты в виде пакетов, бинарников, динамических библиотек и т.п.</p></div><div class="bespoke-marp-note" data-index="17" tabindex="0"><p>А вот как это выглядит на диске. Заметьте, имя каждого пакета снабжается хэшом, который позволяет избежать коллизий при совпадении имён и даже совпадении имён и версий, а ещё даёт использовать несколько версий библиотеки одновременно. Откуда берётся этот хэш?</p></div><div class="bespoke-marp-note" data-index="18" tabindex="0"><p>Собственно этот хэш и получается с помощью криптографической хэш-функции применённой ко всем входным зависимостям</p></div><div class="bespoke-marp-note" data-index="19" tabindex="0"><p>Вы не полагаетесь на apt, можете при желании собрать систему полностью из исходников.</p></div><div class="bespoke-marp-note" data-index="20" tabindex="0"><p></p></div><div class="bespoke-marp-note" data-index="21" tabindex="0"><p># Текущее состояние nixpkgs</p></div><script>/*!! Lic
!function(){"use strict";const e=document.body,t=(...e)=>history.replaceState(...e),n="presenter",r="next",o=["",n,r],i="bespoke-marp-",a=`data-${i}`,s=(e,{protocol:t,host:n,pathname:r,hash:o}=location)=>{const i=e.toString();return`${t}//${n}${r}${i?"?":""}${i}${o}`},l=()=>e.dataset.bespokeView,d=e=>new URLSearchParams(location.search).get(e),c=(e,n={})=>{var r;const o={location,setter:t,...n},i=new URLSearchParams(o.location.search);for(const t of Object.keys(e)){const n=e[t];"string"==typeof n?i.set(t,n):i.delete(t)}try{o.setter({...null!==(r=window.history.state)&&void 0!==r?r:{}},"",s(i,o.location))}catch(e){console.error(e)}},u=(()=>{const e="bespoke-marp";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(e){return!1}})(),f=e=>{try{return localStorage.getItem(e)}catch(e){return null}},m=(e,t)=>{try{return localStorage.setItem(e,t),!0}catch(e){return!1}},g=e=>{try{return localStorage.removeItem(e),!0}catch(e){return!1}},p=(e,t)=>{const n="aria-hidden";t?e.setAttribute(n,"true"):e.removeAttribute(n)},v=e=>{e.parent.classList.add(`${i}parent`),e.slides.forEach((e=>e.classList.add(`${i}slide`))),e.on("activate",(t=>{const n=`${i}active`,r=t.slide,o=r.classList,a=!o.contains(n);if(e.slides.forEach((e=>{e.classList.remove(n),p(e,!0)})),o.add(n),p(r,!1),a){const e=`${n}-ready`;o.add(e),document.body.clientHeight,o.remove(e)}}))},h=e=>{let t=0,n=0;Object.defineProperty(e,"fragments",{enumerable:!0,value:e.slides.map((e=>[null,...e.querySelectorAll("[data-marpit-fragment]")]))});const r=r=>void 0!==e.fragments[t][n+r],o=(r,o)=>{t=r,n=o,e.fragments.forEach(((e,t)=>{e.forEach(((e,n)=>{if(null==e)return;const i=t<r||t===r&&n<=o;e.setAttribute(`${a}fragment`,(i?"":"in")+"active");const s=`${a}current-fragment`;t===r&&n===o?e.setAttribute(s,"current"):e.removeAttribute(s)}))})),e.fragmentIndex=o;const i={slide:e.slides[r],index:r,fragments:e.fragments[r],fragmentIndex:o};e.fire("fragment",i)};e.on("next",(({fragment:i=!0})=>{if(i){if(r(1))return o(t,n+1),!1;const i=t+1;e.fragments[i]&&o(i,0)}else{const r=e.fragments[t].length;if(n+1<r)return o(t,r-1),!1;const i=e.fragments[t+1];i&&o(t+1,i.length-1)}})),e.on("prev",(({fragment:i=!0})=>{if(r(-1)&&i)return o(t,n-1),!1;const a=t-1;e.fragments[a]&&o(a,e.fragments[a].length-1)})),e.on("slide",(({index:t,fragment:n})=>{let r=0;if(void 0!==n){const o=e.fragments[t];if(o){const{length:e}=o;r=-1===n?e-1:Math.min(Math.max(n,0),e-1)}}o(t,r)})),o(0,0)},y=document,b=()=>!(!y.fullscreenEnabled&&!y.webkitFullscreenEnabled),w=()=>!(!y.fullscreenElement&&!y.webkitFullscreenElement),x=e=>{e.fullscreen=()=>{b()&&(async()=>{return w()?null===(e=y.exitFullscreen||y.webkitExitFullscreen)||void 0===e?void 0:e.call(y):((e=y.body)=>{var t;return null===(t=e.requestFullscreen||e.webkitRequestFullscreen)||void 0===t?void 0:t.call(e)})();var e})()},document.addEventListener("keydown",(t=>{"f"!==t.key&&"F11"!==t.key||t.altKey||t.ctrlKey||t.metaKey||!b()||(e.fullscreen(),t.preventDefault())}))},k=`${i}inactive`,$=(e=2e3)=>({parent:t,fire:n})=>{const r=t.classList,o=e=>n(`marp-${e?"":"in"}active`);let i;const a=()=>{i&&clearTimeout(i),i=setTimeout((()=>{r.add(k),o()}),e),r.contains(k)&&(r.remove(k),o(!0))};for(const e of["mousedown","mousemove","touchend"])document.addEventListener(e,a);setTimeout(a,0)},E=["AUDIO","BUTTON","INPUT","SELECT","TEXTAREA","VIDEO"],L=e=>{e.parent.addEventListener("keydown",(e=>{if(!e.target)return;const t=e.target;(E.includes(t.nodeName)||"true"===t.contentEditable)&&e.stopPropagation()}))},S=e=>{window.addEventListener("load",(()=>{for(const t of e.slides){const e=t.querySelector("marp-auto-scaling, [data-auto-scaling], [data-marp-fitting]");t.setAttribute(`${a}load`,e?"":"hideable")}}))},P=({interval:e=250}={})=>t=>{document.addEventListener("keydown",(e=>{if(" "===e.key&&e.shiftKey)t.prev();else if("ArrowLeft"===e.key||"ArrowUp"===e.key||"PageUp"===e.key)t.prev({fragment:!e.shiftKey});else if(" "!==e.key||e.shiftKey)if("ArrowRight"===e.key||"ArrowDown"===e.key||"PageDown"===e.key)t.next({fragment:!e.shiftKey});else if("End"===e.key)t.slide(t.slides.length-