Hạng B2
4/8/14
264
291
63
Hà nội
tranhchuthap.vn
Hack hệ thống này có mục đích gì?
Đơn giản nhất là dùng khiển vô lăng để điều khiển Raspberry Pi, điện thoại, máy tính bảng.....
ngoài ra còn nhiều ứng dụng khác...... Liên quan chủ đề này mời các bác tham khảo thêm bài viết hướng dẫn lắp hệ thống xem phim, nghe nhạc tất cả các định dạng trên ô tô tại đây

Mục lục
Mở đầu. 4
1. Kết nối phần cứng [3]10
1.1. Các kiến thức cơ bản. 10
1.2. Từng bước tiến hành công tác kết nối12
1.2.1. Bước 1: Xác định giao thức nào được xe sử dụng. 12
1.2.2. Bước 2: Kết nối vật lý. 13
1.2.3. Bước 3: Các kiểm tra cơ bản đầu tiên. 16
1.2.4. Bước 4: Bắt đầu hack. 19
2. Xác định mã lệnh các nút điều khiển của vô lăng trên Can-Bus [4]19
2.1. Khái quát chung. 19
2.2. Các nhiệm vụ cần thực hiện. 20
2.2.1. Nhiệm vụ thứ 1: Thu thập số liệu cơ bản (baseline)20
2.2.2. Nhiệm vụ thứ 2: Lưu dữ liệu từ sự kiện/tương tác. 21
2.2.3. Nhiệm vụ thứ 3: Phân tích dữ liệu. 21
2.2.4. Nhiệm vụ 4: Kiểm tra giả thuyết của bạn. 25
3. Giao tiếp giữa ô tô và Máy Tính thông qua OBDII bằng Python [5]29
3.1. Các thứ cần thiết:29
3.2. Kết nối và tương tác. 29
4. Kết nối OBD-II Bluetooh đến Raspbery Pi30
5. Đọc dữ liệu từ cổng USB Bluetooth trên RPI35
5.1. Cài đặt gói mô đun python-serials đọc dữ liệu cổng serial35
5.2. Mã lệnh mẫu file serialtest.py để thực hiện các câu lệnh đọc và xử lý dữ liệu. 36
5.3. Chạy file lập trình python serialtest.py bên trên. 37
6. Điều khiển XBMC trên Raspbery Pi bằng JSON-RPC API sử dụng Python. 37
6.1. Điều khiển XBMC qua ISON-RPC bằng Python để Pause/Play VIDEO [16]37
6.2. Điều khiển XBMC qua ISON-RPC bằng Python để Pause VIDEO [17]38
6.3. Điều khiển vô lăng cho XBMC. 40
7. Hiển thị các thông số chuẩn đoán xe lên màn hình thông qua Raspberry Pi [6]44
7.1. Phần cứng cần thiết45
7.2. Cài đặt phần mềm.. 45
7.3. Cài đặt xe. 46
7.4. Data Logging. 46
8 Tài liệu tham khảo. 47

[URL='http://anhtay.vn']Hàng nhập khẩu Anh, Nga, Pháp, Đức, Thái Lan[/URL]
[URL='http://anhtay.vn/dung-cu-bao-quan.html']Dụng cụ bảo quản[/URL]
[URL='http://anhtay.vn/dung-cu-nha-bep.html']Dụng cụ nhà bếp[/URL]
[URL='http://anhtay.vn/me-va-be.html']Mẹ và bé[/URL]
[URL='http://anhtay.vn/suc-khoe-sac-dep.html']Sức khỏe, sắc đẹp[/URL]
[URL='http://anhtay.vn/thoi-trang.html']Thời trang[/URL]
[URL='http://anhtay.vn/thuc-pham-do-uong.html']Thực phẩm, đồ uống[/URL]
[URL='http://anhtay.vn/do-dung-sinh-hoat.html']Đồ dùng sinh hoạt[/URL]
[URL='http://anhtay.vn/do-dien-gia-dung.html']Đồ điện gia dụng[/URL]
Mở đầu

CAN là một giao thức truyền thông nối tiếp (serial) được phát triển lần đầu tiên bởi Công ty Robert Bosch vào năm 1983 và được công nhận chính thức vào năm 1986 bởi Hội các Kỹ sư Ô tô (SAE). Năm 1991, Bosch ban hành phiên bản CAN 2.0 và sau đó 2 năm trở thành chuẩn ISO 11898. Hiện nay, hầu như tất cả các xe ô tô đều sử dụng chuẩn CAN để truyền thông giữa các bộ điều khiển. Có thể tổng hợp một số ưu điểm khi một hệ thống sử dụng CAN như sau [1,2]:
Gọn nhẹ và kinh tế hơn so với các chuẩn thông dụng. CAN là chuẩn truyền 2 dây, không đòi hỏi phải có xung đồng bộ để truyền nhận thông tin.
Phù hợp với các ứng dụng yêu cầu thời gian thực. Mạng CAN có thệ thống phân xử dựa trên ID của bản tin giúp cho việc truyền nhận tức thời của các bản tin có mức ưu tiên cao.
Tăng mức độ an toàn của hệ thống. Việc một module trong mạng CAN bị lỗi không gây ra ảnh hưởng tới các module còn lại, trừ khi hai module có liên hệ trực tiếp đến nhau và không thể hoạt động nếu thiếu một module còn lại. Đồng thời, việc thêm/bớt module trong hệ thống có thể được thực hiện ngay khi hệ thống đang làm việc mà không gặp vấn đề gì cho hệ thống điện.
Đặc trưng của CAN là phương pháp định địa chỉ và giao tiếp hướng đối tượng, trong khi hầu hết các hệ thống truyền thông khác đều giao tiếp dựa vào địa chỉ các trạm. Mỗi thông tin trao đổi trong mạng được coi như một đối tượng và được gán một mã ID. Thông tin được gửi lên bus kiểu truyền thông báo với các độ dài khác nhau. Nội dung mỗi thông báo được các trạm phân biệt qua ID được cấp. Mã ID không nói lên địa chỉ đích của thông báo mà chỉ biểu diễn ý nghĩa của dữ liệu thông báo. Vì thế, mỗi trạm trên mạng có thể tự quyết định tiếp nhận và xử lý thông báo hay không tiếp nhận thông báo qua phương thức lọc thông báo, nhờ vậy nhiều trạm có thể nhận đồng thời nhiều thông báo và có các phản ứng khác nhau.
Phiên bản điện tử của ebook này có thể tải về tại đây:
http://tranhchuthap.vn/bai-viet/canbus/Hack-CAN-BUS-Dieu-khien-volang.pdf
Luồng thảo luận trên diễn đàn về chủ đề này xem tại đây:
http://www.otofun.net/threads/860691-huong-dan-hack-he-thong-can-bus-tren-xe-toan-tap
Hoặc tại đây:
https://www.otosaigon.com/threads/hack-he-thong-canbus-tren-o-to.8665190/

can1.gif

Hình 1 - Ghép nối trong một mạng CAN (mỗi một node là một bộ phận của xe như DVD, động cơ, cửa sổ trời, xi nhan .v.v..)

CAN_Node.png

Hình 2 – Cấu trúc của một node (thành viên) trong mạng CAN

CAN-Bus-frame_in_base_format_without_stuffbits.svg.png

Hình 3 – Cấu trúc một bản tin CAN

Mạng CAN sử dụng 2 dây để truyền dữ liệu gồm CAN-H (hoặc CAN-HI) và CAN-L (hoặc CAN-LO). Ở đầu và cuối hệ thống mạng, các điện trở được nối để tránh hiện tượng phản xạ tín hiệu trên đường truyền. Trong xe ô tô, các ECU được nối chung vào hệ thống mạng CAN, mỗi một ECU phải bao gồm một bộ thu nhận tín hiệu và một bộ điều khiển CAN như trong Hình 2 thể hiện. Muốn trao đổi thành công dữ liệu trên mạng CAN, các phần tử kết nối với mạng cần phải được cài đặt tốc độ giống nhau. Tốc độ cao nhất mà mạng CAN đạt được là 1Mbit/s, tuy nhiên, để đảm bảo độ ổn định, trong xe ô tô nói chung thường sử dụng tốc độ 500kbit/s.
Bản tin CAN có thể có 2 dạng (còn gọi là 2 dạng khung bản tin) gồm: dạng khung chuẩn với 11 bit dành cho ID và dạng khung mở rộng với 29 bit ID (gồm 11 bit của khung chuẩn và thêm 18 bit mở rộng). Các thành phần còn lại của 2 dạng khung là giống nhau. Về cơ bản, cấu trúc của một bản tin CAN như thể hiện trong Hình 3 gồm các thành phần sau:
Bảng 1 – Cấu trúc một bản tin CAN tiêu chuẩn
[xtable]
{tbody}
{tr}
{td}
Tên trường{/td}

{td}
Độ dài (bits){/td}

{td}
Mục đích{/td}
{/tr}
{tr}
{td}
Start-of-frame{/td}

{td}
1{/td}

{td}
Denotes the start of frame transmission{/td}
{/tr}
{tr}
{td}
Identifier (green){/td}

{td}
11{/td}

{td}
A (unique) identifier which also represents the message priority{/td}
{/tr}
{tr}
{td}
Remote transmission request (RTR){/td}

{td}
1{/td}

{td}
Must be dominant (0) for data frames and recessive (1) for remote request frames (see Remote Frame, below){/td}
{/tr}
{tr}
{td}
Identifier extension bit (IDE){/td}

{td}
1{/td}

{td}
Must be dominant (0) for base frame format with 11-bit identifiers{/td}
{/tr}
{tr}
{td}
Reserved bit (r0){/td}

{td}
1{/td}

{td}
Reserved bit. Must be dominant (0), but accepted as either dominant or recessive.{/td}
{/tr}
{tr}
{td}
Data length code (DLC) (yellow){/td}

{td}
4{/td}

{td}
Number of bytes of data (0–8 bytes)[sup][a][/sup]{/td}
{/tr}
{tr}
{td}
Data field (red){/td}

{td}
0–64 (0-8 bytes){/td}

{td}
Data to be transmitted (length in bytes dictated by DLC field){/td}
{/tr}
{tr}
{td}
CRC{/td}

{td}
15{/td}

{td}
Cyclic redundancy check{/td}
{/tr}
{tr}
{td}
CRC delimiter{/td}

{td}
1{/td}

{td}
Must be recessive (1){/td}
{/tr}
{tr}
{td}
ACK slot{/td}

{td}
1{/td}

{td}
Transmitter sends recessive (1) and any receiver can assert a dominant (0){/td}
{/tr}
{tr}
{td}
ACK delimiter{/td}

{td}
1{/td}

{td}
Must be recessive (1){/td}
{/tr}
{tr}
{td}
End-of-frame (EOF){/td}

{td}
7{/td}

{td}
Must be recessive (1){/td}
{/tr}
{/tbody}
[/xtable]

Bảng 2 – Cấu trúc một bản tin CAN mở rộng
[xtable]
{thead}
{tr}
{td}
Tên trường{/td}

{td}
Độ dài (bits){/td}

{td}
Mục đích{/td}
{/tr}
{/thead}
{tbody}
{tr}
{td}
Start-of-frame{/td}

{td}
1{/td}

{td}
Denotes the start of frame transmission{/td}
{/tr}
{tr}
{td}
Identifier A{/td}

{td}
11{/td}

