PIC Vietnam

Go Back   PIC Vietnam > Robotics > Thực hành

Tài trợ cho PIC Vietnam
Trang chủ Đăng Kí Hỏi/Ðáp Thành Viên Lịch Bài Trong Ngày Vi điều khiển

Thực hành Bắt đầu làm một robot như thế nào? Mẹo vặt? Kỹ thuật? Công nghệ?... Hãy bắt tay vào việc...

Trả lời
 
Ðiều Chỉnh Xếp Bài
Old 27-03-2007, 02:16 AM   #346
omlun
Đệ tử 1 túi
 
Tham gia ngày: Mar 2007
Bài gửi: 25
:
cảm ơn anh F,anh F đề ra những đề tài hay quá!!
em đang tính tạo một giao diện bằng VB để điều khiển động cơ DC!
thông qua giao diện nhập các thông số ki.kp,kd và có luôn phần vẽ đồ thị
để so sánh 2 giải thuật diều khiển bằng PID và Nơ ron
omlun vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 27-03-2007, 04:18 PM   #347
falleaf
PIC Bang chủ
 
falleaf's Avatar
 
Tham gia ngày: May 2005
Bài gửi: 2,631
:
Send a message via Yahoo to falleaf
Cái này rất tốt, bạn có thể tham gia đề tài. Phần giao diện VB hoặc VC++ có thể được thiết kế đơn giản. Hôm nào mình sẽ vẽ một cái hình đơn giản lên để các bạn xem mẫu giao diện chương trình, và các bạn có thể thực hành trên bất kỳ phần mềm nào các bạn muốn, kể cả Matlab nếu muốn.

Chúc vui
falleaf vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 28-03-2007, 12:41 PM   #348
trungkien_0914373773
Đệ tử 1 túi
 
Tham gia ngày: Sep 2006
Bài gửi: 15
:
toi gui len mach ve dieu khien toc do dong co DC. Vao trang web cua no co ma nguon day. Toi cung chua lam mach that nen chua biet the nao?
trungkien_0914373773 vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 28-03-2007, 12:43 PM   #349
trungkien_0914373773
Đệ tử 1 túi
 
Tham gia ngày: Sep 2006
Bài gửi: 15
:
dong co DC

mach nguyen ly
File Kèm Theo
File Type: pdf mach dieu khien toc do dong co DC.pdf (10.5 KB, 743 lần tải)
trungkien_0914373773 vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 16-04-2007, 10:12 PM   #350
omlun
Đệ tử 1 túi
 
Tham gia ngày: Mar 2007
Bài gửi: 25
:
Trích:
Nguyên văn bởi bluepine View Post
Chào mọi người, em hiện đã điều khiển được động cơ dùng PID, số liệu khá chính xác (sai lệch về tốc độ rất nhỏ). Tuy nhiên chỉ điều khiển được với một tải cố định thôi, khi gỡ cục tải ra thì không còn đúng nữa nên em nghĩ các thông số PID thay đổi khi tải thay đổi. Anh F cho em hỏi có cách nào tính các thông số PID theo sự thay đổi của tải không?
Đây là chương trình em đã chạy tốt với 1 tải cố định

#include <16f877a.h>
#fuses HS,NOPROTECT,NOWDT,NOBROWNOUT
#use delay (clock = 20000000)
// Giao tiep vi dieu khien
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8) // Giao tiep RS232

#include <stdlib.h>
#include <string.h>
#include <math.h>
#include<ctype.h>

#byte PR2 = 0x92

int16 e2;
int16 e1;
///////////////////////////////////////////////////////

int16 v_set = 250;

/////////////////////////////////////////////////////////
int16 v_cur;
int16 e_sum;
int16 e_del;
int16 flag_timer1;


///////////////////////////////////////////////////////////
unsigned long kp =5;
unsigned long ki = 0.62;
unsigned long kd = 10;
////////////////////////////////////////////////////////////


int16 pw_duty;
int16 counted_round_value;
int16 temp_timer0;
int16 update_counted_round_value;

