<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Home - Localization</title>
    <link rel="self" type="application/atom+xml" href="https://shaostassen.github.io/ShaoFastRobots/tags/localization/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://shaostassen.github.io/ShaoFastRobots"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-04-27T00:00:00+00:00</updated>
    <id>https://shaostassen.github.io/ShaoFastRobots/tags/localization/atom.xml</id>
    <entry xml:lang="en">
        <title>Lab 11: Localization on the Real Robot</title>
        <published>2026-04-27T00:00:00+00:00</published>
        <updated>2026-04-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Shao Stassen
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://shaostassen.github.io/ShaoFastRobots/Fast Robots Stuff/lab-11/"/>
        <id>https://shaostassen.github.io/ShaoFastRobots/Fast Robots Stuff/lab-11/</id>
        
        <content type="html" xml:base="https://shaostassen.github.io/ShaoFastRobots/Fast Robots Stuff/lab-11/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Lab 10 implemented the Bayes filter in simulation. This lab implements it directly on the RC car. Because the motion model is too noisy to be useful on the car, we only run the &lt;strong&gt;update step&lt;&#x2F;strong&gt; run, against a uniform prior. The robot does a single 360° scan, the filter processes 18 range readings, and we see how well a single observation can pin down position.&lt;&#x2F;p&gt;
