diff --git a/coresdk/src/backend/gpio_driver.cpp b/coresdk/src/backend/gpio_driver.cpp index ef99839a..f5bb4035 100644 --- a/coresdk/src/backend/gpio_driver.cpp +++ b/coresdk/src/backend/gpio_driver.cpp @@ -128,6 +128,20 @@ namespace splashkit_lib } } } + + int sk_get_pwm_range(int pin) + { + if (check_pi()) + { + int result = get_PWM_range(pi, pin); + if (result < 0) + { + LOG(ERROR) << sk_gpio_error_message(result); + } + return result; + } + } + void sk_set_pwm_frequency(int pin, int frequency) { if (check_pi()) diff --git a/coresdk/src/backend/gpio_driver.h b/coresdk/src/backend/gpio_driver.h index c370b360..b155b8b4 100644 --- a/coresdk/src/backend/gpio_driver.h +++ b/coresdk/src/backend/gpio_driver.h @@ -191,6 +191,7 @@ namespace splashkit_lib void sk_gpio_set_pull_up_down(int pin, int pud); void sk_gpio_write(int pin, int value); void sk_set_pwm_range(int pin, int range); + void sk_get_pwm_range(int pin); void sk_set_pwm_frequency(int pin, int frequency); void sk_set_pwm_dutycycle(int pin, int dutycycle); void sk_gpio_clear_bank_1(); diff --git a/coresdk/src/coresdk/raspi_gpio.cpp b/coresdk/src/coresdk/raspi_gpio.cpp index 15915965..c10a0988 100644 --- a/coresdk/src/coresdk/raspi_gpio.cpp +++ b/coresdk/src/coresdk/raspi_gpio.cpp @@ -173,6 +173,21 @@ namespace splashkit_lib #endif } + int raspi_get_pwm_range(gpio_pin pin) + { +#ifdef RASPBERRY_PI + int bcmPin = boardToBCM(pin); + if (bcmPin >= 2) + { + return sk_get_pwm_range(bcmPin); + } + return -1; +#else + LOG(ERROR) << "Unable to get PWM range - GPIO not supported on this platform"; + return -1; +#endif + } + void raspi_set_pwm_frequency(gpio_pin pin, int frequency) { #ifdef RASPBERRY_PI @@ -242,58 +257,33 @@ namespace splashkit_lib return ""; #endif } + int raspi_get_servo_pulsewidth(gpio_pin pin) { #ifdef RASPBERRY_PI - if (has_gpio()) + int bcmPin = boardToBCM(pin); + // if the pin is not a PWM pin, return + if (bcmPin >= 2) { - gpio_pin pwmPins[] = {PIN_12, PIN_32, PIN_33, PIN_35}; - // if the pin is not a PWM pin, return - if (std::find(std::begin(pwmPins), std::end(pwmPins), pin) == std::end(pwmPins)) - { - LOG(ERROR) << "Pin " << pin << " is not a PWM pin"; - return -1; - } - int bcmPin = boardToBCM(pin); - // if the pin is not a PWM pin, return - if (bcmPin < 2) - { - LOG(ERROR) << "Pin " << pin << " is not a PWM pin"; - return -1; - } return sk_get_servo_pulsewidth(bcmPin); } - else - { - LOG(ERROR) << "Servo driver not supported on this platform"; - return -1; - } + return -1; #else - LOG(ERROR) << "Servo driver not supported on this platform"; + LOG(ERROR) << "Unable to get servo pulse width - GPIO not supported on this platform"; return -1; #endif } + void raspi_set_servo_pulsewidth(gpio_pin pin, int pulsewidth) { #ifdef RASPBERRY_PI - if (has_gpio()) + int bcmPin = boardToBCM(pin); + if (bcmPin >= 2) { - gpio_pin pwmPins[] = {PIN_12, PIN_32, PIN_33, PIN_35}; - // if the pin is not a PWM pin, return - if (std::find(std::begin(pwmPins), std::end(pwmPins), pin) == std::end(pwmPins)) - { - LOG(ERROR) << "Pin " << pin << " is not a PWM pin"; - return; // ← early return so we don’t drive an unsupported pin - } - int bcmPin = boardToBCM(pin); sk_set_servo_pulsewidth(bcmPin, pulsewidth); } - else - { - LOG(ERROR) << "Servo driver not supported on this platform"; - } #else - LOG(ERROR) << "Servo driver not supported on this platform"; + LOG(ERROR) << "Unable to set servo pulse width - GPIO not supported on this platform"; #endif } diff --git a/coresdk/src/coresdk/raspi_gpio.h b/coresdk/src/coresdk/raspi_gpio.h index 7deac88f..74005e8c 100644 --- a/coresdk/src/coresdk/raspi_gpio.h +++ b/coresdk/src/coresdk/raspi_gpio.h @@ -81,6 +81,16 @@ namespace splashkit_lib */ void raspi_set_pwm_range(gpio_pin pin, int range); + /** + * @brief Gets the PWM range for the specified pin. + * + * This function gets the PWM range for the specified pin. + * + * @param pin The pin to get the PWM range for. + * @returns The PWM range of the pin. + */ + int raspi_get_pwm_range(gpio_pin pin); + /** * @brief Sets the PWM frequency for the specified pin. * diff --git a/coresdk/src/coresdk/raspi_motor_driver.cpp b/coresdk/src/coresdk/raspi_motor_driver.cpp index d0434514..fee2177c 100644 --- a/coresdk/src/coresdk/raspi_motor_driver.cpp +++ b/coresdk/src/coresdk/raspi_motor_driver.cpp @@ -93,8 +93,9 @@ namespace splashkit_lib if (!dev || dev->id != MOTOR_DRIVER_PTR) return; // input speed goes from 0 to 1 - // output speed goes from 0 to 255 - int pwm_speed = static_cast(speed * 255); + // scale to EN pin's PWM range + int pwm_range = raspi_get_pwm_range(dev->en); + int pwm_speed = static_cast(speed * pwm_range); if (speed < 0) { speed = 0; @@ -114,14 +115,25 @@ namespace splashkit_lib #endif } - void stop_motor(motor_device dev) + void brake_motor(motor_device dev) { -#ifdef RASPBERRY_PI +#ifdef RAPSBERRY_PI if (!dev || dev->id != MOTOR_DRIVER_PTR) return; - // Brake: both inputs high + // L298N goes into brake mode when the two inputs are equal raspi_write(dev->in1, GPIO_HIGH); raspi_write(dev->in2, GPIO_HIGH); +#else + LOG(ERROR) << "motor driver not supported on this platform"; +#endif + } + + void stop_motor(motor_device dev) + { +#ifdef RASPBERRY_PI + if (!dev || dev->id != MOTOR_DRIVER_PTR) + return; + // L298N goes into coast mode when EN = LOW raspi_set_pwm_dutycycle(dev->en, GPIO_LOW); #else LOG(ERROR) << "Motor driver not supported on this platform"; @@ -135,7 +147,7 @@ namespace splashkit_lib return; raspi_write(dev->in1, GPIO_LOW); raspi_write(dev->in2, GPIO_LOW); - raspi_set_pwm_dutycycle(dev->en, GPIO_LOW); + raspi_set_pwm_dutycycle(dev->en, GPIO_LOW) _motor_devices.erase(dev->name); delete dev; #else diff --git a/coresdk/src/coresdk/raspi_motor_driver.h b/coresdk/src/coresdk/raspi_motor_driver.h index 1a4f6226..610f10a5 100644 --- a/coresdk/src/coresdk/raspi_motor_driver.h +++ b/coresdk/src/coresdk/raspi_motor_driver.h @@ -11,7 +11,7 @@ #include #include -#include "backend_types.h" // for pointer_identifier +#include "backend_types.h" // for pointer_identifier #include "easylogging++.h" #include "types.h" @@ -42,14 +42,11 @@ * @attribute class motor_device */ namespace splashkit_lib { - /** * @brief Opaque handle for an L298N motor driver instance. */ typedef struct _motor_data *motor_device; - - /** * Checks if a motor device with the given name is already opened. * @param name Identifier for the motor driver. @@ -93,6 +90,12 @@ namespace splashkit_lib { * Stops the motor immediately (brake). * @param dev The motor device handle. */ + void brake_motor(motor_device dev); + + /** + * Stops the motor and allows it to coast to a stop. + * @param dev The motor device handle. + */ void stop_motor(motor_device dev); /** @@ -111,7 +114,6 @@ namespace splashkit_lib { * Closes all opened motor devices. */ void close_all_motors(); - } #endif // RASPI_MOTOR_DRIVER_H diff --git a/coresdk/src/coresdk/raspi_servo_driver.cpp b/coresdk/src/coresdk/raspi_servo_driver.cpp index ab638482..8177e469 100644 --- a/coresdk/src/coresdk/raspi_servo_driver.cpp +++ b/coresdk/src/coresdk/raspi_servo_driver.cpp @@ -18,11 +18,13 @@ namespace splashkit_lib pointer_identifier id; std::string name; gpio_pin pin; + double min_angle, max_angle; }; static std::map _servo_devices; - static const unsigned MIN_PW = 500; // µs at 0° - static const unsigned MAX_PW = 2500; // µs at 180° + // Pulse widths for the min and max values of servo range + static const unsigned MIN_PW = 500; + static const unsigned MAX_PW = 2500; bool has_servo_device(const std::string &name) { @@ -35,7 +37,7 @@ namespace splashkit_lib return (it != _servo_devices.end()) ? it->second : nullptr; } - servo_device open_servo(const std::string &name, gpio_pin control_pin) + servo_device open_servo(const std::string &name, gpio_pin control_pin, double min_angle, double max_angle) { #ifdef RASPBERRY_PI if (has_servo_device(name)) @@ -45,9 +47,11 @@ namespace splashkit_lib raspi_init(); auto dev = new _servo_data(); - dev->id = SERVO_DRIVER_PTR; // you'll need to #define this in backend_types.h + dev->id = SERVO_DRIVER_PTR; // defined SERVO_DRIVER_PTR in backend_types.h dev->name = name; dev->pin = control_pin; + dev->min_angle = min_angle; + dev->max_angle = max_angle; // configure as output raspi_set_mode(control_pin, GPIO_OUTPUT); @@ -65,17 +69,34 @@ namespace splashkit_lib #endif } + void set_servo_value(servo_device dev, double value) + { +#ifdef RASPBERRY_PI + if (!dev || dev->id != SERVO_DRIVER_PTR) + return; + + // input value is 0..1 + // scale to servo pulse width range + unsigned pw = static_cast(value * (MAX_PW - MIN_PW) + MIN_PW); + raspi_set_servo_pulsewidth(dev->pin, pw); +#else + LOG(ERROR) << "Servo driver not supported on this platform"; +#endif + } + void set_servo_angle(servo_device dev, double angle) { #ifdef RASPBERRY_PI if (!dev || dev->id != SERVO_DRIVER_PTR) return; - // clamp to [0,180] - angle = std::clamp(angle, 0.0, 180.0); - unsigned pw = static_cast( - MIN_PW + (angle / 180.0) * (MAX_PW - MIN_PW)); - // raspi_set_pwm_dutycycle(dev->pin, pw); + double min = dev->min_angle; + double max = dev->max_angle; + + // clamp input to servo range + angle = std::clamp(angle, min, max); + // scale angle to pulse width range + unsigned pw = static_cast((angle - min / max - min) * (MAX_PW - MIN_PW) + MIN_PW); raspi_set_servo_pulsewidth(dev->pin, pw); #else LOG(ERROR) << "Servo driver not supported on this platform"; diff --git a/coresdk/src/coresdk/raspi_servo_driver.h b/coresdk/src/coresdk/raspi_servo_driver.h index b4ac9750..868204f1 100644 --- a/coresdk/src/coresdk/raspi_servo_driver.h +++ b/coresdk/src/coresdk/raspi_servo_driver.h @@ -67,10 +67,20 @@ namespace splashkit_lib * Open (and initialize) a servo on the given board pin. * @param name Your identifier for this servo. * @param control_pin Board‐numbered GPIO pin for the servo signal line. + * @param min_angle The minimum angle of this servo in degrees, defaults to 0. + * @param max_angle The maximum angle of this servo in degrees, defaults to 180. * @returns A valid servo_device, or nullptr on failure. */ - servo_device open_servo(const std::string &name, gpio_pin control_pin); + servo_device open_servo(const std::string &name, gpio_pin control_pin, double min_angle = 0, double max_angle = 180); + /** + * Maps 0..1 to the pulse width range of a servo. + * Useful if someone doesn't know the min and max angle of a servo device. + * @param dev The servo device to control. + * @param value The value, from 0 (min) to 1 (max) to set the servo to. + */ + void set_servo_value(servo_device dev, double value); + /** * Convenience: map an angle (0…180°) into the 500…2500 µs range. * This is a linear mapping, so it may not be accurate for all servos. diff --git a/coresdk/src/test/test_raspi_servo.cpp b/coresdk/src/test/test_raspi_servo.cpp index 50cc67fc..3294d84b 100644 --- a/coresdk/src/test/test_raspi_servo.cpp +++ b/coresdk/src/test/test_raspi_servo.cpp @@ -25,7 +25,7 @@ void run_servo_driver_tests() // Pause until user is ready write_line("Press ENTER to begin...\n"); - read_line(); // splashkit’s line-reader :contentReference[oaicite:0]{index=0} + read_line(); // splashkit’s line-reader // Open the servo on board pin 12 servo_device srv = open_servo("TestServo", PIN_12); @@ -44,7 +44,7 @@ void run_servo_driver_tests() for (int deg = 0; deg <= 180; deg += STEP_DEG) { set_servo_angle(srv, deg); - delay(DELAY_MS); // splashkit’s millisecond delay :contentReference[oaicite:1]{index=1} + delay(DELAY_MS); // splashkit’s millisecond delay } // Hold at 180° for a second