Welcome to my website


My name is El Hajj Malick Diagne, and I am an amateur engineer and physicist. My main interests are in robotics, control systems, electronics, and computational physics. I am currently an early-college experience student at The Ohio State University and a member of First Robotics Team 3324, The Metrobots. My goal is to major in robotics engineering, if the university offers it, or electrical and computer engineering. I am always looking to learn something new and expand my skill set. I am currently learning how to design printed circuit boards and create mobile apps using Jetpack Compose.

#include <Arduino.h>
#include <PS4Controller.h>

/* -------- Motor Utilities -------- */

constexpr int MOTOR_PWM_FREQUENCY = 20000; // 20 kHz
constexpr int MOTOR_RESOLUTION = 8; // 8-bits [0, 255]
constexpr int MAX_MOTOR_PWM = 255;

/**
 * An interface for controlling a motor channel using the TB6612FNG motor
 * driver. Assumes that the STBY is externally pulled HIGH.
 */
class MotorChannel {
    private:
        uint8_t in1_pin;
        uint8_t in2_pin;
        uint8_t pwm_channel;
        bool is_reversed;
        

        void drive_cw(uint8_t duty_cycle) {
            digitalWrite(in1_pin, HIGH);
            digitalWrite(in2_pin, LOW);
            ledcWrite(pwm_channel, duty_cycle);
        }
        
        void drive_ccw(uint8_t duty_cycle) {
            digitalWrite(in1_pin, LOW);
            digitalWrite(in2_pin, HIGH);
            ledcWrite(pwm_channel, duty_cycle);
        }

    public:
        MotorChannel(uint8_t in1_pin, uint8_t in2_pin, uint8_t pwm_pin, uint8_t channel, bool is_reversed) {
            this->in1_pin = in1_pin;
            this->in2_pin = in2_pin;
            this->pwm_channel = channel;
            this->is_reversed = is_reversed;

            pinMode(in1_pin, OUTPUT);
            pinMode(in2_pin, OUTPUT);
            pinMode(pwm_pin, OUTPUT);

            ledcAttachPin(pwm_pin, channel);
            ledcSetup(channel, MOTOR_PWM_FREQUENCY, MOTOR_RESOLUTION);

            stopMotor();
        }

        /**
         * Brakes the motor and sets the duty cycle to 0.
         */
        void stopMotor() {
            digitalWrite(in1_pin, LOW);
            digitalWrite(in2_pin, LOW);
            ledcWrite(pwm_channel, 0);
        }
        
        /**
         * @param speed The speed and direction to drive the motor. Value: [-255, 255].
         */
        void driveMotor(int16_t speed) {
            speed *= is_reversed ? -1 : 1;
            /* CCW rotation is positive */
            if (speed > 0) {
                drive_ccw(speed);
            } else if (speed < 0) {
                drive_cw(-speed);
            } else {
                stopMotor();
            }
        }
};

/* -------- Status LED -------- */
constexpr uint8_t STATUS_LED_PIN = 2;
constexpr uint16_t SHORT_DELAY = 2000;

/* -------- Motor Driver 1 (Left Side) -------- */
constexpr uint8_t DRIVER1_BIN2_PIN = 4;
constexpr uint8_t DRIVER1_BIN1_PIN = 13;
constexpr uint8_t DRIVER1_AIN2_PIN = 14;
constexpr uint8_t DRIVER1_AIN1_PIN = 18;
constexpr uint8_t DRIVER1_PWMB_PIN = 19;
constexpr uint8_t DRIVER1_PWMA_PIN = 21;

/* -------- Motor Driver 2 (Right Side) -------- */
constexpr uint8_t DRIVER2_BIN2_PIN = 32;
constexpr uint8_t DRIVER2_BIN1_PIN = 27;
constexpr uint8_t DRIVER2_AIN2_PIN = 26;
constexpr uint8_t DRIVER2_AIN1_PIN = 25;
constexpr uint8_t DRIVER2_PWMB_PIN = 23;
constexpr uint8_t DRIVER2_PWMA_PIN = 22;

/* -------- Motor PWM Channels -------- */
constexpr uint8_t FRONT_LEFT_CHANNEL = 1;
constexpr uint8_t BACK_LEFT_CHANNEL = 2;
constexpr uint8_t FRONT_RIGHT_CHANNEL = 3;
constexpr uint8_t BACK_RIGHT_CHANNEL = 4;

/* -------- Drivetrain -------- */
/* The last argument to each constructor is whether or not the motor is reversed. */
MotorChannel front_left_motor = MotorChannel(DRIVER1_AIN1_PIN, DRIVER1_AIN2_PIN, DRIVER1_PWMA_PIN,
                                        FRONT_LEFT_CHANNEL, false);
MotorChannel back_left_motor = MotorChannel(DRIVER1_BIN1_PIN, DRIVER1_BIN2_PIN, DRIVER1_PWMB_PIN,
                                        BACK_LEFT_CHANNEL, false);
