diff --git a/core/dextersim.js b/core/dextersim.js
index 773cfcc2..a8859504 100644
--- a/core/dextersim.js
+++ b/core/dextersim.js
@@ -146,6 +146,11 @@ DexterSim = class DexterSim{
//so just leave that as it is--apr 2019
if (this.sim_actual === true){
let rob = this.robot
+ if((rs_copy[Dexter.INSTRUCTION_TYPE] == "r") &&
+ (typeof(payload_string_maybe) == "number") &&
+ (payload_string_maybe > 0)){
+ rs_copy[Dexter.ERROR_CODE] = payload_string_maybe
+ }
setTimeout(function(){
Socket.on_receive(rs_copy, rob.name, payload_string_maybe)
}, 1)
@@ -422,13 +427,11 @@ DexterSim = class DexterSim{
let whole_content
try { whole_content = read_file(source) }//errors if path in "source" doesn't exist
catch(err){
- return 1 //return the error code
+ return 2 //return the error code
}
let start_index = hunk_index * Instruction.Dexter.read_file.payload_max_chars
let end_index = start_index + Instruction.Dexter.read_file.payload_max_chars
let payload_string = whole_content.substring(start_index, end_index) //ok if end_index is > whole_cotnent.length, it just gets how much it can, no error
- //out("some content from " + source + " hunk: " + hunk_index + " payload: " + payload_string)
- //Socket.r_payload_grab_aux(instruction_array, payload_string)
return payload_string
}
//Dexter.write_file
diff --git a/core/index.js b/core/index.js
index 98d97907..817564b4 100644
--- a/core/index.js
+++ b/core/index.js
@@ -109,7 +109,11 @@ var Coor = require("../math/Coor.js")
var Kin = require("../math/Kin.js")
var Vector = require("../math/Vector.js")
var Job = require("./job.js")
+
var {Robot, Brain, Dexter, Human, Serial} = require("./robot.js")
+var {Control} = require("./instruction_control.js")
+var {IO} = require("./instruction_io.js")
+
var {out} = require("./out.js")
var calibrate_build_tables = require("../low_level_dexter/calibrate_build_tables.js")
var DXF = require("../math/DXF.js")
@@ -119,6 +123,8 @@ global.Dexter = Dexter
global.make_ins = Dexter.make_ins
global.out = out
global.Robot = Robot
+global.Control = Control
+global.IO = IO
global.Job = Job
global.Vector = Vector
global.Kin = Kin
diff --git a/core/instruction.js b/core/instruction.js
index 584d577a..21a8e4ab 100644
--- a/core/instruction.js
+++ b/core/instruction.js
@@ -443,8 +443,8 @@ Instruction.break = class Break extends Instruction{ //class name must be upper
do_item (job_instance){
let loop_pc = Instruction.loop.pc_of_enclosing_loop(job_instance)
if (loop_pc === null) {
- warning("Job " + job_instance.name + ' has a Robot.break instruction at pc: ' + job_instance.program_counter +
- "
but there is no Robot.loop instruction above it.")
+ warning("Job " + job_instance.name + ' has a Control.break instruction at pc: ' + job_instance.program_counter +
+ "
but there is no Control.loop instruction above it.")
job_instance.set_up_next_do(1)
}
else {
@@ -458,7 +458,7 @@ Instruction.break = class Break extends Instruction{ //class name must be upper
}
}
toString(){ return "break" }
- to_source_code(args){ return args.indent + "Robot.break()" }
+ to_source_code(args){ return args.indent + "Control.break()" }
}
Instruction.debugger = class Debugger extends Instruction{ //class name must be upper case because lower case conflicts with js debugger
@@ -468,7 +468,7 @@ Instruction.debugger = class Debugger extends Instruction{ //class name must be
job_instance.set_up_next_do(1, true)
}
toString(){ return "debugger" }
- to_source_code(args){ return args.indent + "Robot.debugger()" }
+ to_source_code(args){ return args.indent + "Control.debugger()" }
}
Instruction.error = class error extends Instruction{
@@ -489,11 +489,11 @@ Instruction.error = class error extends Instruction{
args = jQuery.extend({}, arguments[0])
args.value = this.reason
args.indent = ""
- return this_indent + "Robot.error(" + to_source_code(args) + ")"
+ return this_indent + "Control.error(" + to_source_code(args) + ")"
}
}
-//upper case G to avoid a conflict, but the user instruction is spelled Robot.get_page
+//upper case G to avoid a conflict, but the user instruction is spelled Control.get_page
Instruction.Get_page = class Get_page extends Instruction{
constructor (url_or_options, response_variable_name="http_response") {
super()
@@ -535,7 +535,7 @@ Instruction.Get_page = class Get_page extends Instruction{
else { job_instance.set_up_next_do(1)} //got the response, move to next instruction
}
to_source_code(args){
- return args.indent + "Robot.get_page(" +
+ return args.indent + "Control.get_page(" +
to_source_code({value: this.url_or_options}) +
((this.response_variable_name == "http_response") ? "" : (", " + to_source_code({value: this.response_variable_name}))) +
")"
@@ -566,14 +566,14 @@ Instruction.go_to = class go_to extends Instruction{
job_instance.set_up_next_do(0)
}
}
- toString(){ return "Robot.go_to instruction_location: " + this.instruction_location }
+ toString(){ return "Control.go_to instruction_location: " + this.instruction_location }
to_source_code(args){
let this_indent = args.indent
args = jQuery.extend({}, arguments[0])
args.value = this.instruction_location
args.indent = ""
- return this_indent + "Robot.go_to(" + to_source_code(args) + ")"
+ return this_indent + "Control.go_to(" + to_source_code(args) + ")"
}
}
@@ -634,7 +634,7 @@ Instruction.grab_robot_status = class grab_robot_status extends Instruction{
args.value = this.end_index
args.indent = ""
let ei_src = to_source_code(args)
- return this_indent + "Robot.grab_robot_status(" +
+ return this_indent + "Control.grab_robot_status(" +
ud_src + ", " + si_src + ", " + ei_src + ")"
}
}
@@ -1768,9 +1768,9 @@ Instruction.if_any_errors = class if_any_errors extends Instruction{
let the_error_ins = this.instruction_if_error
if (the_error_ins == null){
let message = "In job: " + job_instance.name +
- ", an instruction of type: Robot.if_any_errors, " +
+ ", an instruction of type: Control.if_any_errors, " +
"discovered that job: " + job_name + " has errored."
- the_error_ins = Robot.error(message)
+ the_error_ins = Control.error(message)
}
job_instance.insert_single_instruction(the_error_ins)
break;
@@ -1778,7 +1778,7 @@ Instruction.if_any_errors = class if_any_errors extends Instruction{
}
else {
job_instance.stop_for_reason("errored", "In job: " + job_instance.name +
- ", an instruction of type: Robot.if_any_errors
" +
+ ", an instruction of type: Control.if_any_errors
" +
"was passed a job name of: " + job_name + "
that doesn't exist.")
job_instance.set_up_next_do(0)
return
@@ -1787,7 +1787,7 @@ Instruction.if_any_errors = class if_any_errors extends Instruction{
job_instance.set_up_next_do(1)
}
to_source_code(args){
- return args.indent + "Robot.if_any_errors(" +
+ return args.indent + "Control.if_any_errors(" +
to_source_code({value: this.job_names}) + ", " +
to_source_code({value: this.instruction_if_error}) + ")"
}
@@ -1797,7 +1797,7 @@ Instruction.include_job = class include_job extends Instruction{
constructor (job_name, start_loc, end_loc) {
super()
if(job_name === undefined){
- dde_error("Robot.include_job was not passed a job_name which is required.")
+ dde_error("Control.include_job was not passed a job_name which is required.")
}
this.job_name = job_name
//It *might* be good to permit job_name to be a job obj, but
@@ -1815,7 +1815,7 @@ Instruction.include_job = class include_job extends Instruction{
if(!name_of_job_to_include.startsWith("Job.")) { name_of_job_to_include = "Job." + name_of_job_to_include }
let job_to_include = value_of_path(name_of_job_to_include)
if(!(job_to_include instanceof Job)) {
- dde_error("Robot.include_job passed a job_name: " + this.job_name +
+ dde_error("Control.include_job passed a job_name: " + this.job_name +
"
that is not bound to a Job, but rather: " + job_to_include)
}
let the_start_loc = ((this.start_loc === null) ? job_to_include.orig_args.program_counter : this.start_loc)
@@ -1845,7 +1845,7 @@ Instruction.include_job = class include_job extends Instruction{
if(first_arg.startsWith("Job.")) {
resolved_first_arg = value_of_path(first_arg)
if(!(resolved_first_arg instanceof Job)){
- dde_error("Robot.include_job's first argument: " + first_arg +
+ dde_error("Control.include_job's first argument: " + first_arg +
"
resolved to: " + resolved_first_arg +
"
but was expected to resolve to a Job instance.")
}
@@ -1866,7 +1866,7 @@ Instruction.include_job = class include_job extends Instruction{
let file_src = read_file(first_arg)
let result_obj = eval_js_part2(file_src, false) // warning: calling straight eval often doesn't return the value of the last expr in the src, but my eval_js_part2 usually does. //window.eval(file_src)
if(result_obj.error_message){
- dde_error("Robot.include_job's first argument: " + first_arg +
+ dde_error("Control.include_job's first argument: " + first_arg +
"
refers to an existing file but
" +
"that file contains the JavaScript error of:
" +
err.message)
@@ -1881,7 +1881,7 @@ Instruction.include_job = class include_job extends Instruction{
if(file_src.startsWith("var ")){
let equal_sign_pos = file_src.indexOf("=")
if(equal_sign_pos == -1){
- dde_error("Robot.include_job's first argument: " + first_arg +
+ dde_error("Control.include_job's first argument: " + first_arg +
"
refers to an existing file containing variable: " + var_name + ".
" +
"However, their is no equal sign after 'var'")
}
@@ -1892,7 +1892,7 @@ Instruction.include_job = class include_job extends Instruction{
do_list_array_to_use = var_val
}
else {
- dde_error("Robot.include_job's first argument: " + first_arg +
+ dde_error("Control.include_job's first argument: " + first_arg +
"
refers to an existing file containing variable: " + var_name + ".
" +
"However, the value is not an array of instructions, but rather:
" +
var_val)
@@ -1902,7 +1902,7 @@ Instruction.include_job = class include_job extends Instruction{
}
}
else {
- dde_error("Robot.include_job's first argument: " + first_arg + " has a dot in it
" +
+ dde_error("Control.include_job's first argument: " + first_arg + " has a dot in it
" +
"so it is presumed to be a file path
" +
"but no such file exists.")
}
@@ -1910,7 +1910,7 @@ Instruction.include_job = class include_job extends Instruction{
else if (window[first_arg]) {
resolved_first_arg = window[first_arg]
if(!Array.isArray(resolved_first_arg)) {
- dde_error("Robot.include_job's first argument: " + first_arg + " is a variable
" +
+ dde_error("Control.include_job's first argument: " + first_arg + " is a variable
" +
"but the value of the variable is not an array:
" +
resolved_first_arg)
}
@@ -1919,20 +1919,20 @@ Instruction.include_job = class include_job extends Instruction{
}
}
else {
- dde_error("Robot.include_job, got a first argument of: " + first_arg +
+ dde_error("Control.include_job, got a first argument of: " + first_arg +
"
which is invalid because, although it is a string,
" +
"it isn't a Job name, file name, nor variable name.")
}
} //end of first_arg is a string processing
else {
- dde_error("Robot.include_job, got a first argument of: " + first_arg +
+ dde_error("Control.include_job, got a first argument of: " + first_arg +
"
which is invalid because its not a Job, array, or string.")
}
//at this point either the above code errored, or we have
//resolved_first_arg set to a Job or a do_list array and
//do_list_array_to_use set to an array
if(Instruction.is_oplet_array(do_list_array_to_use)){
- dde_error("Robot.include_job, got a first argument of: " + first_arg +
+ dde_error("Control.include_job, got a first argument of: " + first_arg +
"
but that resolved to an oplet array: " + do_list_array_to_use +
"
which is not a valid array of instruction.
" +
"If you wrap this oplet array in an outer array, it will be valid.")
@@ -1954,12 +1954,12 @@ Instruction.include_job = class include_job extends Instruction{
if(the_end_loc == null) { the_end_loc = do_list_array_to_use.length }
}
if(!is_non_neg_integer(the_start_loc)){
- dde_error("Robot.include_job passed start_loc of: " + this.start_loc +
+ dde_error("Control.include_job passed start_loc of: " + this.start_loc +
"
but that resolved to: " + the_start_loc +
"
which is not a non-negative integer.")
}
else if(!is_non_neg_integer(the_end_loc)){
- dde_error("Robot.include_job passed end_loc of: " + this.end_loc +
+ dde_error("Control.include_job passed end_loc of: " + this.end_loc +
"
but that resolved to: " + the_end_loc +
"
which is not a non-negative integer.")
}
@@ -1972,7 +1972,7 @@ Instruction.include_job = class include_job extends Instruction{
}
to_source_code(args){
- return args.indent + "Robot.include_job(" +
+ return args.indent + "Control.include_job(" +
to_source_code({value: this.job_name}) + ")"
}
}
@@ -1991,7 +1991,7 @@ Instruction.label = class label extends Instruction{
}
toString(){ return this.name }
to_source_code(args){
- return args.indent + "Robot.label(" +
+ return args.indent + "Control.label(" +
to_source_code({value: this.name}) + ")"
}
}
@@ -2019,7 +2019,7 @@ Instruction.loop = class Loop extends Instruction{
//If on a normal iteration with more to come, the last inst returned will be a
//go_to to this loop instruction. (and that go_to might be the ONLY instruction in the returned array)
//else if null is returned, we're done with this loop.
- //the returned instruction array may contain a Robot.break instruction that
+ //the returned instruction array may contain a Control.break instruction that
//ends this loop. That ending is handled in Job.prototype.do_next_item section that handles loop
get_instructions_for_one_iteration(job_instance){ //strategy: compute:
//1. iter_index, 2. iter_total,3. iter_val & iter_key, 4. instructions for this iteration & return them
@@ -2041,7 +2041,7 @@ Instruction.loop = class Loop extends Instruction{
else if (typeof(fn_result) == "number"){
if(is_non_neg_integer(fn_result)) { this.resolved_times_to_loop = fn_result; this.iter_total = this.resolved_times_to_loop}
else {
- job_instance.stop_for_reason("errored", "Robot.loop passed times_to_loop that returned a number: " + fn_result +
+ job_instance.stop_for_reason("errored", "Control.loop passed times_to_loop that returned a number: " + fn_result +
"\n but it isn't a non-negative integer.")
return null
}
@@ -2053,13 +2053,13 @@ Instruction.loop = class Loop extends Instruction{
this.iter_total = this.resolved_times_to_loop.length
}
else if (typeof(fn_result) == "function") { this.resolved_times_to_loop = fn_result} //rare but possible. //leave iter_total at Infinity
- else { job_instance.stop_for_reason("errored", "Robot.loop passed function for boolean_int_array_number but that function" +
+ else { job_instance.stop_for_reason("errored", "Control.loop passed function for boolean_int_array_number but that function" +
"\n returned an invalid type: " + fn_result +
"\n It must return a boolean, non-negative integer, array, or function")
return null
}
}
- else { job_instance.stop_for_reason("errored", "Robot.loop passed times_to_loop of:\n " +
+ else { job_instance.stop_for_reason("errored", "Control.loop passed times_to_loop of:\n " +
this.times_to_loop +
"\n but that is not one of the valid types of:\n boolean, non-negative integer, array, or function.")
return null
@@ -2074,7 +2074,7 @@ Instruction.loop = class Loop extends Instruction{
this.resolved_times_to_loop = null //ready for next start of this job
return null
}
- else if (this.resolved_times_to_loop === true){ iter_val = true } //loop forever or until body_fn returns Robot.break instruction
+ else if (this.resolved_times_to_loop === true){ iter_val = true } //loop forever or until body_fn returns Control.break instruction
else if(is_non_neg_integer(this.resolved_times_to_loop)){
iter_val = this.iter_index
}
@@ -2093,13 +2093,13 @@ Instruction.loop = class Loop extends Instruction{
}
else if (fn_result === true) { iter_val = true }
else {
- job_instance.stop_for_reason("errored", "Robot.loop passed a function to call to determine if another iteration should occur" +
+ job_instance.stop_for_reason("errored", "Control.loop passed a function to call to determine if another iteration should occur" +
"\n but that function returned: " + fn_result +
"\n however, only true and false are valid results.")
return null
}
}
- else { shouldnt("Robot.loop has an invalid this.resolved_times_to_loop of: " + this.resolved_times_to_loop)}
+ else { shouldnt("Control.loop has an invalid this.resolved_times_to_loop of: " + this.resolved_times_to_loop)}
if(this.iter_index >= this.iter_total) { //done looping but initialize so if the job is restrted, the loop will restart
this.resolved_times_to_loop = null
return null
@@ -2117,13 +2117,13 @@ Instruction.loop = class Loop extends Instruction{
//below we add the go_to at the end.
}
//body_fn_result can legitimately be the empty array at this point.
- //it might also contain a Robot.break instruction.
+ //it might also contain a Control.break instruction.
let go_to_ins = new Instruction.go_to(job_instance.program_counter)
body_fn_result.push(go_to_ins)
return body_fn_result
}
}
- //when called, pc of job_instance will (as of Jun 11 ) be to a Robot.break instruction
+ //when called, pc of job_instance will (as of Jun 11 ) be to a Control.break instruction
//Just search backwards for the first loop instruction and return its pc.
//If job_instance.program_counter happens to be pointing at a loop,
//its just returned.
@@ -2135,7 +2135,7 @@ Instruction.loop = class Loop extends Instruction{
return null // not good. we didn't find an enclosing loop. this will become a warning.
}
to_source_code(args){
- return args.indent + "Robot.loop(" +
+ return args.indent + "Control.loop(" +
to_source_code({value: this.times_to_loop}) + ",\n" +
to_source_code({value: this.body_fn}) +
")"
@@ -2150,13 +2150,13 @@ Instruction.out = class Out extends Instruction{
this.temp = temp
}
do_item (job_instance){
- let message = "Job: " + job_instance.name + ", instruction ID: " + job_instance.program_counter + ", Instruction type: Robot.out
" + this.val
+ let message = "Job: " + job_instance.name + ", instruction ID: " + job_instance.program_counter + ", Instruction type: IO.out
" + this.val
out(message, this.color, this.temp)
job_instance.set_up_next_do(1)
}
- toString() { return "Robot.out of: " + this.val }
+ toString() { return "IO.out of: " + this.val }
to_source_code(args){
- return args.indent + "Robot.out(" +
+ return args.indent + "IO.out(" +
to_source_code({value: this.val}) +
((this.color == "black") ? "" : (", " + to_source_code({value: this.color}))) +
(this.temp ? (", " + to_source_code({value: this.temp})) : "") +
@@ -2235,7 +2235,7 @@ Instruction.send_to_job = class send_to_job extends Instruction{
}
}
to_source_code(args){
- return args.indent + "Robot.send_to_job({" +
+ return args.indent + "Control.send_to_job({" +
((this.do_list_item == null) ? "" : ("do_list_item: " + to_source_code({value: this.do_list_item}) + ", ")) +
((this.where_to_insert === undefined) ? "" : ("where_to_insert: " + to_source_code({value: this.where_to_insert}) + ", ")) +
((this.wait_until_done === false) ? "" : ("wait_until_done: " + to_source_code({value: this.wait_until_done}) + ", ")) +
@@ -2378,12 +2378,12 @@ Instruction.sent_from_job = class sent_from_job extends Instruction{
Instruction.start_job = class start_job extends Instruction{
constructor (job_name, start_options={}, if_started="ignore", wait_until_job_done=false) {
if(!["ignore", "error", "restart"].includes(if_started)){
- dde_error("Robot.start_job has invalid value for if_started of: " +
+ dde_error("Control.start_job has invalid value for if_started of: " +
if_started +
'
Valid values are: "ignore", "error", "restart"')
}
if(![true, false].includes(wait_until_job_done)){
- dde_error("Robot.start_job has invalid value for wait_until_job_done of: " +
+ dde_error("Control.start_job has invalid value for wait_until_job_done of: " +
if_started +
'
Valid values are: true and false')
}
@@ -2412,17 +2412,17 @@ Instruction.start_job = class start_job extends Instruction{
let jobs_in_file = Job.instances_in_file(this.job_name)
if(jobs_in_file.length > 0) { this.job_to_start = jobs_in_file[0] }
else {
- dde_error("Robot.start_job has a job_name that's a path to an existing file: " + this.job_name + "
" +
+ dde_error("Control.start_job has a job_name that's a path to an existing file: " + this.job_name + "
" +
"but that file doesn't define any jobs.")
}
}
else {
- dde_error("Robot.start_job has a job_name of: " + this.job_name +
+ dde_error("Control.start_job has a job_name of: " + this.job_name +
"
but it doesn't resolve to a Job or a file containing one.")
}
}
if(!(this.job_to_start instanceof Job)){
- job_instance.stop_for_reason("errored", "Robot.start_job attempted to start non-existent Job." + this.job_name)
+ job_instance.stop_for_reason("errored", "Control.start_job attempted to start non-existent Job." + this.job_name)
job_instance.set_up_next_do(0)
}
}
@@ -2446,14 +2446,14 @@ Instruction.start_job = class start_job extends Instruction{
return
}
else if(["starting", "running"].includes(stat)) {
- job_instance.wait_reason = "Robot.start_job waiting at instruction " +
+ job_instance.wait_reason = "Control.start_job waiting at instruction " +
job_instance.program_counter + " for " + this.job_to_start.name + " to complete."
job_instance.set_status_code("waiting")
job_instance.set_up_next_do(0)
return
}
else if(stat == "waiting") {
- job_instance.wait_reason = "Robot.start_job waiting at instruction " +
+ job_instance.wait_reason = "Control.start_job waiting at instruction " +
job_instance.program_counter + " for " + this.job_to_start.name + " to complete,\n" +
"but its now waiting for: " + this.job_to_start.wait_reason
job_instance.set_status_code("waiting")
@@ -2462,7 +2462,7 @@ Instruction.start_job = class start_job extends Instruction{
}
else if (stat == "suspended") {
this.job_to_start.unsuspend()
- job_instance.wait_reason = "Robot.start_job waiting at instruction " +
+ job_instance.wait_reason = "Control.start_job waiting at instruction " +
job_instance.program_counter + " for " + this.job_to_start.name + " to complete."
job_instance.set_status_code("waiting")
job_instance.set_up_next_do(0)
@@ -2511,7 +2511,7 @@ Instruction.start_job = class start_job extends Instruction{
}
else { //if_started is tested for validity in the constructor, but just in case...
shouldnt("Job." + job_instance.name +
- " has a Robot.start_job instruction with an invalid " +
+ " has a Control.start_job instruction with an invalid " +
"
if_started value of: " + this.if_started)
}
}
@@ -2520,7 +2520,7 @@ Instruction.start_job = class start_job extends Instruction{
job_instance.set_up_next_do(1)
}
else {
- shouldnt("Robot.start_job got a status_code from Job." +
+ shouldnt("Control.start_job got a status_code from Job." +
this.job_to_start.name + " that it doesn't understand.")
}
}
@@ -2528,7 +2528,7 @@ Instruction.start_job = class start_job extends Instruction{
return "start_job: " + this.job_name
}
to_source_code(args){
- return args.indent + "Robot.start_job(" +
+ return args.indent + "Control.start_job(" +
to_source_code({value: this.job_name}) +
(similar(this.start_options, {}) ? "" : (", " + to_source_code({value: this.start_options}))) +
((this.if_started == "ignore") ? "" : (", " + to_source_code({value: this.if_started}))) +
@@ -2549,7 +2549,7 @@ Instruction.stop_job = class stop_job extends Instruction{
if (!job_to_stop) { job_to_stop = job_instance }
job_to_stop.ending_program_counter = this.instruction_location
if (!this.stop_reason){
- this.stop_reason = "Stopped by Job." + job_instance.name + " instruction: Robot.stop_job."
+ this.stop_reason = "Stopped by Job." + job_instance.name + " instruction: Control.stop_job."
}
job_to_stop.stop_for_reason("completed", this.stop_reason, this.perform_when_stopped)
//this is not an error or interrupted, its a normal stoppage of the job.
@@ -2572,7 +2572,7 @@ Instruction.stop_job = class stop_job extends Instruction{
props_args.value = this.perform_when_stopped
let pws_src = to_source_code(props_args)
let result = indent +
- "Robot.stop_job(" +
+ "Control.stop_job(" +
loc_src + ", " +
sr_src + ", " +
pws_src +
@@ -2604,7 +2604,7 @@ Instruction.suspend = class suspend extends Instruction{
}
}
to_source_code(args){
- return args.indent + "Robot.suspend(" +
+ return args.indent + "Control.suspend(" +
to_source_code({value: this.job_name}) +
((this.reason == "") ? "" : (", " + to_source_code({value: this.reason}))) +
")"
@@ -2636,7 +2636,7 @@ Instruction.unsuspend = class unsuspend extends Instruction{
}
to_source_code(args){
- return args.indent + "Robot.unsuspend(" +
+ return args.indent + "Control.unsuspend(" +
to_source_code({value: this.job_name}) +
")"
}
@@ -2711,7 +2711,7 @@ Instruction.sync_point = class sync_point extends Instruction{
}
}
to_source_code(args){
- return args.indent + "Robot.sync_point(" +
+ return args.indent + "Control.sync_point(" +
to_source_code({value: this.name}) + ", " +
to_source_code({value: this.job_names}) +
")"
@@ -2730,7 +2730,7 @@ Instruction.wait_until = class wait_until extends Instruction{
else if (Array.isArray(this.fn_date_dur) ||
(typeof(this.fn_date_dur) == "object")){
if(!Job.instruction_location_to_job(this.fn_date_dur, false)){
- warning("Robot.wait_until passed an array or literal object
" +
+ warning("Control.wait_until passed an array or literal object
" +
"for an instruction location but
" +
"it does not contain a job.
" +
"That implies this job will wait for itself, and thus forever.
" +
@@ -2739,7 +2739,7 @@ Instruction.wait_until = class wait_until extends Instruction{
}
else if (fn_data_dur instanceof Job) {}
else {
- dde_error("Robot.wait_until instruction passed: " + this.fn_date_dur +
+ dde_error("Control.wait_until instruction passed: " + this.fn_date_dur +
'
which is not a number, date, function,
' +
'"new_instruction" or instruction location array.')
}
@@ -2787,7 +2787,7 @@ Instruction.wait_until = class wait_until extends Instruction{
//so that we can keep the tcp connection alive, send a virtual heartbeat
let new_wait_dur_in_sec = this.fn_date_dur - (dur_from_start_in_ms / 1000)
let new_instructions = [make_ins("g"), //just a do nothing to get a round trip to Dexter.
- Robot.wait_until(new_wait_dur_in_sec)] //create new wait_until to wait for the remaining time
+ Control.wait_until(new_wait_dur_in_sec)] //create new wait_until to wait for the remaining time
job_instance.insert_instructions(new_instructions)
//job_instance.added_items_count[job_instance.program_counter] += 2 this is done automatically by insert_instructions
this.start_time_in_ms = null //essential for the 2nd thru nth call to start() for this job.
@@ -2865,7 +2865,7 @@ Instruction.wait_until = class wait_until extends Instruction{
var loc_pc = loc_job_instance.instruction_location_to_id(this.fn_date_dur)
if(loc_pc > loc_job_instance.program_counter){ //wait until loc_job_instance advances
if(loc_job_instance.stop_reason){
- warning("Robot.wait_until is waiting for job: " + loc_job_instance.name +
+ warning("Control.wait_until is waiting for job: " + loc_job_instance.name +
"
but that job is stopped, so it will probably wait forever.")
}
job_instance.wait_reason = "a wait_until instruction_location is reached."
@@ -2887,7 +2887,7 @@ Instruction.wait_until = class wait_until extends Instruction{
}
}
to_source_code(args){
- return args.indent + "Robot.wait_until(" +
+ return args.indent + "Control.wait_until(" +
to_source_code({value: this.fn_date_dur, function_names: true}) +
")"
}
diff --git a/core/instruction_control.js b/core/instruction_control.js
new file mode 100644
index 00000000..24b45c01
--- /dev/null
+++ b/core/instruction_control.js
@@ -0,0 +1,24 @@
+var {Robot} = require('./robot.js')
+
+class Control{}
+
+Control.break = Robot.break
+Control.go_to = Robot.go_to
+Control.loop = Robot.loop
+Control.label = Robot.label
+Control.suspend = Robot.suspend
+Control.unsuspend = Robot.unsuspend
+Control.sync_point = Robot.sync_point
+Control.wait_until = Robot.wait_until
+
+Control.include_job = Robot.include_job
+Control.send_to_job = Robot.send_to_job
+Control.sent_from_job = Robot.sent_from_job
+Control.start_job = Robot.start_job
+Control.stop_job = Robot.stop_job
+
+Control.debugger = Robot.debugger
+Control.error = Robot.error
+Control.if_any_errors = Robot.if_any_errors
+
+module.exports.Control = Control
\ No newline at end of file
diff --git a/core/instruction_dexter.js b/core/instruction_dexter.js
index b4d755fa..ecf28a29 100644
--- a/core/instruction_dexter.js
+++ b/core/instruction_dexter.js
@@ -689,7 +689,7 @@ Instruction.Dexter.read_file = class read_file extends Instruction.Dexter{
if(!this.robot) { this.set_instruction_robot_from_job(job_instance) }
if (this.first_do_item_call) {
const sim_actual = Robot.get_simulate_actual(this.robot.simulate)
- //have to check for dexter_file_systems or else the 2nd time I rn the job, it will
+ //have to check for dexter_file_systems or else the 2nd time I run the job, it will
//have a double length path with 2 dexter_file_systems parts
if (!this.source.startsWith("/") && (sim_actual === true) && !this.source.startsWith("dexter_file_systems")) {
this.fuller_source = "dexter_file_systems/" + this.robot.name + "/" + this.source
@@ -703,23 +703,23 @@ Instruction.Dexter.read_file = class read_file extends Instruction.Dexter{
//the below can never happen
//if (this.is_done) {
// this.processing_r_instruction = false
- // return Robot.break()
+ // return Control.break()
//}
let read_file_instance = this
let robot = this.robot //closed over
- job_instance.insert_single_instruction(Robot.loop(true, function(content_hunk_index){
+ job_instance.insert_single_instruction(Control.loop(true, function(content_hunk_index){
let job_instance = this
if (read_file_instance.is_done) {
//init this inst just in case it gets used again
read_file_instance.is_done = false
read_file_instance.first_do_item_call = true
read_file_instance.processing_r_instruction = false
- return Robot.break()
+ return Control.break()
}
else {
read_file_instance.processing_r_instruction = true
return [make_ins("r", content_hunk_index, read_file_instance.fuller_source, robot),
- Robot.wait_until(function(){
+ Control.wait_until(function(){
return !read_file_instance.processing_r_instruction
})
]
@@ -744,6 +744,7 @@ Instruction.Dexter.read_file = class read_file extends Instruction.Dexter{
}
//called from socket.js
+ //payload_string_maybe is a string or an error code (an int > 0)
static got_content_hunk(job_id, ins_id, payload_string_maybe){
let job_instance = Job.job_id_to_job_instance(job_id)
if (job_instance == null){
@@ -764,9 +765,13 @@ Instruction.Dexter.read_file = class read_file extends Instruction.Dexter{
}
}
- //used by Dexter.write_file too
+ //used by Dexter.write_file to prepare path for passing it to make_ins("W" ...)
+ //because the path used for write_file defaults to "srv/samba/share/dde_apps",
+ //whereas the path for make_ins("W" ...) defaults to srv/samba/share
+ //see Dexter.srv_samba_share_default_to_absolute_path to do the opposite
static add_default_file_prefix_maybe(path){
- if(path.startsWith("/")) { return path }
+ if (path.startsWith("/")) { return path }
+ else if (path.startsWith("#")) { return path }
else if (path.startsWith("./")) { return "dde_apps/" + path.substring(2) }
else if (path.startsWith("../")) { return path.substring(3) } //will go to dexrun's default foler, ie /srv/samba/share/
else { return "dde_apps/" + path }
diff --git a/core/instruction_io.js b/core/instruction_io.js
new file mode 100644
index 00000000..8089e3c6
--- /dev/null
+++ b/core/instruction_io.js
@@ -0,0 +1,16 @@
+var {Robot} = require('./robot.js')
+
+class IO{}
+
+IO.get_page = Robot.get_page
+IO.grab_robot_status = Robot.grab_robot_status
+IO.out = Robot.out
+IO.show_picture = Robot.show_picture
+IO.show_video = Robot.show_video
+IO.take_picture = Robot.take_picture
+//read_file and write_file are Dexter-specific instructions only,
+//so they are under Dexter.read_file and Dexter.write_file
+
+module.exports.IO = IO
+
+
diff --git a/core/job.js b/core/job.js
index 8871b7f8..22b6fa45 100644
--- a/core/job.js
+++ b/core/job.js
@@ -253,10 +253,10 @@ class Job{
inter_do_item_dur: 0.005, //we don't need to have fast communication with Dexter. Minimize traffic
do_list:[
Dexter.write_file("job/run/" + dde_monitor_job_instance.name + ".dde", job_src),
- Robot.loop(true,
+ Control.loop(true,
function(){
if(this.user_data.dexter_log !== undefined) { //got a dexter log meaning the monitored job is over.
- return Robot.break()
+ return Control.break()
}
else if ((this.user_data.stop_job_running_on_dexter) &&
(!this.user_data.already_handled_stop_job)) { //set by clicking the job button
@@ -1658,7 +1658,7 @@ Job.prototype.handle_start_object = function(cur_do_item){
}
}
else if(cur_do_item.dur) {
- this.insert_single_instruction(Robot.wait_until(cur_do_item.dur))
+ this.insert_single_instruction(Control.wait_until(cur_do_item.dur))
}
if (!start_args) { cur_do_item.start.apply(the_inst_this) }
else if (Array.isArray(start_args)) { cur_do_item.start.apply(the_inst_this, start_args) }
@@ -2261,7 +2261,7 @@ Job.prototype.increment_added_items_count_for_parent_instruction_of = function(i
(type_of(par_loc_index) == "number") &&
(par_loc_index < this.program_counter)) { //backwards goto in same job
let loop_inst_maybe = this.do_list[par_loc_index]
- if(loop_inst_maybe instanceof Robot.loop){ //shoot, we can't make the inserted instruction a sub_object of a loop's go_to
+ if(loop_inst_maybe instanceof Control.loop){ //shoot, we can't make the inserted instruction a sub_object of a loop's go_to
//so we've got to climb up the tree and increment the next instr that has a positive added_items_count
//but that aic must "contain" the instr_id of the added instruction
for(let maybe_par_id = par_loc_index - 1; maybe_par_id >= 0; maybe_par_id--){
diff --git a/core/out.js b/core/out.js
index f9626490..05ffdbfb 100644
--- a/core/out.js
+++ b/core/out.js
@@ -108,6 +108,7 @@ function out_eval_result(text, color="#000000", src){
src = replace_substrings(src, "'", "'")
src_formatted = " " + src_formatted + src_formatted_suffix + "
"
}
+ //if (src_formatted == "") { console.log("_____out_eval_result passed src: " + src + " with empty string for src_formatted and text: " + text)}
text = "
simulate=true
and run it.")
+ "simulate=true
and run it.")
}
else if (this_robot.simulate === null){
if ((sim_actual === false) || (sim_actual === "both")){
this_job.stop_for_reason("errored", "The job: " + this_job.name + " is using robot: " + this_robot.name +
- 'Robot.debugger
+ on the do_list is run. If the running Job executes a Control.debugger
instruction, that will also cause the job to pause.
When a job is paused, clicking the button will cause
@@ -768,16 +766,16 @@ Robot.debugger()
in a do_list will cause
+ Control.debugger()
in a do_list will cause
the pause checkbox to be checked and the job to pause.
- A function that returns the result of Robot.debugger()
or
- even an array that has an element of the result of Robot.debugger()
+ A function that returns the result of Control.debugger()
or
+ even an array that has an element of the result of Control.debugger()
will cause a pause.
- You can insert this instruction using the Learn JS menu/Debugging etc/Robot.debugger().
+ You can insert this instruction using the Learn JS menu/Debugging etc/Control.debugger().
- Note that using Robot.debugger()
+ Note that using Control.debugger()
is intentionally similar to using the JavaScript constant debugger
.
If you have the constant debugger
in the body of a function that is a do_list item, or is called by
@@ -1073,7 +1071,7 @@ Robot.stop
to end a job immediately without processing the insructions after the stop instruction,
- and Robot.wait_until
which pauses execution of the job's instructions until
+ and Control.wait_until
which pauses execution of the job's instructions until
the calling of the given JS function returns true.
See submenu "robot" for details about robots as
@@ -1413,10 +1411,10 @@ Robot.out("some data")
creates an
+ IO.out("some data")
creates an
instruction in a Job's do_list to print content to the output console
with similar functionality to out
- See Robot.out.new Job({show_instructions=some_fn})
lets you call an arbitrary function (with clever defaults) before each
diff --git a/doc/mental_model_of_memory.html b/doc/mental_model_of_memory.html
index b941695e..293c572d 100644
--- a/doc/mental_model_of_memory.html
+++ b/doc/mental_model_of_memory.html
@@ -36,7 +36,7 @@ Robot.send_to_job
.
+the instruction Control.send_to_job
.
Dangerous and ProductiveRobot.wait_until
returns false when it is called
+ If the function arg to Control.wait_until
returns false when it is called
by the job running process, the Job continues
waiting. Hit the ESC key on the keyboard to end the wait_until.
Because Gamepad.down_keys()
@@ -657,8 +657,8 @@
new Job({
name: "gamepad_job1",
- do_list: [Robot.out("Press RIGHT arrow or ESC to exit."),
- Robot.wait_until(function(){
+ do_list: [IO.out("Press RIGHT arrow or ESC to exit."),
+ Control.wait_until(function(){
let dks = Gamepad.down_keys() //returns array of down key objects
if (dks.length == 0){ return false } //keep waiting
else if (dks[0].keyname == "ESCAPE"){ //end the "wait_until"
@@ -674,7 +674,7 @@
return false //keep waiting
}
}),
- Robot.out("done")
+ IO.out("done")
]})
new Job({name: "my_job",
- do_list: [Robot.show_picture()]})
-
+ There is a corresponding instruction, IO.show_picture
new Job({name: "my_job",
- do_list: [Robot.show_video()]})
-
+There is a corresponding instruction IO.show_video
Picture.take_picture()
Picture.take_picture({callback: inspect})
-Robot Instructionthis
bound to the job
-this instruction is running in.new Job({name: "my_job",
- do_list: [Robot.take_picture({
- callback: "my_pic"})]})
-
- Job.my_job.user_data.my_pic
Midi.init()
Midi.all_notes_off
.
-This can also be called by choosing Insert menu/Sound/Midi.init().
+This can also be called by choosing Insert menu/Sound/Midi.init().get_page
retrieves the contents of a web page.
- You pass in a url and get_page returns the contents as a string.
- The argument can either be a string of a url, or a literal JS object.get_page
retrieves the contents of a web page. get_page("http://ibm.com")
get_page_async("http://ibm.com",
function(err, response, body){
@@ -3034,7 +3024,7 @@
new Job({name: "my_job",
robot: Robot.dexter0,
do_list: [ Dexter.move_to([0, 0.5, 0.075]),
- Robot.wait_until(2)
+ Control.wait_until(2)
//...
]
})
@@ -3047,7 +3037,7 @@
- Clicking on a running Job's button, i.e. in the Output pane
- Calling
Job.my_job.stop_for_reason("interrupted", "why you want it stopped")
- In a running Job, executing the instruction:
-
Robot.stop_job()
+ Control.stop_job()
You can stop all jobs by:
@@ -3058,17 +3048,175 @@
Stopped jobs may be restarted by calling Job.my_job.start()
again.
This reinitializes the job with the original arguments passed to new Job
and runs the do_list instructions again.
+
Webinar videos for Job:
Making Jobs
Advanced Jobs
+Definition Time vs Run Time
+ To fully understand how a job operates, you must understand the difference
+ between Job Definition Time and Job Run Time.
+
+ Job Definition Time
+ When you select and evaluate the source code of a job, you are
+ defining the Job. This simply uses JavaScript's eval
+ function to evaluate the source code, just like evaling any source code.
+ The result of evaling
+ new Job({name: "my_job" ...})
+ is an instance of the
+ class Job. Once done, you can access the Job instance via
+ Job.my_job
+ Many properties of the job are accessible via, for example,
+ Job.my_job.name
, which returns the string of the Job's name.
+ Of particular import is the do_list. In the case of:
+ var ang1 = 90
+new Job({name: "my_job",
+ do_list: [Dexter.move_all_joints(ang1)]
+ })
+ , evaluation sets the global variable ang1
to 90.
+ Then it sets Job.my_job to the new Job instance.
+ Within this instance, the property Job.my_job.do_list will
+ be effectively set to an array of instructions.
+ We say "effectively" because the actual do_list isn't bound
+ until the job is started. It is cached away so that it
+ can be copied afresh for each starting of the job.
+ But in any case, the do_list will now be an array containing
+ just one instance of the move_all_joints instruction.
+ This instance will have its joint1 angle set to 90 because ang1
+ is evaled when the Job definition is evaluated, and ang1
evals
+ to 90. If you simply eval Dexter.move_all_joints(90)
,
+ you can inspect the returned object and see that it has an
+ array_of_angles property storing where the Dexter's angles will
+ be commanded to go when the Job is actually run.
+
+ Job Run time
+ Now let's walk through Job Run Time. You run a Job
+ by clicking its button or by calling
+ Job.my_job.start()
+ One way to think of starting a job is that it is a second evaluation
+ of the Job. Only this time, it is not using JavaScript's eval, it is using
+ Job's special evaluator. Instead of taking an input of JavaScript source code,
+ its taking input of the items on the do_list (created via JS eval when defining the Job)
+ which can be of many different types.
+ Each instruction is "evaluated" by the Job differently, depending on its type.
+ (similar to JavaScript's eval!)
+ In the case of an instance of the move_all_joints instruction,
+ that instance is transformed to a lower level instruction
+ that is very similar to what you get when evaluating
+ make_ins("a", 90)
, then the 90 is convertered from
+ degrees into arcseconds, and sent to the Job's default robot, which better be a Dexter.
+
+ Re-Running a Job
+ After a job has finished, you can rerun it by clicking its
+ button or calling its start method again.
+ This does not redefine the job.
+ So for instance, if between two runnings of a Job, we set our
+ global variable of ang1
to 45,
+ that will have no effect on
+ the 2nd running of our job, because we are not re-evaluating
+ ang1
or even
+ Dexter.move_all_joints(ang1)
.
+ Nor are we re-defining my_job.
+ That Joint1 inside the instance of move_all_joints is still 90,
+ so our 2nd running of my_job should behave the same, even
+ if we modify the value of ang1
.
+ Actually if you do re_run my_job, it won't be exactly the same
+ because the Dexter robot will now be at a pose with Joint 1 equal to 90,
+ so in our 2nd running, the robot won't move. But besides this initial
+ "set up move", following moves would be the same between the two runnings.
+
+ Functions on the do_list
+ The most flexible of instruction types is a JavaScript function.
+ This allows you to execute arbritary JavaScript at Job Run Time.
+ You might need to do this because you want to use the current environment
+ to help determine what instruction to run next. That current environment
+ may not be knowable at Job Definition Time. Perhaps you want to
+ verify that Dexter really is where you told it to go, or
+ you want to check on the status of some other Job before
+ proceeding with this one.
+
+ To run arbitrary JS code during the running of a Job, wrap that code
+ in a function definition like so:
+ new Job({name: "my_job",
+ do_list: [function(){return Dexter.move_all_joints(ang1)}]
+ })
+ We could also do:
+ function move_it_buddy(){return Dexter.move_all_joints(ang1)}
+new Job({name: "my_job",
+ do_list: [move_it_buddy]
+ })
+ particulary helpful for long functions or functions we want to
+ call multiple times.
+
+ We are not doing:
+ do_list: [move_it_buddy()]
because
+ we don't want to CALL move_it_buddy
, as that would put its result on
+ the do_list at define time. We just want to eval the global variable
+ move_it_buddy
to put its value, a function definition, onto the do_list
+ at define time.
+
+ When a JavaScript function is called,
+ including when a running Job calls a function definition on its do_list,
+ it sets local variables of the function's parameters to the values passed in,
+ and evaluates the code in the body of the function.
+
+ In the cases above, ang1
will be evaled at Job Run Time,
+ as will the code that creates the instance of move_all_joints.
+ Anything returned by a function definition on the do_list will be
+ dynamically added to the do_list right below the function definition.
+ Our do_list started out with just one item, but after running
+ that one item, our do_list is extended by an instance of move_all_joints.
+ That instance of move_all_joints is inserted into the do_list immediately after
+ the function that generated it, making it run immediately after the function.
+ So now, if we change the value of ang1 between two runnings of my_job,
+ we won't have to redefine the whole job in order to get the effect
+ of changing the value of ang1.
+
+ A function definition on a do_list doesn't
+ have to return anything. It may just have side effects like calling out
+ for a print statement. But if it returns something that is not a valid instruction,
+ the Job will error.
+
+ Job Instance Access
+ If you want to access the running Job Instance at run time, use a
+ function definition on the do_list, and reference this
in
+ the body of that function definition.
+ Example:
+ new Job({name: "my_job",
+ do_list:[function(){ this.user_data.foo = 2},
+ function(){ out("foo: " + this.user_data.foo +
+ ", robot: " + this.robot.name) }
+ ]})
+
+ Note that using user_data
is a convenient way to pass values from one
+ instruction to another, without cluttering the global variable space.
+ Flexibility and Complexity
+ Jobs have a great deal of flexibility. We can use the full power of
+ a general purpose programming language plus DDE's libraries
+ to define them. During their
+ running, Jobs can also use the the full power of
+ a general purpose programming language plus DDE's libraries, or any
+ that you import or create.
+
+ Though powerful, this flexibility comes
+ at the cost of complexity. Using JavaScript's function defining
+ capability, you can hide (but not eliminate) many details.
+ Also, DDE attempts to make writing JavaScript and Jobs as simple as
+ possible, but it is still not simple, especially if you want
+ to understand what's going on beneath the surface. The goal of Dexter
+ is to enable you to make as many things as possible. This is why DDE needs to be so flexible.
+
+ For a more complete understanding of JavaScript eval, see the DDE article:
+ How to Think like a Computer
+
+
new Job parameters
The parameters used to define a new Job all have defaults.
new Job()
is a valid job to define and run, though it will give a warning message:
Warning: While starting job: job_1, the do_list is empty.
- The job still requests the status of Dexter but does not cause it to move.
+ The job still requests the status of Dexter, but does not cause it to move.
You can customize a job with the parameters:
- name Default's to an unused name of the format:
"job_1"
, "job_2"
, "job_3"
, etc.
You can use Job.a_job_name
to get the instance programmatically.
@@ -3098,15 +3246,15 @@
Normally a Job definition will look something like:
new Job({name: "my_job",
- do_list: [Robot.out("hi")]})
+ do_list: [IO.out("hi")]})
- The call to Robot.out
is evaled when the call to new Job is evaled.
- Robot.out("hi")
evals to an instruction object.
- (Go ahead and select the call to Robot.out and click
+ The call to IO.out
is evaled when the call to new Job is evaled.
+ IO.out("hi")
evals to an instruction object.
+ (Go ahead and select the call to IO.out and click
.)
It is that object which is put on the do_list.
- If that call to Robot.out was inside a function and returned,
- and that function was on the do_list, the result of the Robot.out
+ If that call to IO.out was inside a function and returned,
+ and that function was on the do_list, the result of the IO.out
would be put on the do_list.
If instead we had put on our do_list:
@@ -3214,7 +3362,7 @@
the initial instructions when running the job.
This is most commonly a non-negative integer but
you can use any instruction_location here.
- See Robot.go_to
+ See Control.go_to
for documentation on all the different kinds of instruction_locations.
- ending_program_counter Default:
"end"
Declare at the outset of a job that it
@@ -3222,7 +3370,7 @@
valid instruction_location that does not include a job. It is evaluated
at the start of each instruction, so if labels move as a result of
dynamically added instructions, that's OK.
- See Robot.go_to
+ See Control.go_to
for documentation on all the different kinds of instruction_locations.
Use program_counter and ending_program_counter to "play" just a segment
@@ -3254,21 +3402,32 @@
A function
When the job reaches its normal stopping point,
the function is called with a 'this' of the job instance and no arguments.
This is effectively a callback when the job is done.
- An instruction location
This is similar to Robot.go_to
+ An instruction location
This is similar to Control.go_to
except that the job is re-initialized with its original (as defined) do_list.
Any valid instruction location can be used
- (see doc in Robot.go_to) except
+ (see doc in Control.go_to) except
that it must have no job or indicate the current job. Using 0
set's the job's program_counter to instruction 0, causing the job to loop.
Using an instruction location 'offset' of greater than 0, such as a label,
will cause the initial running of the job to execute its top instructions,
but then subsequent iterations will start somewhere in the middle.
- A Robot.stop_job instruction can be used to end a loop.
+ A Control.stop_job instruction can be used to end a loop.
See the menu item: Jobs/Insert Example/when_stopped
- callback_param An advanced feature of start_object, not normally used.
+ All of these parameters are accessible as properties from the job instance that they help create.
+ Example:
+ Job.my_job.robot
gets the default robot for the job.
+ To access these properties from an instruction in a running job, use a function definition
+ on the do_list. When a running job encounters a function definition on its do_list,
+ it calls that function with no arguments, but with a this
of
+ the job instance. From that you can get the Job's properties like so:
+ new Job ({name: "my_job",
+ do_list: [function(){out(this.robot.name)}]})
+ where this
refers to Job.my_job
.
+ When run, my_job prints its default robot's name to the Output pane.
start
@@ -3285,7 +3444,7 @@
- program_counter Initialize the program_counter to an instruction id.
The default is 0. You can use any instruction_location here.
- See Robot.go_to
+ See Control.go_to
for documentation on all the different kinds of instruction_locations.
- initial_instruction Add an initial instruction to the do_list at
@@ -3308,15 +3467,15 @@
instruction The instruction to insert. This can be an array of instructions
if you effectively want to insert more than one.
location Any instruction_location documented under
- Robot.go_to literal can be used
+ Control.go_to literal can be used
including integers, names of labels, etc.
-Example: Job.insert_instruction(Robot.out("the end"),
+Example: Job.insert_instruction(IO.out("the end"),
{job: "my_job",
offset: "end"})
Adds an instruction that prints "the end" at the end of Job.my_job.do_list
.
-The instruction Robot.send_to_job
performs the core of this functionality
+The instruction Control.send_to_job
performs the core of this functionality
in an instruction format.
-See Robot.wait_until
documentation for its "new_instruction" argument
+See Control.wait_until
documentation for its "new_instruction" argument
on how to continually add and execute a new instruction in a running job.
@@ -3328,6 +3487,15 @@
A robot is a machine that can execute the instructions in its instruction set. In general,
each kind of robot will have its own instruction set. The primary
difference between robots is the difference in their instruction sets.
+
+ All Jobs have a default robot property. You can access the robot property
+ from a running job like so:
+
new Job ({name: "my_job",
+ do_list: [function(){ this.robot }]})
+ where this
refers to Job.my_job
.
+ You might use this to print out the current robot's name, by replacing
+ this.robot
with:
+ out(this.robot.name)
Robot Instructions
These instructions can be used for any robot, as can the instructions for
@@ -3342,7 +3510,7 @@
Arrays may be nested to any depth.
Example:
new Job({name: "Job1",
- do_list: [[Dexter.move_all_joints([10, 20, 0, 0, 0]), Robot.out("did it")],
+ do_list: [[Dexter.move_all_joints([10, 20, 0, 0, 0]), IO.out("did it")],
function(){
let result = []
for(let ang = 0; ang <= 90; ang += 15){
@@ -3427,14 +3595,14 @@
}
The above example could better be implemented using
-Robot.wait_until
, but there are
+Control.wait_until
, but there are
cases where the increased flexibility of the above is convenient.
You can put both named and anonymous functions on a do_list.
A named instruction allows you to add a bit of "documentation" to
the function. You can also use the name of a function like a
label and "go to"
-that name using a Robot.go_to instruction,
+that name using a Control.go_to instruction,
or use the function's name in
any uses of an instruction_location.
@@ -3449,9 +3617,9 @@
If you have some JavaScript code that you want to go between 2
other instructions on a Job's do_list, your first inclination
might be to just stick it on the do_list like so
- do_list: [Robot.out("hi"),
+ do_list: [IO.out("hi"),
my_fn(12, 34),
- Robot.out("bye")
+ IO.out("bye")
]
What happens here is that when the definition of the job is evaled,
@@ -3463,7 +3631,7 @@
then you're all set.
BUT if what you want is for the eval of my_fn(12, 34)
-to occur after the instruction returned by Robot.out("hi")
is run,
+to occur after the instruction returned by IO.out("hi")
is run,
then you'll want to wrap your code in a function, and put the definition
of that wrapper function on the do_list like so:
function(){ my_fn(12, 34) }
@@ -3519,9 +3687,9 @@
function* my_gen(){
while(true){
if(Math.random() > 0.2) {
- yield Robot.out("my_gen still alive")
+ yield IO.out("my_gen still alive")
}
- else { return Robot.out("gotta go") }
+ else { return IO.out("gotta go") }
}
}
new Job({name: "my_job",
@@ -3531,7 +3699,7 @@
for code examples. Related Job facilities are:
-
using instruction
-
Robot.wait_until("new_instruction")
+Control.wait_until("new_instruction")
- Job parameter:
when_stopped
@@ -3557,7 +3725,7 @@
when "instructions" on the do_list are started.
DDE has a number of instruction types that help you control
when the next instruction is run. A primary one is called
-wait_until
+wait_until
that blocks the processing of the following instruction.
In order to provide a more general mechanism to handle such methods
@@ -3627,7 +3795,7 @@
new Job({name: "Job1",
do_list: [{start: function(){out("wait a sec or 3")},
dur: 3},
- Robot.out("done")]})
+ IO.out("done")]})
user_data_variable Default: null
If present and non-null,
the automatically synthesized callback
@@ -3640,7 +3808,7 @@
Examples:
new Job({name: "my_job1",
- do_list: [Robot.out("hey from my_job1")]})
+ do_list: [IO.out("hey from my_job1")]})
new Job({name: "my_job2",
robot: new Brain({name: "brain2"}),
do_list: [Job.my_job1]})
@@ -3673,7 +3841,7 @@
new Job({name: "my_job",
do_list: [{start: function(){out("wait a sec or 3")},
dur: 3},
- Robot.out("done waiting")]})
+ IO.out("done waiting")]})
Above when the job starts, the first instruction's start method is
called, which prints in the Output pane, "wait a sec or 3".
@@ -3683,7 +3851,7 @@
and prints out "done waiting".
new Job({name: "my_job",
- do_list: [Robot.out("hey"),
+ do_list: [IO.out("hey"),
{start: speak,
start_args: {speak_data: "Clean my work space.", rate:0.8},
callback_param: "callback",
@@ -3694,7 +3862,7 @@
callback_param: "callback",
user_data_variable: "the_text2"
},
- Robot.out("you")
+ IO.out("you")
]})
The above job first prints out "hey", then speaks
@@ -3718,7 +3886,7 @@
callback(b, a, 123)
}
new Job({name: "my_job",
- do_list: [Robot.out("hey"),
+ do_list: [IO.out("hey"),
{start: test_cb,
start_args: [11, 22],
callback_param: 2,
@@ -3758,65 +3926,45 @@
they already were.
new Job({name: "my_job",
- do_list: [Robot.out("start of job"),
- Robot.loop(true,
+ do_list: [IO.out("start of job"),
+ Control.loop(true,
function(iter_index, iter_val, iter_total){
if(iter_index < 3) {
- return Robot.out("index: " + iter_index +
+ return IO.out("index: " + iter_index +
" iter_val: " + iter_val +
" iter_total: " + iter_total)}
- else { return Robot.break() } }),
- Robot.out("end of job")
+ else { return Control.break() } }),
+ IO.out("end of job")
]})
- If you have nested loops, Robot.break ends the inner loop only.
- If Robot.break is not in a loop, a warning will be printed in the Output pane.
+ If you have nested loops, Control.break ends the inner loop only.
+ If Control.break is not in a loop, a warning will be printed in the Output pane.
Note that Javascript also uses the symbol break
to end a JavaScript for
loop.
Robot.debugger()
allows you to pause and step through the rest of the instructions.
- See Robot.debugger
+ Control.debugger()
allows you to pause and step through the rest of the instructions.
+ See Control.debugger
Robot.error("fubar")
+ will aid in debugging. Example:Control.error("fubar")
get_page
, only made into an instruction.
- This instruction gets the content of a url and places it in a given user_data variable
- on the job instance before allowing the next instruction in the do_list to run.new Job({name: "j1",
- do_list: [Robot.get_page("http://www.nactem.ac.uk/software/acromine/dictionary.py?sf=BMI"),
- function(){out("got response of: " +
- this.user_data.http_response)}
- ]})
- Parameters:"http_response"
. The name
- of the property in the job instance's user_data object to set to the
- content of the url.
-
-Using make_url
can help make constructing calls to get_page
a bit easier.
-Example: Robot.get_page(make_url("www.nactem.ac.uk/software/acromine/dictionary.py",
- {sf: "BMI"}))
-make_url
is documented in the reference manual under "I/O".
-"highest_completed_instruction_or_zero"
is more useful than
"highest_completed_instruction"
.
{offset: 12}
program_counter
in defining the job, as well as
-in calling a job's start method. The Robot.send_to_job
instruction
+in calling a job's start method. The Control.send_to_job
instruction
uses an instruction_location for identifying
where within the job to insert the given instruction as does the method
Job.insert_instruction
.
Much of the time that you'd be tempted to use a backwards
- Robot.go_to,
- Robot.loop is better.
+ Control.go_to,
+ Control.loop is better.
robot_status
.
- The instruction: Robot.grab_robot_status()
provides an easy way to get values out of that array
- and made available for other instructions to use."grabbed_robot_status"
A string (required) of the name of the job's
- user_data
variable to shove the grabbed
- robot_status data into. If there is already such a variable,
- its value is over-written. If not, it is created and intialized
- with the new value.
-
- After this instruction is run, the grabbed value
- is available globally Job.the_job_name.user_data.the_val_of_this_arg. Job.my_job.user_data.my_var
- But inside another instruction that is defined as a function,
- this
will be bound to the current job instance so:
- this.user_data.my_var
will access the grabbed data.Serial.DATA0
- Another normal value would be Dexter.J1_ANGLE
- See below for a comprehensive list.
- "all"
The entire 60 element robot_status
- array is used. The value of end_index is ignored."data_array"
The part of the robot_status array after
- the header information is used. For Serial robots, this will be just
- the data returned by the serial port. For Dexter robots, this
- will be the data about Dexter's joint angles, etc.
- The value of end_index is ignored.null
.
- If this value is null or not passed, only the data at the start_index
- is used. The value stored in the user_data variable will NOT be an array,
- just that one element."end"
The portion of the robot_status
- from start_index through the end of the robot_status array is extracted.
-
- If both the start_index and end_index are not passed,
- then the value will be: For a Serial robot, the first "item"
- returned from the serial port in response to a send.
- For Dexter, it will be DMA_READ_DATA.
-
- You can use some constants for the values of start_index and end_index.Dexter.JOB_ID
Dexter.INSTRUCTION_ID
Dexter.START_TIME
//ms since jan 1, 1970 from Dexter's clockDexter.STOP_TIME
Dexter.INSTRUCTION_TYPE
//a letter signifying the instruction type.Dexter.ERROR_CODE
//0 means no error.Dexter.DMA_READ_DATA
Dexter.READ_BLOCK_COUNT
Dexter.RECORD_BLOCK_SIZE
Dexter.END_EFFECTOR_IN
Dexter.J1_ANGLE
Dexter.J1_DELTA
Dexter.J1_PID_DELTA
Dexter.J1_FORCE_CALC_ANGLE
Dexter.J1_A2D_SIN
Dexter.J1_A2D_COS
Dexter.J1_PLAYBACK
Dexter.J1_SENT
Dexter.J1_SLOPE
Serial.JOB_ID
Serial.INSTRUCTION_ID
Serial.START_TIME
// ms since jan 1, 1970 from Dexter's clockSerial.STOP_TIME
// ms since jan 1, 1970 from Dexter's clockSerial.INSTRUCTION_TYPE
// A letter indicating the instruction typeSerial.ERROR_CODE
// means no error.Serial.DATA0
// data coming back from the boardSerial.DATA1
Serial.DATA2
Serial.DATA3
Serial.DATA4
Serial.DATA5
Serial.DATA6
Serial.DATA7
Serial.DATA8
Serial.DATA9
Dexter.get_robot_status()
in your do_list before
-the grab_robot_status instruction.Dexter.get_robot_status()
Robot.grab_robot_status("my_zero_data", Serial.DATA0)
Robot
like so: Robot.dexter0.grab_robot_status("my_user_data_var")
-
-See Job Example: Serial Port for an extended example.
-Robot.if_any_errors
checks to see if any of the supplied jobs have errored.
+Control.if_any_errors
checks to see if any of the supplied jobs have errored.
If so, it inserts the supplied instruction into the do_list on the job
- that this instruction is on. In either case, Robot.if_any_errors
continues
+ that this instruction is on. In either case, Control.if_any_errors
continues
the job that its on.
ParametersRobot.error()
An instruction that will be inserted into the do_list
+ instruction_if_error Default: Control.error()
An instruction that will be inserted into the do_list
immediately after this instruction IF one of the named jobs has errored.
The default for instruction_if_error
is a function that
- inserts an instance of Robot.error into the do_list of this job, causing it to error.
+ inserts an instance of Control.error into the do_list of this job, causing it to error.
The "reason" for that error instruction is explicit about the cause of the error.
Generally a job should be stopped quickly if there is an error.
@@ -4060,13 +4099,13 @@
current job for "this") so that some arbitrary compensation can be made for the error.
Robot.include_job
instruction.
+ AFTER the Job definition containing the Control.include_job
instruction.
String formats:
"Job.my_job"
0
When job_name refers to a job, start_loc can be any 'instruction_location'.instruction_location
format. instruction_location
format.
Example:Robot.include_job("Job.my_job")
Control.include_job("Job.my_job")
Robot.send_to_job
.Robot.label("lab2")
+for Control.go_to, initializing the program_counter of a job, and
+a location to insert an instruction using Control.send_to_job
.Control.label("lab2")
Robot.loop
lets a Job repeat a sequence of instructions a number of times.
+Control.loop
lets a Job repeat a sequence of instructions a number of times.
This instruction is one of the most powerful and complex
in DDE, providing a wide range of looping behavior.false
, loop no times. This loop becomes a no-op.true
, loop forever, or until a Robot.break instruction in the body_fn
+ If true
, loop forever, or until a Control.break instruction in the body_fn
is executed. Like all arguments, this is evaluated at Job definition time to
supply a value of a boolean (true or false).
non-negative integer0
,
the loop becomes a no-op, just like when this arg is false
.
This can be Infinity
such that looping would only
- be limited by a Robot.break
instruction in the body_fn or
+ be limited by a Control.break
instruction in the body_fn or
stopping the Job.
arraytrue
is returned,
that "true" is used for the first iteration, and the function is called
at the beginning of every subsequent iteration until false
- is returned or the body_fn executes a Robot.break
instruction.
+ is returned or the body_fn executes a Control.break
instruction.
You want to use a function here instead of directly using a boolean, non-neg-integer,
or array, when you want those values to be computed at the time
- the Robot.loop instruction is executed as opposed to Job definition time.
+ the Control.loop instruction is executed as opposed to Job definition time.
body_fn This function is called with basically the same args as
are used to call times_to_loop when it is a function.6
and generally appear before normal string-named keys.
Its best if you don't depend on an ordering of the properties.
- Loop instructions may be nested. Robot.break
instructions will
- end the inner-most loop that contains the Robot.break
.
+ Loop instructions may be nested. Control.break
instructions will
+ end the inner-most loop that contains the Control.break
.
Much of the time that you'd be tempted to use a backwards
- Robot.go_to,
+ Control.go_to,
loops are better.
Example
new Job({name: "my_job",
- do_list: [Robot.out("start of job"),
- Robot.loop([100, 101, 102, 103, 104],
+ do_list: [IO.out("start of job"),
+ Control.loop([100, 101, 102, 103, 104],
function(iter_index, iter_val, iter_total){
if(iter_index < 3) {
- return Robot.out("index: " + iter_index +
+ return IO.out("index: " + iter_index +
" iter_val: " + iter_val +
" iter_total: " + iter_total)}
- else { return Robot.break() }
+ else { return Control.break() }
}
),
- Robot.out("end of job"),
+ IO.out("end of job"),
]})
- See Jobs menu/Insert Example/Robot.loop for more examples.
+ See Jobs menu/Insert Example/Control.loop for more examples.
out
but made for use as a robot instruction.
- Prints a message to the Output pane in the color of your choice.
- This is the "print statement" as an instruction, so useful in debugging.
- Example:Robot.out("hey " + 345, "green")
- Parameters:"rgb(255, 100, 0)"
.false
. With the default, printed output stays in the
- Output pane until DDE is relaunched.
-
- If temp is true
,
- then val is still printed in the Output pane, but is over-ridden
- by subsequence calls to out with temp == true. Calls to out with temp == false
- will erase any "temp" output.
-
- If temp is a string, then out prints val similarly to temp == true in that
- the previous call to out with that temp string will be over-ridden in place.
- However, when another call to out with a different value for temp occurs,
- the output of out with a temp string will not be erased.
- Thus the last call to out with a given temp string remains in the Output pane,
- in its place, regardless of other out calls.
-
- This is the most basic debugging tool, often used to let you know that
- the job its in has reached this instruction. Unlike an instruction such as:function(){out("The status is: " + this.status_code)}
val
.
-
- See also print statements
-Robot.start_job
starts another job.Control.start_job
starts another job.
new Job({name: "job1",
- do_list: [Robot.out("in job 1"),
- Robot.wait_until(5)]})
+ do_list: [IO.out("in job 1"),
+ Control.wait_until(5)]})
new Job({name: "job2",
robot: new Brain({name: "b1"}),
- do_list: [Robot.start_job("Job.job1"),
- Robot.out("last instruction")
+ do_list: [Control.start_job("Job.job1"),
+ IO.out("last instruction")
]
})
job2 starts job1 and waits for job1 to complete before continuing,
because the last arg to start_job is true
.
new Job({name: "job1",
- do_list: [Robot.out("in job 1"),
- Robot.wait_until(5)]})
+ do_list: [IO.out("in job 1"),
+ Control.wait_until(5)]})
new Job({name: "job2",
- do_list: [Robot.start_job("job1", undefined, undefined, true),
- Robot.out("last instruction")]
+ do_list: [Control.start_job("job1", undefined, undefined, true),
+ IO.out("last instruction")]
})
job2 starts job1 and waits for job1 to complete before continuing,
because the last arg to start_job is true
.
@@ -4392,17 +4394,17 @@
neither can rely on the Dexter being where they last told it to go.
new Job({name: "job1",
- do_list: [Robot.out("in job 1"),
- Robot.wait_until(5)]})
+ do_list: [IO.out("in job 1"),
+ Control.wait_until(5)]})
new Job({name: "job2",
robot: new Brain({name: "b1"}),
- do_list: [Robot.start_job("job1", {start_if_robot_busy: true}, undefined, true),
- Robot.out("last instruction")]
+ do_list: [Control.start_job("job1", {start_if_robot_busy: true}, undefined, true),
+ IO.out("last instruction")]
})
- See also Robot.include_job
+ See also Control.include_job
"program_counter"
, i.e. the job will
stop before executing its next instruction. Thus the default is that
the current job will be stopped immediately.
- See Robot.go_to for details
+ See Control.go_to for details
on the instruction_location
format.false
(the default)
the job will behave as if its 'when_stopped' parameter is "stop"
,
i.e. the job will end. When true
, the job's when_stopped action will
be performed.Robot.stop_job({job: "my_job", offset: "label1"})
+ Example:Control.stop_job({job: "my_job", offset: "label1"})
Job.my_job
will stop when it reaches the instruction named "label1".
""
. A string of why the job is suspended.Robot.suspend()
.Control.suspend()
.Robot.suspend("my_job")
+Control.suspend("my_job")
unsuspend is also a method on a job. Job.my_job.unsuspend()
.Robot.sync_point("midway", ["job_one", "job_two"])
Control.sync_point("midway", ["job_one", "job_two"])
Robot.send_to_job
inserts instructions into another job's do_list. It can also
-start, unsuspend and grab data from another job. Robot.send_to_job
is complex, powerful,
+Control.send_to_job
inserts instructions into another job's do_list. It can also
+start, unsuspend and grab data from another job. Control.send_to_job
is complex, powerful,
and rarely used. Example: -Robot.send_to_job({do_list_item: Dexter.move_to([0, 0.5, 0.075]), +Control.send_to_job({do_list_item: Dexter.move_to([0, 0.5, 0.075]), where_to_insert: "end", unsuspend: true, wait_until_done: true})@@ -4497,7 +4499,7 @@
where_to_insert
can be seen in the documentation for the
- Robot.go_to instruction.
+ Control.go_to instruction.
Particularly useful ones for send_to_job are:{job: "other_job", offset: "next_top_level"}
Inserts the do_list_item
after the program_counter and just before the next original (top level) do_list item
@@ -4545,13 +4547,13 @@
Job.insert_instruction
.
Robot.wait_until(2)
Control.wait_until(2)
1
This argument can be one of:
new Job({name: "my_job",
- do_list: [Robot.out("first instruction"),
- Robot.wait_until("new_instruction")]})
+ do_list: [IO.out("first instruction"),
+ Control.wait_until("new_instruction")]})
Evaling Job.my_job.start()
- Job.insert_instruction(Robot.out("the end"),
+ Job.insert_instruction(IO.out("the end"),
{job: "my_job",
offset: "after_program_counter"})
Causes wait_until to stop waiting, "the end" is printed and the job completes successfully.Job.insert_instruction
, we had instead used:
- Job.insert_instruction([Robot.out("the middle"),
- Robot.wait_until("new_instruction")],
+ Job.insert_instruction([IO.out("the middle"),
+ Control.wait_until("new_instruction")],
{job: "my_job",
offset: "after_program_counter"})
then each time we eval that code, it prints "the middle" and
@@ -4613,26 +4615,240 @@
to refer to a program_counter that is less than or equal to
the program_counter in the job referenced by the instruction_location.
This instruction waits until a job gets to a certain instruction.
- This performs like a one_sided Robot.sync_point
instruction
+ This performs like a one_sided Control.sync_point
instruction
where the job this instruction is in will wait for the job
specified in the instruction_location, but not the other way around.
- Its advantage over Robot.sync_point
is that you don't have
- to have a Robot.sync_point instruction in the job you're waiting for.
+ Its advantage over Control.sync_point
is that you don't have
+ to have a Control.sync_point instruction in the job you're waiting for.
Thus you can wait for a job reaching one of its instructions
that never expected it to be waited for.Robot.wait_until
instruction is in, or lets the instruction_location
+ that this Control.wait_until
instruction is in, or lets the instruction_location
default to that, this job could wait for itself and thus forever.
get_page
, only made into an instruction.
+ This instruction gets the content of a url and places it in a given user_data variable
+ on the job instance before allowing the next instruction in the do_list to run.new Job({name: "j1",
+ do_list: [IO.get_page("http://www.nactem.ac.uk/software/acromine/dictionary.py?sf=BMI"),
+ function(){out("got response of: " +
+ this.user_data.http_response)}
+ ]})
+ Parameters:"http_response"
. The name
+ of the property in the job instance's user_data object to set to the
+ content of the url.
+
+ Using make_url
can help make constructing calls to get_page
a bit easier.
+ Example: Control.get_page(make_url("www.nactem.ac.uk/software/acromine/dictionary.py",
+ {sf: "BMI"}))
+ make_url
is documented in the reference manual under "I/O".
+ robot_status
.
+ The instruction: IO.grab_robot_status()
provides an easy way to get values out of that array
+ and made available for other instructions to use."grabbed_robot_status"
A string (required) of the name of the job's
+ user_data
variable to shove the grabbed
+ robot_status data into. If there is already such a variable,
+ its value is over-written. If not, it is created and intialized
+ with the new value.
+
+ After this instruction is run, the grabbed value
+ is available globally Job.the_job_name.user_data.the_val_of_this_arg. Job.my_job.user_data.my_var
+ But inside another instruction that is defined as a function,
+ this
will be bound to the current job instance so:
+ this.user_data.my_var
will access the grabbed data.Serial.DATA0
+ Another normal value would be Dexter.J1_ANGLE
+ See below for a comprehensive list.
+ "all"
The entire 60 element robot_status
+ array is used. The value of end_index is ignored."data_array"
The part of the robot_status array after
+ the header information is used. For Serial robots, this will be just
+ the data returned by the serial port. For Dexter robots, this
+ will be the data about Dexter's joint angles, etc.
+ The value of end_index is ignored.null
.
+ If this value is null or not passed, only the data at the start_index
+ is used. The value stored in the user_data variable will NOT be an array,
+ just that one element."end"
The portion of the robot_status
+ from start_index through the end of the robot_status array is extracted.
+
+ If both the start_index and end_index are not passed,
+ then the value will be: For a Serial robot, the first "item"
+ returned from the serial port in response to a send.
+ For Dexter, it will be DMA_READ_DATA.
+
+ You can use some constants for the values of start_index and end_index.Dexter.JOB_ID
Dexter.INSTRUCTION_ID
Dexter.START_TIME
//ms since jan 1, 1970 from Dexter's clockDexter.STOP_TIME
Dexter.INSTRUCTION_TYPE
//a letter signifying the instruction type.Dexter.ERROR_CODE
//0 means no error.Dexter.RECORD_BLOCK_SIZE
Dexter.END_EFFECTOR_IN
Dexter.J6_MEASURED_ANGLE
Dexter.J6_MEASURED_TORQUE
Dexter.J7_MEASURED_ANGLE
Dexter.J7_MEASURED_TORQUE
Dexter.J1_ANGLE
Dexter.J1_DELTA
Dexter.J1_PID_DELTA
Dexter.J1_A2D_SIN
Dexter.J1_A2D_COS
Dexter.J1_MEASURED_ANGLE
Dexter.J1_SENT
Serial.JOB_ID
Serial.INSTRUCTION_ID
Serial.START_TIME
// ms since jan 1, 1970 from Dexter's clockSerial.STOP_TIME
// ms since jan 1, 1970 from Dexter's clockSerial.INSTRUCTION_TYPE
// A letter indicating the instruction typeSerial.ERROR_CODE
// means no error.Serial.DATA0
// data coming back from the boardSerial.DATA1
Serial.DATA2
Serial.DATA3
Serial.DATA4
Serial.DATA5
Serial.DATA6
Serial.DATA7
Serial.DATA8
Serial.DATA9
Dexter.get_robot_status()
in your do_list before
+ the grab_robot_status instruction.Dexter.get_robot_status()
IO.grab_robot_status("my_zero_data", Serial.DATA0)
Robot
like so: Robot.dexter0.grab_robot_status("my_user_data_var")
+
+ See Job Example: Serial Port for an extended example.
+ out
but made for use as a robot instruction.
+ Prints a message to the Output pane in the color of your choice.
+ This is the "print statement" as an instruction, so useful in debugging.
+ Example:IO.out("hey " + 345, "green")
+ Parameters:"rgb(255, 100, 0)"
.false
. With the default, printed output stays in the
+ Output pane until DDE is relaunched.
+
+ If temp is true
,
+ then val is still printed in the Output pane, but is over-ridden
+ by subsequence calls to out with temp == true. Calls to out with temp == false
+ will erase any "temp" output.
+
+ If temp is a string, then out prints val similarly to temp == true in that
+ the previous call to out with that temp string will be over-ridden in place.
+ However, when another call to out with a different value for temp occurs,
+ the output of out with a temp string will not be erased.
+ Thus the last call to out with a given temp string remains in the Output pane,
+ in its place, regardless of other out calls.
+
+ Unlike an instruction such as:function(){out("The status is: " + this.status_code)}
val
.
+
+ See also print statements
+ new Job({name: "my_job",
+ do_list: [IO.show_picture()]})
+
+ new Job({name: "my_job",
+ do_list: [IO.show_video()]})
+
+ this
bound to the job
+ that this instruction is running in.new Job({name: "my_job",
+ do_list: [IO.take_picture({callback: "my_pic"})]})
+
+ Job.my_job.user_data.my_pic
Robot.grab_robot_status
+See also the instruction: Control.grab_robot_status
30
,
and the next move_all_joints command for j1 indicated [5]
, then
j1 would be moved to 35 degrees. The syntax of using a number wrapped in an array
@@ -5238,7 +5454,12 @@
}
]})
See also read_file
-
+
+ Dexter.read_from_robot
is a similar instruction, except that the default folder
+ for the source is "/srv/samba/share/" and not
+ "/srv/samba/share/dde_apps" as it is for Dexter.read_file
.
+ Dexter.read_from_robot
is maintained for backwards compatibility.
+ Most users are expected to use Dexter.read_file
"/srv/samba/share/AdcCenters.txt"
is
+ where calibration data is written.""
The content to be written. This function automatically escapes
null, semicolon and percent (the escape character) in a_string
for transmission.
"/srv/samba/share/AdcCenters.txt"
is
- where calibration data is written.Dexter.write_file("/srv/samba/share/greeting.txt", "hello world")
Dexter.write_to_robot
is a similar instruction,
+ except that the default folder
+ for the file_name is "/srv/samba/share/" and not
+ "/srv/samba/share/dde_apps" as it is for Dexter.write_file
.
+ Also write_to_robot has its content argument 1st, and its file_name argument 2nd.
+ Dexter.write_to_robot
is maintained for backwards compatibility.
+ Most users are expected to use Dexter.write_file
Dexter.dexter0.robot_status
Dexter.dexter0.robot_status[Dexter.J1_MEASURED_ANGLE]
RobotStatus
is a class whose instances store information about
- a Dexter robot. Each Dexter robot instance has a field named robot_status
- i.e. Robot.dexter0.robot_status
+ a Dexter robot. Each Dexter robot instance has a field named rs
+ i.e. Dexter.dexter0.rs
whose value is an instance of RobotStatus
.
- The following are instance methods on RobotStatus
.
+ The following are instance methods on RobotStatus
that make it easy
+ to access various robot status values.Dexter.dexter0.rs.job_id()
new Job({name: "my_job",
+ do_list:[function(){out(this.robot.rs.measured_angle(1))}]
+ })
5
An integer from 0 through 7 indicating the number of joints to return their angles on.
new Job({name: "my_job",
do_list: [Human.task({task: "Load filament now."}),
- Robot.out("We're done.")]})
+ IO.out("We're done.")]})
new Job({name: "my_job",
do_list: [Human.task({title: "<b>Attention</b> Operator!",
@@ -5855,7 +6100,7 @@
width: 300,
height: 120,
background_color: "rgb(200, 255, 200)"}),
- Robot.out("We're done.")]})
+ IO.out("We're done.")]})
Robot.out("Amount: " this.user_data.a_number)
IO.out("Amount: " this.user_data.a_number)
Robot.out("Amount: " Job.my_job.user_data.a_number)
IO.out("Amount: " Job.my_job.user_data.a_number)
new Job(...)
and thus
the new job would not yet be defined, much less have the
@@ -6368,7 +6613,7 @@
See Jobs menu/Insert Example/Serial Port for an extended example.
Robot.grab_robot_status
with a subject of
+You can also call Control.grab_robot_status
with a subject of
a robot instance (instead of Robot
) so that
you can be sure to get the correct return value from
a given string_instruction instruction.make_folder
now works for WindowsOS too.
+ This fixes a bug in write_file on WindowsOS when hte dir is none-existent.to_source_code_instruction_array
+ fixed bug when the "indent" property doesn't exist on arg.Dexter.read_file
and Dexter.write_file
,
+ if the path starts with a #,
+ don't modify it by adding "dde_apps", just leave it alone.Dexter.set_parameter
args
+ from DDE high level (degrees, meters) to
+ what is actually sent to Dexter (arcseconds, microns)
+ updated to match https://github.com/HaddingtonDynamics/Dexter/wiki/set-parameter-oplet
+ which included fixing:get_page
& get_page_async
extended with:
+ (Permissible options) include the HTTP methods of:Robot
instructions have been moved to
+ Control
and IO
classes.
+ Control now has:Control.loop
, IO.get_page
, etc.Robot.loop
and Robot.get_page
, etc.
+ are deprecated but still available.
+ Ref Man for Robot instructions moved into new sections for Control and IO.
+ All examples updated.IO.show_picture
, IO.show_video
, IO.take_picture
+ are now formally documented under Ref Man/Robot/Robot Instructions/IOnew Job({
+ name: "my_job",
+ do_list: [
+ | (vert vbar is whare cursor is left)
+ ]
+})
+ into the editor. If there is a select, it assumes its one or more do_list items
+ and wraps the new Job around the selection.
+ Keystroke Ctrl-jread_file
, write_file
both instructions and functions:
+ their default folder is dde_apps, including on Dexter, srv/samba/share/dde_apps
+ BUT the "r" and "W" oplets and the older instructions
+ Dexter.read_from_robot
, Dexter.write_to_robot
(deprecated)
+ instructions use srv/samba/share as their default folders.
+ Ref Man/Robot/Dexter/Dexter Instructions/read_file and write_file documentation updated.Dexter.read_file
and
+ Dexter.read_from_robot
given default value
+ for "destination" param of: "read_file_content".make_folder
fixed to adjust to OS file path conventions.
@@ -30,7 +194,7 @@
now handled properly and
the user_data.destination is filled with an integer error code, typically 1.Robot.loop
that caused it not to initialize correctly
+ Control.loop
that caused it not to initialize correctly
when restarting a job with a loop instruction in it. Robot.if_any_errors
ref man doc improved. Control.if_any_errors
ref man doc improved.Robot.break
instruction to properly handle skipping past end of loop
when the loop body has nested instructions.Robot.go_to
Control.go_to
Job.insert_instruction
Robot.go_to
+ This caused some instructions to be skipped when a Control.go_to
backwards instruction was executed.Kin.is_in_reach()
has been updated.