{td}
First part of the (unique) identifier which also represents the message priority{/td}
{/tr}
{tr}
{td}
Substitute remote request (SRR){/td}

{td}
1{/td}

{td}
Must be recessive (1){/td}
{/tr}
{tr}
{td}
Identifier extension bit (IDE){/td}

{td}
1{/td}

{td}
Must be recessive (1) for extended frame format with 29-bit identifiers{/td}
{/tr}
{tr}
{td}
Identifier B{/td}

{td}
18{/td}

{td}
Second part of the (unique) identifier which also represents the message priority{/td}
{/tr}
{tr}
{td}
Remote transmission request (RTR){/td}

{td}
1{/td}

{td}
Must be dominant (0) for data frames and recessive (1) for remote request frames (see Remote Frame, below){/td}
{/tr}
{tr}
{td}
Reserved bits (r1, r0){/td}

{td}
2{/td}

{td}
Reserved bits which must be set dominant (0), but accepted as either dominant or recessive{/td}
{/tr}
{tr}
{td}
Data length code (DLC){/td}

{td}
4{/td}

{td}
Number of bytes of data (0–8 bytes)[sup][a][/sup]{/td}
{/tr}
{tr}
{td}
Data field{/td}

{td}
0–64 (0-8 bytes){/td}

{td}
Data to be transmitted (length dictated by DLC field){/td}
{/tr}
{tr}
{td}
CRC{/td}

{td}
15{/td}

{td}
Cyclic redundancy check{/td}
{/tr}
{tr}
{td}
CRC delimiter{/td}

{td}
1{/td}

{td}
Must be recessive (1){/td}
{/tr}
{tr}
{td}
ACK slot{/td}

{td}
1{/td}

{td}
Transmitter sends recessive (1) and any receiver can assert a dominant (0){/td}
{/tr}
{tr}
{td}
ACK delimiter{/td}

{td}
1{/td}

{td}
Must be recessive (1){/td}
{/tr}
{tr}
{td}
End-of-frame (EOF){/td}

{td}
7{/td}

{td}
Must be recessive (1){/td}
{/tr}
{/tbody}
[/xtable]

Ghi chú: Về mặt vật lý thì với 4-bit DLC có thể cho các giá trị byte từ 0-16 nhưng trong thực tế giá trị này chỉ sử dụng đến 8.
 Khởi đầu khung là một bit trội và đánh dấu khởi đầu của một bản tin. Tất cả các thành phần kết nối với mạng CAN sẽ phải đồng bộ hóa dựa vào bit khởi đầu này.
 Các bit ID của bản tin, còn được gọi là các bit phân xử. Các bit ID ngoài việc được sử dụng để xác định đối tượng của bản tin, nó còn được sử dụng để xác định mức ưu tiên, quyết định quyền truy nhập bus khi có nhiều thông tin được gửi đi đồng thời. Vùng bit phân xử có chiều dài 12 bit với dạng khung chuẩn và 32 bit với dạng khung mở rộng, trong đó mã ID dài 11 hoặc 29 bit. Bit cuối cùng của ô phân xử là bit RTR (Remote Transmission Request), dùng để phân biệt giữa khung dữ liệu (bit trội) và khung yêu cầu dữ liệu (bit lặn).
 Vùng điều khiển dài 6 bit, trong đó 4 bit cuối mã hóa chiều dài dữ liệu.
 Vùng dữ liệu có chiều dài từ 0 đến 8 byte, trong đó mỗi byte được truyền đi theo thứ tự từ bit có trọng số cao nhất (MSB) đến bit có trọng số thấp nhất (LSB).
 Vùng kiểm soát lỗi CRC bao gồm 15 bit được thực hiện theo phương pháp CRC và 1 bit lặn phân cách. Dãy bit đầu vào để tính bao gồm bit khởi đầu khung, các bit phân xử, vùng điều khiển và vùng dữ liệu.
 Vùng xác nhậc ACK (Acknowlegment) gồm 2 bit để các thành phần trên mạng CAN thực hiện kiểm tra mã CRC.
 Kết thúc khung được đánh dấu bằng 7 bit lặn.
id-prioty.png

Hình 5 - Vùng ID được sử dụng để xác định mức ưu tiên
Trong quá trình hoạt động, nếu 2 thành phần cùng gửi bản tin lên mạng CAN tại cùng một thời điểm, bản tin nào có ID thấp hơn, bản tin đó có mức ưu tiên cao hơn và được quyền sử dụng mạng để gửi đi yêu cầu hoặc dữ liệu. Ví dụ như trong H.5, có 2 thiết bị cùng sử dụng mạng CAN tại cùng một thời điểm. Tuy nhiên, chỉ có thiết bị 1 có ID thấp hơn được sử dụng mạng còn thiết bị 2 phải tạm dừng (tại thời điểm số 3). Đây chính là ưu điểm của giao thức CAN so với các chuẩn truyền thông khác.



1. Kết nối phần cứng [3]

1.1. Các kiến thức cơ bản

Các xe hiện đại đều được tích hợp một mạng nội bộ mà nó cho phép truy cập đến hầu như mọi thành phần chính và phụ của xe - tất cả mọi thứ từ việc truyền tải đến các hệ thống giải trí và điều khiển.
Tại sao hack nó? bởi vì bạn có thể! có thể bạn muốn cài đặt một máy tính trên xe theo cách của riêng mình mà nó sẽ thay thế cho các hệ thống điều khiển hệ thống radio và điều hòa không khí. Hoặc bạn muốn làm một hệt thống mở cửa từ xa hay khởi động xe từ xa, hay sử dụng điều khiển vô lăng để điều khiển điện thoại, điều khiển máy tính bảng, điều khiển raspberry pi…. Tôi chắc rằng bạn có thể nghĩ về một cái gì đó.
Có vẻ như mọi người thường tiếp cận khái niệm này với một bo mạch khả trình Arduino / NetDuino / PIC / vv, cộng với một cái chắn hoặc một số mạch điện tùy chỉnh, và một chút mã nguồn tùy chỉnh. Tùy thuộc vào mục tiêu cuối cùng của bạn, một vi điều khiển có thể là phương pháp tốt nhất. Tuy nhiên, bài viết này là về việc bắt đầu một cách nhanh chóng và rẻ tiền bằng cách tận dụng một bộ điều hợp ELM327 dựa trên OBD-II công cụ quét tiêu chuẩn (giá thị trường khoảng ~ $25) và máy tính xách tay của bạn, máy tính bảng, điện thoại, Raspberry Pi, v.v.
P1070847-001.JPG

Hình 1.1 Phương pháp tiếp cận sử dụng các bo mạch phát triển với chip khả trình được mọi người thường nghĩ đến
Lưu ý: Ở đây tôi không nói về việc "lấy mã lỗi" hoặc xóa đèn báo lỗi động cơ kiểm tra, đó là những thứ công việc rất đơn giản hiện đã phổ biến với hàng loạt công cụ tràn lan mà bạn có thể tải về từ bất cứ đâu trên các chợ ứng dụng của Android hay IOS. Chúng ta muốn điều khiển và nhận các thông tin từ các bộ phận trên xe. Cơ bản về hệ thống mạng cục bộ trên xe:
Vào năm 1996 một đạo luật liên bang có hiệu lực đòi hỏi hầu hết các xe mới của người tiêu dùng ở Mỹ phải có tiêu chuẩn dựa trên On Board Diagnostics, gọi là OBD-2. Các quy định OBD được đưa ra bởi các EPA cho việc giám sát phát thải các thành phần liên quan, nhưng các hệ thống đã tiến hóa để có nhiều hơn nữa những khả năng.
Không chỉ là một công cụ: những điều tốt về OBD-II là nó định nghĩa một tập hạn chế các loại mạng mà một hãng sản xuất xe hơi có thể thực hiện đối với các chẩn đoán liên quan khí thải. Điều đó có nghĩa rằng các công cụ giao tiếp với các mạng này cũng có thể trở thành tiêu chuẩn và không tốn kém, gọi là công cụ quét. Chúng ra đời với phiên bản đầy đủ tính năng cùng phần mềm tích hợp / màn hiển thị / nút bấm, và các phiên bản dump mà phải được kết nối với một máy PC / Mac / máy tính bảng / điện thoại để có thể sử dụng được.
scantool.jpg

Hình 1.2 Các phiên bản của công cụ quét mã, phiên bản đầy đủ (trái) và phiên bản Dump (phải)
Những gì trong bài này là giải pháp để sử dụng một trong những công cụ quét rẻ tiền (USB dump, Bluetooth, hoặc các loại cổng nối tiếp – serials) để giao tiếp với một chiếc xe bởi cách mà vốn dĩ nó không được thiết kế để làm như vậy.
Một vài giải pháp rẻ tiền đã thành công gồm:
USB: Scantool ElmScan 5
Bluetooth: BAFX Sản phẩm ELM 327 công cụ quét Bluetooth OBD2

1.2. Từng bước tiến hành công tác kết nối

Các khó khăn: tiêu chuẩn OBD-II chỉ áp dụng đối với các phần BUS liên quan đến kiểm soát khí thải của một chiếc xe. Các hệ thống khác thường hoạt động trên một BUS khác hoàn toàn mà có thể sử dụng giao thức giống hoặc không giống như BUS chẩn đoán OBD-2. Thậm chí tồi tệ hơn, dữ liệu BUS không liên quan đến khí thải là độc quyền thông tin của nhà sản xuất và có thể thay đổi tùy theo từng phiên bản xe / mô hình / năm sản xuất.
Nhưng may thay là để đơn giản và tiết kiệm chi phí, hầu hết các nhà sản xuất chỉ thực hiện một kiểu mạng đơn trong phạm vi nhất định trong năm. Vì họ phải sử dụng một trong các giao thức OBD-II tiêu chuẩn cho BUS chẩn đoán, họ cũng có thể sử dụng cùng một giao thức (hay một sự thay đổi nhỏ) trên BUS khác. đây là lý do tại sao đôi khi chúng ta có thể sử dụng một công cụ quét để giao tiếp với một BUS không tiêu chuẩn OBD.
Ở mức độ cao, chúng ta cần phải:
Xác định giao thức sử dụng xe trên xe của chúng ta
Xây dựng các kết nối vật lý
Thử nghiệm kết nối và giao tiếp chúng với nhau
Bắt đầu hacking
Bây giờ tôi sẽ đi vào những chi tiết ...
1.2.1. Bước 1: Xác định giao thức nào được xe sử dụng