#byte TMR0 = 0x01 //timer0 REGISTER
#byte TMR1_L = 0X0E
#byte TMR1_H = 0X0F

#define START_VALUE_TIMER0 55 //tri khoi tao ban dau cua timer0 55, so xung dem duoc moi khi ngat la 255 - 55
#define START_VALUE_TIMER1 15535 //tri khoi tao ban dau cua timer1 65536-15536

#INT_TIMER0 // ngat timer0 tang bien len 1
void TIMER0_int()
{

set_timer0(START_VALUE_TIMER0);
counted_round_value++;

}

#INT_TIMER1 // ngat timer0 tang bien len 1
void timer1_int()
{

set_timer1(START_VALUE_TIMER1);


temp_timer0 = get_timer0();

if (temp_timer0 == 0){
temp_timer0 = 255;
}
v_cur = counted_round_value*400 + 2*(temp_timer0 - START_VALUE_TIMER0);
set_timer0(START_VALUE_TIMER0);
counted_round_value = 0;
//printf("%ld\t",pw_duty);
flag_timer1 = 1;
}


void init_timer0()
{

setup_timer_0(RTCC_EXT_H_TO_L | RTCC_DIV_2); // timer0 dung xung ngoai va chia xung vao


setup_timer_1(T1_INTERNAL | T1_DIV_BY_4); // moi lan tran timer1 la 50000*4* (1/5) uS = 40ms

set_timer0(START_VALUE_TIMER0);
set_timer1(START_VALUE_TIMER1);
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_TIMER1);
}

void init_PWM(int16 frequency){

setup_ccp1(CCP_PWM); // initiate PWM
PR2 = 20000000/4/frequency - 1; // set PWM period

setup_timer_2(T2_DIV_BY_1,255,1); // initiate time 2 The cycle time will be (1/clock)*4*t2div*(period+1)
// (1/20000000)*4*1*(255+1) = 51.2 us( will over flow every 51.2 us, will intrup every 51.2 uS or 19.5 khz;

}

void cal_pid(){

long temp_kp;
long temp_ki;
long temp_kd;
e2 = v_set - v_cur;
e_sum += e2;
e_del = e2 - e1;
e1 = e2;

temp_kp = kp*e2;
temp_ki = ki*e_sum;
temp_kd = kd*e_del;
pw_duty +=temp_kp;

if (pw_duty <1000)
pw_duty += temp_ki;
if (pw_duty <1000)
pw_duty += temp_kd;
if (pw_duty <256) // vi khi pw_duty <256 thi PWM chi dieu rong xung 8 bit / //chu khong phai 10 bit,
pw_duty = 256;
if (pw_duty >1000) // bao hoa
pw_duty = 1000;

printf(" \t%ld", v_cur); // truyen toc do xung ve may tinh hien thi tren Hyperterminal
}

void main()
{
int8 timer0_value;

init_timer0();
init_PWM(19500);

while(true){
if (flag_timer1 ==1){
flag_timer1 = 0;
cal_pid();
set_pwm1_duty(pw_duty);
}
}
}

mến

Bạn có thể cho mình biết thông số động cơ Dc cuả bạn.Và giải thích giùm đoạn code này cho mình được không:
v_cur = counted_round_value*400 + 2*(temp_timer0 - START_VALUE_TIMER0);

mình mới tập lập trình nên không rành lắm.
omlun vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 18-04-2007, 09:30 AM   #351
bluepine
Đệ tử 3 túi
 
Tham gia ngày: Jun 2006
Bài gửi: 53
:
Chào bạn,
thông số động cơ của tớ là:
Ra= 2.1 ohm; La = 3.3 mH, moment inertia: J = 5.5x10^(-4); Kt= 0.11N.m/A, damping ratio b= 0.29
Động cơ tớ mua là đồ second hand, cái nhãn bị mờ ròi nên nhìn không rõ, nên lên mạng tìm và thấy cái này có hình rất giống thôi, không biết chính xác hay không nữa.
còn về đoạn code trên thì tớ giải thích ngắn gọn thế này: tớ dùng timer0 ở chế độ ngắt tràn để đếm xung ngoài từ encoder, timer1 ở chế độ ngắt tràn.
đoạn chương trình trên có thể viết lại như sau

