<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Milo Blog]]></title><description><![CDATA[Charting my path to becoming a Full-stack Robotics Engineer.]]></description><link>https://blog.miloarchive.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 07 Jun 2026 07:35:27 GMT</lastBuildDate><atom:link href="https://blog.miloarchive.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Maze Navigation with Reinforcement Learning]]></title><description><![CDATA[Related Post:

Implementing Autonomous Target Navigation in MuJoCo via the Right-Hand Rule

This post explores how to solve a maze using Proximal Policy Optimization (PPO) within a custom MuJoCo envir]]></description><link>https://blog.miloarchive.com/maze-navigation-with-reinforcement-learning</link><guid isPermaLink="true">https://blog.miloarchive.com/maze-navigation-with-reinforcement-learning</guid><category><![CDATA[MuJoCo]]></category><category><![CDATA[C++]]></category><category><![CDATA[Autonomous vehicles]]></category><category><![CDATA[Reinforcement Learning]]></category><dc:creator><![CDATA[Milo]]></dc:creator><pubDate>Tue, 02 Jun 2026 10:48:29 GMT</pubDate><content:encoded><![CDATA[<p><strong>Related Post:</strong></p>
<ul>
<li><a href="https://blog.miloarchive.com/implementing-autonomous-target-navigation-in-mujoco-via-the-right-hand-rule">Implementing Autonomous Target Navigation in MuJoCo via the Right-Hand Rule</a></li>
</ul>
<p>This post explores how to solve a maze using Proximal Policy Optimization (PPO) within a custom MuJoCo environment I built previously. We'll start by understanding PPO. The core mechanism of PPO is 'clipping,' which keeps policy updates within a safe range and prevents extreme changes.</p>
<img src="https://cdn.hashnode.com/uploads/covers/697a014233686646a792dd2d/3e768553-e68d-467e-8ece-db1f05da936b.png" alt="" style="display:block;margin:0 auto" />

<p>The logic is quite straightforward and is based on the Right-Hand Rule. If the car drifts too far from the right wall or fails to stay parallel, it loses a reward. Furthermore, if it gets too close to the wall, it is also penalized. Conversely, maintaining the correct distance and alignment yields a positive reward. To implement this, we use LiDAR sensors to continuously measure the distance to the wall. The code below demonstrates this logic:</p>
<pre><code class="language-cpp">// ... rest of the code ...
forward, right_forward, right, right_back = obs

reward += ((action[0] + action[1]) / 2) * 1.5
reward += 0.5

if right &lt; 1.5:
    parallel_error = abs(right_back - right_forward)
    dist_error = abs(right - self.target_dist)
    steering_penalty = abs(action[0] - action[1])
    reward -= parallel_error * 3
    reward -= dist_error * 2
    reward -= steering_penalty * 0.5
else:
    if action[0] &gt; action[1]:
        reward += (action[0] - action[1]) * 3.0

if forward &lt; 1.5:
    reward -= (1.5 - forward) * 10
    if action[1] &gt; action[0]:
        reward += (action[1] - action[0]) * 3.0

if right_forward &lt; 1.5 and right_back &lt; 1.5:
    if action[1] &gt; action[0]:
        reward += (action[1] - action[0]) * 3.0

if min(obs) &lt; 0.3:
    reward -= 200.0
    terminated = True

info = {}
return obs, float(reward), terminated, truncated, info
</code></pre>
<p>Through this project, I realized that reward design is the key to reinforcement learning. Simply increasing penalties or rewards is not a perfect solution. In complex environments, excessive penalties often lead to the agent giving up (inaction), while excessive rewards cause reward hacking. Although this project isn't completely flawless, it successfully solved the core problem to a meaningful extent.</p>
<p><a class="embed-card" href="https://youtu.be/o87S0XbEy3A">https://youtu.be/o87S0XbEy3A</a></p>

