우선, 감응신호란?
교차로로 들어오는 각 도로에서 차량이 진입하거나 보행자의 유무에 따라서 신호를 자동으로 부여하는 신호체계를 말합니다.
즉 차가 별로 다니지 않는 도로에 차가 대기한다면 신호를 바꿔주는 것입니다.
좌회전 차선, 횡단보도도 마찬가지 입니다.
Verilog 를 공부하던 도중 신호등 예제를 만들어 봤는데
FPGA에 동작시켜보면 재밌겠다! 싶어서 기획하여 구현하게 되었습니다.
위와 같이 어떠한 센서를 통해 들어온 값을 토대로 zynq 보드에서 신호등처럼 나타내었습니다.
저는 라즈베리파이와 zynq를 소켓통신을 통해서 연결한 뒤에
라즈베라파이에 달려 있는 초음파 센서를 활용해서 감응신호를 잡아내어 보낼 것 입니다.
차가 있는지 없는지 판단한 데이터를 zynq에서 차의 유무에 맞게 처리할 것입니다.
신호등의 RED, GREEN, YELLOW 불빛은 RGB LED를 활용해서 나타내었습니다.
라즈베리파이 4 4GB, Zybo-z7-20, Vivado 18.3 에서 진행하였습니다.
라즈베리파이 client code
< Client.c >
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <wiringPi.h>
void error_handling(char* message);
const int pinEcho = 22;
const int pinTrigger = 21;
int main(int argc, char* argv[])
{
int clnt_sock;
struct sockaddr_in serv_addr;
char message[1024] = {0x00, };
wiringPiSetup();
pinMode(pinEcho, INPUT);
pinMode(pinTrigger, OUTPUT);
digitalWrite(pinTrigger, LOW);
delay(30);
clnt_sock = socket(PF_INET, SOCK_STREAM, 0);
if(clnt_sock == -1)
error_handling("socket error");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
serv_addr.sin_port = htons(atoi(argv[2]));
if(connect(clnt_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
error_handling("connect error");
char msg[] = "Car_ON";
char msg2[] = "Car_OFF";
while(1)
{
digitalWrite(pinTrigger, HIGH);
delayMicroseconds(20);
digitalWrite(pinTrigger, LOW);
while(digitalRead(pinEcho)==LOW);
long startTime = micros();
while(digitalRead(pinEcho)==HIGH);
long endTime = micros()-startTime;
int distance = endTime / 58;
if(distance <10) {
write(clnt_sock, msg, sizeof(msg));
printf("Send message :%s\n", msg);
}
else {
write(clnt_sock, msg2, sizeof(msg));
printf("Send message :%s\n", msg2);
}
delay(1000);
}
if(read(clnt_sock, message, sizeof(message)-1) == -1)
error_handling("read error");
printf("Message from server :%s\n", message);
close(clnt_sock);
return 0;
}
void error_handling(char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
FSM 신호등 verilog code
vivodo 내에서 한글로 주석처리를 하면 깨져 영문으로 주석처리 하였습니다.
< traffic_light_control.v >
module traffic_light (reset_n,X,clk,main_G, main_R, cntry_G, cntry_R);
input reset_n;
input X;
input clk;
output main_G, main_R;
output cntry_G, cntry_R;
reg main_G, main_R;
reg cntry_G, cntry_R;
reg [2:0] state;
reg [2:0] next_state;
reg [27:0] counter;
//parameter RED = 2'b00, YELLOW = 2'b01, GREEN = 2'b11;
parameter LED_ON = 1'b1 , LED_OFF = 1'b0;
parameter S0 = 3'b000, // main : Green, cntry : RED
S1 = 3'b001, // main : Yellow, cntry : RED
S2 = 3'b010, // main : RED, cntry : RED
S3 = 3'b011, // main : RED, cntry : Green
S4 = 3'b100; // main : RED, cntry : Yellow
always @(posedge clk or negedge reset_n) begin
if(!reset_n) begin
state <= S0;
counter <= 0;
end
else if(state == S1 || state == S2 || state == S4) begin
if(counter == 28'b1011111010111100001000000000) begin // Axi clk Freq = 100MHz , 2sec delay = 200,000,000
state <= next_state;
counter <= 0;
end
else counter <= counter +1;
end
else
state <= next_state;
end
always @(state) begin
case(state)
S0 : begin
// default setting
// main : Green, cntry : Red
cntry_G <= LED_OFF;
cntry_R <= LED_ON;
main_G <= LED_ON;
main_R <= LED_OFF;
end
S1 : begin
// main : Yellow, cntry : Red
main_G <= LED_ON;
main_R <= LED_ON;
cntry_G <= LED_OFF;
cntry_R <= LED_ON;
end
S2 : begin
// main : RED, cntry : RED
main_G <= LED_OFF;
main_R <= LED_ON;
cntry_G <= LED_OFF;
cntry_R <= LED_ON;
end
S3 : begin
// main : RED, cntry : Green
main_G <= LED_OFF;
main_R <= LED_ON;
cntry_G <= LED_ON;
cntry_R <= LED_OFF;
end
S4 : begin
// main : RED, cntry : Yellow
main_R <= LED_ON;
main_G <= LED_OFF;
cntry_G <= LED_ON;
cntry_R <= LED_ON;
end
endcase
end
always @(state or X) begin
case (state)
S0 : if(X) // car_on -> next state
next_state <= S1;
else
next_state <= S0;
S1 :
next_state <= S2;
S2 :
next_state <= S3;
S3 : if(X) // car_on -> current state
next_state <= S3;
else
next_state <= S4;
S4 :
next_state <= S0;
default : next_state <= S0;
endcase
end
endmodule
신호의 딜레이는 counter 를 활용하여 지연을 시켰고
AXI 클럭 주파수가 100 Mhz로 설정하였고
counter는 200M (2초)를 딜레이 하였습니다
Axi 인터페이스와 신호등 코드를 연결하는 구문을 추가 하였습니다.
main_out[0] = RED, main_out[1] = GREEN
cntry_out[0] = GREEN, cntry_out[1] = RED
YELLOW 색은 RED와 GREEN색을 섞어서, 즉 [0], [1] 을 둘다 1로 만들어서 LED 2개를 켜도록 하였습니다.
AXI 인터페이스를 이용하여 제가 만든 신호등 ip를 추가하여 디자인을 구성했습니다.
SDK 내에서 [ IwIP Echo Server ] 템플릿을 활용해서 진행하였습니다.
헤더를 추가하고
#include "xparameters.h" #include "xbasic_types.h" #include "xil_io.h" |
기본적으로 만들어지는 echo.c 파일에 아래의 코드를 첨가해
제가 구성한 AXI 인터페이스에 맞게 들어 오는 센서값을 제어하도록 하였다.
보드 ip에 맞게 socket을 해주면 된다.
< 시연 영상 >
2개의 LED 중 오른쪽 LED가 메인 도로의 LED로서 기본적으로 초록불이 점등되어 있습니다.
허나 자동차가 감지 되면 신호가 바뀌게 됩니다.
'개인프로젝트' 카테고리의 다른 글
라즈베리파이 프로젝트 "스마트 선풍기" 만들기 (term project) (2) | 2021.05.31 |
---|---|
[OPENCV] OPENCV를 활용한 이미지 게임 만들기 (C언어 사과 찾기 게임) (0) | 2021.05.11 |
[C언어] 미로찾기 게임 만들기 (Maze Game) 프로젝트 (11) | 2021.01.01 |
소켓통신으로 받은 데이터 Firebase Database에 저장 후 안드로이드에서 실시간 읽기 (0) | 2020.09.03 |