v_cur = timer0_interupt_number*2*(255 - START_VALUE_TIMER0) + 2*(get_timer0() - START_VALUE_TIMER0);

+ v_cur: số xung đếm được trong mỗi chu kì ngắt timer1
+ timer0_interupt_number: số làn timer0 tràn trong mỗi chu kì ngắt timer1
+ START_VALUE_TIMER0 giá trị nạp cho thanh ghi timer0 ban đầu
+ phải nhân 2 vì ở chế độ đếm xung ngoài thì scaler min =2, (coi datasheet)
+ Nhân (255 - START_VALUE_TIMER0) là số xung mỗi lần timer0 tràn
+ Cộng 2*(get_timer0() - START_VALUE_TIMER0) vì khi ngắt timer1 thì timer0 vẫn đang đếm nên phải cộng thêm giá trị hiện tại của timer0.
chút vui
bluepine vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 18-04-2007, 02:26 PM   #352
linhnc308
Đệ tử 5 túi
 
Tham gia ngày: Oct 2005
Bài gửi: 117
:
Code lập trình này trông quen quen. Trước cũng làm một chương trình điều khiển DC như vầy, thế chú e đã cho thủ vẽ đồ thị tín hiệu chưa. Còn về các tham số của bộ PID, sao ko dùng đường 232 và dùng ngắt 232 để truyền và cập nhật các tham số PID khi có tải thay đổi, như vậy sẽ test được với nhiều tải hơn và tìm ra dc bộ tham số thích hợp.
__________________
CallerID, Ethernet-RS232, PICWEB, Cảnh báo BTS
Giải pháp toàn diện giám sát - điều khiển từ xa qua GSM/Internet
0988006696

http://linhnc308.blogspot.com
linhnc308@gmail.com
linhnc308 vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 18-04-2007, 05:29 PM   #353
omlun
Đệ tử 1 túi
 
Tham gia ngày: Mar 2007
Bài gửi: 25
:
cảm ơn bạn nhiều!!vì tớ đang làm đồ án về đề tài này!!
omlun vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 18-04-2007, 08:26 PM   #354
nguyenphuocviet
Nhập môn đệ tử
 
Tham gia ngày: Oct 2005
Bài gửi: 3
:
Send a message via Yahoo to nguyenphuocviet
Anh F em hiện đang rất thích về PIC va đang chuẩn bi làm dề tài vê điều khiển DC nhưng diện giờ em chưa hình dung ra là bắt đầu từ đâu . Hiện em chỉ biết sơ về encoder, DC , và viet chương trình cho VDK họ 89** không ah .Còn về PIC thi ko biết , nhưng thời gian em làm dề tài chi có hờ gian là 2 tháng rưỡi thôi nên hi vọng các sư quynh chỉ giúp cho .
nguyenphuocviet vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 18-04-2007, 09:57 PM   #355
falleaf
PIC Bang chủ
 
falleaf's Avatar
 
Tham gia ngày: May 2005
Bài gửi: 2,631
:
Send a message via Yahoo to falleaf
Đọc lại từ đầu luồng này tới giờ, chắc chắn bạn sẽ có đầy đủ thông tin để làm đề tài. Về bắt đầu học PIC, đọc ở portal trang chủ, bên trái có cái "Dành cho người mới học".

Đọc từ đó đọc đi.

Chúc vui
falleaf vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 19-04-2007, 09:25 AM   #356
bluepine
Đệ tử 3 túi
 