<p>Finally, you can watch the final result of the simulation in the video above. The complete source code for this project is available on my <a href="https://github.com/RustSynx/robot-simulation/tree/main/example/reinforcement_simulation"><strong>GitHub repository</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Implementing Autonomous Target Navigation in MuJoCo via the Right-Hand Rule]]></title><description><![CDATA[In this post, we'll explore simple autonomous navigation using the right-hand rule before diving into more complex AI. Think of the right-hand rule as a person finding their way through a dark room by]]></description><link>https://blog.miloarchive.com/implementing-autonomous-target-navigation-in-mujoco-via-the-right-hand-rule</link><guid isPermaLink="true">https://blog.miloarchive.com/implementing-autonomous-target-navigation-in-mujoco-via-the-right-hand-rule</guid><category><![CDATA[MuJoCo]]></category><category><![CDATA[C++]]></category><category><![CDATA[Autonomous vehicles]]></category><dc:creator><![CDATA[Milo]]></dc:creator><pubDate>Fri, 01 May 2026 02:59:59 GMT</pubDate><content:encoded><![CDATA[<p>In this post, we'll explore simple autonomous navigation using the right-hand rule before diving into more complex AI. Think of the right-hand rule as a person finding their way through a dark room by keeping their hand on the right wall. To simulate this, we'll use a simple car model equipped with a LiDAR sensor in MuJoCo.</p>
<p>First, we'll build a maze and a simple car model. The maze includes a destination point and several walls to navigate. The image below shows the simulation environment we'll be using.</p>
<img src="https://cdn.hashnode.com/uploads/covers/697a014233686646a792dd2d/72dc0a34-10b7-472d-8671-f08f7b979227.png" alt="" style="display:block;margin:0 auto" />

<p>The logic is quite straightforward. If the car drifts too far from the right wall, it moves back toward it. Conversely, if it gets too close to the wall, it steers away to maintain a safe distance. To implement this, we use the LiDAR sensor to constantly measure the distance to the wall. The code below demonstrates the logic:</p>
<pre><code class="language-cpp">void controller(const std::vector&lt;double&gt;&amp; lidar_data, mjData *d) {
  double front_dist = lidar_data[0];
  double right_dist = lidar_data[270];
  double right_corner_dist = lidar_data[310];
  double speed = 1.0;
  if (front_dist &lt; 0.8) {
    d-&gt;ctrl[0] = -speed;
    d-&gt;ctrl[1] = speed;
  } else if (right_dist &gt; 0.5 || right_corner_dist &gt; 0.5) {
    d-&gt;ctrl[0] = speed;
    d-&gt;ctrl[1] = speed * 0.05;
  } else if (right_dist &lt; 0.5 || right_corner_dist &lt; 0.5) {
    d-&gt;ctrl[0] = speed * 0.05;
    d-&gt;ctrl[1] = speed;
  } else {
    d-&gt;ctrl[0] = speed;
    d-&gt;ctrl[1] = speed;
  }
}
</code></pre>
<p>The code below shows how to retrieve the LiDAR sensor data:</p>
<pre><code class="language-cpp">const int NUM_RAYS = 360;
const double MAX_RANGE = 10.0;

std::vector&lt;double&gt; get_lidar_data(const mjModel* m, mjData* d, int car_body_id) {
  mjtNum* pos = d-&gt;xpos + 3 * car_body_id;
  mjtNum* mat = d-&gt;xmat + 9 * car_body_id;

  std::vector&lt;double&gt; lidar_data(NUM_RAYS, MAX_RANGE);

  for (int i = 0; i &lt; NUM_RAYS; i++) {
    double angle = (i * 2.0 * M_PI) / NUM_RAYS;

    mjtNum local_vec[3] = {cos(angle), sin(angle), 0.0};
    mjtNum global_vec[3] = {0, 0, 0};

    mju_mulMatVec(global_vec, mat, local_vec, 3, 3);
    int geomid = -1;
    mjtNum normal[3];
    mjtNum dist = mj_ray(m, d, pos, global_vec, NULL, 1, car_body_id, &amp;geomid, normal);

    if (dist &gt; 0 &amp;&amp; dist &lt; MAX_RANGE) {
      lidar_data[i] = dist;
    }
  }
  return lidar_data;
}
</code></pre>
<p>The core of this implementation is the <code>mj_ray</code> function. It is a built-in MuJoCo utility used to measure distances within the simulation. If you'd like to learn more about how it works, you can check the <a href="https://mujoco.readthedocs.io/en/stable/APIreference/APIfunctions.html#mj-ray">official reference documentation</a>.</p>
<p><a class="embed-card" href="https://www.youtube.com/watch?v=mFOSd44_NfA">https://www.youtube.com/watch?v=mFOSd44_NfA</a></p>

<p>Finally, you can watch the final result of the simulation in the video above. The complete source code for this project is available on my <a href="https://github.com/RustSynx/robot-simulation/tree/main/example/lidar_simulation">GitHub repository</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Implementation of a Pick-and-Place Task with a 6-Axis Robot using Numerical Methods
]]></title><description><![CDATA[Related Post:

Implementation of a Pick-and-Place Task with a 6-Axis Robot

This article explains how to use numerical methods, which are a common approach to robot movement. First, we will explore Ja]]></description><link>https://blog.miloarchive.com/implementation-of-a-pick-and-place-task-with-a-6-axis-robot-using-numerical-methods</link><guid isPermaLink="true">https://blog.miloarchive.com/implementation-of-a-pick-and-place-task-with-a-6-axis-robot-using-numerical-methods</guid><category><![CDATA[MuJoCo]]></category><category><![CDATA[C++]]></category><category><![CDATA[dynamics]]></category><category><![CDATA[robotics]]></category><category><![CDATA[kinematics]]></category><dc:creator><![CDATA[Milo]]></dc:creator><pubDate>Mon, 20 Apr 2026 04:17:56 GMT</pubDate><content:encoded><![CDATA[<p><strong>Related Post:</strong></p>
<ul>
<li><a href="https://blog.miloarchive.com/implementation-of-a-pick-and-place-task-with-a-6-axis-robot">Implementation of a Pick-and-Place Task with a 6-Axis Robot</a></li>
</ul>
<p>This article explains how to use numerical methods, which are a common approach to robot movement. First, we will explore Jacobian-based methods, which primarily consist of the Jacobian Transpose, the Pseudo-inverse, and Damped Least Squares (DLS). Following this overview, we will derive the Jacobian matrix and apply the Damped Least Squares (DLS) method to control the movement of a 6-DOF robot arm.</p>
<p>Step 1: State Backup and Target Orientation Setup</p>
<pre><code class="language-cpp">Eigen::VectorXd solve_ik(const Eigen::Vector3d &amp;target_pos, int site_id) {
  // ... rest of the code ...
  Eigen::VectorXd original_qpos(m-&gt;nq);
  for (int i = 0; i &lt; m-&gt;nq; ++i)
    original_qpos[i] = d-&gt;qpos[i];

  // ... rest of the code ...
  for (int i = 0; i &lt; m-&gt;nq; ++i)
    d-&gt;qpos[i] = original_qpos[i];
  mj_forward(m, d);

  return target_qpos;
}
</code></pre>
<p>We must save initial <code>qpos</code> before calculation. If we don't, the robot arm will move instantly because the MuJoCo engine updates the robot's physical state during the calculation loop. By backing up the origin state, we can restore it after the calculation and ensure a smooth physical movement to the target.</p>
<p>Step 2: Calculating the 6-DOF Error Vector</p>
<pre><code class="language-cpp">  // ... rest of the code ...
  Eigen::Vector3d pos_error = target_pos - current_pos;

  // ... rest of the code ...
  Eigen::Vector3d ori_error = get_orientation_error(R_target, R_current);

  // ... rest of the code ...
