Welcome to the how-to control your InMoov servo services in MyRobotLab(MRL) using python and creating gestures tutorial.
#INSERT IMAGE
This tutorial assumes that you have already have a basic understanding of using MRL and the InMoov services (i01).
- Know how to launch servo services from the InMoov (i01) UI, calibrate and move your servos with the sliders in the servo services.
MyRobotLab (MRL)'s latest edition (Nixie) is still receiving constant updates, bug fixes, etc etc.
- Everytime something new is added, a bug is fixed, etc etc, an updated Ver of MRL releases.
- If you notice anything in this tutorial not working, it likely means you are using an outdated copy.
- Try and not fall too many versions behind.
Download latest version here:
You can transfer your saved services (calibrated servos, etc, etc) easily over to the updated version.
- Data for anything you have saved will be in the date folder. Example: "myrobotlab-1.1.1402\data\config".
- Tranfer that folder over to newest version's data folder. "Example: "myrobotlab-1.1.1411\data\config".
- Back in business. :)
As you open up the default InMoov Servo services, you will see them displayed on the left side panel.
- They are displayed with a Servo Icon, followed by the service names for each part.
The names of these servo services is what will be especially important as we move onto python.
You can access python from the tab on the left side. It will be in your service listing by default.
Since we will be experimenting and you may have other tabs open which launch with your i01 services by default, click "New" and enter a name.
- "Test" for example.
Now you should have a new tab open for whatever you named the file. "Test".
If you are completely new to python, it is a good idea to remember the # symbol.
#THIS IS AN EXAMPLE OF USING THE HASHTAG "#".
Using the hashtag symbol, we can let python know it should ignore anything following a "#" symbol. Any text following # will be displayed in green.
- Python will ignore all green text.
- This is useful for making notes for yourself or for others within your code.
- You can also use this to disable lines of code that you don't want read.
- Useful for temporarily disabling lines OR maintaining code you don't want read for potentially using again in the future. (Not so temporarily).
Line spacing (How many blank lines between lines) will not matter in python.
- You can spread lines out as much as you want to make things easier to find/manage.
#THIS IS AN EXAMPLE OF USING LINE SPACING.
#YEP!
To run a script you have written out, hit the "execute button".
You can run the following example from the above image for yourself to test it. It will do NOTHING! :D
#THIS IS A TEST SCRIPT WITH NO FUNCTION, EXECUTE ME!
Python is very picky with names. It generally does not like the names of the i01 services as they contain too many dots.
Make sure when using python to change the names of your servo services to use underscores " _ " instead of dots " . "
- i01.head.neck >>> i01_head_neck
- i01.leftArm.bicep >>> i01_leftArm_bicep
- etc, etc.
Here is a list of all the current i01 InMoov servo services currently available at the time of writing this tutorial.
If you're using for example i01_head_neck , it CANNOT be written with a different case of letters.
- It must be written with the same matching character case for python to know it is the same service.
If you forget to change the service names accordingly, you will likely see a traceback error like this.
Alternatively, if you do see errors at any time, the error will help you identify why there is an error and which line it can be found in.
- You will see the error listed in the bottom "console".
Here is another example of an error and how to identify it within the console.
In this case, the traceback error told us...
- The error occured in line 1.
- i01_head_neck is not defined. This is because it does NOT currently exist. I have not started the i01.head.neck servo service yet.
Movement ranges between ( 0° < 90 > 180° ). This will apply to servos with limited Min/Max settings as well and keep within your set limits.
In the image below, you can see that I have my "i01.torso.midStom" servo limited to Min:60 / Max: 120.
When moving the slider to the 0 position, it is moving the servo to my defined Min: 60 position despite still using a 0-180 range slider.
- Think of 0° as max rotation in one direction (according to your Min/Max limits)
- 180° as max rotation in the opposite direction. (according to your Min/Max limits)
- 90° will be your center position. (according to your Min/Max limits)
These same ranges will apply when moving your servos in python as well. Your servos will act the same way as the sliders.
Using the .moveTo() command line, we will be adding the desired position we want the servo to move to within the "( )".
- Example: i01_torso_midStom.moveTo(180)
i01_torso_midStom.moveTo(180)
You can see here, when I click back to the i01.torso.midStom servo service, it has moved the slider to the 180 position.
You can move as many DIFFERENT servos as you want at the same time!
i01_torso_topStom.moveTo(90)
i01_torso_midStom.moveTo(90)
Moving the SAME servo more than once will be continued below in "THE IMPORTANCE OF SLEEP".
Using .rest() will return the servo to your defined rest position.
i01_torso_midStom.rest()
.rest() will function the same way as if you click the Rest button in the servo service.
This can make life easier for you if you don't remember all rest positions.
When changing the speeds of you servos, you are actually setting speed limits to further reduce the speed of a servo.
The speed limit settings range between ( 0 - 200 + None )
- 0 - Slowest (likely not moving at this speed)
- 200 - Fastest "while still limited"
- None - Removes all speed limits = FULL SPEED (MAX)
SIDE NOTE: The speed limits only range between 0-200 with the slider. It is possible to go beyond 200 with python.
- It is hard to tell you exactly what the max limit range will be as it will depend on your servos.
- If you set it too high, you may not even notice a difference between the servos max speed and the limits applied.
- You likely won't need to go beyond 200, just it maybe possible. (You can experiment if so desiring to do so.)
Using the .setSpeed() command line, we will be adding the desired speed limit we want set for the servo within the "( )".
i01_head_neck.setSpeed(100)
As you can see, the speed limit was also changed in the i01.head.neck servo service as well.
Side Note: I'm not entirely sure at this time if the slider is bugged or this is intentional.
- The speed limit is set to 100, but the slider is still at the prior speed limit position. (semi useful for remembering prior set speed regardless)
- The speed limit IS being applied correctly.
.setSpeed(None) will remove all speed limits from the servo.
i01_head_neck.setSpeed(None)
Again if going back to the servo service, you can see that it has changed the speed limit to Max / removed limits.
Alternatively you can also use .setMaxSpeed() to accomplish the same speed limit removal as .setSpeed(None).
- Either way will work fine, they are essentially the same thing.
i01_head_neck.setMaxSpeed()
The desired speed limit for a servo must be set prior to moving the servo for the limits to apply.
- .setSpeed() will be written above the .moveTo() command.
i01_head_neck.setSpeed(200)
i01_head_neck.moveTo(90)
sleep() will be essential for you to get used to using as it plays such a big role in creating gestures, amongst other things.
The sleep() command line is what you will add to your code to break servo movements apart and let python know that it can wait a certain amount of time and then move onto the next movement line.
You will add the desired time length within the "( )" to add a pause before python moves to the next lines.
- You can use either milliseconds or seconds in the "( )" to create a pause/break.
sleep(1)
The following examples will hopefully show you why sleep() is so important.
You will NEED to add sleep() to your code to let it know there is a break between movements of the same servo! You will see in the following example why !!!!!
- Example 1: Move to 180 > wait 3s > move to 0 > wait 2s > return servo to center.
- The sleep timers are what allows to servo to reach its position before moving to the next.
i01_head_neck.moveTo(180)
sleep(3)
i01_head_neck.moveTo(0)
sleep(2)
i01_head_neck.moveTo(90)
WARNING!!!! Do not attempt this example.
- In this example, the servo will attempt to reach the 180 position and the 0 position at THE SAME TIME.
- Without adding a sleep() between the lines, python won't know that they are meant as two seperate movements.
Side Note: You likely won't break your servos if you forgot to include it.... but it is a good idea to try and avoid it.
- Things may get funny if you forget sleep().
As mentioned earlier, you can move as many different servos as wanting at the same time. Now we will move 5 servos together.
- All servos to 180 > sleep for 5s > all servos to 0 > sleep for 5s > all servos to 90 > sleep for 0.1s.
i01_head_neck.moveTo(180)
i01_head_rothead.moveTo(180)
i01_head_rollNeck.moveTo(180)
i01_leftArm_bicep.moveTo(180)
i01_rightArm_bicep.moveTo(180)
sleep(5)
i01_head_neck.moveTo(0)
i01_head_rothead.moveTo(0)
i01_head_rollNeck.moveTo(0)
i01_leftArm_bicep.moveTo(0)
i01_rightArm_bicep.moveTo(0)
sleep(5)
i01_head_neck.moveTo(90)
i01_head_rothead.moveTo(90)
i01_head_rollNeck.moveTo(90)
i01_leftArm_bicep.moveTo(90)
i01_rightArm_bicep.moveTo(90)
sleep(0.1)
In this example, you can see how to apply speed limits + move multiple servos > sleep > repeat to your hearts content or until you go crazy. :D
i01_head_neck.setSpeed(150)
i01_head_rothead.setSpeed(200)
i01_head_rollNeck.setSpeed(50)
i01_head_neck.moveTo(180)
i01_head_rothead.moveTo(180)
i01_head_rollNeck.moveTo(180)
sleep(7)
i01_head_neck.setSpeed(100)
i01_head_rothead.setSpeed(None)
i01_head_rollneck.setMaxSpeed()
i01_head_neck.moveTo(0)
i01_head_rothead.moveTo(0)
i01_head_rollNeck.moveTo(0)
sleep(3)
i01_head_neck.setSpeed(200)
i01_head_rothead.setSpeed(200)
i01_head_rollNeck.setSpeed(200)
i01_head_neck.moveTo(90)
i01_head_rothead.moveTo(90)
i01_head_rollNeck.moveTo(90)
It will be important when you first start playing with gestures to take it slow!
Even with a well calibrated robot, accidents can happen. Your servo calibration protects that servo and that part from breaking itself.
- It does NOT protect other servos from breaking that part.
Examples of try to avoid movements
-
Index and Thumb: When closing at the same time and speed, it is possible for them to bump.
- It is best to either adjust the speed limits or sleep timers so they will avoid each other.
-
If the shoulders rotate servo is rotated inwards, bicep raised and shoulder moved back, the arm can hit the stomach.
- This one can be avoided if the omoplate is also raised.
- However: Omoplate must have power to the servo or gravity cause it to come crashing down. (Auto-Disable timers: See below)
-
Certain movements with the arms are able to hit the head of the robot.
Get comfortable with smaller ranges of movement while moving various servos before pushing them to their limits!
You need to give a servo a reasonable enough time length to reach its position before sending it to the next position.
- In this example, the .sleep() timer is set so short, the servo cannot reach the 180 posistion before moving to the 0 position.
- It will still ATTEMPT to reach 180, but it's movement will get cut off and proceed to the 0 position.
It will take some practice getting used to how long sleep timers will need for each servo to be able to reach from position to position.
i01_torso_midStom.setSpeed(None)
i01_torso_midStom.moveTo(0)
sleep(10)
i01_torso_midStom.moveTo(180)
sleep(5)
i01_torso_midStom.moveTo(90)
sleep(2.5)
i01_torso_midStom.moveTo(0)
- Experiment with different length timers.
- You will need a longer timer moving a servo from 0 to 180 than you would moving it from 0 to 90.
- I suggest starting with slightly longer sleep times, run the code, reduce/adjust as needed, repeat until you are happy with it.
You will need to make sure your servos auto disable timers are long enough that the servo is able to reach its longest destination range.
- 0-180 for example. If you servo can reach from 0 - 180 within 5 seconds for example you know it is safe.
- You can continue to reduce and repeat until you have found an ideal auto disable timer.
- This can be a bit tricky once you apply different speed limits, so you will need to experiment.
USE WITH CAUTION!!!!
You really should not use these until you are very comfortable playing around with your servos.
- Auto disable timers are important as they help prevent your servos from burning out.
With the following example, we can disable the autoDisable timer within python and also re-enable it.
USE CASE:
-
Can be useful for when we need a servo to maintain power for longer than normal to hold a position.
- Omoplate is an example of a servo that requires power to be held up. Once autodisable kicks in, it can come crashing down.
-
Can use useful for when using slower speed limits to avoid autoDisable timer kicking in before destination reached.
I strongly suggest you don't use this until you have played with ALOT of gesture creation and start getting more and more fancy with them.
i01_head_neck.setAutoDisable(False)
sleep(5)
i01_head_neck.setAutoDisable(True) #REMEMBER ME!
And that is all I am going to cover for individual line servo commands! HOWEVER, there are more options available still!
I'll be updating this page over the next few days, more updates to come shortly. o/
=======================================================
Servo groups are another way you can control your servos in python.
Think of Servo Groups as a condensed version of ".moveTo()" or ".setSpeed()" for multiple servos which are sorted into limb sections.
- head = neck, rothead, eyeX, eyeY, jaw, rollNeck
- Arm = bicep, rotate, shoulder, omoplate
- Hand = thumb, index, majeure, ringFinger, pinky, wrist
- torso = topStom, midStom & lowStom.
Benefits of groups:
- Hugely decrease the amount of lines in your code.
Negatives of groups:
- You MUST remember which value represents which servo or you might move the wrong servo unexpectedly.
- Accidents can happen when moving the wrong servos depending on the various servo positions.
- Not all servos have groups! See below in "MISSING GROUPS".
Looking at the example, we will see four numbers within the ( ). The order in which they appear is important!
- Each of these numbers represent a specific servo and the position we want to move it to.
- In this case, the first value "10" represents i01.leftArm.bicep and that we want to move it to the 10 position.
- For ARMS and HANDS you will see either "left" or "right" initially within the ( ) which determines which side Arm or Hand you are moving.
#Example: Moving all 4 "left" Arm servos (bicep / rotate / shoulder / omoplate)
i01.moveArm("left",10,80,40,20)
#PLEASE USE EXAMPLE BELOW INSTEAD OF TESTING THIS EXAMPLE!
I suggest testing each servo group with only moving one servo at a time while you get used to using groups to avoid accidents.
#Example: Moving only the left bicep servo. (bicep / rotate / shoulder / omoplate)
i01.moveArm("left",10,None,None,None)
More safe to try examples below!
HEAD EXAMPLES:
#Setting the whole group speed limit to 200.
i01.setHeadSpeed(200,200,200,200,200,200) #(neck,rothead,eyeX,eyeY,jaw,rollNeck)
#Moving only the neck within the group.
i01.moveHead(100,None,None,None,None,None) #(neck,rothead,eyeX,eyeY,jaw,rollNeck)
LEFT ARM EXAMPLES:
#Setting the whole group speed limit to 200.
i01.setArmSpeed("left",200,200,200,200) #("left",bicep,rotate,shoulder,omoplate)
#Moving only "left" bicep within the group.
i01.moveArm("left",10,None,None,None) #("left",bicep,rotate,shoulder,omoplate)
RIGHT ARM EXAMPLES:
#Setting the whole group speed limit to 200.
i01.setArmSpeed("right",200,200,200,200) #("right",bicep,rotate,shoulder,omoplate)
#Moving only "right" bicep within the group.
i01.moveArm("right",10,None,None,None) #("right",bicep,rotate,shoulder,omoplate)
LEFT HAND EXAMPLES:
#Setting the whole group speed limit to 200.
i01.setHandSpeed("left",200,200,200,200,200,200) #("left",thumb,index,majeure,ringFinger,wrist)
#Moving only "left" wrist within the group.
i01.moveHand("left",None,None,None,None,None,180) #("left",thumb,index,majeure,ringFinger,wrist)
RIGHT HAND EXAMPLES:
#Setting the whole group speed limit to 200.
i01.setHandSpeed("right",200,200,200,200,200,200) #("right",thumb,index,majeure,ringFinger,wrist)
#Moving only "right" wrist within the group.
i01.moveHand("right",0,None,None,None,None,None) #("right",thumb,index,majeure,ringFinger,wrist)
TORSO EXAMPLES:
#Setting the whole group speed limit to 200.
i01.setTorsoSpeed(200,200,200) #(topStom,midStom,lowStom)
#Moving only "midStom" within the group.
i01.moveTorso(None,90,None) #(topStom,midStom,lowStom)
Remember not to confuse "None" between movement and speed settings in groups. They have different functions.
-
MOVEMENT: Ignore Servo
-
SPEED: Remove limits
V2 Head Servos
- As of when I am writing this, there are currently no group setting for the V2 head.
- The V2 head is still very new and I believe code side things are still being planned out.
i01.head.eyelidLeft & i01.head.eyelidRight
- While there is a service for i01.head.eyelidLeft & i01.head.eyelidRight, they were not part of the official build.
- They were added to allow people to explore with mods and are NOT part of any groups.
There are a few V1 head servo sub-groups which were made over the years. You can use them as well if so desiring to do so.
If you ever explore the built-in gestures folder, you may come across some examples of lines looking like the following example.
- (There is more info relating to built-in gestures at the bottom of this page.)
You can see in the below example which values represent which servo.
-
They are very similar to the Servo Groups mentioned above.
i01.moveHead(100,100) #(neck,rothead)
i01.moveHead(100,100,100) #(neck,rothead,rollNeck)
#i01.moveHead(100,100,100,100) DOESN'T EXIST / WILL CAUSE TRACEBACK ERROR
i01.moveHead(100,100,100,100,100) #(neck,rothead,eyeX,eyeY,jaw)
i01.moveHead(100,100,100,100,100,100) #(neck,rothead,eyeX,eyeY,jaw,rollNeck) Full group.
I don't personally ever use these, but they exist as an option.
- Atleast you will understand what role "i01.moveHead(100,100)" plays now if you see it in the gestures folder.
- I believe "01.setHeadSpeed(100,100)" for example will also work for these sub groups.
In order to use speech in python, you will need a mouth.
......"01.mouth" service that is. :)
There are two different ways to achieve speech.
- i01.speak()
- i01.speakBlocking()
#i01.speak() vs i01.speakBlocking()
i01.speak("I am speaking RIGHT NOW!")
sleep(4)
i01.speakBlocking("Now I am speak Blocking! Haha")
When using i01.speak() , you will place the text you want spoken between quotes within the ( ).
- Example: "I am speaking" >>> i01.speak("I am speaking")
This is the simplest way to achieve speech.
i01.speak("I am speaking now. Test test Test!")
Here is another example of using the same example above while the head is in motion.
#You will see the head continue to move back and forth as speech is happening.
i01_head_rothead.setSpeed(50)
i01_head_rothead.moveTo(50)
sleep(1.5)
i01.speak("I am speaking now. Test test Test!")
i01_head_rothead.moveTo(130)
sleep(1.5)
i01_head_rothead.moveTo(50)
sleep(1.5)
i01_head_rothead.moveTo(130)
sleep(1.5)
i01_head_rothead.moveTo(90)
Another way to achieve speaking is with i01.speakBlocking().
The same rule applies when using i01.speakBlocking(). Place spoken text between quotes within between the ( ).
i01.speakBlocking("Now I am speak Blocking! Haha")
The major difference with i01.speakBlocking() is that it will "Block" all of the following lines in your script until it is done saying whatever is within the ().
- This means if you have a .moveTo() command following i01.speakBlocking(), it will not move until the speech is complete.
#In this example you can see rothead will only move to the 130 position AFTER i01_mouth.speakBlocking() is complete.
i01_mouth.speakBlocking("Now I am speak Blocking! Haha")
i01_head_rothead.moveTo(130)
You will notice in the above example that there is no sleep() timer before the .moveTo().
i01.speakBlocking() is acting like a sleep timer in this situation by "blocking" all lines following until speech is complete.
- This acts as a "break" in the code which resembles a sleep() timer with the duration the length of the spoken text.
- Because of this, sleep() is not needed. Adding a sleep() would further extend the time before moveTo() begins.
It is personal preference honestly. Extra options are always nice.
I know Gael has used i01.speakBlocking() in various gestures over the years.
- You can find some examples of his usage in various built-in gestures. (Info at bottom)
Benefits of i01.speak():
- You can move various servos even while speech is occuring which is useful for more advanced gestures.
- Your bot won't come to a stand still while waiting for the spoken text to finish.
- This means though you need to figure out sleep() timer lengths for when speech applies during which movements, etc.
Benefits of i01.speakBlocking():
- You don't have to worry about adding a sleep() timer and figuring out time lengths.
- You know exactly when the following lines will start since it waits/blocks until speech is finished.
- This option can make creating gestures easier/faster for you.
- but also limits what can be done during speech.
Generally I want various servos to be able to move even while the bot is still speaking to avoid any awkward pauses in a gesture.
- That is why I almost always use i01.speak().
- There maybe some ideal use cases for i01.speakBlocking() which I can't think due to not using it often. shrug
=======================================================
When defining your gestures, you will need to change the format from what we have used so far.
- The number of initial spaces doesn't matter, but must remaining consistent for all lines.
- There are exceptions to this in more complex examples which we are not worried about at this point.
def examplescripttest1():
i01_head_rothead.moveTo(130)
sleep(4)
i01_head_rothead.moveTo(50)
sleep(4)
i01_head_rothead.moveTo(90)
#### <--- 4 spaces.
def examplescripttest2():
i01_head_rothead.moveTo(130)
sleep(4)
i01_head_rothead.moveTo(50)
sleep(4)
i01_head_rothead.moveTo(90)
## <--- 2 spaces.
def examplescripttest3():
i01_head_rothead.moveTo(130)
sleep(4)
i01_head_rothead.moveTo(50)
sleep(4)
i01_head_rothead.moveTo(90)
#### <--- 4 spaces with tabs. = Bad practice, but MRL saves us... this time.
NOTE: You may have noticed that I have 3 different things defined here.
- You can have as many different things defined in one script as you want!
- Obviously it can be hard to find them all again easily if you add hundreds of them into the same file, but ... its possible.
Once your script looks ready, you will need to hit execute for it to be able to run them.
- Note: This will not "run" the individual scripts, but rather make them able to be ran as seen in the next step.
Here I have opened up another tab to be able to test the scripts from above.
- You can see the format for how we will test them once they have been executed. (As seen above)
- In this example, I have hastagged out the other two examples so I can test one at a time. (Adding and removing #)
- Hit execute to run the script. (This time, it will move the servos or whatever is in the defined script.)
examplescripttest1()
#examplescripttest2()
#examplescripttest3()
Here I have opened another new tab and have given it the name "exampletestscripts".
- When hitting the save button, this is the name that it will output the .py file as.
When the file is saved, it can be found in your MRL(ver) root folder.
- You can change the name to whatever you want after you save it too of course.
If you save a file with the same name as a file still in your root directory, it will be overwritten!
- Using different names is always a good idea for safety. This is why I suggest naming your tab to whatever you want to call the file.
- Also not keeping the files in your root directory is a good idea as well which we will get into next!
REASONS:
- When you close MRL, whatever you have written in the python service will vanish. If you haven't saved it, it is lost.
OTHER SOFTWARE:
- I will be using VScode in these examples as it is free to download and useful for us in this situation.
- You can download VScode here: https://code.visualstudio.com/
REASONS:
-
When closing VScode, your code will remain! You would need to close the specific tab for that code to get rid of it.
-
This is very important for not losing your hard work on your gestures. Accidents happen or you forget to save things.
- You can do the same type of thing using Notepad++ as well, but VScode will be used for this example.
When you first open up VScode and hit "File > New", it will appear like this.
- Click "Select a language" and select "Python".
It will now format it to look like this for you and you are good to go. Safe gesture storage = win!
Note: VScode also auto-converts tabs for you. :9
Example: Here you can see I have a MRL folder created for the various versions of MRL for when updating.
-
I have created a "Custom" folder within that folder to put my various files in when I use MRL regardless of version.
- It can be named anything you want, the pathway to the folder files are what we are concerned with.
-
The important thing is that this folder is not within any specific version of MRL.
- With its own location, it can be applied to other versions easily.
- Avoid using complex names or symbols is suggested as things could get strange/errors.
For now I have moved the "examplescripttests.py" file from earlier into the root of my Custom folder.
Note: "BasicMovement" I made for small basic "gestures" moving both eyes left for example.
- The "Gestures" folder is where I generally put things that are more complex than one or two movements.
- Completely upto you how you set things up and or what you keep in the folder. :)
All the data from any config you have saved will be located in the Data\Config folder.
- Start up whatever i01 services you want > runtime > save config > "whichever name."
- When loading the config name you saved it with should be listed as well.
For example: I have named my config i01Syntek as I am running my bot "Syntek" with the i01 InMoov services.
- This is why you can see a i01Syntek folder. :)
Inside your service folder, you will want to locate the "python.yml" file and open it up.
- notepad /note++/whatever text editor you want.
You will be looking at startScripts:
- There should be brackets [ ] by default.
Starting on the line following "startScripts:" you will want to list all your python scripts you want included and loaded at startup.
- inclue a - followed by the file location. Example below.
- C:\MRL\Custom\examplescripttests.py
- C:\MRL\Custom\randomnametestscript.py
One you have entered whichever scripts you want included, save the file and then boot MRL.
Boot your config (runtime > start "saved config name") and click over to python.
- You will see that the scripts do not autoload instantly and appear not to be there.
- Click "load and apply configuration"
Now you can see the scripts are all loaded in. You do NOT need to execute them, they are loaded in as such.
Now you can see I opened up a new "test" tab to try and run one of the example scripts, hit execute and magic. It works.
If you DON'T load your scripts into MRL after you boot up your config, and then you happen to save your config from runtime:
- They WILL vanish from the python.yml startScripts: list!
- Without them loading in, the config will assume startScripts is empty and overwrite that file.
- You will need to enter them into the list again if that happens.
It can be useful to make a text backup of the python.yml file to be able to copy and paste back in the script list - just incase.
- This can save you needing to remember which scripts you have included, if for example you have a long list of scripts.
THIS WILL MAKE UPDATING TO NEW VERSIONS OF MRL MUCH EASIER.
- The new chatbot will be tied to your
data\config
folder and not the current MRL version you are running. - This way when you update to new versions, all you need to worry about is bringing your
config
folder over.
=======================================================
Find the chatbot you will want to clone in the MRL(version#)\resource\ProgramAB
folder. Copy it!
- There are a number of different bots already there. Most of them are for different language support.
- Choose the language you will be using.
In this case, I am using English and I copied en-US
.
Going back to the Custom
folder I made earlier, I have also made a new folder in it called Chatbot
.
- You can call things whatever you want. The file pathway is what we care about.
Paste the copied en-US
folder into your Chatbot
folder and rename it! Renaming the folder is IMPORTANT!
- I renamed mine
Syntek
as that is my robots name, name it whatever you would like. :)
After it is copy/pasted and renamed, we will ignore the folder for a few steps.
Now we will head back to your config folder MRL(ver)\data\config\
and locate the i01.chatBot.yml
.
When you open up i01.chatBot.yml
initially, it should look like this by default.
- You can keep all the bots on the list or remove them as wanted.
Note: I had already changed mine, so I made a default i01.chatBot.yml
in another config.
ERROR WARNING: If you are migrating your config folder over from a previous version of MRL, you may have an outdated i01.chatBot.yml
.
You will need to remove botDir: resource/ProgramAB
from Line 2
.
- This line can cause errors and needs to be removed from older versions of
i01.chatBot.yml
.
Add the new location of your chatbot into the bot:
list and save.
=======================================
Open MRL and start your config from runtime. Head over to the i01.chatBot
tab and confirm your bots name is selected.
- It should already be selected by default if you only had one chatbot in your
i01.chatBot.yml
. - It you have multiple chatbots, change it to whichever one you will be using when moving onto adding voice commands.
IF you had multiple chatbots:
- Remember to first
load and apply settings
frompython
to avoid losing scripts included inpython.yml
prior to saving config. - Save config from
runtime
. (This will keep your new chatbot as the default when loading your config now).
Now we will return to our chatbot folder. MRL\Custom\Chatbot\Syntek\
Within that folder we will be using a file named _inmoovGestures.aiml
located within the aiml
folder.
- Example location:
MRL\Custom\Chatbot\Syntek\aiml\_inmoovGestures.aiml
Here we can see an example of the format in which voice commands within _inmoovGestures.aiml
will work.
CLOSE HANDS
- will be the voice command said to the robot.Closing my hands.
- Will be how the robot responds. (This is optional, you can leave it blank if you don't want a response.)handsclose()
- is the defined gesture name.
NOTE: What you say MUST match the command exactly. If in this example you said "Closed Hands", or "Close Hand" it will not work.
- Unless of course you have made another command with that differently phrased voice command, or one already exists.
Now we will add a new voice command of our own. I have placed this towards the bottom of the _inmoovGestures.aiml
.
- The new voice command must be located above the
</aiml>
at the bottom to work or not cause an error.
You can use this as an outline if wanting and add it to your _inmoovGestures.aiml
.
<category><pattern>TEST YOUR NECK FOR ME</pattern>
<template>Testing my neck.
<oob><mrl><service>python</service><method>exec</method><param>examplescripttest1()</param></mrl></oob></template>
</category>
Don't forget to load and apply configuration
from python
to load your scripts prior to trying voice commands!
- They will not work if you haven't loaded your scripts yet!
- See IMPORTING YOUR GESTURES -
load and apply configuration
.
This has been updated to the link below.
https://github.com/CyberSyntek/i01InMoovIntro
InMoov built in gestures folder location.
- "myrobotlab-1.1.1402\resource\InMoov2\gestures"
You may want to explore this a bit and examine the various gesture examples you have available to you already.
Keep in mind when I say explore, I mean examine the code rather then run them.
- Some of the premade gestures are only partial gestures. They are not all made to run on their own.
- What this means is, one gesture might end in a position in which it was made to flow into another gesture.
- If you are running just the partial gesture, it may not end in a safe place if it can't flow to the next.
- Once autoDisable kills the power to certain servos, gravity may force them to come down on their own. (Risk of breaking something).
I'm planning on breaking that down a bit sometime near future and making a list to highlight the safe to run examples.
- Some of them are safe as is, but I suggest you get used to reading the code before you run them so you can tell for yourself.
- OR... wait for my list. :)
THINGS TO UPDATE
- audioFile? (Jaw responses to audio)
- audioPlayer? (Jaw does NOT respond to audio)
- Examples of Examples! Exploring the many other script examples available.
- print() (Why it is a good idea to add this to your script!)