diff --git a/src/behavior.scm b/src/behavior.scm index 1f3cecda..39f90895 100644 --- a/src/behavior.scm +++ b/src/behavior.scm @@ -12,22 +12,30 @@ ; HOWTO: ; ------ ; Run the main loop: -; (behavior-tree-run) +; (run) ; Pause the main loop: -; (behavior-tree-halt) +; (halt) ; ; TODO: ; ----- -; XXX This needs a major redesign, to NOT use behavior trees at the top -; level, but instead to provide a library of suitable actions that can -; be searched over, and then performed when a given situation applies. -; That is, given a certain state vector (typically, a subset of the -; current state), the library is searched to see if there is a behavior -; sequence that can be applied to this situation. If there is no such -; explicit match, then the fuzzy matcher should be employed to find -; something that is at least close. If nothing close is found, then -; either the concept blending code, or a hack of the MOSES knob-turning -; and genetic cross-over code should be used to create new quasi-random +; The current OpenPsi framework allows much more general and flexible +; rules than what are presented below; this geneality should be made +; use of. +; +; A general OpenPsi rule has the form of if(context) then take(action); +; these can contain variables, adn can also be classed into different +; groups based on the demands that they are fulfilling. +; +; The content below consits entirely of actions to nbe taken; the +; contexts are in the `self-model.scm` file. The structure of the +; conexts is fairly rigid; these could probably be loosened to a +; large degree. +; +; The OpenPsi engine could be (should be?) updated to perform fuzzy +; matching on the contexts, to find close or similar contexts, if no +; one exact match can be made. If nothing close is found, then either +; the concept blending code, or a hack of the MOSES knob-turning and +; genetic cross-over code should be used to create new quasi-random ; performance sequences from a bag of likely matches. ; ; Unit testing: @@ -719,6 +727,7 @@ )) (TrueLink) )) + (DefineLink (DefinedPredicate "Keep alive") (SequentialAnd @@ -740,83 +749,5 @@ )) (TrueLink) )) -;; ------------------------------------------------------------------ -;; Main loop. Uses tail recursion optimization to form the loop. -(DefineLink - (DefinedPredicate "main loop") - (SatisfactionLink - (SequentialAnd - (SequentialOr - (DefinedPredicate "Skip Interaction?") - - (SequentialAnd - (DefinedPredicate "Someone requests interaction?") - (DefinedPredicate "Interaction requested action")) - - (SequentialAnd - (DefinedPredicate "Did someone arrive?") - (DefinedPredicate "New arrival sequence")) - - (SequentialAnd - (DefinedPredicate "Did someone leave?") - (DefinedPredicate "Someone left action")) - - ; True, if there is anyone visible. - (SequentialAnd - (DefinedPredicate "Someone visible?") - (DefinedPredicate "Interact with people")) - - (DefinedPredicate "Nothing is happening") - (True)) - - ;; XXX FIXME chatbot is disengaged from everything else. - ;; The room can be empty, the head is bored or even asleep, - ;; but the chatbot is still smiling and yabbering. - ;; If interaction is turned-off need keep alive gestures - (SequentialOr - ; If the TTS vocalization started (chatbot started talking) ... - (SequentialAnd - (DefinedPredicate "chatbot started talking?") - (DefinedPredicate "Speech started")) - - ; If the chatbot currently talking ... - (SequentialAnd - (DefinedPredicate "chatbot is talking?") - (DefinedPredicate "Speech ongoing")) - - ; If the chatbot stopped talking ... - (SequentialAnd - (DefinedPredicate "chatbot stopped talking?") - (DefinedPredicate "Speech ended")) - - (SequentialAnd - (DefinedPredicate "chatbot started listening?") - (DefinedPredicate "Listening started")) - - ; If the chatbot stopped talking ... - (SequentialAnd - (DefinedPredicate "chatbot is listening?") - (DefinedPredicate "Listening ongoing")) - - ; If the chatbot stopped talking ... - (SequentialAnd - (DefinedPredicate "chatbot stopped listening?") - (DefinedPredicate "Listening ended")) - - (SequentialAnd - (DefinedPredicate "Skip Interaction?") - (DefinedPredicate "Keep alive")) - - (True) - ) - - ; If ROS is dead, or the continue flag not set, then stop - ; running the behavior loop. - (DefinedPredicate "Continue running loop?") - (DefinedPredicate "ROS is running?") - - ;; Call self -- tail-recurse. - (DefinedPredicate "main loop") - ))) ; ---------------------------------------------------------------------- diff --git a/src/btree-eva-mute.scm b/src/btree-eva-mute.scm index 37c1b648..5de6e0c5 100644 --- a/src/btree-eva-mute.scm +++ b/src/btree-eva-mute.scm @@ -40,6 +40,7 @@ ; (display %load-path) (add-to-load-path "../src") (load-from-path "cfg-eva.scm") ;;; <<<=== See, its Eva here! +(load-from-path "old-tree.scm") ;; Call (run) to run the main loop, (halt) to pause the loop. ;; The main loop runs in its own thread. diff --git a/src/btree-eva.scm b/src/btree-eva.scm index 99562318..8bdb7c70 100644 --- a/src/btree-eva.scm +++ b/src/btree-eva.scm @@ -1,7 +1,7 @@ ; ; btree-eva.scm ; -; Eva behavior tree (for the Eva blender model animations). +; Eva OpenPsi behaviors (for the Eva blender model animations). ; ; Runs a set of defined behaviors that express Eva's personality. ; This version integrates the OpenCog chatbot. @@ -36,16 +36,18 @@ (use-modules (opencog exec)) ; needed for cog-evaluate! in put_atoms.py (use-modules (opencog eva-model)) ; needed for defines in put_atoms.py (use-modules (opencog eva-behavior)) +(use-modules (opencog openpsi)) ; Load the Eva personality configuration. ; (display %load-path) (add-to-load-path "../src") (load-from-path "cfg-eva.scm") ;;; <<<=== See, its Eva here! +(load-from-path "psi-behavior.scm") ;; Call (run) to run the main loop, (halt) to pause the loop. ;; The main loop runs in its own thread. -(define (run) (behavior-tree-run)) -(define (halt) (behavior-tree-halt)) +(define (run) (psi-run)) +(define (halt) (psi-halt)) ; --------------------------------------------------------- ; Load the chat modules. diff --git a/src/btree-psi.scm b/src/btree-psi.scm index 4bc0e490..3e6cb454 100644 --- a/src/btree-psi.scm +++ b/src/btree-psi.scm @@ -1,10 +1,10 @@ ; ; btree-psi.scm ; -; OpenPsi-based Eva behavior action selection (for the Eva blender +; Sophia OpenPsi behavior action selection (for the Sophia blender ; model animations). ; -; Runs a set of defined behaviors that express Eva's personality. +; Runs a set of defined behaviors that express Sophia's personality. ; This version integrates the OpenCog chatbot. ; ; The currently-defined behaviors include acknowledging new people who @@ -48,23 +48,6 @@ ;; Load the actual psi rules. (load-from-path "psi-behavior.scm") -; There MUST be a DefinedPredicateNode with exactly the name -; below in order for psi-run to work. Or we could just blow -; that off, and use our own loop... -(define loop-name (string-append psi-prefix-str "loop")) -(DefineLink - (DefinedPredicate loop-name) - (SatisfactionLink - (SequentialAnd - (Evaluation (GroundedPredicate "scm: psi-step") - (ListLink)) - (Evaluation (GroundedPredicate "scm: psi-run-continue?") - (ListLink)) - ; If ROS is dead, or the continue flag not set, - ; then stop running the behavior loop. - (DefinedPredicate "ROS is running?") - (DefinedPredicate loop-name)))) - ;; Call (run) to run the main loop, (halt) to pause the loop. ;; The main loop runs in its own thread. (define (run) (psi-run)) @@ -99,7 +82,7 @@ ; --------------------------------------------------------- ; Run the hacky garbage collection loop. -; (run-behavior-tree-gc) +(run-behavior-tree-gc) ; Silence the output. *unspecified* diff --git a/src/btree.scm b/src/btree.scm index 17350568..a0303354 100644 --- a/src/btree.scm +++ b/src/btree.scm @@ -61,6 +61,7 @@ ;; Call (run) to run the main loop, (halt) to pause the loop. ;; The main loop runs in its own thread. +(load-from-path "old-tree.scm") (define (run) (behavior-tree-run)) (define (halt) (behavior-tree-halt)) diff --git a/src/old-tree.scm b/src/old-tree.scm new file mode 100644 index 00000000..2bddf381 --- /dev/null +++ b/src/old-tree.scm @@ -0,0 +1,155 @@ +; +; old-tree.scm +; +; Old (deprecated) top-level behavior tree main loop. +; +; This has been supplanted by the newer, OpenPsi-based behavior +; rules, and is temporarily maintained here for backwards +; compaitbility. +; +; HOWTO: +; ------ +; Run the main loop: +; (behavior-tree-run) +; Pause the main loop: +; (behavior-tree-halt) +; +;; ------------------------------------------------------------------ +;; Main loop. Uses tail recursion optimization to form the loop. +(DefineLink + (DefinedPredicate "main loop") + (SatisfactionLink + (SequentialAnd + (SequentialOr + (DefinedPredicate "Skip Interaction?") + + (SequentialAnd + (DefinedPredicate "Someone requests interaction?") + (DefinedPredicate "Interaction requested action")) + + (SequentialAnd + (DefinedPredicate "Did someone arrive?") + (DefinedPredicate "New arrival sequence")) + + (SequentialAnd + (DefinedPredicate "Did someone leave?") + (DefinedPredicate "Someone left action")) + + ; True, if there is anyone visible. + (SequentialAnd + (DefinedPredicate "Someone visible?") + (DefinedPredicate "Interact with people")) + + (DefinedPredicate "Nothing is happening") + (True)) + + ;; XXX FIXME chatbot is disengaged from everything else. + ;; The room can be empty, the head is bored or even asleep, + ;; but the chatbot is still smiling and yabbering. + ;; If interaction is turned-off need keep alive gestures + (SequentialOr + ; If the TTS vocalization started (chatbot started talking) ... + (SequentialAnd + (DefinedPredicate "chatbot started talking?") + (DefinedPredicate "Speech started")) + + ; If the chatbot currently talking ... + (SequentialAnd + (DefinedPredicate "chatbot is talking?") + (DefinedPredicate "Speech ongoing")) + + ; If the chatbot stopped talking ... + (SequentialAnd + (DefinedPredicate "chatbot stopped talking?") + (DefinedPredicate "Speech ended")) + + (SequentialAnd + (DefinedPredicate "chatbot started listening?") + (DefinedPredicate "Listening started")) + + ; If the chatbot stopped talking ... + (SequentialAnd + (DefinedPredicate "chatbot is listening?") + (DefinedPredicate "Listening ongoing")) + + ; If the chatbot stopped talking ... + (SequentialAnd + (DefinedPredicate "chatbot stopped listening?") + (DefinedPredicate "Listening ended")) + + (SequentialAnd + (DefinedPredicate "Skip Interaction?") + (DefinedPredicate "Keep alive")) + + (True) + ) + + ; If ROS is dead, or the continue flag not set, then stop + ; running the behavior loop. + (DefinedPredicate "Continue running loop?") + (DefinedPredicate "ROS is running?") + + ;; Call self -- tail-recurse. + (DefinedPredicate "main loop") + ))) + +; ---------------------------------------------------------------------- +;; Main loop control +(define do-run-loop #t) + +(define-public (behavior-tree-run) +" + behavior-tree-run + + Run the Eva behavior tree main loop (in a new thread), + Call (behavior-tree-halt) to exit the loop. +" + (set! do-run-loop #t) + (call-with-new-thread + (lambda () (cog-evaluate! (DefinedPredicateNode "main loop"))))) + +(define-public (behavior-tree-halt) +" + behavior-tree-halt + + Tell the Eva behavior tree main loop thread to exit. +" + (set! do-run-loop #f)) + + +(define-public (behavior-tree-running?) +" + behavior-tree-running? + + Return #t if the behavior tree is running, else return false. +" + do-run-loop) + +(define-public (behavior-tree-loop-count) +" + behavior-tree-loop-count + + Return the loop-count of the behavior tree. +" + loop-count) + + +(define loop-count 0) +(define-public (continue-running-loop) ; public only because its in a GPN + (set! loop-count (+ loop-count 1)) + + ; Print loop count to the screen. + ; (if (eq? 0 (modulo loop-count 30)) + ; (format #t "Main loop: ~a\n" loop-count)) + + ; Pause for one-tenth of a second... 101 millisecs + (usleep 101000) + (if do-run-loop (stv 1 1) (stv 0 1))) + +; Return true if the behavior loop should keep running. +(DefineLink + (DefinedPredicate "Continue running loop?") + (Evaluation + (GroundedPredicate "scm:continue-running-loop") (ListLink))) + +; ---------------------------------------------------------------------- diff --git a/src/primitives.scm b/src/primitives.scm index 20a96aba..802c9415 100644 --- a/src/primitives.scm +++ b/src/primitives.scm @@ -177,65 +177,7 @@ except: (change-template "Time to change gaze" "attn-search" "time_search_attn_min" "time_search_attn_max") -;; ------------------------------------------------------------------ -;; Main loop control -(define do-run-loop #t) - -(define-public (behavior-tree-run) -" - behavior-tree-run - - Run the Eva behavior tree main loop (in a new thread), - Call (behavior-tree-halt) to exit the loop. -" - (set! do-run-loop #t) - (call-with-new-thread - (lambda () (cog-evaluate! (DefinedPredicateNode "main loop"))))) - -(define-public (behavior-tree-halt) -" - behavior-tree-halt - - Tell the Eva behavior tree main loop thread to exit. -" - (set! do-run-loop #f)) - - -(define-public (behavior-tree-running?) -" - behavior-tree-running? - - Return #t if the behavior tree is running, else return false. -" - do-run-loop) - -(define-public (behavior-tree-loop-count) -" - behavior-tree-loop-count - - Return the loop-count of the behavior tree. -" - loop-count) - - -(define loop-count 0) -(define-public (continue-running-loop) ; public only because its in a GPN - (set! loop-count (+ loop-count 1)) - - ; Print loop count to the screen. - ; (if (eq? 0 (modulo loop-count 30)) - ; (format #t "Main loop: ~a\n" loop-count)) - - ; Pause for one-tenth of a second... 101 millisecs - (usleep 101000) - (if do-run-loop (stv 1 1) (stv 0 1))) - -; Return true if the behavior loop should keep running. -(DefineLink - (DefinedPredicate "Continue running loop?") - (Evaluation - (GroundedPredicate "scm:continue-running-loop") (ListLink))) - +; ---------------------------------------------------------------------- ; Return true if ROS is still running. (DefineLink (DefinedPredicate "ROS is running?") diff --git a/src/psi-behavior.scm b/src/psi-behavior.scm index 74613eb5..73a7bc7e 100644 --- a/src/psi-behavior.scm +++ b/src/psi-behavior.scm @@ -10,6 +10,8 @@ ; ;; ------------------------------------------------------------------ +; XXX FIXME -- terrible errible hack -- mostly because OpenPsi +; is expecting actions to be schema, and not predicates. (define (foobar x) ; (display "duuuuuuuude foobar pred-schema wrapper\n") ; (display x) (newline) @@ -39,7 +41,7 @@ ;(DefineLink (DefinedPredicateNode "do-noop") (True)) ;(pred-2-schema "do-noop") -(define demand-satisfied (True)) +(define face-demand-satisfied (True)) (define speech-demand-satisfied (True)) (define face-demand (psi-demand "face interaction" 1)) (define speech-demand (psi-demand "speech interaction" 1)) @@ -58,27 +60,27 @@ (psi-rule (list (NotLink (DefinedPredicate "Skip Interaction?")) (DefinedPredicate "Someone requests interaction?")) (DefinedSchemaNode "Interaction requested action") - demand-satisfied (stv 1 1) face-demand) + face-demand-satisfied (stv 1 1) face-demand) (psi-rule (list (NotLink (DefinedPredicate "Skip Interaction?")) (DefinedPredicate "Did someone arrive?")) (DefinedSchemaNode "New arrival sequence") - demand-satisfied (stv 1 1) face-demand) + face-demand-satisfied (stv 1 1) face-demand) (psi-rule (list (NotLink (DefinedPredicate "Skip Interaction?")) (DefinedPredicate "Did someone leave?")) (DefinedSchemaNode "Someone left action") - demand-satisfied (stv 1 1) face-demand) + face-demand-satisfied (stv 1 1) face-demand) (psi-rule (list (NotLink (DefinedPredicate "Skip Interaction?")) (DefinedPredicate "Someone visible?")) (DefinedSchemaNode "Interact with people") - demand-satisfied (stv 1 1) face-demand) + face-demand-satisfied (stv 1 1) face-demand) (psi-rule (list (NotLink (DefinedPredicate "Skip Interaction?")) (DefinedPredicate "Nothing happening?")) (DefinedSchemaNode "Nothing is happening") - demand-satisfied (stv 1 1) face-demand) + face-demand-satisfied (stv 1 1) face-demand) (psi-rule (list (NotLink (DefinedPredicate "Skip Interaction?")) (DefinedPredicate "chatbot started talking?")) @@ -115,3 +117,22 @@ speech-demand-satisfied (stv 1 1) speech-demand) ; ---------------------------------------------------------------------- + +; There MUST be a DefinedPredicateNode with exactly the name +; below in order for psi-run to work. Or we could just blow +; that off, and use our own loop... +(define loop-name (string-append psi-prefix-str "loop")) +(DefineLink + (DefinedPredicate loop-name) + (SatisfactionLink + (SequentialAnd + (Evaluation (GroundedPredicate "scm: psi-step") + (ListLink)) + (Evaluation (GroundedPredicate "scm: psi-run-continue?") + (ListLink)) + ; If ROS is dead, or the continue flag not set, + ; then stop running the behavior loop. + (DefinedPredicate "ROS is running?") + (DefinedPredicate loop-name)))) + +; ----------------------------------------------------------------------