I have recently been experimenting with a meArm robotic arm and I wanted to be able to move each of the 4 servos to any reasonable angle
First I wrote an input routine that would accept commands such as /b120 which commands the base to move to angle 120 and /s25 which commands the shoulder to move to angle 25. Linefeed was used as the input terminator.
Next I wrote a function that would accept the commands as strings (lowercase s), interpret them and move the relevant servo to the commanded position. I could now enter commands from the Serial monitor and cause a servo to move as commanded.
Like you I wanted to send sequences of commands to the servos so I put those in an array of which this is an example segment. b is base, s is shoulder, e is elbow and g is gripper
//sequence 1
{
"1 block at 90 main commands only",
"g120", //gripper open
"b90", "e40", "s160", "g170", "s90", //forward, grip, retract
"b150", "s160", "g120", "s90", //forward, release, retract
"e40", "s160", "g170", "s90", //forward, grip, retract
"b120", "s160", "g120", "s90", //forward, release, retract
"e40", "s160", "g170", "s90", //forward, grip, retract
"b90", "s160", "g120", "s90", //forward, release, retract
"e40", "s160", "g170", "s90", //forward, grip, retract
"b60", "s160", "g120", "s90", //forward, release, retract
"e40", "s160", "g170", "s90", //forward, grip, retract
"b30", "s160", "g120", "s90", //forward, release, retract
"e40", "s160", "g170", "s90", //forward, grip, retract
"b90", "s160", "g120", "s90", //forward, release, retract
"end"
},
This worked OK but was tedious to enter and many command sequences were repeated.
The next step was to use what amounts to subroutines of the movements, for example
//sequence 8 - grab
{
"grab sequence",
"g90","e40", "s155", "g170", "s90", //forward, grip, retract
"end"
},
//sequence 9 - drop
{
"drop sequence",
"s160", "g140", "s90", //forward, release, retract
"end"
}
I changed the input routine and parser to allow it to accept lift and drop commands which cause the base to move as commanded and the lift or drop sequence to be called. An example of which would be
{
"lift block at 90 drop at 110",
"L90", //lift at 90
"D110", //drop at 110
"end"
},
The L and D commands trigger the sequences to move the 3 servos to lift or drop the target and the number indicates the base angle to do it at.
When running a sequence of commands if a servo is already in the commanded position the command to move there is ignored because it is not necessary.
I have also added a random move command which picks up an object from a random position in a previously defined map of blocks (held in an array of structs), drops the block in an available space and updates the map of blocks and spaces. Needless to say you can specify how many random moves should be made. At the end of the random sequence the blocks are put back on the same pattern as they started and at the end of any sequence of commands the special /a command is executed to move all of the servos to a home position, usually 90 degrees but it can be specified.
I am not sure whether any of this will help you but you should take lessons from it.
Write code incrementally and test small functions independently
Think ahead so that you have a picture of how your small pieces of code will fit together.
Give variables and functions meaningful names so that when you go back to the code you have a fighting chance of reading and understanding it.
Separate the data and the program. For instance my list of sequences and the map of the block positions are each in separate .h files which makes finding and amending them easier.
Print out what is going on when the program is running so that you can see what is happening in the program as well as what the servos are doing.
Do not run the servos at full speed because when anything unexpected happens there is potential for chaos and damage and I have the broken servos to prove it.