Click here to access the Canvas page with the repository for this assignment.
The last few assignments have focused on serial communication between the Arduino and a Java program running on your laptop computer. First we set up a way of sending data in each direction. Then we established a protocol to send a variety of meaningful messages one byte at a time. In this assignment we will use the protocol as a way to control (or not control!) a robotic car from a Java program and send useful data about the car’s location back to Java.
Over the past few studios, we have constructed the various physical elements of the robotic car: a switch, a button to debounce, the ultrasonic distance sensor, and servo motors driven by analog outputs. We now put them together and form a car that can drive autonomously forward until it detects an obstacle at which point it stops and changes direction. Or, if we push the button, the car switches modes and responds only to commands given to it from the Java program. The car also contains an LED to indicate which mode it is in and a power switch to turn the whole thing on or off.
To implement the robotic car and the Java program that controls it, you will need to use the protocol that we have established to send data in each direction. This assignment will also require delta timing to control the timing of the car’s various outgoing messages and give it the ability to process incoming messages and figure how far it is from obstacles in a non-blocking manner.
You have already built all the physical elements of the robotic car in previous studios. Here, we will combine the car from this module’s studio with the ultrasonic sensor from the earlier studio. An image of the (nearly) completed car is below.
Note that this looks very close to the image from studio, but has the ultrasonic distance sensor included as well. You will need to add a button and LED, too. Instructions for the physical construction are on SparkFun’s tutorial, but you don’t need to add the battery pack (it can be powered directly from the USB on your laptop as we’ve done all semester).
Before you get started on the actual assignment, it is a very good idea to check out the components that you’ve already used. Using software from the studios, put the ultrasonic distance sensor and the car through their paces, making sure they each individually operate as intended.
Starting from the
AutonomousRobot.ino sketch in your repository (this one also came straight from SparkFun, with the units changed from
cm), adjust the pin numbers (if needed), add your studio code to convert time to distance (in cm), and play with the robot to make sure it does what is advertised.
As we did in studio, when you’re not actively using the ultrasonic sensor, please unplug the Arduino. This helps eliminate interference with other groups.
You will need to define two control modes: Remote Control Mode (Default) and Autonomous Control Mode. The given code contains proper behavior for Autonomous Control Mode. When you are in Remote Control Mode, your LED should be ON. When the switch is off, your car should not drive autonomously or respond to keyboard input from Java.
At the beginning of your loop you will need to read the state of the button (with debouncing!) to determine whether it has been pressed. If it has, you need to toggle a mode change and change the behavior of the robotic car. Remember to turn the LED on or off as is appropriate!
As part of your
loop() function you should regularly read in data for instructions of what your car should do when it is in Remote Control Mode. (Be sure to only do this if there is something to read, and you are ready to proceed to the next command!) The commands will come in via a newly-defined
MOVE message in our protocol. The
MOVE key is
0x35, and its message consists of two bytes. The first byte is a direction to move in
right. The second byte is an unsigned distance to move.
d (like directional arrows on the keyboard) may alternatively be used in place of
r. Once you have successfully parsed a
MOVE message, you may optionally send an
INFO message back to Java acknowledging the type and distance of the received command.
loop() function currently calls
delay(50) at its end to ensure that the calculation of the distance occurs ever 50ms. Switch this behavior of taking distance readings ever 50 ms to be non-blocking (using delta timing). HINT: Steps 2 and 3 above should not be in this delta timing loop, but Steps 4-8 should be!
Once per second, send the newest (raw) distance sensor reading to the Java program in a message using the protocol from the previous module. You should do this regardless of which mode the car is in. Keep in mind, however, that the behavior currently in the loop function is what we would like for the Autonomous Mode. You will want to do something else if the car is in Remote Control Mode. So, I suggest different functions that are called within your delta timing loop depending on the current mode of the car.
Be sure to read the value of the switch before turning on the motors!
Some blocking behavior is ok within Autonomous Mode. Calls to
delay(turnTime); can stay as they are. However, with Remote Control Mode, everything needs to be non-blocking and use delta timing. To help you account for the time that executing a move or turn instruction will take, we have included the constants
When writing the function to implement commands in Remote Control Mode, you should implement an FSM for moving the car. It is either ready to
MOVE, or it is
IDLE. Enter into the
MOVE state when you asynchronously read a valid
MOVE message from Java. Then, using the code from this module’s studio, define the commands for moving the car
r whichever distance was sent. After you finish a move, go back to the
IDLE state of your FSM. Be sure to implement all of this in a non-blocking way!
The Java portion of this assignment will regularly receive data from the Arduino in the form of messages that adhere to the protocol from Module 6. I suggest starting with a copy of the Java code (including
SerialComm) you used in Assignment 6 for reading in messages. Be sure to print out any messages you receive. This includes distance readings (which Java will need to convert to cm) and
readByte() method will block until a byte is consumed from the serial port, so never first call it without ensuring that there is a byte to be read. Java needs to be able to both receive incoming messages from Arduino and read input typed by the user that is meant to control the robot car. Both must be fully non-blocking!
To read input from the console in a non-blocking way, use
System.in.available() > 0 to check for bytes. Note, input is line-buffered, so input data is not transmitted until the Enter key is pressed. Then
System.in.read() will get one byte from the line buffered by the Enter key. A valid byte read in from the console will be one of the 8 letters allowed by
f || w,
b || s,
l || a, or
r || d for
right. Use that byte to construct a
MOVE message using the protocol. The first byte of the message’s value should be the byte read in from the user. We recommend using a constant value (perhaps 10) for the second byte of all messages.
Note, this is merely advisory, the precise rubric is on Canvas.
Generated at 2023-11-17 18:42:25 +0000.
Page written by James Orr, Roger Chamberlain, Michael Hall.