1414__email__ = "amir@avisengine.com"
1515
1616
17- class Car :
17+ class Car () :
1818 '''
1919 AVIS Engine Main Car class
20+
21+ Attributes
22+ ----------
23+
24+ Public:
25+ steering_value
26+ speed_value
27+ sensor_status
28+ image_mode
29+ get_Speed
30+ data_arr
31+ data_str
32+ sock
33+ image
34+ sensors
35+ current_speed
36+ sensor_angle
2037 '''
21- def __init__ (self ) -> None :
22- # Instance variables for car state
23- self .steering_value : int = 0
24- self .speed_value : int = 0
25- self .sensor_status : int = 1
26- self .image_mode : int = 1
27- self .get_Speed : int = 1
28- self .sensor_angle : int = 30
29- self .sock : socket .socket = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
30- self ._data_format : str = "Speed:{},Steering:{},ImageStatus:{},SensorStatus:{},GetSpeed:{},SensorAngle:{}"
31- self .data_str : str = self ._data_format .format (
32- self .speed_value , self .steering_value , self .image_mode , self .sensor_status , self .get_Speed , self .sensor_angle
33- )
34- self .image = None
35- self .sensors = None
36- self .current_speed = None
37- self ._is_initialized = False
38- self ._init_frames_needed = 4 # Number of frames needed for stabilization
39-
40- def connect (self , server : str , port : int ) -> bool :
38+
39+ #Attributes to kind of replicate a Pub-sub pattern messaging to request data
40+ steering_value = 0
41+ speed_value = 0
42+ sensor_status = 1
43+ image_mode = 1
44+ get_Speed = 1
45+ sensor_angle = 30
46+
47+ sock = socket .socket (socket .AF_INET , socket .SOCK_STREAM )
48+
49+ #Data format for request
50+ data_arr = [speed_value , steering_value , image_mode , sensor_status , get_Speed , sensor_angle ]
51+ _data_format = "Speed:{},Steering:{},ImageStatus:{},SensorStatus:{},GetSpeed:{},SensorAngle:{}"
52+ data_str = _data_format .format (data_arr [0 ], data_arr [1 ], data_arr [2 ], data_arr [3 ], data_arr [4 ], data_arr [5 ])
53+
54+ image = None
55+ sensors = None
56+ current_speed = None
57+
58+ def connect (self ,server ,port ):
4159 '''
4260 Connecting to the simulator (server)
4361 '''
4462 try :
4563 self .sock .connect ((server , port ))
4664 self .sock .settimeout (5.0 )
47- print (f"connected to { server } { port } " )
48- # Give simulator time to initialize
49- time .sleep (3 )
50- # Request initial data frames for stabilization
51- for _ in range (self ._init_frames_needed ):
52- self .getData ()
53- self ._is_initialized = True
65+
66+ print ("connected to " , server , port )
5467 return True
55- except Exception as e :
56- print (f "Failed to connect to { server } { port } : { e } " )
68+ except :
69+ print ("Failed to connect to " , server , port )
5770 return False
5871
59- def recvall (self , sock : socket .socket ) -> str :
72+
73+ def recvall (self , socket ):
6074 '''
6175 Function to receive all the data chunks
6276 '''
6377 BUFFER_SIZE = 131072 # Increased buffer size for better performance
64- data = bytearray ()
78+ data = bytearray () # Use a bytearray for better performance
79+
6580 while True :
66- part = sock .recv (BUFFER_SIZE )
81+ part = socket .recv (BUFFER_SIZE )
6782 data .extend (part )
68- if utils .KMPSearch (b"<EOF>" , data ) > - 1 :
83+
84+ # Use KMP search to find the <EOF>, KMPSearch() returns -1 if the pattern was not found
85+ # It is 9 times faster than the simple python search
86+ if utils .KMPSearch (b"<EOF>" , data ) > - 1 : # Convert "<EOF>" to bytes
6987 break
88+
7089 return data .decode ("utf-8" )
7190
72- def setSteering (self , steering : int ) -> None :
91+
92+ def setSteering (self ,steering ):
7393 '''
7494 Setting the steering of the car
95+
96+ Parameters
97+ ----------
98+ steering : int
99+ Steering value in degree
75100 '''
76101 self .steering_value = steering
77102 self .image_mode = 0
@@ -80,9 +105,13 @@ def setSteering(self, steering: int) -> None:
80105 self .sock .sendall (self .data_str .encode ("utf-8" ))
81106 time .sleep (0.01 )
82107
83- def setSpeed (self , speed : int ) -> None :
108+ def setSpeed (self ,speed ) :
84109 '''
85110 Setting the speed of the car
111+
112+ Parameters
113+ ----------
114+ speed : int
86115 '''
87116 self .speed_value = speed
88117 self .image_mode = 0
@@ -91,49 +120,61 @@ def setSpeed(self, speed: int) -> None:
91120 self .sock .sendall (self .data_str .encode ("utf-8" ))
92121 time .sleep (0.01 )
93122
94- def setSensorAngle (self , angle : int ) -> None :
123+ def setSensorAngle (self , angle ) :
95124 '''
96125 Setting the angle between each sensor ray
126+
127+ Parameters
128+ ----------
129+ angle : int
130+ In degrees
97131 '''
132+
98133 self .image_mode = 0
99134 self .sensor_status = 0
100135 self .sensor_angle = angle
101136 self .updateData ()
102137 self .sock .sendall (self .data_str .encode ("utf-8" ))
103-
104- def getData (self ) -> None :
138+
139+ def getData (self ):
105140 '''
106141 Requesting for the data from the simulator
107142 '''
108143 self .image_mode = 1
109144 self .sensor_status = 1
110145 self .updateData ()
111146 self .sock .sendall (self .data_str .encode ("utf-8" ))
147+
112148 receive = self .recvall (self .sock )
149+
113150 imageTagCheck = re .search ('<image>(.*?)<\/image>' , receive )
114151 sensorTagCheck = re .search ('<sensor>(.*?)<\/sensor>' , receive )
115- speedTagCheck = re .search ('<speed>(.*?)<\/speed>' , receive )
152+ speedTagCheck = re .search ('<speed>(.*?)<\/speed>' , receive )
153+
116154 try :
117- if imageTagCheck :
155+ if ( imageTagCheck ) :
118156 imageData = imageTagCheck .group (1 )
119157 im_bytes = base64 .b64decode (imageData )
120- im_arr = np .frombuffer (im_bytes , dtype = np .uint8 )
158+ im_arr = np .frombuffer (im_bytes , dtype = np .uint8 ) # im_arr is one-dim Numpy array
121159 imageOpenCV = cv2 .imdecode (im_arr , flags = cv2 .IMREAD_COLOR )
122160 self .image = imageOpenCV
123- if sensorTagCheck :
161+
162+ if (sensorTagCheck ):
124163 sensorData = sensorTagCheck .group (1 )
125164 sensor_arr = re .findall ("\d+" , sensorData )
126- sensor_int_arr = list (map (int , sensor_arr ))
165+ sensor_int_arr = list (map (int , sensor_arr ))
127166 self .sensors = sensor_int_arr
128167 else :
129- self .sensors = [1500 , 1500 , 1500 ]
130- if speedTagCheck :
168+ self .sensors = [1500 ,1500 ,1500 ]
169+
170+ if (speedTagCheck ):
131171 current_sp = speedTagCheck .group (1 )
132172 self .current_speed = int (current_sp )
133173 else :
134174 self .current_speed = 0
135- except Exception as e :
136- print (f"Failed to receive data: { e } " )
175+ except :
176+ print ("Failed to receive data" )
177+
137178
138179 def getImage (self ):
139180 '''
@@ -144,59 +185,36 @@ def getImage(self):
144185 def getSensors (self ):
145186 '''
146187 Returns the sensor data
188+ A List:
189+ [Left Sensor: int, Middle Sensor: int, Right Sensor: int]
147190 '''
148191 return self .sensors
149-
192+
150193 def getSpeed (self ):
151194 '''
152195 Returns the speed of the car
153196 '''
154197 return self .current_speed
155-
156- def updateData (self ) -> None :
198+
199+ def updateData (self ):
157200 '''
158201 Updating the request data array and data string
159202 '''
160- data = [self .speed_value , self .steering_value , self .image_mode , self .sensor_status , self .get_Speed , self .sensor_angle ]
161- self .data_str = self ._data_format .format (* data )
162-
163- def stop (self ) -> None :
164- '''
165- Stopping the car and closing the socket
166- '''
167- try :
168- self .setSpeed (0 )
169- self .setSteering (0 )
170- self .sock .sendall ("stop" .encode ("utf-8" ))
171- self .sock .close ()
172- print ("Process stopped successfully!" )
173- except Exception as e :
174- print (f"Error during stop: { e } " )
175-
176- def is_ready (self ) -> bool :
177- '''
178- Check if the car is initialized and ready for operation
203+ data = [self .speed_value ,self .steering_value ,self .image_mode ,self .sensor_status ,self .get_Speed , self .sensor_angle ]
204+ self .data_str = self ._data_format .format (data [0 ], data [1 ], data [2 ], data [3 ], data [4 ], data [5 ])
179205
180- Returns
181- -------
182- bool: True if the car is initialized and ready for operation
206+ def stop (self ):
183207 '''
184- return self ._is_initialized
185-
186- def __enter__ (self ):
187- '''Enable use as a context manager.'''
188- return self
189-
190- def __exit__ (self , exc_type , exc_val , exc_tb ):
191- '''Ensure resources are cleaned up when exiting context.'''
192- self .stop ()
193- return False # Do not suppress exceptions
194-
208+ Stoping the car and closing the socket
209+ '''
210+ self .setSpeed (0 )
211+ self .setSteering (0 )
212+ self .sock .sendall ("stop" .encode ("utf-8" ))
213+ self .sock .close ()
214+ print ("Process stopped successfully!" )
215+
195216 def __del__ (self ):
196- try :
197- self .stop ()
198- except Exception :
199- pass
200-
201-
202-
217+ self .stop ()
218+
219+
220+
0 commit comments