&lt;p&gt;I am using the provided solution as an optimized filter (&lt;code&gt;localization_extras.py&lt;&#x2F;code&gt;), as well as an accurate map of the world. I need to implement the 360° scan and localize the robot in a discretized map using the Bayes filter.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;verifying-the-filter-in-simulation&quot;&gt;Verifying the Filter in Simulation&lt;&#x2F;h2&gt;
&lt;p&gt;Running &lt;code&gt;lab11_sim.ipynb&lt;&#x2F;code&gt; produced the expected behavior. The filter belief stays close to ground truth across the whole trajectory, even as the odometry drifts off course. This is very similar to the result I get from lab 10.&lt;&#x2F;p&gt;
&lt;img src=&quot;sim.jpg&quot; alt=&quot;Lab 11 simulation result&quot; style=&quot;display:block;&quot;&gt;
&lt;figcaption&gt;Bayes filter trajectory in simulation&lt;&#x2F;figcaption&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Blue:&lt;&#x2F;strong&gt; filter belief&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Red:&lt;&#x2F;strong&gt; odometry-only estimate&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Green:&lt;&#x2F;strong&gt; ground truth&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;real-robot-pipeline&quot;&gt;Real Robot Pipeline&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;arduino-single-360-degree-scan&quot;&gt;Arduino: Single 360 degree Scan&lt;&#x2F;h3&gt;
&lt;p&gt;I added a new BLE command, &lt;code&gt;LOCALIZE&lt;&#x2F;code&gt;, alongside Lab 9&#x27;s existing &lt;code&gt;MAP&lt;&#x2F;code&gt; command. Where mapping does a 720° dual-pass at 12° increments, localization does &lt;strong&gt;18 readings spaced at 20°&lt;&#x2F;strong&gt; for one full rotation.&lt;&#x2F;p&gt;
&lt;p&gt;The hardest part wasn&#x27;t the rotation itself, because my PID is already tuned pretty well. It was knowing precisely when the robot was still enough to take a measurement. A fixed 2-second wait per setpoint left the robot oscillating at some turns when the ToF fired, adding noise to the angular accuracy of each reading.&lt;&#x2F;p&gt;
&lt;p&gt;My fix to this was active settle detection. The PID drives toward each 20° target; once heading error stays within ±1.5° for 400 ms continuously, the motors brake hard for another 100 ms before the ToF capture fires. Only then does it advance to the next target. This made the scan reliable while still keeping it reasonably fast.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;while&lt;&#x2F;span&gt;&lt;span&gt; (rot_counter &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 18&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; BLE.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;central&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;connected&lt;&#x2F;span&gt;&lt;span&gt;()) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    uint32_t&lt;&#x2F;span&gt;&lt;span&gt; step_start_time &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; millis&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    uint32_t&lt;&#x2F;span&gt;&lt;span&gt; in_tolerance_since &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    bool&lt;&#x2F;span&gt;&lt;span&gt; settled &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    while&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;settled &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; BLE.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;central&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;connected&lt;&#x2F;span&gt;&lt;span&gt;()) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        uint32_t&lt;&#x2F;span&gt;&lt;span&gt; current_time &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; millis&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;        readIMUFIFO&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;        get_roll_pitch_yaw&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        float&lt;&#x2F;span&gt;&lt;span&gt; curr_yaw &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; yaw_readings[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        float&lt;&#x2F;span&gt;&lt;span&gt; e &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; curr_yaw &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt; target_turn;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; (e &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 180.0&lt;&#x2F;span&gt;&lt;span&gt;)       e &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;-=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 360.0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        else if&lt;&#x2F;span&gt;&lt;span&gt; (e &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;&amp;lt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;180.0&lt;&#x2F;span&gt;&lt;span&gt;) e &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;+=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 360.0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        &#x2F;&#x2F; Apply PID; brake if inside the deadband&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        int&lt;&#x2F;span&gt;&lt;span&gt; motor_out &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;)(Kp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;e &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; Ki&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;error_total &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; Kd&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;error_change);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;abs&lt;&#x2F;span&gt;&lt;span&gt;(e)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; ANGLE_TOLERANCE) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;            brakeMotors&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; else if&lt;&#x2F;span&gt;&lt;span&gt; (motor_out &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            motor_out &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; constrain&lt;&#x2F;span&gt;&lt;span&gt;(motor_out, PWM_FLOOR, PWM_CEILING);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;            setMotors&lt;&#x2F;span&gt;&lt;span&gt;(motor_out,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span&gt;motor_out);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            motor_out &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; constrain&lt;&#x2F;span&gt;&lt;span&gt;(motor_out,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span&gt;PWM_CEILING,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span&gt;PWM_FLOOR);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;            setMotors&lt;&#x2F;span&gt;&lt;span&gt;(motor_out,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span&gt;motor_out);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;        &#x2F;&#x2F; Settle detection: must stay in tolerance continuously&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;abs&lt;&#x2F;span&gt;&lt;span&gt;(e)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; ANGLE_TOLERANCE) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;            if&lt;&#x2F;span&gt;&lt;span&gt; (in_tolerance_since &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;) in_tolerance_since &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; current_time;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;            if&lt;&#x2F;span&gt;&lt;span&gt; ((current_time &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt; in_tolerance_since &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;&amp;gt;=&lt;&#x2F;span&gt;&lt;span&gt; SETTLE_TIME_MS)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (current_time &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt; step_start_time &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;&amp;gt;=&lt;&#x2F;span&gt;&lt;span&gt; MIN_STEP_MS)) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                settled &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            in_tolerance_since &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; Capture ToF reading with the robot idle&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;    brakeMotors&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;    delay&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (distanceSensor1.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;checkForDataReady&lt;&#x2F;span&gt;&lt;span&gt;()) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        tof1_disc[disc_idx]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; distanceSensor1.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt;getDistance&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    yaw_disc[disc_idx]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; yaw_readings[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    disc_idx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;++&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    &#x2F;&#x2F; Step the target 20° CCW; reset PID state between steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    target_turn &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;-=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 20.0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (target_turn &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;&amp;lt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;180.0&lt;&#x2F;span&gt;&lt;span&gt;) target_turn &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;+=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 360.0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    error_total &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    last_error  &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rot_counter&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;++&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Two non-obvious details. First, my IMU reports yaw as decreasing during CCW rotation. I discovered this back in Lab 9 when my mapping function turned clockwise instead of CCW, and I had to flip my map across the y=x line to correct for it. So in this scan I decrement target_turn by 20° per step to physically rotate CCW. Second, resetting error_total between steps prevents integral windup from biasing the next approach.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;python-pass-the-scan-into-the-filter&quot;&gt;Python: Pass the Scan Into the Filter&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;RealRobot.perform_observation_loop()&lt;&#x2F;code&gt; invokes the BLE scan, accumulates the 18 streamed readings, and returns them as column arrays. It also auto-corrects the rotation direction by inspecting the IMU sign convention from the data itself.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #24292E; background-color: #FFFFFF;&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6F42C1;&quot;&gt; perform_observation_loop&lt;&#x2F;span&gt;&lt;span&gt;(self, rot_vel&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;120&lt;&#x2F;span&gt;&lt;span&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;    self&lt;&#x2F;span&gt;&lt;span&gt;._ranges_m.clear(); &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;._yaws_deg.clear()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;    self&lt;&#x2F;span&gt;&lt;span&gt;._receiving&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; False&lt;&#x2F;span&gt;&lt;span&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;._done&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;    self&lt;&#x2F;span&gt;&lt;span&gt;.ble.start_notify(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.ble.uuid[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;#39;RX_STRING&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;],&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;._localize_handler)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;    self&lt;&#x2F;span&gt;&lt;span&gt;.ble.send_command(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;CMD&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;LOCALIZE&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt; &amp;quot;1.5|0.05|0.1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    t0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; time.time()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    while not&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;._done&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; and&lt;&#x2F;span&gt;&lt;span&gt; (time.time()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span&gt; t0)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 60&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        time.sleep(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0.2&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;    self&lt;&#x2F;span&gt;&lt;span&gt;.ble.stop_notify(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.ble.uuid[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #032F62;&quot;&gt;&amp;#39;RX_STRING&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ranges&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; np.array(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;._ranges_m,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E36209;&quot;&gt; dtype&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;float&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    yaws_unwrapped&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; np.rad2deg(np.unwrap(np.deg2rad(np.array(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;._yaws_deg))))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6A737D;&quot;&gt;    # Detect IMU rotation convention from the data itself&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; np.mean(np.diff(yaws_unwrapped))&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        yaws_rel_deg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; yaws_unwrapped&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span&gt; yaws_unwrapped[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    else&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        yaws_rel_deg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; = -&lt;&#x2F;span&gt;&lt;span&gt;(yaws_unwrapped&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span&gt; yaws_unwrapped[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; len&lt;&#x2F;span&gt;&lt;span&gt;(ranges)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt; 18&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ranges&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; ranges[:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;]; yaws_rel_deg&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; yaws_rel_deg[:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #005CC5;&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #D73A49;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; ranges[np.newaxis].T, yaws_rel_deg[np.newaxis].T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The notification handler parses the Arduino&#x27;s &lt;code&gt;time:yaw:tof1:tof2&lt;&#x2F;code&gt; strings, converts ToF readings from millimeters to meters, and signals completion on receiving &lt;code&gt;DONE_MAP&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;When I first ran this, I noticed my RC car did an okay job doing the rotation. I did some tuning, which made it a lot better, and I was able to get some really good localization results. However, as my battery drained, my turns started to degrade again, and so did my localization results. This reminded me of Lab 5 and Lab 6 where the same issue happened before. Here are some bad localization:&lt;&#x2F;p&gt;
&lt;img src=&quot;bad03.jpg&quot; alt=&quot;Bad Localization at (0, 3)&quot; style=&quot;display:block;&quot;&gt;
&lt;figcaption&gt;Bad localization at (0, 3)&lt;&#x2F;figcaption&gt;
&lt;img src=&quot;bad53.jpg&quot; alt=&quot;Bad Localization at (5, 3)&quot; style=&quot;display:block;&quot;&gt;
&lt;figcaption&gt;Bad localizatin at (5, 3)&lt;&#x2F;figcaption&gt;
&lt;p&gt;After I replaced my battery, I was able to go back to my originally tuned PID gains and got better localization results.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;localization-results&quot;&gt;Localization Results&lt;&#x2F;h2&gt;
&lt;p&gt;I ran the update step at each of the four marked grid positions, plus an additional (0,0) spot, starting from a uniform prior. &lt;strong&gt;Green&lt;&#x2F;strong&gt; is ground truth; &lt;strong&gt;blue&lt;&#x2F;strong&gt; is the most likely cell from the filter.&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;&lt;strong&gt;(-3, -2)&lt;&#x2F;strong&gt;&lt;&#x2F;summary&gt;
&lt;img src=&quot;-3-2.jpg&quot; alt=&quot;Localization at (-3, -2)&quot; style=&quot;display:block;&quot;&gt;
&lt;figcaption&gt;Belief vs. ground truth at (-3, -2)&lt;&#x2F;figcaption&gt;
&lt;iframe width=&quot;450&quot; height=&quot;315&quot; src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;rvKvDf84wlo&quot; allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;figcaption&gt;Update step at (-3, -2)&lt;&#x2F;figcaption&gt;
&lt;&#x2F;details&gt;
&lt;details&gt;
&lt;summary&gt;&lt;strong&gt;(0, 3)&lt;&#x2F;strong&gt;&lt;&#x2F;summary&gt;
&lt;img src=&quot;03.jpg&quot; alt=&quot;Localization at (0, 3)&quot; style=&quot;display:block;&quot;&gt;
&lt;figcaption&gt;Belief vs. ground truth at (0, 3)&lt;&#x2F;figcaption&gt;
&lt;iframe width=&quot;450&quot; height=&quot;315&quot; src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;YI2PUDUP7lg&quot; allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;figcaption&gt;Update step at (0, 3)&lt;&#x2F;figcaption&gt;
&lt;&#x2F;details&gt;
&lt;details&gt;
&lt;summary&gt;&lt;strong&gt;(5, -3)&lt;&#x2F;strong&gt;&lt;&#x2F;summary&gt;
&lt;img src=&quot;5-3.jpg&quot; alt=&quot;Localization at (5, -3)&quot; style=&quot;display:block;&quot;&gt;
&lt;figcaption&gt;Belief vs. ground truth at (5, -3)&lt;&#x2F;figcaption&gt;
&lt;iframe width=&quot;450&quot; height=&quot;315&quot; src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;LxDthlAkrXs&quot; allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;figcaption&gt;Update step at (5, -3)&lt;&#x2F;figcaption&gt;
&lt;&#x2F;details&gt;
&lt;details&gt;
&lt;summary&gt;&lt;strong&gt;(5, 3)&lt;&#x2F;strong&gt;&lt;&#x2F;summary&gt;
&lt;img src=&quot;53.jpg&quot; alt=&quot;Localization at (5, 3)&quot; style=&quot;display:block;&quot;&gt;
&lt;figcaption&gt;Belief vs. ground truth at (5, 3)&lt;&#x2F;figcaption&gt;
&lt;iframe width=&quot;450&quot; height=&quot;315&quot; src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;wLfYSopqFc0&quot; allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;figcaption&gt;Update step at (5, 3)&lt;&#x2F;figcaption&gt;
&lt;&#x2F;details&gt;
&lt;details&gt;
&lt;summary&gt;&lt;strong&gt;(0, 0)&lt;&#x2F;strong&gt; — bonus origin test&lt;&#x2F;summary&gt;
&lt;img src=&quot;00.jpg&quot; alt=&quot;Localization at (0, 0)&quot; style=&quot;display:block;&quot;&gt;
&lt;figcaption&gt;Belief vs. ground truth at (0, 0)&lt;&#x2F;figcaption&gt;
&lt;iframe width=&quot;450&quot; height=&quot;315&quot; src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;tmtGkR4kjDw&quot; allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;figcaption&gt;Update step at (0, 0)&lt;&#x2F;figcaption&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;best-localization-summary&quot;&gt;Best Localization Summary&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Marked Pose (ft,ft,°)&lt;&#x2F;th&gt;&lt;th&gt;Ground Truth (m,m,°)&lt;&#x2F;th&gt;&lt;th&gt;Filter Belief (m, m, °)&lt;&#x2F;th&gt;&lt;th&gt;Cell Probability&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;(-3, -2, 0)&lt;&#x2F;td&gt;&lt;td&gt;(-0.914, -0.610, 0)&lt;&#x2F;td&gt;&lt;td&gt;(-0.914, -0.610, 10.000)&lt;&#x2F;td&gt;&lt;td&gt;1.000&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;(0, 3, 0)&lt;&#x2F;td&gt;&lt;td&gt;(0.000, 0.914, 0)&lt;&#x2F;td&gt;&lt;td&gt;(0.000, 0.914, -10.000)&lt;&#x2F;td&gt;&lt;td&gt;1.000&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;(5, -3, 0)&lt;&#x2F;td&gt;&lt;td&gt;(1.524, -0.914, 0)&lt;&#x2F;td&gt;&lt;td&gt;(1.524, -0.914, 10.000)&lt;&#x2F;td&gt;&lt;td&gt;0.999&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;(5, 3, 0)&lt;&#x2F;td&gt;&lt;td&gt;(1.524, 0.914, 0)&lt;&#x2F;td&gt;&lt;td&gt;(1.524, 0.610, -10.000)&lt;&#x2F;td&gt;&lt;td&gt;0.993&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;(0, 0, 0)&lt;&#x2F;td&gt;&lt;td&gt;(0.000, 0.000, 0)&lt;&#x2F;td&gt;&lt;td&gt;(0.000, 0.000, -10.000)&lt;&#x2F;td&gt;&lt;td&gt;1.000&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;discussion&quot;&gt;Discussion&lt;&#x2F;h2&gt;
&lt;p&gt;Looking at each of the pose plots and the summary table, the filter localized 4 of the 5 spots with very high probability. The position estimate was always within one discretized cell of ground truth, and the orientation was off less than 20° angular bin. The orientation offset of ±10° from ground truth is the closest the filter can get when the true heading sits exactly on a bin boundary. The only spot the filter couldn&#x27;t get exactly was (5, 3), where it returned (5, 2). That&#x27;s still within one cell, but a bit further off than the other poses.&lt;&#x2F;p&gt;
&lt;p&gt;I also noticed the car had a harder time localizing at the top of the map, (0, 3) and (5, 3), and a few people I talked to in lab said the same. That suggests something about the geometry up there (sparse walls, fewer distinctive ToF fingerprints) or environment factors (the floor is not leveled) makes the sensor model less informative in that region.&lt;&#x2F;p&gt;
&lt;p&gt;Lastly, I experimented with sensor_sigma in world.yaml. Increasing it gave noticeably worse localization, which suggests the default sensor_sigma = 0.1 is well-calibrated for my sensor&#x27;s actual noise level.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;collaboration&quot;&gt;Collaboration&lt;&#x2F;h2&gt;
&lt;p&gt;I referred to Adian McNay&#x27;s site for how to format the lab report.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
