Impulse
About
Impulse is two wheeled bipedal robot that I built over the course of 6 months. Originally, Impulse was suppose to be a walking bipedal robot similar to the LimX Dynamics P1. I decided to pivot to a wheeled biped around 4 months into the project because walking robots are extremely hard to make from a controls standpoint.
Features
Self-balancing
Fast acceleration
Auto deployment/landing
Variable height
Portable
Specifications
6-DOF
Weight: 5.35 kg (11.79 lbs)
Height range: 305.5 - 455.5 mm (12.03 - 17.93 in)
Max tested payload: 2.27 kg (5 lbs)
Max tested speed: 1.64 m/s (3.67 mph)
Max theoretical speed: 3.98 m/s (8.90 mph)
Max jump height: 26 mm (1.02 in)
Labeled Diagram of Impulse (Front and Back Views)
Design
Since Impulse is a 6-DOF robot, each leg has 3-DOF. In other words, each leg has 3 actuators: the hip actuator, the knee actuator, and the feet actuator/hub motor. The knee actuator drives the lower leg linkage through a 1:1 belt-pulley drive. Although each leg has 3-DOF, the foot can only move in a 2D plane. This is due to the fact that the hub motors add a rotational degree of freedom to the leg and not a translational degree of freedom. The inverse and forward kinematic equations were quite simple to solve because of this. The length of the upper and lower linkages was chosen to be 140mm based on the measured stall torque of the actuators. Knowing the stall torque allows you to find the maximum linkage length that an actuator can handle since torque = force x distance. The full extent of the calculations was done using a bit of statics.
The robot was fully 3D printed on my Bambu Lab A1 in PLA. One of my main design considerations was to maintain a good strength-to-weight ratio on each part. To accomplish this, I added lots of triangle cutouts to the parts since triangles are a strong structural shape. As a bonus, the cutouts added to the aesthetic of the robot. Another important design consideration was portability. I wanted to be able to carry the robot from place to place without having to hold it awkwardly or put it in some sort of container. To accomplish this, I incorporated some really strong N52-grade magnets into the lower leg linkage and the main body. This way, I could have the legs attach themselves to the main body when folded. This also helped with calibrating the actuators on startup as the actuators need to start at roughly the same position in order for the encoders to read properly. In addition to the magnets, I also added a handle to the robot to achieve portability.
The main housing of the robot features arrays of vent holes to passively cool the electronics. The upper leg linkage has stilts that serve to help the robot auto-deploy. Without the stilts, the robot would have to deploy straight from the ground which would be quite difficult. Imagine having to jump up from sitting on the ground vs sitting on a chair. Having the extra elevation from the chair makes jumping up much easier.
Hardware
The brains of Impulse is a Teensy 4.1 microcontroller, my go-to for Arduino-based robotics projects. It has a clock speed of 600 MHz. For comparison, an Arduino UNO has a clock speed of 16 MHz. Overall my code was able to achieve a loop frequency of 100 Hz with the Teensy.
The GIM6010-8 is what I used for the hip and knee actuators. For only $50, you get a brushless actuator with an 8:1 planetary gear set located in the center of the stator. The gears are made from steel and are of the helical type. Helical gears have low noise and high load capacity. I purchased the GIM6010-8 using the “motor without shell” option which is part of the reason why it was so cheap. I didn’t need the shell because I designed my own 3D-printed actuator housings to better integrate with the robot’s design. The actuator has a 24N28P configuration, weighs 254 grams, has a measured KV rating of 108 RPM/V, and has a measured stall torque of 3 Nm. Note that the KV rating refers to the motor with the gearbox. The KV rating of the motor alone would be approximately 8 times the KV of the motor and gearbox due to the 8:1 reduction. I was hoping for a little more torque since the manufacturer claims 11 Nm (more than triple what I measured). I tried rewinding the stator with more turns of thinner wire. This had negligible effects. I think the lack of torque is due to the fact that the permanent magnets on the rotor are really thin and probably cheap. Considering the actuator’s low price, I half expected this. The actuators come with a thermistor embedded into the windings, but I removed them since I didn’t think overheating would be an issue. The actuator also comes with a magnetic encoder already mounted on the input shaft (the shaft before the gearbox). I used the ODrive Micro to control the GIM6010-8. It’s a super low-profile FOC board with great performance. With the onboard encoder, I was able to mount the boards onto the back of the actuators which made things really compact.
The DBS2.0 electric skateboard hub motors were used for the wheeled feet. The tires are made from a high shore hardness polyurethane and they have great traction. Electric skateboard hub motors just seemed to make sense for this build since they have low rotational inertia, high rotational acceleration, and enough torque to support human weight. While testing, I was able to accelerate the motor from 1000 RPM to -1000 RPM almost instantly. I measured the KV of the motor to be 60 RPM/V and measured the stall torque to be 2.66 Nm. The motors have three hall effect sensors embedded in their stator for position feedback. Using this video as reference, I was able to find that the resolution of the sensors for this specific motor’s configuration is 6°. This is pretty poor for a robotics application, so I turned to the ODrive OA1 magnetic encoder for precise position feedback. The OA1 is a 12-bit encoder which means that it has 0.09° of angular resolution. The OA1 is made to directly interface with the ODrive S1 FOC board, which is the board that I used to control the DBS2.0. I also drilled and tapped holes into the rotor of the DBS2.0 so that I could mount a shaft with an encoder magnet to be read by the OA1.
4x GIM6010 Actuators and 2x DBS2.0 hub motors
4x ODrive Micros and 2x ODrive S1s
I used the BNO086 IMU to measure the tilt of the robot. This board is super packed. It’s a 14-bit 9-axis IMU with drift correction and a 32-bit ARM Cortex MO+ processor onboard relieving computing power from the microcontroller. The BNO080 boards were designed for Android phones to be used with VR headsets which shows their level of precision. One benefit of this being a 9-axis IMU is that the 3-axis magnetometer allows for absolute orientation so that the IMU doesn’t have to be calibrated on startup.
To control Impulse, I’m using the Radiolink T8S 8-channel RC transmitter and receiver pair, another go-to for robotics projects. This controller has 1.2 miles of range in the air. Something that I discovered while working on this project is that if you use interrupts to read the pulse widths of the channels instead of constantly reading the pulse widths, you can get super-fast responses from the transmitter without slowing down the code. I used tank drive as the method for driving the robot. Essentially the left joystick operates the left wheel and the right joystick operates the right wheel. To go forward you push both joysticks forward. To go backward you pull both joysticks backward. To turn about the robot’s center you push both joysticks in opposite directions. For a swing turn, you push both joysticks in the same direction but at different amounts.
CAN bus was used to communicate the motor controllers and the microcontroller. CAN bus is great because, with only 2 pins on the Teensy, you can control a large number of motors. I used the Waveshare SN65HVD230 CAN transceiver to interface the Teensy with the CAN pins on the motor controllers.
Impulse is powered by a 24V 3000mAh Kobalt battery. This is my new go-to for robots instead of RC LiPo batteries. It’s so easy to clip the Kobalt battery onto the robot using the power wheel adapter. The battery also has a little four-bar indicator to monitor the juice level. When it’s time for a recharge, the single bar starts blinking. I used this charger to charge the battery; a 5V regulator to power the Teensy; and 3.3V from the Teensy to power the IMU, RC receiver, and CAN bus transceiver.
Control Theory
When it comes to balancing robots, control theory is where the magic happens. Although an LQR controller would probably be the best controller to use here, I opted to use PID controllers because they’re simple and easier to implement. In total, I used 3x PID controllers to control Impulse.
PID #1: Roll Controller
The first controller is the most important as it controls the roll angle of the robot. In other words, this is what balances the robot. The roll angle, measured by the IMU, acts as the input to the controller. The output of the controller is the desired velocity of hub motors which is directly fed to the ODrive controllers. The setpoint of the controller is the angle at which the robot should balance.
Roll Angle PID Controller Diagram
PID #2: Velocity Controller
Just having a roll-angle controller is not enough to maximize performance. Unless the robot is designed to be perfectly symmetric along its centerline there will be an uneven mass distribution that will lead to the robot having a slight bias. In other words, when the roll setpoint is 0° the robot won’t stay perfectly stationary and may drift forward or backward. The velocity controller ensures that this doesn’t happen. The input of the controller is the average velocity of the hub motors measured by the OA1 encoders. The output of the controller is the desired roll setpoint which is fed directly to the first PID controller. The setpoint of the controller is the desired average velocity of the hub motors. To keep the robot stationary, the average velocity setpoint is set to 0 rev/s. The controller then dynamically determines the roll setpoint to keep the robot from moving. For example, If the robot is drifting forward the controller will make the robot tilt backward by making the roll setpoint negative. The nice thing about this controller is that it not only prevents the robot from drifting forward or backward, but it also keeps the robot in the same position. Since the proportional term of the controller is the average velocity of the hub motors, the integral term is the average displacement of the hub motors. This means that the robot rolls back to its original position when it’s pushed. The derivative term of the controller would then be the acceleration of the hub motors. I honestly didn’t see much of a performance difference with the derivative term. The velocity controller can work well just as a PI controller. Another great thing about the controller is that it can be used to drive the robot. For example, let’s say you want to drive both wheels forward at 5 rev/s. The setpoint of the controller would be 5 rev/s. The velocity of the hub motors (fed to the ODrives) would then be equal to the output of the roll controller (PID #1) plus the base velocity, which is 5 rev/s. The base velocity acts as a feedforward term for the roll controller.
Velocity PID Controller Diagram
PID #3: Pitch Controller
While PID #1 and PID #2 can be used for any basic two-wheeled balancing robot, PID #3 is specific to a two-wheeled bipedal robot. This controller is used to change the lengths of the robot’s legs in order to keep the robot stable. Imagine someone pushes you from the side. Your first instinct is to bend the knee opposite to the side being pushed. This helps you absorb the impact of the push and restabilize. The pitch controller does exactly this. If the robot is pushed from the side or drives over a bump, it shortens the leg opposite to the side being pushed or opposite to the side driving over the bump. This controller is especially useful for drifting as it allows the robot to lean in towards the center of the curve as it make a sharp turn.
Pitch Controller PID Diagram
Size Matters…for Robots
The system dynamics of the robot change with the robot’s height. For balancing robots, a higher center of mass means a slower angular acceleration. In other words, generally speaking, taller robots fall slower. There’s a great Wired Article on this. One way to observe this phenomenon is to try balancing a pencil versus balancing a broom. The broom is much easier to balance. In fact, the pencil is virtually impossible to balance. Since the system dynamics of the robot are height dependent, the same PID gains cannot be used for different heights. To accomplish this, I experimentally determined the best gains for each height, graphed it in excel, and used a linear best fit line to find an equation for each gain. I then plugged these equations into the code so that the robot can determine the best gains to use for its current height.
Things I Would Do Differently
If I were to revisit this project I would want to do several things differently. Firstly, I would use different hub motors. The current hub motors have a really small diameter and a cylindrical shape. Ideally, the motors should have a large diameter and a donut shape to be best suitable for off-road driving. The robot, as it is now, is only suitable for flat and even terrains. With a larger diameter, you are trading off fast acceleration, but I think it’s worth the added terrain versatility. Another modification that I would make to the robot’s design is adding extra support to the lower leg linkage. The legs are quite skinny which leads them to bend when the robot jumps. One of the legs actually broke during testing because of this. Lastly, I would like to make unmounting individual parts easier. When the leg broke, I had to cut a bunch of wires to unmount it.