Fixed bug in core/index.js for the folder of the require statement that loads dexter_defaults.js
Fixed bug in storage.js of the default value for outerWidth and outerHeight.
diff --git a/package.json b/package.json
index 4070dc64..f8e765dc 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
{
"name": "dexter_dev_env",
"productName": "dexter_dev_env",
- "version": "3.8.9",
- "release_date": "Sep 30, 2022",
+ "version": "3.8.10",
+ "release_date": "Oct 22, 2022",
"description": "Dexter Development Environment for programming the Dexter robot.",
"author": "Fry",
"license": "GPL-3.0",
diff --git a/tutorials/dexter_ui_tutorial.js b/tutorials/dexter_ui_tutorial.js
index 8630dbbf..4d6e40a8 100644
--- a/tutorials/dexter_ui_tutorial.js
+++ b/tutorials/dexter_ui_tutorial.js
@@ -60,22 +60,24 @@ dui_tour.addSteps([
select real to move a real robot.`,
popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 20] } }]},
},
- {attachTo: {element: '#warning_moving_dexter', on: 'top'},
+ {classes: "shepherd_step_dui_wide",
text: `Using this tutorial with real selected will move Dexter.
Please clear its surrounding area and move Dexter slowly.`,
popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 20] } }]},
- },
+ },
{text: `If you didn't see the Dexter User Interface dialog box just pop up,
- check the lower left Output pane in DDE for warnings.
+ please try:
+
+
Check the lower left Output pane in DDE for warnings.
One common problem: With real checked, your
- Dexter may not be connected.
-
- Click the X in this window.
+ Dexter may not be connected.
+
Click the X in this window.
You can start the tutorial over and choose simulate or
choose the Configure Dexter tutorial.
-
- If you do see the Dexter User Interface dialog box, click Next.`,
+
+
+ Otherwise, just click Next.`,
when: {
show() {
const currentStepElement = dui_tour.currentStep.el;
@@ -93,9 +95,18 @@ dui_tour.addSteps([
}
},
},
+ {attachTo: {element: '.dui_dialog [name=direction_checkbox]', on: 'top'},
+
+ text: `Often you want Dexter's end effector pointed down to work on the table surface.
+ But for this tutorial, its easiest to not use that constraint.
+ Please uncheck this checkbox.`,
+ popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 15] } }]}
+ },
{attachTo: {element: '.dui_dialog [name=j2_range]', on: 'left'},
- text: `Drag the joint 2 slider very slowly for just a short distance.
+ text: `Observe that under the big red square, the "J2" slider is highlighted.
+ ("J2" stands for Dexter's joint 2.)
+ Drag the joint 2 slider very slowly for just a short distance.
(Dexter has a maximum speed that's slower than you can drag.)
Observe that the simulated Dexter's joint 2 changes.
Notice that other controls' values change in concert.`,
@@ -110,6 +121,19 @@ dui_tour.addSteps([
Notice that other controls change too.`,
popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 30] } }]}
},
+ {classes: "shepherd_step_dui_wide",
+ text: `There are two basic ways to move Dexter.
+
+
Move the joints. This is low level and gives you explicit control
+ of the angle of each joint, independent of the other joints.
+
Move Dexter's end effector to a particular x, y, z coodinate.
+ This is higher level and often more useful for practical positioning.
+
+ The Dexter UI dialog box helps you understand the relationship between these
+ two coordinate systems, an important concept called Kinematics.`,
+ buttons: [{text: 'Next', action: dui_tour.next}],
+ },
+
{attachTo: {element: '.dui_dialog [name=z_slider]', on: 'right'},
text: `Drag the Z slider's dot slowly
to move Dexter's end effector vertically.
@@ -131,20 +155,20 @@ dui_tour.addSteps([
popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 20] } }]}
},
- {attachTo: {element: '.dui_dialog [name=j1_angle_num]', on: 'bottom'},
+ {attachTo: {element: '.dui_dialog [name=j5_angle_num]', on: 'top'},
text: `You can specify Dexter's movements more accurately by
using the numerical controls.
- Change joint 1 by using the highlighted control.
+ Change joint 5 by using the highlighted control.
Use its up and down arrows to increment or decriment
- joint 1's degrees without typing.
- Dexter will move slowly in response.`,
+ joint 5's degrees without typing.
+ Dexter will barely move in response.`,
popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 5] } }]}
},
{attachTo: {element: '#editor_pane_id', on: 'top-start'},
text: `A Job contains the sequence of instructions that reproduce
- a complex process. Let's create a Job.
+ a complex process. Let's create a Job.
DDE has 4 panes. The upper left one (now highlighted)
- is the Editor pane.
+ is the Editor pane.
If it has text in it, click on its File menu
and select New to give us an empty editor.`,
popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, -50] } }]}
@@ -159,17 +183,16 @@ dui_tour.addSteps([
This will insert the JavaScript for an instruction
that tells Dexter to move to where it currently is.`,
},
- {attachTo: {element: 'body' , on: 'right'},
+ {attachTo: { element: '.dui_dialog', on: 'left'},
+ text: `Drag the title bar of the dialog box right,
+ so that you can see at least the first argument
+ of the inserted instruction.`
+ },
+ {attachTo: {element: '.dui_dialog [name=j1_range]' , on: 'top'},
text: `Modify the new instruction
by dragging the joint 1 slider.
This changes not just the robot and other controls,
- but joint 1's argument in the editor too.
- An instruction's arguments are often hidden by the
- Dexter UI dialog box. Drag its title bar so you can see
- the inserted instructions in the editor.
- If you are using the simulator, try to position
- the dialog so you can still see the simulated Dexter.
- `,
+ but joint 1's argument in the editor too.`,
popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 5] } }]}
},
{attachTo: {element: '.dui_dialog', on: 'right'},
@@ -179,9 +202,12 @@ dui_tour.addSteps([
(bottom-right).`,
popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 0] } }]}
},
- {attachTo: {element: '.dui_dialog [name=step_arrow_buttons]', on: 'right'},
+ {attachTo: {element: '.dui_dialog [name=step_arrow_buttons]', on: 'bottom'},
text: `Run individual instructions, or many at once,
using the green arrow buttons.
+ The small green arrows allow you to step through each instruction,
+ forwards or back. Very useful in debugging.
+
Start with the small, left pointing arrow,
to run the previous instruction.
Notice that the previoius instruction becomes selected in the editor.
@@ -209,22 +235,24 @@ dui_tour.addSteps([
text: `The Eval button runs the selected JavaScript code
in the editor.
Click it now to evaluate the selection.
- In the Output pane you'll see the internal data structure
+ In the Output pane you'll see, in the inspector, the internal data structure
that represents the instruction, but this does not cause
- Dexter to move until its run as part of a Job.`,
+ Dexter to move until it is run as part of a Job.`,
popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 10] } }]}
},
{attachTo: {element: '#editor_pane_id', on: 'bottom-start'},
text: `If there is no selection, the Eval button
evaluates all the code in the editor.
Click anywhere in the editor to remove the selection
- and get help on the underlying source code.
+ and get help on the underlying source code in the output pane.
`,
popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 10] } }]}
},
{attachTo: {element: '#eval_id', on: 'right'},
text: `We want to evaluate the JavaScript for the whole Job
- to define it. Click the Eval button.`,
+ to define it.
+ Click the Eval button.
+ Observe the data structure representing the Job in the inspector.`,
popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 10] } }]}
},
{attachTo: {element: '#jobs_button_bar_id', on: 'bottom'},
@@ -234,13 +262,30 @@ dui_tour.addSteps([
in the Job.`,
popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 0] } }]}
},
+ {attachTo: {element: '#jobs_button_bar_id', on: 'top'},
+ text: `The color of a Job's button indicates its state:
+
Gray means never run.
+
Green means running.
+
Yellow means paused.
+
Purple means successfully completed.
+
Orange means user clicked running Job button to stop it.
+
Red means error during running.
+
+ Place the mouse over a Job button to see text of it's state.`,
+ popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 0] } }]}
+ },
+ {attachTo: {element: '#jobs_button_bar_id', on: 'bottom'},
+ text: `Click my_job's button to run it again.
+ You can run a Job as many times as you like.`,
+ popperOptions: {modifiers: [{ name: 'offset', options: { offset: [0, 0] } }]}
+ },
{attachTo: { element: '.dui_dialog', on: 'right'},
text: `We're almost done so
close the Dexter UI dialog by
clicking the X in its upper right corner`
},
{attachTo: { element: '#editor_pane_id', on: 'left'},
- text: `Get the Dexter UI dialog back by clicking
+ text: `Get the Dexter UI dialog back by clicking
on the Jobs menu's Dexter UI item.`
},
{attachTo: { element: '#doc_pane_id', on: 'left'},
@@ -249,19 +294,21 @@ dui_tour.addSteps([
that describes the Dexter UI dialog.
There's more to it than this tutorial covers.`
},
- {attachTo: { element: '#help_system_id', on: 'left'},
+ {attachTo: { element: '#help_system_id', on: 'left'},
text: `Clicking the Help button will bring back the
"Welcome to DDE" dialog box containing the tutorials menu.`
},
{classes: "shepherd_step_dui_wide",
- text: `Congrats, You're a Dexter Process Author!
+ text: `Congrats! You're a Dexter Process Author!
When you click Exit, you'll have
unrestricted access to the:
-
Dexter User Interface dialog box
-
Simulator
-
Editor
-
Eval button
-
Rest of DDE
+
+
Dexter User Interface dialog box
+
Simulator
+
Editor
+
Eval button
+
Job buttons
+
Rest of DDE
`,
buttons: [{text: 'Back', action: dui_tour.back},
{text: 'Exit', action: dui_tour.complete}]
diff --git a/user_tools/dexter_user_interface2.js b/user_tools/dexter_user_interface2.js
index a4d72f39..ebdfaced 100644
--- a/user_tools/dexter_user_interface2.js
+++ b/user_tools/dexter_user_interface2.js
@@ -15,6 +15,12 @@ var dui2 = class dui2 {
dui2.instances.push(this)
}
+ static the_dexter
+
+ static dexter_instruction_subject_source(){
+ return "Dexter." + this.the_dexter.name + "."
+ }
+
//if angle_array is an array whose first 5 elts are 0, return true,
//else return false
static is_home_angles(angle_array){
@@ -83,17 +89,16 @@ var dui2 = class dui2 {
commanded_angles.push(0)
}
let angles_to_use = Vector.subtract(slider_angles, commanded_angles)
- let instr = Dexter.pid_move_all_joints(angles_to_use)
+ let instr = dui2.the_dexter.pid_move_all_joints(angles_to_use)
return instr
}
//this is the top level code in this file that is called when the user chooses Jobs menu, Dexter UI item.
static make_job(explicitly_start_job=false){
- let dex = (window.default_robot ? Dexter.default : Dexter.dexter0)
- let name = ((platform === "dde") ? "dui2_for_" + dex.name : "dexter_user_interface2") //the job engine Job name must match the file name (sans .js")
+ let the_dex = (window.default_robot ? Dexter.default : Dexter.dexter0)
+ let name = ((platform === "dde") ? "dui2_for_" + the_dex.name : "dexter_user_interface2") //the job engine Job name must match the file name (sans .js")
if (Job[name] && Job[name].is_active()) { //we're redefining the job so we want to make sure the
//previous version is stopped first
- //if (Job[name].robot instanceof Dexter) {Job[name].robot.empty_instruction_queue_now() }
Job[name].stop_for_reason("interrupted", "User is redefining this job.")
setTimeout(function(){ dui2.make_job(true) }, 200)
}
@@ -102,13 +107,12 @@ var dui2 = class dui2 {
//with a new job_id. This should be fine.
let new_job = new Job({
name: name,
- robot: dex,
+ robot: new Brain({name: "dui_brain"}),
when_do_list_done: "wait",
do_list: [dui2.init,
- Dexter.empty_instruction_queue() //needed because the next instruction may need to look a the measured_angles, and we want them updated to where dexter is really at.
+ the_dex.empty_instruction_queue() //needed because the next instruction may need to look a the measured_angles, and we want them updated to where dexter is really at.
]
})
- // dex.instruction_callback = this.dui_instruction_callback //used for "run_forward" , complicated to get this to work so now run_forward does something simpler
if(explicitly_start_job) {
new_job.start()
}
@@ -147,7 +151,8 @@ var dui2 = class dui2 {
}
let dui_instance = new dui2()
dui_instance.job_name = this.name
- dui_instance.dexter_instance = this.robot
+ dui2.the_dexter = (globalThis.default_robot ? Dexter.default : Dexter.dexter0)
+ dui_instance.dexter_instance = dui2.the_dexter
let initial_angles
let initial_move_instruction
//set initial_angles
@@ -168,9 +173,7 @@ var dui2 = class dui2 {
//but, it means we have to move the dexter.
initial_angles = Kin.point_down([0,0,0,0,0, 0, 50]) //change our initial_angles,
//j7 needs to be 50 as it is in the new HOME, to avoid overtorque when its 0.
- initial_move_instruction = //Dexter.pid_move_all_joints(initial_angles)
- //dui_instance.make_move_instruction(initial_angles)
- Dexter.move_all_joints(initial_angles)
+ initial_move_instruction = dui2.the_dexter.move_all_joints(initial_angles)
}
else {
dui_instance.should_point_down = dui_instance.dexter_instance.is_direction() //the checkbox is in sync with this.
@@ -237,7 +240,7 @@ var dui2 = class dui2 {
`` +
`` +
"" + //needed by tutorial
- `◀` +
+ `◀` +
`◀` +
`▶` +
`▶` +
@@ -574,8 +577,7 @@ var dui2 = class dui2 {
if(j_angles.length === 6) { j_angles.push(dui_instance.maj_angles[6]) } //joint 7 vals.j7_angle_num) }
dui_instance.set_maj_angles(j_angles)
dui_instance.update_all(dui_instance.should_point_down) // do update_all before move_all_joints because update_all may modify ui2_instance.maj_angles if the direction_checkbox is checked
- let instr = //Dexter.pid_move_all_joints(dui_instance.maj_angles)
- dui_instance.make_move_instruction(dui_instance.maj_angles)
+ let instr = dui_instance.make_move_instruction(dui_instance.maj_angles)
//Job.insert_instruction(instr, {job: dui_instance.job_name, offset: "end"}) //todo overwrite
Job[dui_instance.job_name].insert_last_instruction_overwrite(instr)
}
@@ -592,7 +594,7 @@ var dui2 = class dui2 {
//inspect(dui2.dui_instance_under_mouse())
if(vals.clicked_button_value === "close_button"){
if(dui_instance.dexter_mode === "follow_me") {
- let instr = Dexter.set_keep_position()
+ let instr = dui2.the_dexter.set_keep_position()
Job.insert_instruction(instr, {job: vals.job_name, offset: "end"})
dui_instance.dexter_mode = "keep_position" //do this even through we're ending the job because this will stop the follow_me loop setTimeout
out(dui_instance.dexter_instance.name + " restored to mode: keep_position.")
@@ -685,36 +687,52 @@ var dui2 = class dui2 {
else if(vals.clicked_button_value == "ready"){
//dui_instance.set_maj_angles([0, 0, 90, 0, 0, 0, 50])
let new_angs = [0, 0, 90, 0, 0, 0, 50]
- let instr = [Dexter.pid_move_all_joints([0, 0, 0, 0, 0]),
- Dexter.move_all_joints(new_angs),
- Dexter.empty_instruction_queue()]
+ let instr = [dui2.the_dexter.pid_move_all_joints([0, 0, 0, 0, 0]),
+ dui2.the_dexter.move_all_joints(new_angs),
+ dui2.the_dexter.empty_instruction_queue()]
Job.insert_instruction(instr, {job: vals.job_name, offset: "end"})
dui_instance.set_maj_angles(new_angs)
dui_instance.update_all(dui_instance.should_point_down)
return //don't run usual code at bottom of this fn
}
else if(vals.clicked_button_value == "home"){
- //let instr = [Dexter.move_all_joints(Dexter.HOME_ANGLES),
- // Dexter.empty_instruction_queue()]
- //Job.insert_instruction(instr, {job: vals.job_name, offset: "end"}) //James W says HOME needs both a pid_maj and maj instructions.
- //dui_instance.set_maj_angles(Dexter.HOME_ANGLES) //ultimately causes a pid_move_all_joints insert
-
//programmatically uncheck point down here
//if(vals.direction_checkbox){
dui_instance.should_point_down = false
//}
let new_angs = Dexter.HOME_ANGLES
- let instr = [Dexter.pid_move_all_joints([0, 0, 0, 0, 0]),
- Dexter.move_all_joints(new_angs),
- Dexter.empty_instruction_queue()]
+ let instr = [dui2.the_dexter.pid_move_all_joints([0, 0, 0, 0, 0]),
+ dui2.the_dexter.move_all_joints(new_angs),
+ dui2.the_dexter.empty_instruction_queue()]
Job.insert_instruction(instr, {job: vals.job_name, offset: "end"})
dui_instance.set_maj_angles(new_angs)
dui_instance.update_all(dui_instance.should_point_down)
return //don't run usual code at bottom of this fn
}
+ /*not now used but maybe add this as a feature.
else if(vals.clicked_button_value == "go_to_start"){
let continue_running = dui2.go_to_start_button_click_action(dui_instance)
if(!continue_running) { return }
+ }*/
+ else if(vals.clicked_button_value == "run_backward"){
+ let continue_running
+ for(var i = 0; i < 100000; i++){
+ continue_running = dui2.step_backward_button_click_action(dui_instance) //dui2.run_forward_button_click_action(dui_instance)
+ if(!continue_running) { return } //error in processing next instr, perhaps syntactic, perhaps already did last instruction
+ else if (continue_running == "already_inserted_instruction"){ //instruction was a valid instr but not a move instruction
+ }
+ else { //got a move instruction, keep going to bottom of this method for the instruction selection and insertion
+ dui_instance.update_all(dui_instance.should_point_down) // do update_all before move_all_joints because update_all may modify ui2_instance.maj_angles if the direction_checkbox is checked
+ let instr = dui_instance.make_move_instruction(dui_instance.maj_angles)
+ Job.insert_instruction(instr, {job: vals.job_name, offset: "end"})
+ instr = dui2.the_dexter.empty_instruction_queue() //Control.wait_until(0.5)
+ Job.insert_instruction(instr, {job: vals.job_name, offset: "end"})
+ }
+ }
+ //let show_win_elt = window[vals.show_window_elt_id]
+ //show_win_elt.focus() //so that is_dui_the_focus will work after setting the selection.
+ //is_dui_the_focus needed by dui_instruction_callback
+ return
}
else if(vals.clicked_button_value == "step_backward"){
let continue_running = dui2.step_backward_button_click_action(dui_instance)
@@ -733,8 +751,9 @@ var dui2 = class dui2 {
}
else { //got a move instruction, keep going to bottom of this method for the instruction selection and insertion
dui_instance.update_all(dui_instance.should_point_down) // do update_all before move_all_joints because update_all may modify ui2_instance.maj_angles if the direction_checkbox is checked
- let instr = //Dexter.pid_move_all_joints(dui_instance.maj_angles)
- dui_instance.make_move_instruction(dui_instance.maj_angles)
+ let instr = dui_instance.make_move_instruction(dui_instance.maj_angles)
+ Job.insert_instruction(instr, {job: vals.job_name, offset: "end"})
+ instr = dui2.the_dexter.empty_instruction_queue() //Control.wait_until(0.5)
Job.insert_instruction(instr, {job: vals.job_name, offset: "end"})
}
}
@@ -763,7 +782,7 @@ var dui2 = class dui2 {
if(!from_dexter_checkbox.checked) {return} //its over. user unchecked checkbox.
else if (dui_instance.waiting_for_user_to_start_get_points) { //not yet inited.
let job_instance = Job[dui_instance.job_name]
- job_instance.insert_single_instruction(Dexter.get_robot_status(), false)
+ job_instance.insert_single_instruction(dui2.the_dexter.get_robot_status(), false)
if((!dui_instance.waiting_for_phui_gui_button_click) ||
dui_instance.dexter_instance.was_phui_button_down()){ //ready to start getting points
dui_instance.waiting_for_phui_gui_button_click = false
@@ -772,7 +791,7 @@ var dui2 = class dui2 {
for(let elt of output_div_id.querySelectorAll(".get_points_from_dexter")){
elt.disabled = true
}
- Job.insert_instruction(Dexter.set_follow_me(), {job: dui_instance.job_name, offset: "end"}) //builds up long do_list
+ Job.insert_instruction(dui2.the_dexter.set_follow_me(), {job: dui_instance.job_name, offset: "end"}) //builds up long do_list
dui_instance.dexter_mode = "follow_me"
out("Manually move Dexter to set the Dexter User Interface dialog point. " +
"To record a point, click Dexter's Phui button or " +
@@ -783,7 +802,7 @@ var dui2 = class dui2 {
return
}
else { //we started
- Job[dui_instance.job_name].insert_last_instruction_overwrite(Dexter.get_robot_status())
+ Job[dui_instance.job_name].insert_last_instruction_overwrite(dui2.the_dexter.get_robot_status())
let j_angles = dui_instance.dexter_instance.rs.measured_angles(7) //note, this probably gets the prev robot status, but that's ok
dui_instance.set_maj_angles(j_angles)
dui_instance.update_all(false) //hmm, needs work on should_point_down.
@@ -804,7 +823,7 @@ var dui2 = class dui2 {
dui_instance.waiting_for_phui_gui_button_click = false
dui_instance.waiting_for_user_to_start_get_points = false
dui_instance.dexter_mode = "keep_position"
- Job.insert_instruction(Dexter.set_keep_position(), {job: vals.job_name, offset: "end"})
+ Job.insert_instruction(dui2.the_dexter.set_keep_position(), {job: vals.job_name, offset: "end"})
dui_instance.enable_all_robot_moving_elts(true)
return
}
@@ -833,8 +852,6 @@ var dui2 = class dui2 {
let job_prefix_src =
`\nnew Job({
name: "my_job",
- keep_history: false,
- show_instructions: false,
do_list: [
`
/* inserts an instruction but not the right thing if you use FromDex mode to get all points
@@ -872,8 +889,7 @@ var dui2 = class dui2 {
return
}
dui_instance.update_all(dui_instance.should_point_down) // do update_all before move_all_joints because update_all may modify ui2_instance.maj_angles if the direction_checkbox is checked
- let instr = //Dexter.pid_move_all_joints(dui_instance.maj_angles)
- dui_instance.make_move_instruction(dui_instance.maj_angles)
+ let instr = dui_instance.make_move_instruction(dui_instance.maj_angles)
//Job.insert_instruction(instr, {job: vals.job_name, offset: "end"})
Job[dui_instance.job_name].insert_last_instruction_overwrite(instr)
@@ -1147,7 +1163,7 @@ var dui2 = class dui2 {
}
let do_list_pos = full_src.lastIndexOf("do_list:", start_pos)
if(do_list_pos > prev_prev_newline_pos) {
- warning("you're already at the first instruction of the Job.")
+ warning("you're already at the first instruction of the Job.", true)
return null
}
@@ -1201,7 +1217,7 @@ var dui2 = class dui2 {
make_instruction_source(){
let instr_name = dui_instr_type_id.value
- let instr_code = "Dexter." + instr_name
+ let instr_code = dui2.dexter_instruction_subject_source() + instr_name
let new_args
if(instr_name.endsWith("move_all_joints")) {
/*let angles_to_use = this.maj_angles