00001
00002
00003
00004
00005 """Base code provided by I Heart Robotics, modified extensivly by Peter Tran. It now
00006 includes a sentry function that allows the robot to survey its surroundings for
00007 persons, as well as giving the robot a new direction to travel in. The code now also
00008 includes a bumper sensor, to avoid the robot from running into things it does not detect
00009 with kinect data. The code is also intergrated with tracking.py and follow.py so that
00010 if it detects a person, it will stop moving autonomously and begin following."""
00011
00012 import rospy
00013 import tf
00014 from geometry_msgs.msg import Twist
00015 from sensor_msgs.msg import LaserScan
00016 from std_msgs.msg import Bool
00017 from kobuki_msgs.msg import BumperEvent, CliffEvent
00018 from random import randint
00019
00020 class Scan_msg:
00021
00022 def __init__(self):
00023 '''Initializes an object of this class.
00024
00025 The constructor creates a publisher, a twist message.
00026 3 integer variables are created to keep track of where obstacles exist.
00027 3 dictionaries are to keep track of the movement and log messages.'''
00028 self.bump_subscriber = rospy.Subscriber('/mobile_base/events/bumper', BumperEvent, self.bumper_event_callback)
00029 self.wheel_drop_subscriber = rospy.Subscriber('/mobile_base/events/wheel_drop', CliffEvent, self.cliff_event_callback)
00030 self.pub = rospy.Publisher('/cmd_vel_mux/input/navi',Twist,queue_size = 10)
00031 self.msg = Twist()
00032 self.sect_1 = 0
00033 self.sect_2 = 0
00034 self.sect_3 = 0
00035 """self.ang and self.fwd is used to determine how the robot will move according to
00036 its position relative to the sensors"""
00037 self.ang = {0:0,001:-1.2,10:-1.2,11:-1.2,100:1.5,101:1.0,110:1.0,111:1.2}
00038 self.fwd = {0:.2,1:0,10:0,11:0,100:0.1,101:0,110:0,111:0}
00039 self.dbgmsg = {0:'Move forward',1:'Veer right',10:'Veer right',11:'Veer right',100:'Veer left',101:'Veer left',110:'Veer left',111:'Veer right'}
00040
00041 def reset_sect(self):
00042 '''Resets the below variables before each new scan message is read'''
00043 self.sect_1 = 0
00044 self.sect_2 = 0
00045 self.sect_3 = 0
00046
00047 def sort(self, laserscan):
00048 '''Goes through 'ranges' array in laserscan message and determines
00049 where obstacles are located. The class variables sect_1, sect_2,
00050 and sect_3 are updated as either '0' (no obstacles within 0.7 m)
00051 or '1' (obstacles within 0.7 m)
00052
00053 Parameter laserscan is a laserscan message.'''
00054 entries = len(laserscan.ranges)
00055 for entry in range(0,entries):
00056 if 0.01 < laserscan.ranges[entry] < 0.75:
00057 self.sect_1 = 1 if (0 < entry < entries/3) else 0
00058 self.sect_2 = 1 if (entries/3 < entry < entries/2) else 0
00059 self.sect_3 = 1 if (entries/2 < entry < entries) else 0
00060
00061
00062 def movement(self, sect1, sect2, sect3):
00063 '''Uses the information known about the obstacles to move robot.
00064
00065 Parameters are class variables and are used to assign a value to
00066 variable sect and then set the appropriate angular and linear
00067 velocities, and log messages.
00068 These are published and the sect variables are reset.'''
00069 sect = int(str(self.sect_1) + str(self.sect_2) + str(self.sect_3))
00070
00071
00072 """This is where the sentry function comes in, the robot will randomly, at a low
00073 chance, spin around in a circle for a random amount of time surveying the environment
00074 as well as randomizing which direction it will be facing."""
00075 i = randint(0,2000)
00076 if i > 1998:
00077 crosscounter = randint(10000,100000)
00078 j = 0
00079 i = 0
00080 for j in range(0, crosscounter):
00081 self.msg.angular.z = .5
00082 self.msg.linear.x = 0
00083 self.pub.publish(self.msg)
00084 j = j + 1
00085 i = 0
00086
00087 self.msg.angular.z = self.ang[sect]
00088 self.msg.linear.x = self.fwd[sect]
00089
00090 self.pub.publish(self.msg)
00091
00092 self.reset_sect()
00093
00094 def bumper_event_callback(self, msg):
00095 """Checks to see if the bumper has been pressed, if so the robot will then
00096 back up and turn in a random direction."""
00097 k = 0
00098 if msg.state == BumperEvent.PRESSED:
00099 for k in range(0, 4999):
00100 self.msg.angular.z = 0
00101 self.msg.linear.x = -0.1
00102 self.pub.publish(self.msg)
00103 k = k + 1
00104
00105 k = 0
00106 crosscounter = randint(5000,50000)
00107 orientation = randint(-1,1)
00108 for orientation in range (0, 0):
00109 orientation = randint(-1,1)
00110
00111 for k in range(0, crosscounter):
00112 self.msg.angular.z = orientation
00113 self.msg.linear.x = 0
00114 self.pub.publish(self.msg)
00115 k = k + 1
00116
00117 def cliff_event_callback(self, msg):
00118 """Checks to see if the robot is over a cliff. If so, then backs up to turn in
00119 a random direction. Currently does not work, be careful not to trash your
00120 robot."""
00121 k = 0
00122 if msg.state == CliffEvent.CLIFF:
00123 for k in range(0, 4999):
00124 self.msg.angular.z = 0
00125 self.msg.linear.x = -0.1
00126 self.pub.publish(self.msg)
00127 k = k + 1
00128
00129 k = 0
00130 crosscounter = randint(5000,50000)
00131 orientation = randint(-1,1)
00132 for orientation in range (0, 0):
00133 orientation = randint(-1,1)
00134
00135 for k in range(0, crosscounter):
00136 self.msg.angular.z = orientation
00137 self.msg.linear.x = 0
00138 self.pub.publish(self.msg)
00139 k = k + 1
00140
00141 def move_callback(self, data):
00142 """Checks to see if the subscriber from tracking.py is sending in a value
00143 of False before sending movement commands to the robot. This is to avoid
00144 the robot from both trying to follow a person as well as autonomously
00145 navigate."""
00146 while str(data) == "data: False":
00147 self.movement(self.sect_1, self.sect_2, self.sect_3)
00148
00149 def for_callback(self, laserscan):
00150 '''Passes laserscan onto function sort which gives the sect
00151 variables the proper values. Then the movement function is run
00152 with the class sect variables as parameters.
00153
00154 Parameter laserscan is received from callback function.
00155
00156 Also subscribes to tracking.py.'''
00157 self.sort(laserscan)
00158 self.sub = rospy.Subscriber("move", Bool, self.move_callback)
00159
00160
00161 def call_back(scanmsg):
00162 '''Passes laser scan message to for_callback function of sub_obj.
00163
00164 Parameter scanmsg is laserscan message.'''
00165 sub_obj.for_callback(scanmsg)
00166
00167 def listener():
00168 '''Initializes node, creates subscriber, and states callback
00169 function.'''
00170 rospy.init_node('navigation_sensors')
00171 rospy.loginfo("Subscriber Starting")
00172 tracker_subscriber = rospy.Subscriber("tracking", Bool, tracker_callback)
00173 sub = rospy.Subscriber('/scan', LaserScan, call_back)
00174 rospy.spin()
00175
00176 def tracker_callback(data):
00177 """Checks to see if the subscriber from tracking.py has sent in a True value for
00178 tracking a person. If True, it will publish to follow.py to begin following."""
00179 if str(data) == "data: True":
00180 pub = rospy.Publisher('move', Bool,queue_size=10)
00181 pub.publish(True)
00182
00183 if __name__ == "__main__":
00184 '''A Scan_msg class object called sub_obj is created and listener
00185 function is run'''
00186 sub_obj = Scan_msg()
00187 listener()
00188