<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://alvvalencia.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://alvvalencia.github.io/" rel="alternate" type="text/html" /><updated>2026-07-07T13:15:44+00:00</updated><id>https://alvvalencia.github.io/feed.xml</id><title type="html">Álvaro Valencia</title><subtitle>Portfolio and engineering log of Álvaro Valencia — Robotics Software Engineer at Auryn Robotics, Robotics Software Engineering graduate from URJC. SLAM, navigation, localization and embedded systems with ROS 2, Gazebo, C++ and Python.</subtitle><author><name>Álvaro Valencia Maiquez</name></author><entry><title type="html">P6 — Visual Localization</title><link href="https://alvvalencia.github.io/service-robotics/2025/12/22/P6-Visual-Localization.html" rel="alternate" type="text/html" title="P6 — Visual Localization" /><published>2025-12-22T09:00:00+00:00</published><updated>2025-12-22T09:00:00+00:00</updated><id>https://alvvalencia.github.io/service-robotics/2025/12/22/P6-Visual-Localization</id><content type="html" xml:base="https://alvvalencia.github.io/service-robotics/2025/12/22/P6-Visual-Localization.html"><![CDATA[<h1 id="visual-localization-and-navigation-using-apriltags"><strong>Visual Localization and Navigation Using AprilTags</strong></h1>

<p>This project implements a <strong>vision-based localization and navigation system</strong> for a mobile robot using <strong>AprilTags</strong> as known references.<br />
The robot continuously detects visual markers, estimates its global pose from the camera, and autonomously navigates towards them while avoiding frontal obstacles.</p>

<p>The system combines camera geometry, pose estimation, reactive control, and landmark-based localization, <strong>without relying on odometry or mapping</strong>.</p>

<div style="text-align: center;">
    <img src="/assets/images/PNP.png" alt="Visual Marker Example" />
</div>

<h2 id="general-strategy"><strong>General Strategy</strong></h2>

<p>The robot follows a main loop that integrates:</p>

<ul>
  <li>AprilTag detection using the onboard camera</li>
  <li>Absolute pose estimation using known tag positions</li>
  <li>Reactive obstacle avoidance using laser data</li>
  <li>Navigation directed toward detected tags</li>
  <li>Memory of visited landmarks</li>
</ul>

<p>If no valid visual references are available, the robot performs a controlled rotation to recover localization.</p>

<h2 id="apriltag-map"><strong>AprilTag Map</strong></h2>

<p>Tag positions are defined <strong>a priori</strong> in a YAML file, each with:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">(x, y, z)</code> position</li>
  <li><code class="language-plaintext highlighter-rouge">yaw</code> orientation</li>
</ul>

<p>These data are transformed into <strong>4x4 homogeneous matrices</strong>, allowing direct transformations between the tag frame, the camera, and the world, establishing a <strong>global reference system</strong>.</p>

<h2 id="camera-model-and-tag-geometry"><strong>Camera Model and Tag Geometry</strong></h2>

<p>The camera is modeled as a <strong>pinhole projection</strong>:</p>

<ul>
  <li>Square focal length proportional to the image width</li>
  <li>Principal point at the center</li>
  <li>No lens distortion</li>
</ul>

<p>Each tag is defined as a square with known dimensions and its four local 3D points are stored, allowing pose estimation from a single image.</p>

<h2 id="visual-pose-estimation"><strong>Visual Pose Estimation</strong></h2>

<p>For each detected tag:</p>

<ol>
  <li>Extract the corners from the image</li>
  <li>Apply <code class="language-plaintext highlighter-rouge">solvePnP</code> to obtain the <strong>camera→tag</strong> transformation</li>
  <li>Invert it to get <strong>tag→camera</strong></li>
  <li>Select the nearest tag to reduce noise</li>
  <li>Compute the chain of transformations to the world</li>
</ol>

<p>From this, we obtain:</p>

<ul>
  <li>Global pose <code class="language-plaintext highlighter-rouge">(x, y)</code></li>
  <li><code class="language-plaintext highlighter-rouge">yaw</code> orientation of the camera’s forward axis</li>
</ul>

<p>This provides an <strong>absolute pose estimate</strong>, independent of prior state.</p>

<h2 id="reference-frame-alignment"><strong>Reference Frame Alignment</strong></h2>

<p>Fixed rotations are applied to align:</p>

<ul>
  <li>Camera forward direction</li>
  <li>Horizontal world plane</li>
  <li>Extracted yaw angle</li>
</ul>

<p>This ensures a consistent geometric interpretation of position and orientation.</p>

<h2 id="reactive-obstacle-avoidance"><strong>Reactive Obstacle Avoidance</strong></h2>

<p>The frontal sector is continuously monitored with the laser:</p>

<ul>
  <li>If a nearby obstacle is detected</li>
  <li>And no tags are visible</li>
</ul>

<p>The robot stops linear motion and rotates in place. The rotation direction depends on the obstacle location, enabling safe exploration while searching for visual references.</p>

<h2 id="landmark-selection"><strong>Landmark Selection</strong></h2>

<p>To avoid oscillations:</p>

<ul>
  <li>Detected tags are filtered using a memory of visited ones</li>
  <li>Unvisited tags are prioritized</li>
  <li>When approaching a tag, it is marked as visited</li>
  <li>After each visit, the rotation direction can be reversed to improve coverage</li>
</ul>

<h2 id="motion-control"><strong>Motion Control</strong></h2>

<p>A proportional controller is used toward the selected tag:</p>

<ul>
  <li>Linear velocity proportional to distance</li>
  <li>Angular velocity proportional to orientation error</li>
  <li>Commands are saturated to ensure smooth motion</li>
</ul>

<p>If no valid pose estimate exists, the robot adopts cautious movement or a recovery rotation.</p>

<h2 id="pose-propagation"><strong>Pose Propagation</strong></h2>

<p>When no visual update is available, the estimated pose is propagated using differential kinematics.<br />
Angular velocity is scaled to compensate for actuator mismatches, improving temporal consistency.</p>

<h2 id="videos"><strong>Videos</strong></h2>

<p><strong>Non-Inverter</strong></p>
<div style="display: flex; justify-content: center;">
  <iframe width="700" height="394" src="https://www.youtube.com/embed/jmLAXsD6uHo" frameborder="0" allowfullscreen=""></iframe>
</div>

<p><strong>Inverter</strong></p>
<div style="display: flex; justify-content: center;">
  <iframe width="700" height="394" src="https://www.youtube.com/embed/8IMoRLsYa5M" frameborder="0" allowfullscreen=""></iframe>
</div>

<h2 id="conclusion"><strong>Conclusion</strong></h2>

<p>This project demonstrates a complete landmark-based visual localization system:</p>

<ul>
  <li>Absolute pose estimation from tags</li>
  <li>Robust recovery from reference loss</li>
  <li>Reactive obstacle avoidance</li>
  <li>Simple and effective navigation</li>
  <li>Lightweight, modular, and suitable for indoor environments with visual markers</li>
</ul>]]></content><author><name>Álvaro Valencia Maiquez</name></author><category term="service-robotics" /><summary type="html"><![CDATA[Visual Localization and Navigation Using AprilTags]]></summary></entry><entry><title type="html">P5 — Autonomous Mapping (SLAM)</title><link href="https://alvvalencia.github.io/service-robotics/2025/12/08/P5-SLAM.html" rel="alternate" type="text/html" title="P5 — Autonomous Mapping (SLAM)" /><published>2025-12-08T09:00:00+00:00</published><updated>2025-12-08T09:00:00+00:00</updated><id>https://alvvalencia.github.io/service-robotics/2025/12/08/P5-SLAM</id><content type="html" xml:base="https://alvvalencia.github.io/service-robotics/2025/12/08/P5-SLAM.html"><![CDATA[<h1 id="autonomous-mapping"><strong>Autonomous Mapping</strong></h1>

<p>This work presents the design of an autonomous robot capable of <strong>exploring an unknown environment</strong>, continuously building a navigable map, and moving toward newly discovered targets using <strong>Breadth-First Search (BFS)</strong>. The system integrates laser perception, dynamic map construction, reactive navigation, and automatic collision avoidance.</p>

<p>The goal is to achieve fully independent behavior where the robot identifies traversable areas, evaluates safety, generates local goals, and travels to them while actively avoiding nearby obstacles.</p>

<h2 id="general-goal"><strong>General Goal</strong></h2>

<p>The robot operates without predefined waypoints or prior maps.<br />
Its mission is to:</p>

<ul>
  <li><strong>Explore the environment while mapping obstacles in real time.</strong></li>
  <li><strong>Identify safe regions distant from the robot and navigate toward them.</strong></li>
  <li><strong>Avoid collisions and redirect its route when obstacles are detected.</strong></li>
  <li><strong>Update the map and goal positions throughout the process.</strong></li>
</ul>

<p>This enables free exploration and progressive expansion of the mapped environment with no supervision.</p>

<h2 id="map-generation"><strong>Map Generation</strong></h2>

<p>The map is represented as an intensity grid:</p>

<table>
  <thead>
    <tr>
      <th>Value</th>
      <th>Meaning</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">0</code></td>
      <td>obstacle detected</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">&gt;0</code></td>
      <td>free space, brighter = more frequently observed</td>
    </tr>
  </tbody>
</table>

<p>The laser sensor reconstructs the environment through a full angular sweep:</p>

<ol>
  <li>Each ray advances in discrete steps, increasing intensity on free cells.</li>
  <li>If an obstacle is detected, that cell is penalized by lowering intensity.</li>
  <li>The map is <strong>updated only when the robot has moved sufficiently</strong> from its last recorded position, avoiding unnecessary recalculation of already explored areas.</li>
  <li>The map is published to <strong>WebGUI</strong> as a <em>user map</em> viewable in real time.</li>
</ol>

<p>The result is a continuous map where frequently observed areas appear brighter, and collision zones appear darker. The intensity updates use a <strong>logistic model</strong> to prevent saturation and allow gradual reinforcement of free space.</p>

<h2 id="intelligent-goal-selection"><strong>Intelligent Goal Selection</strong></h2>

<p>The navigation engine runs a <strong>radial BFS</strong> from the robot’s current position.<br />
It searches for a cell that meets:</p>

<p>✔ safe minimum distance from the robot<br />
✔ free region surrounding the target area<br />
✔ unobstructed path from origin to goal</p>

<p>BFS returns two coordinates:</p>

<ul>
  <li>a <strong>mid target</strong> for smoother trajectory</li>
  <li>a <strong>final target</strong> that optimally expands the exploration frontier</li>
</ul>

<p>The robot moves toward the mid target first, then proceeds to the final target, gradually increasing the mapped region.</p>

