NXP-Linefollower / docs / programming.md
programming.md
Raw

Programming Guide for Line Follower Robot

โ† Back to Main

Table of Contents

  1. Setup & First Steps
  2. LED Blinky Demo
  3. PWM Control for Motors (Coming soon)
  4. Reading Line Sensors (Coming soon)
  5. Differential Drive Control (Coming soon)

Step 1: Setup and First Steps

Get Started with the Board

The FRDM-MCXN947 board comes pre-programmed with an LED blinky demo. This built-in example serves as a quick sanity check to confirm that the board is functioning correctly right out of the box.

Plug in the Board

Connect a USB Type-C cable from connector J17 on the FRDM-MCXN947 board to your host computer or a USB power supply. This will power up the board and automatically run the pre-programmed demo application.

What to expect: The onboard RGB LED should start blinking at a steady rhythm. This indicates that the board is functioning correctly and the demo firmware is running as expected.


Get Required Tools

To access the tools required for this project, you'll need to create an NXP account. You can use either your personal or student email address.

Create your account by visiting this page.


Get MCUXpresso IDE

Download the latest version of the MCUXpresso IDE from the NXP website.

Make sure to select the installer that matches your operating system (Windows, Linux, or macOS).


Install MCUXpresso IDE

Continue clicking "Next" until you reach the install window.

In this step, you may be prompted to install additional drivers during the installation process. Allow these to be installed.


Install SDK for FRDM-MCXN947

Now launch the MCUXpresso IDE and install the SDK. On the IDE Welcome page, click "Download and Install SDKs".

Search for "mcxn947" and click "Install".


Get MCUXpresso Config Tools

Next, download the MCUXpresso Config Tools, which is a suite of utilities that simplifies the configuration of pins, peripherals, and clocks for your project.

Get the correct installation for the machine you are using.

Accept the "License Agreement" and press "Next" until you get to the installation window.

Congratulations! You have successfully tested the board and installed the required tools!


Step 2: LED Blinky Demo

Create a Workspace

First, let's create a workspace folder. Launch the IDE and select where you want to locate your workspace. Keep in mind that switching workspaces restarts the IDE.


Import the LED Blinky Example

Close the Welcome page and select "Import SDK example(s)...". Select the correct MCXN947 board and press "Next".

From the Import Wizard, expand the demo_apps section and select the "led_blinky" application. Then press "Finish" and wait for the project to open.


Explore the Project

You can see that the project window is split into several sections.


Understanding the Code

Let's take a look at the code. The top part contains the include files present in the project tree and visible in the Project Explorer tab.


SysTick_Handler Function

The next section is the SysTick_Handler function that toggles the red LED on the board.

This function is periodically called to switch the LED ON and OFF.

Ctrl + Click on the GPIO_PortToggle function to open the declaration in the fsl_gpio.h header file.


Main Function

The main function starts by calling the initialization function.


Hardware Initialization

The initialization function can be found in the hardware_init.c file.

This function:

  • Enables a clock
  • Initializes the board pins
  • BOARD_BootClockFRO12M() sets the clock frequency to 12 MHz
  • SysTick_Config(12000000UL) sets a counter with a value of 12,000,000 that makes the LED blink once per second

Note: Changing the counter value will increase/decrease the blinking frequency, but it needs to be slow enough for the human eye to notice it.

LED_RED_INIT(LOGIC_LED_OFF) calls GPIO_PinWrite() that changes the output of the GPIO (in this case to the OFF state).


Build the Project

To build a project, select it and then either click on the "Build" icon in the shortcuts or click "Build" in the Quickstart Panel.

The project should finish the build without any errors or warnings in the console.


Download to Board

Make sure your board is connected to the computer through the J17 'MCU-LINK' port.

Download the application to your board by either clicking on the "Debug" icon or clicking "Debug" in the Quickstart Panel.

In the next window, select the MCU-LINK CMSIS-DAP debug probe.


Run the Application

To run the application, press the "Run" icon.

Congratulations! You have successfully built and run your first program on the FRDM-MCXN947!



Step 3: Import Line Follower Project

Download the Project Archive

