diff --git a/.moves.py.swp b/.moves.py.swp new file mode 100644 index 0000000..310a83d Binary files /dev/null and b/.moves.py.swp differ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3314378 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,199 @@ +cmake_minimum_required(VERSION 2.8.3) +project(final_project) + +## Compile as C++11, supported in ROS Kinetic and newer +# add_compile_options(-std=c++11) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + geometry_msgs + rospy + smach +) + +## System dependencies are found with CMake's conventions +# find_package(Boost REQUIRED COMPONENTS system) + + +## Uncomment this if the package has a setup.py. This macro ensures +## modules and global scripts declared therein get installed +## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html +# catkin_python_setup() + +################################################ +## Declare ROS messages, services and actions ## +################################################ + +## To declare and build messages, services or actions from within this +## package, follow these steps: +## * Let MSG_DEP_SET be the set of packages whose message types you use in +## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). +## * In the file package.xml: +## * add a build_depend tag for "message_generation" +## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET +## * If MSG_DEP_SET isn't empty the following dependency has been pulled in +## but can be declared for certainty nonetheless: +## * add a exec_depend tag for "message_runtime" +## * In this file (CMakeLists.txt): +## * add "message_generation" and every package in MSG_DEP_SET to +## find_package(catkin REQUIRED COMPONENTS ...) +## * add "message_runtime" and every package in MSG_DEP_SET to +## catkin_package(CATKIN_DEPENDS ...) +## * uncomment the add_*_files sections below as needed +## and list every .msg/.srv/.action file to be processed +## * uncomment the generate_messages entry below +## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) + +## Generate messages in the 'msg' folder +# add_message_files( +# FILES +# Message1.msg +# Message2.msg +# ) + +## Generate services in the 'srv' folder +# add_service_files( +# FILES +# Service1.srv +# Service2.srv +# ) + +## Generate actions in the 'action' folder +# add_action_files( +# FILES +# Action1.action +# Action2.action +# ) + +## Generate added messages and services with any dependencies listed here +# generate_messages( +# DEPENDENCIES +# geometry_msgs +# ) + +################################################ +## Declare ROS dynamic reconfigure parameters ## +################################################ + +## To declare and build dynamic reconfigure parameters within this +## package, follow these steps: +## * In the file package.xml: +## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" +## * In this file (CMakeLists.txt): +## * add "dynamic_reconfigure" to +## find_package(catkin REQUIRED COMPONENTS ...) +## * uncomment the "generate_dynamic_reconfigure_options" section below +## and list every .cfg file to be processed + +## Generate dynamic reconfigure parameters in the 'cfg' folder +# generate_dynamic_reconfigure_options( +# cfg/DynReconf1.cfg +# cfg/DynReconf2.cfg +# ) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if your package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( +# INCLUDE_DIRS include +# LIBRARIES final_project +# CATKIN_DEPENDS geometry_msgs rospy smach +# DEPENDS system_lib +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +include_directories( +# include + ${catkin_INCLUDE_DIRS} +) + +## Declare a C++ library +# add_library(${PROJECT_NAME} +# src/${PROJECT_NAME}/final_project.cpp +# ) + +## Add cmake target dependencies of the library +## as an example, code may need to be generated before libraries +## either from message generation or dynamic reconfigure +# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Declare a C++ executable +## With catkin_make all packages are built within a single CMake context +## The recommended prefix ensures that target names across packages don't collide +# add_executable(${PROJECT_NAME}_node src/final_project_node.cpp) + +## Rename C++ executable without prefix +## The above recommended prefix causes long target names, the following renames the +## target back to the shorter version for ease of user use +## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" +# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") + +## Add cmake target dependencies of the executable +## same as for the library above +# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Specify libraries to link a library or executable target against +# target_link_libraries(${PROJECT_NAME}_node +# ${catkin_LIBRARIES} +# ) + +############# +## Install ## +############# + +# all install targets should use catkin DESTINATION variables +# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html + +## Mark executable scripts (Python etc.) for installation +## in contrast to setup.py, you can choose the destination +# install(PROGRAMS +# scripts/my_python_script +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark executables and/or libraries for installation +# install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node +# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} +# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + +## Mark cpp header files for installation +# install(DIRECTORY include/${PROJECT_NAME}/ +# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +# FILES_MATCHING PATTERN "*.h" +# PATTERN ".svn" EXCLUDE +# ) + +## Mark other files for installation (e.g. launch and bag files, etc.) +# install(FILES +# # myfile1 +# # myfile2 +# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +# ) + +############# +## Testing ## +############# + +## Add gtest based cpp test target and link libraries +# catkin_add_gtest(${PROJECT_NAME}-test test/test_final_project.cpp) +# if(TARGET ${PROJECT_NAME}-test) +# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) +# endif() + +## Add folders to be run by python nosetests +# catkin_add_nosetests(test) diff --git a/ChaChaDance/__init__.py b/ChaChaDance/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ChaChaDance/__init__.pyc b/ChaChaDance/__init__.pyc new file mode 100644 index 0000000..9b885a0 Binary files /dev/null and b/ChaChaDance/__init__.pyc differ diff --git a/ChaChaDance/backward.py b/ChaChaDance/backward.py new file mode 100644 index 0000000..0724057 --- /dev/null +++ b/ChaChaDance/backward.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +# Import libraries +import rospy +import smach +import time +from geometry_msgs.msg import Twist + + +# Define backward state +class Backward(smach.State): + def __init__(self, pub_controls): + smach.State.__init__(self, outcomes=["do_plan"], input_keys=["curr_state"]) + self.counter = 0 + self.pub_controls = pub_controls + + def execute(self, userdata): + # get state attributes + state_name = userdata.curr_state["name"] + + rospy.loginfo("Running {} state".format(state_name)) + + dur = rospy.Duration(2.8 / (6.0)) + rate = rospy.Rate(10) + start = rospy.Time.now() + + while rospy.Time.now() - start < dur: + move_cmd = Twist() + move_cmd.linear.x = -3.0 + self.pub_controls.publish(move_cmd) + rate.sleep() + + move_cmd = Twist() + move_cmd.linear.x = 0.0 + self.pub_controls.publish(move_cmd) + + return "do_plan" + diff --git a/ChaChaDance/backward.pyc b/ChaChaDance/backward.pyc new file mode 100644 index 0000000..2f146da Binary files /dev/null and b/ChaChaDance/backward.pyc differ diff --git a/ChaChaDance/circle.py b/ChaChaDance/circle.py new file mode 100644 index 0000000..b0e7ba4 --- /dev/null +++ b/ChaChaDance/circle.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +# Import libraries +import rospy +import smach +import time +import math +from geometry_msgs.msg import Twist + + +# Define circle state +class Circle(smach.State): + def __init__(self, pub_controls): + smach.State.__init__(self, outcomes=["do_plan"], input_keys=["curr_state"]) + self.counter = 0 + self.pub_controls = pub_controls + + def execute(self, userdata): + # get state attributes + state_name = userdata.curr_state["name"] + direction = userdata.curr_state["direction"] + + rospy.loginfo("Running {} state".format(state_name)) + + dur = rospy.Duration(47 / (70.0)) + rate = rospy.Rate(10) + + move_cmd = Twist() + move_cmd.linear.x= 5 + move_cmd.angular.z = 5 * direction + + t0=rospy.Time.now() + while rospy.Time.now() - t0 < dur: + self.pub_controls.publish(move_cmd) + rate.sleep() + + #After the loop, stops the robot + move_cmd = Twist() + move_cmd.angular.z = 0 + move_cmd.linear.x = 0 + self.pub_controls.publish(move_cmd) + + return "do_plan" + diff --git a/ChaChaDance/circle.pyc b/ChaChaDance/circle.pyc new file mode 100644 index 0000000..cf234fd Binary files /dev/null and b/ChaChaDance/circle.pyc differ diff --git a/ChaChaDance/forward.py b/ChaChaDance/forward.py new file mode 100644 index 0000000..af67d04 --- /dev/null +++ b/ChaChaDance/forward.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +# Import libraries +import rospy +import smach +import time +from geometry_msgs.msg import Twist + + +# Define forward state +class Forward(smach.State): + def __init__(self, pub_controls): + smach.State.__init__(self, outcomes=["do_plan"], input_keys=["curr_state"]) + self.counter = 0 + self.pub_controls = pub_controls + + def execute(self, userdata): + # get state attributes + state_name = userdata.curr_state["name"] + + rospy.loginfo("Running {} state".format(state_name)) + + dur = rospy.Duration(2.8 / (6.0)) + rate = rospy.Rate(10) + start = rospy.Time.now() + + while rospy.Time.now() - start < dur: + move_cmd = Twist() + move_cmd.linear.x = 3.0 + self.pub_controls.publish(move_cmd) + rate.sleep() + + move_cmd = Twist() + move_cmd.linear.x = 0.0 + self.pub_controls.publish(move_cmd) + + return "do_plan" + diff --git a/ChaChaDance/forward.pyc b/ChaChaDance/forward.pyc new file mode 100644 index 0000000..eb4f6e1 Binary files /dev/null and b/ChaChaDance/forward.pyc differ diff --git a/ChaChaDance/plan.py b/ChaChaDance/plan.py new file mode 100644 index 0000000..dd06a75 --- /dev/null +++ b/ChaChaDance/plan.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python + +# Import libraries +import rospy +import smach +import time + + +# Define planning state +class Plan(smach.State): + def __init__(self): + smach.State.__init__(self, outcomes=["do_forward", "do_backward", "do_exit", + "do_turnL", "do_turnR", "do_circle"], + input_keys=["plan", "curr_state", "plan_length"], + output_keys=["curr_state"]) + + self.counter = 0 + + def execute(self, userdata): + # if plan is empty, exit + if not userdata.plan: + return 'do_exit' + + # get the first state + current_state = userdata.plan.pop(0) + userdata.curr_state = current_state + rospy.loginfo("Planning attempting to run: {}".format(current_state["name"])) + + time.sleep(1) + + return current_state["name"] diff --git a/ChaChaDance/plan.pyc b/ChaChaDance/plan.pyc new file mode 100644 index 0000000..4d43320 Binary files /dev/null and b/ChaChaDance/plan.pyc differ diff --git a/ChaChaDance/stop.py b/ChaChaDance/stop.py new file mode 100644 index 0000000..a716ce5 --- /dev/null +++ b/ChaChaDance/stop.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +# Import libraries +import rospy +import smach +import time +from geometry_msgs.msg import Twist + + +# Define the stop state +class Stop(smach.State): + def __init__(self, pub_controls): + smach.State.__init__(self, outcomes=["do_exit"]) + self.counter = 0 + self.pub_controls = pub_controls + + def execute(self, userdata): + rospy.loginfo("Running Stop state") + + move_cmd = Twist() + move_cmd.linear.x = 0.0 + self.pub_controls.publish(move_cmd) + + time.sleep(1) + + return "do_exit" diff --git a/ChaChaDance/stop.pyc b/ChaChaDance/stop.pyc new file mode 100644 index 0000000..600f38b Binary files /dev/null and b/ChaChaDance/stop.pyc differ diff --git a/ChaChaDance/turnL.py b/ChaChaDance/turnL.py new file mode 100644 index 0000000..8758e1a --- /dev/null +++ b/ChaChaDance/turnL.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Import libraries +import rospy +import smach +import time +from geometry_msgs.msg import Twist + + +# define state turnL - turn left +class TurnL(smach.State): + def __init__(self, pub_controls): + smach.State.__init__(self, outcomes=['do_plan'], + input_keys=['curr_state']) + self.pub_controls = pub_controls + self.counter = 0 + + def execute(self, userdata): + # get state attributes + state_name = userdata.curr_state["name"] + + rospy.loginfo("Running {} state".format(state_name)) + + move_cmd = Twist() + move_cmd.angular.z = 10 + + rate = rospy.Rate(10) + + dur = rospy.Duration(3.5 / (7.0)) + t0 = rospy.Time.now() + + while rospy.Time.now() - t0 < dur: + self.pub_controls.publish(move_cmd) + rate.sleep() + + move_cmd = Twist() + move_cmd.angular.z = 0.0 + self.pub_controls.publish(move_cmd) + + return "do_plan" diff --git a/ChaChaDance/turnL.pyc b/ChaChaDance/turnL.pyc new file mode 100644 index 0000000..3f4f7f4 Binary files /dev/null and b/ChaChaDance/turnL.pyc differ diff --git a/ChaChaDance/turnR.py b/ChaChaDance/turnR.py new file mode 100644 index 0000000..7ef6e78 --- /dev/null +++ b/ChaChaDance/turnR.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Import libraries +import rospy +import smach +import time +from geometry_msgs.msg import Twist + + +# define state turnR - turn right +class TurnR(smach.State): + def __init__(self, pub_controls): + smach.State.__init__(self, outcomes=['do_plan'], + input_keys=['curr_state']) + self.pub_controls = pub_controls + self.counter = 0 + + def execute(self, userdata): + # get state attributes + state_name = userdata.curr_state["name"] + + rospy.loginfo("Running {} state".format(state_name)) + + move_cmd = Twist() + move_cmd.angular.z = -10 + + rate = rospy.Rate(10) + + dur = rospy.Duration(3.5 / (7.0)) + t0 = rospy.Time.now() + + while rospy.Time.now() - t0 < dur: + self.pub_controls.publish(move_cmd) + rate.sleep() + + move_cmd = Twist() + move_cmd.angular.z = 0.0 + self.pub_controls.publish(move_cmd) + + return "do_plan" diff --git a/ChaChaDance/turnR.pyc b/ChaChaDance/turnR.pyc new file mode 100644 index 0000000..d8620c4 Binary files /dev/null and b/ChaChaDance/turnR.pyc differ diff --git a/FinalProject.launch b/FinalProject.launch new file mode 100755 index 0000000..8ac6139 --- /dev/null +++ b/FinalProject.launch @@ -0,0 +1,4 @@ + + + + diff --git a/__pycache__/plan_handler.cpython-35.pyc b/__pycache__/plan_handler.cpython-35.pyc new file mode 100644 index 0000000..3e16837 Binary files /dev/null and b/__pycache__/plan_handler.cpython-35.pyc differ diff --git a/__pycache__/plan_handler_test.cpython-27-PYTEST.pyc b/__pycache__/plan_handler_test.cpython-27-PYTEST.pyc new file mode 100644 index 0000000..ba51ded Binary files /dev/null and b/__pycache__/plan_handler_test.cpython-27-PYTEST.pyc differ diff --git a/main.py b/main.py new file mode 100755 index 0000000..3d47238 --- /dev/null +++ b/main.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python + +# Import libraries +import rospy +import smach +import time +import pathlib +import websocket +import thread +import time +from plan_handler import get_filtered_plans +from geometry_msgs.msg import Twist +from plan_parser import parse_plan +from ChaChaDance.plan import Plan +from ChaChaDance.stop import Stop +from ChaChaDance.forward import Forward +from ChaChaDance.backward import Backward +from ChaChaDance.turnL import TurnL +from ChaChaDance.turnR import TurnR +from ChaChaDance.circle import Circle + +def on_message(ws, message): + plan = get_filtered_plans(message) + if plan: + runTurtleBot(plan) + +def on_error(ws, error): + print(error) + + +def on_close(ws, close_status_code, close_msg): + print("### closed ###") + + +def on_open(ws): + def run(*args): + time.sleep(1) + print("WSS connection opened") + thread.start_new_thread(run, ()) + + +def runTurtleBot(plan): + pub_controls = rospy.Publisher('/cmd_vel', Twist, queue_size=1) + + # Create a SMACH state machine + sm = smach.StateMachine(outcomes=['do_exit']) + sm.userdata.plan = plan + sm.userdata.plan_length = len(plan) + sm.userdata.curr_state = {} + + with sm: + # Add states to the container + smach.StateMachine.add('Plan', Plan(), + transitions={'do_forward': 'Forward', 'do_backward': 'Backward', + 'do_turnL': 'TurnL', 'do_turnR': 'TurnR', 'do_exit': 'Stop', + 'do_circle': 'Circle'}) + smach.StateMachine.add('Forward', Forward(pub_controls), + transitions={'do_plan': 'Plan'}, + remapping={"curr_state": "curr_state"}) + smach.StateMachine.add("Backward", Backward(pub_controls), + transitions={"do_plan": "Plan"}, + remapping={"curr_state": "curr_state"}) + smach.StateMachine.add("TurnL", TurnL(pub_controls), + transitions={"do_plan": "Plan"}, + remapping={"curr_state": "curr_state"}) + smach.StateMachine.add("TurnR", TurnR(pub_controls), + transitions={"do_plan": "Plan"}, + remapping={"curr_state": "curr_state"}) + smach.StateMachine.add("Circle", Circle(pub_controls), + transitions={"do_plan": "Plan"}, + remapping={"curr_state": "curr_state"}) + smach.StateMachine.add("Stop", Stop(pub_controls), + transitions={"do_exit": "do_exit"}) + outcome = sm.execute() + + +def read_cha_cha(): + websocket.enableTrace(True) + ws = websocket.WebSocketApp("wss://squushy.herokuapp.com", + on_open=on_open, + on_message=on_message, + on_error=on_error, + on_close=on_close) + ws.run_forever() + + +if __name__ == '__main__': + rospy.init_node('squishy_turtlebot3') + + abs_path = pathlib.Path(__file__).parent.resolve() + plan_path = str(abs_path) + "/plans/plan1.json" + plan = parse_plan(plan_path) + print(plan) + + read_cha_cha() diff --git a/moves.py b/moves.py new file mode 100644 index 0000000..4cdbeaa --- /dev/null +++ b/moves.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +# Import libraries +import rospy +import smach +import time +import math +from geometry_msgs.msg import Twist + +def move_circle(pub_controls, direction): + rospy.loginfo("Running circle state. Direction: {}".format(direction)) + + dur = rospy.Duration(47 / (20.0)) + rate = rospy.Rate(10) + + move_cmd = Twist() + move_cmd.linear.x= 5 + move_cmd.angular.z = 5 * direction + + t0=rospy.Time.now() + while rospy.Time.now() - t0 < dur: + pub_controls.publish(move_cmd) + rate.sleep() + + #After the loop, stops the robot + move_cmd = Twist() + move_cmd.angular.z = 0 + move_cmd.linear.x = 0 + pub_controls.publish(move_cmd) + +def move_forward(pub_controls, direction): + rospy.loginfo("Running forward state. Direction: {}".format(direction)) + + dur = rospy.Duration(10.8 / (6.0)) + rate = rospy.Rate(10) + start = rospy.Time.now() + + while rospy.Time.now() - start < dur: + move_cmd = Twist() + move_cmd.linear.x = 3.0 * direction + pub_controls.publish(move_cmd) + rate.sleep() + + move_cmd = Twist() + move_cmd.linear.x = 0.0 + pub_controls.publish(move_cmd) + +def move_left(pub_controls): + rospy.loginfo("Running left state.") + + move_cmd = Twist() + move_cmd.angular.z = 10 + + rate = rospy.Rate(10) + + dur = rospy.Duration(3.5 / (7.0)) + t0 = rospy.Time.now() + + while rospy.Time.now() - t0 < dur: + pub_controls.publish(move_cmd) + rate.sleep() + + move_cmd = Twist() + move_cmd.angular.z = 0.0 + pub_controls.publish(move_cmd) + +def move_right(pub_controls): + rospy.loginfo("Running left state.") + + move_cmd = Twist() + move_cmd.angular.z = -10 + + rate = rospy.Rate(10) + + dur = rospy.Duration(3.5 / (7.0)) + t0 = rospy.Time.now() + + while rospy.Time.now() - t0 < dur: + pub_controls.publish(move_cmd) + rate.sleep() + + move_cmd = Twist() + move_cmd.angular.z = 0.0 + pub_controls.publish(move_cmd) diff --git a/moves.pyc b/moves.pyc new file mode 100644 index 0000000..f5b2623 Binary files /dev/null and b/moves.pyc differ diff --git a/package.xml b/package.xml new file mode 100644 index 0000000..37751af --- /dev/null +++ b/package.xml @@ -0,0 +1,68 @@ + + + final_project + 0.0.0 + The final_project package + + + + + pi + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + catkin + geometry_msgs + rospy + smach + geometry_msgs + rospy + smach + geometry_msgs + rospy + smach + + + + + + + + diff --git a/plan_handler.py b/plan_handler.py new file mode 100644 index 0000000..e9c9f56 --- /dev/null +++ b/plan_handler.py @@ -0,0 +1,264 @@ +#!/usr/bin/env/ python + +# Import libraries +import rospy +from geometry_msgs.msg import Twist +from moves import move_circle, move_forward, move_left, move_right +from datetime import timedelta, datetime + +# Global Counters +in_progress = False +last_moves = [] +last_move_time = datetime.utcnow() - timedelta(days=1) + +# Return plans depending on song filter +def get_filtered_plans(last_words): + last_words = ' '.join(last_words.split()[-5:]) + + global in_progress + global last_move_time + + if in_progress: + return [] + + in_progress = True + + last_words_str = str(last_words) + last_words_lower = last_words_str.lower() + + #print(last_words_lower) + cur_time = datetime.utcnow() + + pub_controls = rospy.Publisher('/cmd_vel', Twist, queue_size=1) + if cur_time > last_move_time + timedelta(seconds=2.5): + cha_cha_handler(last_words_lower, pub_controls) + clap_handler(last_words_lower, pub_controls) + left_handler(last_words_lower, pub_controls) + back_handler(last_words_lower, pub_controls) + one_hop_handler(last_words_lower, pub_controls) + right_foot_handler(last_words_lower, pub_controls) + left_foot_handler(last_words_lower, pub_controls) + circle_handler(last_words_lower, pub_controls) + + in_progress = False + + return [] + + +def cha_cha_handler(last_words, pub_controls): + global last_moves + global last_move_time + + if len(last_moves) >= 1 and \ + last_moves[-1] == 'cha cha': + return [] + + matches = [ + "we're gonna get funky", + "we're going to get funky", + "cha-cha", + "cha cha", + "time to get funky" + ] + + for match in matches: + if match in last_words: + last_move_time = datetime.utcnow() + last_moves.append('cha cha') + + print("Found cha-cha move. Attempting to execute.") + + move_circle(pub_controls, 1) + move_circle(pub_controls, -1) + + return True + + return False + + +def clap_handler(last_words, pub_controls): + global last_moves + global last_move_time + + if len(last_moves) >= 2 and \ + last_moves[-1] == 'clap': + return [] + + matches = [ + "everybody clap your hands", + "clap clap clap" + ] + + for match in matches: + if match in last_words: + last_move_time = datetime.utcnow() + last_moves.append('clap') + + print("Found clap. Attempting to execute.") + + move_forward(pub_controls, 1) + move_forward(pub_controls, -1) + + return True + + return False + + +def left_handler(last_words, pub_controls): + global last_moves + global last_move_time + + if len(last_moves) >= 1 and \ + last_moves[-1] == 'left': + return [] + + matches = [ + "to the left", + "turn the lamp" + ] + + for match in matches: + if match in last_words: + last_move_time = datetime.utcnow() + last_moves.append('left') + + print("Found left. Attempting to execute.") + + move_left(pub_controls) + + return True + + return False + + +def back_handler(last_words, pub_controls): + global last_moves + global last_move_time + + if len(last_moves) >= 1 and \ + last_moves[-1] == 'back': + return [] + + matches = [ + "take it back", + "back now y'all" + ] + + for match in matches: + if match in last_words: + last_move_time = datetime.utcnow() + last_moves.append('back') + + print("Found back. Attempting to execute.") + + move_forward(pub_controls, -1) + + return True + + return False + +def one_hop_handler(last_words, pub_controls): + global last_moves + global last_move_time + + if len(last_moves) >= 1 and \ + last_moves[-1] == 'one hop': + return [] + + matches = [ + "one hop this time", + ] + + for match in matches: + if match in last_words: + last_move_time = datetime.utcnow() + last_moves.append('one hop') + + print("Found one hop. Attempting to execute.") + + move_forward(pub_controls, -1) + + return True + + return False + +def right_foot_handler(last_words, pub_controls): + global last_moves + global last_move_time + + if len(last_moves) >= 1 and \ + last_moves[-1] == 'right foot': + return [] + + matches = [ + "right foot", + "to the right now", + "the right now", + "right now" + ] + + for match in matches: + if match in last_words: + last_move_time = datetime.utcnow() + last_moves.append('right foot') + + print("Found right foot. Attempting to execute.") + + move_right(pub_controls) + + return True + + return False + +def left_foot_handler(last_words, pub_controls): + global last_moves + global last_move_time + + if len(last_moves) >= 1 and \ + last_moves[-1] == 'left foot stomp': + return [] + + matches = [ + "left foot", + "left foot let's stomp", + "left foot lets stomp" + ] + + for match in matches: + if match in last_words: + last_move_time = datetime.utcnow() + last_moves.append('left foot stomp') + + print("Found left foot. Attempting to execute.") + + move_left(pub_controls) + + return True + + return False + +def circle_handler(last_words, pub_controls): + global last_moves + global last_move_time + + if len(last_moves) >= 1 and \ + last_moves[-1] == 'circle': + return [] + + matches = [ + "turn it out", + "turn it up" + ] + + for match in matches: + if match in last_words: + last_move_time = datetime.utcnow() + last_moves.append('circle') + + print("Found circle. Attempting to execute.") + + move_circle(pub_controls, 1) + + return True + + return False diff --git a/plan_handler.pyc b/plan_handler.pyc new file mode 100644 index 0000000..9c9b132 Binary files /dev/null and b/plan_handler.pyc differ diff --git a/plan_handler_test.py b/plan_handler_test.py new file mode 100644 index 0000000..eff5de2 --- /dev/null +++ b/plan_handler_test.py @@ -0,0 +1,133 @@ +#!/usr/bin/env/ python + +import pytest +from mock import patch +from plan_handler import cha_cha_handler, clap_handler, left_handler, back_handler, one_hop_handler, right_foot_handler, left_foot_handler, circle_handler + +@patch('plan_handler.last_moves', []) +def test_cha_cha_handler_true(mocker): + mocker.patch('plan_handler.move_circle', return_value=True) + + res = cha_cha_handler("we're gonna get funky", None) + + assert res == True + +@patch('plan_handler.last_moves', []) +def test_cha_cha_handler_false(mocker): + mocker.patch('plan_handler.move_circle', return_value=True) + + res = cha_cha_handler("NO", None) + + assert res == False + +@patch('plan_handler.last_moves', []) +def test_clap_handler_true(mocker): + mocker.patch('plan_handler.move_forward', return_value=True) + + res = clap_handler("clap clap clap", None) + + assert res == True + +@patch('plan_handler.last_moves', []) +def test_clap_handler_false(mocker): + mocker.patch('plan_handler.move_forward', return_value=True) + + res = clap_handler("NO", None) + + assert res == False + +@patch('plan_handler.last_moves', []) +def test_left_handler_true(mocker): + mocker.patch('plan_handler.move_left', return_value=True) + + res = left_handler("to the left", None) + + assert res == True + +@patch('plan_handler.last_moves', []) +def test_left_handler_false(mocker): + mocker.patch('plan_handler.move_left', return_value=True) + + res = left_handler("NO", None) + + assert res == False + +@patch('plan_handler.last_moves', []) +def test_back_handler_true(mocker): + mocker.patch('plan_handler.move_forward', return_value=True) + + res = back_handler("take it back", None) + + assert res == True + +@patch('plan_handler.last_moves', []) +def test_back_handler_false(mocker): + mocker.patch('plan_handler.move_forward', return_value=True) + + res = back_handler("NO", None) + + assert res == False + +@patch('plan_handler.last_moves', []) +def test_one_hop_handler_true(mocker): + mocker.patch('plan_handler.move_forward', return_value=True) + + res = one_hop_handler("one hop this time", None) + + assert res == True + +@patch('plan_handler.last_moves', []) +def test_one_hop_handler_false(mocker): + mocker.patch('plan_handler.move_forward', return_value=True) + + res = one_hop_handler("NO", None) + + assert res == False + +@patch('plan_handler.last_moves', []) +def test_right_foot_handler_true(mocker): + mocker.patch('plan_handler.move_right', return_value=True) + + res = right_foot_handler("right foot", None) + + assert res == True + +@patch('plan_handler.last_moves', []) +def test_right_foot_handler_false(mocker): + mocker.patch('plan_handler.move_right', return_value=True) + + res = right_foot_handler("NO", None) + + assert res == False + +@patch('plan_handler.last_moves', []) +def test_left_foot_handler_true(mocker): + mocker.patch('plan_handler.move_left', return_value=True) + + res = left_foot_handler("left foot", None) + + assert res == True + +@patch('plan_handler.last_moves', []) +def test_left_foot_handler_false(mocker): + mocker.patch('plan_handler.move_left', return_value=True) + + res = left_foot_handler("NO", None) + + assert res == False + +@patch('plan_handler.last_moves', []) +def test_circle_handler_true(mocker): + mocker.patch('plan_handler.move_circle', return_value=True) + + res = circle_handler("turn it out", None) + + assert res == True + +@patch('plan_handler.last_moves', []) +def test_circle_handler_false(mocker): + mocker.patch('plan_handler.move_circle', return_value=True) + + res = circle_handler("NO", None) + + assert res == False diff --git a/plan_parser.py b/plan_parser.py new file mode 100644 index 0000000..864e11c --- /dev/null +++ b/plan_parser.py @@ -0,0 +1,11 @@ +#!/usr/bin/env/ python + +# Import libraries +import json + + +# Parse the task planner json file into individual states. +def parse_plan(task_planner_path): + with open(task_planner_path) as planner_file: + planner_states = json.load(planner_file) + return planner_states["states"] diff --git a/plan_parser.pyc b/plan_parser.pyc new file mode 100644 index 0000000..97b6417 Binary files /dev/null and b/plan_parser.pyc differ diff --git a/plans/plan1.json b/plans/plan1.json new file mode 100644 index 0000000..3efd175 --- /dev/null +++ b/plans/plan1.json @@ -0,0 +1,10 @@ +{ + "states": [ + { + "name": "do_forward" + }, + { + "name": "do_backward" + } + ] +} diff --git a/pocketsphinx b/pocketsphinx new file mode 160000 index 0000000..051fabb --- /dev/null +++ b/pocketsphinx @@ -0,0 +1 @@ +Subproject commit 051fabb69e4439051abada8bed2c3ed3f1c35ebf diff --git a/project2/README.md b/project2/README.md new file mode 100644 index 0000000..e69de29 diff --git a/project2/main.py b/project2/main.py new file mode 100644 index 0000000..e69de29 diff --git a/project2/maze_navigator.py b/project2/maze_navigator.py new file mode 100644 index 0000000..e69de29 diff --git a/project2/moveturtle.py b/project2/moveturtle.py new file mode 100644 index 0000000..e69de29