<h2 id="motion-control"><strong>Motion Control</strong></h2>

<p>Movement relies on reactive orientation:</p>

<ul>
  <li>The relative angle between robot and target is computed.</li>
  <li>If the angular error is high → rotation only.</li>
  <li>If alignment is achieved → forward velocity is applied.</li>
</ul>

<p>When half the route is completed, the goal automatically switches to the final target.<br />
If the target area becomes unsafe, it is discarded and BFS selects a new one.</p>

<h2 id="active-obstacle-avoidance"><strong>Active Obstacle Avoidance</strong></h2>

<p>A front-safety module ensures collision prevention:</p>

<p>If the laser detects a close obstacle within a narrow angular window, navigation is suspended and avoidance mode starts:</p>

<table>
  <thead>
    <tr>
      <th>Stage</th>
      <th>Action</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>phase 1 ~ rotation</td>
      <td>in-place turn to open space</td>
    </tr>
    <tr>
      <td>phase 2 ~ short forward motion</td>
      <td>lateral escape from obstacle</td>
    </tr>
    <tr>
      <td>phase 3</td>
      <td>return to navigation mode</td>
    </tr>
  </tbody>
</table>

<p>This sequence improves stability and provides fast reactions in confined areas. The duration of each phase is <strong>parametrizable</strong> to adapt to different environments.</p>

<h2 id="visualization"><strong>Visualization</strong></h2>

<p>The interface displays:</p>

<ul>
  <li>the full map updated live</li>
  <li>robot and targets highlighted as markers</li>
  <li>exploration trail and processed goal points</li>
</ul>

<p>This makes it easy to monitor exploration and understand how BFS drives spatial expansion.</p>

<h2 id="video"><strong>Video</strong></h2>

<p><strong>SLAM INTENSITY</strong></p>
<div style="display: flex; justify-content: center;">
  <iframe width="700" height="394" src="https://www.youtube.com/embed/9s7i0ycGTtQ" frameborder="0" allowfullscreen=""></iframe>
</div>

<p><strong>SLAM PROBABILISTIC INTENSITY</strong></p>
<div style="display: flex; justify-content: center;">
  <iframe width="700" height="394" src="https://www.youtube.com/embed/rzXXaRrLl6I" frameborder="0" allowfullscreen=""></iframe>
</div>

<h2 id="conclusion"><strong>Conclusion</strong></h2>

<p>This robot establishes a robust foundation for autonomous exploration and surveillance in unknown environments.<br />
Its achieved capabilities include:</p>

<ul>
  <li>incremental laser-based mapping with continuous reconstruction</li>
  <li>autonomous BFS-based target generation</li>
  <li>reactive motion driven by angular error</li>
  <li>immediate avoidance of close obstacles</li>
</ul>

<p>The system is independent of prior maps or predefined routes, making it light, scalable, and suitable for real-world exploration and search applications.</p>]]></content><author><name>Álvaro Valencia Maiquez</name></author><category term="service-robotics" /><summary type="html"><![CDATA[Autonomous Mapping]]></summary></entry><entry><title type="html">P4 — Autonomous Loading Robot</title><link href="https://alvvalencia.github.io/service-robotics/2025/11/22/P4-Autonomous-loading-robot.html" rel="alternate" type="text/html" title="P4 — Autonomous Loading Robot" /><published>2025-11-22T09:00:00+00:00</published><updated>2025-11-22T09:00:00+00:00</updated><id>https://alvvalencia.github.io/service-robotics/2025/11/22/P4-Autonomous-loading-robot</id><content type="html" xml:base="https://alvvalencia.github.io/service-robotics/2025/11/22/P4-Autonomous-loading-robot.html"><![CDATA[<h1 id="autonomous-loading-robot-in-warehouse-simulation"><strong>Autonomous Loading Robot in Warehouse Simulation</strong></h1>

<p>This project presents the development of an <strong>autonomous robot system</strong> capable of navigating a warehouse environment, transporting shelves, and placing them in designated locations. The main goal is to combine path planning, precise motion control, and state-based task execution to achieve fully autonomous loading operations.</p>

<p>The system is designed to handle shelves of different sizes, avoid collisions, and interact with a simulated warehouse map to update the occupancy grid in real time.</p>

<h2 id="general-strategy"><strong>General Strategy</strong></h2>

<p>The architecture integrates several modules:</p>

<ul>
  <li><strong>Occupancy Map Handling</strong>: Processing warehouse maps, inflating obstacles, and adapting images for path planning.</li>
  <li><strong>Path Planning</strong>: Generating collision-free trajectories using the <strong>OMPL Reeds-Shepp planner</strong>, supporting forward and backward motion and minimum turning radius constraints.</li>
  <li><strong>Control and Navigation</strong>: Ackermann-style velocity and steering control to follow planned paths with precision.</li>
  <li><strong>Shelf Manipulation</strong>: Lifting and depositing shelves using virtual actuators, updating the occupancy map accordingly.</li>
  <li><strong>State Management</strong>: A finite state machine (FSM) coordinates planning, moving, elevating, dropping, and waiting stages.</li>
</ul>

<h2 id="occupancy-map-processing"><strong>Occupancy Map Processing</strong></h2>

<p>The robot relies on a map image of the warehouse. Several transformations are applied:</p>

<ol>
  <li><strong>Map Inflation</strong>: Obstacles are expanded by the robot radius to ensure safe navigation, if it’s necessary.</li>
  <li><strong>Numpy Adaptation</strong>: The map is converted to numerical arrays for easy computation, where free space and obstacles are encoded with distinct intensity values.</li>
  <li><strong>Coordinate Transformations</strong>: Functions convert between <strong>world coordinates</strong> and <strong>map pixels</strong>, enabling accurate collision checks and path visualization.</li>
</ol>

<h2 id="path-planning-with-ompl"><strong>Path Planning with OMPL</strong></h2>

<p>Collision-free paths are planned using <strong>Reeds-Shepp curves</strong>:</p>

<ul>
  <li><strong>State Validity</strong>: Each state is checked for collision by evaluating the robot’s footprint or the shelf’s footprint if carrying a load.</li>
  <li><strong>Planner Setup</strong>: The robot space is bounded to the warehouse dimensions. Start and goal positions include x, y, and yaw coordinates.</li>
  <li><strong>Planner Execution</strong>: <code class="language-plaintext highlighter-rouge">RRT*</code> searches for an optimal path, interpolated for smooth execution.</li>
  <li><strong>Path Visualization</strong>: Planned paths are drawn on the map using lines and points, providing real-time feedback of trajectories.</li>
</ul>

<h2 id="control-and-motion"><strong>Control and Motion</strong></h2>

<p>While moving along the path:</p>

<ul>
  <li>The robot computes the distance and angular error to the next waypoint.</li>
  <li>Linear and angular velocities are adjusted using proportional control to reduce positional and heading errors.</li>
  <li>Special alignment maneuvers are executed when approaching shelves to ensure precise pickup.</li>
  <li>Motion parameters are adapted depending on whether the robot is carrying a shelf or not.</li>
</ul>

<h2 id="shelf-manipulation"><strong>Shelf Manipulation</strong></h2>

<p>The robot performs two main operations with shelves:</p>

<ol>
  <li>
    <p><strong>Elevate (Pickup)</strong>:<br />
When the robot reaches a shelf position, it lifts the shelf using <code class="language-plaintext highlighter-rouge">HAL.lift()</code>, temporarily removes it from the occupancy map, and marks it as carried.</p>
  </li>
  <li>
    <p><strong>Drop (Deposit)</strong>:<br />
Upon reaching the target position, the shelf is placed using <code class="language-plaintext highlighter-rouge">HAL.putdown()</code>, and the occupancy map is updated to reflect the shelf’s new location.</p>
  </li>
</ol>

<p>A waiting time ensures the elevator mechanism completes its movement before resuming planning.</p>

<h2 id="finite-state-machine"><strong>Finite State Machine</strong></h2>

<p>The robot’s behavior is coordinated by the following states:</p>

<ol>
  <li>
    <p><strong>PLANNING</strong><br />
Computes a new path to the current goal using the updated occupancy map.</p>
  </li>
  <li>
    <p><strong>MOVE</strong><br />
Follows the planned trajectory while correcting speed and heading, including special alignment for pickup points.</p>
  </li>
  <li>
    <p><strong>ELEVATE</strong><br />
Lifts the shelf from the floor and updates the map.</p>
  </li>
  <li>
    <p><strong>DROP_IT</strong><br />
Deposits the shelf at the target location, updating the occupancy map.</p>
  </li>
  <li>
    <p><strong>ELAVATOR</strong><br />
Waits for the lifting or dropping operation to finish before proceeding.</p>
  </li>
  <li>
    <p><strong>FINISHED</strong><br />
Indicates completion of all assigned transport tasks.</p>
  </li>
</ol>

<p>The FSM ensures robust sequencing of actions and allows the robot to autonomously cycle between multiple pickup and drop locations.</p>

<div style="text-align: center;">
    <img src="/assets/images/Warehouse.png" alt="Autonomous loading robot path visualization" />
</div>

<h2 id="visualization-and-supervision"><strong>Visualization and Supervision</strong></h2>

<p>The WebGUI interface shows:</p>

<ul>
  <li>The current occupancy map with obstacles and shelves.</li>
  <li>Planned paths with waypoints and traveled trajectories.</li>
  <li>Updates in real time as shelves are moved, providing intuitive supervision of the robot’s operations.</li>
</ul>

<h2 id="videos"><strong>Videos</strong></h2>

<p><strong>Holonomic Robot</strong></p>
<div style="display: flex; justify-content: center;">
  <iframe width="700" height="394" src="https://www.youtube.com/embed/THtjO0i5f7k" frameborder="0" allowfullscreen=""></iframe>
</div>

<p><strong>Ackermann Robot</strong></p>
<div style="display: flex; justify-content: center;">
  <iframe width="700" height="394" src="https://www.youtube.com/embed/gq3E_x_AsTk" frameborder="0" allowfullscreen=""></iframe>
</div>

<h2 id="conclusions"><strong>Conclusions</strong></h2>

<p>The autonomous loading robot demonstrates effective integration of path planning, motion control, and task sequencing in a warehouse scenario.</p>

<p>Key achievements include:</p>

<ul>
  <li>Collision-free navigation in dynamic warehouse maps.</li>
  <li>Autonomous pickup and deposition of shelves with precise positioning.</li>
  <li>Real-time visualization of paths and occupancy updates.</li>
  <li>Modular FSM design, making it easy to extend or modify tasks.</li>
</ul>