To begin working on the line follower application, you'll need to import the existing project into MCUXpresso IDE.

Download the project archive: ๐Ÿ“ฆ Download NXP Line Follower Project (ZIP)

Note: Make sure you have the project archive file (.zip) ready before proceeding.

Import the Project into MCUXpresso IDE

Inside the MCUXpresso IDE, go to File and choose the Import option.

In the popup window that will open, expand the General menu and choose the "Existing Projects into Workspace" option, then click "Next".

In the next popup window, select "Select archive file" and browse to the downloaded project .zip file. Then press "Finish".


Build the Project

Now you can build the imported project. Select the project in the Project Explorer and click the "Build" icon or use the Quickstart Panel.

The project should compile without errors. If you encounter any issues, make sure:

  • The SDK for MCXN947 is properly installed
  • All project files were imported correctly

Download and Run

Connect your FRDM-MCXN947 board via the J17 MCU-LINK port and follow the same steps as in the LED Blinky demo:

  1. Click "Debug" to download the application
  2. Select MCU-LINK CMSIS-DAP as the debug probe
  3. Click "Run" to start the application

Congratulations! You have successfully imported and run the line follower project!



Step 4: Reading Line Sensors

Overview

The line follower robot uses 8 infrared reflective sensors (S10-S17) connected to GPIO pins. These sensors detect the line on the track by measuring the difference in reflectivity between the line and the background surface.

The sensors are connected through the comparators on the shield (U4-U7 LM339), which convert the analog sensor output to digital signals (0 or 1).

Note: The GPIO pins are already configured in the provided project. You don't need to configure them manually.


Sensor Reading Functions

The project provides 8 inline functions to read each sensor individually. Each function uses the SDK's GPIO_PinRead() to read the current state of the sensor pin.

Available Sensor Functions

static inline uint8_t raw_S10(void) { 
    return GPIO_PinRead(BOARD_INITPINS_S10_GPIO, BOARD_INITPINS_S10_GPIO_PIN); 
}

static inline uint8_t raw_S11(void) { 
    return GPIO_PinRead(BOARD_INITPINS_S11_GPIO, BOARD_INITPINS_S11_GPIO_PIN); 
}

static inline uint8_t raw_S12(void) { 
    return GPIO_PinRead(BOARD_INITPINS_S12_GPIO, BOARD_INITPINS_S12_GPIO_PIN); 
}

static inline uint8_t raw_S13(void) { 
    return GPIO_PinRead(BOARD_INITPINS_S13_GPIO, BOARD_INITPINS_S13_GPIO_PIN); 
}

static inline uint8_t raw_S14(void) { 
    return GPIO_PinRead(BOARD_INITPINS_S14_GPIO, BOARD_INITPINS_S14_GPIO_PIN); 
}

static inline uint8_t raw_S15(void) { 
    return GPIO_PinRead(BOARD_INITPINS_S15_GPIO, BOARD_INITPINS_S15_GPIO_PIN); 
}

static inline uint8_t raw_S16(void) { 
    return GPIO_PinRead(BOARD_INITPINS_S16_GPIO, BOARD_INITPINS_S16_GPIO_PIN); 
}

static inline uint8_t raw_S17(void) { 
    return GPIO_PinRead(BOARD_INITPINS_S17_GPIO, BOARD_INITPINS_S17_GPIO_PIN); 
}

How They Work

Each function:

  • Reads the digital state of one sensor GPIO pin
  • Returns 0 or 1 depending on whether the sensor detects the line
  • Uses macros generated by the pin configuration (BOARD_INITPINS_Sx_GPIO and BOARD_INITPINS_Sx_GPIO_PIN)

The return value depends on your sensor configuration:

  • Active HIGH: Returns 1 when line is detected (sensor over black line)
  • Active LOW: Returns 0 when line is detected (sensor over black line)

Sensor Array Layout

The 8 sensors are physically arranged in a line across the front of the robot:

[S10] [S11] [S12] [S13] [S14] [S15] [S16] [S17]
 Left โ†                              โ†’ Right

Important: Verify the physical orientation of your sensor array. If S10 is on the right side instead of left, you'll need to account for this in your line following algorithm.


