The key invariant in an AVL tree is that the balance factor of each node is either -1, 0, or +1. Here, the "balance factor" is the difference in the height between the left and right subtrees. +1 means the left subtree is one taller than the right subtree, -1 means the left subtree is one shorter than the right subtree, and 0 means the subtrees have the same size. This information is usually cached in each node.
When you get a node with a balance factor of -2 or +2, you will need to do a rotation. Here's one possible setup for when a rotation is necessary:
u (-2)
/ \
A v (-1)
/ \
B C
If we fill in the heights of these trees, we get
u h + 2
/ \
h-1 A v h + 1
/ \
h-1 B C h
If this happens, doing a single right rotation yields
v h+1
/ \
h u C h
/ \
h-1 A B h-1
And hey! The tree is balanced. The mirror-image of this tree would also be fixable with a single left rotation.
All of the AVL tree rotations can be determined simply by enumerating the possible balance factors within a small range and then determining which rotations should be applied at each step. I'll leave this as an exercise to the reader. :-) If you just want to look up the answers, the Wikipedia article on AVL trees has a nice picture that summarizes all the rotations that might need to be applied.
Hope this helps!