From my previous post, We had addressed the hardware issue, installed Vivado 2019.2, and executed the demo program. We will interface with the IR sensors and will be discussing the Logical Implementation in this blog.
Logic Implementation
We will be using the five IR sensors to identify the black line. Based on the sensor data, the speed of the left and right motors are changed to catch and follow the line.
These conditions are applied to follow the line.
- When S3 is ON, both motors will move forward.
- When S4 or S5 is ON, the left motors will move forward.
- When S1 or S2 is ON, the right motors will move forward.
- When S1, S2, and S3 are ON, the left motors will move reverse and the right motor will move forward.
- When S3, S4, and S5 are ON, the left motors will move forward and the right motor will move reverse.
if mid_sensor detects black // Move Forward set left motor ON set right motor ON if right_sensor detects black // Move Right set left motor ON set right motor OFF else if left_sensor detects black // Move Left set left motor OFF set right motor ON endif
Create a Vivado Project file
We will be creating a sensors_test project to test the IR sensors and Motor Driver Shield.
Select RTL Project and make sure you select Do not specify sources at this time.
Select Arty S7-50 Board under the Boards tab.
Check the Project Summary and then Click the Finish button.
Click on Add Sources in the Project Manager and select Add or create constraints.
Select the constraints file for the Arty S7-50 board.
From the pinout, we will be using Digital I/O from IO0 to IO9 for this line follower application
image pinout
The IR Sensors are connected to the pins IO0, IO1, IO2, IO4, and IO7 and the motor driver pins are connected to IO3, IO5, IO6, and IO11. We will be updating the constraints as shown below.
## LEDs set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]; #IO_L16N_T2_A27_15 Sch=led[2] set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]; #IO_L17P_T2_A26_15 Sch=led[3] set_property -dict { PACKAGE_PIN E13 IOSTANDARD LVCMOS33 } [get_ports { led[2] }]; #IO_L17N_T2_A25_15 Sch=led[4] set_property -dict { PACKAGE_PIN F18 IOSTANDARD LVCMOS33 } [get_ports { led[3] }]; #IO_L16P_T2_A28_15 Sch=led1_g set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { led[4] }]; #IO_L14N_T2_SRCC_15 Sch=led0_g ## IR Sensors set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { sen[0] }]; #IO_0_14 Sch=ck_io[0] set_property -dict { PACKAGE_PIN N13 IOSTANDARD LVCMOS33 } [get_ports { sen[1] }]; #IO_L6N_T0_D08_VREF_14 Sch=ck_io[1] set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { sen[2] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=ck_io[2] set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { sen[3] }]; #IO_L13N_T2_MRCC_14 Sch=ck_io[4] set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { sen[4] }]; #IO_L16N_T2_A15_D31_14 Sch=ck_io[7] ## Motor Driver Pins #set_property -dict { PACKAGE_PIN R14 IOSTANDARD LVCMOS33 } [get_ports { left_m[0] }]; #IO_L13P_T2_MRCC_14 Sch=ck_io[3] #set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { left_m[1]}]; #IO_L14P_T2_SRCC_14 Sch=ck_io[5] #set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { right_m[0] }]; #IO_L14N_T2_SRCC_14 Sch=ck_io[6] #set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { right_m[1]}]; #IO_L22N_T3_A16_15 Sch=ck_io11_mos
Interfacing IR Sensors
IR transmits infrared lights. When infrared rays fall on the white surface, it’s reflected back and caught by photodiodes which generate some voltage changes. When IR light falls on a black surface, light is absorbed by the black surface and no rays are reflected back, thus photodiode does not receive any light or rays. We will be using the five IR sensors to identify the black line.
Let's add the design sources to the project.
Select SystemVerilog and name the file as top.sv
Add the following code to the top.sv file.
module top (
input wire logic [4:0] sen,
output logic [4:0] led
);
always_comb begin
led[0] = sen[0] ? 1'b1 : 1'b0;
led[1] = sen[1] ? 1'b1 : 1'b0;
led[2] = sen[2] ? 1'b1 : 1'b0;
led[3] = sen[3] ? 1'b1 : 1'b0;
led[4] = sen[4] ? 1'b1 : 1'b0;
end
endmodule
Now, let's test the above code - IR Sensors.
Interfacing Motor Driver
The H-Bridge Motor Drivers L298N is used to drive DC motors as they require much more current than the IO ports.
We will create design sources named "motor_control.sv" and "pwm.sv" and add the following code to the pwm.sv file.
module pwm (
input wire logic clk,
input wire logic [7:0] duty,
output logic pwm_out
);
logic [7:0] cnt = 8'b0;
always_ff @(posedge clk) begin
cnt <= cnt + 1;
end
always_comb pwm_out = (cnt < duty);
endmodule
Add the following code to the motor_control.sv file.
module motor_control(
input wire logic clk,
output logic [1:0] left_m, [1:0] right_m
);logic [7:0] speed = 8'd0;
pwm in1 (.clk, .duty(speed), .pwm_out(left_m[0]));
pwm in2 (.clk, .duty(speed+255), .pwm_out(left_m[1]));
pwm in3 (.clk, .duty(speed), .pwm_out(right_m[0]));
pwm in4 (.clk, .duty(speed+250), .pwm_out(right_m[1]));endmodule
Now, let's test the above code - Motor Control (PWM)
Yay! Now the Hardware is ready to be programmed. Next, we will be assembling the Hardware components in the next blog.