
Mickey666Maus

Hey guys, I was trying to script some animation for my robot...trying to figure out how to make smooth animations which will run correctly timed and without getting jumpy servos!
I experienced that my script is running smooth if it is the only thing running, once I start the camera the movement gets really choppy/jumpy...is this because the camera takes too much bandwidth, is the communication to the board being flooded? It does not happen if I use the Laptops Webcam!
How do I workaround this?
Is my approach of scripting animation wrong? My idea was to animate 30FPS and point out the specific servo position for every frame, followed by a pause...
like this
ServoSpeed(D8,0) ServoSpeed(D6,0)
Servo(D8,39.417) Servo(D6,96.2251) Sleep(33.3333) Servo(D8,35.6368) Servo(D6,99.7181) Sleep(33.3333) Servo(D8,30.7226) Servo(D6,104.559) Sleep(33.3333) Servo(D8,25.8083) Servo(D6,109.944) Sleep(33.3333)
etc...
Excellent work and a fascinating project. I had something like that in the back of my mind for some time. The controlling part that is, not the designing and printing part. Anyway, here are my thoughts.
What you seem to be trying to do is similar to stop motion animation. That sort of animation requires an accurate frame rate to achieve fluid motion. As DJ mentioned, the timers in the script are software based and not real-time based, with interrupts and all that. You cannot rely on the sleep command to provide a steady, accurate frame rate or even an accurate timing from Sleep function call to Sleep function call. Especially at very short times.
One way to perhaps compensate for it's lack of accuracy in most cases could be to perform a running calculation such that the script can come up with a variable delay (sleep value) so as to try to maintain a given frame rate, despite changing conditions. The problem with this solution, however, is that there could still be some jerkiness as the new value is calculated and the algorithm might not not be very responsive to these changes.
It may be better to use a vector approach. That is to say, instead of many small movements, timed to a particular frame rate, go with a series of start and end positions. Most of them would be relative. For example, if a given servo starts at 10 degrees, then this becomes the start point. If the next movement is to go to 20 degrees then the next point to be recorded is "+10", and added to the previous position to cause the servo to go to the new position, and so on. The same for any other servo being moved at the same time. All these points go into one long string, along with appropriate characters to tell a reader script how to move the servos.
For example, something like this: "D0|10,D1|30,S+1000,D0+10,D1+15,S+1000,D0-10," ....
What this would be saying is, Set D0 to 10 degrees and D1 to 30 degrees initially. Then sleep for 1000ms. Then move D0 +10 degrees from where it is right now and move D1 +15 degrees from where it is now. Then Sleep for another 1000 ms, Then move D0 back 10 degrees (-10), and so on. In this case the Vertical Line character "|" (also called vertical-bar, vbar, vertical line or vertical slash) would be used to represent an absolute position. "+" and "-" would represent relative positions. Your 3DS program would create the string as you move the 3DS robot to its' various positions. Then, at some point, save it to a text file.
Basically a "Reader" script would take the information in the string and execute the commands described in it to move the robot where it is to go for that particular sequences of movements. Something like this:
This sort of thing is easier to use since it requires no copy and paste to get it into the script. You can directly load the text file into a variable ($TheDataStr, above) from the disk using The FileReadLine or FileReadAll script instruction, then have the Reader code read it and move the servos accordingly. NOTE: The above code is just off the top of my head and may not be bug free as I haven't actually tested it.
Additionally, other commands can be added as needed such as one that will use the ServoSpeed instruction. Something like "R|D0|100" for example. Using the letter "R" to stand for "Rate", since "S" is already used for "Sleep". This would say... Set the servo speed of D0 to 100. It would be broken down like this:
So, basically you have a comma separated variables string that is broken apart by the Split function with each group used to do something with the robot. This method also helps insure you don't flood the channel by sending many small increments.
Hope you find this helpful.
Relying on the ARC sleep() command is the cause of the occasional delays. Here's a good simplified explanation: http://stackoverflow.com/questions/1303667/how-accurate-is-thread-sleeptimespan
This cannot be resolved - due to the Microsoft Windows OS not being a real time operating system.
@WBS00001 Thank you so much for this awesome reply! And thanks for making the effort to put all that code together for me! I am really bad when it comes to coding, it takes me forever...
I was actually thinking to reduce the frames in my animation to lighten communication between ARC and my servos, but your approach makes a lot more sense! I guess this is kind of how the Auto Position in ARC works, right?
I do not have the time to check this right now, but I will try your approach asap!
The rigging in the 3D application is a bit complicated, to extract all the rotational values from an object is kind of tedious because of the rotation matrix they use...but once it is done it is also rewarding. You can playback and modify your animation in a nondestructive way to tighten your movements, and the timing controls are helping to make readable motion!
Also your way of sending the data thru a variable could help for directly controlling the robot live thru the 3D application, this always caused a lot of jerky movement...it could be used as a buffer I guess? Just tossing ideas around in my head already!
Thanks so much for your help guys! You are great!
Got my first 3D printed servo brackets today...still not perfect, but I hope to get my K[8] up an running soon!
Glad you might find the method useful. I'll be happy to help with more coding as needed. Just let me know what you require.
A few points. I don't know about 3DS or what it takes to write something to create the control string from it. However, if it is easier to create all absolute positions rather than mixture of absolute and relative positions, that should be fine. Also, other characters can be used to separate the characters within a given group, such as a space. For instance, the group D0|100 could also be be D0 100, using a space as the separator. Even the groups currently using a plus or a minus character (Relative movements) could use a space: D0+100 could be done as D0 +100 with a space separator between the D0 and the +100. It's all a question of appropriate grouping. Come to think of it, a uniform separator would simplify the code in some ways. I'll have to ponder that a bit more. I had one more point to make but I've forgotten what it was at the moment. I'll post again when it comes to me.
Yes, you're right. It is something like how the Auto Position control works. Of course, the Auto Positioner directly controls the servos with a series of commands sent to the EZB-4 through the underlying C# code. In the case of this method, the comma separated groups are somewhat like parts of a Frame. I suppose the analogy could be carried further by using parenthesis to separate groups of groups and call each a complete Frame. Something like: (D0|10 D1|30 S+1000 D0+10 D1+15 S+1000 D0-10).(D0|10 D1|30 S+1000 D0+10 D1+15 S+1000 D0-10). etc. Each group in the Frame would be separated by a space (or whatever). While that might make it easier to read and manipulate after generation, it might make things more complicated than it's worth.
Anyway, just let me know what you would like to see changed in the code and I'll be glad to do it.
@WBS00001 It should be fairly easy to create any type of control string to be send out from 3ds max via HTTP or into a .txt document...
So I would create the absolute position of the servo once, which would be the starting position...and after I would jump to the next keyframe in 3dsmax and write this position as the next relative position right? Then jump to the next keyframe etc...
Right now I was sending the position of each servo every frame, which was a lot more data obviously.
But how would I calculate the sleep, meaning the delay which the script needs until the servo has reached its position? Right now I am using a 33ms on every frame...so I would need to check how many keys it took from one keyframe to the next and muliply this times 33? This would need some digging, but I guess I could find out how to do this in maxscript!
I could start to test your approach by having my keyframes set to fixed intervals, just to check how it works...
I just found this thread. I've been hoping to get something like this to work except I use Lightwave not Max. I did manage a few years ago to get Maya to connect via Python to an ardurino to control servo's live or recorded. All the programs and sketches were written by an Australian author in 2009. He never explained how to make a set up with more than 4 servo's and dropped off the earth.
So I could use various means to control the servo via motion capture, or a virtual dial or joystick with the rotational values out putted to the servo. I've built a lot of animatronics over the years and pre recording playing back and tweeking the animations is the only thing missing in ARC to take it to the next level. But using an animation package is the way to go until/ if that happens. I'm extremely interested in what you guys come up with. I can't code so I have to depend on others. But I can contribute ideas