Yes, I think that PID is the answer. I also agree that you could probably leave the Derivative out.
It seems that simple physics with trig would fix the problem but it doesn't. You need PI or PID.
Balancing a robot without PID is like controlling the speed of your ceiling fan by manually shutting it on and off really fast. By doing this, you over compensate and undercompensate your target speed. You turn off the fan when it's too fast, and you turn it on when it's slower than your target speed. You end up oscillating from your target speed and that would basically also explain why your robot oscillates. If I get it right, it seems that your robot reacts based on tilt only and I would presume that the speed of your motor is directly proportional to the amount of tilt that you get from the accelerometer. If the above is correct, then that means that you're not putting into consideration the speed of your robot as it tilt towards the ground.
From my experience, here's what I found:
1. accelerometer signal is unreliable when in motion (too much noise). You need to filter it out
either digitally (code-wise) or analog (using capacitor and resistor).
2. the speed of motor to keep the robot perpendicular is direclty proportional to the angular
speed of the robot and the tilt of the robot. A gyro would give you angular speed and it is
immune to vibration.
3. PID would reduce or eliminate your robot's oscillation.
So I suggest:
1. filter out your accelerometer using capacitor and resistor until it becomes immune to some
vibrations. About 100 samples per second (100Hz) is decent to balance your robot. I think
a real Segway also samples at 100Hz.
2. if you're not going to use a gyro, then you need to spend more time polishing your PID and
accelerometer signal. The more you filter your accelerometer to reduce noise, the more
sophisticated your PID should be.
3. as you tweak your PID, also try tweaking the center of gravity.
4. turn off your robot when it reached 30 degree angle because it's almost impossible to recover
from that angle without running your motors on high.
I'm not an expert in PID but this might help.
When balacing a robot, ideally your target angle is zero or 90 degrees (perpendicular to ground).
Right now you probably only have a "Proportional" control of your motors. When you get a tilt you subtract it from the target point, then you tell your motor to move forward or backward based on that tilt. That part alone is the P in PID. You're driving your motor "Proportional" to the amount of error from the target point.
P = p_Gain x (target_angle - actual_angle)
if you look at your code closely, you'll probably realized that you're multiplying your error by a certain
amount before giving the command to your motors. That constant is called your "proportional gain".
if you only use a Proportional control, then you can be sure that your robot will oscillate. =)
to enhance your Proportional controller, you have to introduce the Integral part (the I in PID)...
remember the (target_angle - actual_angle) in the above equation for the proportional controller? That's the "error" part. The "Integral" part takes into consideration ALL your previous errors in the past and adds them all up. For example, if your robot is tilted forward and you commanded your robot to move forward based on its tilt, but after the command your robot is still tilted forward, then the Integral part will put that into consideration and would further increase the speed of your motor to
try to decrease the current error.
this is your error = (target_angle - actual_angle)
Integral = i_Gain x (Sum of all error) once again i_Gain is a constant that you use to multiply
the sum of error...
now you could add Integral to your Proportional controller...
Output = P + I this is your Proportional Integral controller...
you'll notice that PI controller is much much better than the Proportional controller... it should
really improve the balancing of your robot...
you'll notice that the PI controller is less twitchy and it's more accurate...
you could further improve on your PI controller by adding in the Derivative term... the derivative
term is like the dampener on a spring... the Integral part rushes your value towards the desired
angle, but it has the tendency to overshoot, the Derivative takes this "rushing" aspect into
consideration and "dampens" it... you'll notice that the Derivative term slows down your motor
when it gets close to the target angle... pretty cool huh?! =)
so here's the summary... P term describes the current condition of your robot... the I term
describes the past behavior of your robot... and D describes what the future out come will be...
if we have all those three covered, then your robot should be able to balance...
current_error = (target_angle - actual_angle)
previous_error = (target_angle_previous - actual_angle_previous)
D = d_Gain x (( current_error - previous_error)/time) yup! it seems that the derivative term
depends on the current error and the previous
error.. then multiplied by gain...
if you look at this mathematically, it would look like an equation for a slope... slope basically
tells you the rate... i'll leave it up to you to whether or not you need the "time" term in there
because right now I can't quite remember...
PID = p_Gain x error + integral of error + derivative of error
(please correct me if i got any of the equations wrong) but I think I got them all right...