</code></pre>
<p>In this step, we calculate the difference between the target pose and the current pose of the end-effector. In robotics, this difference is mathematically referred to as the 'error'.</p>
<p>Step 3: Extracting the Jacobian Matrix</p>
<pre><code class="language-cpp">void get_full_jacobian(Eigen::MatrixXd &amp;J, int site_id) {
  std::vector&lt;mjtNum&gt; jacp(3 * m-&gt;nv);
  std::vector&lt;mjtNum&gt; jacr(3 * m-&gt;nv);

  mj_jacSite(m, d, jacp.data(), jacr.data(), site_id);

  for (int i = 0; i &lt; 3; ++i) {
    for (int j = 0; j &lt; m-&gt;nv; ++j) {
      J(i, j) = jacp[i * m-&gt;nv + j];
      J(i + 3, j) = jacr[i * m-&gt;nv + j];
    }
  }
}
</code></pre>
<p>Our ultimate goal is to find out how much the motors need to rotate (\(dq\)) to cover the spatial error (\(dx\)). Mathematically, the relationship is defined by the Jacobian matrix as \(dx = J \cdot dq\). Therefore, to find \(dq\), we need to calculate the inverse of the Jacobian (\(dq = J^{-1} \cdot dx\)). The first thing we must do is extract this \(J\) matrix.</p>
<p>Instead of providing a single combined matrix, the <code>mj_jacSite</code> function calculates the Jacobian Position (<code>jacp</code>) and the Jacobian Rotation (<code>jacr</code>) separately as 1D arrays. Since we are using the <code>Eigen</code> library for complex matrix operations in the next steps, we need to. convert these raw 1D C-style arrays into a proper 2D Eigen matrix.</p>
<p>Step 4: Computing the Inverse Matrix using DLS</p>
<pre><code class="language-cpp">    // ... rest of the code ...
    Eigen::MatrixXd lambda_matrix =
        Eigen::MatrixXd::Identity(6, 6) * (damping * damping);
    Eigen::MatrixXd J_inv =
        J.transpose() * (J * J.transpose() + lambda_matrix).inverse();
    // ... rest of the code ...
</code></pre>
<p>To find the joint changes (\(dq\)), we traditionally use the Moore-Penrose Pseudo-inverse:</p>
<p>Step 5: Virtual Integration and Forward Kinematics</p>
<pre><code class="language-cpp">    // ... rest of the code ...
    mj_integratePos(m, d-&gt;qpos, dq.data(), step_size);
    mj_forward(m, d);
    // ... rest of the code ...
</code></pre>
<p>Once we obtain the required joint changes (<code>dq</code>), we must apply them to our robot. However, applying the full change all at once can lead to inaccuracies. To minimize the error as much as possible, we need a process of iterative refinement—a method fundamentally identical to how Artificial Intelligence (AI) optimizes models.</p>
<p>Just like Gradient Descent in AI, we take small, iterative steps instead of one massive leap. We use the <code>mj_integratePos</code> function to update the virtual joint positions (<code>d-&gt;qpos</code>) by adding a fraction of <code>dq</code>.</p>
<p>After taking a small step, we call <code>mj_forward</code> to update the forward kinematics. This allows us to check the new position of the end-effector in the virtual space. We repeat this process—stepping and checking—until the error is minimized below our target tolerance.</p>
<p>Step 6: Finalizing the Solution and Restoring Physics</p>
<pre><code class="language-cpp">      // ... rest of the code ...
      Eigen::VectorXd target_qpos = solve_ik(current_target_pos, attachment);

      for (int i = 0; i &lt; m-&gt;nu; ++i) {
        if (i == 6) continue;
        int joint_id = m-&gt;actuator_trnid[i * 2];
        int qpos_adr = m-&gt;jnt_qposadr[joint_id];
        d-&gt;ctrl[i] = target_qpos[qpos_adr];
      }
      // ... rest of the code ...