Tham gia ngày: Jun 2006
Bài gửi: 53
:
Trích:
Nguyên văn bởi linhnc308 View Post
Code lập trình này trông quen quen. Trước cũng làm một chương trình điều khiển DC như vầy, thế chú e đã cho thủ vẽ đồ thị tín hiệu chưa. Còn về các tham số của bộ PID, sao ko dùng đường 232 và dùng ngắt 232 để truyền và cập nhật các tham số PID khi có tải thay đổi, như vậy sẽ test được với nhiều tải hơn và tìm ra dc bộ tham số thích hợp.
chào bạn,
tớ đã truyền tín hiệu về máy tính qua RS 232 , dùng matlab vẽ đồ thị rồi, nhưng kết quả vẫn chưa được tốt ( sai số xác lập và độ vọt lố còn lớn),
với lại đang test thì bổng nhiên động cơ chạy ầm ầm lên, rồi tớ tắt nguồn thì thấy cái cúc tản nhiệt trên cầu H nóng quá, sau đó bật nguồn lại thì động cơ không chạy nữa. kiểm tra thấy xuất VDk suất xung bình thường, chắc cái cầu cháy rồi, đang chuẩn bị mua con khác về thử.
bluepine vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 25-04-2007, 10:23 PM   #357
omlun
Đệ tử 1 túi
 
Tham gia ngày: Mar 2007
Bài gửi: 25
:
hiccc!! không thấy ai làm phần điều khiển DC dùng điều khiển PID với các thông số Ki,Kp,Kd nhập từ máy tính hết vậy
omlun vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 09-05-2007, 06:40 PM   #358
omlun
Đệ tử 1 túi
 
Tham gia ngày: Mar 2007
Bài gửi: 25
:
Trích:
Nguyên văn bởi bluepine View Post
Chào mọi người, em hiện đã điều khiển được động cơ dùng PID, số liệu khá chính xác (sai lệch về tốc độ rất nhỏ). Tuy nhiên chỉ điều khiển được với một tải cố định thôi, khi gỡ cục tải ra thì không còn đúng nữa nên em nghĩ các thông số PID thay đổi khi tải thay đổi. Anh F cho em hỏi có cách nào tính các thông số PID theo sự thay đổi của tải không?
Đây là chương trình em đã chạy tốt với 1 tải cố định

#include <16f877a.h>
#fuses HS,NOPROTECT,NOWDT,NOBROWNOUT
#use delay (clock = 20000000)
// Giao tiep vi dieu khien
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8) // Giao tiep RS232

#include <stdlib.h>
#include <string.h>
#include <math.h>
#include<ctype.h>

#byte PR2 = 0x92

int16 e2;
int16 e1;
///////////////////////////////////////////////////////

int16 v_set = 250;

/////////////////////////////////////////////////////////
int16 v_cur;
int16 e_sum;
int16 e_del;
int16 flag_timer1;


///////////////////////////////////////////////////////////
unsigned long kp =5;
unsigned long ki = 0.62;
unsigned long kd = 10;
////////////////////////////////////////////////////////////


int16 pw_duty;
int16 counted_round_value;
int16 temp_timer0;
int16 update_counted_round_value;

#byte TMR0 = 0x01 //timer0 REGISTER
#byte TMR1_L = 0X0E
#byte TMR1_H = 0X0F

#define START_VALUE_TIMER0 55 //tri khoi tao ban dau cua timer0 55, so xung dem duoc moi khi ngat la 255 - 55
#define START_VALUE_TIMER1 15535 //tri khoi tao ban dau cua timer1 65536-15536

#INT_TIMER0 // ngat timer0 tang bien len 1
void TIMER0_int()
{

set_timer0(START_VALUE_TIMER0);
counted_round_value++;

}

#INT_TIMER1 // ngat timer0 tang bien len 1
void timer1_int()
{

set_timer1(START_VALUE_TIMER1);


temp_timer0 = get_timer0();

if (temp_timer0 == 0){
temp_timer0 = 255;
}
v_cur = counted_round_value*400 + 2*(temp_timer0 - START_VALUE_TIMER0);
set_timer0(START_VALUE_TIMER0);
counted_round_value = 0;
//printf("%ld\t",pw_duty);
flag_timer1 = 1;
}


