14
14
15
15
16
16
17
- class Car () :
17
+ class Car :
18
18
'''
19
19
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
37
20
'''
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 ):
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 :
59
41
'''
60
42
Connecting to the simulator (server)
61
43
'''
62
44
try :
63
45
self .sock .connect ((server , port ))
64
46
self .sock .settimeout (5.0 )
65
-
66
- print ("connected to " , server , port )
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
67
54
return True
68
- except :
69
- print ("Failed to connect to " , server , port )
55
+ except Exception as e :
56
+ print (f "Failed to connect to { server } { port } : { e } " )
70
57
return False
71
58
72
-
73
- def recvall (self , socket ):
59
+ def recvall (self , sock : socket .socket ) -> str :
74
60
'''
75
61
Function to receive all the data chunks
76
62
'''
77
63
BUFFER_SIZE = 131072 # Increased buffer size for better performance
78
- data = bytearray () # Use a bytearray for better performance
79
-
64
+ data = bytearray ()
80
65
while True :
81
- part = socket .recv (BUFFER_SIZE )
66
+ part = sock .recv (BUFFER_SIZE )
82
67
data .extend (part )
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
68
+ if utils .KMPSearch (b"<EOF>" , data ) > - 1 :
87
69
break
88
-
89
70
return data .decode ("utf-8" )
90
71
91
-
92
- def setSteering (self ,steering ):
72
+ def setSteering (self , steering : int ) -> None :
93
73
'''
94
74
Setting the steering of the car
95
-
96
- Parameters
97
- ----------
98
- steering : int
99
- Steering value in degree
100
75
'''
101
76
self .steering_value = steering
102
77
self .image_mode = 0
@@ -105,13 +80,9 @@ def setSteering(self,steering):
105
80
self .sock .sendall (self .data_str .encode ("utf-8" ))
106
81
time .sleep (0.01 )
107
82
108
- def setSpeed (self ,speed ) :
83
+ def setSpeed (self , speed : int ) -> None :
109
84
'''
110
85
Setting the speed of the car
111
-
112
- Parameters
113
- ----------
114
- speed : int
115
86
'''
116
87
self .speed_value = speed
117
88
self .image_mode = 0
@@ -120,61 +91,49 @@ def setSpeed(self,speed):
120
91
self .sock .sendall (self .data_str .encode ("utf-8" ))
121
92
time .sleep (0.01 )
122
93
123
- def setSensorAngle (self , angle ) :
94
+ def setSensorAngle (self , angle : int ) -> None :
124
95
'''
125
96
Setting the angle between each sensor ray
126
-
127
- Parameters
128
- ----------
129
- angle : int
130
- In degrees
131
97
'''
132
-
133
98
self .image_mode = 0
134
99
self .sensor_status = 0
135
100
self .sensor_angle = angle
136
101
self .updateData ()
137
102
self .sock .sendall (self .data_str .encode ("utf-8" ))
138
-
139
- def getData (self ):
103
+
104
+ def getData (self ) -> None :
140
105
'''
141
106
Requesting for the data from the simulator
142
107
'''
143
108
self .image_mode = 1
144
109
self .sensor_status = 1
145
110
self .updateData ()
146
111
self .sock .sendall (self .data_str .encode ("utf-8" ))
147
-
148
112
receive = self .recvall (self .sock )
149
-
150
113
imageTagCheck = re .search ('<image>(.*?)<\/image>' , receive )
151
114
sensorTagCheck = re .search ('<sensor>(.*?)<\/sensor>' , receive )
152
- speedTagCheck = re .search ('<speed>(.*?)<\/speed>' , receive )
153
-
115
+ speedTagCheck = re .search ('<speed>(.*?)<\/speed>' , receive )
154
116
try :
155
- if ( imageTagCheck ) :
117
+ if imageTagCheck :
156
118
imageData = imageTagCheck .group (1 )
157
119
im_bytes = base64 .b64decode (imageData )
158
- im_arr = np .frombuffer (im_bytes , dtype = np .uint8 ) # im_arr is one-dim Numpy array
120
+ im_arr = np .frombuffer (im_bytes , dtype = np .uint8 )
159
121
imageOpenCV = cv2 .imdecode (im_arr , flags = cv2 .IMREAD_COLOR )
160
122
self .image = imageOpenCV
161
-
162
- if (sensorTagCheck ):
123
+ if sensorTagCheck :
163
124
sensorData = sensorTagCheck .group (1 )
164
125
sensor_arr = re .findall ("\d+" , sensorData )
165
- sensor_int_arr = list (map (int , sensor_arr ))
126
+ sensor_int_arr = list (map (int , sensor_arr ))
166
127
self .sensors = sensor_int_arr
167
128
else :
168
- self .sensors = [1500 ,1500 ,1500 ]
169
-
170
- if (speedTagCheck ):
129
+ self .sensors = [1500 , 1500 , 1500 ]
130
+ if speedTagCheck :
171
131
current_sp = speedTagCheck .group (1 )
172
132
self .current_speed = int (current_sp )
173
133
else :
174
134
self .current_speed = 0
175
- except :
176
- print ("Failed to receive data" )
177
-
135
+ except Exception as e :
136
+ print (f"Failed to receive data: { e } " )
178
137
179
138
def getImage (self ):
180
139
'''
@@ -185,36 +144,59 @@ def getImage(self):
185
144
def getSensors (self ):
186
145
'''
187
146
Returns the sensor data
188
- A List:
189
- [Left Sensor: int, Middle Sensor: int, Right Sensor: int]
190
147
'''
191
148
return self .sensors
192
-
149
+
193
150
def getSpeed (self ):
194
151
'''
195
152
Returns the speed of the car
196
153
'''
197
154
return self .current_speed
198
-
199
- def updateData (self ):
155
+
156
+ def updateData (self ) -> None :
200
157
'''
201
158
Updating the request data array and data string
202
159
'''
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 ] )
205
-
206
- def stop (self ):
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 :
207
164
'''
208
- Stoping the car and closing the socket
165
+ Stopping the car and closing the socket
209
166
'''
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
-
216
- def __del__ (self ):
217
- self .stop ()
218
-
219
-
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
220
179
180
+ Returns
181
+ -------
182
+ bool: True if the car is initialized and ready for operation
183
+ '''
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
+
195
+ def __del__ (self ):
196
+ try :
197
+ self .stop ()
198
+ except Exception :
199
+ pass
200
+
201
+
202
+
0 commit comments