3.4.1. Lập trình PID cho động cơ
Động cơ ban đầu được lập trình điều khiển qua mạch BTS với thuật toán đơn giản như sau: Serial.begin(9600); pinMode(motorA1, OUTPUT); pinMode(motorA2, OUTPUT); pinMode(motorB1, OUTPUT); pinMode(motorB2, OUTPUT);
pinMode(9,OUTPUT); //toc do banh phai pinMode(11,OUTPUT); //toc do banh trai
digitalWrite(motorA1, 1); digitalWrite(motorA2, 0); digitalWrite(motorB1, 1); digitalWrite(motorB2, 0); analogWrite(9,vSpeed);
analogWrite(11,vSpeed-them); digitalWrite(2,HIGH);
Nguyên lý của thuật toán bao gồm việc đóng mở các chân transistor để điều khiển động cơ, nhược điểm của thuật toán này sẽ làm động cơ chạy không đồng tốc độ với nhau, dẫn đến xe sẽ chạy lệch so với đường thẳng, nhược điểm sẽ ảnh hưởng rất nhiều tới độ chính xác của xe nếu cho xe chạy với đường dài, khi thực nghiệm ở sa hình rộng hơn và phức tạp hơn. Vì vậy nhóm em đã tạo thêm một thuật toán pid số dựa trên cơ sở có sẵn.
PID được tính như sau:
Tốc độ được thiết lập là: 995 vòng Thời gian lấy mẫu là T: 0,01 giây
Biến Error = tốc độ đặt – tốc độ, tốc độ được tính theo số xung của động cơ x = 2*T*Kp + Ki*T*T + 2*Kd
y = T*T*Ki – 4xKd - 2*T*Kp z = 2*Kd
55 Thuật toán được tham khảo từ Ths.Nguyễn Văn Đông Hải khoa Điện - Điện tử trường Đại học Sư Phạm Kỹ Thuật Tp.HCM.
Vì động cơ dẫn động thông qua hộp số bao gồm 4 bánh răng và tín hiệu encoder được dẫn động từ một bánh răng được thiết kế đi kèm nên việc tính toán chỉ số Kp Ki Kd trên lý thuyết là rất khó khăn vì sai số từ động cơ và bánh răng dẫn động module PID là rất lớn kèm theo khi xe di chuyển với các điều kiện có tải hoặc không tải, vì vậy nên chúng em quyết định cho xe chạy không tải và cho kết nối với một mạch đo điện áp từ động cơ, sau đó tiến hành quan sát mức thay đổi điện áp của động cơ chúng em tiến hành chọn lọc ra chỉ số phù hợp và ổn định nhất. Sau đó tiến hành cho xe chạy có tải và chạy trực tiếp trên mặt đường nhiều lần và tiến hành đo đạc, quan sát xe khi chạy, độ lệch của xe so với điểm xuất phát ban đầu, và chọn ra các chỉ số phù hợp nhất, bảng thống kê các lần chạy thử sẽ được liệt kê ở mục kết luận và đánh giá.
.
Hình 3.35. Mạch đo điện áp từ động cơ
56 - Phương pháp dò chỉ số Kp Ki Kd
Hình 3.37. Mô phỏng 2D bánh răng dẫn động encoder
Hình 3.38. Bánh răng hoàn chỉnh được lắp đặt trên xe
57
3.4.2. Cài đặt Anaconda3 và NvidiaCuda
Cài đặt Anaconda3: Yêu cầu phần cứng và phần mềm:
- Hệ điều hành: Win 7, Win 8/8.1, Win 10, Red Hat Enterprise Linux/CentOS 6.7, 7.3, 7.4, and 7.5, and Ubuntu 12.04+.
- Ram tối thiểu 4GB
- Ổ cứng trống tối thiểu 3GB để tải và cài đặt Tiến hành cài đặt Anaconda3 theo các bước:
59
60 Anaconda3 là chương trình tạo ra các môi trường để chạy thuật toán, ta khới tạo môi trường Anaconda với ngôn ngữ Python với câu lệnh như sau:
conda create -n name anaconda python=3.6.8 *name là tên môi trường đặt
Cách mở môi trường đã cài theo câu lệnh:
Activate name
Trong đó name là tên môi trường ta đã đặt lúc khởi tạo Câu lệnh tải và cài đặt thư viện như sau
Conda install numpy==1.1.2
Numpy là tên thư viện 1.1.2 là phiên bản của thư viện
Câu lệnh kiểm tra các thư viện đã cài trên môi trường như sau
Conda list
3.4.3. Sửa đổi thuật toán training
Để việc training thuật toán của xe có hiệu suất tốt nhất và ổn định, nhóm em đã khởi tạo 2 môi trường khác nhau, một môi trường traning và một môi trường chạy thuật toán, nguyên nhân xuất phát từ việc GPU của các máy có đời và phiên bản khác nhau nên việc thích ứng các phiên bản của thư viện cũng khác nhau.
61
62
63 Thuật toán training được chỉnh sửa bao gồm:
Số lượng thư mục ảnh đầu vào tăng từ 3 ở thuật toán cũ y1 = len(glob.glob(os.path.join("D:\\thuthapanh\\thang1",'*jpg'))) y2 = len(glob.glob(os.path.join("D:\\thuthapanh\\cong1",'*jpg'))) y3 = len(glob.glob(os.path.join("D:\\thuthapanh\\thang2",'*jpg')))
được gia tăng lên 8
y1 = len(glob.glob(os.path.join("D:\\thuthapanh\\t1",'*jpg'))) y2 = len(glob.glob(os.path.join("D:\\thuthapanh\\t2",'*jpg'))) y3 = len(glob.glob(os.path.join("D:\\thuthapanh\\t3",'*jpg'))) y4 = len(glob.glob(os.path.join("D:\\thuthapanh\\t4",'*jpg'))) y5 = len(glob.glob(os.path.join("D:\\thuthapanh\\c1",'*jpg'))) y6 = len(glob.glob(os.path.join("D:\\thuthapanh\\c2",'*jpg'))) y7 = len(glob.glob(os.path.join("D:\\thuthapanh\\c3",'*jpg'))) y8 = len(glob.glob(os.path.join("D:\\thuthapanh\\c4",'*jpg')))
Số lớp quét tăng từ 4 lên 8 number_class = 4 => 8
Số ảnh 1 lần quét giảm từ 500 xuống 300 batchsize = 500 => 300 # số hình 1 lần quét
Ma trận gán cho số lượng hình được tăng từ 3 lên 8 y = np.asarray([0]*y1 + [1]*y2 + [2]*y3 )
tăng lên thành
y = np.asarray([0]*y1+[1]*y2+[2]*y3+[3]*y4+[4]*y5+[5]*y6+[6]*y7+7*[y8])
Việc thay đổi thuật toán này là vì mở rộng phạm vi hoạt động của xe nên việc gia tăng số lượng ảnh đầu vào là điều cần thiết
Đồng thời việc gia tăng số lượng ảnh thì đi kèm theo đó là số lớp quét và ma trận gán cho các mục ảnh cũng được gia tăng theo phù hợp
Tuy nhiên vì số lượng ảnh train được giảm đi so với bản cũ trung bình từ 4000 ~ 5000 còn 800 ~ 1000 ảnh nên số ảnh quét cho 1 lần được giảm xuống còn 300 để tăng độ chính xác, ổn định cho file sau khi train
64
Cài đặt CUDA 10:
Vì thuật toán vẫn sử dụng tensorflow nên việc cần thiết là phải cài đúng CUDA và lib cuDNN, CUDA dùng để tính toán song song còn cuDNN là thư viện hỗ trợ Deeplearning gọi lệnh CUDA, vậy nên khi cài đặt cần cài CUDA trước sau đó tiến hành cài cuDNN sau.
Kiểm tra GPU có thích hợp cài CUDA hay không phải dùng GPUz, CUDA là công nghệ của Nvidia nên các máy tính có card đồ họa AMD/ATI sẽ không chạy được CUDA.
Tiến hành cài đặt CUDA 10.1:
Download CUDA 10 trên web của Nvidia, chọn phiên bản phù hợp với window
Sau khi tải xong tiến hành cài đặt bình thường, sau đó khởi động lại máy tính.
Cài thư viện cuDNN
Đầu tiên đăng ký tài khoản developer, sau khi đăng kí xong tải cuDNN Chọn cuDNN library for windows 10, không nện chọn bản mới hơn 7.6.5
65 Sau khi tải xong, giải nén và copy tất cả các file vào thư mục theo đường dẫn
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1. Sau đó khởi động máy vậy là xong.
66
3.4.4. Xây dựng lưu đồ giải thuật 3.4.4.1. Lưu đồ nhận diện lane 3.4.4.1. Lưu đồ nhận diện lane
Khi đã có module được traning, ta sẽ dùng model này để nhận diện và điều khiển. Tùy thuộc vào phạm vi hoạt động của xe ta có thể xây dựng các class tương ứng để xe có thể hoạt động một cách chính xác nhất.
3.4.4.2. Lưu đồ nhận diện biển báo Stop
Việc đầu tiên chúng ta cần phải khởi tạo các thư viện của Opencv để hỗ trợ cho việc thu thập dữ liệu. Tương tự phần trên sau khi lấy được ảnh đầu vào ta tiến hành chuẩn hóa theo lưu đồ giải thuật trên.
Đọc ảnh đầu vào và tiến hành xử lý giống với phần thu thập dữ liệu để phù hợp với model nhiện diện biển báo Stop đã được huấn luyện. Đưa ảnh vào nhận diện, khi nhận diện được biển báo Stop thì thuật toán sẽ vẽ một hình chữ nhật bao xung quanh biển báo để thông báo là đã xác định được vât.Sau đó diện tích của biển báo sẽ được tính toán theo đơn vị là pixel,khi diện tích biển báo lớn hơn giá trị cho phép thì tính hiệu sẽ được truyền xuống
67 để dừng xe,còn ngược lại khi diện tích biển báo nhỏ hơn chứng tỏ xe chưa đến vị trí cần dừng lại thì xe vẫn xe đi thẳng.
Hình 3.56. Nhận diện biến báo Stop ở trong xưởng
68
3.4.4.3 Cải tiến thuật toán training cho ảnh màu và thiết kế bộ CNN mới
Thuật toán training cũ chỉ train được các hình ảnh trắng đen, điều này làm khả năng tiếp cận các hình ảnh màu hoặc ảnh thực tế bị gặp khó khăn, vì vậy việc phát triển một thuật toán traning mới và kiểm soát tốt quá trình train bằng cách tạo các biểu đồ tương ứng, đồng thời tạo dựng kiến trúc CNN mới tốt hơn
Tạo kiến trúc CNN mới
Để tạo kiến trúc CNN mới tốt hơn kiến trúc CNN cũ ta cần tạo dựng CNN cũ và phân tích rõ thành phần cấu tạo bên trong kiến trúc CNN cũ.
model = Sequential()
model.add(Conv2D(8, kernel_size=(7, 7), # 8 chanel . 7*7 kích thước c ửa sổ để quét các object, tùy vào kích thước object để chọn kích thước cửa sổ
activation='relu', # bỏ giá trị âm
strides=(2, 2), # độ trượt input_shape= (400,200,3), # kích thước ảnh 60*200*3(RGB) padding='valid',)) model.add(Conv2D(16, kernel_size=(5, 5), activation='relu', strides=(2, 2), padding='valid',)) model.add(Conv2D(32, kernel_size=(5, 5), activation='relu', strides=(2, 2), padding='valid',)) model.add(Conv2D(64, kernel_size=(3, 3), activation='relu', strides=(1, 1), padding='valid',)) model.add(Conv2D(64, kernel_size=(3, 3), activation='relu', strides=(1, 1), padding='valid',))
model.add(Dense(number_class, activation='softmax'))
model.summary()
- Phân tích: số lượng tích chập
Lần tích chập đầu tiên là tích chập với filter lớn số lượng filter nhỏ mục đích là để lấy đặc điểm ảnh 1 cách cục bộ và giảm thiểu thời gian traning vì lượng ảnh cần training quá lớn 4000 đến 6000 ảnh cho một cung đường
Các lần tích chập lần sau thì số lượng filter và kích thước filter được giảm dần, từ ma trận được tích chập bởi các lần tích chập trước.
69 Hàm kích hoạt là relu và dùng solfmax để chuyển đổi ma trận thành các vecto xác suất.
Bảng 3.3. Phân tích số lượng tích chập
Số lần Số lượng ma trận
filter Kích thước filter Kích thước ma trận tổng hợp
1 8 7x7 2x2
2 16 5x5 2x2
3 32 5x5 2x2
4 64 3x3 1x1
5 64 3x3 1x1
Tạo dựng kiến trúc CNN mới: model = Sequential()
model.add(Conv2D(filters=32, kernel_size=(5,5), activation='relu', input_s
hape=X_train.shape[1:]))
model.add(Conv2D(filters=32, kernel_size=(5,5), activation='relu')) model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Dropout(rate=0.25))
model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu')) model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu')) model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Dropout(rate=0.25)) model.add(Flatten())
model.add(Dense(256, activation='relu')) model.add(Dropout(rate=0.5))
model.add(Dense(43, activation='softmax'))
Điều khác biệt khi tạo dựng kiến trúc mới là sử dụng bộ filter nhỏ hơn so với bộ filter của kiến trúc CNN cũ đồng thời gia tăng số lượng filter lên gấp 4 lần. điều này giúp việc máy học được các đặc tính của ảnh một cách rõ ràng và chi tiết hơn đồng thời giảm số lần dùng ma trận tổng hợp nhằm giảm sự chuyển dịch giá trị đặc tính của ma trận.
70 Để kiểm soát và quan sát quá trình train, thì cách đơn giản và hiệu quả là chèn biểu đồ các giá trị accuracy và loss và thuật toán kiểm soát giá trị bằng biểu đồ được thiết kế như sau:
data = np.array(data) labels = np.array(labels)
print(data.shape, labels.shape)
#Splitting training and testing dataset
71 X_train, X_test, y_train, y_test = train_test_split(data, labels, test_siz e=0.2, random_state=42)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape) #Converting the labels into one hot encoding
y_train = to_categorical(y_train, 43) y_test = to_categorical(y_test, 43)
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=[
'accuracy']) epochs = 15
history = model.fit(X_train, y_train, batch_size=32, epochs=epochs, valida
tion_data=(X_test, y_test))
model.save("D:\\kethuc\\filetrain\\my_model.h5") #plotting graphs for accuracy
plt.figure(0)
plt.plot(history.history['accuracy'], label='training accuracy') plt.plot(history.history['val_accuracy'], label='val accuracy') plt.title('Accuracy') plt.xlabel('epochs') plt.ylabel('accuracy') plt.legend() plt.show() plt.figure(1)
plt.plot(history.history['loss'], label='training loss') plt.plot(history.history['val_loss'], label='val loss') plt.title('Loss')
plt.xlabel('epochs') plt.ylabel('loss') plt.legend() plt.show()
Ở biểu đồ cho thấy độ chính xác của thuật toán là 98% giá trị bị mất là 5% một kết quả rất cao so với một số lần thực nghiệm khác chỉ có mức ở 90% tuy nhiên để đảm bảo giá trị này là giá trị thực bằng cách dùng một mô hình test được thiết lập sẵn, thuật toán khá đơn giản để kiểm tra.
#testing accuracy on test dataset
from sklearn.metrics import accuracy_score y_test = pd.read_csv('Test.csv')
labels = y_test["ClassId"].values imgs = y_test["Path"].values data=[]
72
for img in imgs:
image = Image.open(img) image = image.resize((30,30)) data.append(np.array(image)) X_test=np.array(data)
pred = model.predict_classes(X_test) #Accuracy with the test data
from sklearn.metrics import accuracy_score
print(accuracy_score(labels, pred))
Sau khi kiểm tra trên mô hình test thì ta tiến hành sử dụng file train thực nghiệm để kiểm tra độ chính xác và hiệu quả ở môi trường tự nhiên.
73
CHƯƠNG 4: THỰC NGHIỆM VÀ ĐÁNH GIÁ
4.1. KẾT QUẢ
Sau 10 tuần thiết kế và thi công, nhóm đã hoàn thành mô hình xe tự hành dựa trên mô hình và cơ sở của nhóm cũ.
Về phần khung xe nhóm đã thay đổi 4 bánh xe từ bánh nhựa thành bánh cao su, hệ thống lái với 2 bánh răng thành bánh răng trục vít, vị trí lắp đặt camera vẫn không thay đổi, thiết kế bộ pid cho khối động cơ phía sau, lắp đặt hệ thống mạch điện, lắp đặt cầu chì trên xe, tháo dỡ một số bộ phận không cần thiết.
Hình 4.2. Mô hình xe sau khi thi công
74 Trong quá trình vận hành mặc dù hệ thống được lắp đặt PID nhưng vẫn chưa hoàn toàn làm xe hoạt động thẳng tuyệt đối. Thước lái được cải tạo tuy vẫn giữ được cho xe
Hình 4.5. Khi xe nhận diện thẳng
Hình 4.3. Mạch điện mới
75 chạy ổn định nhưng vào góc đánh lái vẫn chưa được tốt và chính xác.
Hình 4.6. Khi xe đi thẳng
76
4.2. THỰC NGHIỆM
4.2.1. Thực nghiệm xe nhận diện biển báo và lane
Nhóm chúng em thực nghiệm trong môi trường thực tế, với môi trường tự nhiên thì việc xe bị ảnh hưởng bởi ánh sáng ngoài trời là điều không thể tránh khỏi và rất khó để khắc phục. Vậy nên quá trình thực nghiệm nhóm chúng em sẽ dựa theo phương pháp của nhóm cũ tiến hành thực nghiệm trong nhiều ngày theo những điểm thời gian và cường độ sáng khác nhau, từ đó xây dựng bảng số liệu các lần cho xe chạy thực nghiệm.
Hình 4.8. Khi xe vào cua
77 - Nhận xét:
Qua quá trình thực nghiệm nhóm chúng em nhận thấy rằng việc gia cố thêm kết cấu của xe trở nên chắc chắn hơn rất quan trọng, việc lựa chọn tốc độ phù hợp cho xe, lựa chọn số ảnh mỗi giây trên khung hình, góc đánh lái ở mỗi đoạn cua là điều cần thiết để xe hoạt chính xác yêu cầu được đề ra.
Điều tiếp theo là về độ nhiễu vì ánh sáng và góc đổ bóng của tán cây thậm chí là bóng của chính chiếc xe là vẫn còn ảnh hưởng rất nhiều đến độ chính xác của xe.
4.2.2. Thực nghiệm PID ở khối động cơ của xe
Như trình bày ở bên trên, chúng em sẽ không để xe chạy Pid không tải và quan sát trên biểu đồ như các ví dụ trên lớp học, mà nhóm chúng em sẽ quan sát ra các bộ số Kp, Ki, Kd và tốc độ được cài đặt sẵn tiềm năng, sau đó tiến hành cho xe chạy thử (có tải) ở môi trường thực tế (khuôn viên khoa cơ khí động lực) từ đó đưa ra bảng thống kế và lựa chọn ra chỉ số Kp Ki Kd phù hợp nhất, ngoài ra để đảm bảo xe chạy đúng với yêu cầu nhóm chúng em còn lắp thêm 1 module đo đạc điện áp đầu ra của động cơ.
78 - Nhận xét: Tuy được thiết kế bộ PID cho động cơ trên xe, tuy nhiên khối động cơ vẫn không hoạt động chính xác như mong muốn mặc dù vẫn đáp ứng được các yêu cầu cơ bản đã đề ra.
4.3. THỐNG KÊ
4.3.1. Thống kê khi cho xe nhận diện biến báo và lane 4.3.1.1. Lập bảng thống kê 4.3.1.1. Lập bảng thống kê
Ở bảng thống kê của nhóm Nguyễn Trung Trực và Lê Mình Hùng được thực hiện vào tháng 5 và 6 2020 tức là vào mùa hè là thời điểm nắng lớn nhất trong năm, đồng nghĩa là ánh sáng có được nhiều nhất điều này là điều kiện gia tăng độ chính xác khi nhận diện lane và biển báo vì cường độ ánh sáng ảnh hưởng rất quan trọng đến quá trình nhận diện của thuật toán, bảng thống kê đó được mô tả ở bên dưới.
Bảng 4.8. Bảng thống kê thực nghiệm Giờ Số lần 7 AM 8 AM 9 AM 10 AM 11 AM 12 AM 1 PM 2 PM 3 PM 4 PM 5 PM 6 PM 1 O O O X O O O O O O O X 2 O O O O O O X O X X O X 3 X O O O O O X O O X O X 4 O O O O O O O O X O O O 5 O X X O O O O X X O X O 6 X O O X X O O O O X X X 7 O O O O X O O O O X O X