MotorChannel front_right_motor = MotorChannel(DRIVER2_AIN1_PIN, DRIVER2_AIN2_PIN, DRIVER2_PWMA_PIN,
                                        FRONT_RIGHT_CHANNEL, true);
MotorChannel back_right_motor = MotorChannel(DRIVER2_BIN1_PIN, DRIVER2_BIN2_PIN, DRIVER2_PWMB_PIN,
                                        BACK_RIGHT_CHANNEL, false);

/**
 * Drive the robot using inputs from a joystick.
 * 
 * @param fwd The speed of the robot in the forwards-backwards direction.
 * Forwards is positive, backwards is negative. Range: [-1.0, 1.0].
 * @param strafe The speed of the robot in the side-to-side direction.
 * Right is positive, left is negative. Range: [-1.0, 1.0].
 * @param rot The speed to rotate the robot. Clockwise is positive (TODO: Check
 * this). Range: [-1.0, 1.0].
 */
void drive(double fwd, double strafe, double rot) {
    // Front left motor power
    double fl = fwd + rot + strafe;
    // Front right motor power
    double fr = fwd - rot - strafe;
    // Back left motor power
    double bl = fwd + rot - strafe;
    // Back right motor power
    double br = fwd - rot + strafe;
    /* Normalize motor powers if any of them exceed 1.0 in magnitude. */
    double max_val = max({abs(fl), abs(fr), abs(bl), abs(br)});
    if (max_val > 1.0) {
        fl /= max_val;
        fr /= max_val;
        bl /= max_val;
        br /= max_val;
    }
    /* Convert from percentages to duty cycles */
    int16_t fl_speed = fl * MAX_MOTOR_PWM;
    int16_t fr_speed = fr * MAX_MOTOR_PWM;
    int16_t bl_speed = bl * MAX_MOTOR_PWM;
    int16_t br_speed = br * MAX_MOTOR_PWM;
    /* Drive each motor */
    front_left_motor.driveMotor(fl_speed);
    front_right_motor.driveMotor(fr_speed);
    back_left_motor.driveMotor(bl_speed);
    back_right_motor.driveMotor(br_speed);
}

void test_drive() {
    front_left_motor.driveMotor(100);
    delay(SHORT_DELAY);
    front_left_motor.stopMotor();
    front_right_motor.driveMotor(100);
    delay(SHORT_DELAY);
    front_right_motor.stopMotor();
    back_right_motor.driveMotor(100);
    delay(SHORT_DELAY);
    back_right_motor.stopMotor();
    back_left_motor.driveMotor(100);
    delay(SHORT_DELAY);
    back_left_motor.stopMotor();
}

/* -------- Controller -------- */
// This is the of the device the controller is paired with (not the controller itself).
const char* PS4_MAC_ADDRESS = "44:85:00:A0:09:0F";
// Through my testing, all values in the range of [-10, 10] (out of [-128, 127]) can be ignored as stick drift.
constexpr int8_t JOYSTICK_DEADBAND = 10;
constexpr int8_t MAX_JOYSTICK_INPUT = 128;

int8_t apply_deadband(int8_t input) {
    return (abs(input) <= JOYSTICK_DEADBAND) ? 0 : input;
}

void setup() {
    pinMode(STATUS_LED_PIN, OUTPUT);
    PS4.begin(PS4_MAC_ADDRESS);    
    while (!PS4.isConnected()) {
        digitalWrite(STATUS_LED_PIN, HIGH);
        delay(500);
        digitalWrite(STATUS_LED_PIN, LOW);
        delay(500);
    }
    digitalWrite(STATUS_LED_PIN, HIGH);
}

void loop() {
    /* Raw joystick input values. Right is +x, left is +y, and range is [-128, 127]. */
    int8_t raw_lx = PS4.LStickX();
    int8_t raw_ly = PS4.LStickY();
    int8_t raw_rx = PS4.RStickX();
    /* Map raw inputs into percentages onto the interval [-1.0, 1.0]. */
    double lx = (double) apply_deadband(raw_lx) / MAX_JOYSTICK_INPUT;
    double ly = (double) apply_deadband(raw_ly) / MAX_JOYSTICK_INPUT;
    double rx = (double) apply_deadband(raw_rx) / MAX_JOYSTICK_INPUT;
    /* Drive robot using the controller inputs. Left joystick controls translation,
    right joystick controls rotation. */
    drive(ly, lx, -rx);
    delay(100);
}


Articulated Snake Fidget Model

In terms of programming languages, I mainly use Rust, Kotlin, and Python, but I am also proficient in C, C++, Java, and TypeScript. While web and app development aren't personal interests of mine, I am comfortable using SvelteKit to build websites, such as this one. I have experience working with multiple popular microcontroller families including Arduino, ESP32, and STM32 development boards. I am also experienced at using Onshape for 3D CAD work. You can see a full list of my projects here.