Xe thường có ít nhất 2 BUS, BUS chẩn đoán chính và một BUS nội thất hoặc tiện nghi. BUS chẩn đoán thường có quyền truy cập vào tất cả các thành phần hệ thống truyền lực cũng như các công cụ phát thải OBD-2. Những chiếc xe dễ hack nhất là những chiếc mà tất cả các BUS sử dụng cùng một giao thức và tất cả các thông điệp được chuyển cho nhau. Một số xe có thể có những BUS thứ cấp kết nối đến bus chẩn đoán thông qua một cổng mà chỉ có thể chuyển tiếp thông tin khi truy vấn với các lệnh chính xác. Một số khác thì sử dụng giao thức thức chung như nhau trên tất cả các BUS, nhưng tốc độ khác nhau.
Hãy mua một cuốn hướng dẫn sửa chữa (Factory Service Manual - FSM) cho chiếc xe của bạn nếu có thể. Nó gần như luôn cho bạn biết đầy đủ những thông tin cần thiết để kết nối. Bạn có thể nhận được FSM trên ebay nếu chiếc xe của bạn là một chiếc đã vài năm tuổi hoặc có thể kiếm được phiên bản pdf. Thư viện công nghệ trực tuyến như AllDataDIY có thể có các tài liệu hoàn chỉnh cho chiếc xe của bạn. Thư viện công công đôi khi có đăng ký cho những dịch vụ này. Và cuối cùng đừng bao giờ quên google với từ khóa liên quan đến chiếc xe của bạn như “phiên bản xe/model” và “OBDII protocol”, “OBD bus”, v.v.
Cuối cùng, chúng ta đang tìm kiếm các giao thức chính xác mà chiếc xe của chúng ta sử dụng và các thông tin về các thông điệp mà các thành phần trên xe gửi và nhận cho nhau. Nếu chúng ta không có thông tin này, chúng ta vẫn có thể thử kết nối đến bus chẩn đoán và hy vọng nó chuyển tiếp từ BUS mục tiêu của chúng ta.
OBD-II cho phép các giao thức sau: SAE J1850 PWM, SAE J1850 VPW, ISO 9141-2, ISO 14230-4 KWP, ISO 15765-4 CAN, SAE J1939 CAN. nếu BUS mục tiêu của chúng ta sử dụng một trong những giao thức trên, hoặc nếu BUS mục tiêu chuyển tiếp các tín hiệu trở về BUS chẩn đoán, thì chúng ta có thể tiếp tục với việc hack bằng cách sử dụng một công cụ quét để giao tiếp với nó.
Ví dụ: tôi đã có thể tìm kiếm trực tuyến thấy rằng chiếc 2003 Jeep Grand Cherokee (WJ) thực tế hỗ trợ 2 giao thức khác nhau cho hệ thống OBD-II (do lỗi của nhà sản xuất). Tài liệu FSM đã xóa đi cái giao thức cho “Chrysler PCI Bus” (SAE J1850 VPW). Nó cũng xác thực rằng radio và khiển vô lăng liên kết tới các nút trên vô lăng thông qua PCI Bus. Sử dụng các nút để điều khiển cái gì đó khác là mục đích chính của tôi.
1.2.2. Bước 2: Kết nối vật lý

OBD-II đòi hỏi một cổng chẩn đoán tiêu chuẩn đặt trong vòng 3 feet từ vị trí lái xe và có thể truy cập mà không cần công cụ. Thường là nằm dưới bảng điều khiển, ngay trên bàn chân của bạn, và trông như thế này:
P1070854.JPG

Hình 1.3 Cổng kết nối OBD-II trên xe
Đây thường là nơi đơn giản nhất để truy cập vào bus. Các cổng này sẽ có các chân tiêu chuẩn nhất định phụ thuộc vào giao thức OBD-II chiếc xe sử dụng. Những chân còn lại không được xác định vì nó phụ thuộc và đặc tính của mỗi nhà sản xuất xe hơi. Nó thường cho phép truy cập vào các bus khác trên các chân này để công cụ quét độc quyền của nhà sản xuất có thể giao tiếp với toàn bộ chiếc xe. Tham khảo tài liệu sửa chữa của xe bạn để biết các chân này hoặc sơ đồ nối dây. Dưới đây là sơ đồ chân của một cổng chuẩn đoán lỗi tiêu chuẩn:
OBDII_Pinout.jpg

Hình 1.4 Sơ đồ chân của một cổng OBD-II tiêu chuẩn
Lưu ý quan trọng: tại thời điểm này bạn nên chuyển sang bước 3 và thử bus chẩn đoán chính đầu tiên. Nếu điều đó không giúp bạn có được những thông tin bạn muốn, sau đó quay trở lại đây để làm thế nào để khai thác trực tiếp vào các bus chính xác.
Nếu cổng chẩn đoán chiếc xe của bạn không có các chân tiếp cận với bus mục tiêu, thì bạn có thể tháo công cụ quét hoán đổi dây của bạn từ các chân tiêu chuẩn tới các chân bus mục tiêu. Nếu không bạn có thể cần phải thực sự ghép vào một dây nịt ở đâu đó trong xe. Bạn có thể nhận được một cáp mở rộng OBD-II từ Amazon / eBay với giá rẻ và cắt nó ra để sử dụng các dây thô và thử với việc hoán đổi các đầu dây.
Gợi ý: dò theo dây canbus nối vào hệ thống radio thường là một nơi tuyệt vời để có được kết nối chuẩn xác cho bus nội thất/tiện nghi.

Ví dụ: FSM của tôi cho biết rằng chân số 3 của cổng chẩn đoán đi tới bus liên quan radio. Do bản Grand Cherokee của tôi sử dụng giao thức duy nhất J1850-VPW, tôi chỉ phải trao đổi một dây bên trong công cụ quét của tôi từ chân 2 đến chân 3 để có được một kết nối trực tiếp với bus mà tôi quan tâm. Sau đó tôi phát hiện ra rằng tất cả các bus trên xe của tồi đều được chuyển tiếp qua lại cho vì vậy tôi đã thực sự thậm chí không cần phải làm điều đó (việc đổi chân 2 và 3).
Trên đây là các kiến thức chung nhất và tổng quát nhất về kết nối qua cổng OBDII, để xem chi tiết từng bước thực hiện để kết nối thông qua Bluetooth cho Raspberry Pi vui lòng xem mục III trong bài viết này.
1.2.3. Bước 3: Các kiểm tra cơ bản đầu tiên

Nếu bạn vẫn đang đọc thì có lẽ bạn đã có tất cả các thông tin cơ bản, bạn tiến hành một số hack thực tế. Hãy mời bia tôi vì bạn sẽ có thêm một mớ kiến thức cần thiết - làm thế nào sử dụng một công cụ quét căn bản ELM327 để đọc và ghi dữ liệu bus.
Các công cụ quét này sử dụng IC ELM327 IC từ Elm Electronics (hoặc là các bản copy của Trung cộng đang bày bán tràn làn). Chúng ta có thể tương tác với IC sử dụng các lệnh AT tương tự như các modem trước đây.
Để bắt đầu khai thác bạn cần một ứng dụng cổng giao tiếp nối tiếp (cho các thiết bị USB và Bluetooth, chúng tạo ra một cổng nối tiếp ảo). HyperTerminal cho PC có bản dùng thử, goSerial cho Mac thì miễn phí, và Slick USB 2 Serial Terminal cho Android 3.1+ thì vừa thu phí vừa cho không.
Kết nối công cụ quét đến xe của bạn và máy tính hoặc thiết bị Android (thiết bị IOS có thể cũng được nhưng thôi không có để mà thử). Bật xe của bạn lên (không cần phải khởi động động cơ). Mở ứng dụng cổng nối tiếp của bạn lên và kết nối tới công cụ quét. Kiểm tra hướng dẫn cho các cài đặt kết nối. Hầu hết mọi người mà tôi đã kiểm tra thì đều sử dụng các thiết lập như dưới đây:
Speed/Baud: 115200
Data Bits: 8
Parity: none
Stop Bits: 1
Hardware Flow Control Input: none
Hardware Flow Control Output: none
Khi đã kết nối, gõ lệnh ATI và bấm enter. Bạn có thể nhận được phản hồi ELM327 6.4b (phiên bản có thể khác). Nếu không nhận được gì, thử ATZ và chờ vài giây để thiết bị khởi động lại. Nếu bạn không nhận được gì hoặc nhận được các ký tự rời rạc ngẫu nhiên, có thể bạn đang đặt baud rate sai trong phần mềm serial. Tôi đã thử một công cụ quét cũ mà nó sử dụng rate 9600 khi không kết nối đến Xe và 38400 khi đã kết nối.
Khi bạn đã xác nhận rằng kết nối đến công cụ quét làm việc bình thường, thì chúng ta kiểm tra kết nối từ thiết bị quét đến xe đã làm việc chưa. Cung cấp lệnh ATSP0 để yêu cầu công cụ lựa chọn sử dụng giao thức tự động (bạn có thể nhận được phản hồi OK). Sau đó cung cấp lênh ATMA và bạn sẽ nhận được trả về tream data (một tập hợp các số hex được bung ra). Bấm enter một lần nữa để dừng stream. Nếu bạn không nhận được bất kỳ dữ liệu nào trả về, thì kiểm tra cả kết nối của công cụ quét và kiểm tra x exe đã được bật chưa.

Nếu bạn biết chắc rằng xe của bạn sử dụng giao thức nào, bạn có thể thiết lập cho công cụ quét làm việc với giao thức đó thay vì cho nó chọn tự động. Dùng lệnh ATSP# nhưng thay dấu “#” bằng một trong các mã sau:

0 – Automatic
1 – SAE J1850 PWM (41.6 kbaud)
2 – SAE J1850 VPW (10.4 kbaud)
3 – ISO 9141-2 (5 baud init, 10.4 kbaud)
4 – ISO 14230-4 KWP (5 baud init, 10.4 kbaud)
5 – ISO 14230-4 KWP (fast init, 10.4 kbaud)
6 – ISO 15765-4 CAN (11 bit ID, 500 kbaud)
7 – ISO 15765-4 CAN (29 bit ID, 500 kbaud)
8 – ISO 15765-4 CAN (11 bit ID, 250 kbaud)
9 – ISO 15765-4 CAN (29 bit ID, 250 kbaud)
A – SAE J1939 CAN (29 bit ID, 250 kbaud)
Tôi luôn luôn cấp các lệnh sau để nhận kết quả quét về dạng baseline state (nhập từng lệnh một, bạn có thể nhận được Ok mỗi lần gõ enter sau một lệnh): ATL1, ATH1, ATS1, ATAL. Điều đó cho phép bạn đọc được kết quả ở định dạng có thể đọc được bởi con người, mà nó cho phép chúng ta phân tích điều gì đang diễn ra. Hầu hết các công cụ quét sẽ nhớ các cài đặt này giữa các lần sử dụng.
goSerialSession.jpg

Hình 1.5 Màn hình nhập lệnh và kết quả trả về từ OBD-II
Để biết thêm thông tin về giao tiếp với IC ELM327 IC (và tìm hiểu tác dụng của mỗi lệnh) xem các tài liệu sau:
ELM327 AT commands quick reference: http://elmelectronics.com/ELM327/AT_Commands.pdf
ELM327 data sheet (explains the commands):
http://elmelectronics.com/DSheets/ELM327DS.pdf
1.2.4. Bước 4: Bắt đầu hack

Với việc đọc kỹ tập tin ELM327 AT commands quick reference và ELM327 data sheet bên trên bạn đã có thể bắt đầu các công việc Hack được rồi. Công việc tiếp theo thuộc bên phần mềm và được trình bày ở phần II sau đây.

2. Xác định mã lệnh các nút điều khiển của vô lăng trên Can-Bus [4]

2.1. Khái quát chung

Trong phần I bên trên chúng ta đã thực hiện việc kết nối và kiểm tra xem kết nối đã hoạt động chưa, trong phần này sẽ tiến hành các công việc thực sự để đạt mục đích của chúng ra. Ở đây tôi sẽ trình bày các nội dung gồm:
- Tìm hiểu cấu trúc của thông điệp mà hệ thống canbus nó gửi hòa vào trong mạng cục bộ
- Một ví dụ thực tiễn nhất về việc làm thế nào tìm được thông điệp mà ta đang quan tâm trong hàng ngàn tin được gửi vào mạng bus của nó, ở đây là xem các phím trên vô lăng gửi lệnh gì vào mạng canbus để trích xuất nó ra dùng cho các mục đích của chúng ta.
- Làm thế nào gửi thông điệp vào canbus để thực hiện việc điều khiển.
hack-vehiclebus-part2.jpg

