kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Ported shim examples to C++, and tidy up
rodzic
3c3a8c1752
commit
fac3e7365a
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
|
@ -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.
|
|
@ -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})
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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})
|
|
@ -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();
|
|
@ -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})
|
|
@ -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();
|
||||
}
|
|
@ -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})
|
|
@ -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();
|
||||
}
|
|
@ -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})
|
|
@ -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;
|
||||
}
|
|
@ -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})
|
|
@ -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.
|
|
@ -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
|
||||
|
|
Ładowanie…
Reference in New Issue