I decided to make a write up specifically just for the principles of RL because I have found that when I am working with RL problems, if I am able to intuitively adjust the training process I get much better results. This intuition is often quite hard to get from plain research papers or textbook definitions so I hope the way I explain concepts here and the interactive figures I've added go above and beyond those resources in helping you have that "ah ha, I get it" moment.
To keep things concrete throughout this article, I'll often refer to a 7-DOF robot arm and gripper (like the Franka arm in Part I: Building a Robot Brain) as a running example for applying concepts to it. I've also highlighted key RL/robotics terminology with dashed underlines so you can hover over (or tap) any highlighted term to view its meaning inline.
in robotics requires knowledge of classical control theory, deep learning optimization via , physics simulation, and of course, lots of math. In most engineering contexts, these disciplines would have their own dedicated specialists. But to train a robot to perform a task well, all of these concepts must be brought together in a single, coherent system. This is the job of a robotics RL engineer. And let me tell you upfront, it is quite complex.
So in this write-up I'll try my best to teach you the different components of a robotics RL system, how they interact, and which specific things you can tweak to change the behavior. If I've done my job well, you should be able to look at a training run that is going badly and form a real hypothesis about why, instead of changing a random number and hoping.
But first, let's do some fun stuff. Let's do a live demo!
Click Train to start the simulation. You can drag the target dot anywhere in the circle to test reaching in real time, tweak the sliders to see how learning rate or entropy affect stability, or flip the truncation bug switch to see what happens when timeouts are mishandled. The green shaded bands mark healthy diagnostic ranges.
This simulation is running a real RL training algorithm (Proximal Policy Optimization) in a Web Worker on your machine—nothing is pre-recorded. In the rest of the article, we'll break down exactly what's happening under the hood to make that work.
The Anatomy of a Robot Brain
In reinforcement learning, the robot's decision-making strategy is called its policy (). At a conceptual level, a policy is just a mathematical function that answers a simple question: "Given what the robot senses right now, what action should it take?"
Because a physical robot moves through continuous 3D space with infinite possible joint positions, velocities, and sensor readings, we cannot store decisions in a discrete lookup table or hardcode them with rules. Instead, modern robotics RL uses deep neural networks as function approximators. Their adjustable numerical allow the robot to smoothly generalize its motor skills across states it has never seen before.
"Neural network" is a broad umbrella term that encompasses everything from massive Vision Transformers to convolutional image networks. If you don't know what those are right now, that's fine, just know they are variants. I am going to keep it simple in this write-up and focus on a single variant to illustrate the core principles of robotics RL.
The Dual-MLP Architecture
An MLP (Multi-Layer Perceptron) is the workhorse of robotics RL. It is a fully-connected feedforward network. This means all the nodes in each layer are all connected to the nodes in the next layer. Actions happen by the network from propagating calculations from left to right (feeding the input forward through the network). The linear node layers are separated by non-linear activation functions (like Tanh or ELU) so the network is able to learn non-linear properties from its inputs. If textual explanations aren't helpful for you (they're not for me), check the figure below.
Dense multi-layer perceptron
all-to-all connectivity
Every neuron in a layer connects to every neuron in the next, each edge carrying its own weight. The input is a flat vector with no assumed structure, which is exactly what a list of joint angles and velocities is. Switch to “run a pass” to push real numbers through a small one and watch the gradient come back.
Joint encoders, velocities, and coordinate targets — the default for proprioception.
No structural assumptions to get wrong on unstructured physical state.
Parameter count scales with input size, so raw images are hopeless.
This neural network isn't as much of a mysterious black box as many people make it out to be. It's just a structured pipeline of floating-point numbers:
- Inputs: At any instant , the network receives a clean snapshot of the robot's physical body. For example, node 1 might get the joint 1 rotational velocity, node 2 might get the gripper position, and so on. Each node has a fixed input assignment across all timestamps.
- Weights and Biases: A weight is a floating point number that scales the signal traveling along a connection between two neurons. As such, the weights are assigned to the edges of the network graph. In a 30x512 MLP all 30 input nodes connect to all 512 layer 2 neurons, so these connections form a 2D table (a weight matrix) where each row describes a node and each column is used to store the values for its edges that connect to another node. A bias on the other hand is a floating point number which represents a baseline offset attached to the neuron itself. Biases are not on input nodes but they are included on all layers after that, including the output layer. To store this we can just simply use a 1D vector whose size is equal to the number of nodes in the corresponding layer.
- The Squashing Functions: If you just multiply inputs by weights and add biases, stacking 100 linear layers is mathematically identical to 1 layer () so adding new layers adds no benefit and your network is not able to learn complex non-linear behavior. Non-linear activation functions like Tanh (which is really just an s-curve) are used to squish values into some range non-linearly. For Tanh this is . The simple fact that the tanh is an s-curve instead of a straight line gives the network the mathematical curvature needed to learn complex behaviors. Its such a simple concept but it is one of the most impactful discoveries in Machine Learning.
- Neuron Calculations & Activations: Every hidden neuron calculates its output in two simple steps. First, it computes an internal "pre-activation" by multiplying incoming inputs by their edge weights and adding its bias (). Second, right before that value leaves the neuron, its passed to the squashing function (). That final squashed output is what we call the neuron's layer.
Proximal Policy Optimization (PPO) is what I will mainly be discussing in this article. It is a reinforcement learning algorithm which uses two completely separate MLPs. One is used as an "Actor" and one is a "Critic". The Actor drives the robot and decides actions to take while the Critic evaluates how good the Actor's decisions turned out.
Takes sensory observations (joint angles, velocities, target goals) and outputs physical motor actions (target position setpoints). This is the network that actually drives the robot, and when training is complete, it is the only network deployed to real hardware.
Takes sensory observations and predicts a single scalar number for the expected cumulative reward () the robot will collect from that state forward. It acts as a training baseline to determine whether the Actor's choices turned out better or worse than expected. Once training is done, the Critic is discarded.
In this setup, the Actor has its own weights to command joint movements, and the Critic has its own weights to predict expected rewards.
Keeping the two networks completely separate is standard practice in robotics because they are optimizing for two different things. The Critic tries to accurately predict reward scores, while the Actor learns to control the robot smoothly. If they shared layers, large error corrections from a mispredicted score could easily drown out the subtle shifts the Actor needs for precise motor control.
The Multi-Rate Execution Loop
In robot reinforcement learning, control is almost always split across two distinct frequencies: a low-frequency policy loop (typically 20 to 50 Hz) where the neural network evaluates sensor data and makes decisions, and a high-frequency physics and control loop (500 to 1000 Hz) where the motors and contact dynamics are managed.
While a single clock would be simpler, it isn't usually a viable option. The system has incompatible timing requirements:
- The physics and motors must run fast (500+ Hz): Resolving stiff contacts, friction transitions, and joint damping requires sub-millisecond numerical integration. If motor feedback is evaluated too slowly, the discrete solver overshoots the contact constraint, corrects, overshoots again, and the joint chatters.
- The neural network cannot run that fast (20–50 Hz max): Polling hardware buses, normalizing observation vectors, synchronizing camera frames, and computing forward passes through deep networks takes time. A 500 Hz loop imposes a strict 2-millisecond hard deadline. Even with a high-end GPU, most networks cannot reliably finish in that time window.
Because the AI brain updates at 20 Hz while the physical motors require updates at 500 Hz, the trained policy cannot be used to command raw motor torques directly. Doing so would mean holding a static torque for 50 milliseconds, leaving the robot uncontrolled between decisions. On top of that, asking a neural network to calculate raw torques forces it to learn the robot's mass matrix, gravity compensation, and joint inertia from scratch which complicates the training.
Instead, the policy outputs target positions (or velocity deltas), and a deterministic running at 500 Hz works to get the joint to that target until the next policy decision arrives. With this setup the PD controller acts as a sort of virtual spring-damper, pulling the joints to where they need to be while (ideally) not overshooting and causing jitter.
The dashed line is the 50 ms policy setpoint; the solid line is the joint driven across 25 PD substeps. Try dropping the policy rate to 5 Hz to see the staircase get coarser while the joint still tracks smoothly, or set kd to zero to watch undamped spring oscillations.
Collecting Experience in the Simulation
So now you know about the actor and the critic networks, and you know their operating frequency. We can now look at the broader training loop. RL training alternates between two distinct phases: and .
During simulation training, each step of this collection cycle follows a fixed sequence:
- Initialize: The environment initializes the robot to a valid starting state and randomizes physical parameters like payload masses, joint friction, surface contact properties, and visual lighting. (We explored tuning these parameter distributions to fix visual overfitting in Part II: Hardening the Robot Brain). This forces the policy to learn motor behaviors that work beyond idealized simulation.
- Observe & Normalize: The policy receives raw data along with target task goals. Because angular velocities ( rad/s) and sub-millimeter position offsets ( m) operate on vastly different numerical scales, a running filter normalizes each observation channel to before network evaluation.
- Action Decision & Baseline Evaluation: The actor network uses the sensor data and chooses a target movement (the setpoint ), with an extra bit of random exploration noise to help it discover new strategies. At the same time, the critic network generates a baseline score guess representing how much total reward the robot is expected to earn from this state. The Actor's action is then dispatched to the low-level controller.
- Physics Sub-Stepping & Environment Step: The robot executes the movement. The low-level PD controller holds the target setpoint while stepping the physics engine (for example, 25 micro-steps at 500 Hz to fill one 20 Hz decision window, as described above). The simulator then returns the robot's new state , an immediate reward score for the action, and a flag indicating if the task completed or failed. The reward is something that you setup manually (more on that later) and is calculated based on the state of the simulation and how close it is to what you want it to be.
- Saving the Experience: The information about what the robot saw , what action it took , the reward it earned , and the critic's baseline prediction is saved into a in GPU memory.
How to Train 4,096 Robots in a Single Matrix Operation
RL training takes a lot of episodes to get the robot to do what you want it to do. You can just train it sequentially on your CPU if you want but its so slow that its impractical. Most serious modern RL training tends to use parallelization on GPU(s). This allows you to go from training 1 robot at a time to training 4,096 robots all at the same time. If you're training 4,096 robots at the same time in simulation, you might wonder: do we need 4096 copies of the neural network or do we loop through the robots one by one to find out what the neural net says that robot should be doing?
Neither. In GPU memory, there is only one single set of network weights (). Instead of a slow iterative loop, the simulator stacks all 4,096 robot state vectors into a single 2D table called a Tensor (specifically, an matrix with dimensions ). Assuming you have 30 input items e.g. joint velocity, position, etc. It uses this single shared "brain" to control all robots simultaneously.
The GPU then computes a single matrix multiplication:
When it's time to update the network, the backward pass does the exact same thing in reverse: multiplying the transposed inputs against the error tensor combines all 4,096 robot error vectors into one single consensus gradient matrix () without ever looping row by row or making copies of the network.
Tap or hover a robot's row, a weight, or an output number to see what it touches.
A Deeper Look Into Learning
Once the parallel simulators finish gathering data from running their episodes, data collection stops and the optimization phase begins. At this point the GPU now holds a full rollout buffer containing tens of thousands of recorded state tuples: what the robot saw , what action it took , the immediate reward it received , the critic's baseline prediction , and whether the step terminated .
That buffer cannot go straight into the optimization process just yet though. Immediate rewards say almost nothing about whether an action was good in the big picture. A gripper that opens at step 10 may not collect any reward on that tick, but that open gripper is the only reason another grasping action 30 steps later is even possible.
Before updating any weights in the network, we need to pass the entire rollout buffer through a two-stage optimization workflow:
- Compute Advantages: We use a process known as Generalized Advantage Estimation (GAE) to give us some additional data to help optimize our network. GAE computes a refined score (for the Actor) and a score (as the answer key for the Critic) for every recorded step. Each of these values are saved directly into the rollout buffer. The advantage score is used to tell the Actor which actions actually worked, and the value target is to teach the Critic what total score it should have predicted.
- Optimize Networks (PPO): Once the rollout buffer is fully enriched with advantage scores and value targets, the training loop enters the optimization phase. We can't push hundreds of thousands of recorded steps through backpropagation in a single giant push, so the optimizer shuffles the entire buffer randomly and slices it into smaller chunks called mini-batches (typically 4,096 steps each). Shuffling ensures each mini-batch contains a diverse mix of experiences to keep the robot "well-rounded." Without it, the network would train on thousands of nearly identical consecutive frames, becoming an expert at one tiny slice of the simulation while failing the rest of it. For each mini-batch, the GPU updates both the actor and critic networks in parallel. The Actor consumes the advantage scores () to nudge its movement targets toward winning movements, while the Critic consumes the value targets () to minimize its prediction error. Because simulating physics is computationally expensive, the optimizer makes 3 to 5 full passes (epochs) over the mini-batches to extract maximum learning before clearing the buffer and sending the robots back into simulation.
When computing advantages with GAE, you have two primary dials to tune.
- The Overall Task Horizon (): Dictates how far into the future the robot cares about rewards. At and a 20 Hz policy loop, the robot effectively plans roughly 5 seconds ( steps) ahead. Enough time to reach, grasp, and lift. If you set , the robot only looks 0.5 seconds ahead and becomes completely short-sighted. Set it to 1 and you essentially tell the robot time doesn't matter and you end up with a procrastinating robot that takes ages to do anything.
- The Sub-Action Credit Window (): Dictates how quickly credit decays backward between individual movements. In robotics, creates an effective credit window of about 1 to 2 seconds. Just long enough for an early wrist alignment to get credit for a successful grasp. If you set , credit dies in 250 ms which makes it hard to give credit to net good actions even if they were not recent. If you set , an early wrist rotation gets unfairly blamed for a random collision 400 steps later.
The Horizon Bug: Why Your Robot Suddenly Drops Everything
There is one notorious gotcha in GAE that trips up almost everyone who builds a custom simulation environment. In robotics, a failing simulation episode ends for two main reasons:
- Timeout (
truncated): The episode reached its time limit. The robot didn't do anything wrong per say, the clock just ran out. - Crash / Failure (
terminated): The robot dropped the object, collided with a table, threatened humanity, or did anything else you told it it can't do.
If your simulation environment code accidentally merges both into a single done = True flag, the math tells the robot that whatever it was doing when the timer expires has zero future
value. It could have been doing a perfectly acceptable, even desirable action, just ran out of time.
But the advantage that GAE gives you in this scenario is sharply negative since it "failed", and
GAE propagates that penalty backward into the past. From this your robot develops late-episode panic,
learning that whatever it was doing before when it ran out of time was a terrible idea and this
can frighten it into never taking the beneficial action you want it to take since it learned it
will get penalized heavily for it. The simple way out of this is to handle simulation success, failures,
and timeouts all as their own independent end states.
Click Run the backward pass to watch advantages calculate right-to-left. Move the sliders to see how γ extends the planning horizon and λ stretches credit decay arcs, or toggle truncated vs. terminated to see how zeroing V(s₁₄) on a timeout penalizes the entire trajectory without changing any underlying rewards.
What an Advantage Does to the Weights
In the previous section, we saw how GAE calculates an advantage score () for every single action recorded in our rollout buffer. But this brings up a fundamental question: how does a simple score actually reach inside the neural network and update its millions of internal weights?
To appreciate why this is tricky let's compare how standard supervised learning works (like training a computer vision model to spot cats). In supervised learning, you have an exact answer key. If the model predicts "dog" when the label says "cat," the error is straightforward: you subtract the prediction from the ground truth and tell the network exactly what it should have done instead.
In robotics reinforcement learning, there is no precise answer key. No supervisor is standing over the robot telling it: "at timestep 42, your elbow angle should have been precisely 47.3 degrees." All the robot gets is trial and error. To discover what works, the Actor network outputs a central baseline setpoint (). This is its current best guess for what the joint angles should be. It then adds a small amount of random exploration noise (a gentle "wobble") to pick the actual action () sent to the low-level controller.
Now suppose the robot wiggles its elbow a few degrees higher than its baseline and attempts a grasp. The simulation runs, and GAE evaluates the result, handing us an advantage score . If the grasp succeeded, is positive; if the arm crashed, is negative. How do we convert that signed scorecard into precise adjustments across all the layers of the network?
Diving Into Gradients and Backpropagation
This is where the concept of a gradient comes in. Earlier, we established that a neural network is a giant web of floating-point numbers called weights. You can think of each weight as a tiny adjustable knob. A gradient is simply a sensitivity measurement for one of those knobs: "If I turn this specific weight knob slightly to the right, how much does the network's output change, and in what direction?"
Calculating that sensitivity for a single knob connected to the output layer is easy. But modern robotics networks have hundreds of thousands, or millions, or even billions, of interconnected weight knobs spread across multiple deep layers. Adjusting a weight in the first layer ripples through every hidden neuron before finally affecting the joint motors at the output.
Figuring out how every single knob contributed to the final motor command is the job of . Because every neuron simply multiplies its inputs by weights and passes the sum through a smooth squashing function (like the Tanh activation we saw in Fig. 2), the entire network is mathematically differentiable. Backpropagation applies the calculus chain rule in a single, lightning-fast sweep backward from the output motors all the way to the input sensors. In that single backward pass, every single weight knob in the network receives its own gradient, showing precisely how much turning that knob will shift the output setpoint.
The Policy Gradient
Once backpropagation tells us how to steer the network's output, the policy gradient update ties the whole loop together. The update sent backward to adjust the Actor's baseline setpoint for a joint is remarkably intuitive:
Let's break down each piece of this relationship.
First, is the Actor's baseline setpoint for the current sensory state —what the network's current weights originally wanted to do. Second, is the actual exploratory action the robot executed after adding random noise. The difference between them, , represents the exploration offset: the exact direction and magnitude the robot wiggled (for example, higher on the elbow joint). Finally, is the advantage score from GAE, and the proportionality symbol () indicates that the size and direction of our weight adjustment scales directly with this product.
Look at how this product behaves in both scenarios:
When an exploratory movement succeeds, GAE gives it a positive advantage (). Multiplying a positive exploration offset by a positive advantage produces a positive update. Gradient descent turns the network's weight knobs so that next time the robot encounters this state, its baseline setpoint naturally shifts toward that exploratory angle. The robot has reinforced a winning habit.
Conversely, when an exploratory movement leads to a dropped object or collision, GAE assigns a negative advantage (). Multiplying that same positive offset by a negative number flips the sign of the update. The optimizer nudges the weights in the opposite direction, pushing the baseline setpoint away from that failed movement. Without anyone ever telling the robot what the perfect motor command was, trial-and-error combined with a signed scorecard nudges millions of parameters in the right direction.
This is where the parallel matrix design we looked at in Figure 4 comes back into play. For training at scale, rather than updating weights one robot at a time, the GPU computes this backward pass across all 4,096 simulation environments simultaneously. By multiplying the transposed state matrix against the advantage-weighted error tensor we turn thousands of independent trial-and-error experiments into one single consensus gradient matrix in fractions of a millisecond. It still feels a bit like magic to me.
Why We Need a Leash During Training
While this policy gradient formulation is remarkably powerful, it has a vulnerability: it is very easy to or over-react to a single batch of data.
If a robot gets lucky on a few rollouts and stumbles into a high reward by chance, an unconstrained gradient step might steer the network weights aggressively in that direction. Because neural network weights are interconnected, a large update intended to fix an elbow movement in one state can inadvertently destroy the shoulder stabilization skills the robot learned hours earlier. If you attempt to run multiple training passes over the same recorded batch, the policy rapidly overfits to that stale data, causing overall performance to crash catastrophically.
In early RL algorithms, the only solution was to take tiny, timid update steps and throw away expensive simulation data after a single pass. To make training fast, stable, and data-efficient, we need a way to apply these gradient updates while putting a strict mathematical leash on how far the policy is allowed to change. That brings us to the core engine of PPO.
Inside the PPO Optimization Engine
Earlier, when we outlined the two-stage optimization workflow, we noted that the optimizer makes 3 to 5 full passes (epochs) over the recorded simulation buffer before throwing it away. Let's dive into how we are able to do that without over-fitting or over-correcting.
In older reinforcement learning methods, you could only run one single gradient step (1 epoch) on your rollout buffer. The moment the network weights updated even once, the robot's brain changed, meaning the recorded experiences in the buffer were now "stale" (off-policy). If you ran a second gradient pass on that same data, the updated network would overfit to lucky anomalies, take an overly aggressive step, and catastrophically crash the robot's balance. Throwing away hundreds of thousands of expensive physics steps after just 1 gradient pass was slow and wasteful.
This is where gets its name. In Latin, proximus means "nearest" or "in close proximity." PPO places a strict mathematical leash on every gradient update, guaranteeing that the updated policy remains in the immediate neighborhood of the policy that gathered the data. This proximal leash is the exact mechanism that makes it safe to run 3 to 5 epochs of gradient descent on the same simulation data without the robot's policy collapsing.
PPO enforces this proximal leash by tracking the action probability ratio , which compares the updated policy's decisions against the old policy that recorded the buffer:
If , the updated policy is 15% more likely to take that action. If , it's 15% less likely. (Note: this ratio is completely separate from the environment reward ).
To keep the update within safe bounds, PPO clips this ratio inside a narrow trust window (typically , with ):
If an action succeeded () and its probability ratio reaches , the objective flattens: the gradient drops to zero and the optimizer stops pushing. This keeps the network from over-committing to what might have just been a lucky bounce. Meanwhile, the operator ensures the clipping is one-sided: if an update accidentally makes a good action less likely, it is never clipped, allowing full gradient flow to correct the mistake.
Adjust the exploration temperature or PPO clipping leash to see how high-advantage or over-clipped updates shape the distribution.
In production, the actor policy loss, critic regression, and an exploration bonus are combined into a single master objective:
The pays the robot to stay curious. Without it, a robot that earns a small reward for standing still might collapse its action distribution to near-zero variance early in training, locking into a mediocre strategy and never learning to walk.
The Secret Sauce to Making PPO Work
In the original PPO papers they make it seem like if you simply implement the clipped objective formula then badda-bing badda-boom you have a working robot policy. In practice, if you write a pure mathematical implementation of PPO and hit "train," your robot will almost certainly fail spectacularly.
As it turns out, a huge portion of PPO's real-world success and stability doesn't come from the loss equation alone. We also have a handful of critical low-level code implementation details that research studies have surfaced over the years. For our use-case, three specific engineering practices make a big difference here:
- Orthogonal Initialization: Think of a deep neural network as a chain of 4 or 5 audio amplifiers in a row. If each amplifier
multiplies the volume by , after 5 layers the sound is
screaming at volume, causing severe clipping
and distortion. If each amplifier multiplies by , after 5
layers the volume collapses to ,
essentially total silence. In a neural network, "signal variance" is simply this spread (or
volume) of numbers flowing through the layers.
If you initialize the network with random weights, signal variance quickly explodes or dies. If variance explodes, numbers become huge () and get pinned to the flat edges of squashing functions like Tanh (). Because the slope at those edges is basically zero, gradients completely die during backpropagation and the network goes deaf. If variance goes way down on the other hand, the neurons all output values near zero, meaning the network doesn't have enough signal to tell the difference between a robot arm at versus .
Orthogonal initialization solves this with good ol' geometry. An orthogonal matrix is a special matrix where every row is perpendicular to every other row and has a length of exactly 1. In multi-dimensional space, multiplying a vector by an orthogonal matrix is a pure rotation and reflection (). It spins the vector to point in a new direction, but it never stretches and never shrinks the vector's length. Because lengths are preserved, the spread (variance) of information leaving each layer is identical to what entered. And it gets better, the transpose of an orthogonal matrix () is also orthogonal, meaning error gradients flowing backward during backpropagation are equally preserved.
There is one catch though. Non-linear activation functions (like ReLU or Tanh) naturally chop off or squash part of the distribution, eating away roughly half of the signal's energy at each step. To cancel this out, we multiply the orthogonal matrix by a small booster gain of . Because signal variance scales with the square of the multiplier (), this doubles the signal energy right before it enters the activation function. This way the network still can learn complex non-linear traits and we don't have to sacrifice all of our signal energy to do so.
Finally, the very last layer (the output layer commanding the motors) is treated as a special exception. While hidden layers use full-strength weights to think, we deliberately scale the output layer weights to almost zero (). If the output layer had full-strength random weights on timestep 1, the network would immediately command extreme joint angles, causing the robot to violently spasm and collide on startup. Scaling output weights to ensures the initial commanded actions are near zero, letting the robot start in a calm, neutral posture and explore smoothly from a safe baseline.
- Global Gradient Clipping: In physics simulation, contacts are stiff and unforgiving. When a robot gripper accidentally slams
into a tabletop at high speed or bangs into a hard joint limit, the sudden impact creates a massive
spike in simulation penalties and value errors. Without protection, that single collision sends
a tidal wave gradient through backpropagation, violently overwriting millions of weights across
all layers in a single backward pass. This can cause the robot to forget skills it spent hours
learning. Global gradient clipping acts as a voice of reason for the network to keep it from panicking.
It treats the gradients across all network layers as a single high-dimensional vector. If its
total Euclidean length exceeds a threshold (typically
max_grad_norm = 0.5), the optimizer scales the entire vector down proportionally. The direction of the correction is completely preserved, but the shock value of it is reduced. The robot still learns that colliding was a mistake, but it doesn't overreact to the mistake. - Advantage Normalization: As we established in the policy gradient update, the size of our weight adjustment scales directly
with the advantage score (). But raw advantage scores vary wildly across a training run. In early training, when the
robot fails constantly, returns are tiny or negative (e.g. scores between and ); late in training, when the robot masters the task,
returns can soar into the hundreds.
Advantage normalization fixes this by standardizing the advantage scores in each mini-batch so their average is zero and their spread is one ().
This forces the optimizer to evaluate actions relative to the robot's current skill level. In early training, when almost every rollout is a failure (say, scores between and ), the attempts that were slightly closer to the goal () get shifted into positive territory, giving the robot breadcrumbs to follow. In late training, when the robot succeeds constantly, only truly exceptional moves get rewarded. At the same time, scaling the spread to 1.0 guarantees that our gradient updates stay a predictable, healthy size from the first minute of training to the final hour.
| Implementation Detail | Standard Value | Why It Matters on Continuous Robots |
|---|---|---|
| Orthogonal Initialization | Preserves signal variance through pure rotation; tiny output weights ensure calm startup. | |
| Global Gradient Clipping | max_grad_norm = 0.5 | Acts as a circuit breaker against violent contact spikes during physics collisions. |
| Advantage Normalization | Evaluates actions relative to current skill level to keep update sizes balanced across training phases. |
Monitoring Training, Beyond Looking at Reward
When an RL training run isn't working like you want it to you have to fight the instinct to interrogate the reward curve like its withholding information you need. Staring at the reward curve to debug training is like staring at the scoreboard after a basketball game to figure out why your team lost. To know how to debug the failure you gotta know how all the pieces tie together. Here is a little refresher, bringing all the previous sections together now.
- The Critic tries to look ahead and guess what kind of score the robot will end up with from where it's sitting right now ().
- GAE subtracts that guess from what actually happened to create up the advantage scores (), deciding whether each action was good or a mistake.
- The PPO clipping leash checks those scores and makes sure that any updates stay within reason by squashing any extreme values. ().
- And finally, gradient descent updates the Actor weights so we can try the simulation again, just hopefully better than last time.
Because every piece feeds directly into the next, errors carry forward and destabilize the whole thing. If the Critic gets confused and starts throwing out random guesses, the advantage scores become gibberish. The Actor tries to learn from that nonsense, picks up bad habits, and 50 iterations later your reward curve drops like the 2008 stock market. And if the leash is pulled too tight the Actor takes timid baby steps and the reward never budges at all.
Checking The Dashboard
The metrics below are a great thing to be checking during a problematic training run.
1. Critic Explained Variance
The Critic's main job is to remove dumb luck from the advantage signal. If your robot arm happens to spawn in an awkward corner of the workspace and earns a lousy score, the Critic should have seen that coming a mile away so the Actor doesn't get unfairly blamed for a tough starting pose.
To quantify this concept we use the metric of explained variance ():
| Explained Variance | Critic Fit | What It Means in Practice |
|---|---|---|
| > 0.70 | High Accuracy | Target Sweet Spot: Prediction error is tiny relative to return variance. The Critic provides clean, trustworthy advantage baselines. |
| 0.20 – 0.70 | Partial Fit | Developing: Normal during early-to-mid training while the Critic is still learning to value complex or rare states. |
| 0.0 – 0.20 | Uninformative | Guessing: The Critic has gone from predicting to pure guessing. It offers little to no baseline benefit, but isn't actively harming anything. |
| < 0.0 (Negative) | Toxic Noise | Sabotaging Actor: Predictions are worse than random guessing. Subtracting injects chaos into advantages (check for missing state inputs like angular velocities or unnormalized rewards). |
2. Approximate KL Divergence (The Policy Step Size)
Remember earlier when we set up the probability ratio ? For every sample in our mini-batch, we already have that exact ratio sitting in GPU memory, allowing us to approximate KL directly:
Re-using rollout data across multiple epochs is only valid when the new policy remains close to the old one. Monitoring KL ensures your policy updates stay inside the safe trusted region rather than leaping off a cliff into stale data.
| Dashboard KL | Action Shift () | What It Means in Practice |
|---|---|---|
| < 0.005 | < 10% | Under-updating: The policy is barely moving. Learning rate may be too conservative or batch size too large. |
| 0.010 – 0.025 | 14% – 22% | Target Sweet Spot: Healthy, steady updates per batch without destabilizing the policy. |
| 0.030 – 0.050 | 24% – 32% | Warning Zone: Action probabilities are swinging by up to a third. Rollout buffer data is losing validity fast. |
| > 0.050+ | > 32% | Catastrophic Step: The policy changed too drastically, invalidating the rollout data and risking policy collapse. |
3. Clip Fraction
The clip fraction measures what percentage of mini-batch transitions pushed past the safety window, zeroing out further gradient push on those specific samples.
It reveals whether PPO's clipping mechanism is actively guiding updates or choking off training efficiency.
| Clip Fraction | Clipping State | What It Means in Practice |
|---|---|---|
| < 0.05 (< 5%) | Near Zero | Under-utilizing Data: Updates are overly timid. The policy is barely pushing toward the trust region boundary; training is slower than necessary. |
| 0.10 – 0.25 (10% – 25%) | Moderate | Target Sweet Spot: The optimizer aggressively pushes on winning actions while leaving 75%–90% of transitions in the smooth unclipped zone. |
| 0.25 – 0.40 (25% – 40%) | Elevated | Warning Zone: A large fraction of samples are hitting the clip boundary; learning rate or PPO epochs per rollout may be slightly high. |
| > 0.40 (> 40%) | Heavy Clipping | Over-aggressive: Too many gradients are getting flattened out, wasting simulation rollouts and indicating policy updates are fighting the clipping leash. |
4. Policy Entropy
To encourage exploration, continuous robot motors sample actions from a Gaussian distribution with standard deviation . The average per-joint differential entropy is:
Entropy acts as a gauge for the Actor's curiosity. You want a smooth, gradual decay over the run rather than a sudden freeze.
| Entropy () | Exploration () | What It Means in Practice |
|---|---|---|
| +0.20 to +0.50 nats | ~0.30 – 0.40 rad | Initial Exploration: Wide random flailing across the workspace so the arm discovers where the goal is. |
| 0.0 to -1.0 nats | 0.10 – 0.25 rad | Skill Acquisition: Arm begins honing in on successful trajectories while maintaining exploratory flexibility. |
| -1.5 to -2.0 nats | 0.03 – 0.06 rad | Target Sweet Spot (Convergence): Policy is confident and tightly focused for crisp, high-precision control with minimal jitter. |
| Rapid Drop (< -1.8 early) | < 0.03 rad | Entropy Cliff Drop (Freeze Trap): Policy collapsed prematurely to avoid movement or collision penalties. The arm locks into a rigid local minimum and stops learning. |
The Robotics Gotcha: If you apply heavy penalties on joint speeds or collisions with a weak entropy bonus (), the robot quickly learns a cheeky loophole: if it never moves, it never gets penalized. Keep entropy decaying smoothly to avoid this freeze trap.
Healthy Training (Nominal Learning)
Balanced updates inside the trust region. The Critic accurately models state values, and entropy decays smoothly as motor precision develops.
Rapid skill acquisition: the critic explained variance crosses 0.70; advantages give clear directional guidance.
The arm begins swinging purposefully toward the target sphere with increasing accuracy.
Parameters are well balanced. Maintain training.
How to read this: Toggle between the scenarios above to inspect the signature traces of healthy training versus common failure modes. Hover or drag across any plot to scrub through training iterations and see what happens to the math, the arm, and the network at each phase.
Where to Look When a Run Goes Bad
When the training run goes wrong, work down this checklist in order.
- Check the Critic first (Explained Variance). If explained variance is near zero or negative, your Critic's value predictions are failing. Before touching anything else, double-check that your observation vector isn't missing vital physics (did you forget angular velocities?) and that contact penalties aren't spiking into outer space.
- Read KL divergence and clip fraction as a pair. If KL is spiking above 0.05 while clip fraction blows past 40%, the updates are way too violent. Dial back the learning rate or drop your PPO epochs per batch. If KL is basically zero and clip fraction never leaves the floor, your policy isn't learning at all. Bump the learning rate or make sure you turned on advantage normalization.
- Look for an entropy cliff drop. If entropy craters in the first ten iterations while task reward is flat on the floor, your robot found the freeze trap. Bump up the entropy bonus or ease up on harsh movement penalties so the arm is willing to explore again.
- Check for a setup bug. Inspect your environment code for episode termination flags. If timeouts and crashes share the same flag, GAE assumes running out of time is a catastrophic failure, zeroing out future value and giving your robot late-episode panic.
- Only touch the reward function as a last resort. Rewriting reward functions is tempting, but it can be the biggest time sink and can create a brand new set of weird behaviors. In practice, most early rounds of RL training that fail are from broken telemetry, missing state inputs, or unstable update steps, not your reward math. You need to setup the params so that the training even has a chance to succeed. It can train to your poor rewards at first that is fine, just get it training then worry about tweaking the rewards.
Once you absorb all of the information in this article and start to make sense of the metrics available to you, RL stops feeling like an exercise in lighting incense and praying to the gradient gods. I hope this article at least helped to build some foundational intuition within you.
After learning how RL works you will have a much better time training your robot to do something cool like make your bed for you while you watch the training dashboard and identify if the policy is updating nominally. Of course, the confusion can quickly come back though as you read the latest research paper about how some lab of highly caffeinated Phd students used a new method of machine learning to solve the problem way better than before... but that is part of the game! This is a discipline where you need to always be learning.
The Robot RL Engineering Series
If you want to learn more, or see the things you just learned put into practice, check these out:
Mamba SSM + Liquid Neural Networks
Replacing heavy Transformer context windows with linear-time State Space Models for 50 Hz recurrent robot control.
Hardening the Robot Brain
Continuous reward redesign, domain randomization across friction and lighting, and multi-GPU training scaling.