void init_timer0()
{

setup_timer_0(RTCC_EXT_H_TO_L | RTCC_DIV_2); // timer0 dung xung ngoai va chia xung vao


setup_timer_1(T1_INTERNAL | T1_DIV_BY_4); // moi lan tran timer1 la 50000*4* (1/5) uS = 40ms

set_timer0(START_VALUE_TIMER0);
set_timer1(START_VALUE_TIMER1);
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_TIMER1);
}

void init_PWM(int16 frequency){

setup_ccp1(CCP_PWM); // initiate PWM
PR2 = 20000000/4/frequency - 1; // set PWM period

setup_timer_2(T2_DIV_BY_1,255,1); // initiate time 2 The cycle time will be (1/clock)*4*t2div*(period+1)
// (1/20000000)*4*1*(255+1) = 51.2 us( will over flow every 51.2 us, will intrup every 51.2 uS or 19.5 khz;

}

void cal_pid(){

long temp_kp;
long temp_ki;
long temp_kd;
e2 = v_set - v_cur;
e_sum += e2;
e_del = e2 - e1;
e1 = e2;

temp_kp = kp*e2;
temp_ki = ki*e_sum;
temp_kd = kd*e_del;
pw_duty +=temp_kp;

if (pw_duty <1000)
pw_duty += temp_ki;
if (pw_duty <1000)
pw_duty += temp_kd;
if (pw_duty <256) // vi khi pw_duty <256 thi PWM chi dieu rong xung 8 bit / //chu khong phai 10 bit,
pw_duty = 256;
if (pw_duty >1000) // bao hoa
pw_duty = 1000;

printf(" \t%ld", v_cur); // truyen toc do xung ve may tinh hien thi tren Hyperterminal
}

void main()
{
int8 timer0_value;

init_timer0();
init_PWM(19500);

while(true){
if (flag_timer1 ==1){
flag_timer1 = 0;
cal_pid();
set_pwm1_duty(pw_duty);
}
}
}

mến

bạn có thể pót sơ đồ nguyên lý của mạch điều khiển động cơ l;ên ko??
xung encoder pha A ban nối vào chân nào vậy?
đọc xong code của bạn tớ đang tính làm 1 mạch để tét thử
omlun vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 11-05-2007, 09:57 AM   #359
bluepine
Đệ tử 3 túi
 
Tham gia ngày: Jun 2006
Bài gửi: 53
:
Smile

Chào bạn,
đây là sơ đồ nguyên lý của mạch điều khiển động cơ của mình, nếu bạn muốn test thử thì cứ dùng khối pic, khối cầu và khối Rs232 để gủi dữ liệu về máy tính là được rồi.
thân
File Kèm Theo
File Type: rar PICvietnam.rar (919 Bytes, 672 lần tải)
bluepine vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Old 12-05-2007, 06:07 PM   #360
omlun
Đệ tử 1 túi
 
Tham gia ngày: Mar 2007
Bài gửi: 25
:
cảm ơn bạn!!
mạch của mình ,do chân encoder mình đưa chân timer 1!
nên mình tính dùng timer 1 để đọc encoder, động cơ mình dùng có công
suất thấp với lại encoder 100 xung/1 vòng nên timer 1 ko sợ bị tràn
mình có sửa lại đoạn code của cậu cho phù hợp với mạch của mình!
khi chạy thử thì no báo lỗi
mong bạn giúp đỡ
Code:
#include <16f877a.h>
#fuses HS,NOPROTECT,NOWDT,NOBROWNOUT
#use delay (clock = 20000000)
// Giao tiep vi dieu khien
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8) // Giao tiep RS232

#include <stdlib.h>
#include <string.h>
#include <math.h>
#include<ctype.h>

#byte PR2 = 0x92

int16 e2;
int16 e1;
///////////////////////////////////////////////////////

int16 v_set = 250;

/////////////////////////////////////////////////////////
int16 v_cur;
int16 e_sum;
int16 e_del;
int16 flag_timer1;


