TRƯỜNG ĐẠI HỌC GIAO THÔNG VẬN TẢI THÀNH PHỐ HỒ CHÍ MINH KHOA ĐIỆN – ĐIỆN TỬ VIỄN THÔNG ĐO LƯỜNG VÀ ĐIỀU KHIỂN BẰNG MÁY TÍNH TRUYỀN THÔNG NỐI TIẾP GIỮA PC VÀ ARDUINO SỬ DỤNG CẢM BIẾN GÓC NGHIÊNG MPU 60[.]
Trang 1TRƯỜNG ĐẠI HỌC GIAO THÔNG VẬN TẢI THÀNH PHỐ HỒ CHÍ MINH
KHOA ĐIỆN – ĐIỆN TỬ VIỄN THÔNG
ĐO LƯỜNG VÀ ĐIỀU KHIỂN BẰNG MÁY TÍNH
TRUYỀN THÔNG NỐI TIẾP GIỮA PC VÀ ARDUINO
SỬ DỤNG CẢM BIẾN GÓC NGHIÊNG MPU 6050
Giảng viên hướng dẫn: Th.S Lê Mạnh Thắng
Nhóm thực hiện: Nhóm 16
Trần Ngọc Sơn 2051050173 TD20D Đoàn Thành Đạt 2051050086 TD20A Trần Xuân Tín 2051050185 TD20D
Thành phố Hồ Chí Minh, ngày 08 tháng 04 năm 2023
Trang 2MỤC LỤC
LỜI NÓI ĐẦU 3
CHƯƠNG 1 TÌM HIỂU VỀ CẢM BIẾN GY-521 6DOF IMU MPU6050 4
1.1 Giới thiệu về cảm biến GY-521 6DOF IMU MPU6050 4
1.2 Thông số kỹ thuật cảm biến GY-521 6DOF IMU MPU6050 4
1.3 Chức năng các chân cảm biến GY-521 6DOF IMU MPU6050 5
1.4 Ứng dụng cảm biến GY-521 6DOF IMU MPU6050 5
CHƯƠNG 2 CODE LẬP TRÌNH ARDUINO 6
2.1 Thư viện sử dụng 6
2.2 Thời gian đọc và truyền dữ liệu 6
2.3 Khung dữ liệu truyền lên máy tính 6
2.4 Code Arduino 6
CHƯƠNG 3 CODE C# VÀ GIAO DIỆN 8
3.1 Code C# lập trình 8
3.2 Giao diện Winforms 17
CHƯƠNG 4 KẾT QUẢ THỰC HIỆN 18
4.1 Hình ảnh thực tế 18
4.2 Kiểm chứng kết quả và đánh giá sai số 18
4.3 Video thuyết trình 19
Trang 3LỜI NÓI ĐẦU
Chúng ta có thể thấy rằng cảm biến góc nghiêng được ứng dụng trong nhiều lĩnh vực Ví dụ như hệ thống cân bằng trong drone, thước đo góc, tripod, các mô hình trong không gian 3D, v.v Đề tài của nhóm em sẽ sử dụng cảm biến góc nghiêng MPU6050
dể khảo sát các trục X, Y, Z Xem sai số của cảm biến so với thực tế và mức độ ảnh hưởng lẫn nhau của 3 trục
Trang 4CHƯƠNG 1 TÌM HIỂU VỀ CẢM BIẾN GY-521 6DOF IMU MPU6050 1.1 Giới thiệu về cảm biến GY-521 6DOF IMU MPU6050
Cảm biến GY-521 6DOF IMU MPU6050 là IC tích hợp cảm biến tích gia tốc kế
và cảm biến từ trường Nó thường được sử dụng để nhận biết 6 thông số: 3 trục Góc quay (Gyro), 3 trục gia tốc hướng (Accelerometer) Ngoài ra, từ các giá trị này, người
ta cho đi qua các bộ lọc số (AHRS Kalman, v.v) để thu được giá trị đã loại bỏ nhiễu
Hình 1 Cảm biến MPU 6050
Các giá trị này tiếp tục được dùng để xác định các giá trị thứ cấp như tốc độ dài, tọa độ không gian, gia tốc góc, vận tốc góc, góc quay với độ chính xác lên tới 0.01 độ,
đo gia tốc, vận tốc chuyển động tịnh tiến
Module cảm biến MPU 6050 có thể kết nối với vi điều khiển qua 1 trong 2 giao thức là SPI hoặc I2C MPU 6050 còn có 1KB bộ nhớ để lưu trữ lệnh từ vi điều khiển
và dữ liệu sau khi nó tính toán xong các giá trị đo được
Cảm biến MPU 6050 không có tính năng chuyển từ tín hiệu analog sang digital Cảm biến này nhận biết các tín hiệu giá trị gia tốc góc nghiêng Sau đó, các tín hiệu này sẽ được truyền sang vi mạch chuyển đổi tín hiệu trong MPU 6050 được gọi là Digital Motion Processor (DMP) Thiết bị này tích hợp nhiều tính năng xử lý tín hiệu
và lưu trữ dữ liệu đa dạng Nó tính toán góc quay và gia tốc trong thời gian thực và truyền dữ liệu này đến vi điều khiển thông qua giao tiếp I2C hoặc SPI Các tín hiệu đi qua DMP sẽ trở thành tín hiệu chuẩn hóa (dạng analog) Khi đó, nhờ vào tính năng ADC của Arduino sẽ chuyển đổi tín hiệu từ dạng analog này sang digital
1.2 Thông số kỹ thuật cảm biến GY-521 6DOF IMU MPU6050
Điện áp sử dụng: 3~5VDC
Điện áp giao tiếp: 3~5VDC
Chuẩn giao tiếp: I2C
Giá trị góc quay (Gyroscopes):
Trục X: từ -250 đến +250 độ/giây
Trục Y: từ -250 đến +250 độ/giây
Trang 5 Trục Z: từ -250 đến +250 độ/giây.
Giá trị gia tốc (Acceleration):
Trục X: từ -2g đến +2g
Trục Y: từ -2g đến +2g
Trục Z: từ -2g đến +2g
Giao tiếp: I2C, SPI
Hỗ trợ AD 16 Bit
1.3 Chức năng các chân cảm biến GY-521 6DOF IMU MPU6050
dụng cảm biến GY-521 6DOF IMU MPU6050
Đây là loại cảm biến gia tốc phổ biến nhất trên thị trường hiện nay Các ứng dụng và code dành cho nó rất nhiều và hầu như có trên mọi loại vi điều khiển MPU6050 sẽ là sự lựa chọn tối ưu cho các ứng dụng như:
Mô hình như con lắc động
Xe tự cân bằng
Các thiết bị ổn định hình ảnh, chống rung
Các ứng dụng điều khiển không tiếp xúc
Các ứng dụng nhận biết chuyển động
Thiết bị game, ứng dụng cầm tay
Các thí nghiệm, đo lường
VCC 5V/3V3
GND 0V
SCL Chân SCL trong giao tiếp I2C
SDA Chân SDA trong giao tiếp I2C
XDA Chân dữ liệu (kết nối với cảm biến khác)
XCL Chân xung (kết nối với cảm biến khác)
AD0 Bit0 của địa chỉ I2C
INT Chân ngắt
Trang 6CHƯƠNG 2 CODE LẬP TRÌNH ARDUINO
2.1 Thư viện sử dụng
MPU6050_tockn.h
Thư viện của cảm biến MPU 6050
Wire.h
Thư viện dùng để gửi và nhận dữ liệu giữa cảm biến MPU 6050 và Arduino
2.2 Thời gian đọc và truyền dữ liệu
Delay(200)
Lệnh delay mỗi 200ms arduino gửi giá trị lên 1 lần
2.3 Khung dữ liệu truyền lên máy tính
mpu6050.update()
Lệnh update các giá trị của MPU 6050
float x = mpu6050.getAngleX();
float y = mpu6050.getAngleY();
float z = mpu6050.getAngleZ();
Dùng float để định nghĩa số thực x,y,z, bằng các giá trị trục x,y,z
Serial.println ("X" + String(x) + "Y" + String(y) + "Z" + String(z) )
Gửi lên pc chuỗi
2.4 Code Arduino
//include thư viện của mpu 6050
#include <MPU6050_tockn.h>
#include <Wire.h>
// thiết lập thư viện wire
void setup()
{
Serial.begin(9600);
Wire.begin();
mpu6050.begin();
mpu6050.calcGyroOffsets(false);
}
void loop()
{
Trang 7// lệnh update các giá trị của mpu6050
mpu6050.update();
// dùng float để định nghĩa số thực x,y,z, bằng các giá trị trục x,y,z float x = mpu6050.getAngleX();
float y = mpu6050.getAngleY();
float z = mpu6050.getAngleZ();
// gửi lên pc chuỗi
Serial.println ("X" + String(x) + "Y" + String(y) + "Z" + String(z) ); // vidu X0Y0Z0
//lệnh delay mỗi 200ms arduino gửi giá trị lên 1 lần
delay(200);
}
Trang 8CHƯƠNG 3 CODE C# VÀ GIAO DIỆN
3.1 Code C# lập trình.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;
using static System.Windows.Forms.VisualStyles.VisualStyleElement; using System.Reflection.Emit;
using ZedGraph;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
#region Form
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
string[] BaudRate = {"9600"};
cbxbaud.Items.AddRange(BaudRate);
}
private void Form1_Load(object sender, EventArgs e)
Trang 9{
cbxtencom.DataSource = SerialPort.GetPortNames();
cbxbaud.Text = "9600";
// khoi tao bieu do goc X
GraphPane mypanel1 = zedGraphControl1.GraphPane;
mypanel1.Title.Text = "Giá trị góc nghiêng X";
mypanel1.YAxis.Title.Text = "Giá trị ";
mypanel1.XAxis.Title.Text = "Thời gian";
// khoi tao bieu do goc Y
GraphPane mypanel2 = zedGraphControl2.GraphPane;
mypanel2.Title.Text = "Giá trị góc nghiêng Y";
mypanel2.YAxis.Title.Text = "Giá trị ";
mypanel2.XAxis.Title.Text = "Thời gian";
// khoi tao bieu do goc Z
GraphPane mypanel3 = zedGraphControl3.GraphPane;
mypanel3.Title.Text = "Giá trị góc nghiêng Z";
mypanel3.YAxis.Title.Text = "Giá trị ";
mypanel3.XAxis.Title.Text = "Thời gian";
// khoi tao bieu do 3 goc X Y Z
GraphPane mypanel4 = zedGraphControl4.GraphPane;
mypanel4.Title.Text = "Giá trị góc nghiêgn X, Y, Z";
mypanel4.YAxis.Title.Text = "Giá trị ";
mypanel4.XAxis.Title.Text = "Thời gian";
//thiet lam muc list gia tri co the chay toi da 50000 so
RollingPointPairList list1 = new RollingPointPairList(50000); RollingPointPairList list2 = new RollingPointPairList(50000); RollingPointPairList list3 = new RollingPointPairList(50000); RollingPointPairList list4 = new RollingPointPairList(50000); RollingPointPairList list5 = new RollingPointPairList(50000); RollingPointPairList list6 = new RollingPointPairList(50000);
Trang 10//thiet lap duong line truc X, Y, Z add lan luot vao panel1,2,3 de hien thi tren 3 do thi X Y Z
//do thi 1 la góc X
//do thi 2 la goc y
//do thi 3 la goc z
LineItem line1 = mypanel1.AddCurve("goc X", list1, Color.Red, SymbolType.None);
LineItem line2 = mypanel2.AddCurve("goc Y", list2, Color.Blue, SymbolType.None);
LineItem line3 = mypanel3.AddCurve("goc Z", list3, Color.Black, SymbolType.None);
//thiet lap duong line x,y,Z vao do thi 4
//do thi 4 la do thi so sanh 3 goc xyz
LineItem line4 = mypanel4.AddCurve("goc X", list1, Color.Red, SymbolType.None);
LineItem line5 = mypanel4.AddCurve("goc Y", list2, Color.Blue, SymbolType.None);
LineItem line6 = mypanel4.AddCurve("goc Z", list3, Color.Black, SymbolType.None);
//khoang cach cach trong bieu do truc X
mypanel1.YAxis.Scale.Min = -100;
mypanel1.YAxis.Scale.Max = 100;
mypanel1.YAxis.Scale.MinorStep = 10;
mypanel1.YAxis.Scale.MajorStep = 20;
zedGraphControl1.AxisChange();
//khoang cach cach trong bieu do truc y
Trang 11
mypanel2.YAxis.Scale.Min = -100;
mypanel2.YAxis.Scale.Max = 100;
mypanel2.YAxis.Scale.MinorStep = 10;
mypanel2.YAxis.Scale.MajorStep = 20;
zedGraphControl2.AxisChange();
//khoang cach cach trong bieu do truc z
mypanel3.YAxis.Scale.Min = -100;
mypanel3.YAxis.Scale.Max = 100;
mypanel3.YAxis.Scale.MinorStep = 10;
mypanel3.YAxis.Scale.MajorStep = 20;
zedGraphControl3.AxisChange();
//khoang cach cach trong bieu do goc so sanh xyz
mypanel4.YAxis.Scale.Min = -100;
mypanel4.YAxis.Scale.Max = 100;
mypanel4.YAxis.Scale.MinorStep = 10;
mypanel4.YAxis.Scale.MajorStep = 20;
zedGraphControl4.AxisChange();
}
int tong = 0;
public void draw1 (double line1) // ve duong x trong bieu do goc x
{
LineItem duongline1 = zedGraphControl1.GraphPane.CurveList[0] as LineItem;
Trang 12if (duongline1 == null )
{
return;
}
IPointListEdit list1 = duongline1.Points as IPointListEdit;
if (list1 == null)
{
return;
}
list1.Add(tong, line1);
zedGraphControl1.AxisChange();
zedGraphControl1.Invalidate();
tong += 2;
}
public void draw2(double line2)
{
LineItem duongline2 = zedGraphControl2.GraphPane.CurveList[0] as LineItem;
if (duongline2 == null)
{
return;
}
IPointListEdit list2 = duongline2.Points as IPointListEdit;
if (list2 == null)
{
return;
}
list2.Add(tong, line2);
zedGraphControl2.AxisChange();
zedGraphControl2.Invalidate();
tong += 2;
}
Trang 13public void draw3(double line3)
{
LineItem duongline3 = zedGraphControl3.GraphPane.CurveList[0] as LineItem;
if (duongline3 == null)
{
return;
}
IPointListEdit list3 = duongline3.Points as IPointListEdit;
if (list3 == null)
{
return;
}
list3.Add(tong, line3);
zedGraphControl3.AxisChange();
zedGraphControl3.Invalidate();
tong += 2;
}
public void draw4(double line4)
{
LineItem duongline4 = zedGraphControl4.GraphPane.CurveList[0] as LineItem;
if (duongline4 == null)
{
return;
}
IPointListEdit list4 = duongline4.Points as IPointListEdit;
if (list4 == null)
{
return;
}
list4.Add(tong, line4);
Trang 14zedGraphControl4.Invalidate();
tong += 2;
}
public void draw5(double line5)
{
LineItem duongline5 = zedGraphControl4.GraphPane.CurveList[1] as LineItem;
if (duongline5 == null)
{
return;
}
IPointListEdit list5 = duongline5.Points as IPointListEdit;
if (list5 == null)
{
return;
}
list5.Add(tong, line5);
zedGraphControl4.AxisChange();
zedGraphControl4.Invalidate();
tong += 2;
}
public void draw6(double line6)
{
LineItem duongline6 = zedGraphControl4.GraphPane.CurveList[2] as LineItem;
if (duongline6 == null)
{
return;
}
IPointListEdit list6 = duongline6.Points as IPointListEdit;
if (list6 == null)
Trang 15{
return;
}
list6.Add(tong, line6);
zedGraphControl4.AxisChange();
zedGraphControl4.Invalidate();
tong += 2;
}
private void Form1_KeyDown(object sender, KeyEventArgs e) {
switch (e.KeyCode)
{
case Keys.Escape:
{
Close();
break;
}
}
}
#endregion
private void btnconnect_Click(object sender, EventArgs e) {
UART.PortName = cbxtencom.Text;
UART.Open();
if (UART.IsOpen)
{
MessageBox.Show("KET NOI COM THANH CONG"); }
}
Trang 16private void btndisconnect_Click(object sender, EventArgs e)
{
UART.Close();
MessageBox.Show("NGAT KET NOI COM THANH CONG");
}
private void UART_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string Alldata = "";
Alldata = UART.ReadLine();// chuoi Alldata bang du lieu duoc gui len tu arduino
Alldata = Alldata.Trim();//
int len = Alldata.Length;
if (len > 0)
{
//ham gui len co gia tri X0Y0Z0
int gcX = Alldata.IndexOf('X');// ham tim vi tri chu X
int gcY = Alldata.IndexOf('Y');// ham tim vi tri chu Y
int gcZ = Alldata.IndexOf('Z');// ham tim vi tri chu Z
//=> cac gia tri xyz gui len can xac dinh dung vi tri
//tach cac du lieu ra rieng
string gocx = Alldata.Substring(gcX + 1,gcY - gcX- 1);// chuoi se bat dau tu sau chu x
string gocy = Alldata.Substring(gcY + 1,gcZ - gcY - 1);
string gocz = Alldata.Substring(gcZ + 1);
//=> tinh toan tach du lieu cac goc ra bang canh gia su bat dau tu goc x
// hien thi nhung du lieu vua tach ra text box
txbx.Text = gocx;// in goc x ra textbox
txby.Text = gocy;// in goc y ra textbox
Trang 17txbz.Text = gocz;// in goc z ra textbox
// in du lieu ra do thi
Invoke(new MethodInvoker(() => draw1(Convert.ToDouble(gocx)))); Invoke(new MethodInvoker(() => draw2(Convert.ToDouble(gocy)))); Invoke(new MethodInvoker(() => draw3(Convert.ToDouble(gocz)))); Invoke(new MethodInvoker(() => draw4(Convert.ToDouble(gocx)))); Invoke(new MethodInvoker(() => draw5(Convert.ToDouble(gocy)))); Invoke(new MethodInvoker(() => draw6(Convert.ToDouble(gocz))));
}
}
}
3.2 Giao diện Winforms
Hình 2 Giao diện Winforms
Trang 18CHƯƠNG 4 KẾT QUẢ THỰC HIỆN
4.1 Hình ảnh thực tế
Hình 3 Mô hình thực tế
4.2 Kiểm chứng kết quả và đánh giá sai số
Dải đo 0 độ
Trục X : kết quả góc đo trong khoảng 1.12 độ sai số khoảng 1.12 %
Trục Y : kết quả góc đo trong khoảng 0.35 độ sai số khoảng 0.35 %
Trục Z : kết quả góc đo trong khoảng 0.67 độ sai số khoảng 0.67 %
Kết luận ở dải đo 0 độ
Các trục đo không giữ vững kết quả đo ở 0 độ, lý do có thể do đế đạt cảm biến chưa đảm bảo chất lượng
Dải đo 45 độ
Khi nghiêng trục X theo thước 45 độ
Trục X : kết quả góc đo giao động trong khoảng 43 độ sai số khoảng 4.4%
Trục Y : thay đổi khoảng 0.3 độ
Trục Z : thay đổi 1.5 độ
Khi nghiêng trục Y theo thước 45 độ
Trục Y : kết quả góc đo giao động trong khoảng 43.5 độ sai số khoảng 3.3%
Trục X : thay đổi khoảng 0.45 độ
Trục Z : thay đổi 2 độ
Khi nghiêng trục Z theo thước 45 độ