Microcontrollers are crucial to robotics. They are essentially the brains running tasks to be completed. In this article, I will show how to create a C program using the Arduino IDE with an Atmega328 uController to run a mecbot.
This article will demonstrate how to create an Arduino C program for a mecbot to follow a line through a maze. We will do this using the Atmega328 AVR microcontroller. We will make a separate assembly and machine code file for the C program to read, controlling the different mecbot components.
Just a quick note before we get started: these instructions are for creating a C program when the mecbot is already built, the wiring is connected, and the assembly and hex files already exist. However, I will still provide a quick overview on how to run all the files together.
As mentioned, the mecbot with its sensors, switches, LEDs, motors, and other components should already be wired with the microcontroller and Arduino UNO board. I chose an Arduino UNO because it can easily interface with the Atemega328 chip.
Next, you will need to download the Arduino IDE. It comes with a text editor, compiler, and uploader already integrated into one software environment. This allows you to program your AVR uController in C. The only drawback to using the Arduino IDE is that you are limited to using Arduino Boards.
The following links will provide more information on the Atmega328 microcontroller, including which pins connect to devices on the microcontroller:
What is a Microcontroller and How to Use Assembly Language
Let’s begin with a clear understanding of what a microcontroller is and how it is used. Microcontrollers are embedded devices often used in the engineering industry to control mechanical devices, making interfacing with outside devices easier. This is accomplished by first setting the data direction register (DDRx), then the actual pin on the port (PORTx).
The microcontroller used in this project is the Atmega328 chip. Its memory map outlines the memory organization inside its MCU, specified by an array of addresses called memory locations. Next, we have the register map provided in the datasheet. This map specifies high-speed memories connected to the arithmetic logic unit (ALU). One can easily manipulate data by moving in and out of the registers and implementing logic operations.
Now, to program the microcontroller, you need to use assembly language. It is beneficial to learn assembly language for other uses, too. Assembly language helps control hardware devices where timing is critical and makes it easier to debug your C program. Most importantly, it creates small and efficient routines.
To program assembly in Arduino, I first embedded assembly in a C program. To do this, I compiled three different files: c program (.ino), the header file (.h), and the assembly file (.s). Saving all three files to the same directory is important (Arduino does this automatically for you).
To have the C program read the assembly code file (.s) and machine code file (.h), perform the following steps:
- Start a new Arduino program and name it.
- Erase the processing “Setup and Loop” function: this is where you write your code.
- Use the down arrow button on the tab bar and select “set up a new header file tab”. Do this step twice, once to create a file that defines the assembly functions (.h) and the second time for your assembly function (.s).
C Program for Arduino
Now, moving on to the main portion of this project, the C program. I decided to create two functions, one for the line-following portion and the second for the maze portion. This will make the main program more compact and make debugging easier.
Here’s the pin assignment of the mecbot:
|LED Bar – 8 segments||O||PB0-PB5, PD6-PD7||Shared with motor and ADC|
|Buzzer||O||PB3||Shared with ADC|
|Motor||O||PB0-PB2, PD7||Shared with LEDs|
|Bumpers||I||PD3-PD5, PC1||Shared with push buttons|
|Push Buttons||I||PD3-PD5, PC1||Shared with bumpers|
|DIP Switches||I||PC2-PC5||Shared with encoders|
|Encoders||I||PC2-PC3||Shared with DIP|
The main objective of the mecbot is to complete two tasks. When the bumper of the mecbot is pressed, the mecbot starts tracking line A. Once it detects line B, it has to stop for 3 seconds then enter and complete the maze.
Let’s begin by creating the line-following part of the project. Start by including all the header files necessary to run the mecbot, then define a line-following function, and within it four variables to hold the readings from the line sensors:
Next, I started a while loop and set each line sensor as input with its corresponding pin. Here, the line sensors and the motors from the mecbot worked together to prevent the mecbot from derailing from the black line.
As you might have noticed, the sensor reading 800 is the one being used in each condition. I chose this number after trial and error, playing around with the mecbot to check which sensor reading would recognize the black line. For your sensors, this might be different, so always check by testing first.
Another way to find this value is to use the serial monitor in Arduino, located at the top right corner of the IDE. You can test your sensors individually by reading the input of the sensor and printing it on the serial monitor. For example, before attaching the line sensor to the mecbot, I would test it by hovering my sensor over the black line to check what reading it prints on the serial monitor. This is much easier and less time consuming because the serial monitor prints the reading you need to use in the program. Here is a simple tutorial on how to use a Serial Monitor with an easy push-button setup.
After I tested the function
linefollowing(), I moved on to implementing the maze portion. Here I started by defining my function and setting up all the microcontroller ports that were used. Then, I defined all variables in which the sensor readings will be stored and variables for which values are fixed.
Next, I created a while loop, and, within it, many if conditions for obstacle avoidance. The first condition checks if there is a wall in front and on either side of the mecbot. If true, the motor function is called to make a u-turn.
Then, I implemented the second part of the code. The implementation is similar to the u-turn code, using nested else if statements combined with for loops. The first if statement triggers a right turn if there is a wall in front and on the left side of the mecbot. The second statement, an else if statement, triggers a left turn if there is a wall in front and on the right side of the mecbot.
Initially, when I ran the code, there was a problem. The mecbot would sometimes run into the wall and be unable to complete the maze. To fix this, I added an extra if statement to each for-loop to read data from the bumper. When the mecbot collides with a wall, the bumper will cause the mecbot to reverse and correct itself. The mecbot will then re-read the distance sensors to complete the maze.
If there is no wall blocking the mecbot’s path, it continues to move forward.
Now that the functions are created, the main code (below) will be simpler and more compact.
Finally, the main program of the mecbot! Once the left bumper is pressed, the function
linefollowing() runs. After its completion, the mecbot will pause for 3 seconds, then the function
maze() runs for the mecbot to complete its final task.
To sum up, we learned about microcontrollers, their uses, and how to successfully have your .ino file read the assembly and machine code files.
We also made a C program in Arduino and used the Atmega328 chip connection to run our mecbot.
Hopefully, this provided some insight into how to use a microcontroller for your projects requiring multiple connections, and how to make your program more efficient.