Ported shim examples to C++, and tidy up

pull/352/head
ZodiusInfuser 2022-05-12 13:20:52 +01:00
rodzic 3c3a8c1752
commit fac3e7365a
26 zmienionych plików z 508 dodań i 275 usunięć

Wyświetl plik

@ -5,7 +5,6 @@
- [Multiple Motors](#multiple-motors)
- [Motor Cluster](#motor-cluster)
- [Motor Wave](#motor-wave)
- [Stop Motors](#stop-motors)
- [Function Examples](#function-examples)
- [Read Sensors](#read-sensors)
- [Read Encoders](#read-encoders)
@ -28,25 +27,25 @@
## Motor Examples
### Single Motor
[motor2040_single_motor.py](motor2040_single_motor.py)
[motor2040_single_motor.cpp](motor2040_single_motor.cpp)
Demonstrates how to create a Motor object and control it.
### Multiple Motors
[motor2040_multiple_motors.py](motor2040_multiple_motors.py)
[motor2040_multiple_motors.cpp](motor2040_multiple_motors.cpp)
Demonstrates how to create multiple Motor objects and control them together.
### Motor Cluster
[motor2040_motor_cluster.py](motor2040_motor_cluster.py)
[motor2040_motor_cluster.cpp](motor2040_motor_cluster.cpp)
Demonstrates how to create a MotorCluster object to control multiple motors at once.
### Motor Wave
[motor2040_motor_wave.py](motor2040_motor_wave.py)
[motor2040_motor_wave.cpp](motor2040_motor_wave.cpp)
An example of applying a wave pattern to a group of motors and the LEDs.
@ -54,26 +53,26 @@ An example of applying a wave pattern to a group of motors and the LEDs.
## Function Examples
### Read Sensors
[motor2040_read_sensors.py](motor2040_read_sensors.py)
[motor2040_read_sensors.cpp](motor2040_read_sensors.cpp)
Shows how to initialise and read the 2 external and 6 internal sensors of Motor 2040.
### Read Encoders
[motor2040_read_encoders.py](motor2040_read_encoders.py)
[motor2040_read_encoders.cpp](motor2040_read_encoders.cpp)
Demonstrates how to read the angles of Motor 2040's four encoders.
### Motor Profiler
[motor2040_motor_profiler.py](motor2040_motor_profiler.py)
[motor2040_motor_profiler.cpp](motor2040_motor_profiler.cpp)
A program that profiles the speed of a motor across its PWM
duty cycle range using the attached encoder for feedback.
### LED Rainbow
[motor2040_led_rainbow.py](motor2040_led_rainbow.py)
[motor2040_led_rainbow.cpp](motor2040_led_rainbow.cpp)
Displays a rotating rainbow pattern on the Motor 2040's onboard LED.
@ -81,36 +80,37 @@ Displays a rotating rainbow pattern on the Motor 2040's onboard LED.
## Control Examples
### Position Control
[motor2040_position_control.py](motor2040_position_control.py)
[motor2040_position_control.cpp](motor2040_position_control.cpp)
An example of how to move a motor smoothly between random positions, with the help of it's attached encoder and PID control.
### Velocity Control
[motor2040_velocity_control.py](motor2040_velocity_control.py)
[motor2040_velocity_control.cpp](motor2040_velocity_control.cpp)
An example of how to drive a motor smoothly between random speeds, with the help of it's attached encoder and PID control.
### Position on Velocity Control
[motor2040_position_on_velocity_control.py](motor2040_position_on_velocity_control.py)
[motor2040_position_on_velocity_control.cpp](motor2040_position_on_velocity_control.cpp)
An example of how to move a motor smoothly between random positions, with velocity limits, with the help of it's attached encoder and PID control.
### Reactive Encoder
[motor2040_reactive_encoder.py](motor2040_reactive_encoder.py)
[motor2040_reactive_encoder.cpp](motor2040_reactive_encoder.cpp)
A demonstration of how a motor with an encoder can be used as a programmable rotary encoder for user input, with force-feedback for arbitrary detents and end stops.
### Quad Position Wave
[motor2040_quad_position_wave.py](motor2040_quad_position_wave.py)
[motor2040_quad_position_wave.cpp](motor2040_quad_position_wave.cpp)
A demonstration of driving all four of Motor 2040's motor outputs between positions, with the help of their attached encoders and PID control.
### Quad Velocity Sequence
[motor2040_quad_velocity_sequence.py](motor2040_quad_velocity_sequence.py)
[motor2040_quad_velocity_sequence.cpp](motor2040_quad_velocity_sequence.cpp)
A demonstration of driving all four of Motor 2040's motor outputs through a sequence of velocities, with the help of their attached encoders and PID control.
@ -118,18 +118,18 @@ A demonstration of driving all four of Motor 2040's motor outputs through a sequ
## Tuning Examples
### Position Tuning
[motor2040_position_tuning.py](motor2040_position_tuning.py)
[motor2040_position_tuning.cpp](motor2040_position_tuning.cpp)
A program to aid in the discovery and tuning of motor PID values for position control. It does this by commanding the motor to move repeatedly between two setpoint angles and plots the measured response.
### Velocity Tuning
[motor2040_velocity_tuning.py](motor2040_velocity_tuning.py)
[motor2040_velocity_tuning.cpp](motor2040_velocity_tuning.cpp)
A program to aid in the discovery and tuning of motor PID values for velocity control. It does this by commanding the motor to drive repeatedly between two setpoint speeds and plots the measured response.
### Position on Velocity Tuning
[motor2040_position_on_velocity_tuning.py](motor2040_position_on_velocity_tuning.py)
[motor2040_position_on_velocity_tuning.cpp](motor2040_position_on_velocity_tuning.cpp)
A program to aid in the discovery and tuning of motor PID values for position on velocity control. It does this by commanding the motor to move repeatedly between two setpoint angles and plots the measured response.

Wyświetl plik

@ -31,7 +31,7 @@ constexpr float COUNTS_PER_REV = MMME_CPR * GEAR_RATIO;
const Direction DIRECTION = NORMAL_DIR;
// The scaling to apply to the motor's speed to match its real-world speed
float SPEED_SCALE = 5.4f;
constexpr float SPEED_SCALE = 5.4f;
// How many times to update the motor per second
const uint UPDATES = 100;

Wyświetl plik

@ -31,7 +31,7 @@ constexpr float COUNTS_PER_REV = MMME_CPR * GEAR_RATIO;
const Direction DIRECTION = NORMAL_DIR;
// The scaling to apply to the motor's speed to match its real-world speed
float SPEED_SCALE = 5.4f;
constexpr float SPEED_SCALE = 5.4f;
// How many times to update the motor per second
const uint UPDATES = 100;

Wyświetl plik

@ -33,7 +33,7 @@ constexpr float COUNTS_PER_REV = MMME_CPR * GEAR_RATIO;
const Direction DIRECTION = NORMAL_DIR;
// The scaling to apply to the motor's speed to match its real-world speed
float SPEED_SCALE = 5.4f;
constexpr float SPEED_SCALE = 5.4f;
// How many times to update the motor per second
const uint UPDATES = 100;

Wyświetl plik

@ -33,7 +33,7 @@ constexpr float COUNTS_PER_REV = MMME_CPR * GEAR_RATIO;
const Direction DIRECTION = NORMAL_DIR;
// The scaling to apply to the motor's speed to match its real-world speed
float SPEED_SCALE = 5.4f;
constexpr float SPEED_SCALE = 5.4f;
// How many times to update the motor per second
const uint UPDATES = 100;

Wyświetl plik

@ -23,7 +23,7 @@ constexpr float GEAR_RATIO = 50.0f;
constexpr float COUNTS_PER_REV = MMME_CPR * GEAR_RATIO;
// The scaling to apply to the motor's speed to match its real-world speed
float SPEED_SCALE = 5.4f;
constexpr float SPEED_SCALE = 5.4f;
// How many times to update the motor per second
const uint UPDATES = 100;

Wyświetl plik

@ -29,7 +29,7 @@ constexpr float GEAR_RATIO = 50.0f;
constexpr float COUNTS_PER_REV = MMME_CPR * GEAR_RATIO;
// The scaling to apply to the motor's speed to match its real-world speed
float SPEED_SCALE = 5.4f;
constexpr float SPEED_SCALE = 5.4f;
// How many times to update the motor per second
const uint UPDATES = 100;

Wyświetl plik

@ -33,7 +33,7 @@ constexpr float COUNTS_PER_REV = MMME_CPR * GEAR_RATIO;
const Direction DIRECTION = NORMAL_DIR;
// The scaling to apply to the motor's speed to match its real-world speed
float SPEED_SCALE = 5.4f;
constexpr float SPEED_SCALE = 5.4f;
// How many times to update the motor per second
const uint UPDATES = 100;

Wyświetl plik

@ -17,7 +17,7 @@ const uint STEPS = 10;
// The time in milliseconds between each step of the sequence
const uint STEPS_INTERVAL_MS = 500;
// How far from zero to move the motor when sweeping
// How far from zero to drive the motor when sweeping
constexpr float SPEED_EXTENT = 1.0f;

Wyświetl plik

@ -31,7 +31,7 @@ constexpr float COUNTS_PER_REV = MMME_CPR * GEAR_RATIO;
const Direction DIRECTION = NORMAL_DIR;
// The scaling to apply to the motor's speed to match its real-world speed
float SPEED_SCALE = 5.4f;
constexpr float SPEED_SCALE = 5.4f;
// How many times to update the motor per second
const uint UPDATES = 100;

Wyświetl plik

@ -33,7 +33,7 @@ constexpr float COUNTS_PER_REV = MMME_CPR * GEAR_RATIO;
const Direction DIRECTION = NORMAL_DIR;
// The scaling to apply to the motor's speed to match its real-world speed
float SPEED_SCALE = 5.4f;
constexpr float SPEED_SCALE = 5.4f;
// How many times to update the motor per second
const uint UPDATES = 100;

Wyświetl plik

@ -1,3 +1,4 @@
add_subdirectory(balance)
add_subdirectory(sequence)
add_subdirectory(song)
include(motorshim_dual_motors.cmake)
include(motorshim_movements.cmake)
include(motorshim_motor_song.cmake)
include(motorshim_single_motor.cmake)

Wyświetl plik

@ -0,0 +1,33 @@
# Pico Motor Shim C++ Examples <!-- omit in toc -->
- [Examples](#examples)
- [Single Motor](#single-motor)
- [Dual Motors](#dual-motors)
- [Movements](#movements)
- [Motor Song](#motor-song)
## Motor Examples
### Single Motor
[motorshim_single_motor.cpp](motorshim_single_motor.cpp)
Demonstrates how to create a Motor object and control it.
### Dual Motors
[motorshim_dual_motors.cpp](motorshim_dual_motors.cpp)
Demonstrates how to create two Motor objects and control them together.
### Movements
[motorshim_movements.cpp](motorshim_movements.cpp)
An example of how to perform simple movements of a 2-wheeled driving robot.
### Motor Song
[motorshim_motor_song.cpp](motorshim_motor_song.cpp)
A fun example of how to change a motor's frequency to have it play a song.

Wyświetl plik

@ -0,0 +1,12 @@
set(OUTPUT_NAME motorshim_dual_motors)
add_executable(${OUTPUT_NAME} motorshim_dual_motors.cpp)
target_link_libraries(${OUTPUT_NAME}
pico_stdlib
pico_motor_shim
)
# enable usb output
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,105 @@
#include <math.h>
#include "pico/stdlib.h"
#include "pico_motor_shim.hpp"
/*
Demonstrates how to create two Motor objects and control them together.
*/
using namespace motor;
// How many sweeps of the motors to perform
const uint SWEEPS = 2;
// The number of discrete sweep steps
const uint STEPS = 10;
// The time in milliseconds between each step of the sequence
const uint STEPS_INTERVAL_MS = 500;
// How far from zero to drive the motors when sweeping
constexpr float SPEED_EXTENT = 1.0f;
// Create an array of motor pointers
const pin_pair motor_pins[] = {pico_motor_shim::MOTOR_1, pico_motor_shim::MOTOR_2};
const uint NUM_MOTORS = count_of(motor_pins);
Motor *motors[NUM_MOTORS];
int main() {
stdio_init_all();
// Fill the array of motors, and initialise them. Up to 8 motors can be created
for(auto m = 0u; m < NUM_MOTORS; m++) {
motors[m] = new Motor(motor_pins[m]);
motors[m]->init();
}
// Uncomment the below lines to reverse
// the driving direction of a motor
// motors[0].direction(REVERSED_DIR);
// motors[1].direction(REVERSED_DIR);
// Enable all motors
for(auto m = 0u; m < NUM_MOTORS; m++) {
motors[m]->enable();
}
sleep_ms(2000);
// Drive at full positive
for(auto m = 0u; m < NUM_MOTORS; m++) {
motors[m]->full_positive();
}
sleep_ms(2000);
// Stop all moving
for(auto m = 0u; m < NUM_MOTORS; m++) {
motors[m]->stop();
}
sleep_ms(2000);
// Drive at full negative
for(auto m = 0u; m < NUM_MOTORS; m++) {
motors[m]->full_negative();
}
sleep_ms(2000);
// Coast all to a gradual stop
for(auto m = 0u; m < NUM_MOTORS; m++) {
motors[m]->coast();
}
sleep_ms(2000);
// Do a sine speed sweep
for(auto j = 0u; j < SWEEPS; j++) {
for(auto i = 0u; i < 360; i++) {
float speed = sin(((float)i * (float)M_PI) / 180.0f) * SPEED_EXTENT;
for(auto m = 0u; m < NUM_MOTORS; m++) {
motors[m]->speed(speed);
}
sleep_ms(20);
}
}
// Do a stepped speed sweep
for(auto j = 0u; j < SWEEPS; j++) {
for(auto i = 0u; i < STEPS; i++) {
for(auto m = 0u; m < NUM_MOTORS; m++) {
motors[m]->to_percent(i, 0, STEPS, 0.0 - SPEED_EXTENT, SPEED_EXTENT);
}
sleep_ms(STEPS_INTERVAL_MS);
}
for(auto i = 0u; i < STEPS; i++) {
for(auto m = 0u; m < NUM_MOTORS; m++) {
motors[m]->to_percent(i, STEPS, 0, 0.0 - SPEED_EXTENT, SPEED_EXTENT);
}
sleep_ms(STEPS_INTERVAL_MS);
}
}
// Disable the motors
for(auto m = 0u; m < NUM_MOTORS; m++) {
motors[m]->disable();
}
}

Wyświetl plik

@ -0,0 +1,13 @@
set(OUTPUT_NAME motorshim_motor_song)
add_executable(${OUTPUT_NAME} motorshim_motor_song.cpp)
target_link_libraries(${OUTPUT_NAME}
pico_stdlib
pico_motor_shim
button
)
# enable usb output
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -1,13 +1,13 @@
#include <stdio.h>
#include "pico_motor_shim.hpp"
#include "pico/stdlib.h"
#include "common/pimoroni_common.hpp"
#include "motor.hpp"
#include "pico_motor_shim.hpp"
#include "button.hpp"
/*
Play a song using a motor! Works by setting the PWM duty cycle to 50% and changing the frequency on the fly.
Plug a motor into connector 1, and press "A" to start the song playing (does not loop). Press the button again will stop the song early.
A fun example of how to change a motor's frequency to have it play a song.
Press "A" to start or stop the song.
*/
using namespace pimoroni;
@ -21,43 +21,41 @@ constexpr float SONG[] = {1397, 1397, 1319, 1397, 698, 0, 698, 0, 1047,
0, 1175, 1319, 1397, 1319, 1175, 1047, 1175, 1047, 932,
880, 932, 880, 784, 698, 784, 698, 659, 587, 523,
587, 659, 698, 784, 932, 880, 784, 880, 698, 0, 698};
constexpr uint SONG_LENGTH = sizeof(SONG) / sizeof(float);
constexpr uint SONG_LENGTH = count_of(SONG);
//The time (in milliseconds) to play each note for. Change this to make the song play faster or slower
static const uint NOTE_DURATION_MS = 150;
// The time (in seconds) to play each note for. Change this to make the song play faster or slower
const uint NOTE_DURATION_MS = 150;
//Uncomment this lineto have the song be played without the motor turning
//Note, this will affect the audio quality of the sound produced
//#define STATIONARY_PLAYBACK
// The time (in microseconds) between each direction switch of the motor when using STATIONARY_PLAYBACK
const uint STATIONARY_TOGGLE_US = 2000;
//The time (in microseconds) between each direction switch of the motor when using STATIONARY_PLAYBACK
static const uint STATIONARY_TOGGLE_US = 2000;
// Whether to play the song with or without the motors spinning
const bool STATIONARY_PLAYBACK = false;
//Uncomment this line to use the fast decay (coasting) motor mode.
//This seems to produce a louder sound with STATIONARY_PLAYBACK enabled, but will make movement poorer when STATIONARY_PLAYBACK is disabled
//#define USE_FAST_DECAY
// The motor decay mode to use, either FAST_DECAY (0) or SLOW_DECAY (1). Affects the song's quality
const DecayMode DECAY_MODE = SLOW_DECAY;
Button button_a(pico_motor_shim::BUTTON_A, Polarity::ACTIVE_LOW, 0);
// Create two motor objects with a given decay mode
Motor motor_1(pico_motor_shim::MOTOR_1);
Motor motor_2(pico_motor_shim::MOTOR_2);
static bool button_toggle = false;
// Create the user button
Button button_a(pico_motor_shim::BUTTON_A, Polarity::ACTIVE_LOW, 0);
/**
* Checks if the button has been pressed, toggling a value that is also returned.
*/
// Variable for recording if the button has been toggled
// Starting as true makes the song play automatically
static bool button_toggle = true;
// 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) {
if(button_a.read()) {
button_toggle = !button_toggle;
}
return button_toggle;
}
/**
* The entry point of the program.
*/
int main() {
stdio_init_all();
@ -65,28 +63,30 @@ int main() {
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
#ifdef USE_FAST_DECAY
motor_1.decay_mode(FAST_DECAY);
motor_2.decay_mode(FAST_DECAY);
#endif
// Se the two motor's decay modes
motor_1.decay_mode(DECAY_MODE);
motor_2.decay_mode(DECAY_MODE);
//Initialise the motor
// Initialise the motors
if(!motor_1.init() || !motor_2.init()) {
printf("Cannot initialise the motors. Check the provided parameters\n");
return 0;
}
while(true) {
// Has the button been toggled?
if(check_button_toggle()) {
//Turn the Pico's LED on to show that the song has started
// Turn the Pico's LED on to show that the song has started
gpio_put(PICO_DEFAULT_LED_PIN, true);
//Play the song
// Play the song
for(uint i = 0; i < SONG_LENGTH && check_button_toggle(); i++) {
if(motor_1.frequency(SONG[i]) && motor_2.frequency(SONG[i])) {
#ifdef STATIONARY_PLAYBACK
//Set the motors to 50% duty cycle to play the note, but alternate
//the direction so that the motor does not actually spin
// Get the frequency of the note and attempt to set the motors to it
float freq = SONG[i];
if(motor_1.frequency(freq) && motor_2.frequency(freq)) {
if(STATIONARY_PLAYBACK) {
// Set the motors to 50% duty cycle to play the note, but alternate
// the direction so that the motor does not actually spin
uint t = 0;
while(t < NOTE_DURATION_MS * 1000) {
motor_1.duty(0.5f);
@ -99,15 +99,16 @@ int main() {
sleep_us(STATIONARY_TOGGLE_US);
t += STATIONARY_TOGGLE_US;
}
#else
//Set the motors to 50% duty cycle to play the note
}
else {
// Set the motors to 50% duty cycle to play the note
motor_1.duty(0.5f);
motor_2.duty(0.5f);
sleep_ms(NOTE_DURATION_MS);
#endif
}
}
else {
//The frequency was invalid, so we are treating that to mean this is a pause note
// The frequency was invalid, so we are treating that to mean this is a pause note
motor_1.stop();
motor_2.stop();
sleep_ms(NOTE_DURATION_MS);
@ -115,7 +116,7 @@ int main() {
}
button_toggle = false;
//The song has finished, so turn off the Pico's LED and disable the motors
// The song has finished, so turn off the Pico's LED and disable the motors
gpio_put(PICO_DEFAULT_LED_PIN, false);
motor_1.disable();
motor_2.disable();

Wyświetl plik

@ -0,0 +1,12 @@
set(OUTPUT_NAME motorshim_movements)
add_executable(${OUTPUT_NAME} motorshim_movements.cpp)
target_link_libraries(${OUTPUT_NAME}
pico_stdlib
pico_motor_shim
)
# enable usb output
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,126 @@
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico_motor_shim.hpp"
/*
An example of how to perform simple movements of a 2-wheeled driving robot.
*/
using namespace motor;
// The scaling to apply to each motor's speed to match its real-world speed
constexpr float SPEED_SCALE = 5.4f;
// The speed to drive the wheels at, from 0.0 to SPEED_SCALE
constexpr float DRIVING_SPEED = SPEED_SCALE;
// Create the left and right motors with a given speed scale
// Swap the numbers and directions if this is different to your setup
Motor left(pico_motor_shim::MOTOR_1, NORMAL_DIR, SPEED_SCALE);
Motor right(pico_motor_shim::MOTOR_2, REVERSED_DIR, SPEED_SCALE);
// Helper functions for driving in common directions
void forward(float speed=DRIVING_SPEED) {
left.speed(speed);
right.speed(speed);
}
void backward(float speed=DRIVING_SPEED) {
left.speed(-speed);
right.speed(-speed);
}
void turn_left(float speed=DRIVING_SPEED) {
left.speed(-speed);
right.speed(speed);
}
void turn_right(float speed=DRIVING_SPEED) {
left.speed(speed);
right.speed(-speed);
}
void curve_forward_left(float speed=DRIVING_SPEED) {
left.speed(0.0);
right.speed(speed);
}
void curve_forward_right(float speed=DRIVING_SPEED) {
left.speed(speed);
right.speed(0.0);
}
void curve_backward_left(float speed=DRIVING_SPEED) {
left.speed(0.0);
right.speed(-speed);
}
void curve_backward_right(float speed=DRIVING_SPEED) {
left.speed(-speed);
right.speed(0.0);
}
void stop() {
left.stop();
right.stop();
}
void coast() {
left.coast();
right.coast();
}
int main() {
stdio_init_all();
// Initialise the motors
if(!left.init() || !right.init()) {
printf("Cannot initialise the motors. Check the provided parameters\n");
return 0;
}
// Demo each of the move methods
forward();
sleep_ms(1000);
backward();
sleep_ms(1000);
curve_forward_right();
sleep_ms(1000);
curve_forward_left();
sleep_ms(1000);
turn_right();
sleep_ms(1000);
forward(0.5 * DRIVING_SPEED); // Half speed
sleep_ms(1000);
turn_left(0.5 * DRIVING_SPEED); // Half speed
sleep_ms(1000);
curve_backward_right(0.75 * DRIVING_SPEED); // Three quarters speed
sleep_ms(1000);
forward(); // Full speed
sleep_ms(500);
coast(); // Come to a halt gently
sleep_ms(1000);
forward();
sleep_ms(500);
stop(); // Apply the brakes
sleep_ms(1000);
// Disable the motors
left.disable();
right.disable();
}

Wyświetl plik

@ -0,0 +1,12 @@
set(OUTPUT_NAME motorshim_single_motor)
add_executable(${OUTPUT_NAME} motorshim_single_motor.cpp)
target_link_libraries(${OUTPUT_NAME}
pico_stdlib
pico_motor_shim
)
# enable usb output
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,78 @@
#include <math.h>
#include "pico/stdlib.h"
#include "pico_motor_shim.hpp"
/*
Demonstrates how to create a Motor object and control it.
*/
using namespace motor;
// How many sweeps of the motor to perform
const uint SWEEPS = 2;
// The number of discrete sweep steps
const uint STEPS = 10;
// The time in milliseconds between each step of the sequence
const uint STEPS_INTERVAL_MS = 500;
// How far from zero to drive the motor when sweeping
constexpr float SPEED_EXTENT = 1.0f;
// Create a motor
Motor m = Motor(pico_motor_shim::MOTOR_1);
int main() {
stdio_init_all();
// Initialise the motor
m.init();
// Enable the motor
m.enable();
sleep_ms(2000);
// Drive at full positive
m.full_positive();
sleep_ms(2000);
// Stop moving
m.stop();
sleep_ms(2000);
// Drive at full negative
m.full_negative();
sleep_ms(2000);
// Coast to a gradual stop
m.coast();
sleep_ms(2000);
// Do a sine speed sweep
for(auto j = 0u; j < SWEEPS; j++) {
for(auto i = 0u; i < 360; i++) {
m.speed(sin(((float)i * (float)M_PI) / 180.0f) * SPEED_EXTENT);
sleep_ms(20);
}
}
// Do a stepped speed sweep
for(auto j = 0u; j < SWEEPS; j++) {
for(auto i = 0u; i < STEPS; i++) {
m.to_percent(i, 0, STEPS, 0.0 - SPEED_EXTENT, SPEED_EXTENT);
sleep_ms(STEPS_INTERVAL_MS);
}
for(auto i = 0u; i < STEPS; i++) {
m.to_percent(i, STEPS, 0, 0.0 - SPEED_EXTENT, SPEED_EXTENT);
sleep_ms(STEPS_INTERVAL_MS);
}
}
// Disable the motor
m.disable();
}

Wyświetl plik

@ -1,16 +0,0 @@
set(OUTPUT_NAME motor_shim_sequence)
add_executable(
${OUTPUT_NAME}
demo.cpp
)
# enable usb output, disable uart output
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
pico_enable_stdio_uart(${OUTPUT_NAME} 1)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_motor_shim motor button)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -1,170 +0,0 @@
#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;
}

Wyświetl plik

@ -1,16 +0,0 @@
set(OUTPUT_NAME motor_shim_song)
add_executable(
${OUTPUT_NAME}
demo.cpp
)
# enable usb output, disable uart output
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
pico_enable_stdio_uart(${OUTPUT_NAME} 1)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_motor_shim motor button breakout_msa301)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,40 @@
# Pico Motor Shim C++ Examples <!-- omit in toc -->
- [Examples](#examples)
- [Single Motor](#single-motor)
- [Dual Motors](#dual-motors)
- [Movements](#movements)
- [Motor Song](#motor-song)
- [Stop Motors](#stop-motors)
## Motor Examples
### Single Motor
[single_motor.py](single_motor.py)
Demonstrates how to create a Motor object and control it.
### Dual Motors
[dual_motors.py](dual_motors.py)
Demonstrates how to create two Motor objects and control them together.
### Movements
[movements.py](movements.py)
An example of how to perform simple movements of a 2-wheeled driving robot.
### Motor Song
[motor_song.py](motor_song.py)
A fun example of how to change a motor's frequency to have it play a song.
### Stop Motors
[stop_motors.py](motorshim_motor_song.py)
A simple program that stops the motors.

Wyświetl plik

@ -6,6 +6,8 @@ from pimoroni import Button
"""
A fun example of how to change a motor's frequency to have it play a song.
Press "A" to start or stop the song.
"""
# This handy dictionary converts notes into frequencies