<p>This system forms a foundation for future autonomous logistics solutions, capable of handling multiple transport goals with minimal supervision.</p>]]></content><author><name>Álvaro Valencia Maiquez</name></author><category term="service-robotics" /><summary type="html"><![CDATA[Autonomous Loading Robot in Warehouse Simulation]]></summary></entry><entry><title type="html">P3 — Autonomous Parking</title><link href="https://alvvalencia.github.io/service-robotics/2025/11/07/P3-Autonomous-Parking.html" rel="alternate" type="text/html" title="P3 — Autonomous Parking" /><published>2025-11-07T09:00:00+00:00</published><updated>2025-11-07T09:00:00+00:00</updated><id>https://alvvalencia.github.io/service-robotics/2025/11/07/P3-Autonomous-Parking</id><content type="html" xml:base="https://alvvalencia.github.io/service-robotics/2025/11/07/P3-Autonomous-Parking.html"><![CDATA[<h1 id="autonomous-parking-controller"><strong>Autonomous Parking Controller</strong></h1>

<p>This project describes the implementation of a complete autonomous parking system applied to ground mobile robots. The main goal is to enable the robot to move through the environment, detect a free parking spot on its right side, align with it, and perform a full automatic parking maneuver with no human intervention.</p>

<p>The overall architecture combines laser–based perception, continuous reactive control over orientation, and a state machine responsible for selecting the correct behavior in each stage of the maneuver.</p>

<h2 id="general-strategy"><strong>General Strategy</strong></h2>

<p>The system continuously reads data from the front, right, and rear laser sensors.<br />
From these scans it performs:</p>

<ul>
  <li>Lateral correction and heading stabilization</li>
  <li>Detection of available free space on the right side</li>
  <li>Classification of lateral blocking context</li>
  <li>State transitions based on geometric patterns</li>
</ul>

<p>Control is executed by publishing linear and angular velocities through HAL.</p>

<h2 id="sensor-processing"><strong>Sensor Processing</strong></h2>

<p>Laser readings are filtered, infinite values are removed, and only valid useful ranges close to the robot are considered.<br />
This allows conversion of raw scan data into relevant information such as:</p>

<ul>
  <li>Real lateral distance to obstacles</li>
  <li>Frontal/rear proximity</li>
  <li>Angular minimum patterns for geometric reasoning</li>
</ul>

<h2 id="lateral-stabilization"><strong>Lateral Stabilization</strong></h2>

<p>While searching for a spot, the robot keeps a stable lateral distance to the side.<br />
This is done by combining front, back and center-right differences to maintain a parallel trajectory relative to the street.</p>

<h2 id="environment-classification"><strong>Environment Classification</strong></h2>

<p>Once the system detects a potential parking space on the <strong>right</strong> side of the robot, it analyzes the lateral context to determine which variant of parking maneuver should be executed.</p>

<p>The classification determines if on the right side there are vehicles:</p>

<ul>
  <li>In front of the parking gap</li>
  <li>Behind the parking gap</li>
  <li>On both sides of the parking gap</li>
</ul>

<p>This allows the controller to choose the correct parking sequence variant, adapting steering direction and geometry to the scenario.</p>

<h2 id="gap-detection-with-trigonometry"><strong>Gap Detection with Trigonometry</strong></h2>

<p>To verify if the parking gap is truly usable, the system checks whether a rectangle equivalent to the parking dimensions (<code class="language-plaintext highlighter-rouge">PARKING_SIZE</code>) could physically fit inside that space.</p>

<p>Using the lateral distance measured by the right laser, the controller calculates the angular region that represents the potential volume of the parking slot. Through trigonometric relations, the diagonal of that rectangle is obtained, representing the maximum spatial ray that should remain unobstructed. Si todas las lecturas dentro de ese rango angular son mayores que esta diagonal, significa que el robot puede entrar sin colisión.</p>

<p>Una vez que esta condición se cumple, el hueco se valida y se pasa a la fase de alineación.</p>

<div style="text-align: center;">
    <img src="/assets/images/gap_trig.png" alt="Texto alternativo" />
</div>

<h2 id="state-machine"><strong>State Machine</strong></h2>

<p>The full maneuver is structured as:</p>

<ol>
  <li>
    <p><strong>SEARCHING</strong><br />
Drives forward while maintaining lateral regulation until a valid spot is found.</p>
  </li>
  <li>
    <p><strong>MOVE_CARS</strong><br />
Waits stable before starting alignment to allow external vehicle motion or scenario stabilization.</p>
  </li>
  <li>
    <p><strong>ALIGN</strong><br />
Initial alignment before starting the backup turn.</p>
  </li>
  <li>
    <p><strong>F_PARKING</strong><br />
First steering movement into the parking gap.</p>
  </li>
  <li>
    <p><strong>S_PARKING</strong><br />
Inverse steering correction finishing the “S” shape.</p>
  </li>
  <li>
    <p><strong>S_ALIGN</strong><br />
Final alignment phase inside the parking spot.</p>
  </li>
  <li>
    <p><strong>FINISHED</strong><br />
Parking completed.</p>
  </li>
</ol>

<p>All transitions depend exclusively on laser perception, no mapping, global navigation, or localization is required.</p>

<div style="text-align: center;">
    <img src="/assets/images/Auto_park.png" alt="Texto alternativo" />
</div>

<h2 id="test"><strong>Test</strong></h2>

<p>The system also supports evaluation without depending on real scenario detection.<br />
Through the internal variable <code class="language-plaintext highlighter-rouge">test_env_</code> you can force manually which lateral scenario the robot believes it is in.</p>

<p>This allows testing each branch of the maneuver logic without needing to physically move cars inside the simulator:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">[1,0]</code> simulates a vehicle in front of the parking right side</li>
  <li><code class="language-plaintext highlighter-rouge">[0,1]</code> simulates a vehicle behind</li>
  <li><code class="language-plaintext highlighter-rouge">[1,1]</code> simulates vehicles both in front and behind the spot</li>
</ul>

<p>This significantly accelerates functional testing and allows tuning before executing tests with realistic or more complex worlds.</p>

<h2 id="video"><strong>Video</strong></h2>

<p><strong>Both cars</strong></p>
<div style="display: flex; justify-content: center;">
  <video width="700" controls="">
    <source src="/assets/videos/auto_park.mp4" type="video/webm" />
    Your browser does not support WebM format.
  </video>
</div>

<p><strong>Front car</strong></p>
<div style="display: flex; justify-content: center;">
  <video width="700" controls="">
    <source src="/assets/videos/auto_park_1front.mp4" type="video/webm" />
    Your browser does not support WebM format.
  </video>
</div>

<p><strong>Back car</strong></p>
<div style="display: flex; justify-content: center;">
  <video width="700" controls="">
    <source src="/assets/videos/auto_park_1back.mp4" type="video/webm" />
    Your browser does not support WebM format.
  </video>
</div>

<h2 id="conclusion"><strong>Conclusion</strong></h2>

<p>This autonomous parking controller provides a practical and self–contained solution for parking in mobile robots.<br />
Its reactive perception-driven architecture and state machine design enable robust behavior without complex planning systems.</p>

<p>Its lightweight structure is ideal for AGV applications, experimental urban robotics, and industrial autonomous navigation research.</p>]]></content><author><name>Álvaro Valencia Maiquez</name></author><category term="service-robotics" /><summary type="html"><![CDATA[Autonomous Parking Controller]]></summary></entry><entry><title type="html">P2 — Rescue Drone</title><link href="https://alvvalencia.github.io/service-robotics/2025/10/23/P2-Rescue-drone.html" rel="alternate" type="text/html" title="P2 — Rescue Drone" /><published>2025-10-23T09:00:00+00:00</published><updated>2025-10-23T09:00:00+00:00</updated><id>https://alvvalencia.github.io/service-robotics/2025/10/23/P2-Rescue-drone</id><content type="html" xml:base="https://alvvalencia.github.io/service-robotics/2025/10/23/P2-Rescue-drone.html"><![CDATA[<h1 id="autonomous-search-and-rescue-drone"><strong>Autonomous Search and Rescue Drone</strong></h1>

<p>This project presents the implementation of an <strong>autonomous search and rescue system</strong> for a drone, designed to explore a defined area, locate people through computer vision, and automatically return to its base upon mission completion or under critical conditions.</p>

<p>The main objective is to ensure systematic and efficient exploration of the environment by combining geometric planning, flight control, and visual detection through image processing.</p>

<h2 id="general-strategy"><strong>General Strategy</strong></h2>

<p>The system integrates several coordinated modules:</p>

<ul>
  <li><strong>Path Planning</strong>: Generation of a square sweep trajectory over the search area.</li>
  <li><strong>Autonomous Flight Control</strong>: Waypoint tracking with position and orientation control.</li>
  <li><strong>Computer Vision</strong>: Human face detection using a cascade classifier.</li>
  <li><strong>State Management</strong>: Automatic transition between takeoff, exploration, return, and landing phases.</li>
  <li><strong>Temporal Supervision</strong>: Automatic return to the base point when the battery is depleted.</li>
</ul>

<h2 id="sweep-planning"><strong>Sweep Planning</strong></h2>

<p>The search area is structured as a square defined by an initial coordinate, centered at the origin, and a lateral size.<br />
The drone generates a set of evenly spaced waypoints covering the entire surface, alternating the exploration direction between rows to optimize the path and avoid unnecessary displacements.</p>

<p>The flight pattern ensures complete coverage with a constant altitude and an orientation angle calculated toward each new target. Each point is considered reached when the distance to the drone falls below a defined tolerance threshold.</p>

<h2 id="geographical-conversion"><strong>Geographical Conversion</strong></h2>

<p>The coordinates of key points, such as the base ship position and the rescue zone, are defined in <strong>degrees, minutes, and seconds (DMS)</strong> format and converted into <strong>UTM</strong> distances, which are then transformed into Cartesian coordinates.<br />
This conversion allows precise calculation of distances and directions using spherical trigonometry, taking the Earth’s radius as the reference.</p>

<h2 id="system-states"><strong>System States</strong></h2>

<p>The drone operates sequentially according to a defined set of states:</p>

<ol>
  <li>
    <p><strong>TAKEOFF</strong><br />
The drone takes off to a predefined operating altitude. Depending on the recharge status or if an interruption has been triggered, it proceeds to planning or resumes the search.</p>
  </li>
  <li>
    <p><strong>PLANIFICATE</strong><br />
The position of the rescue area is calculated from geographic coordinates, and the square exploration pattern is generated.</p>
  </li>
  <li>
    <p><strong>SEARCH_IT</strong><br />
