In this lab, you will learn about the functionality of the IR sensors of your TI RSLK-Max robotics kit, and will be provided modules to make them functional within your Verilog code. With this module, and the skills you have learned over the course of these labs, you will be tasked with your final project for this lab course, creating a control system to have your car intercept and follow a black line marking on the ground
IR SensorsThe IR Sensors are located on the bottom of the car, eight of them in a row, right behind the front caster wheel indentation. They work by projecting an invisible-to-the-naked-eye infrared light onto the ground, and measuring how much of that IR light is reflected back up at the car. See the image below for visual reference, as well as the pin map for interfacing these sensors into your Verilog code.
// @MAP_IO ir_evenLED 12
// @MAP_IO ir_oddLED 14
// @MAP_IO ir_snsrch0 18
// @MAP_IO ir_snsrch1 19
// @MAP_IO ir_snsrch2 20
// @MAP_IO ir_snsrch3 21
// @MAP_IO ir_snsrch4 22
// @MAP_IO ir_snsrch5 23
// @MAP_IO ir_snsrch6 24
// @MAP_IO ir_snsrch7 25
The pulsing and measuring of the IR LEDs actually happen along the same channel, so to facilitate this we are using a new type of module variable called an inout; see below for how you should declare them in your fpga_top module.
inout wire ir_snsrch0, ir_snsrch1, ir_snsrch2, ir_snsrch3, ir_snsrch4, ir_snsrch5, ir_snsrch6, ir_snsrch7,
The even and odd LED channels should both be outputs; these turn the even number IR LEDs (0, 2, 4, 6) and the odd numbered LEDs (1, 3, 5, 7) on, respectively. The IR LED control module has logic within it to automatically turn the IR LEDs on and off then they need to be.
The basic idea behind the IR LED modules is measuring the time to decay of the IR sensors. We bounce IR light off the ground and into these IR sensors, the corresponding signals of which we have set to high by way of using the inout as an output. Then, in our IR sensors module, we keep track of how long it takes the high signal to decay down to zero, measuring the inout as an input into our module. We set the inout ports as an input by setting their value to high impedance. Extremely white surfaces will decay the sensor’s high value very quickly, while black values will have a very high time to decay. By measuring this time to decay value (henceforth referred to as ttd) for each of the 8 IR sensors, we can intuit with pretty good accuracy where our car is relative to the black line. Let’s take a look at the IR sensor modules we’re providing you. We have a core IR sensor control module, which itself instantiates 8 submodules to measure the ttd of each of the IR sensors. We also included a basic timer module necessary to measure the ttd that will be instantiated in each of the 8 submodules, as well as a PWM module we use to selectively pulse the IR LED outputs to save on power.
module IRcontrol (
input wire clk,
input wire [7:0] channel_sel,
inout wire ir_snsrch0, ir_snsrch1, ir_snsrch2, ir_snsrch3,
ir_snsrch4, ir_snsrch5, ir_snsrch6, ir_snsrch7,
output wire[16:0] ttd0, ttd1, ttd2, ttd3, ttd4, ttd5, ttd6, ttd7,
output wire ir_evenLED, ir_oddLED
);
wire ir_evenLED_en, ir_oddLED_en;
pwm irevenLED (clk, ir_evenLED_en, 16'd16000, ir_evenLED);
pwm iroddLED (clk, ir_oddLED_en, 16'd16000, ir_oddLED);
IRread ch0 (clk, channel_sel[0], ir_snsrch0, ttd0);
IRread ch1 (clk, channel_sel[1], ir_snsrch1, ttd1);
IRread ch2 (clk, channel_sel[2], ir_snsrch2, ttd2);
IRread ch3 (clk, channel_sel[3], ir_snsrch3, ttd3);
IRread ch4 (clk, channel_sel[4], ir_snsrch4, ttd4);
IRread ch5 (clk, channel_sel[5], ir_snsrch5, ttd5);
IRread ch6 (clk, channel_sel[6], ir_snsrch6, ttd6);
IRread ch7 (clk, channel_sel[7], ir_snsrch7, ttd7);
assign ir_evenLED_en = channel_sel[0] | channel_sel[2] | channel_sel[4] | channel_sel[6];
assign ir_oddLED_en = channel_sel[1] | channel_sel[3] | channel_sel[5] | channel_sel[7];
endmodule
module IRread (
input clk, enable,
inout sensor,
output reg[16:0] ttd
);
localparam s0 = 3'b000;
localparam s1 = 3'b001;
localparam s2 = 3'b010;
localparam s3 = 3'b011;
localparam s4 = 3'b100;
localparam s5 = 3'b101;
reg[2:0] current_state, next_state;
reg timer10us_en, timerttd_en, drive_sensor, writettd;
wire[7:0] timer10us;
wire[16:0] timerttd;
timer ten_us_buffer (clk, timer10us_en, 1'bZ, timer10us);
timer decay_timer (clk, timerttd_en, 1'bZ, timerttd);
always @(posedge clk)
begin
if (enable)
current_state <= next_state;
else
current_state <= 0;
end
always @(*)
begin
casex(current_state)
//reset state
s0: begin
drive_sensor = 0;
timer10us_en = 0;
timerttd_en = 0;
writettd = 0;
next_state = s1;
end
// drive the sensor high and wait at least 10us
s1: begin
drive_sensor = 1;
timer10us_en = 1;
timerttd_en = 0;
writettd = 0;
if (timer10us == 8'd160)
next_state = s2;
else
next_state = s1;
end
//now the sensor is switched to an input and the ttd timer starts
s2: begin
drive_sensor = 0;
timer10us_en = 0;
timerttd_en = 1;
writettd = 0;
if (sensor == 0)
next_state = s3;
else
next_state = s2;
end
//write the current value in the ttd timer to the ttd output
//then begin the entire process again
s3: begin
drive_sensor = 0;
timer10us_en = 0;
timerttd_en = 1;
writettd = 1;
next_state = s1;
end
endcase
end
// Datapath
assign sensor = drive_sensor ? 1'b1 : 1'bZ;
always @(*)
begin
if (!enable)
begin
ttd = 0;
end
else if (writettd)
ttd = timerttd;
else
ttd = ttd;
end
endmodule
module pwm (
input wire clk,
input enable,
input[15:0] timeon,
output reg PWM
);
reg [15:0] timerPWM;
always @(posedge clk)
begin
if (enable)
begin
timerPWM <= timerPWM + 1'b1;
if (timerPWM == 16'd16000)
begin
timerPWM <= 0;
PWM <= 1'b1;
end
else if (timerPWM > timeon)
PWM <= 1'b0;
end
else
begin
timerPWM <=0;
PWM <= 0;
end
end
endmodu
This is a lot of code, but we’ll do our best to break it down for you. The IR control module accepts the clock, the inout wires for each of the IR sensors, and an 8 bit value called channel_sel. It outputs the control signals for the even and odd IR LEDs and the ttd values for each of the 8 IR sensors. The value channel_sel is encoded in such a way that each bit corresponds to asking for a reading from one of the IR sensors. If you set bit 0 high (ie, making channel_sel equal to 00000001), then you will receive a reading from IR sensor 0. If you set bit 7 high (10000000), then you will get a reading from IR sensor 7. The IR control module pulses the corresponding IR LED for the sensor being read in both cases, as long as you wire up the IR control outputs of the module to the corresponding output of the fpga_top module. As long as channel_sel is set to high for the sensor, you’ll keep receiving updated ttd values for each IR sensor to make control system decisions with. Be sure to have 17 bit wires in your top level module to hold each of the ttd values that are output by the IR control module.
With these modules, you have the ability to receive a constant stream of 8 IR LED ttd values from your sensors. But how can you use these inputs to make a control system that actually does something?
Black Line FollowingMaking a car that can intercept and follow a black line is your final assignment for this lab course. This may seem like a daunting task, but the purpose of this section is to break it down into manageable parts, and give hints for solutions to each of the problems.
So, you have this stream of ttd inputs from each of the sensors we enabled, but what do they mean? Sure, a high ttd means the car is seeing something dark that absorbs light, and a low ttd value means you’re seeing something that’s light and reflects light. But how can you use this to determine if your car is on the line? In order to be able to do this, you’ll need to calibrate your vehicle’s IR sensors. To do this, you must design a state machine at start up to capture ttd values on command. Design a state that will store the value of a specific IR sensor when you give it a command, through a button or bumper switch press. You’ll want to do this every time you start your line-following program, as the amount of light reflected or absorbed by the track will vary based on the ambient light in the room. Once you can consistently store at least the value for black, you can proceed to the next part of the system.
Now that you can tell black from white, you’re going to need to be able to find the line now. Your car will start in the center of a black circle. Having the car move forward until one of the sensors sees the line will be easy enough, but then you have to line that sensor up on the black line. Lucky for you, you can do precise degrees turns using the encoder subsystem! Your next goal for the state machine should be to make it so it lines up on the line correctly. You can have the LEDs on the RSLK to light up to indicate when a sensor is on the black line to help you see if the car is lined up correctly. It’s going to take some tuning of the degree of the turn and the speed to consistently land at least one sensor on the black line. Once you can do that, you can proceed to the final part of the assignment.
Now that you know what the line looks like, and you know that you’re on it, you’re going to have to make your car follow the line. You can do this by creating a control system that changes the car’s behavior based on the car’s relative position on the line. You can do this using multiple sensors to get a more accurate idea of the line’s relative position, or even just a single sensor. You basically want to think about what the car will do when it is on line, what it will do when it is to the left of the line, and what it will do when it is to the right of the line, and how it can tell where it is relative to the line. It also might not hurt to build in some sort of emergency kill switch into one of the bumper switches in case the car goes off the rails or you need a quick way to stop it.
Once you have completed these three components (calibration, interception, and following), you will have completed the course. Don’t be daunted by this task. You have all the equipment and skills you need to succeed, and a strong foundation of code modules to build off of.
ConclusionCongratulations! You have completed the final lab, and have created a car that can not only move, but do so intelligently too. You’ve learned how to write hardware to create what is effectively a rudimentary operating system that controls the entire functionality of a robotic car. The lights, the wheels, the encoders, the bumper switches, and an array of IR sensors, all controlled through hardware you designed on an assembly smaller than a postcard that you soldered and assembled. Be proud! The car and assembly are now yours to do with and program as you please. The RSLK robotics kit is incredibly robust, and it’s full potential is at your fingertips. Experiment with the kit, refine it, modify it, and don’t forget to have fun!
Thank you for taking the time to read and follow our little try at integrating an FPGA into an embedded TI RSLK MAX, we hope that you make cool things and enjoy the modules and code.
-Team 4
Comments