HIDE NAV

Microcontroller Unit Lab 5

Multiple Independant H-Bridge Motors

Organized by C Struct Variables with PWM Throttle



Code

Part 1 Library & Timed Sequence Demonstration.

h-bridge.h


#include "pico/stdlib.h"
#include "hardware/pwm.h"

#define HB_PWM_WRAP 499
#define HB_PWM_DIV 10

struct H_Bridge {
  uint fwd_gp;
  uint rev_gp;
};

enum H_Bridge_Mode {
  STOP,
  FORWARD,
  REVERSE
};

void hb_pin_setup(struct H_Bridge hb);

void hb_set_duty(struct H_Bridge hb, enum H_Bridge_Mode m, float duty_set);


h-bridge.c


#include "h-bridge.h"

void hb_pin_setup(struct H_Bridge hb){
  //forward pin
  gpio_set_function(hb.fwd_gp, GPIO_FUNC_PWM);
  int f_slice_num = pwm_gpio_to_slice_num(hb.fwd_gp);
  pwm_set_enabled(f_slice_num, true);
  pwm_set_wrap(f_slice_num, HB_PWM_WRAP);
  pwm_set_clkdiv_int_frac(f_slice_num, HB_PWM_DIV, 0);
  pwm_set_gpio_level(hb.fwd_gp, 0);

  //reverse pin
  gpio_set_function(hb.rev_gp, GPIO_FUNC_PWM);
  int r_slice_num = pwm_gpio_to_slice_num(hb.rev_gp);
  pwm_set_enabled(r_slice_num, true);
  pwm_set_wrap(r_slice_num, HB_PWM_WRAP);
  pwm_set_clkdiv_int_frac(r_slice_num, HB_PWM_DIV, 0);
  pwm_set_gpio_level(hb.rev_gp, 0);
}

void hb_set_duty(struct H_Bridge hb, enum H_Bridge_Mode m, float duty_set){
  if(duty_set > 1.0f) duty_set = 1.0f;
  if(duty_set < 0.0f) duty_set = 0.0f;

  switch(m) {
    default:
    case STOP:
      pwm_set_gpio_level(hb.fwd_gp, 0);
      pwm_set_gpio_level(hb.rev_gp, 0);
      break;
    case FORWARD:
      pwm_set_gpio_level(hb.rev_gp, 0);
      int f_level = duty_set * HB_PWM_WRAP;
      pwm_set_gpio_level(hb.fwd_gp, f_level);
      break;
    case REVERSE:
      pwm_set_gpio_level(hb.fwd_gp, 0);
      int r_level = duty_set * HB_PWM_WRAP;
      pwm_set_gpio_level(hb.rev_gp, r_level);
      break;
  }
}

main.c


#include "pico/stdlib.h"
#include "h-bridge.h"

struct H_Bridge hb_motor_left;
struct H_Bridge hb_motor_right;

int main() {
	// setup &  initialize
	hb_motor_left.fwd_gp = 12;
	hb_motor_left.rev_gp = 13;
	hb_pin_setup(hb_motor_left);

	hb_motor_right.fwd_gp = 14;
	hb_motor_right.rev_gp = 15;
	hb_pin_setup(hb_motor_right);

	// primary loop
	while (true) {

		hb_set_duty(hb_motor_right, FORWARD, 0.85f);
		hb_set_duty(hb_motor_left, FORWARD, .8f);
		sleep_ms(1000);

		hb_set_duty(hb_motor_right, STOP, 0.0f);
		hb_set_duty(hb_motor_left, STOP, 0.0f);
		sleep_ms(1000);

		hb_set_duty(hb_motor_right, REVERSE, 0.90f);
		hb_set_duty(hb_motor_left, REVERSE, 0.95f);
		sleep_ms(1000);

		hb_set_duty(hb_motor_right, STOP, 0.0f);
		hb_set_duty(hb_motor_left, STOP, 0.0f);
		sleep_ms(1000);

	}
}



Code