</code></pre>
<p>Finally, we have our solved joint positions (<code>target_qpos</code>). Now we must send these target angles to the actual motors to make the robot move. However, we cannot simply copy the array over. In MuJoCo, the control array (<code>ctrl</code>) and the position array (<code>qpos</code>) have different sizes and structures.</p>
<p>This requires a specific mapping process. Here is how we track down the correct index.</p>
<ul>
<li><p><code>m-&gt;nu</code> : The total number of actuators (motors). We loop through each one.</p>
</li>
<li><p><code>if (i == 6) continue;</code> : We skip the 6th actuator, which controls the gripper. The gripper is operated separately by our State Machine (open/close commands), not by the IK solver.</p>
</li>
<li><p><code>actuator_trnid</code> : This array tells us which physical joint is driven by the current motor.</p>
</li>
<li><p><code>jnt_qposadr</code> : Once we know the joint ID, this array gives us the exact starting address of that joint's data inside the massive <code>qpos</code> array.</p>
</li>
</ul>
<p>By tracing this path, we extract the exact target angle for each specific joint from our <code>target_qpos</code> and feed it into the <code>d-&gt;ctrl</code> array. The physics engine then takes over, applying the necessary forces to smoothly drive the robotic arm to the target position. You can see the final result of this entire process in the video below and find the <a href="https://github.com/RustSynx/robot-simulation/tree/main/example/pick_and_place_2">complete simulation source</a> on my GitHub.</p>
<img src="https://cdn.hashnode.com/uploads/covers/697a014233686646a792dd2d/c05966fb-8202-452b-a31a-aac2a81fe058.gif" alt="" style="display:block;margin:0 auto" />]]></content:encoded></item><item><title><![CDATA[[Paper Review] Robot Operating System 2: Design, Architecture, and Uses In The Wild]]></title><description><![CDATA[Brief Summary
This paper explains the ROS 2 framework, which provides essential components for robotics development environments. It also introduces real-world case studies to demonstrate how ROS 2 ca]]></description><link>https://blog.miloarchive.com/paper-review-robot-operating-system-2-design-architecture-and-uses-in-the-wild</link><guid isPermaLink="true">https://blog.miloarchive.com/paper-review-robot-operating-system-2-design-architecture-and-uses-in-the-wild</guid><category><![CDATA[ros2]]></category><category><![CDATA[robotics]]></category><category><![CDATA[Paper Review]]></category><category><![CDATA[robot-operating-system]]></category><category><![CDATA[DDS ]]></category><category><![CDATA[Ubuntu]]></category><dc:creator><![CDATA[Milo]]></dc:creator><pubDate>Sun, 08 Mar 2026 13:24:56 GMT</pubDate><content:encoded><![CDATA[<h3>Brief Summary</h3>
<p>This paper explains the ROS 2 framework, which provides essential components for robotics development environments. It also introduces real-world case studies to demonstrate how ROS 2 can be utilized and what makes it so useful.</p>
<h3>Motivation</h3>
<p>It is almost impossible to discuss modern robotics development without mentioning ROS 2. As an open-source platform, it has a dominant market share compared to other robot operating systems. This is why I wanted to learn deeply about ROS 2. I firmly believe that properly mastering one foundational robot OS will help me easily adapt to other development environments, and even build a strong foundation if I ever design a new robot OS in the future.</p>
<h3>Key Takeaways</h3>
<p>This paper offers a comprehensive breakdown of ROS 2. First, it introduces the background of ROS 2 and highlights the key differences and improvements over ROS 1. Then, it dives into specific topics: scope, design principles, design requirements, communication patterns, middleware architecture, software quality, performance, reliability, and security. Notably, the paper provides benchmarking test data in the performance section, offering a clear visual representation of its capabilities. Finally, it presents real-world use cases, showing ROS 2 as an enabler, an equalizer, and an accelerator in the robotics industry.</p>
<h3>Personal Insights</h3>
<p>From a current perspective, ROS 2 is undoubtedly an excellent framework. However, if I had to point out one downside, it would be its practical reliance on Ubuntu. It is not that you cannot develop on Windows or macOS, but the limitations are quite clear. This practical limitation feels a bit disappointing.</p>
<h3><strong>Reference</strong></h3>
<ul>
<li><a href="https://arxiv.org/abs/2211.07752">Robot Operating System 2: Design, Architecture, and Uses In The Wild</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Implementation of a Pick-and-Place Task with a 6-Axis Robot]]></title><description><![CDATA[Related Post:

Exploring Robotic Dynamics with MuJoCo: 2-DOF Modeling

Exploring Robotic Dynamics with MuJoCo: Calculating 3-DOF coordinates


In this post, I will demonstrate a simple pick-and-place ]]></description><link>https://blog.miloarchive.com/implementation-of-a-pick-and-place-task-with-a-6-axis-robot</link><guid isPermaLink="true">https://blog.miloarchive.com/implementation-of-a-pick-and-place-task-with-a-6-axis-robot</guid><category><![CDATA[MuJoCo]]></category><category><![CDATA[C++]]></category><category><![CDATA[dynamics]]></category><category><![CDATA[robotics]]></category><category><![CDATA[kinematics]]></category><dc:creator><![CDATA[Milo]]></dc:creator><pubDate>Sun, 01 Mar 2026 10:31:23 GMT</pubDate><content:encoded><![CDATA[<p><strong>Related Post:</strong></p>
<ul>
<li><p><a href="https://blog.miloarchive.com/exploring-robotic-dynamics-with-mujoco-2-dof-modeling">Exploring Robotic Dynamics with MuJoCo: 2-DOF Modeling</a></p>
</li>
<li><p><a href="https://blog.miloarchive.com/exploring-robotic-dynamics-with-mujoco-calculating-3-dof-coordinates">Exploring Robotic Dynamics with MuJoCo: Calculating 3-DOF coordinates</a></p>
</li>
</ul>
<p>In this post, I will demonstrate a simple pick-and-place operation using a UR5e robotic arm. The sequence follows a standard workflow: starting from the home position, moving to the red box, grasping it, transferring it to the target location, and finally releasing it.</p>
<p>Since the UR5e features the updated offset wrist design (unlike older models), I performed some calibration for accuracy. However, please note that there is still a slight margin of error in the final movements.</p>
<p>This image below</p>
<img src="https://cdn.hashnode.com/uploads/covers/697a014233686646a792dd2d/29e91d13-8e78-4016-9482-1d898f311bf5.png" alt="" style="display:block;margin:0 auto" />