Hình 2.1 Dùng điều khiển vô lăng để điều khiển máy tính bảng qua giao tiếp OBD II
Với dự án đầu tiên của tôi, tôi muốn hiểu làm thế nào nhận được các giao tiếp của khiển vô lăng điều khiển radio khi diễn ra các sự kiện nút bấm. Tôi thay thế radio nguyên bản theo xe thành máy tính bảng Motorola Xoom 10″ Android để có một cái máy GPS tốt hơn (ứng dụng OBDII và các tùy chọn giải trí tốt hơn,…). Tuy nhiên, bấm màn cảm ứng khi đang lái xe có thể khá khó khan (ngoại trừ dừng xe để điều khiển). Đó là lý do vì sao tôi muốn các phím điều khiển vô lăng nguyên bản vẫn có thế điều khiển âm lượng, track, play/pause, v.v. Tôi sẽ sử dụng kết quả này như một ví dụ để bước vào điều hướng dữ liệu bus.
https://www.youtube.com/watch?v=T3BidW0OYek
Mã nguồn của ứng dụng Android trên có thể tải về từ GitHub:
http://github.com/theksmith/Steering-Wheel-Interface
2.2. Các nhiệm vụ cần thực hiện

Bạn sẽ cần những gì?
- Kiên nhẫn! -> một điều không thể thiếu của hacker
- Một chiếc xe và giao tiếp phần cứng (công cụ quét xem phần I)
- Máy tính hoặc máy tính bảng với ứng dụng serial terminal cho phép lưu log ra file
- Microsoft Excel (hoặc Apple Numbers, Google Docs spreadsheet, MS Access, v5.)
2.2.1. Nhiệm vụ thứ 1: Thu thập số liệu cơ bản (baseline)

Nhiệm vụ đầu tiên là thu thập các số liệu cơ bản, nghĩa là thông điệp gì đang diễn ra xung quanh bus khi bạn không làm gì cả và khi bạn tương tác để tìm kiếm thông điệp cần thiết. Tôi đã thử và nhận thấy khi xe không nổ máy tôi vẫn có thể sử dụng khiển vô lăng để điều khiển radio, điều đó làm cho sự việc trở lên đơn giản hơn khi tôi có thể thu được các mẫu dữ liệu của tôi khi không cần nổ máy (tất nhiên xe phải mở khóa điện). Ở bước này tuyệt đối không tương tác các tính năng đang cần sao chép, (trường hợp cụ thể ở đây là không được bấm các nút bấm trên khiển vô lăng), mục đích của việc này là tạo ra một cơ sở dữ liệu không chứa các thông điệp chúng ta cần nghiên cứu (không chứa lệnh của các nút trên vô lăng) để làm cơ sở loại trừ trong các bước về sau.
Cấp các lệnh sau (từng lệnh một): ATL1, ATH1, ATS1, ATAL
Hãy chắc chắn ứng dụng serial terminal của bạn thiết lập để lưu log ra một file text.
Cấp lệnh ATMA để công cụ quét lấy hết các thông điệp trong mạng mà nó thấy được.
Hãy bấm enter sau một phút để dừng việc stream data.
2.2.2. Nhiệm vụ thứ 2: Lưu dữ liệu từ sự kiện/tương tác

Các công việc tiếp theo là lưu các thông điệp bus khi các hành động (test run) mà bạn đang tìm kiếm xảy ra. đây có thể là khi một cái gì đó giống như khi các đài phát thanh thay đổi bài hát, khi bạn nhấn nút đóng cửa sổ trời, vv tôi muốn biết các thông điệp cho mỗi nút trên vô lăng. Tôi đã làm một bộ sưu tập dữ liệu chạy cho mỗi 6 nút riêng biệt. Mỗi lần chạy, tôi sẽ nhấn vào nút đó 5 lần, cố gắng khoảng trống giữa mỗi lần ấn đồng đều khoảng 1 giây. Tôi muốn tạo ra một số dữ liệu mà hy vọng nó sẽ nổi bật trong dòng dữ liệu.
Lặp lại các bước ở nhiệm vụ trước, khi xảy ra các sự kiện mong muốn (hoặc để nó xảy ra mà bạn hoàn toàn không điều khiển gì cả - mục đích là để sau này lọc ra các dữ liệu không phải do mình điều khiển).

2.2.3. Nhiệm vụ thứ 3: Phân tích dữ liệu

Bây giờ bạn sẽ phân tích dữ liệu thu thập để tìm ra thông điệp bus mà bạn quan tâm. Tôi sử dụng excel, nhưng bạn có thể dùng các chương trình khác tương tự. Bảng excel hoàn chỉnh cho các ví dụ bên dưới có thể tải về từ đây: 2003WJ-PCIBus-SWButtonData.xls
http://theksmith.com/wp-content/uploads/2013/04/2003WJ-PCIBus-SWButtonData.xls
- Paste dữ liệu từ mỗi lần thu thập baseline/test run vào một sheet riêng biệt. Tất cả các thông điệp bus nên để cột 1, header của cột là “msg“.
sheets.jpg

Hình 2.2 Cấu trúc bảng dữ liệu
- Trong sheet với dữ liệu baseline, thêm một cột với header là “count“. Điền vào cột này giá trị “1” cho mỗi dòng
baseline-columns.jpg

Hình 2.3 Bổ sung cột dữ liệu count
- Vẫn trong bảng dữ liệu tại sheet baseline, tạo một bảng pivot mà nó tổng hợp lại bộ đếm cho mỗi thông điệp. Cái này chỉ là một cách đơn giản để cho bạn một danh sách các thông điệp khác nhau.
baseline-pivot.jpg

Hình 2.4 Bảng privot để gộp các giá trị giống nhau vào một dòng và cộng tổng số dòng giống nhau
- Bây giờ đến sheet với mẫu đầu tiên của bạn và chạy. Một lần nữa sử dụng header “msg” cho cột đầu tiên và cột thứ 2 với header “count“ với các giá trị “1”.
- Với cột thứ 3 thêm header “not in baseline“. Với giá trị ở mỗi dòng đặt một hàm mà nó đặt thông điệp từ cột 1 và cột này chỉ khi thông điệp đó không có trong danh sách baseline. Hàm có thể trông giống như thế này (bảng dữ liệu privot của tôi nằm ở sheet có tên “baseline”, tại cột “D”):
=IF(ISNA(MATCH(A2,baseline!D:D,0)), A2, "")
Bạn có thể kết thúc với một vài thứ tương tự thế này, trong đó cột thứ 3 là một loạt các ô trống, chỉ vài ô là có thông điệp trong đó:
testrun-data.jpg

Hình 2.5 Bảng lọc dữ liệu không có trong baseline
- Tiếp tục tạo một bảng privot tương tự như trước. Tuy nhiên, cho sheet mẫu chạy này, sử dụng các cột “not in baseline” và “count”. Việc này sẽ cung cấp cho bạn một danh sách các của các thông điệp xảy ra trong quá trình test mà không trùng lặp với các thông điệp trong baseline. Nó cũng cho bạn biết thông điệp xảy ra bao nhiêu lần. Bạn về cơ bản đã có thể xóa các nhiễu nền không mong muốn từ dữ liệu mẫu. Đến đây đã gần như đến đích cho các mục tiêu đơn giản của bạn. Với dự án của tôi, tôi cần so sánh nhiều nút để hiểu thực sự điều gì đang diễn ra.
testrun-pivot.jpg

Hình 2.6 Bảng lọc các giá trị không mong muốn khỏi cơ sở dữ liệu
- Trong hình trước chú ý rằng tôi có nhiều thông điệp khác nhau mà nó không có trong baseline. Tôi đã bấm nút “up” bên phải của vô lăng 5 lần cho bài kiểm tra này và thực tế dữ liệu thu được cho thấy không có cái thông điệp nào trong “not-in-baseline” xảy ra chính xác 5 lần! vì vậy tôi đã quay lại từ đầu lặp lại kiểm tra này cho 2 nút của vô lăng bên phải và dưới đây là bảng privot cho mỗi lần kiểm tra:
testrun-compare.jpg

Hình 2.7 Bảng privot cho các nút trên điều khiển vô lăng
- Bây giờ với một số lý luận suy cơ bản và một chút trực giác. Ở trên tôi đã đánh dấu màu đỏ tất cả các thông điệp mà nó xảy ra ít nhất 5 lần - tôi biết rằng tôi chắc nhấn các nút rõ ràng và đủ mạnh để nó chắc chắn đã nhận lệnh cho mỗi lần nhấn, nhưng có lẽ chúng đã gửi nhiều thông điệp nếu tôi giữ chúng xuống hơi lâu một chút? tiếp theo tôi gạch bỏ tất cả các thông điệp trùng lặp giữa bài kiểm tra (vì 3 nút khác nhau không thể tạo ra cùng một thông điệp).
testrun-compare2.jpg

Hình 2.8 Lọc bỏ các thông điệp không phù hợp
- Việc này này để lại cho tôi một thông điệp duy nhất trong hai bảng của hai nút và 2 thông điệp trong một bảng của một nút khác (nút Middle). Tuy nhiên với chút ít các dữ liệu còn lại ít này khá dễ dàng nhận ra được khuôn dạng của nó - tất cả 3 mẫu có một thông điệp được gửi tới bus ID11. Tôi đoán rằng 11 phải là ID của Radio, và 3 thông điệp riêng biệt gửi đó phải là 3 nút trên bên phải vô lăng của tôi.
2.2.4. Nhiệm vụ 4: Kiểm tra giả thuyết của bạn