///////////////////////////////////////////////////////////
unsigned long kp =5;
unsigned long ki = 0.62;
unsigned long kd = 10;
////////////////////////////////////////////////////////////

int16 i = 1 ;
int16 pw_duty;
int16 counted_round_value;
int16 temp_timer0;
int16 temp_timer1;
int16 update_counted_round_value;

#byte TMR0 = 0x01 //timer0 REGISTER
#byte TMR1_L = 0X0E
#byte TMR1_H = 0X0F

#define START_VALUE_TIMER0 5 //tri khoi tao ban dau cua timer0 5, so xung dem duoc moi khi ngat la 255 - 5
#define START_VALUE_TIMER1 5535 //tri khoi tao ban dau cua timer1 65536-5536=60000

#INT_TIMER0 // ngat timer0 tang bien len 1
void TIMER0_int()
{

set_timer0(START_VALUE_TIMER0);
i++;

}

void doc_xung()
{
if ( i==50 )

temp_timer1 = get_timer1();
set_timer1(START_VALUE_TIMER1);//lan tran thu 50 cua timer0 se set timer1
i=0;
if (temp_timer0 == 0){
temp_timer0= 255;
}
v_cur =  2*(temp_timer1 - START_VALUE_TIMER1);
set_timer1(START_VALUE_TIMER1);
i = 1;
//printf("%ld\t",pw_duty);
flag_timer1 = 1;
}


void init_timer0()
{

setup_timer_0(RTCC_INTERNAL | RTCC_DIV_16); // moi lan tran timer0 tuong ung 250*16*1/5 us = 0.8ms,chu ky lay mau=0.8*50=40ms


setup_timer_1(T1_EXTERNAL | T1_DIV_BY_1); // moi lan tran timer0 , khoi tao lai luon gia tri dem xung timer1

enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER0);

}

void init_PWM(int16 frequency){

setup_ccp1(CCP_PWM); // initiate PWM
PR2 = 20000000/4/frequency - 1; // set PWM period

setup_timer_2(T2_DIV_BY_1,255,1); // initiate time 2 The cycle time will be (1/clock)*4*t2div*(period+1)
// (1/20000000)*4*1*(255+1) = 51.2 us( will over flow every 51.2 us, will intrup every 51.2 uS or 19.5 khz;

}

void cal_pid(){

long temp_kp;
long temp_ki;
long temp_kd;
e2 = v_set - v_cur;
e_sum += e2;
e_del = e2 - e1;
e1 = e2;

temp_kp = kp*e2;
temp_ki = ki*e_sum;
temp_kd = kd*e_del;
pw_duty +=temp_kp;

if (pw_duty <800)
pw_duty += temp_ki;
if (pw_duty <800)
pw_duty += temp_kd;
if (pw_duty <256) // vi khi pw_duty <256 thi PWM chi dieu rong xung 8 bit / //chu khong phai 10 bit,
pw_duty = 256;
if (pw_duty >800) // bao hoa
pw_duty = 800;

printf(" \t%ld", v_cur); // truyen toc do xung ve may tinh hien thi tren Hyperterminal
}

void main()
{
int8 timer0_value;

init_timer0();
init_PWM(19500);

while(true){
if (flag_timer1 ==1){
flag_timer1 = 0;
cal_pid();
set_pwm1_duty(pw_duty);
}
}
}

thay đổi nội dung bởi: namqn, 12-05-2007 lúc 06:50 PM.
omlun vẫn chưa có mặt trong diễn đàn   Trả Lời Với Trích Dẫn
Trả lời


Quyền Sử Dụng Ở Diễn Ðàn
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is Mở
Smilies đang Mở
[IMG] đang Mở
HTML đang Tắt

Chuyển đến


Múi giờ GMT. Hiện tại là 05:21 AM.


Được sáng lập bởi Đoàn Hiệp
Powered by vBulletin®
Page copy protected against web site content infringement by Copyscape
Copyright © PIC Vietnam