The drone follows the planned trajectory. During flight, it analyzes images from its downward-facing camera to identify potential people using a face detection model.<br />
Image rotations and HSV color-space filtering are applied to reduce false positives and improve robustness against lighting variations.</p>
  </li>
  <li>
    <p><strong>RETURN</strong><br />
Once the search is complete or the battery signal is triggered, the drone automatically returns to the base point, adjusting its orientation and flight path accordingly.</p>
  </li>
  <li>
    <p><strong>LAND</strong><br />
The drone initiates a controlled landing procedure. After verifying its position and maintaining stability for a minimum duration, the final landing is executed.</p>
  </li>
  <li>
    <p><strong>DONE</strong><br />
The mission concludes when the number of detected people reaches the predefined target or when the flight cycle is completed.</p>
  </li>
</ol>

<div style="text-align: center;">
    <img src="/assets/images/Drone.drawio.png" alt="Texto alternativo" />
</div>

<h2 id="person-detection"><strong>Person Detection</strong></h2>

<p>Human identification is performed using a Haar Cascade classifier trained for face detection.<br />
During the search, the drone analyzes multiple image orientations to increase detection probability from different angles.<br />
Each detection is validated against previously registered positions to avoid duplicates in nearby areas.</p>

<p>Detected positions are stored in an internal list associating the drone’s spatial coordinates with the locations where faces were identified.</p>

<h2 id="interruption-management-and-automatic-return"><strong>Interruption Management and Automatic Return</strong></h2>

<p>The system includes a safety timer that limits mission duration to simulate battery depletion.<br />
If the set time is exceeded or a critical event is detected, an interruption is triggered to force a transition to the return state.<br />
This mechanism ensures the drone preserves enough battery to complete a safe landing.</p>

<h2 id="visualization-and-supervision"><strong>Visualization and Supervision</strong></h2>

<p>During execution, the downward and front cameras are displayed in real time through the WebGUI interface, allowing monitoring of both navigation and human detection.<br />
This visual system facilitates algorithm validation, drone behavior verification, and spatial coverage analysis.</p>

<h2 id="video"><strong>Video</strong></h2>

<div style="display: flex; justify-content: center;">
  <video width="700" controls="">
    <source src="/assets/videos/Drone_rescue_perfect.mp4" type="video/webm" />
    Your browser does not support WebM format.
  </video>
</div>

<h2 id="conclusions"><strong>Conclusions</strong></h2>

<p>The search and rescue drone combines autonomous planning, flight control, computer vision, and real-time supervision to conduct exploration missions in bounded environments.<br />
Its state-based architecture enhances system extensibility, allowing new conditions or sensors to be integrated without altering the main structure.</p>

<p>The integration of strategies such as sweep planning, automatic return, and multicriteria face detection forms a solid foundation for future applications in autonomous rescue and surveillance missions.</p>]]></content><author><name>Álvaro Valencia Maiquez</name></author><category term="service-robotics" /><summary type="html"><![CDATA[Autonomous Search and Rescue Drone]]></summary></entry><entry><title type="html">P1 — Autonomous Vacuum Cleaner</title><link href="https://alvvalencia.github.io/service-robotics/2025/10/12/P1-Autonomous-vacuum-cleaner.html" rel="alternate" type="text/html" title="P1 — Autonomous Vacuum Cleaner" /><published>2025-10-12T09:00:00+00:00</published><updated>2025-10-12T09:00:00+00:00</updated><id>https://alvvalencia.github.io/service-robotics/2025/10/12/P1-Autonomous-vacuum-cleaner</id><content type="html" xml:base="https://alvvalencia.github.io/service-robotics/2025/10/12/P1-Autonomous-vacuum-cleaner.html"><![CDATA[<h1 id="autonomous-navigation-for-a-vacuum-robot"><strong>Autonomous Navigation for a Vacuum Robot</strong></h1>

<p>In this blog, I present the implementation of a <strong>Grid-Based Planning &amp; Navigation Algorithm</strong> for a vacuum robot. This system allows the robot to explore and clean an area efficiently, avoiding obstacles and optimizing surface coverage.</p>

<div style="text-align: center;">
    <img src="/assets/images/cleaner_img.png" alt="Grid-based planning" />
</div>

<h2 id="strategy"><strong>Strategy</strong></h2>

<p>The algorithm combines several techniques:</p>

<ul>
  <li><strong>Obstacle Inflation 🚧</strong>: Increases the perceived size of obstacles to ensure the robot does not collide.</li>
  <li><strong>Grid Creation</strong>: The map is divided into cells classified by their state (free, occupied, obstacle, critical, or return).</li>
  <li><strong>Grid-Based Planning</strong>: A movement plan is generated from the starting cell to cover all accessible areas.</li>
  <li><strong>Robot Control</strong>: A proportional controller adjusts linear and angular velocity to follow the plan smoothly.</li>
  <li><strong>Initial Direction Selection</strong>: Based on laser data, the robot decides its initial orientation toward the area with the most free space.</li>
</ul>

<h2 id="map-preparation"><strong>Map Preparation</strong></h2>

<p><strong>1. Obstacle Inflation</strong><br />
The <strong>map is inflated</strong> to increase obstacle size considering the robot’s radius, ensuring it does not get too close to walls or furniture.</p>

<p><strong>2. NumPy Conversion</strong><br />
The map is converted into a <strong>NumPy array</strong> for easier processing, representing free and occupied cells with discrete values.</p>

<p><strong>3. Grid Creation</strong><br />
The grid divides the map into cells roughly the size of the robot’s diameter. Each cell is classified as:</p>

<ul>
  <li><strong>FREE</strong>: Accessible cell.</li>
  <li><strong>OBSTACLE</strong>: Cell occupied by an obstacle.</li>
  <li><strong>CLOSED</strong>: Partially accessible cell.</li>
  <li><strong>OCCUPIED</strong>: Already visited cell.</li>
  <li><strong>CRITICAL</strong>: Currently targeted cell.</li>
  <li><strong>RETURNED</strong>: Return cell to follow unexplored paths.</li>
</ul>

<p>Each cell stores its center in pixels and its state, facilitating planning and visualization.</p>

<div style="text-align: center;">
    <img src="/assets/visual_grids.gif" alt="Grid visualization" />
</div>

<h2 id="motion-planning"><strong>Motion Planning</strong></h2>

<p><strong>1. Selecting the Initial Cell</strong><br />
The robot’s current cell is identified using its world coordinates and a map-to-pixels transformation function.</p>

<p><strong>2. Priority and Exploration Order</strong><br />
The algorithm explores neighboring cells following a <strong>Dynamic Priority Order</strong> adjustable in real time. By default, it may follow West → North → East → South, but it can be modified depending on the environment or user preferences.</p>

<p>Each visited cell is marked as <strong>OCCUPIED</strong>. This dynamic priority is passed directly to the <code class="language-plaintext highlighter-rouge">planificate_grid</code> function, allowing the robot to change its exploration strategy based on specific needs or sensor data.</p>

<p><strong>3. Searching for the Nearest Free Cell</strong><br />
If the robot gets stuck, <strong>BFS (Breadth-First Search)</strong> is used to find the nearest free cell. This ensures the robot continues exploring the entire area without getting trapped.</p>

<p><strong>4. Plan Generation</strong><br />
The final plan consists of a list of cells the robot must visit, prioritizing full coverage while avoiding obstacles.</p>

<h2 id="robot-control"><strong>Robot Control</strong></h2>

<p>The robot adjusts its <strong>linear &amp; angular velocity</strong> using a proportional controller that considers:</p>

<ul>
  <li>Distance to the target.</li>
  <li>Angular error between the robot’s orientation and the target cell direction.</li>
  <li>Alignment of upcoming cells to smooth or accelerate movement.</li>
  <li>Speed reduction when approaching the target cell.</li>
</ul>

<p>Maximum speed is limited for safety, and adjustment factors are applied to keep the robot aligned with the planned trajectory.</p>

<h2 id="initial-direction-based-on-laser"><strong>Initial Direction Based on Laser</strong></h2>

<p>Before starting, the laser data is analyzed to select the initial direction with the most free space. This avoids unnecessary movement toward blocked areas at the beginning of the route.</p>

<h2 id="robot-states-"><strong>Robot States 🤖</strong></h2>

<p>The algorithm defines three main states:</p>

<ul>
  <li><strong>PLANIFICATE 🗺️</strong>: Generates the exploration plan based on the grid.</li>
  <li><strong>TRAVEL_IT 🚶</strong>: Robot follows the plan visiting cells.</li>
  <li><strong>FINISHED ✅</strong>: All accessible cells have been explored.</li>
  <li><strong>TEST 🧪</strong>: Allows visual verification of the grid and the robot’s current position without moving.</li>
</ul>

<h2 id="visualization-and-monitoring"><strong>Visualization and Monitoring</strong></h2>

<p>The grid and map are visualized in real time using WebGUI, with different colors according to each cell’s state:</p>

<ul>
  <li><strong>Black</strong>: Obstacle</li>
  <li><strong>Green</strong>: Free</li>
  <li><strong>Indigo</strong>: Occupied</li>
  <li><strong>Red</strong>: Critical</li>
  <li><strong>Violet</strong>: Return</li>
  <li><strong>Orange</strong>: Default/Closed</li>
</ul>

<p>This enables intuitive monitoring of the robot’s planning and progress.</p>

<div style="text-align: center;">
    <img src="/assets/planify_bfs(1).gif" alt="Grid visualization" />
</div>

<h1 id="videos"><strong>Videos</strong></h1>

<ul>
  <li><strong>Autonomous Cleaner 🤖</strong>:</li>
</ul>
<div style="display: flex; justify-content: center;">
  <video width="700" controls="">
    <source src="/assets/videos/Cleaner_aut_short.mp4" type="video/webm" />
    Your browser does not support WebM format.
  </video>
</div>

<h2 id="conclusion"><strong>Conclusion</strong></h2>

<p>This <strong>grid-based navigation system</strong> allows a vacuum robot to:</p>

<ul>
  <li>Explore complex areas autonomously.</li>
  <li>Avoid obstacles and minimize collisions.</li>
  <li>Efficiently cover the entire map surface.</li>
</ul>

