pimoroni-pico/examples/pico_motor_shim/sequence/demo.cpp

171 lines
4.9 KiB
C++

#include <stdio.h>
#include "pico_motor_shim.hpp"
#include "common/pimoroni_common.hpp"
#include "motor.hpp"
#include "button.hpp"
/*
Program showing how the two motors of the Pico Motor Shim can be perform a sequence of movements.
Press "A" to start and stop the movement sequence
*/
using namespace pimoroni;
using namespace motor;
static constexpr float TOP_SPEED = 1.0f; //A value between 0 and 1
static const uint32_t ACCELERATE_TIME_MS = 2000;
static const uint32_t WAIT_TIME_MS = 1000;
static const uint32_t STOP_TIME_MS = 1000;
Button button_a(pico_motor_shim::BUTTON_A, Polarity::ACTIVE_LOW, 0);
Motor motor_1(pico_motor_shim::MOTOR_1);//, Motor::DEFAULT_PWM_FREQUENCY, Motor::DEFAULT_DECAY_MODE);
Motor motor_2(pico_motor_shim::MOTOR_2);//, Motor::DEFAULT_PWM_FREQUENCY, Motor::DEFAULT_DECAY_MODE);
static bool button_toggle = false;
/**
* Checks if the button has been pressed, toggling a value that is also returned.
*/
bool check_button_toggle() {
bool button_pressed = button_a.read();
if(button_pressed) {
button_toggle = !button_toggle;
}
return button_toggle;
}
/**
* Waits for a given amount of time (in milliseconds).
* Exits early if the user presses the button to stop the sequence, returning false.
*/
bool wait_for(uint32_t duration_ms) {
uint32_t start_time = millis();
uint32_t ellapsed = 0;
//Loops until the duration has elapsed, checking the button state every millisecond
while(ellapsed < duration_ms) {
if(!check_button_toggle())
return false;
sleep_ms(1);
ellapsed = millis() - start_time;
}
return true;
}
/**
* Accelerate/Decelerate the motors from their current speed to the target speed over the given amount of time (in milliseconds).
* Exits early if the user presses the button to stop the sequence, returning false.
*/
bool accelerate_over(float left_speed, float right_speed, uint32_t duration_ms) {
uint32_t start_time = millis();
uint32_t ellapsed = 0;
//Get the current motor speeds
float last_left = motor_1.speed();
float last_right = motor_2.speed();
//Loops until the duration has elapsed, checking the button state every millisecond, and updating motor speeds
while(ellapsed <= duration_ms) {
if(!check_button_toggle())
return false;
//Calculate and set the new motor speeds
float percentage = (float)ellapsed / (float)duration_ms;
motor_1.speed(((left_speed - last_left) * percentage) + last_left);
motor_2.speed(((right_speed - last_right) * percentage) + last_right);
sleep_ms(1);
ellapsed = millis() - start_time;
}
//Set the final motor speeds as loop may not reach 100%
motor_1.speed(left_speed);
motor_2.speed(right_speed);
return true;
}
/**
* The function that performs the driving sequence.
* Exits early if the user presses the button to stop the sequence, returning false.
*/
bool sequence() {
printf("accelerate forward\n");
if(!accelerate_over(-TOP_SPEED, TOP_SPEED, ACCELERATE_TIME_MS))
return false; //Early exit if the button was toggled
printf("driving forward\n");
if(!wait_for(WAIT_TIME_MS))
return false; //Early exit if the button was toggled
printf("deccelerate forward\n");
if(!accelerate_over(0.0f, 0.0f, ACCELERATE_TIME_MS))
return false; //Early exit if the button was toggled
printf("stop\n");
motor_1.stop();
motor_2.stop();
if(!wait_for(STOP_TIME_MS))
return false; //Early exit if the button was toggled
printf("accelerate turn left\n");
if(!accelerate_over(TOP_SPEED * 0.5f, TOP_SPEED * 0.5f, ACCELERATE_TIME_MS * 0.5f))
return false; //Early exit if the button was toggled
printf("turning left\n");
if(!wait_for(WAIT_TIME_MS))
return false; //Early exit if the button was toggled
printf("deccelerate turn left\n");
if(!accelerate_over(0.0f, 0.0f, ACCELERATE_TIME_MS * 0.5f))
return false; //Early exit if the button was toggled
printf("stop\n");
motor_1.stop();
motor_2.stop();
if(!wait_for(STOP_TIME_MS))
return false; //Early exit if the button was toggled
//Signal that the sequence completed successfully
return true;
}
/**
* The entry point of the program.
*/
int main() {
stdio_init_all();
//Initialise the LED. We use this to indicate that the sequence is running.
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
//Initialise the two motors
if(!motor_1.init() || !motor_2.init()) {
printf("Cannot initialise motors. Check the provided parameters\n");
return 0;
}
while(true) {
//Has the user has pressed the button to start the sequence
if(check_button_toggle()) {
//Turn the Pico's LED on to show that the sequence has started
gpio_put(PICO_DEFAULT_LED_PIN, true);
//Run the sequence in a perpetual loop, exiting early if the button is pressed again
while(sequence());
}
//The sequence loop has ended, so turn off the Pico's LED and disable the motors
gpio_put(PICO_DEFAULT_LED_PIN, false);
motor_1.disable();
motor_2.disable();
}
return 0;
}