Part 2 2wd Mode Select, No Speed Yet.

main.c


#include "pico/stdlib.h"
#include "h-bridge.h"

/*
//// BENCH
#define HB_L_FWD_GP 13
#define HB_L_REV_GP 12
#define HB_R_FWD_GP 14
#define HB_R_REV_GP 15

#define BTN_MODE_GP 22
*/

//// ACTUAL CAR
#define HB_L_FWD_GP 15
#define HB_L_REV_GP 14
#define HB_R_FWD_GP 13
#define HB_R_REV_GP 12

#define BTN_MODE_GP 18

// Buttons:  speed up, speed down

#define POLL_DELAY_MS_FAST 10
#define POLL_DELAY_MS_SLOW 250
bool do_slow_delay = false;

struct H_Bridge hb_motor_left;
struct H_Bridge hb_motor_right;

enum Drive_Mode {
		D_STOP,
		D_FORWARD,
		D_REVERSE,
		D_ROTATE_L,
		D_ROTATE_R
};

enum Drive_Mode drive_mode_last_active = D_STOP;
enum Drive_Mode drive_mode_current = D_STOP;

//TODO: speed/duty variables
// 	current, increment, min

//PROTOS
void app_pin_setup();
void app_check_buttons();
void app_mode_change();
void app_update_motors();
void app_poll_delay();

int main() {
	// setup &  initialize
	hb_motor_left.fwd_gp = HB_L_FWD_GP;
	hb_motor_left.rev_gp = HB_L_REV_GP;
	hb_pin_setup(hb_motor_left);

	hb_motor_right.fwd_gp = HB_R_FWD_GP;
	hb_motor_right.rev_gp = HB_R_REV_GP;
	hb_pin_setup(hb_motor_right);

	app_pin_setup();

	// primary loop
		while (true) {
			app_check_buttons();
			app_update_motors();
			app_poll_delay();
		}
}
//IMPLEMENTS
void app_check_buttons(){
	int mode_state = gpio_get(BTN_MODE_GP);
	if(mode_state == 0) {
		app_mode_change();
		do_slow_delay = true;
	}
}

void app_pin_setup(){
	gpio_init(BTN_MODE_GP);
	gpio_set_dir(BTN_MODE_GP, GPIO_IN);
	gpio_pull_up(BTN_MODE_GP);
}

void app_mode_change() {
	if(drive_mode_current != D_STOP) {
		drive_mode_last_active = drive_mode_current;
		drive_mode_current = D_STOP;
	} else {
			//the drive mode WAS stop
		drive_mode_current = drive_mode_last_active + 1;
		if(drive_mode_current > D_ROTATE_R) drive_mode_current = D_FORWARD;
	}
}

void app_update_motors(){
	switch(drive_mode_current){
		default:
		case D_STOP:
			hb_set_duty(hb_motor_left, STOP, 0.0f);
			hb_set_duty(hb_motor_right, STOP, 0.0f);
			break;
		case D_FORWARD:
			hb_set_duty(hb_motor_left, FORWARD, 1.0f);
			hb_set_duty(hb_motor_right, FORWARD, 1.0f);
			break;
		case D_REVERSE:
			hb_set_duty(hb_motor_left, REVERSE, 1.0f);
			hb_set_duty(hb_motor_right, REVERSE, 1.0f);
			break;
		case D_ROTATE_L:
			hb_set_duty(hb_motor_left, REVERSE, 1.0f);
			hb_set_duty(hb_motor_right, FORWARD, 1.0f);
			break;
		case D_ROTATE_R:
			hb_set_duty(hb_motor_left, FORWARD, 1.0f);
			hb_set_duty(hb_motor_right, REVERSE, 1.0f);
			break;
	}

}

void app_poll_delay() {
	if (do_slow_delay) {
		sleep_ms(POLL_DELAY_MS_SLOW);
		do_slow_delay = false;
	} else {
		sleep_ms(POLL_DELAY_MS_FAST);
	}
}