<p>Thanks to the combination of <strong>Obstacle Inflation 🚧</strong>, <strong>Grid Planning 🟩</strong>, <strong>BFS for Alternative Routes 🔍</strong>, and a <strong>Proportional Controller ⚙️</strong>, the robot achieves full and safe autonomous cleaning. This approach is scalable and can adapt to different environments by simply adjusting the grid size and the robot’s radius.</p>]]></content><author><name>Álvaro Valencia Maiquez</name></author><category term="service-robotics" /><summary type="html"><![CDATA[Autonomous Navigation for a Vacuum Robot]]></summary></entry><entry><title type="html">ROS 2 Rover</title><link href="https://alvvalencia.github.io/modelating-simulation/2025/05/01/ROS2-Rover.html" rel="alternate" type="text/html" title="ROS 2 Rover" /><published>2025-05-01T08:00:00+00:00</published><updated>2025-05-01T08:00:00+00:00</updated><id>https://alvvalencia.github.io/modelating-simulation/2025/05/01/ROS2-Rover</id><content type="html" xml:base="https://alvvalencia.github.io/modelating-simulation/2025/05/01/ROS2-Rover.html"><![CDATA[<h2 id="modelating-rover-on-ros-2">Modelating Rover on ROS 2</h2>

<p>Este proyecto se basa en la creación y modelación de un Rover en ROS 2. 
En una primera fase se realizó la modelación del Rover en Blender, para su posterior adición a Gazebo y su control mediante ROS 2.</p>

<h2 id="plataformas-utilizadas"><strong>Plataformas Utilizadas</strong></h2>

<ul>
  <li><strong>Blender</strong></li>
  <li><strong>Pybullet</strong></li>
  <li><strong>Gazebo</strong></li>
  <li><strong>Moveit</strong></li>
</ul>

<h2 id="arbol-de-transformadas"><strong>Arbol De Transformadas</strong></h2>

<p><img src="/assets/images/Captura%20desde%202025-05-01%2018-44-34.png" alt="Animación de ejemplo" /></p>
<div style="text-align: center;">
  <a href="https://github.com/Alvvalencia/danieljr_armed_rover_ROS_2" target="_blank">Github of the rover</a>
</div>

<h2 id="grafos-del-rover"><strong>Grafos Del Rover</strong></h2>

<ul>
  <li><strong>Grafo De Aceleracion</strong>
<img src="/assets/images/grafico_aceleracion.png" alt="Animación de ejemplo" /></li>
</ul>

<p>Aquí se puede ver cómo cambia la aceleración del rover a lo largo del movimiento. Al principio los valores son bastante estables, pero en el momento en que el rover se mueve hacia atrás y hace maniobras para posicionarse, empiezan a aparecer picos. Los picos más grandes se ven cuando el robot avanza con el cubo ya dentro, que es cuando más se nota el peso y los pequeños baches o ajustes del terreno.
Se nota totalmente, cuando el robot esta parado y solamente le influyen las fuerzas correspondientes a las físicas, como por ejemplo la gravedad en el <strong>eje z</strong>.</p>

<ul>
  <li><strong>Grafo De Posicion</strong>
<img src="/assets/images/grafico_posicion.png" alt="Animación de ejemplo" /></li>
</ul>

<p>En esta gráfica se refleja claramente cuándo el rover da marcha atrás y luego empieza a moverse con el cubo ya dentro. Algunas ruedas tienen más movimiento que otras, debido a las pequeñas correcciones para posicionar el <strong>scara</strong> encima del cubo, y después para salir del sitio.</p>

<ul>
  <li><strong>Grafo De Gasto</strong>
<img src="/assets/images/grafico_gasto_parcial_.png" alt="Animación de ejemplo" /></li>
</ul>

<p>En este gráfico se observa claramente el comportamiento del brazo SCARA durante una tarea de manipulación, reflejado en el gasto parcial (asociado a la fuerza en las articulaciones).</p>

<ul>
  <li>
    <p>Al inicio, el valor es bajo y estable, indicando que el brazo aún no ha comenzado a interactuar físicamente con el entorno.</p>
  </li>
  <li>
    <p>Luego, hay un primer aumento de fuerza, que corresponde al momento en que el brazo se mueve hacia atrás para posicionarse y alinearse sobre el cubo.</p>
  </li>
  <li>
    <p>A partir de ahí, se observa un pico más pronunciado: esto coincide con el descenso del brazo hacia el cubo. La fuerza aumenta al encontrarse con resistencia al hacer contacto con el objeto.</p>
  </li>
  <li>
    <p>Posteriormente, se mantiene una fuerza elevada y algo estable. Esta fase representa cuando el brazo sostiene el cubo, manteniendo la pinza cerrada mientras se eleva y lo transporta hacia el compartimento de destino.</p>
  </li>
  <li>
    <p>A mitad del gráfico se nota una ligera caída temporal en la fuerza, lo que se puede asociar a un momento de menor esfuerzo, probablemente al finalizar el levantamiento o en un punto de movimiento más controlado y suave.</p>
  </li>
  <li>
    <p>Finalmente, se observa otro pico cuando el brazo desciende para colocar el cubo. La fuerza vuelve a aumentar al soltar el objeto, y luego cae bruscamente cuando finaliza la acción y el brazo queda en reposo.</p>
  </li>
</ul>

<h2 id="camaras"><strong>Camaras</strong></h2>
<ul>
  <li><strong>Front Camera</strong></li>
</ul>
<div style="display: flex; justify-content: center;">
    <img src="/assets/images/front_camera.png" alt="Imagen de ejemplo" />
</div>

<ul>
  <li><strong>Gripper Camera</strong></li>
</ul>
<div style="display: flex; justify-content: center;">
    <img src="/assets/images/gripper_camera.png" alt="Imagen de ejemplo" />
</div>

<h2 id="video"><strong>Video</strong></h2>
<div style="display: flex; justify-content: center;">
  <video width="500" controls="">
    <source src="/assets/videos/danieljr_rover_.mp4" type="video/webm" />
    Tu navegador no soporta videos en formato WebM.
  </video>
</div>

<h2 id="rosbag"><strong>ROSBAG</strong></h2>
<div style="text-align: center;">
  <a href="https://drive.google.com/drive/folders/1VN2PsVczo4zJnjfGJdyYVtV7DMUfw1vY?usp=sharing" target="_blank">Ver archivos en Google Drive</a>
</div>

<hr />

<h2 id="conclusión"><strong>Conclusión</strong></h2>

<p>En esta práctica se ha realizado la integración del robot en Gazebo y su control mediante ROS 2. Además, se ha simulado una tarea de recogida y transporte de un objeto utilizando un brazo SCARA, analizando el comportamiento del sistema a través de gráficas de aceleración, posición y esfuerzo.</p>]]></content><author><name>Álvaro Valencia Maiquez</name></author><category term="modelating-simulation" /><summary type="html"><![CDATA[Modelating Rover on ROS 2]]></summary></entry><entry><title type="html">P4 — SmartCar Follow-Line</title><link href="https://alvvalencia.github.io/sistemas-empotrados/2024/12/21/Race-car.html" rel="alternate" type="text/html" title="P4 — SmartCar Follow-Line" /><published>2024-12-21T08:00:00+00:00</published><updated>2024-12-21T08:00:00+00:00</updated><id>https://alvvalencia.github.io/sistemas-empotrados/2024/12/21/Race-car</id><content type="html" xml:base="https://alvvalencia.github.io/sistemas-empotrados/2024/12/21/Race-car.html"><![CDATA[<h2 id="p4-smartcar-followline">P4 SmartCar FollowLine</h2>

<p>Este proyecto describe el desarrollo de un coche seguidor de línea equipado con sensores infrarrojos y comunicación MQTT mediante un ESP32. El Arduino controla los motores y lee los sensores, mientras que el ESP32 recibe la información por puerto serie y la retransmite a un servidor MQTT para monitoreo remoto.</p>

<hr />

<h2 id="componentes-utilizados"><strong>Componentes Utilizados</strong></h2>

<ul>
  <li><strong>Sensores infrarrojos:</strong> Detectan la línea mediante valores analógicos.</li>
  <li><strong>Motores de corriente continua (DC):</strong> Controlados mediante señales analógicas PWM para ajustar velocidad y dirección.</li>
  <li><strong>ESP32:</strong> Encargado de la comunicación WiFi y MQTT.</li>
  <li><strong>Arduino UNO:</strong> Procesa los datos de los sensores y controla los motores.</li>
  <li><strong>LED RGB:</strong> Proporciona retroalimentación visual sobre el estado del sistema.</li>
  <li><strong>Sensor ultrasónico (HC-SR04):</strong> Detecta obstáculos en el camino.</li>
</ul>

<hr />

<h2 id="detección-de-línea-con-sensores-infrarrojos"><strong>Detección de Línea con Sensores Infrarrojos</strong></h2>

<p>Los sensores infrarrojos detectan la intensidad de luz reflejada, proporcionando un valor analógico. Este valor se compara con un umbral predefinido para determinar si el sensor está sobre la línea o fuera de ella.</p>

<p><strong>Configuración de Sensores:</strong></p>
<ul>
  <li><strong>Left</strong>: <code class="language-plaintext highlighter-rouge">A2</code></li>
  <li><strong>Mid</strong>: <code class="language-plaintext highlighter-rouge">A1</code></li>
  <li><strong>Right</strong>: <code class="language-plaintext highlighter-rouge">A0</code></li>
</ul>

<p>Se define un umbral (<code class="language-plaintext highlighter-rouge">VALUE_LINE</code>) que determina si el valor leído está dentro del rango esperado para la línea. Este valor puede ajustarse experimentalmente según el entorno de operación.</p>

<hr />

<h2 id="control-de-motores"><strong>Control de Motores</strong></h2>

<p>El sistema utiliza un control proporcional-derivativo (<strong>PD</strong>) para ajustar la velocidad de los motores en función del error calculado.</p>

<p><strong>Errores y Corrección:</strong></p>
<ul>
  <li>El error se basa en la diferencia entre los sensores laterales (izquierda y derecha).</li>
  <li>Fórmula del error: <code class="language-plaintext highlighter-rouge">error = (valor_derecha - valor_izquierda)</code>.</li>
  <li>Se aplica una corrección proporcional definida en los parametros <code class="language-plaintext highlighter-rouge">KP</code> y <code class="language-plaintext highlighter-rouge">KD</code>.</li>
</ul>

<p><strong>Control de Velocidad:</strong>
La velocidad de los motores se ajusta usando <code class="language-plaintext highlighter-rouge">analogWrite</code> para generar señales <strong>PWM</strong>, permitiendo un control suave y preciso. Por ejemplo:</p>
<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">left_speed</span> <span class="o">=</span> <span class="n">base_speed</span> <span class="o">+</span> <span class="p">(</span><span class="n">KP</span> <span class="o">*</span> <span class="n">error</span> <span class="o">+</span> <span class="n">KD</span> <span class="o">*</span> <span class="p">(</span><span class="n">error</span> <span class="o">-</span> <span class="n">last_error</span><span class="p">));</span>
<span class="n">right_speed</span> <span class="o">=</span> <span class="n">base_speed</span> <span class="o">-</span> <span class="p">(</span><span class="n">KP</span> <span class="o">*</span> <span class="n">error</span> <span class="o">+</span> <span class="n">KD</span> <span class="o">*</span> <span class="p">(</span><span class="n">error</span> <span class="o">-</span> <span class="n">last_error</span><span class="p">));</span>
</code></pre></div></div>