Tiếp theo có thể bạn muốn thực hiện kiểm tra để xác nhận, theo gõi chỉ các ID mà bạn tin rằng nó đang gửi thông điệp (ATMT#), hoặc chỉ ID nhận (ATMR#).
Dựa trên việc trích ở trên, tôi nghĩ rằng tôi xác định đúng 3 thông điệp bus. Nhưng tại sao chúng không xảy ra chính xác số lần tôi nhấn các nút? tôi đã quyết định để thực hiện một thử nghiệm khác, nhưng chỉ theo dõi ID 11 (radio). Hy vọng dữ liệu mẫu của tôi sẽ là nhỏ đủ để nhìn trực tiếp và tại xác định khuôn dạng tại chỗ. Một lần nữa tôi đã kiểm tra từng nút riêng biệt, lần này cấp lệnh ATMR11 để chỉ nhìn thấy thông điệp dành cho Radio. Tôi bấm mỗi nút 5 lần nữa, cách nhau khoảng một giây. Lúc này tôi đã rất thận trọng và nhất quán trong cách tôi bấm mỗi nút. Kiểm tra kết quả:
testrun-confirmation.jpg

Hình 2.9 Bảng tổng hợp kết quả kiểm tra ID 11
Tôi nghĩ chuyện này xảy ra là do tiếp xúc của nút bấm nhưng sau đó tôi nhận thấy rằng giữ nút bấm này sẽ gửi liên tiếp các thống điệp lặp lại, trong khi bấm nhanh sẽ gửi từ 1-3 thông điệp. Điều này đã loại bỏ nhận định ban đầu của tôi.
- Một cách khác để kiểm tra nhận của bạn là gửi thông điệp vào bus và kiểm tra phản hồi vật lý của xe. Việc này có thể làm việc cho các hoạt động locking/unlocking các cửa, v.v. Tôi đã thử lặp lại lệnh gửi thông điệp của nút “UP” bên phải của vô lăng. Nếu rôi gửi đúng thông điệp tôi sẽ nghe thấy tiếng âm lượng tăng lên và thấy hiển thị trên màn hình biểu tượng tăng âm lượng như khi bấm nút thực sự. Thông điệp của nút “Up” mà tôi đã quan sát được là 3D 11 04 00 C3, vậy tôi đã sử dụng lệnh ATSH 3D 11 04 và sau đó cấp 00 (checksum C3 sẽ được tạo tự động bởi ELM327). Chắc chắn như vậy là đủ và nó làm việc!
Tất cả các ví dụ đến nay tôi đã đang làm với kiểu bus SAE J1850. Cấu trúc thông điệp và mẫu lệnh có thể hoạt động với hầu hết các giao thức khác trừ CAN-Bus. Bạn có thể đã suy ra một phần của cấu trúc:
3 byte header + up to 7 data bytes + checksum
ELM327 trả về thông điệp ở dạng hex, vì vậy chúng trông thế này (trong đó PP = priority, RR = receiver ID, TT = transmitter ID, DD = data, CC = checksum):

PP RR TT DD DD DD DD DD DD DD CC

Cấu trúc cho CAN chỉ hơi khác một chút, và ELM327 có một tập lệnh đặc biệt để làm việc với giao thức đó. Kiểm tra datasheet để biết các thông tin đầy đủ về cấu trúc và tất cả các lệnh có thể.



3. Giao tiếp giữa ô tô và Máy Tính thông qua OBDII bằng Python [5]

3.1. Các thứ cần thiết:

- Ô tô có cổng OBD2 (hầu hết các xe từ năm 1996 trở lại đều có)
- Laptop/máy tính hoặc Raspberry Pi để cài đặt và chạy Python 2.7.3
- Một thiết bị kết nối cổng OBD (có thể sử dụng OBDII Bluetooth hoặc loại dùng cáp. Loại ELM327 bluetooth giá chỉ 10 đô)
6002162_orig.jpg

Hình 3.1 – Phần cứng cần thiết
3.2. Kết nối và tương tác

Khi bạn sử dụng kết nối dù cáp Usb hay Usb Bluetooth đến máy tính thì nó được nhận là một giao tiếp serials. Với hệ điều hành Linux có thể tìm thấy cổng đã kết nối tới máy tính bằng lệnh
ls /dev/tty*
(Trong đó “ls” là viết tắt của từ “list the following with file name” và “/dev/tty” là phần tiền tố của tất cả các cổng serial).
Tiếp theo
Tải pyserial về máy và cài đặt.
Mở cửa sổ dòng lệnh terminal (nó là command prompt trên Windows).
Gõ vào lệnh python để khởi động start Python.
Gõ vào lệnh import serial để sử dụng Pyserial
Bây giờ kết nối tới thiết bị serial. Để làm điều này bạn cần tên của thiết bị usb đã kết nối (xem lại phía trên). Gõ vào lệnh:
ser = serial.Serial('NAME_OF_SERIAL_DEVICE', 38400, timeout=1)
Bây giờ bạn đã kết nối tới OBD, vì vậy bạn có thể bắt đầu gửi lệnh. Ví dụ, để đo tốc độ của xe gõ vào:
ser.write("01 0D \r")
Danh sách đầy đủ các lệnh của OBD có thể xem tại đây:
http://en.wikipedia.org/wiki/OBD-II_PIDs
Thiết bị OBD elm327 trả về giá trị HEX (hệ thập lục phân). Để đọc giá trị bạn chỉ cần yêu cầu trong Python bằng lệnh:
speed_hex = ser.readline().split(' ')
Chuyển đổi giá trị HEX sang hệ thập phân (decimal) bằng lệnh:
speed = float(int('0x'+speed_hex[3], 0 ))
Cuối cùng đưa giá trị ra màn hình bằng lệnh:
print 'Speed: ', speed, 'km/h'
Bây giờ bạn có thể nhìn thất tốc độ xe hiển thị trên màn hình.

4. Kết nối OBD-II Bluetooh đến Raspbery Pi

- Kết nối OBD2 Bluetooth vào cổng OBD2 trên xe
- Kết nối USB Bluetooth và RPI
- Khởi động RPi , xe ô tô và thực hiện SSH để sử dụng dòng lệnh trên RPi từ máy tính
- Từ màn hình SSH chạy các lệnh sau:
pi@raspberrypi ~ $ sudo su root@raspberrypi:/home/pi#
Nếu đây là RPI mới và chưa chạy cập nhật lần nào thì chạy:
# apt-get update
# apt-get upgrade
Quá trình này mất chút thời gian, đợi đến khi cập nhật xong tiến hành kích hoạt DBUS:
# update-rc.d -f dbus defaults
D-Bus là hệ thống message-bus, một cách để các ứng dụng giao tiếp với ứng dụng khác. Nó làm việc với Unix sockets giữa các ứng dụng và daemons. Nó cần thiết cho Bluez, mà chúng ta sẽ cài sau đây. Tại thời điểm này cần khởi động lại RPi:
# reboot
Sauk hi đăng nhập lại và vào lại chế độ root chúng ta có thể cài một số công cụ bluetooth bằng cách sử dụng lệnh apt-get:
# apt-get install bluetooth bluez-utils blueman
Bây giờ nếu liệt kê danh sách thiết bị usb trên RPI chúng ra sẽ thấy USB Bluetooth đã xuất hiện (như của tôi là Broadcom Corp như bên dưới):
# lsusb
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp. Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. Bus 001 Device 004: ID 0a5c:21e8 Broadcom Corp.
Nếu mọi thứ làm việc bình thường chúng ra có thể quét các thiết bị Bluetooth khả dụng xung quanh với hcitool:
# hcitool scan
Scanning ... CC:6D:A0:11:08:66 Roku Player 00:0D:18:A0:4E:35 OBDII 00:0D:4B:F0:CB:6E Roku Player
Bạn có thể thấy ở đây tôi có một vài box Roku xung quanh và OBDII adapter có địa chỉ 00:0D:18:A0:4E:35. Nếu hcitool scan không làm việc, bạn có thể kiểm tra để chắc chắn bluetooth đã được bật bằng lệnh hciconfig:
# hciconfig hci0: Type: BR/EDR Bus: USB BD Address: 00:02:72:C6:A6:81 ACL MTU: 1021:8 SCO MTU: 64:1 UP RUNNING PSCAN RX bytes:121283 acl:138 sco:0 events:12710 errors:0 TX bytes:70273 acl:104 sco:0 commands:12591 errors:0
Nếu nó không hoạt động bạn có thể kiểm tra trạng thái bluetooth:
# /etc/init.d/bluetooth status
Và khởi động lại nếu cần thiết:
# /etc/init.d/bluetooth [stop/start/restart]
Tại thời điểm này chúng ta có thể kết nối USB Bluetooth với đầu đọc OBD-II Bluetooth bằng Bluez:
# bluez-simple-agent hci0 00:0D:18:A0:4E:35
Có thể bạn cần phải nhập mật khẩu kết nối vào lúc này, nhưng trong trường hợp của tôi, máy không yêu cầu. Mật khẩu kết nối Bluetooth thường mặc định là “1234” hoặc “0000”. Sau đó bạn có thể làm cho adpter được “tin tưởng” để không cần phải kết nối thủ công lại mỗi lần sử dụng về sau:
# bluez-test-device trusted 00:0D:18:A0:4E:35 yes
Tại thời điểm này, sau khi nghịch ngợm đủ trò với các lệnh bluez khác nhau để thử kết nối form dòng lệnh tôi đã đưa ra và thực thi một VNC session Preferences => Bluetooth Manager. Bạn có thể chỉ cần cắm vào một màn hình nhưng đây là cách cài đặt (để hiển thị màn hình cho RPI lên màn hình máy tính) VNC nếu bạn không muốn sử dụng màn hình riêng cho RPI:
# sudo apt-get install tightvncserver
# tightvncserver
# vncserver :0 -geometry 1920x1080 -depth 24

Khi đã kết nối bạn có một thiết bị mới tại */dev/rfcomm0 *với cái này để truyền tin.
Screen_Shot_2013-10-19_at_1_24_16_PM_ttyw8d.png

Hình 3.1. Cài đặt màn hình ảo
Để bắt đầu truyền tin với /dev/rfcomm0, bạn sẽ cần cài màn hình:
# apt-get install screen
Và sau đó kết nối tới /dev/rfcomm0 với màn hình. Màn hình là một trình quản lý windows đầy màn hình mà kết hợp các cổng vật lý giữa nhiều tiến trình xử lý, về cơ bản là chúng liên quan lẫn nhau:
# screen /dev/rfcomm0
Trong màn hình bạn có thể nhập vào các lệnh. Trước hết bạn nên biết về một số lệnh AT commands. Các lệnh này là các lệnh hệ thống mà nó bắt trước lại một số tập lệnh AT “ATtention” của Modem Hayes cũ.
Trước hết bạn sẽ cần thiết lập một số tùy chọn định dạng bởi vì mặc định là một mớ phản hồi lộn xộn trên đỉnh của truy vấn, làm cho việc đọc rất khó khăn:
> ATZ
Khởi động lại thiết bị. Bạn sẽ cần làm việc này thường xuyên.
> ATL1
Bật linefeeds
> ATH1
Bật headers
> ATS1
Bật khoảng trống spaces
>ATSP0
Thiết lập giao thức thành tự động Auto
Các lệnh này có thể chỉ đơn giản là trả về phản hồi “OK” từ chip ELM327. Nếu bạn muốn thông tin về con chip, bạn có thể nhập vào:
>ATI
ELM327 6.5
Nhưng tất các những cái đó thật tẻ nhạt. Hãy truy vấn một vài thông tin từ xe ô tô!
Trước hế, hãy xem liệu chúng ta có mã lỗi MIL nào được lưu trữ không với truy vấn chế độ 03:
>03
SEARCHING... 87 F1 12 43 04 44 00 00 00 00 15
Tôi có mã lỗi được lưu là 0444 (Tôi đã để bớm ga lỏng để thể hiện lỗi này). Phản hồi ở đây thể hiện một chuỗi các cặp số thập lục phân. Ngay trước 0444, bạn sẽ thấy một số “43”. Điều này nói rằng đó là phản hồi cho truy vấn chế độ 03 (số 4 chỉ ra rằng là một phản hồi, số 3 là truy vấn mà nó phản hồi tới). Các số còn lại có thể không cần quan tâm.
Thế còn lấy số VIN thế nào? Đó là chế độ truy vấn 09 với một PID giá trị là 02, vậy ta nhập vào:
>0902
87 F1 12 49 02 01 00 00 00 57 2D
87 F1 12 49 02 02 42 41 45 56 F5
...

Thực tế việc này sẽ trả về 5 khung (dòng) dữ liệu cho mã VIN nhưng tôi không muốn post mã VIN của tôi lên cho cả thiên hạ xem nên tôi đã cắt 3 dòng cuối. Bạn có thể xem thông tin thời gian thực. Đây là một ví dụ của việc xem tốc độ vòng quay RPM hiện tại của máy. Dữ liệu thời gian thực là truy vấn chế độ 01, tốc độ vòng quay RPM là PID 0C:
>010C
84 F1 12 41 0C 0A DC BA

Một lần nữa chúng ta có một vài dữ liệu hex (thập lục phân), vậy làm thế nào giải mã nó? Chúng ta quan tâm đến 2 cặp phía sau chỉ dấu phản hồi, mà trong trường hợp này “41 0C” (4 cho phản hồi, 1 vì nó là chế độ truy vấn 1, và 0C bởi vì PID là 0C). Tốc độ vòng quay phản hồi được phản hồi là ¼ của RPM (đừng hỏi tôi tại sao lại thế), và 0ADC trong hex thì bằng 2780 trong hệ thập phân (có thể dùng cái máy tính trên window mà convert từ hex sang dec). 2780 / 4 *RPM = 695*RPM đó là cơ sở của việc tính toán.
Đây là video thể hiện quá trình sử dụng lệnh trên màn hình:
http://www.youtube.com/watch?v=Jrk_1Z67OfY
Như vậy, đó là những điều cơ bản của việc kết nối Raspberry Pi đến cổng OBD-II trên ô tô thông qua Bluetooth.
Gợi ý: bạn cóh tể thoát khỏi màn hình với Ctrl-A, Ctrl-D.
Đây là một vài địa chỉ thông tin rất bổ ích:

5. Đọc dữ liệu từ cổng USB Bluetooth trên RPI

5.1. Cài đặt gói mô đun python-serials đọc dữ liệu cổng serial

Việc cài đặt mô đun PySerial cho phép raspberry pi đọc được dữ liệu giao tiếp serial từ cổng usb
+ Phương pháp cài trực tuyến
sudo apt-get install python-serial
+ Phương pháp cài ofline:
Tải file file pyserial-2.6.tar.gz từ
https://pypi.python.org/pypi/pyserial
Startx
Sử dụng 'file manager'
Copy the file vào /home/pi
double click vào pyserial-2.6.tar.gz
Chọn 'Action'
Chọn 'Extract'
double click vào pyserial-2.6.tar0
Chọn 'Action'
Chọn 'Extract'
Mở LXTerminal
Gõ cd pyserial-2.6
Gõ Enter
Gõ sudo python setup.py install
Gõ Enter

5.2. Mã lệnh mẫu file serialtest.py để thực hiện các câu lệnh đọc và xử lý dữ liệu

Chú ý cần sửa /dev/ttyAMA0 và baudrate cho phù hợp từng trường hợp cụ thể
+ Đoạn mã ví dụ đọc 10 bits dữ liệu
import serial

port = serial.Serial("/dev/ttyAMA0", baudrate=38400, timeout=1)

while True:
port.write("\r\nSay something:")
rcv = port.read(10)
port.write("\r\nYou sent:" + repr(rcv))


+ Đoạn mã ví dụ đọc một dòng dữ liệu [7]
import serial
import time

def readlineCR(port):
rv = ""
while True:
ch = port.read()
rv += ch
if ch=='\r' or ch=='':
return rv

port = serial.Serial("/dev/ttyAMA0", baudrate=115200, timeout=3.0)

while True:
port.write("\r\nSay something:")
rcv = readlineCR(port)
port.write("\r\nYou sent:" + repr(rcv))

5.3. Chạy file lập trình python serialtest.py bên trên

python serialtest.py

6. Điều khiển XBMC trên Raspbery Pi bằng JSON-RPC API sử dụng Python

Dưới đây trình bày một số ví dụ mẫu code điều khiển XBMC sử dụng Python
6.1. Điều khiển XBMC qua ISON-RPC bằng Python để Pause/Play VIDEO [16]

Yêu cầu : Bật chế độ “Allow control of XBMC via HTTP” trong Settings -> Services -> Webserver.
Đoạn mã dưới đây thực hiện 2 yêu cầu: Đầu tiên, nó thực hiện một yêu cầu HTTP GET để lấy các tập tin đang chơi hoặc tạm dừng (nếu có). Nếu kết quả được trả về, chúng ta thực hiện một POST để JSON-RPC tạm dừng các tập tin đang chơi bằng cách sử dụng "playerid" trở về từ yêu cầu GET của chúng ta.
Lưu ý – phương thức Player.PlayPause sẽ chuyển đổi giữa 2 trạng thái playing và pausing video. Nếu video đang tạm dừng nó sẽ làm cho video chạy và ngược lại.
#**********************************
importrequests
importjson
importurllib

#Required header for XBMC JSON-RPC calls, otherwise you'll get a
#415 HTTP response code - Unsupported media type
headers ={'content-type': 'application/json'}

#Host name where XBMC is running, leave as localhost if on this PC
#Make sure "Allow control of XBMC via HTTP" is set to ON in Settings ->
#Services -> Webserver
xbmc_host ='localhost'

#Configured in Settings -> Services -> Webserver -> Port
xbmc_port =8888

#Base URL of the json RPC calls. For GET calls we append a "request" URI
#parameter. For POSTs, we add the payload as JSON the the HTTP request body
xbmc_json_rpc_url ="http://"+xbmc_host +":"+str(xbmc_port) +"/jsonrpc"

#Payload for the method to get the currently playing / paused video or audio
payload ={"jsonrpc": "2.0", "method": "Player.GetActivePlayers", "id": 1}
url_param =urllib.urlencode({'request': json.dumps(payload)})

response =requests.get(xbmc_json_rpc_url +'?'+url_param,headers=headers)

#response.text will look like this if something is playing
#{"id":1,"jsonrpc":"2.0","result":[{"playerid":1,"type":"video"}]}
#and if nothing is playing:
#{"id":1,"jsonrpc":"2.0","result":[]}

data =json.loads(response.text)
#result is an empty list if nothing is playing or paused.
ifdata['result']:
#We need the specific "playerid" of the currently playing file in order
#to pause it
player_id =data['result'][0]["playerid"]

payload ={"jsonrpc": "2.0", "method": "Player.PlayPause",
"params": { "playerid": player_id }, "id": 1}
response =requests.post(xbmc_json_rpc_url, data=json.dumps(payload),
headers=headers)

#response.text will look like this if we're successful:
#{"id":1,"jsonrpc":"2.0","result":{"speed":0}}

#**********************************
Để đảm bảo tính toàn vẹn của mã nguồn, tránh lỗi do copy, định dạng văn bản có thể tải đoạn mã trên đây tại http://tranhchuthap.vn/bai-viet/canbus/python_play_pause_video.py sau đó dùng notepad++ mở để xem và sửa. Nếu trình duyệt báo lỗi và không tải được hãy copy đường dẫn trên vào IDM để tải về bình thường.

6.2. Điều khiển XBMC qua ISON-RPC bằng Python để Pause VIDEO [17]

Trong ví dụ phần 6.1 đã trình bày một đoạn mẫu cho phép việc Play/Pause một video. Tuy nhiên nó sẽ chuyển đổi qua lại giữa việc Chơi và Tạm dừng mỗi lần chạy. Việc này sẽ thuận lợi khi làm các điều khiển từ xa với chỉ một nút Pause/Play nhưng trong nhiều trường hợp khác nó gây bất tiện. Đoạn code dưới đây sẽ chỉ thực hiện việc làm Tạm dừng chơi video mà không bật nó chạy trởi lại ở lần thao tác kế tiếp.
Để thực hiện việc này chúng ta sử dụng phương thức Player.GetProperties để nhận giá trị “speed” của tập tin đang chơi, điều này sẽ cho chúng ta biết tập tin đó đang chạy hay tạm dừng. Vậy để tạm dừng chúng ta cần sử dụng 3 hàm API:
- Player.GetActivePlayers để nhận được ID của tập tin đang chơi “playerid”
- Player.GetProperties thông qua playerid từ giá trị trả về của Player.GetActivePlayers để nhận được giá trị “speed” mà nó cho chúng ta biết tập tin đang tạm dừng hay đang chạy.
- Player.PlayPause được gọi chỉ khi giá trị trả về của “speed” khác 0
Dưới đây là đoạn mã.
#**********************************
importrequests
importjson
importurllib

#Required header for XBMC JSON-RPC calls, otherwise you'll get a
#415 HTTP response code - Unsupported media type
headers ={'content-type': 'application/json'}

#Host name where XBMC is running, leave as localhost if on this PC
#Make sure "Allow control of XBMC via HTTP" is set to ON in Settings ->
#Services -> Webserver
xbmc_host ='localhost'

#Configured in Settings -> Services -> Webserver -> Port
xbmc_port =8888

#Base URL of the json RPC calls. For GET calls we append a "request" URI
#parameter. For POSTs, we add the payload as JSON the the HTTP request body
xbmc_json_rpc_url ="http://"+xbmc_host +":"+str(xbmc_port) +"/jsonrpc"

#Payload for the method to get the currently playing / paused video or audio
payload ={"jsonrpc": "2.0", "method": "Player.GetActivePlayers", "id": 1}
url_param =urllib.urlencode({'request': json.dumps(payload)})

response =requests.get(xbmc_json_rpc_url +'?'+url_param,
headers=headers)

#response.text will look like this if something is playing
#{"id":1,"jsonrpc":"2.0","result":[{"playerid":1,"type":"video"}]}
#and if nothing is playing:
#{"id":1,"jsonrpc":"2.0","result":[]}

data =json.loads(response.text)
#result is an empty list if nothing is playing or paused.
ifdata['result']:
#We need the specific "playerid" of the currently playing file in order
#to pause it
player_id =data['result'][0]["playerid"]

payload ={"jsonrpc": "2.0", "method": "Player.GetProperties",
"params": { "playerid": player_id, "properties": ["speed"] }, "id": 1}
url_param =urllib.urlencode({'request': json.dumps(payload)})
response =requests.get(xbmc_json_rpc_url +'?'+url_param,
headers=headers)

data =json.loads(response.text)

ifdata["result"]["speed"]:
payload ={"jsonrpc": "2.0", "method": "Player.PlayPause",
"params": { "playerid": player_id }, "id": 1}
response =requests.post(xbmc_json_rpc_url, data=json.dumps(payload),
headers=headers)

#response.text will look like this if we're successful:
#{"id":1,"jsonrpc":"2.0","result":{"speed":0}}

#**********************************
Để đảm bảo tính toàn vẹn của mã nguồn, tránh lỗi do copy, định dạng văn bản có thể tải đoạn mã trên đây tại http://tranhchuthap.vn/bai-viet/canbus/python_only_pause_video.py sau đó dùng notepad++ mở để xem và sửa. Nếu trình duyệt báo lỗi và không tải được hãy copy đường dẫn trên vào IDM để tải về bình thường.

6.3. Điều khiển vô lăng cho XBMC

Từ các ví dụ ở mục 5.2, 5.3, 6.1 và 6.2 có thể kết hợp với nhau để điều khiển vô lăng cho XBMC KODI trên Raspberry Pi
Sau khi nhận được mã điều khiển của các nút trên vô lăng ta có thể tiến hành việc nhận lệnh điều khiển của các nút đó điều khiển XBMC, KODI trên Raspberry Pi thông qua ngôn ngữ lập trình Python thông qua chức năng điều khiển JSON-RPC API đã tích hợp sẵn của KODI. Để kích hoạt chức năng JSON-RPC API cần vào setting bật chế độ điêu khiển qua web của XBMC, KODI.
Lệnh điều khiển XBMC, KODI từ Python như sau:
import json
import xbmc
import os
xbmc.executeJSONRPC( lenh_dieu_khien )
Trong đó tất cả các lệnh điều khiển Kodi trên nền JSON-RPC API có thể xem tại http://KODI.wiki/view/JSON-RPC_API cần chọn đúng phiên bản API để xem lệnh. Ví dụ với JSON-RPC API V6 đi theo KODI HELIX 14.1 xem tại http://KODI.wiki/view/JSON-RPC_API/v6 . Một vài lệnh điều khiển thường dùng như sau:
Up = '{"jsonrpc": "2.0", "method": "Input.Up", "id": 1}'
Down = '{"jsonrpc": "2.0", "method": "Input.Down", "id": 1}'
Left = '{"jsonrpc": "2.0", "method": "Input.Left", "id": 1}'
Right = '{"jsonrpc": "2.0", "method": "Input.Right", "id": 1}'
Select = '{"jsonrpc": "2.0", "method": "Input.Select", "id": 1}'
Back = '{"jsonrpc": "2.0", "method": "Input.Back", "id": 1}'
Home = '{"jsonrpc": "2.0", "method": "Input.Home", "id": 1}'
Play_Pause = '{"jsonrpc": "2.0", "method": "Player.PlayPause", "params": {"playerid": 0}, "id": 1}'
Shutdown = '{"jsonrpc": "2.0", "method": "System.Shutdown ", "id": 1}'



+ Dưới đây là file mẫu Python điều khiển thông qua JSON-RPC_API với giao thức HTTP (cần điều chỉnh lại cho phù hợp với các mã nút của từng xe):

import serial
import time
import requests
import json
import urllib

# Thiết lập kết nối http cho JSON-PRC
# Cần phải có header cho XBMC JSON-RPC calls, nếu không bạn sẽ nhận được lỗi
#415 HTTP response code - Unsupported media type
headers = {'content-type': 'application/json'}

#Host name của máy chạy XBMC, để là localhost nếu chạy trên máy hiện tại
#Hãy chắc chắn rằng "Allow control of XBMC via HTTP" được đặt là ON trong Settings ->
#Services -> Webserver
xbmc_host = 'localhost'

#Con số này lấy trong Settings -> Services -> Webserver -> Port của XBMC
xbmc_port = 8888
#Base URL of the json RPC calls. For GET calls we append a "request" URI
#parameter. For POSTs, we add the payload as JSON the the HTTP request body
xbmc_json_rpc_url = "http://" + xbmc_host + ":" + str(xbmc_port) + "/jsonrpc"

#//Hết phần thiết lập kết nối http cho JSON-PRC

# Gán các nút trên vô lăng, phần này cần điều chỉnh cụ thể cho từng xe ô tô
up="3DA2"
down= "3DA1"
right="3DA2"
left="3DA3"
select="3DA4"
back="3DA5"
play_pause="3DA6"
home="3DA7"
shuthdown="3DA8"
# //Hết đoạn mã Gán các nút trên vô lăng

# Thiết lập cổng kết nối serial, trong đó "/dev/ttyAMA0" baudrate=115200 phải
# điều chỉnh chính xác theo từng trường hợp cụ thể.
# Đọc ebook tại:
# http://tranhchuthap.vn/bai-viet/canbus/Hack-CAN-BUS-Dieu-khien-volang.pdf
# để biết thêm chi tiết

port = serial.Serial("/dev/ttyAMA0", baudrate=115200, timeout=3.0)

# Kiểm tra xem OBDII đã kết nối tới Rasperry Pi chưa, nếu chưa chờ 5s rồi
# kiểm tra lại, khi nào có kết nối mới thực hiện các công việc tiếp theo

while (port.isOpen() == False):
print("chua ket noi OBDII toi Raspberry Pi!")
time.sleep(5)


# Gửi lệnh dump CANBUS để đọc tất cả các message trên mạng CAN.
# Tuy nhiên nếu đã biết ID của vô lăng thì có thể chỉ dump các
# mesage có ID đó để cho công việc này trở nên đơn giản và nhẹ nhàng

port.write("ATL1\r") # Bật Line feed, nghĩa là cứ mỗi một khung truyền được tạo thành một dòng trên màn hình kết quả
port.write("ATH1\r") # Bật Header để xem ID của các tin nhắn, nhìn vào ID có thể luận ra tin nhắn đó do bộ phận nào trên xe gửi và gửi cho bộ phận nào
port.write("ATSP0\r") # Thiết lập giao thức (protocol) về tự động. Nếu biết cụ thể xe dùng giao thức nào thì tốt nhất chỉnh cố định thay vì tự động. Trong Hack-CAN-BUS-Dieu-khien-volang.pdf đã nói rõ về việc này
port.write("ATS1\r") # Bật khoảng trống giữa các byte để kết quả dễ nhìn. Ví dụ 1A 2B 13 4F thay vì 1A2B134F. Cái này ko thích có thể bỏ qua
port.write("ATAL\r")
port.write("ATMA\r") # Lệnh này dump toàn bộ các message trên mạng canbus và gửi ra RaspBerry Pi, nếu biết ID của vô lăng có thể dump riêng chỉ những ID của vô lăng

#if port.isOpen():
#print("serial is open!")
def readlineCR(port):
rv = ""
while True:
ch = port.read()
rv += ch
if ch=='\r' or ch=='':
return rv

# Lặp đi lặp lại việc: Đọc giá trị từ cổng serial -> kiểm tra xem giá trị nhận được giống với mã của nút nào
# trên vô lăng thì thực hiện việc gửi lệnh điều khiển do mình đặt tới XBMC qua JSON-RPC

while True:
rcv = readlineCR(port)
if (rcv == play_pause):
#Payload for the method to get the currently playing / paused video or audio
payload = {"jsonrpc": "2.0", "method": "Player.GetActivePlayers", "id": 1}
url_param = urllib.urlencode({'request': json.dumps(payload)})

response = requests.get(xbmc_json_rpc_url + '?' + url_param, headers=headers)

#response.text will look like this if something is playing
#{"id":1,"jsonrpc":"2.0","result":[{"playerid":1,"type":"video"}]}
#and if nothing is playing:
#{"id":1,"jsonrpc":"2.0","result":[]}

data = json.loads(response.text)
#result is an empty list if nothing is playing or paused.
if data['result']:
#We need the specific "playerid" of the currently playing file in order
#to pause it
player_id = data['result'][0]["playerid"]

payload = {"jsonrpc": "2.0", "method": "Player.PlayPause","params": {"playerid": player_id }, "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

#response.text will look like this if we're successful:
#{"id":1,"jsonrpc":"2.0","result":{"speed":0}}

if (rcv == up):
payload = {"jsonrpc": "2.0", "method": "Input.Up", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == down):
payload = {"jsonrpc": "2.0", "method": "Input.Down", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == right):
payload = {"jsonrpc": "2.0", "method": "Input.Right", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == left):
payload = {"jsonrpc": "2.0", "method": "Input.Left", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == select):
payload = {"jsonrpc": "2.0", "method": "Input.Select", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == back):
payload = {"jsonrpc": "2.0", "method": "Input.Back", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == home):
payload = {"jsonrpc": "2.0", "method": "Input.Home", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == shuthdown):
payload = {"jsonrpc": "2.0", "method": "System.Shutdown ", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)


Để đảm bảo tính toàn vẹn của mã nguồn, tránh lỗi do copy, định dạng văn bản có thể tải đoạn mã trên đây tại http://tranhchuthap.vn/bai-viet/canbus/python_khien_vo_lang.py sau đó dùng notepad++ mở để xem và sửa. Nếu trình duyệt báo lỗi và không tải được hãy copy đường dẫn trên vào IDM để tải về bình thường.
7. Hiển thị các thông số chuẩn đoán xe lên màn hình thông qua Raspberry Pi [6]

5754635_orig.jpg

Hình 6.1 Màn hình hiển thị các thông số của xe
https://youtu.be/UAwiVERLmDo
Phần này sẽ hướng dẫn các bạn hiển thị dữ liệu thời gian thực của động cơ lên màn hình DVD trên xe thông qua raspberry pi.
7.1. Phần cứng cần thiết

- Raspberry Pi (Model B hoặc B+ hoặc Raspberry Pi 2 mới nhất hiện nay) và có kết nối internet
- Màn hình DVD trên ô tô (yêu cầu: phải có đường video in hoặc HDMI in)
- USB Bluetooth 4.0 Low Energy Micro Adapter
- 2A Car Supply / Switch or Micro USB Car Charger (cái này tùy chọn, ko có cũng được)
- ELM327 Bluetooth Adapter hoặc ELM327 USB Cable
- RCA cable để kết nối hình từ Raspbery Pi vào màn hình trên xe
- Keyboard (*tùy chọn)
7.2. Cài đặt phần mềm

Thực hiện kết nốiS SSH từ máy tính đến RPI thực hiện các lệnh dưới đây
+ Trước hết thực hiện các lệnh sau:
# sudo apt-get update
# sudo apt-get upgrade
# sudo apt-get autoremove
# sudo reboot

+ Cài đặt các thành phần:
# sudo apt-get install python-serial
# sudo apt-get install bluetooth bluez-utils blueman
# sudo apt-get install python-wxgtk2.8 python-wxtools wx2.8-i18n libwxgtk2.8-dev
# sudo apt-get install git-core
# sudo reboot

Tiếp theo tải phần mềm OBD-Pi từ GitHub: https://github.com/Pbartek/pyobd-pi.git
Hoặc sử dụng lệnh sau để cài trực tuyến:
# cd ~
# git clone https://github.com/Pbartek/pyobd-pi.git


7.3. Cài đặt xe

Công việc cài đặt trên xe khá đơn giản.
1. Cắm USB Bluetooth dongle vào Raspberry Pi cùng với SD card.
2. Cắm OBD-II Bluetooth adapter vào cổng SAE J196216 (OBD Port) trên xe.
3. Kết nối cáp RCA lên màn hình của xe, đầu còn lại cắm vào Raspberry Pi.
4. Lắp đặt bo mạch nguồn 2A Car Supply / Switch cho RPI hoặc dùng một chiếc sạc tẩu.
5. Cuối cùng là bật nguồn cho hệ thống, chuyển DVD về chế độ video in.
6. Đăng nhập vào Rpi và chạy:
# startx
7. Kết nối Rpi và ô tô qua Bluetooth như trong hướng dẫn tại mục III
8. Mở Terminal và chạy:
# cd pyobd-pi
# sudo su
# python obd_gui.py

Dùng phím Left và Right để điều hướng đến các màn hình của từng thành phần gauge display.
Chú ý: Click chuột trái và phải cũng làm việc.
Để thoát ứng dụng bấm Control+C hoặc Alt+Esc.

7.4. Data Logging

Nếu bạn muốn lưu lại dữ liệu canbus:
# cd pyobd-pi
# python obd_recorder.py

Tập tin log sẽ được lưu ở:
/home/username/pyobd-pi/log/



8 Tài liệu tham khảo

1. National Instruments Corporation: Controller Area Network (CAN), http://www.ni.com, 2014.
2. Harald Eisele; Adam Opel AG: The Benefits of CAN for In-Vehicle Networking, CAN in Automation, iCC, 2012.
3. A complete guide to hacking your vehicle bus on the cheap & easy – part 1 (hardware interface), http://theksmith.com/technology/hack-vehicle-bus-cheap-easy-part-1/
4. A complete guide to hacking your vehicle bus on the cheap & easy – part 1 (hardware interface), http://theksmith.com/software/hack-vehicle-bus-cheap-easy-part-2/
5. How to interface with your car’s ECU through OBD2 and Python, http://blog.brianhemeryck.me/how-to-interface-with-your-cars-ecu-through-obd2-and-python/
6. OBD-Pi: Raspberry Pi Displaying Car Diagnostics (OBD-II) Data On An Aftermarket Head Unit, http://www.cowfishstudios.com/blog/...stics-obd-ii-data-on-an-aftermarket-head-unit
7. Serial port programming, http://elinux.org/Serial_port_programming
8. Python serial communication – sending hexadecimal commands, https://tungweilin.wordpress.com/20...l-communication-sending-hexadecimal-commands/
9. Python serial port communication, https://tungweilin.wordpress.com/2015/01/04/python-serial-port-communication/
10. Serial Communication, https://learn.sparkfun.com/tutorials/serial-communication
11. Serial Terminal Basics, https://learn.sparkfun.com/tutorials/terminal-basics
12. Logic Levels, https://learn.sparkfun.com/tutorials/logic-levels
13. Raspberry Pi Car-puter, http://nikrooz.co.uk/raspberry-pi-car-puter/
14. CANned Pi: (Part1), http://www.cowfishstudios.com/blog/canned-pi-part1
15. Reading a car's OBDII port with a Raspberry Pi, http://fabcirablog.weebly.com/blog/reading-a-cars-obdii-port-with-a-raspberry-pi, 2014.
16. Calling XBMC’s (Kodi) JSON-RPC API using Python’s requests library – Pause a video, http://www.foo.co.za/calling-xbmcs-kodi-json-rpc-using-pythons-requests-library-pause-a-video, 2014.
17. XBMC’s JSON-RPC API – REALLY Pausing a video, http://www.foo.co.za/xbmcs-json-rpc-api-really-pausing-a-video, 2014.
18. http://forum.KODI.tv/showthread.php?tid=197645
19. http://KODI.wiki/view/JSON-RPC_API
20. http://forum.KODI.tv/showthread.php?tid=197645
21. https://pypi.python.org/pypi/xbmc-json/
22. http://forum.KODI.tv/showthread.php?tid=157996
=================================================
Hàng nhập khẩu

Mỹ phẩm đồ điện gia dụng nhập khẩu

Đồ bếp nhập khẩu

http://anhtay.vn
=================================================
 
Chỉnh sửa cuối:
  • Like
Reactions: pplayer and lakfvn
Hạng D
21/12/08
2.716
47.143
113
Cám ơn bác chủ, bài viết hay quá và e không hiểu cái gì hết.
Cuối cùng là hack để làm cái gì vậy ???
 
Hạng B2
25/7/12
129
107
43
Lúc nào cũng ngưỡng mộ bác chủ. Bài viết của bác là một công trình nghiên cứu tỉ mỉ và hướng dẫn rất chi tiết. Em nghĩ bác và bác Jungle mà kết hợp lại với nhau thì chắc tạo được nhiều cái hay cho anh em thích DIY ở VN.

Bác chủ cho hỏi mình có thể kết nối cái đầu DVD trên xe (WinCE) với cục ODB II được không? Có ứng dụng nào sẵn không?
 
Hạng B2
4/8/14
264
291
63
Hà nội
tranhchuthap.vn
Lúc nào cũng ngưỡng mộ bác chủ. Bài viết của bác là một công trình nghiên cứu tỉ mỉ và hướng dẫn rất chi tiết. Em nghĩ bác và bác Jungle mà kết hợp lại với nhau thì chắc tạo được nhiều cái hay cho anh em thích DIY ở VN.

Bác chủ cho hỏi mình có thể kết nối cái đầu DVD trên xe (WinCE) với cục ODB II được không? Có ứng dụng nào sẵn không?
DVD hàng OEM thì nó có sẵn đường vào canbus rồi ví dụ cụ xem cái dvd của cháu đây, chữ CANL và CANH chính là hai đường mà trên các cổng OBDII người ra kết nối đó:
Hack hệ thống canbus trên ô tô

Hack hệ thống canbus trên ô tô

Hack hệ thống canbus trên ô tô

Còn đối với các DVD hàng market (hàng chợ) thì cái có cái không, hầu như là không.
Vậy với các DVD có đường CAN BUS cho các dòng xe thì nó có tích hợp sẵn ứng dụng để nhận lệnh điều khiển rồi. Cái đó chính là khi dùng khiển vô lăng để tăng âm lượng, chuyển bài .... đấy/

Còn ứng dụng để nối wince với cục OBDII thì nhằm mục đích gì? việc này khó vì cái DVD wince trên ô tô các kết nối ngoại vi nghèo làn, ko có USB host, ko có bluetooth bên main wince thì khó lắm. Với lại phần mềm cũng ko có cho wince vì nó đã hết thời.Giờ người ta đang chuyển sang android
 
Hạng B2
4/8/14
264
291
63
Hà nội
tranhchuthap.vn
Code file Python dùng điều khiển vô lăng cho Raspberry Pi chạy XBMC. Giá trị các nút bấm cần được thay thế bằng giá trị thật tìm theo mục 2 của bài viết ở trang 1 (2. Xác định mã lệnh các nút điều khiển của vô lăng trên Can-Bus)

import serial
import time
import requests
import json
import urllib

# Thiet lap ket noi JSON-PRC
#Required header for XBMC JSON-RPC calls, otherwise you'll get a
#415 HTTP response code - Unsupported media type
headers = {'content-type': 'application/json'}

#Host name where XBMC is running, leave as localhost if on this PC
#Make sure "Allow control of XBMC via HTTP" is set to ON in Settings ->
#Services -> Webserver
xbmc_host = 'localhost'

#Configured in Settings -> Services -> Webserver -> Port
xbmc_port = 8888
#Base URL of the json RPC calls. For GET calls we append a "request" URI
#parameter. For POSTs, we add the payload as JSON the the HTTP request body
xbmc_json_rpc_url = "http://" + xbmc_host + ":" + str(xbmc_port) + "/jsonrpc"

#//Thiet lap ket noi JSON-PRC

# Gan cac nut tren vo lang
up='3DA2'
down= '3DA1'
right='3DA2'
left='3DA3'
select='3DA4'
back='3DA5'
play_pause='3DA6'
home='3DA7'
shuthdown='3DA8'
# //Gan cac nut tren vo lang

def readlineCR(port):
rv = ""
while True:
ch = port.read()
rv += ch
if ch=='\r' or ch=='':
return rv

port = serial.Serial("/dev/ttyAMA0", baudrate=115200, timeout=3.0)

# Kiem tra xem da co ket noi chua, neu chua cho 5s sau kiem tra lai
while (port.isOpen() == False):
print("serial is not connected!")
time.sleep(5)


# Gui lenh dump CANBUS

port.write("ATL1\r")
port.write("ATH1\r")
port.write("ATSP0\r")
port.write("ATS1\r")
port.write("ATAL\r")
port.write("ATMA\r")

#if port.isOpen():
#print("serial is open!")

while True:
rcv = readlineCR(port)
if (rcv == play_pause):
#Payload for the method to get the currently playing / paused video or audio
payload = {"jsonrpc": "2.0", "method": "Player.GetActivePlayers", "id": 1}
url_param = urllib.urlencode({'request': json.dumps(payload)})

response = requests.get(xbmc_json_rpc_url + '?' + url_param, headers=headers)

#response.text will look like this if something is playing
#{"id":1,"jsonrpc":"2.0","result":[{"playerid":1,"type":"video"}]}
#and if nothing is playing:
#{"id":1,"jsonrpc":"2.0","result":[]}

data = json.loads(response.text)
#result is an empty list if nothing is playing or paused.
if data['result']:
#We need the specific "playerid" of the currently playing file in order
#to pause it
player_id = data['result'][0]["playerid"]

payload = {"jsonrpc": "2.0", "method": "Player.PlayPause","params": {"playerid": player_id }, "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

#response.text will look like this if we're successful:
#{"id":1,"jsonrpc":"2.0","result":{"speed":0}}

if (rcv == up):
payload = {"jsonrpc": "2.0", "method": "Input.Up", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)


if (rcv == down):
payload = {"jsonrpc": "2.0", "method": "Input.Down", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == right):
payload = {"jsonrpc": "2.0", "method": "Input.Right", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == left):
payload = {"jsonrpc": "2.0", "method": "Input.Left", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == select):
payload = {"jsonrpc": "2.0", "method": "Input.Select", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == back):
payload = {"jsonrpc": "2.0", "method": "Input.Back", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == home):
payload = {"jsonrpc": "2.0", "method": "Input.Home", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)

if (rcv == shuthdown):
payload = {"jsonrpc": "2.0", "method": "System.Shutdown ", "id": 1}
response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),headers=headers)
 
Chỉnh sửa cuối:
Hạng B2
25/7/12
129
107
43
Bác chủ cho em hỏi có thể lập trình để dùng đầu DVD điều khiển thiết bị trên xe như đèn, lock cửa, lên kính, gập gương được không ạ? Theo em nghĩ thì các thiết bị đó trên xe cỏ như KIA Sorento của em chắc ko có kết nối vào CANBUS rồi. Vậy thì có cách nào kết nối một thiết bị vào CANBUS để từ đó có thể được điều khiển bằng phần mềm không?
 
Hạng B2
4/8/14
264
291
63
Hà nội
tranhchuthap.vn
Bác chủ cho em hỏi có thể lập trình để dùng đầu DVD điều khiển thiết bị trên xe như đèn, lock cửa, lên kính, gập gương được không ạ? Theo em nghĩ thì các thiết bị đó trên xe cỏ như KIA Sorento của em chắc ko có kết nối vào CANBUS rồi. Vậy thì có cách nào kết nối một thiết bị vào CANBUS để từ đó có thể được điều khiển bằng phần mềm không?
Với một bo mạch phát triển (raspberry pi là một ví dụ) một chút kiến thức điện tử, một chút kiến thức lập trình thì ko gì là không thể cụ ạ. Chỉ có điều trong cháu chưa hội tụ đủ đc tất cả để làm việc này. Cụ thể là lập trình giao diện để điều khiển. Cháu vẫn đang tiếp tục timg hiểu và phát triển. Từng bước sẽ đạt đc và ẽ công bố hướng dẫn làm công khai, phi lợi nhuận. Giá cháu có thể kết hịp đc với cụ nào biết lập trình wince, android, ios và lập trình giao tiếp serial nữa là đủ bộ.
 
  • Like
Reactions: pplayer
Hạng B2
4/8/14
264
291
63
Hà nội
tranhchuthap.vn
Cụ thể là với yêu cầu của cụ thì lập trình để đưa tín hiệu điều khiển ra các chân gpio của raspberry pi sau đó lấy điện từ các chân này đưa về mạch điều khiển nơi đặt công tắc của các chức năng cụ cần, ghép qua một con đi ốt là cho nó cấy vào đc ạ
 
  • Like
Reactions: pplayer