Pneumatic-Drive Rover

Rover with a plushie driver on top Autonomous course layout and scoring

Project Overview

As part of a course at UCI (MAE 106), I conceptualized, designed, and manufactured an autonomous pneumatic-piston-powered robot. My role was primarily to program the rover in C++ and assist with the design and CAD modeling of the rover's components, along with manufacturing and assembly. The project posed the following design requirements:

  • Must be able to navigate the defined "trench" area without crossing through the entrance walls.
  • Must fit within a 12in diameter cylinder.
  • We must mount the provided tire horizontally at 16.0±0.25 inches above the ground.
  • The provided tire must provide air to the provided piston, which is the only allowable locomotion source.
  • The only allowed sensors are the provided IMU (Mag, Gyro, Accel) and limit switches.
  • All required parts are provided to us, and some additional parts and fabrication (laser cutting, 3d printing) may be purchased from the school up to $100.

The project took about 7 weeks to complete, with about 4 weeks of it being testing and improving systems.

Programming

CAD model of the rover next to the plush of the driver

Overview

I programmed the entirety of the robot's navigation using C++ in PlatformIO, a popular open-source embeded system IDE. I utilized best-practices to create clean, easy to modify code for each part of the robot's automated program. I divided the project into multiple .cpp and .hpp files to abstract each type of operation. For example, I create an Actuation file, a Navigation file, etc. which would all contain their respective functions to be called on a global scope. This allowed me to more easily modify my code and track bugs.

The rover ran all autonomous systems on an Arduino Uno, which has very limited RAM (2kB) and flash (32kB).

My rover utilized more complex systems than most other teams because I wanted to challenge myself with coding and I wanted to ensure optimal track performance even during times of poor sensor data.

Unique Features

  • Redundant piston-firing sequencing, ensuring optimal performance despite highly variable piston stroke time.
  • Limit switch failure detection and resolution on the steering wheels and piston.
  • Closed-loop waypoint-based guidance allowing for variable speed and live turning radius calculations.
  • Accurate geometrically-based turning radius calculation to avoid tip-over due to elevated center of gravity.
  • Kalman filter combining magnetometer and gyroscope data to provide more stable heading reading.
  • Tip-over detection and 3D orientation monitoring for the safety of the robot and anyone around it.
  • Custom 3D vector and quaternion library (because I wanted to learn more about classes in C++).
  • 100Hz sensor update frequency.
  • Wired data stream and Python plotter, used for debugging unexpected behavior.

Design Challenges

RAM

One of the first major issues I ran into during this project was running out of RAM. Despite the device being preloaded with only around 80% of its max RAM, I found that mysterious issues were occuring with corrupted data. I discovered this issue was due to the arduino running out of RAM during its processing (due to fragmentation) and needed to find a solution. I then discovered that all of the Serial.print("debug info here") commands used to provide debug info to the serial port were actually storing their strings in RAM. Using the F("mystring") macro, I moved all of those strings into flash (which has a lot of extra capacity) and freed up around 40% of the RAM capacity, resolving the issue.

Magnetometer Interference

The next greatest issue I faced was getting useable magnetometer data. The piston driving the vehicle utilizes a solenoid valve, which produces a significant magnetic field when actuated. Despite positioning the magnetometer as far as possible from the solenoid, the valve could still induce the equivalent of 10 degrees of heading offset. This would cause the rover to take a wavy path between waypoints and could ultimately make it unstable and fall over. To correct for this, I calibrated a solenoid offset which would be applied to the raw magnetometer data whenever the solenoid fired. I also implemented a feature to ignore the transient data during the first 100ms after the piston changes state. This was required to avoid a spike in the heading leading to instability.

Magnetometer Mapping

In addition to the solenoid interfering with the magnetometer, I identified a non-linear relationship between the actual heading of the rover and the calculated heading based on the magnetometer, even after multiple calibrations. During the autonomous sequence, the rover is expected to move straight forward, then turn 90 degrees, then move forward more. Because of the non-linear mapping, orthogonal directions in the physical world were not interpreted as orthogonal to the program. This meant that the actual path taken by the robot involved moving in non-orthogonal directions, which inhibited the rover's ability to understand its current position. Therefore, a small offset was added to the intended waypoint positions to ensure it ended at the expected target for full points. This fix was not ideal and require a lot of tweaking, and was very sensitive to small changes. In the future, I might consider doing a more thorough mapping of the actual magnetometer response to provide more accurate navigation.

github logo

Visit the GitHub repo!

Final Competition

Results

During the final competition, my rover won first place due to its fairly consisent run-to-run behavior and ability to reach to bonus point square. One of the greatest challenges during the competition was having other robots navigating at the same time. The robots do not have any way of sensing or avoiding other robots, so there were multiple occasions where a very capable robot would get hit or knocked over by another robot. My robot got trapped in a big pile up on one of the three rounds, and managed to do very well on the other two.

My effort to make the code readable and geometry-based paid off when various track factors, such as the slope of the pavement or magnetometer issues required adjustments to the autonomous program that were impossible to predict.