<hr />

<h2 id="gestión-de-obstáculos"><strong>Gestión de Obstáculos</strong></h2>

<p>Un sensor ultrasónico detecta obstáculos y detiene el coche si la distancia detectada es inferior a un umbral seguro. Además, se envían mensajes de estado al <strong>ESP32</strong>, que posteriormente los retransmite al servidor <strong>MQTT</strong>.</p>

<p><strong>Ejemplo de Código:</strong></p>
<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">ultraSound</span><span class="o">-&gt;</span><span class="n">getDistance</span><span class="p">()</span> <span class="o">&lt;</span> <span class="mi">12</span> <span class="o">&amp;&amp;</span> <span class="n">ultraSound</span><span class="o">-&gt;</span><span class="n">getDistance</span><span class="p">()</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">analogWrite</span><span class="p">(</span><span class="n">PIN_Motor_PWMA</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">analogWrite</span><span class="p">(</span><span class="n">PIN_Motor_PWMB</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</code></pre></div></div>

<hr />

<h2 id="comunicación-entre-arduino-y-esp32"><strong>Comunicación entre Arduino y ESP32</strong></h2>

<p>La comunicación entre el <strong>Arduino</strong> y el <strong>ESP32</strong> se realiza mediante el puerto serie. El <strong>Arduino</strong> envía información en formato JSON al <strong>ESP32</strong>, que posteriormente la envía a un servidor <strong>MQTT</strong>.</p>

<h3 id="proceso-de-comunicación"><strong>Proceso de Comunicación:</strong></h3>
<ol>
  <li><strong>Arduino:</strong>
    <ul>
      <li>Envía mensajes JSON como:
        <ul>
          <li><code class="language-plaintext highlighter-rouge">{"line": 1}</code> para pérdida de línea.</li>
          <li><code class="language-plaintext highlighter-rouge">{"obst": distancia}</code> para obstáculos.</li>
        </ul>
      </li>
    </ul>
  </li>
  <li><strong>ESP32:</strong>
    <ul>
      <li>Recibe los mensajes del Arduino por el puerto serie.</li>
      <li>Los retransmite al servidor MQTT mediante el protocolo de publicación y suscripción.
        <div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   <span class="n">mqttClient</span><span class="p">.</span><span class="n">beginMessage</span><span class="p">(</span><span class="n">topic</span><span class="p">);</span>        <span class="n">mqttClient</span><span class="p">.</span><span class="n">beginMessage</span><span class="p">(</span><span class="n">topic</span><span class="p">);</span>
   <span class="n">mqttClient</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="n">get_json</span><span class="p">(</span><span class="s">"</span><span class="se">\"</span><span class="s">START_LAP</span><span class="se">\"</span><span class="s">"</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.00</span><span class="p">));</span>
   <span class="n">mqttClient</span><span class="p">.</span><span class="n">endMessage</span><span class="p">();</span>
   <span class="n">mqttClient</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="n">get_json</span><span class="p">(</span><span class="s">"</span><span class="se">\"</span><span class="s">START_LAP</span><span class="se">\"</span><span class="s">"</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mf">1.00</span><span class="p">));</span>
   <span class="n">mqttClient</span><span class="p">.</span><span class="n">endMessage</span><span class="p">();</span>
</code></pre></div>        </div>
      </li>
    </ul>
  </li>
  <li><strong>Servidor MQTT:</strong>
    <ul>
      <li>Procesa los datos para monitoreo y control remoto.</li>
    </ul>
  </li>
</ol>

<hr />

<h2 id="indicadores-led-rgb"><strong>Indicadores LED RGB</strong></h2>

<p>Los LEDs RGB proporcionan retroalimentación visual en tiempo real:</p>
<ul>
  <li><strong>Verde:</strong> Sobre la línea.</li>
  <li><strong>Rojo:</strong> Fuera de la línea.</li>
</ul>

<hr />

<h2 id="especificaciones-del-código"><strong>Especificaciones del código</strong></h2>
<p>En este proyecto, no se ha utilizado <strong>FreeRTOS</strong> por varias razones. A pesar de que el <strong>Arduino UNO</strong> es compatible con este sistema operativo, el proyecto no requiere un manejo complejo de múltiples tareas concurrentes. La funcionalidad principal del coche seguidor de línea (lectura de sensores, control de motores, y comunicación <strong>MQTT</strong>) se puede gestionar de manera eficiente utilizando un único hilo de ejecución en el <strong>Arduino</strong> y en el <strong>ESP32</strong>. Si que tenemos tareas con prioridades especificas como el hecho
de asegurarnos de publicar cada 4s un <code class="language-plaintext highlighter-rouge">ping</code>, pero el hecho de que incorporar <strong>FreeRTOS</strong> conlleva una perdida de un 20-30% del computo hace que no sea tan prescindible. Creemos que con un buen <strong>PD</strong>, o cualquier controlador optimo para el sistema, hará que las vueltas sean las más rápidas.</p>

<ul>
  <li><strong>Arduino</strong>:
    <ul>
      <li>El código de control de motores y sensores se ejecuta en un bucle principal sin necesidad de un sistema operativo en tiempo real.</li>
      <li>El procesamiento de los valores de los sensores y el ajuste de la velocidad de los motores se realiza en condiciones dentro del bucle principal, lo cual es suficiente para garantizar un control preciso y oportuno.</li>
      <li>Se usa dos condicionantes principales que marcan si estás dentro de la linea o, totalmente perdido. Sinónimo de <code class="language-plaintext highlighter-rouge">In Line</code> o <code class="language-plaintext highlighter-rouge">Search Line</code>.</li>
      <li>El sensor ultrasónico tiene un thread asociado que se llama cada <strong>12ms</strong>, que realiza una toma de medición, accediendo a el mediante <code class="language-plaintext highlighter-rouge">ultraSound-&gt;getDistance()</code>.</li>
      <li>El <code class="language-plaintext highlighter-rouge">ping</code> está incorporado dentro de un thread llamado cada <strong>4000ms</strong>.</li>
      <li>El código esta totalmente pensado para si detecta un obstáculo pararse y mandar todo lo relacionado con <code class="language-plaintext highlighter-rouge">END_LAP</code>, pero si quitamos el obstáculo se vuelve a hacer otra vuelta nueva.</li>
    </ul>
  </li>
  <li><strong>ESP32</strong>:
    <ul>
      <li>La comunicación entre el Arduino y el ESP32 se maneja mediante el puerto serie y para ello no se requiere la complejidad de FreeRTOS.</li>
      <li>El ESP32 utiliza su capacidad WiFi para enviar los datos a un servidor MQTT, gestionando de manera eficiente la conexión y retransmisión de mensajes.</li>
    </ul>
  </li>
</ul>

<h2 id="video"><strong>Video</strong></h2>
<div style="display: flex; justify-content: center;">
  <video width="500" controls="">
    <source src="/assets/videos/race-car.mp4" type="video/webm" />
    Tu navegador no soporta videos en formato WebM.
  </video>
</div>

<h2 id="conclusión"><strong>Conclusión</strong></h2>

<p>Este sistema combina detección de líneas mediante sensores infrarrojos, control PD para precisión en el movimiento y comunicación MQTT para supervisión remota. La integración entre Arduino y ESP32 garantiza un sistema eficiente y escalable para futuras mejoras. El sistema es adaptable y permite la incorporación de nuevas funciones como seguimiento de múltiples rutas, reconocimiento de patrones y control por voz.</p>]]></content><author><name>Álvaro Valencia Maiquez</name></author><category term="sistemas-empotrados" /><summary type="html"><![CDATA[P4 SmartCar FollowLine]]></summary></entry><entry><title type="html">P5 — Monte Carlo Localization</title><link href="https://alvvalencia.github.io/mobile-robotics/2024/12/21/P5-monte-carlo-localization.html" rel="alternate" type="text/html" title="P5 — Monte Carlo Localization" /><published>2024-12-21T07:30:00+00:00</published><updated>2024-12-21T07:30:00+00:00</updated><id>https://alvvalencia.github.io/mobile-robotics/2024/12/21/P5-monte-carlo-localization</id><content type="html" xml:base="https://alvvalencia.github.io/mobile-robotics/2024/12/21/P5-monte-carlo-localization.html"><![CDATA[<h1 id="monte-carlo-localization-mcl"><strong>Monte Carlo Localization (MCL)</strong></h1>

<p>Monte Carlo Localization (MCL) is a probabilistic algorithm used for estimating the position and orientation of a mobile robot within a known map. It employs a <strong>particle filter</strong> approach, which models the robot’s location using a set of particles distributed across the map. Each particle represents a hypothesis about the robot’s state, and these hypotheses are iteratively refined as the robot moves and receives sensor data.</p>

<h4 id="1-particle-initialization">1. Particle Initialization</h4>
<p>The algorithm begins by generating particles randomly distributed within the map. These particles represent possible initial positions and orientations of the robot. Gaussian noise is applied to each particle to simulate uncertainty, ensuring the robot’s position and orientation are likely represented by one of the particles.</p>

<p><img src="/assets/random-start-filter.gif" alt="Animación de ejemplo" /></p>

<h4 id="2-motion-update-propagation">2. Motion Update (Propagation)</h4>
<p>As the robot moves, the particles are updated based on the motion commands. Random noise is added to account for slippage, wheel errors, and other sources of inaccuracy. This step ensures that the particle distribution reflects the robot’s movement with realistic deviations.</p>

<p><img src="/assets/propagation-particles.gif" alt="Animación de ejemplo" /></p>

<h4 id="3-sensor-update">3. Sensor Update</h4>
<p>For each particle, simulated sensor readings are compared to actual sensor measurements. This comparison helps determine how likely each particle is to represent the robot’s true position. Particles that closely match the real sensor data are assigned higher weights.</p>

<p>Probability formula:</p>

<p><img src="/assets/images/formula.png" alt="Animación de ejemplo" /></p>

<h4 id="4-resampling">4. Resampling</h4>
<p>Particles are resampled based on their weights, giving preference to the most likely hypotheses. Low-probability particles are discarded, while high-probability particles are duplicated. This step effectively concentrates the particles around the areas where the robot is most likely located.</p>

<p><img src="/assets/resampling.gif" alt="Animación de ejemplo" /></p>

<h4 id="5-visualization">5. Visualization</h4>
<p>Particles are displayed visually, providing a real-time graphical representation of the robot’s position estimate. This visualization aids in debugging and helps validate the algorithm’s performance.</p>

