its a bit tricky to do right.
because it has to be very precise so you dont get funky results.
if your character is not complex, then i dont see a need for control objects. but if u have a complex rig that has lots of bells and whistles and you need a way to quickly access the controls, then control objects are great.
but basically here is a typical approach.
make a nurbs circle, snap it to the root joint. name the circle rt_ctrl or whatever naming convention you have.
now you need to align that nurbs circle with the joint's local rotation axis. so they are pointing in the same direction.
group the rt_ctrl to itself, name that group grp_rt_ctrl
snap its pivot to the root joint.
you will need to orient constrain that group to the root joint so their local rotation axis are pointing in the same direction.
so next, select the grp_rt_ctrl in the outliner, then shift select the root joint, and do an orient constrain. now they should be perfectly aligned, if the rt_ctrl rotates in x, just rotate it back to -90 or until its straight again. if it didnt rotate thats fine too. now freeze the transform on the rt_ctrl so that its at 0 0 0 for all the transforms.
now in the hypergraph , delete the orient constrain
thats on the grp_rt_ctrl, u dont need it anymore.
now, make another nurbs circle for the first spine joint, and repeat the steps above. name the controls, something like spine_ctrl then grp_spine_ctrl when u group it.
after you repeat all the steps, select the grp_spine_ctrl and parent constrain it to the rt_ctrl [not the grp_rt_ctrl]
control object you need. after u create your controls, u need to orient and point constrain appropriate joints to their respective control objects. [the spine joints may not need to be point constrained because they will only rotate.
so basically you are creating a hierarchy where one control moves the control object above it.
you might be able to find some tutorials online. but that is one of the easiest workflows for control objects.