@fxrtst
This looks supercool, recording motion capture myself was always one of my greatest desires...I will check on that sensor you mentioned! Is there a thread where you are explaining how you accomplished? Or will you probably make one for us?
The Kinect linked up to record motion also seems to be something worth exploring! I had my Kinect linked up to Motion Builer a long time ago...but the noise of the motion and the lack of real 3d capture made me stop working on this method for extracting motion data.
You seem to know a lot about animating, rigging and modeling in a 3D enviroment...as you know these days 3ds max and Maya are getting easier to use side by side, so I guess you should be able to use your Maya scenes from within 3ds max with a little tweaking!
I think it should also be possible to script the same thing we are doing for 3ds max in Maya...but I dont know anything about its scripting language!
Awesome project...lets try to string it all together if possible!
Sounds very much like what I trying to do here. Good question on the Maya and Max merge or one gets dropped. Autodesk owns them and I'm surprised that they continue to develop them all. Not sure if Maya and Max share the same plug in architecture, my first thought is probably not. The motion Capture program I am using only has a plug in for Maya live, but recorded motions can be sent to any animation package. Just need someone to write a python plug for them. This software was bought last year by a big company and they no longer support it but it is a full fledged working program for now. I believe they used it in the new Star Wars film for the female alien with the thick glasses.
I want to use it for controlling and recording motions for robots. Then I'll move onto full body capture. They use the same rotational values.
There comes a time in every software project when you have to stop tinkering with it and send it out into the world. This is very difficult for programmers to do. And so it is with the first pass on the Maxscript code I have written for this project. This will probably be a long post so don't say you weren't warned.
By way of disclaimer, I should say I have never worked with Maxscript or Python before this so the code is not as elegant as it could be. I still have a lot to learn. Additionally, I could have combined some operations in the code, but I decided to use separate variables to hold intermediate values (instead of putting the functions in-line) for better readability.
Basically as the code now stands, it is working software with debug statements sprinkled through it. The debugging statements can be turned on and off by setting the state of a global variable. Likewise with other functions. Here it is:
/* Declare ALL Global Variables Here */
Global SaveToFile =True --Saves data into text file (TextFileName)
Global SendToEZ =True --Send HTTP commands to ARC HTTPServo control
Global PrintOutput =True --Show servo Instructions generated (in Listener)
Global DebugScript =False --Enables the debug features
Global TextFile
Global Servo_R
Global FileExists =False
Global SockPrefix ="HTTP://"--Standard web prefix
Global SockAddress ="NN.NNN.NNN.NNN" --Address from HTTP Server in ARC.
Global EZ_Logon ="Exec?password=admin&" --Change password (admin) as needed
Global TextFileName ="C:\movement.txt" --Output File (Change as needed).
Global EZ_CommandScript ="Script="
Global EZ_CommandAction ="Action=" --Still working on these last 2.
Global EZ_CommandFrame ="Frame="
Global ScriptCommPrefix =SockPrefix+SockAddress+"/"+EZ_Logon+EZ_CommandScript
Global ActionCommPrefix =SockPrefix+SockAddress+"/"+EZ_Logon+EZ_CommandAction
Global FrameCommPrefix =SockPrefix+SockAddress+"/"+EZ_Logon+EZ_CommandFrame
-- Array of servo Numbers, Order listed = order processed
Global ServoNumbers = #("D6", "D8", "D10" )
-- Array of servo Objects. Order Must match Order of servo Numbers, above
Global ServoObjects = #($SchulterRechts, $ArmLinks, $HandRechts)
Rollout StopButton "Stop" --Generates a UI with a button
(
Button Btn "Stop Script"
On Btn Pressed Do
(
DestroyDialog StopButton --Get rid of the User Interface
Close TextFile --Close The File Variable
SliderTime =1 --Move the slider to force a callback
SliderTime =0
)--End On Btn Pressed
)--End Rollout
CreateDialog StopButton Pos:[1540,600] -- X-Y Position Coords.
/* Creating a textfile for output */
If SaveToFile == True Then
(
FileExists =DoesFileExist TextFileName --If True, file already exists
If FileExists == True Then
(
If DebugScript Then Print ("Pos 1 "+TextFile as string)
TextFile =OpenFile TextFileName mode:"r"
If DebugScript Then Print ("Pos 2 "+TextFile as string)
If TextFile != undefined Then --File sucessfully opened
(
If DebugScript Then Print("Pos 3 "+TextFile as string)
Close TextFile
If DebugScript Then Print("Pos 4 "+TextFile as string)
TextFile =(OpenFile TextFileName mode:"a")--Open for writing
If DebugScript Then Print("Pos 5 "+TextFile as string)
)--End If TextFile
)
Else --Doesn't exist so try to create it.
TextFile =CreateFile TextFileName
Sleep 1 --Delay 1 sec. just to be safe.
If TextFile != undefined Then FileExists =True
--End If FileExists
)--End If SaveToFile
--unregistering previous definitions
--UnregisterRedrawViewsCallback Servo_R
UnregisterTimeCallback Servo_R --In case it's still registered from before
--Http socket open
Rollout HttpSock "HttpSock" width:0 height:0
(
ActiveXControl Port "Microsoft.XMLHTTP" SetupEvents:false ReleaseOnClose:false
);
createDialog HttpSock Pos:[-100,-100]; --Just to get it initialized.
destroyDialog HttpSock;
Fn Servo_R = -- Send the values from the Animator by scanning the Arrays
(
--Local Variables. Declaring them frist helps during debugging
If DebugScript Then
(
Local SleepVal ="0"
Local SleepStr =""
Local ServoStr =""
Local ServoVal =1.0
Local ValueStr =1.0
Local HttpStr =""
)
Local NextServo =1
While NextServo <= ServoNumbers.Count Do
(
ServoStr ="Servo(" +ServoNumbers[NextServo] +"," --Begin forming the servo string
ServoVal =ServoObjects[NextServo].pos.z
ValueStr =((ServoVal + 9) *10) as string
ServoStr =ServoStr +ValueStr +")" --Finish forming the servo string
HttpStr =ScriptCommPrefix +ServoStr --To send to the ARC
If SendToEZ == True Then --HTTP socket connect and send
(
HttpSock.Port.Open "GET" HttpStr False;
HttpSock.Port.Send(); --HTTP Server control in ARC must be running
)--End If SendToEZ
If PrintOutput Then Print(Format "%\n" HttpStr)
SleepVal =33.3333333333 as string
SleepStr ="Sleep(" + SleepVal + ")"
HttpStr =ScriptCommPrefix +SleepStr
If SendToEZ == True Then --HTTP socket connect and send
(
HttpSock.Port.Open "GET" HttpStr False;
HttpSock.Port.Send(); --HTTP Server control in ARC must be running
)--End If SendToEZ
If SaveToFile AND FileExists Then
(
Format "%\n" ServoStr to:Textfile
Format "%\n" SleepStr to:TextFile
)--End If SaveToFile
If PrintOutput Then
(
Print(Format "%\n" HttpStr)
Print(Format "%\n" ServoStr)
Print(Format "%\n" SleepStr)
)--End If PrintOutput
NextServo =NextServo +1
)--End While NextServo
)--End Fn Servo_R
--registerRedrawViewsCallback Servo_R
registerTimeCallback Servo_R
When using the code, it is best to employ a mono-spaced font so as to take advantage of the indentation. It lines up okay here since the code window uses a mono-spaced font. However, things like keywords and comments will not show up properly because the code window is made for displaying ARC script only. As I write this I can't see how it is, since there is no preview function here so I'll just have to discuss it as I think it will look. In a Maxscript Editor window, you can choose Options then click Use Monospaced Font. Unfortunately it seems you have to set that every time you open the editor window unless you change the settings in the Maxscript.Properties file. Which I did.
First off, what does it do? As I said, it's a first pass. It is basically code which was put together by Mickey666Maus who did a pretty good job of it. What I have done is addressed some problems he had with it and introduced formatting and good coding practices, as well as, some additional functionality.
What it does is take movements from a virtual robot created in 3ds and generates a series of statements that are designed to be sent to ARC to control a robot. As it stands now, it will control the robot in real time, following the movements of the virtual robot. This is done by sending thousands of Servo() instructions and Sleep instructions in pairs.
These instructions get to the EZ-Buider through one of two ways. One is via an HTTP Server port. The HTTP Server component is added to the project and set to run. At the 3ds end, HTTP statements are constructed and sent along to the HTTP Server via a network. Upon arrival, they are executed immediately, one after another. No script is needed on the ARC end to do this. Instruction execution is built in if the string sent is in the correct format.
The second way to send the information is via a disk file. One of the functions of the above script is to send these same instructions to a disk file. This file can be loaded into a script variable, decoded and run, line by line via a script. This accomplishes the two initial goals of the project. It's not perfect. The real-time movements are not smooth. And, with other things also running, it can get jerky with hesitations. Previous posts in this thread discuss the reasons for that.
Even though the real-time method is not perfected as would be liked, we are going to live with it for now to concentrate on a method which should provide smoother movements with many fewer instructions needed. I call this the Vector Method.
What the next pass at the Maxscript software will do is to monitor the virtual servos movements. The overall series of movements will begin with a starting point for all the servos. Then the script will watch each to see when a given one has either stopped or changed direction. When that happens, an end point will be said to have been established for that movement. An instruction set will be generated and sent to the robot, via the HTTP Server and (if desired) also sent to a text file. A new start point will be established at the end point from before and the sequence begins again.
Additionally, timers will be going that will allow a sleep period to be calculated to go along with the vector instruction. Finally, the time and distance moved will be used to determine a speed setting for the servo. How that last point will be done has not been determined as yet. The obvious answer would to use the ServoSpeed command, but even a small change in that setting seems to have a disproportionately large effect on servo speed, so using it may not work out. This method will not be Real-Time either. The robot will be one movement behind. This is because the movement instruction group cannot be calculated or sent out until that movement has completed. Of course that only matters when comparing it to the virtual robot, If using the disk file, you will never know it's happening.
Now, a word about the use and setup of the Maxscript.
Up front is a list of global variables which are used throughout script for data manipulation and storage, as well as, for control of feature selection. The first few are for that feature selection.
Global SaveToFile
When set to True, the data generated by the 3ds program and this script goes to a file.
Global SendToEZ
When set to True, the Send HTTP commands are allowed to be sent to the ARC HTTPServo control
Global PrintOutput
When set to True, The servo Instructions generated are displayed in Listener.
Global DebugScript When True the debug features are enabled.
The next part of the code that needs to be described is the servo Number - servo Name relationship. The servo Number is the usual designation for a servo port. D1, D10, etc. The servo Name is the name given to the virtual servo in the 3ds animation. For example in the current setup, these are: $SchulterRechts, $ArmLinks, and $HandRechts. There are two places these values are placed into variables. Lines 24 and 27. They are:
Global ServoNumbers = #("D3", "D4", "D5")
Global ServoObjects = #($SchulterRechts, $ArmLinks, $HandRechts)
This is where you would place your servo numbers and servo names.
NOTE: ORDER IS CRITICAL!
When these arrays are used to access the positions of the virtual servos, they are used in pairs. First to first, second to second, and so on. Having these lists allows the script to go through the servos in a loop, making for compact code. Several methods to do this were considered, including one which would have done all that automatically. But this was considered the most flexible. You can easily insert a new servo in the list or move everything down 1 as needed. Just follow the examples and be careful to maintain the one-to-one correspondence. Also, the servos in the list are used in the order they are listed so if you need a different order for some reason, keep that in mind.
If you decide to modify the code, which is fine, be aware of certain restrictions concerning Maxscript. The big concern during software development is that there is no built-in way to stop the script once it has been started. This seems like a big oversight on the people who make the software, but they no doubt have their reasons. And you WILL need to stop the script and restart it in development. As far as I have been able to tell from the web, there is only one way to stop it. Crash the script. To this end, I have put in a mechanism to do just that.
One of the great things about Maxscript is that you can make and display UI's (User Interfaces) right from the script. This means you can create a window populated with buttons and display areas and menus and drop down lists etc. right from the script. Then make them pop up wherever you want them for the user to see data and provide input as needed. When you are done with them, you can make them vanish as well.
When the DebugScript variable is set to True, one of the things that happens is that a small window will pop up shortly after you start the script. This window will have a button on it which will say "Stop Script". And that is just what it means. When you click it the program will crash and you will get a crash report in the Listener window. The script is now stopped. You can modify the script as you like and restart it again. If you don't do that and you restart the script, what you will actually be doing is starting a second copy of it. The first one will still be running. If there is something like having a file open in that first copy, you will not be able to access the file at all in the second copy because you will not be able to set a variable to it with an open command. Nor will you be able to close it or delete it. You're reading the voice of experience here.
One more thing about the Stop Script pop-up window. It can be positioned wherever you like when it appears. The call to make it show up is on line 44:
CreateDialog StopButton Pos:[1540,600]
The numbers at the end are X-Y co-ordinates in pixels. On my screen that places it about midway up to the screen and to the far right. You will want to adjust it for your screen. It's important it is moved away from the editor or Listener windows because they will tend to cover it up. Remember it's small, so you may have to look for it the first time.
Lines 12, 13, and 14 have places for you to put information specific to your setup.
Line 12 is the address from the HTTP Server control. It is the address in blue on the control itself. The upper one. Put it in place of the "NN.NNN ..." designations:
Global SockAddress ="NN.NNN.NNN.NNN"
Line 13 is the execution and logon data. Unless you change the password in the HTTP Server control, you will not need to change this line.
Global EZ_Logon ="Exec?password=admin&"
Line 14 is the filepath and name of the file to which you intend to write the data generated by the script. You can call it whatever you wish and locate it where ever you like. Just be sure the script will have write privileges to it:
Global TextFileName ="F:\Users\Bills\Desktop\movement.txt"
That's it for now. Questions and comments welcome!
I have no idea what this script says but nonetheless I'm blown away it's description. It must be an elegant and complex masterpeace judging from what you say and what little I actually understand of the code writing. You continue to amaze me. If I had just a 10th of your brain power and tried to apply it with your skill and drive I'd be exhausted most of the day. How do you do it?
@Mickey666Maus, yes some how I missed one of your posts. Thanks for the compliment. I've been working with a program Lightwave for many many years. Once you know one you kinda know thrm all. The interesting thing is animation is very much like animatronics which is what I do. For 20 years I have want to bring them together. Technology is finally here, but I don't know how to do any coding. But I have amazing ideas from my animatronic days that lend to robotics. The key to getting clean mo cap in filtering....kinda like turning an animation path from linear to a s spline ( curve) , the curve filters the highs and lows noise. The next solution is to build a telemetry suit where there is a potenometer at each joint to act as an input . The old Fashion way and a bit restricting. But my interest now lies in facial mo cap for advancing other test robots I have here.
Worst case if I can't find a partner, I'll start paying someone which is always good motivation!
@Dave Schulpius
Thank you for the praise. When you enjoy something it's not work and the knowledge comes easily and the hours pass all too swiftly. I enjoy programming. My meager efforts pale in comparison to your B9 though. That IS a work of art, Inside and out. Heck, this little program isn't even 150 lines. It will expand however ... soon. The real headbanging. "why did I ever get into this?!" stuff is about to start. Fun fun fun!
@fxrtst
Edited: (I should know better than try to post when I haven't had nearly enough sleep)
Thank you as well for your kind words. I would be glad to help with the coding you need, but it would be pretty much on a catch as catch can basis. At least what you need and what Mickey666Maus needs seem to dovetail, so much of what I would do can be used on both projects (I think). Assuming 3ds Maxscript can run under Maya. I'll have to look into that.
@fxrtst This looks supercool, recording motion capture myself was always one of my greatest desires...I will check on that sensor you mentioned! Is there a thread where you are explaining how you accomplished? Or will you probably make one for us?
The Kinect linked up to record motion also seems to be something worth exploring! I had my Kinect linked up to Motion Builer a long time ago...but the noise of the motion and the lack of real 3d capture made me stop working on this method for extracting motion data.
You seem to know a lot about animating, rigging and modeling in a 3D enviroment...as you know these days 3ds max and Maya are getting easier to use side by side, so I guess you should be able to use your Maya scenes from within 3ds max with a little tweaking! I think it should also be possible to script the same thing we are doing for 3ds max in Maya...but I dont know anything about its scripting language!
Awesome project...lets try to string it all together if possible!
@WBS00001 Cant wait to see what you came up with!
Sounds very much like what I trying to do here. Good question on the Maya and Max merge or one gets dropped. Autodesk owns them and I'm surprised that they continue to develop them all. Not sure if Maya and Max share the same plug in architecture, my first thought is probably not. The motion Capture program I am using only has a plug in for Maya live, but recorded motions can be sent to any animation package. Just need someone to write a python plug for them. This software was bought last year by a big company and they no longer support it but it is a full fledged working program for now. I believe they used it in the new Star Wars film for the female alien with the thick glasses.
I want to use it for controlling and recording motions for robots. Then I'll move onto full body capture. They use the same rotational values.
There comes a time in every software project when you have to stop tinkering with it and send it out into the world. This is very difficult for programmers to do. And so it is with the first pass on the Maxscript code I have written for this project. This will probably be a long post so don't say you weren't warned.
By way of disclaimer, I should say I have never worked with Maxscript or Python before this so the code is not as elegant as it could be. I still have a lot to learn. Additionally, I could have combined some operations in the code, but I decided to use separate variables to hold intermediate values (instead of putting the functions in-line) for better readability.
Basically as the code now stands, it is working software with debug statements sprinkled through it. The debugging statements can be turned on and off by setting the state of a global variable. Likewise with other functions. Here it is:
When using the code, it is best to employ a mono-spaced font so as to take advantage of the indentation. It lines up okay here since the code window uses a mono-spaced font. However, things like keywords and comments will not show up properly because the code window is made for displaying ARC script only. As I write this I can't see how it is, since there is no preview function here so I'll just have to discuss it as I think it will look. In a Maxscript Editor window, you can choose Options then click Use Monospaced Font. Unfortunately it seems you have to set that every time you open the editor window unless you change the settings in the Maxscript.Properties file. Which I did.
First off, what does it do? As I said, it's a first pass. It is basically code which was put together by Mickey666Maus who did a pretty good job of it. What I have done is addressed some problems he had with it and introduced formatting and good coding practices, as well as, some additional functionality.
What it does is take movements from a virtual robot created in 3ds and generates a series of statements that are designed to be sent to ARC to control a robot. As it stands now, it will control the robot in real time, following the movements of the virtual robot. This is done by sending thousands of Servo() instructions and Sleep instructions in pairs.
These instructions get to the EZ-Buider through one of two ways. One is via an HTTP Server port. The HTTP Server component is added to the project and set to run. At the 3ds end, HTTP statements are constructed and sent along to the HTTP Server via a network. Upon arrival, they are executed immediately, one after another. No script is needed on the ARC end to do this. Instruction execution is built in if the string sent is in the correct format.
The second way to send the information is via a disk file. One of the functions of the above script is to send these same instructions to a disk file. This file can be loaded into a script variable, decoded and run, line by line via a script. This accomplishes the two initial goals of the project. It's not perfect. The real-time movements are not smooth. And, with other things also running, it can get jerky with hesitations. Previous posts in this thread discuss the reasons for that.
Even though the real-time method is not perfected as would be liked, we are going to live with it for now to concentrate on a method which should provide smoother movements with many fewer instructions needed. I call this the Vector Method.
What the next pass at the Maxscript software will do is to monitor the virtual servos movements. The overall series of movements will begin with a starting point for all the servos. Then the script will watch each to see when a given one has either stopped or changed direction. When that happens, an end point will be said to have been established for that movement. An instruction set will be generated and sent to the robot, via the HTTP Server and (if desired) also sent to a text file. A new start point will be established at the end point from before and the sequence begins again.
Additionally, timers will be going that will allow a sleep period to be calculated to go along with the vector instruction. Finally, the time and distance moved will be used to determine a speed setting for the servo. How that last point will be done has not been determined as yet. The obvious answer would to use the ServoSpeed command, but even a small change in that setting seems to have a disproportionately large effect on servo speed, so using it may not work out. This method will not be Real-Time either. The robot will be one movement behind. This is because the movement instruction group cannot be calculated or sent out until that movement has completed. Of course that only matters when comparing it to the virtual robot, If using the disk file, you will never know it's happening.
Now, a word about the use and setup of the Maxscript.
Up front is a list of global variables which are used throughout script for data manipulation and storage, as well as, for control of feature selection. The first few are for that feature selection. Global SaveToFile
When set to True, the data generated by the 3ds program and this script goes to a file.
Global SendToEZ
When set to True, the Send HTTP commands are allowed to be sent to the ARC HTTPServo control
Global PrintOutput
When set to True, The servo Instructions generated are displayed in Listener.
Global DebugScript When True the debug features are enabled.
The next part of the code that needs to be described is the servo Number - servo Name relationship. The servo Number is the usual designation for a servo port. D1, D10, etc. The servo Name is the name given to the virtual servo in the 3ds animation. For example in the current setup, these are: $SchulterRechts, $ArmLinks, and $HandRechts. There are two places these values are placed into variables. Lines 24 and 27. They are:
This is where you would place your servo numbers and servo names.
When these arrays are used to access the positions of the virtual servos, they are used in pairs. First to first, second to second, and so on. Having these lists allows the script to go through the servos in a loop, making for compact code. Several methods to do this were considered, including one which would have done all that automatically. But this was considered the most flexible. You can easily insert a new servo in the list or move everything down 1 as needed. Just follow the examples and be careful to maintain the one-to-one correspondence. Also, the servos in the list are used in the order they are listed so if you need a different order for some reason, keep that in mind.
If you decide to modify the code, which is fine, be aware of certain restrictions concerning Maxscript. The big concern during software development is that there is no built-in way to stop the script once it has been started. This seems like a big oversight on the people who make the software, but they no doubt have their reasons. And you WILL need to stop the script and restart it in development. As far as I have been able to tell from the web, there is only one way to stop it. Crash the script. To this end, I have put in a mechanism to do just that.
One of the great things about Maxscript is that you can make and display UI's (User Interfaces) right from the script. This means you can create a window populated with buttons and display areas and menus and drop down lists etc. right from the script. Then make them pop up wherever you want them for the user to see data and provide input as needed. When you are done with them, you can make them vanish as well.
When the DebugScript variable is set to True, one of the things that happens is that a small window will pop up shortly after you start the script. This window will have a button on it which will say "Stop Script". And that is just what it means. When you click it the program will crash and you will get a crash report in the Listener window. The script is now stopped. You can modify the script as you like and restart it again. If you don't do that and you restart the script, what you will actually be doing is starting a second copy of it. The first one will still be running. If there is something like having a file open in that first copy, you will not be able to access the file at all in the second copy because you will not be able to set a variable to it with an open command. Nor will you be able to close it or delete it. You're reading the voice of experience here.
One more thing about the Stop Script pop-up window. It can be positioned wherever you like when it appears. The call to make it show up is on line 44: CreateDialog StopButton Pos:[1540,600]
The numbers at the end are X-Y co-ordinates in pixels. On my screen that places it about midway up to the screen and to the far right. You will want to adjust it for your screen. It's important it is moved away from the editor or Listener windows because they will tend to cover it up. Remember it's small, so you may have to look for it the first time.
Lines 12, 13, and 14 have places for you to put information specific to your setup.
Line 12 is the address from the HTTP Server control. It is the address in blue on the control itself. The upper one. Put it in place of the "NN.NNN ..." designations: Global SockAddress ="NN.NNN.NNN.NNN"
Line 13 is the execution and logon data. Unless you change the password in the HTTP Server control, you will not need to change this line. Global EZ_Logon ="Exec?password=admin&"
Line 14 is the filepath and name of the file to which you intend to write the data generated by the script. You can call it whatever you wish and locate it where ever you like. Just be sure the script will have write privileges to it: Global TextFileName ="F:\Users\Bills\Desktop\movement.txt"
That's it for now. Questions and comments welcome!
I have no idea what this script says but nonetheless I'm blown away it's description. It must be an elegant and complex masterpeace judging from what you say and what little I actually understand of the code writing. You continue to amaze me. If I had just a 10th of your brain power and tried to apply it with your skill and drive I'd be exhausted most of the day. How do you do it?
I know right Dave?!? Amazing! Impressive indeed. Hats off to you good sir!
@Mickey666Maus, yes some how I missed one of your posts. Thanks for the compliment. I've been working with a program Lightwave for many many years. Once you know one you kinda know thrm all. The interesting thing is animation is very much like animatronics which is what I do. For 20 years I have want to bring them together. Technology is finally here, but I don't know how to do any coding. But I have amazing ideas from my animatronic days that lend to robotics. The key to getting clean mo cap in filtering....kinda like turning an animation path from linear to a s spline ( curve) , the curve filters the highs and lows noise. The next solution is to build a telemetry suit where there is a potenometer at each joint to act as an input . The old Fashion way and a bit restricting. But my interest now lies in facial mo cap for advancing other test robots I have here.
Worst case if I can't find a partner, I'll start paying someone which is always good motivation!
@Dave Schulpius Thank you for the praise. When you enjoy something it's not work and the knowledge comes easily and the hours pass all too swiftly. I enjoy programming. My meager efforts pale in comparison to your B9 though. That IS a work of art, Inside and out. Heck, this little program isn't even 150 lines. It will expand however ... soon.
The real headbanging. "why did I ever get into this?!" stuff is about to start. Fun fun fun!
@fxrtst Edited: (I should know better than try to post when I haven't had nearly enough sleep) Thank you as well for your kind words. I would be glad to help with the coding you need, but it would be pretty much on a catch as catch can basis. At least what you need and what Mickey666Maus needs seem to dovetail, so much of what I would do can be used on both projects (I think). Assuming 3ds Maxscript can run under Maya. I'll have to look into that.