<h1 id="why-use-mcl"><strong>Why Use MCL?</strong></h1>

<p>MCL is particularly useful because it handles uncertainty effectively and adapts dynamically to the robot’s movements and sensor readings. It is suitable for both static and dynamic environments, making it a versatile approach for mobile robot localization.</p>

<h1 id="challenges-and-limitations"><strong>Challenges and Limitations</strong></h1>

<p>Despite its strengths, MCL also has some limitations:</p>

<ol>
  <li>
    <p><strong>Dependence on an Accurate Map:</strong><br />
The algorithm assumes the map is precise. Errors in the map can lead to localization failures.</p>
  </li>
  <li>
    <p><strong>Particle Count Trade-off:</strong><br />
Using too few particles may produce poor estimates, while too many particles can increase computational costs.</p>
  </li>
  <li>
    <p><strong>Sensor Noise Sensitivity:</strong><br />
Noisy sensor data can degrade performance if not properly modeled.</p>
  </li>
</ol>

<h1 id="parameter-tuning"><strong>Parameter Tuning</strong></h1>

<p>To optimize performance, several parameters were fine-tuned:</p>

<ul>
  <li><strong>Number of Particles:</strong> 1,000 particles were used to balance accuracy and computational efficiency.</li>
  <li><strong>Initial Uncertainty:</strong> Gaussian noise was applied to both position and orientation to simulate realistic uncertainty at startup.</li>
  <li><strong>Motion Noise:</strong> Small random variations were introduced during propagation to account for robot dynamics.</li>
  <li><strong>Sensor Noise:</strong> Probabilistic models were used to handle noisy sensor data and improve robustness.</li>
  <li><strong>Roulette Wheel Noise:</strong><br />
To ensure diversity during the <strong>resampling phase</strong>, Gaussian noise was added to the particles selected by the <strong>roulette wheel algorithm</strong>. This prevents particle depletion and avoids excessive clustering, particularly in environments with ambiguous sensor data or multiple hypotheses.</li>
  <li><strong>Multiprocessing for Virtual Laser Computation:</strong><br />
  To improve computational efficiency, <strong>multiprocessing</strong> was utilized for the computation of virtual laser scans. Each particle’s sensor measurement was calculated in parallel, leveraging multiple CPU cores. This reduced processing time, enabling real-time performance even with high particle counts.</li>
</ul>

<h1 id="videos"><strong>Videos</strong></h1>

<ul>
  <li><strong>MCL</strong>:</li>
</ul>
<div style="display: flex; justify-content: center;">
  <video width="500" controls="">
    <source src="/assets/videos/montecarlo_localization.mp4" type="video/webm" />
    Tu navegador no soporta videos en formato WebM.
  </video>
</div>

<h1 id="conclusion"><strong>Conclusion</strong></h1>

<p>The Monte Carlo Localization algorithm implemented in this project successfully estimates the robot’s position using a particle filter approach. Through careful parameter tuning and noise modeling, the algorithm achieves reliable performance even in the presence of sensor and motion uncertainties. Future improvements could include adaptive particle counts and integration with SLAM techniques for unknown environments.</p>]]></content><author><name>Álvaro Valencia Maiquez</name></author><category term="mobile-robotics" /><summary type="html"><![CDATA[Monte Carlo Localization (MCL)]]></summary></entry><entry><title type="html">P3 — Vending Machine</title><link href="https://alvvalencia.github.io/sistemas-empotrados/2024/11/30/Vending-machine.html" rel="alternate" type="text/html" title="P3 — Vending Machine" /><published>2024-11-30T10:10:00+00:00</published><updated>2024-11-30T10:10:00+00:00</updated><id>https://alvvalencia.github.io/sistemas-empotrados/2024/11/30/Vending-machine</id><content type="html" xml:base="https://alvvalencia.github.io/sistemas-empotrados/2024/11/30/Vending-machine.html"><![CDATA[<h3 id="maquina-expendedora-en-arduino-uno"><strong>Maquina Expendedora En Arduino UNO</strong></h3>

<p>Este blog se centra en la descripción de una maquina expendedora realizada con Arduino UNO, concretamente con el kit Elegoo UNO R3.
La maquina se centra en el funcionamiento de maquina expendedora de café, pero cuenta con una estructura general compatible con ampliaciones,
o modificaciones de su uso, ya que se basa en un FSM(Finite State Machine).</p>
<h3 id="hardware"><strong>Hardware</strong></h3>

<div style="text-align: center;">
    <img src="/assets/images/Maquina_expendedora.jpg" alt="Imagen de ejemplo" />
</div>

<h3 id="introducción"><strong>Introducción</strong></h3>

<p>En vez de realizar el código de manera estricta e intrínseca para una maquina expendedora de café, se ha estructurado de manera generalizada para que
solamente realizando cambios en sus estados la maquina cambie de comportamiento. Para ello todas las funciones de los sensores están encapsuladas en funciones
intrínsecas a su comportamiento, o threads dedicados a ellos, por ello si queremos ampliar los estados de la máquina y en ellos usar distintos sensores se puede realizar, llamando
a las funciones pertinentes o los threads pertinentes.</p>

<ul>
  <li><strong>Threads:</strong>
    <ul>
      <li><strong>LedThread</strong>
        <ul>
          <li>getCounter()</li>
          <li>resetCounter()</li>
        </ul>
      </li>
      <li><strong>IncrementLedThread</strong>
        <ul>
          <li>resetBrightness()</li>
        </ul>
      </li>
      <li><strong>UltraSound</strong>
        <ul>
          <li>getPulseTime()</li>
          <li>getDistance()</li>
          <li>resetDistance()</li>
        </ul>
      </li>
      <li><strong>Dht11</strong>
        <ul>
          <li>getHumidity()</li>
          <li>getTemperature()</li>
        </ul>
      </li>
    </ul>
  </li>
  <li><strong>Functions:</strong>
    <ul>
      <li>joystick_x()</li>
      <li>joystick_y()</li>
    </ul>
  </li>
  <li><strong>Interruptions:</strong>
    <ul>
      <li>jy_button()</li>
      <li>pressed_button()</li>
    </ul>
  </li>
</ul>

<h3 id="estados-de-fsm"><strong>Estados de FSM</strong></h3>

<div style="text-align: center;">
    <img src="/assets/images/Vending_machine.jpg" alt="Imagen de ejemplo" />
</div>

<ol>
  <li><strong>START</strong>: Estado inicial donde la máquina se está cargando.
    <ul>
      <li><strong>Transición</strong>: Después de mostrar el mensaje de carga y cuando el contador de LedThread llegue a 3, pasa a <code class="language-plaintext highlighter-rouge">SERVICE</code>.</li>
    </ul>
  </li>
  <li><strong>SERVICE</strong>: La máquina espera la presencia de un cliente.
    <ul>
      <li><strong>Transición</strong>: Si el sensor ultrasónico detecta un cliente a una distancia menor a <code class="language-plaintext highlighter-rouge">CM_DISTANCE</code>, la máquina pasa a <code class="language-plaintext highlighter-rouge">MEASURES</code>.</li>
    </ul>
  </li>
  <li><strong>MEASURES</strong>: Estado donde se muestran las medidas (temperatura y humedad).
    <ul>
      <li><strong>Transición</strong>: Después de mostrar las medidas, pasa a <code class="language-plaintext highlighter-rouge">ATTENDING</code> cuando pasa <code class="language-plaintext highlighter-rouge">S_MEASURES*1000</code>.</li>
    </ul>
  </li>
  <li><strong>ATTENDING</strong>: Estado donde se muestra el menú de café para que el cliente elija.
    <ul>
      <li><strong>Transición</strong>: El cliente selecciona el café con el joystick (arriba o abajo), si presiona el joystick la máquina transita a <code class="language-plaintext highlighter-rouge">SERVING</code>.</li>
    </ul>
  </li>
  <li><strong>SERVING</strong>: Estado en el que la máquina prepara la bebida seleccionada.
    <ul>
      <li><strong>Transición</strong>: Después de un tiempo aleatorio de preparación (entre 4-8 segundos), la máquina pasa a <code class="language-plaintext highlighter-rouge">ATTENDED</code>.</li>
    </ul>
  </li>
  <li><strong>ATTENDED</strong>: Estado final donde se indica que la bebida está lista para ser retirada.
    <ul>
      <li><strong>Transición</strong>: Después de que el cliente retire la bebida, cuando pasa <code class="language-plaintext highlighter-rouge">S_DRINK*1000</code>, la máquina vuelve a <code class="language-plaintext highlighter-rouge">SERVICE</code>.</li>
    </ul>
  </li>
  <li><strong>ADMIN</strong>: El menú de administración donde se pueden ver los datos de los sensores, los segundos de la placa o modificar precios.
    <ul>
      <li><strong>Transición de llegada</strong>: Manteniendo el botón más de <code class="language-plaintext highlighter-rouge">MIN_S_ADMIN * 1000</code>.</li>
      <li><strong>Transiciónes</strong>: Dependiendo de la opción seleccionada en el menú, puede pasar a <code class="language-plaintext highlighter-rouge">ADMIN_I</code>, <code class="language-plaintext highlighter-rouge">ADMIN_II</code>, <code class="language-plaintext highlighter-rouge">ADMIN_III</code>, o <code class="language-plaintext highlighter-rouge">ADMIN_IV</code>, seleccionando con joystick,</li>
      <li><strong>Transición de salida</strong>: Manteniendo el botón más de <code class="language-plaintext highlighter-rouge">MIN_S_ADMIN * 1000</code>.</li>
    </ul>
  </li>
  <li><strong>ADMIN_I a ADMIN_IV</strong>: Sub-estados del menú de administración donde se pueden ver o modificar configuraciones.
    <ul>
      <li><strong>Transición</strong>: De vuelta a <code class="language-plaintext highlighter-rouge">ADMIN</code> si se navega hacia atrás, o a <code class="language-plaintext highlighter-rouge">SERVICE</code> si se mantiene el botón más de <code class="language-plaintext highlighter-rouge">MIN_S_ADMIN * 1000</code>.</li>
    </ul>
  </li>
  <li><strong>EXIT</strong>: Estado de salida, sin uso.</li>
</ol>

<h3 id="caracteristicas-destacadas"><strong>Caracteristicas Destacadas</strong></h3>

<h4 id="1-estado-start"><strong>1. Estado START</strong></h4>

