Example 3 - DDE do_list Functions

Copy and paste the following job into DDE and read and follow the directions below

function my_function_1(){
	out("my_function_1")
    return Dexter.move_all_joints([30, 30, 0, 0, 0])
}

function my_function_2(){
	out("my_function_2")
    return Dexter.move_all_joints([30, 30, 30, 0, 0])
}

function my_function_3(){
	out("my_function_3")
    return Dexter.move_all_joints([0, 0, 0, 0, 0])
}

new Job({
	name: "Example_3",
    do_list: [
    	Dexter.move_all_joints([0, 0, 0, 0, 0]),
        Dexter.move_all_joints([30, 0, 0, 0, 0]),
        my_function_1,
        my_function_2(),
        Dexter.empty_instruction_queue(),
        my_function_3,
        Dexter.empty_instruction_queue(),
        function(){
        	out("my_function_4a")
    		return Dexter.move_all_joints([0, 0, 0, 0, 30])
        },
        Dexter.empty_instruction_queue(),
        function(){
        	out("my_function_4b")
    		return Dexter.move_all_joints([0, 0, 0, 0, 0])
        },
        Dexter.empty_instruction_queue(),
        function(){
        	out("my_function_5")
    		return [
            	Dexter.move_all_joints([0, 0, 0, 0, 30]),
                Dexter.move_all_joints([0, 0, 0, 0, 0])
            ]
        },
        Dexter.empty_instruction_queue(),
        function(){
        	out("my_function_6")
            let CMD = [
            	Dexter.move_all_joints([0, 0, 0, 0, 30]),
                Dexter.move_all_joints([0, 0, 0, 0, 0])
            ]
    		return CMD
        },
        Dexter.empty_instruction_queue(),
        function(){
        	out("my_function_7")
            let CMD = []
            CMD.push(Dexter.move_all_joints([0, 0, 0, 0, 30]))
            CMD.push(Dexter.move_all_joints([0, 0, 0, 0, 0]))
    		return CMD
        },
        Dexter.empty_instruction_queue()
    ]
})

/*
To Run:
Eval and run the Job.

Notice:

-The order in which the print statements are printed.
- Why does my_function_2 happen before my_function_1?
-The timing of the print statement for my_function_1 vs my_function_3.
-Where is the print statement for my_function_2?
-Is there is functional difference between any of the my_functions 4a-7?

Challenge:

Edit the above code in order to do the following:
a. Get the print statement for my_function_1 to show up after the two move_all_joints above it.
b. Get the print statement for my_function_2 to show up after my_function_1.
c. Write a new Job that:
-Has three unique move_all_joints.
-with each move_all_joints being returned by a different type of function.
-Print statements for when the move_all_joints is start and has completed.
Name this new Job 'Example_3_c'

Explanation:

Something that is unique about Javascript is that everything is a variable.
This includes function definitions.
Meaning you can store function definitions into variables or put them onto an array:

        var x = function my_function(){
out("Hello World")
}
x()

or

	var y = [1, 2, function my_function(){out("Goodbye World")}]
y[2]()

or

	function my_function(){
out("Hi World")
}
var z = [1, 2, my_function]
z[2]()

Notice in this last example that just the function name is there, there is no "()".
If the parenthesis were there it would be called when the variable is defined instead:

	var z = [1, 2, my_function()]

In terms of Jobs this would mean calling the function when the 'Eval' button is clicked not while the Job is running.
The two phrases for these are:
- Job definition time
- Job run time

Most of the time you want functions to be run at Job run time.
This way they can make decisions using the current state of Dexter.
In some cases you would want a function to be run at Job definition time.
One example is parsing and running a g-code file. Running the function at Job definition time would mean doing all the time consuming parsing and computation before the Job is run. This way the g-code will run more smoothly and it most likely will not be changing it trajectory while it's running.

Function definitions can be named like:

function my_function(){
out("Hello World")
}

or could be un-named:

function(){
out("Hello World")
}

These are called 'anonymous functions'.
Normally anonymous functions are useless because once you define them you have no name to call them with.
However, if an anonymous function is an element in an array it can be called.
In normal Javascript anonymous functions are typically used in callbacks
where a process may take some time but when it's done it will call the anonymous function:

setTimeout(function(){out("this will take 5 seconds to print")}, 5000)

A process like this will cause problems if you want to keep things in order:

var my_var = 0
setTimeout(function(){out("I want this to print first"); my_var = 10}, 3000)
out("I want this to print second. Value of my_var: " + my_var)

Code that moves something in physical reality, like Dexter, is basically guaranteed to take some non-instantaneous amount of time, due the laws of physics.
So you have to make a choice:
Do you want the code to stop everything it's doing while it waits for Dexter to physical move?
It may take up to minutes to complete a motion.
The word for this is synchronous.

Or

Do you want to continue to do non-movement related tasks while Dexter is moving?
This could be anything from a print statement to live monitoring of the movement.
The word for this is a-synchronous.

The answer is you want both, but for certain situations.

By default when you have a series of Dexter.move_all_joints() on a do list it will be a-synchronous, and move on to the next instruction after the Instruction is sent but
before the move is complete.
This will allow you to do print statements, update GUI's, monitor the movement, or pre-compute complicated motion.
In order to make it synchronous you'll have to add the following Instruction after each

Dexter.move_all_joints:
Dexter.empty_instruction_queue()

In DDE do_lists on Jobs are essentially chains of callbacks.
If the current do_list item is a function definition it will call it and anything it returns will be added to the do_list below it.
This is useful because functions can generate Instructions or even arrays of Instructions.

In Example_3's code my_function_4a through my_function_7 all have the same functionality.
Some of them return single Instructions, others return arrays of the same Instructions.

A standard that has been adopted by most DDE users is to
-create an empty array at the top of the function named 'CMD' for 'command'
-then push each new Instruction onto that array
-and finally return the CMD array (even if it's empty)

You will see this convention used in many of these Examples.