<p>The image above shows the robot's home position. First, we calculate \(\theta_1\) using the base and target coordinates. During this step, a calibration is applied based on Link 5, which serves as the virtual wrist center. Then, \(\theta_2\) and \(\theta_3\) are derived using the Law of Cosines, with a slight compensation applied to the height value.</p>
<p>After moving to the calculated position and grasping the box, the next coordinates are re-calculated using the same method for the transfer and release. Throughout the process, the state of each step is recorded, and subsequent commands are executed based on the displacement and the gripping force.</p>
<p>Below is an animation demonstrating the full pick-and-place workflow.</p>
<img src="https://cdn.hashnode.com/uploads/covers/697a014233686646a792dd2d/a36a6342-2e88-4652-b6ed-d8b1ce580998.gif" alt="" style="display:block;margin:0 auto" />

<h3>Post-Implementation Review</h3>
<p>Since the UR5e doesn't have the traditional wrist design, I had to spend quite a bit of time studying and applying various calibrations. While the results weren't perfectly precise, it was a deeply rewarding experience because I learned so much by tackling the challenges head-on.</p>
<p>You can find the complete simulation source code <a href="https://github.com/RustSynx/robot-simulation/tree/main/example/pick_and_place"><strong>here</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Exploring Robotic Dynamics with MuJoCo: Calculating 3-DOF coordinates]]></title><description><![CDATA[Related Post:

Exploring Robotic Dynamics with MuJoCo: 2-DOF Modeling

In this session, to handle a 6-DOF robot, we will first learn about calculating 3-DOF coordinates. This practice will help us und]]></description><link>https://blog.miloarchive.com/exploring-robotic-dynamics-with-mujoco-calculating-3-dof-coordinates</link><guid isPermaLink="true">https://blog.miloarchive.com/exploring-robotic-dynamics-with-mujoco-calculating-3-dof-coordinates</guid><category><![CDATA[C++]]></category><category><![CDATA[MuJoCo]]></category><category><![CDATA[dynamics]]></category><category><![CDATA[robotics]]></category><category><![CDATA[kinematics]]></category><dc:creator><![CDATA[Milo]]></dc:creator><pubDate>Sun, 22 Feb 2026 13:08:08 GMT</pubDate><content:encoded><![CDATA[<p><strong>Related Post:</strong></p>
<ul>
<li><a href="https://blog.miloarchive.com//exploring-robotic-dynamics-with-mujoco-2-dof-modeling">Exploring Robotic Dynamics with MuJoCo: 2-DOF Modeling</a></li>
</ul>
<p>In this session, to handle a 6-DOF robot, we will first learn about calculating 3-DOF coordinates. This practice will help us understand how to move the robot. We will fix 3 axes and manipulate the other 3, because starting with full 6-DOF control might be difficult to understand.</p>
<p>This image below shows robot's initial position. We will keep axes 4, 5, and 6 fixed at 0 degrees, and use axes 1, 2, and 3 to move the robot arm toward the target, the red ball.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/697a014233686646a792dd2d/f88f2acd-383f-4aee-8f63-39c28e34b7ae.png" alt="" style="display:block;margin:0 auto" />