<p>En el estado de arranque nos encontramos una función <code class="language-plaintext highlighter-rouge">start_machine()</code>, el cual realiza la representación, en el LCD, de CARGANDO y una serie de puntos que
dan dinamismo a la representación. Lo más característico de este estado es que controlamos el tiempo que tenemos que cargar mediante el parpadeo de un led.
Por ello hemos arrancado un thread <code class="language-plaintext highlighter-rouge">LedThread</code> que en <code class="language-plaintext highlighter-rouge">run()</code> solamente hace la labor de cambio de estado de HIGH a LOW, y cada vez que hace una transición cuenta 1
a su contador interno, y llamando a su método <code class="language-plaintext highlighter-rouge">ledThread1-&gt;getCounter()</code> vemos cuantas veces a parpadeado y si tenemos que cambiar de estado.</p>

<div style="text-align: center;">
    <img src="/assets/Cargando_empotrados(1).gif" alt="Animación de ejemplo" />
</div>

<h4 id="2-movimientos-joystick"><strong>2. Movimientos Joystick</strong></h4>

<p>El joystick cumple un papel principal en la máquina, la comunicación cliente maquina, gracias a el el cliente puede “comunicarse” con la maquina. Al ser un rol tan importante
he tratado de darle el máximo dinamismo posible, por ello tenemos dos funciones principales <code class="language-plaintext highlighter-rouge">joystick_x()</code>/ <code class="language-plaintext highlighter-rouge">joystick_y()</code> las cuales marcan la dirección del movimiento siendo
arriba y abajo gracias al eje <strong>y</strong>, y derecha e izquierda gracias al eje <strong>x</strong>.</p>

<div style="display: flex; justify-content: space-between;">
    <div style="flex: 0 48%;">
        <pre><code>
// 1 is up, -1 is down, 0 no moved
int joystick_y() {
  int index = 0;
  int vy = analogRead(joy_y_pin);
  if (vy &gt; 800) {
    return 1;
  } else if (vy &lt; 300) {
    return -1;
  }
  return 0;
}
        </code></pre>
    </div>
    <div style="flex: 0 48%;">
        <pre><code>
// -1 is left, +1 is right, 0 no moved
int joystick_x() {
  int index = 0;
  int vx = analogRead(joy_x_pin);
  if (vx &gt; 800) {
    return 1;
  } else if (vx &lt; 300) {
    return -1;
  }
  return 0;
}
        </code></pre>
    </div>
</div>

<p>Además para darle el dinamismo deseado podemos scrollear hacia arriba y abajo manteniendo el joystick en una dirección, pero para ello hay que 
realizar esperas entre movimiento y movimiento ya que si no al iterar tan rápido no seriamos capaces de controlarlo. Por ello cuando usamos
el joystick, principalmente en nuestro caso arriba y abajo <code class="language-plaintext highlighter-rouge">joystick_y()</code>, hacemos realizamos esperas definidas en <code class="language-plaintext highlighter-rouge">S_JOY_REACT*1000</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">if</span> <span class="p">(</span><span class="n">millis</span><span class="p">()</span> <span class="o">-</span> <span class="n">time_</span> <span class="o">&gt;=</span> <span class="p">(</span><span class="n">S_JOY_REACT</span><span class="o">*</span><span class="mi">1000</span><span class="p">))</span> <span class="p">{</span>
    <span class="n">m_index</span> <span class="o">=</span> <span class="n">joystick_y</span><span class="p">();</span>
    <span class="n">time_</span> <span class="o">=</span> <span class="n">millis</span><span class="p">();</span>
  <span class="p">}</span>
</code></pre></div></div>

<div style="text-align: center;">
    <img src="/assets/Joystick_empotrados.gif" alt="Animación de ejemplo" />
</div>

<h4 id="3-sensor-de-humedadtemperatura"><strong>3. Sensor De Humedad/Temperatura</strong></h4>

<p>Para tratar este sensor hemos tenido que importar una librería, <code class="language-plaintext highlighter-rouge">DHT sensor library</code> dedicada a nuestro sensor, el sensor <strong>DHT11</strong>. Esta librería nos facilita el uso
del sensor mediante un tipo de dato <code class="language-plaintext highlighter-rouge">DHT(DHTPIN, DHTYPE)</code>, que al pasarle el pin y el tipo de sensor, en nuestro caso DHT11, ya nos establece el sensor. Cuando llamamos
a su método <code class="language-plaintext highlighter-rouge">begin()</code> lo configuramos de la manera correcta, permitiéndonos su uso. A partir de ahí podemos realizar las llamadas sus métodos  <code class="language-plaintext highlighter-rouge">dht-&gt;readHumidity()</code> y 
<code class="language-plaintext highlighter-rouge">dht-&gt;readTemperature()</code>.</p>

<p>Para facilitar su uso, esta integrado todo en una clase Dht11, que se trata de un thread, el cual al arrancarlo y seleccionar su intervalo de recopilación de datos 
el sensor guardará los datos en unos atributos de su clase, y para extraer su valores están los métodos:</p>
<ul>
  <li><strong>getHumidity()</strong></li>
  <li><strong>getTemperature()</strong></li>
</ul>

<div style="text-align: center;">
    <img src="/assets/DHT11_empotradis.gif" alt="Animación de ejemplo" />
</div>

<h4 id="4-sensor-de-ultrasonido"><strong>4. Sensor De UltraSonido</strong></h4>

<p>El funcionamiento del sensor ultrasónico <strong>HC-SR04</strong> se basa en dos pines principales: <strong>Trigger</strong> y <strong>Echo</strong>, que se encargan de emitir y recibir las ondas ultrasónicas, respectivamente. Para su operación, se envía un valor <code class="language-plaintext highlighter-rouge">HIGH</code> al pin <strong>Trigger</strong> durante 10 microsegundos para emitir una onda ultrasónica. Luego, se cambia a <code class="language-plaintext highlighter-rouge">LOW</code> para dejar de emitir. Posteriormente, se utiliza la función <code class="language-plaintext highlighter-rouge">pulseIn(ECHOPIN, HIGH)</code> para medir el tiempo que tarda la onda en regresar, lo que corresponde al ancho de pulso.</p>

<p>Con este valor, se puede calcular la distancia al objeto utilizando la fórmula:</p>

<p><strong>distancia = (t_pulso * 0.034) / 2</strong></p>

<p>Donde:</p>
<ul>
  <li><strong>t_pulso</strong> es el tiempo medido en microsegundos.</li>
  <li><strong>0.034</strong> es la velocidad del sonido en el aire (en cm/µs).</li>
  <li>El factor <strong>2</strong> se debe a que el tiempo medido es el de ida y vuelta de la señal.</li>
</ul>

<div style="text-align: center;">
    <img src="/assets/UltraSonido_empotrados.gif" alt="Animación de ejemplo" />
</div>

<h4 id="5-modificación-de-precios"><strong>5. Modificación De Precios</strong></h4>

<p>Cuando se arranca el programa hay un precios predefinidos pero estos precios pueden ser modificados en el estado <code class="language-plaintext highlighter-rouge">ADMIN_IV</code>, al cual se accede desde <code class="language-plaintext highlighter-rouge">ADMIN</code>.
En este <strong>“subestado”</strong> del <strong>ADMIN</strong>, se hace uso de todos los ejes del <strong>joystick</strong>:</p>
<ul>
  <li>
    <p><strong>x</strong>: Para movernos hacia atrás(izq), ya sea volver a <code class="language-plaintext highlighter-rouge">ADMIN</code> o volver a la selección del café que queremos modificar su precio, o hacia adelante(drch) para seleccionar el apartado precio y modificarlo.</p>
  </li>
  <li>
    <p><strong>y</strong>: Para scrollear arriba y abajo, y así elegir el café correspondiente o modificar subiendo bajando su precio.</p>
  </li>
</ul>

<p>Además cuenta con dinamismo de imagen, ya que al seleccionar el precio este parpadea como símbolo de elección.</p>

<div style="text-align: center;">
    <img src="/assets/Modificar_precio.gif" alt="Animación de ejemplo" />
</div>

<h4 id="6-interrupciones-de-botones"><strong>6. Interrupciones De Botones</strong></h4>

<p>La maquina cuenta con dos interrupciones, tanto el botón del <strong>joystick</strong> como el <strong>botón</strong> común. Ambos gestionados mediante circuito PULL_UP, nos marcan
si se ha presionado o no los respectivos botones. Estos botones solo tienen uso en distintos estados, ya sea:</p>
<ul>
  <li><strong>Joystick button</strong>: Solo tiene uso para seleccionar el café deseado, y seleccionar la información deseada del <code class="language-plaintext highlighter-rouge">ADMIN</code>.</li>
  <li><strong>Common button</strong>: Su uso es durante todo el código, y dicta si se accede a la función de <code class="language-plaintext highlighter-rouge">ADMIN</code>, o se sale, o si has avanzado más del estado <code class="language-plaintext highlighter-rouge">SERVICE</code> para poder salir y esperar a un cliente.</li>
</ul>

<h3 id="videos"><strong>Videos</strong></h3>

<ul>
  <li><strong>Vending Machine</strong>:</li>
</ul>
<div style="text-align: center;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/roQuHYqQfU8" frameborder="0" allowfullscreen=""></iframe>
</div>

<h3 id="conclusión"><strong>Conclusión</strong></h3>

<p>El uso de <em>threads</em> para organizar las tareas de manera más limpia y estructurada facilita el entendimiento del código y distribuye las funciones de forma eficiente. Aunque las operaciones de los <em>threads</em> sean secuenciales, la concurrencia que ofrecen da la impresión de que se ejecutan simultáneamente, mejorando la percepción de fluidez del sistema.</p>

<p>Además, el uso de interrupciones en los botones permite que la máquina nunca esté detenida ni realizando espera activa para comprobar estados, ya que las propias interrupciones se encargan de gestionar los cambios necesarios de manera eficiente.</p>

<p>Finalmente, el empleo de un <em>watchdog</em> proporciona una solución robusta para evitar bloqueos de la máquina. Gracias a la facilidad que ofrecen los <em>threads</em> y su funcionamiento concurrente, es posible utilizar tiempos de comprobación más cortos, minimizando el uso de funciones como <code class="language-plaintext highlighter-rouge">delay()</code> y mejorando la reactividad del sistema.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">wdt_disable</span><span class="p">();</span>
  <span class="n">wdt_enable</span><span class="p">(</span><span class="n">WDTO_1S</span><span class="p">);</span>
  <span class="p">...</span>
  <span class="p">...</span>
  <span class="n">wdt_reset</span><span class="p">();</span>
</code></pre></div></div>]]></content><author><name>Álvaro Valencia Maiquez</name></author><category term="sistemas-empotrados" /><summary type="html"><![CDATA[Maquina Expendedora En Arduino UNO]]></summary></entry></feed>