Using the Sensor Functions

To use these functions in your line following algorithm, simply call them to get the current state of each sensor:

Reading a single sensor:

uint8_t center_left = raw_S13();  // Read center-left sensor
if (center_left == 1) {
    // Line detected by S13
}

Reading all sensors:

uint8_t s10 = raw_S10();
uint8_t s11 = raw_S11();
uint8_t s12 = raw_S12();
uint8_t s13 = raw_S13();
uint8_t s14 = raw_S14();
uint8_t s15 = raw_S15();
uint8_t s16 = raw_S16();
uint8_t s17 = raw_S17();

Creating a sensor reading function:

You can create a function that combines all 8 sensor readings into a single byte where each bit represents one sensor:

uint8_t read_sensors(void)
{
    uint8_t sensors = 0;
    
    if (raw_S10()) sensors |= (1 << 0);
    if (raw_S11()) sensors |= (1 << 1);
    if (raw_S12()) sensors |= (1 << 2);
    if (raw_S13()) sensors |= (1 << 3);
    if (raw_S14()) sensors |= (1 << 4);
    if (raw_S15()) sensors |= (1 << 5);
    if (raw_S16()) sensors |= (1 << 6);
    if (raw_S17()) sensors |= (1 << 7);
    
    return sensors;
}

This compact representation makes it easy to check multiple sensors at once or store sensor history. The returned byte contains: 0bS17_S16_S15_S14_S13_S12_S11_S10


Step 5: Motor Control

Overview

The line follower uses two DC motors controlled by DRV8833 dual H-bridge motor drivers (U2 and U3 on the shield). The motors are controlled using:

  • PWM signals for speed control (generated by CTIMER)
  • GPIO pins for direction control (IN1, IN2 for each motor)

Note: The motor driver and PWM are already configured in the provided project. You don't need to configure them manually.


Motor Control Function

The project provides the HbridgeSpeed() function to control both motors simultaneously.

Function Signature

void HbridgeSpeed(hbridge_t *hbridge, int16_t speed1, int16_t speed2);

Parameters

  • hbridge: Pointer to the H-bridge configuration structure (use &g_hbridge)
  • speed1: Speed for motor 1 (range: -100 to +100)
    • Positive values = forward direction
    • Negative values = reverse direction
    • Zero = motor stopped
  • speed2: Speed for motor 2 (range: -100 to +100)
    • Same behavior as speed1

How It Works

The function:

  1. Converts the speed value (-100 to +100) to a PWM duty cycle (0% to 100%)
  2. Sets the motor direction using GPIO pins: - Forward: IN1=HIGH, IN2=LOW - Reverse: IN1=LOW, IN2=HIGH - Stop: IN1=LOW, IN2=LOW
  3. Updates the CTIMER PWM duty cycle to control motor speed

The absolute value of the speed determines how fast the motor spins, while the sign determines the direction.


Motor Brake Function

The project also provides the HbridgeBrake() function to actively brake both motors.

Function Signature

void HbridgeBrake(hbridge_t *hbridge);

Parameters

  • hbridge: Pointer to the H-bridge configuration structure (use &g_hbridge)

How It Works

The brake function:

  1. Sets both motor direction pins HIGH (IN1=HIGH, IN2=HIGH)
  2. Creates a short circuit across the motor terminals
  3. Actively resists motor rotation, providing quick stopping

Difference Between Brake and Stop

Braking (HbridgeBrake()):

  • Sets IN1=HIGH, IN2=HIGH
  • Motor terminals are shorted together
  • Motor actively resists rotation (regenerative braking)
  • Faster stopping - robot stops quickly
  • Higher current draw during braking

Stopping (HbridgeSpeed(&g_hbridge, 0, 0)):

  • Sets IN1=LOW, IN2=LOW
  • Motor terminals are disconnected
  • Motor coasts to a stop
  • Slower stopping - robot gradually slows down
  • No additional current draw

Using the Brake Function

Emergency stop:

HbridgeBrake(&g_hbridge);  // Actively brake both motors

Quick stop before direction change:

HbridgeSpeed(&g_hbridge, 50, 50);   // Moving forward
// Need to reverse quickly
HbridgeBrake(&g_hbridge);            // Brake first
delay_ms(100);                       // Wait for motors to stop
HbridgeSpeed(&g_hbridge, -50, -50);  // Now reverse

Stopping at a line intersection:

if (all_sensors_detect_line) {
    HbridgeBrake(&g_hbridge);  // Quick stop at intersection
}

When to Use Brake vs Stop

Use HbridgeBrake() when:

  • You need to stop quickly (emergency stop, obstacle detected)
  • Stopping at precise positions (intersections, finish line)
  • Changing direction rapidly
  • Maximum deceleration is required

Use HbridgeSpeed(&g_hbridge, 0, 0) when:

  • Gradual stopping is acceptable
  • Conserving power
  • Normal end of operation
  • Smoother motion is desired

Important Notes

Current Draw:

  • Braking can draw significant current momentarily
  • Don't brake continuously for extended periods
  • Release brake after robot has stopped

Mechanical Stress:

  • Frequent hard braking can stress the drivetrain
  • Use appropriate braking force for your application
  • Consider motor and gearbox limitations

Motor Mapping

In the provided project:

  • Motor 1 (speed1) = Right motor
  • Motor 2 (speed2) = Left motor

This mapping is already configured in the H-bridge initialization. You can use the motors directly without worrying about the physical wiring.


Using the Motor Control Function

To control the robot's movement, call HbridgeSpeed() with the desired speeds for both motors.

Moving forward:

HbridgeSpeed(&g_hbridge, 50, 50);  // Both motors at 50% speed forward

Turning left (differential drive):

HbridgeSpeed(&g_hbridge, 70, 30);  // Right motor faster, left motor slower

Turning right (differential drive):

HbridgeSpeed(&g_hbridge, 30, 70);  // Left motor faster, right motor slower

Moving backward:

HbridgeSpeed(&g_hbridge, -50, -50);  // Both motors at 50% speed reverse

Stopping:

HbridgeSpeed(&g_hbridge, 0, 0);  // Both motors stopped

Sharp turn (spin in place):

HbridgeSpeed(&g_hbridge, 50, -50);  // Right forward, left reverse = spin left
HbridgeSpeed(&g_hbridge, -50, 50);  // Right reverse, left forward = spin right

Differential Drive Steering

For line following, you'll use differential drive - varying the speed of the left and right motors to steer the robot.

Basic principle:

  • Both motors same speed โ†’ Robot goes straight
  • Right motor faster โ†’ Robot turns left
  • Left motor faster โ†’ Robot turns right
  • Speed difference determines how sharp the turn is

Typical line following approach:

  1. Read sensors to determine line position
  2. Calculate error (how far off-center the line is)
  3. Adjust motor speeds based on error:
    • If line is left of center โ†’ slow down left motor, speed up right motor
    • If line is right of center โ†’ slow down right motor, speed up left motor
    • If line is centered โ†’ both motors at same speed

Important Notes

Speed Range:

  • The valid range is -100 to +100
  • Values outside this range will be clamped automatically
  • Start with lower speeds (30-60) for testing and gradually increase

Motor Response:

  • Motors may not respond to very low speed values (< 20)
  • Each motor may have slightly different characteristics
  • You may need to calibrate speeds for straight-line driving

Control Loop Frequency:

  • Call HbridgeSpeed() regularly in your main loop
  • Typical frequency: 100-200 Hz (every 5-10 ms)
  • Too slow โ†’ jerky movement
  • Too fast โ†’ unnecessary CPU usage

Your Task: Implement Line Following

Now that you have:

  • Sensor reading functions (raw_S10() through raw_S17())
  • Motor control function (HbridgeSpeed())

You need to implement the line following algorithm that:

  1. Reads the sensor array
  2. Determines the line position
  3. Calculates appropriate motor speeds
  4. Calls HbridgeSpeed() to steer the robot

Suggested approach:

  • Start with a simple algorithm (e.g., if-else based on sensor patterns)
  • Test on a simple track
  • Gradually improve with more sophisticated control (e.g., PID controller)
  • Tune parameters for speed and accuracy

Good luck with your line follower!


โ† Back to Main