<p>First, looking at the robotic arm and the target point from a top-down view, we will calculate how much the arm needs to rotate to face the target. Second, just as we did with the 2-axis robot, we will calculate the angles for axes 2 and 3 using the law of cosines. Below is the source code for the calculation process based on the UR5e.</p>
<pre><code class="language-cpp">JointAngles InverseKinematics::solve_ik_3dof(double x, double y, double z) {
  // First link length
  const double L1 = 0.425;
  // Second link length
  const double L2 = 0.392;
  joint_angles.theta1 = std::atan2(y, x);

  // The horizontal distance from the base link to the target.
  double r = std::sqrt(x*x + y*y);
  // The vertical distance from the base link to the target, adjusting for the base link's height.
  double r_v = z - 0.163;
  // The distance from the base link to the target.
  double d = std::sqrt(r*r + r_v*r_v);
  double cos_ratio = (d*d - L1*L1 - L2*L2) / (2*L1*L2);

  if (cos_ratio &gt; 1.0) cos_ratio = 1.0;
  if (cos_ratio &lt; -1.0) cos_ratio = -1.0;

  joint_angles.theta3 = std::acos(cos_ratio);

  // The angle between L1 and the line from the base link to the target.
  double inner_angle_1 = std::acos((L2*L2 - d*d - L1*L1) / (2*L1*d));
  // The angle of elevation to the target.
  double inner_angle_2 = std::atan2(z-0.163, r);
  joint_angles.theta2 = inner_angle_1 + inner_angle_2;
  return joint_angles;
}
</code></pre>
<p>Next, here is the simulation result.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/697a014233686646a792dd2d/ec419a7b-8e81-44c8-b7f4-968125b7f55b.gif" alt="" style="display:block;margin:0 auto" />

