Skip to content

Commit e7b508f

Browse files
authored
add beambots page (#22)
1 parent f8cacdc commit e7b508f

8 files changed

Lines changed: 465 additions & 70 deletions

File tree

docs/_/js/search-ui.js

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,9 @@
133133
document.head.appendChild(link);
134134
}
135135

136-
function highlightPageTitle (title, terms) {
137-
const positions = getTermPosition(title, terms);
138-
return buildHighlightedText(title, positions, snippetLength)
139-
}
140-
141136
function highlightSectionTitle (sectionTitle, terms) {
142137
if (sectionTitle) {
143-
const text = sectionTitle.text;
138+
const text = sectionTitle.title ?? sectionTitle.text;
144139
const positions = getTermPosition(text, terms);
145140
return buildHighlightedText(text, positions, snippetLength)
146141
}
@@ -156,8 +151,7 @@
156151
return []
157152
}
158153

159-
function highlightText (doc, terms) {
160-
const text = doc.text;
154+
function highlightText (text, terms) {
161155
const positions = getTermPosition(text, terms);
162156
return buildHighlightedText(text, positions, snippetLength)
163157
}
@@ -183,9 +177,12 @@
183177
}
184178
}
185179
return {
186-
pageTitleNodes: highlightPageTitle(doc.title, terms.title || []),
180+
pageTitleNodes: highlightText(doc.title, terms.title || []),
187181
sectionTitleNodes: highlightSectionTitle(sectionTitle, terms.title || []),
188-
pageContentNodes: highlightText(doc, terms.text || []),
182+
pageContentNodes: highlightText(
183+
sectionTitle?.title && sectionTitle.text ? sectionTitle.text : doc.text,
184+
terms.text || []
185+
),
189186
pageKeywordNodes: highlightKeyword(doc, terms.keyword || []),
190187
}
191188
}
@@ -199,12 +196,12 @@
199196
let sectionTitle;
200197
if (ids.length > 1) {
201198
const titleId = ids[1];
202-
sectionTitle = doc.titles.filter(function (item) {
199+
sectionTitle = doc.titles.find(function (item) {
203200
return String(item.id) === titleId
204-
})[0];
201+
});
205202
}
206203
const metadata = item.matchData.metadata;
207-
const highlightingResult = highlightHit(metadata, sectionTitle, doc);
204+
const highlightingResult = highlightHit(metadata, sectionTitle || doc, doc);
208205
const componentVersion = store.componentVersions[`${doc.component}/${doc.version}`];
209206
if (componentVersion !== undefined && currentComponent !== componentVersion) {
210207
const searchResultComponentHeader = document.createElement('div');

docs/advanced/_images/beambots.png

26.8 KB
Loading

docs/advanced/beambots.html

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,235 @@ <h3 class="title"><a href="../index.html">Electrónica, Robótica e IOT con Elix
270270
</aside>
271271
<article class="doc">
272272
<h1 class="page">Beam Bots</h1>
273+
<div id="preamble">
274+
<div class="sectionbody">
275+
<div class="imageblock">
276+
<div class="content">
277+
<img src="_images/beambots.png" alt="beambots">
278+
</div>
279+
</div>
280+
<div class="paragraph">
281+
<p>Beam Bots es un framework de Elixir diseñado para desarrollar aplicaciones robóticas tolerantes a fallos, aprovechando los principios de OTP.</p>
282+
</div>
283+
<div class="paragraph">
284+
<p>Este framework se basa en un lenguaje específico de dominio (DSL) construido mediante el uso de macros. El resultado es un código que se asemeja a una especificación, reflejando directamente la estructura física del robot.</p>
285+
</div>
286+
</div>
287+
</div>
288+
<div class="sect1">
289+
<h2 id="comparación-con-ros2"><a class="anchor" href="#comparación-con-ros2"></a>Comparación con ROS2</h2>
290+
<div class="sectionbody">
291+
<div class="paragraph">
292+
<p>Beam Bots ofrece un enfoque similar a ROS2 para la comunicación y la gestión de tareas, pero utilizando las capacidades nativas del ecosistema BEAM. A continuación, se presenta una comparación de conceptos clave:</p>
293+
</div>
294+
<table class="tableblock frame-all grid-all stretch">
295+
<colgroup>
296+
<col style="width: 33.3333%;">
297+
<col style="width: 66.6667%;">
298+
</colgroup>
299+
<thead>
300+
<tr>
301+
<th class="tableblock halign-left valign-top">Concepto en ROS2</th>
302+
<th class="tableblock halign-left valign-top">Equivalente en Elixir/Beam Bots</th>
303+
</tr>
304+
</thead>
305+
<tbody>
306+
<tr>
307+
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Comunicación publish/subscribe entre nodos</strong></p></td>
308+
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
309+
<p><code>Phoenix.PubSub</code>, <code>Registry</code> para el registro de procesos, y la capacidad inherente de <strong>process messaging</strong> de Erlang/Elixir.</p>
310+
</div></div></td>
311+
</tr>
312+
<tr>
313+
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Servicios para interacciones síncronas de solicitud/respuesta</strong></p></td>
314+
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
315+
<p><code>GenServer.call/3</code> es el mecanismo estándar para realizar llamadas síncronas a un proceso <code>GenServer</code>, emulando un servicio.</p>
316+
</div></div></td>
317+
</tr>
318+
<tr>
319+
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Acciones para tareas de larga duración con retroalimentación de progreso</strong></p></td>
320+
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
321+
<p><code>Task.Supervisor</code> gestionando procesos <code>Task</code> que pueden enviar mensajes de progreso al proceso solicitante.</p>
322+
</div></div></td>
323+
</tr>
324+
<tr>
325+
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Nodos de ciclo de vida para gestionar transiciones de estado de forma explícita</strong></p></td>
326+
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
327+
<p><code>GenServer</code> con transiciones de estado definidas, permitiendo la implementación de máquinas de estado robustas.</p>
328+
</div></div></td>
329+
</tr>
330+
<tr>
331+
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Sistema de parámetros para configuración dinámica en tiempo de ejecución</strong></p></td>
332+
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
333+
<p><code>ETS</code> (Erlang Term Storage) para almacenar y acceder a configuraciones compartidas y modificables en caliente.</p>
334+
</div></div></td>
335+
</tr>
336+
</tbody>
337+
</table>
338+
</div>
339+
</div>
340+
<div class="sect1">
341+
<h2 id="crear-un-proyecto"><a class="anchor" href="#crear-un-proyecto"></a>Crear un proyecto</h2>
342+
<div class="sectionbody">
343+
<div class="paragraph">
344+
<p>Para iniciar un nuevo proyecto con Beam Bots, ejecuta los siguientes comandos:</p>
345+
</div>
346+
<div class="listingblock">
347+
<div class="content">
348+
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">mix igniter.new
349+
mix igniter.install bb</code></pre>
350+
</div>
351+
</div>
352+
<div class="paragraph">
353+
<p>Igniter te guiará durante el proceso de configuración del proyecto, generando los archivos necesarios e instalando las dependencias.</p>
354+
</div>
355+
</div>
356+
</div>
357+
<div class="sect1">
358+
<h2 id="ejemplo-de-robot"><a class="anchor" href="#ejemplo-de-robot"></a>Ejemplo de Robot</h2>
359+
<div class="sectionbody">
360+
<div class="paragraph">
361+
<p>A continuación, se presenta un ejemplo de un brazo robótico simple, implementado utilizando el DSL de Beam Bots:</p>
362+
</div>
363+
<div class="listingblock">
364+
<div class="content">
365+
<pre class="highlightjs highlight"><code class="language-elixir hljs" data-lang="elixir">defmodule MyRobot do
366+
use BB
367+
368+
defmodule MoveCommand do
369+
use BB.Command
370+
371+
alias BB.Robot.State, as: RobotState
372+
373+
@impl BB.Command
374+
def handle_command(goal, context, state) do
375+
positions =
376+
goal
377+
|&gt; Enum.into(%{})
378+
|&gt; Map.take([:shoulder, :elbow])
379+
380+
:ok = RobotState.set_positions(context.robot_state, positions)
381+
382+
new_positions = RobotState.get_all_positions(context.robot_state)
383+
{:stop, :normal, %{state | result: {:ok, new_positions}}}
384+
end
385+
386+
@impl BB.Command
387+
def result(%{result: result}), do: result
388+
end
389+
390+
commands do
391+
command :arm do
392+
handler BB.Command.Arm
393+
allowed_states [:disarmed]
394+
end
395+
396+
command :disarm do
397+
handler BB.Command.Disarm
398+
allowed_states [:idle]
399+
end
400+
401+
command :move do
402+
handler MoveCommand
403+
allowed_states [:idle]
404+
end
405+
end
406+
407+
topology do
408+
link :base do
409+
joint :shoulder do
410+
type :revolute
273411

412+
axis do
413+
end
414+
415+
limit do
416+
effort(~u(50 newton_meter))
417+
velocity(~u(2 radian_per_second))
418+
end
419+
420+
link :upper_arm do
421+
joint :elbow do
422+
type :revolute
423+
424+
axis do
425+
end
426+
427+
limit do
428+
effort(~u(30 newton_meter))
429+
velocity(~u(3 radian_per_second))
430+
end
431+
432+
link :forearm do
433+
end
434+
end
435+
end
436+
end
437+
end
438+
end
439+
end</code></pre>
440+
</div>
441+
</div>
442+
<div class="paragraph">
443+
<p>El módulo <code>MoveCommand</code> define un comando de movimiento para el robot, el cual se registra en el bloque <code>commands</code>. A continuación, se define la topología del robot, compuesta por enlaces y articulaciones. Cada definición de articulación debe incluir un tipo, un eje y sus límites.</p>
444+
</div>
445+
<div class="paragraph">
446+
<p>Para ejecutar la aplicación del robot, se debe integrar en el archivo <code>application.ex</code> de la siguiente manera:</p>
447+
</div>
448+
<div class="listingblock">
449+
<div class="content">
450+
<pre class="highlightjs highlight"><code class="language-elixir hljs" data-lang="elixir">defmodule MyApp.Application do
451+
use Application
452+
453+
@impl true
454+
def start(_type, _args) do
455+
children = [
456+
MyRobot
457+
]
458+
459+
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
460+
Supervisor.start_link(children, opts)
461+
end
462+
end</code></pre>
463+
</div>
464+
</div>
465+
<div class="sect2">
466+
<h3 id="simulación"><a class="anchor" href="#simulación"></a>Simulación</h3>
467+
<div class="paragraph">
468+
<p>La aplicación también puede ser probada en modo simulación. Para ello, se inicia el entorno del proyecto con <code>iex -S mix</code>, y luego se ejecutan los siguientes comandos:</p>
469+
</div>
470+
<div class="listingblock">
471+
<div class="content">
472+
<pre class="highlightjs highlight"><code class="language-elixir hljs" data-lang="elixir"># iniciar proceso de simulación
473+
{:ok, pid} = MyRobot.start_link(simulation: :kinematic)
474+
475+
# armar robot
476+
{:ok, cmd} = MyRobot.arm()
477+
{:ok, :armed, _} = BB.Command.await(cmd)
478+
479+
# ejemplo de comando de movimiento
480+
{:ok, cmd} = MyRobot.move(shoulder: 0.5, elbow: 1.0)
481+
{:ok, positions} = BB.Command.await(cmd)</code></pre>
482+
</div>
483+
</div>
484+
<div class="paragraph">
485+
<p>El último comando muestra las posiciones de las articulaciones del robot, luego de esperar a que el comando de movimiento termine.</p>
486+
</div>
487+
</div>
488+
</div>
489+
</div>
490+
<div class="sect1">
491+
<h2 id="referencias"><a class="anchor" href="#referencias"></a>Referencias</h2>
492+
<div class="sectionbody">
493+
<div class="ulist">
494+
<ul>
495+
<li>
496+
<p><a href="https://hexdocs.pm/bb/readme.html" class="bare">https://hexdocs.pm/bb/readme.html</a></p>
497+
</li>
498+
</ul>
499+
</div>
500+
</div>
501+
</div>
274502
<nav class="pagination">
275503
<span class="prev"><a href="soleil.html">Soleil</a></span>
276504
<span class="next"><a href="grisp.html">GRiSP</a></span>
-32 KB
Binary file not shown.

docs/search-index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)