<h3>Summary</h3>
<p>Before diving into the full robotic arm control, I ran into a simple simulation using only three degrees of freedom (3-DOF). You can find the complete simulation source code <a href="https://github.com/RustSynx/robot-simulation/tree/main/example/3dof_control">here</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Exploring Robotic Dynamics with MuJoCo: 2-DOF Modeling]]></title><description><![CDATA[In this post, we’re going to dive into a simple simulation of a 2-DOF robot using MuJoCo.
Before we get into complex robot manipulation, it’s essential to understand the fundamentals of how to get a robot to a desired location. We will focus on a str...]]></description><link>https://blog.miloarchive.com/exploring-robotic-dynamics-with-mujoco-2-dof-modeling</link><guid isPermaLink="true">https://blog.miloarchive.com/exploring-robotic-dynamics-with-mujoco-2-dof-modeling</guid><category><![CDATA[MuJoCo]]></category><category><![CDATA[C++]]></category><category><![CDATA[robotics]]></category><category><![CDATA[dynamics]]></category><category><![CDATA[kinematics]]></category><dc:creator><![CDATA[Milo]]></dc:creator><pubDate>Sun, 15 Feb 2026 15:17:16 GMT</pubDate><content:encoded><![CDATA[<p>In this post, we’re going to dive into a simple simulation of a 2-DOF robot using MuJoCo.</p>
<p>Before we get into complex robot manipulation, it’s essential to understand the fundamentals of how to get a robot to a desired location. We will focus on a straightforward simulation: moving the robotic arm from its current state to a specific target coordinate.</p>
<p>If we know the target coordinates and the robot’s current position, we can calculate exactly how the arm needs to move to reach that point. This method is called Inverse Kinematics (IK).</p>
<p>Conversely, if we already know the specific angles for each joint and want to calculate where the robot’s end-effector will end up, that process is called Forward Kinematics (FK).</p>
<p>In this first scenario, we will explore how to use Inverse Kinematics to calculate the required joint angles within a 2D XY coordinate system. Fortunately, in this planar setup, we can determine the angle for each joint simply by applying the Law of Cosines.</p>
<p>First, let’s establish our known variables: the robot’s base position, the link lengths, and the target coordinates.</p>
<p>For this simulation, we will define the robot’s base at the origin (0,0) and set the length of each link (joint) to 20cm. The target destination is set to x = 10cm and y = 30cm.</p>
<ol>
<li>Calculate the distance to the target (\(r\))</li>
</ol>
<p>$$r^2 = x^2+y^2$$</p><p> $$ r^2=10^2+30^2=100+900=1000$$</p>
<ol start="2">
<li>Solve for Joint 2 (\(\theta_2\)) using the Law of Cosines</li>
</ol>
<p>$$r^2 = L_1^2 + L_2^2 - 2L_1L_2\cos(180^\circ - \theta_2)$$</p><p>$$1000 = 20^2 + 20^2 - 2(20)(20)\cos(\pi - \theta_2)$$</p><p>$$1000 = 400 + 400 - 800\cos(\pi - \theta_2)$$</p><p>$$200 = -800\cos(\pi - \theta_2)$$</p><p>$$\cos(\pi - \theta_2)=-cos(\theta_2) = -0.25$$</p><p>$$\theta_2 = \arccos(0.25) \approx \mathbf{1.318 \text{ rad}}$$</p><ol start="3">
<li>Solve for Joint 1 (\(\theta_1\))</li>
</ol>
<p>$$\phi = \arctan(\frac{30}{10}) \approx 1.249 \text{ rad}$$</p><p>Although we could calculate this angle using arccos(x/r), the cosine function cannot differentiate between “up” (+y) and “down” (-y). It would return the same positive angle for both (10,30) and (10,-30). By using arctan, we preserve the sign information, allowing the robot to navigate the full \(360^\circ\) range.</p>
<p>$$\alpha = \frac{\theta_2}{2} \approx 0.659 \text{ rad}$$</p><p>$$\theta_1 = \phi - \alpha$$</p><p>$$ \theta_1 = 1.249 - 0.659 \approx \mathbf{0.590 \text{ rad}}$$</p><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771166634530/c3e00147-f0f2-4439-8ace-29bc01074c30.png" alt class="image--center mx-auto" /></p>
<p>The figure above visualizes the calculation process to aid your understanding.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771167720515/b45afc4c-25da-4658-a26c-45797391ab72.gif" alt class="image--center mx-auto" /></p>
<p>The video above shows a simple simulation of the scenario using MuJoCo. In this demo, I simply hardcoded the calculated values. You can press the Spacebar to start the simulation.</p>
<h2 id="heading-summary"><strong>Summary</strong></h2>
<p>In this post, we explored the basics of Inverse Kinematics and calculation methods using a simple 2-DOF robot, followed by a simulation in MuJoCo.</p>
<p><a target="_blank" href="https://gist.github.com/RustSynx/90b80f6f03141728bf093250a0276d14"><strong>The full code is available here.</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[Elasticity & Safety: From Hooke’s Law to Smart Design]]></title><description><![CDATA[What would happen if we couldn't predict how much weight a bridge could support? We would either be unable to build it at all or, worse, it could collapse under heavy traffic. To prevent such disasters, we must be able to quantify and predict how mat...]]></description><link>https://blog.miloarchive.com/elasticity-and-safety-from-hookes-law-to-smart-design</link><guid isPermaLink="true">https://blog.miloarchive.com/elasticity-and-safety-from-hookes-law-to-smart-design</guid><category><![CDATA[engineering]]></category><category><![CDATA[Materials Science]]></category><category><![CDATA[learning]]></category><category><![CDATA[mechanics]]></category><category><![CDATA[Matlab]]></category><dc:creator><![CDATA[Milo]]></dc:creator><pubDate>Sun, 08 Feb 2026 02:06:19 GMT</pubDate><content:encoded><![CDATA[<p>What would happen if we couldn't predict how much weight a bridge could support? We would either be unable to build it at all or, worse, it could collapse under heavy traffic. To prevent such disasters, we must be able to quantify and predict how materials react to external forces. This process is mathematically formulated through <strong>Hooke’s Law</strong>.</p>
<h3 id="heading-modeling-normal-stress-axial-loading"><strong>Modeling Normal Stress (Axial Loading)</strong></h3>
<p>Normal stress occurs when a force acts perpendicular to a material's cross-section, causing it to stretch or compress.</p>
<p>$$\sigma = E\epsilon$$</p><ul>
<li><p>\(\sigma\) (Normal Stress): The intensity of internal force per unit area.</p>
</li>
<li><p>\(E\) (Young’s Modulus): A fundamental material property representing its resistance to elastic deformation.</p>
</li>
<li><p>\(\epsilon\) (Normal Strain): The ratio of deformation relative to the original length.</p>
</li>
</ul>
<h3 id="heading-modeling-shear-stress-torsional-loading">Modeling Shear Stress (Torsional Loading)</h3>
<p>While normal stress involves stretching, shear stress involves sliding or twisting forces acting parallel to the surface.</p>
<p>$$\tau = G\gamma$$</p><ul>
<li><p>\(\tau\) <strong>(Shear Stress):</strong> The force per unit area acting parallel to the surface.</p>
</li>
<li><p>\(G\) <strong>(Shear Modulus):</strong> The material's resistance to shape change, also known as rigidity.</p>
</li>
<li><p>\(\gamma\) <strong>(Shear Strain):</strong> A measure of the angular deformation (how much the object has been tilted or twisted).</p>
</li>
</ul>
<h2 id="heading-poissons-ratio-nu">Poisson's Ratio (\(\nu\))</h2>
<p>Next is <strong>Poisson's ratio</strong>(\(\nu\)). It serves as a fundamental <strong>measure of volumetric change</strong> and is a key parameter in determining a material's <strong>stiffness</strong>. The following formulas define the strain ratios <strong>under tensile loading</strong>, where the material is elongated along its axis:</p>
<h3 id="heading-sectional-strain-epsilonarea">Sectional Strain (\(\epsilon_{area}\))</h3>
<p>This represents the ratio of the change in cross-sectional area to the original area.</p>
<p>ϵarea=ΔAA≈−2νϵ (where ϵ&gt;0 denotes the axial tensile strain)</p>
<h3 id="heading-volumetric-strain-epsilonv">Volumetric Strain (\(\epsilon_v\))</h3>
<p>This is the ratio of the change in volume to the original volume. A Poisson's ratio of <strong>0.5</strong> implies that the material is <strong>incompressible</strong>, resulting in zero volumetric strain.</p>
<p>$$\epsilon_v = \frac{\Delta V}{V} = \epsilon (1 - 2\nu)$$</p><h4 id="heading-shear-modulus-g"><strong>Shear Modulus (</strong>\(G\)<strong>)</strong></h4>
<p>The Shear Modulus relates the shear stress to the shear strain.</p>
<p>$$G = \frac{E}{2(1+\nu)}$$</p><h4 id="heading-bulk-modulus-k"><strong>Bulk Modulus (</strong>\(K\)<strong>)</strong></h4>
<p>The Bulk Modulus measures a substance's resistance to uniform compression.</p>
<p>$$K = \frac{E}{3(1-2\nu)}$$</p><p>The graph below illustrates the variation of G and K with respect to Poisson’s ratio using MATLAB.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770513694679/953753a6-a280-40fa-a88f-723308fea88f.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-summary">Summary</h2>
<p>In this post, we explored Hooke’s Law and Poisson’s ratio, specifically focusing on how \(G\) and \(K\) each relate to Poisson’s ratio.</p>
<p><a target="_blank" href="https://gist.github.com/RustSynx/133034b9b86aefc9646fff1ee61500cd">The full code is available here.</a></p>
]]></content:encoded></item><item><title><![CDATA[Why Do Materials Deform? Visualizing Stress and Strain with MATLAB]]></title><description><![CDATA[When designing bridges or mechanical components, how can we ensure they won’t deform or fail? To answer this, we must first understand the forces at play. Let’s dive into the types of loads first.
Loads are primarily classified into static loads and ...]]></description><link>https://blog.miloarchive.com/visualizing-stress-strain-matlab</link><guid isPermaLink="true">https://blog.miloarchive.com/visualizing-stress-strain-matlab</guid><category><![CDATA[Matlab]]></category><category><![CDATA[Materials Science]]></category><category><![CDATA[learning]]></category><category><![CDATA[engineering]]></category><category><![CDATA[mechanics]]></category><dc:creator><![CDATA[Milo]]></dc:creator><pubDate>Sun, 01 Feb 2026 12:44:30 GMT</pubDate><content:encoded><![CDATA[<p>When designing bridges or mechanical components, how can we ensure they won’t deform or fail? To answer this, we must first understand the forces at play. Let’s dive into the types of loads first.</p>
<p>Loads are primarily classified into <strong>static loads</strong> and <strong>dynamic loads</strong>. First, <strong>static loads</strong> are forces applied slowly that remain constant over time.</p>
<ul>
<li><p><strong>Normal Load</strong>: A force acting perpendicular to a surface, such as a book resting on a table.</p>
</li>
<li><p><strong>Shear Load</strong>: A force causing layers of a material to slide past one another, like the action of scissors.</p>
</li>
</ul>
<p>In contrast, <strong>dynamic loads</strong> are forces that vary with time.</p>
<ul>
<li><p><strong>Repeated Load</strong>: A load applied repeatedly in a single direction, typically varying in magnitude.</p>
</li>
<li><p><strong>Alternating Load</strong>: A load that cycles between opposite directions.</p>
</li>
<li><p><strong>Impact Load</strong>: A sudden, high-force load applied over a very short period.</p>
</li>
</ul>
<p>Now, let’s look at Stress and Strain. <strong>Stress</strong> is defined as the force acting per unit area. Essentially, it represents the intensity of the internal force distributed within the material. <strong>Strain</strong> describes the deformation resulting from that stress. It is defined as the ratio of the change in dimension to the original dimension.</p>
<p>The graph below shows a stress-strain diagram generated from a MATLAB simulation of a mild steel tensile test. <strong>Note that</strong> the data has been slightly modified for educational purposes to make it easier to understand.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769931112289/4b44f5da-ee32-4b88-bbd0-00cdd23f613a.gif" alt="Stress-Strain Curve Simulation" class="image--center mx-auto" /></p>
<ul>
<li><p><strong>Elastic Region</strong>: The initial phase up to the Upper Yield Point. This point is the peak stress before the transition to plastic deformation.</p>
</li>
<li><p><strong>Yield Drop &amp; Plateau Region</strong>: After the stress drops to the Lower Yield Point, the Yield Plateau Region begins. Here, strain increases significantly with constant or fluctuating stress.</p>
</li>
<li><p><strong>Strain Hardening Region</strong>: Stress begins to rise again until it reaches the peak, known as the Ultimate Tensile Strength (UTS).</p>
</li>
<li><p><strong>Necking Region &amp; Fracture</strong>: Beyond the UTS, the material enters the Necking Region, where it deforms under less force until final fracture occurs.</p>
</li>
</ul>
<h2 id="heading-summary">Summary</h2>
<p>In conclusion, materials deform because the internal stress caused by external loads exceeds the material's limits. This is why plotting the stress-strain curve is so important—it allows us to make more informed decisions when selecting materials for our structural designs.</p>
<p><a target="_blank" href="https://gist.github.com/RustSynx/51dbf9489eccb4042a70f5564c263cae">The full code is available here.</a></p>
]]></content:encoded></item></channel></rss>