From 06c77567716697fe063c643c1cb3f31b8f86825f Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 4 Feb 2024 20:27:36 -0800 Subject: [PATCH 1/3] Add CI --- .github/workflows/ci.yml | 51 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e874027 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,51 @@ +name: 'CI' +on: + pull_request: + push: + branches: + - main + +jobs: + find-latest-release: + uses: lf-lang/lingua-franca/.github/workflows/latest-release.yml@master + + check-compile: + runs-on: ubuntu-latest + needs: find-latest-release + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Set up Java 17 + run: | + echo "$JAVA_HOME_17_X64/bin" >> $GITHUB_PATH + echo "JAVA_HOME=$JAVA_HOME_17_X64" >> $GITHUB_ENV + shell: bash + - name: Install dev dependencies + run: | + sudo apt update + sudo apt install cmake make gcc gcc-arm-none-eabi libnewlib-arm-none-eabi + - uses: lf-lang/action-check-lf-files@main + with: + check_mode: "compile" + no_compile_flag: false + exclude_dirs: '["failing", "experimental"]' + checkout_dir: '../lingua-franca' + compiler_ref: ${{ needs.find-latest-release.outputs.ref }} + + check-format: + runs-on: ubuntu-latest + needs: find-latest-release + steps: + - uses: actions/checkout@v4 + - name: Set up Java 17 + run: | + echo "$JAVA_HOME_17_X64/bin" >> $GITHUB_PATH + echo "JAVA_HOME=$JAVA_HOME_17_X64" >> $GITHUB_ENV + shell: bash + - uses: lf-lang/action-check-lf-files@main + with: + check_mode: "format" + exclude_dirs: '["failing", "experimental"]' + checkout_dir: '../lingua-franca' + compiler_ref: ${{ needs.find-latest-release.outputs.ref }} \ No newline at end of file From f31b6bb7f7fd57642cb7fe65e4a5bb237bfab086 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 4 Feb 2024 20:31:44 -0800 Subject: [PATCH 2/3] Formatting and compatibility --- src/AccelerometerDisplay.lf | 60 +++++++++---------- src/Blink.lf | 7 ++- src/BumpDisplay.lf | 38 ++++++------ src/EncoderDisplay.lf | 10 ++-- src/GyroAngleDisplay.lf | 14 ++--- src/GyroDisplay.lf | 14 ++--- src/HelloPico.lf | 42 ++++++------- src/LineDisplay.lf | 14 ++--- src/RobotTemplate.lf | 27 ++++----- src/Timer.lf | 31 +++++----- src/lib/Bump.lf | 55 +++++++++-------- src/lib/Display.lf | 6 +- src/lib/Encoders.lf | 21 +++---- src/lib/IMU.lf | 109 +++++++++++++++++----------------- src/lib/Line.lf | 6 +- src/lib/Motors.lf | 20 ++++--- src/lib/MotorsWithFeedback.lf | 28 +++++---- src/test/MotorFeedbackTest.lf | 87 ++++++++++++++------------- src/test/MotorTest.lf | 16 ++--- 19 files changed, 307 insertions(+), 298 deletions(-) diff --git a/src/AccelerometerDisplay.lf b/src/AccelerometerDisplay.lf index 0353a46..43aaadd 100644 --- a/src/AccelerometerDisplay.lf +++ b/src/AccelerometerDisplay.lf @@ -1,50 +1,50 @@ /** * Display three dimensions of accelerometer measurements on the LCD display of the - * Pololu 3pi+ 2040 robot. - * To run this program, first put the robot in BOOTSEL mode (hold button B while - * resetting). Then the sequence of commands is something like this: - * + * Pololu 3pi+ 2040 robot. To run this program, first + * put the robot in BOOTSEL mode (hold button B while resetting). Then the sequence of commands is + * something like this: * ``` * $ cd ~/lf-pico * $ lfc src/AccelerometerDisplay.lf * ... * $ picotool load -x bin/AccelerometerDisplay.elf * ``` + * - * This compiles the program, loads it into flash memory on the robot, and begins - * executing it. + * This compiles the program, loads it into flash memory on the robot, and begins executing it. * * @author Edward A. Lee */ - target C { - platform: "RP2040", - threading: false, +target C { + platform: "RP2040", + single-threaded: true } import Accelerometer from "lib/IMU.lf" import Display from "lib/Display.lf" main reactor { - a = new Accelerometer() - d = new Display() - timer t(0, 250 msec) - reaction(t) -> a.trigger {= - lf_set(a.trigger, true); - =} + a = new Accelerometer() + d = new Display() + timer t(0, 250 msec) + + reaction(t) -> a.trigger {= + lf_set(a.trigger, true); + =} - reaction(a.x, a.y, a.z) -> d.line0, d.line1, d.line2 {= - /// TODO: define max string size for line - /// based on font you can have 4 or 8 lines - static char buf0[17]; - static char buf1[17]; - static char buf2[17]; + reaction(a.x, a.y, a.z) -> d.line0, d.line1, d.line2 {= + /// TODO: define max string size for line + /// based on font you can have 4 or 8 lines + static char buf0[17]; + static char buf1[17]; + static char buf2[17]; - snprintf(buf0, 17, "x:%2.4f", a.x->value); - snprintf(buf1, 17, "y:%2.4f", a.y->value); - snprintf(buf2, 17, "z:%2.4f", a.z->value); - - lf_set(d.line0, buf0); - lf_set(d.line1, buf1); - lf_set(d.line2, buf2); - =} -} \ No newline at end of file + snprintf(buf0, 17, "x:%2.4f", a.x->value); + snprintf(buf1, 17, "y:%2.4f", a.y->value); + snprintf(buf2, 17, "z:%2.4f", a.z->value); + + lf_set(d.line0, buf0); + lf_set(d.line1, buf1); + lf_set(d.line2, buf2); + =} +} diff --git a/src/Blink.lf b/src/Blink.lf index 71c82fb..f243ee6 100644 --- a/src/Blink.lf +++ b/src/Blink.lf @@ -9,7 +9,7 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true } preamble {= @@ -19,13 +19,14 @@ preamble {= =} main reactor { - timer t(0, 250 ms); - state led_on:bool = false; + timer t(0, 250 ms) + state led_on: bool = false reaction(startup) {= gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); =} + reaction(t) {= self->led_on = !self->led_on; printf("LED State: %b\n", self->led_on); diff --git a/src/BumpDisplay.lf b/src/BumpDisplay.lf index b711a6f..13f6b4a 100644 --- a/src/BumpDisplay.lf +++ b/src/BumpDisplay.lf @@ -1,7 +1,6 @@ /** * Display messages when the bump sensors on the - * Pololu 3pi+ 2040 robot - * are triggered. + * Pololu 3pi+ 2040 robot are triggered. * @author Abhi Gundrala * @author Edward A. Lee */ @@ -10,26 +9,29 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true } import Bump from "lib/Bump.lf" import Display from "lib/Display.lf" main reactor { - bump = new Bump(); - disp = new Display(); - logical action clear; - reaction(bump.left) -> disp.line0, clear {= - lf_set(disp.line0, "Left Bumped!"); - lf_schedule(clear, SEC(2)); - =} - reaction(bump.right) -> disp.line1, clear {= - lf_set(disp.line1, "Right Bumped!"); - lf_schedule(clear, SEC(2)); - =} - reaction(clear) -> disp.line0, disp.line1 {= - lf_set(disp.line0, ""); - lf_set(disp.line1, ""); - =} + bump = new Bump() + disp = new Display() + logical action clear + + reaction(bump.left) -> disp.line0, clear {= + lf_set(disp.line0, "Left Bumped!"); + lf_schedule(clear, SEC(2)); + =} + + reaction(bump.right) -> disp.line1, clear {= + lf_set(disp.line1, "Right Bumped!"); + lf_schedule(clear, SEC(2)); + =} + + reaction(clear) -> disp.line0, disp.line1 {= + lf_set(disp.line0, ""); + lf_set(disp.line1, ""); + =} } diff --git a/src/EncoderDisplay.lf b/src/EncoderDisplay.lf index 1791e4e..7960587 100644 --- a/src/EncoderDisplay.lf +++ b/src/EncoderDisplay.lf @@ -9,7 +9,7 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true } import Display from "lib/Display.lf" @@ -19,7 +19,7 @@ main reactor { display = new Display() encoder = new Encoders() - timer t(0, 1s) + timer t(0, 1 s) reaction(t) -> encoder.trigger {= lf_set(encoder.trigger, true); @@ -34,10 +34,10 @@ main reactor { snprintf(buf, 17, "L: %d", encoder.left->value); lf_set(display.line1, buf); =} - + reaction(encoder.right) -> display.line2 {= static char buf[17]; snprintf(buf, 17, "R: %d", encoder.right->value); - lf_set(display.line2, buf); + lf_set(display.line2, buf); =} -} \ No newline at end of file +} diff --git a/src/GyroAngleDisplay.lf b/src/GyroAngleDisplay.lf index f98b0ec..81084c0 100644 --- a/src/GyroAngleDisplay.lf +++ b/src/GyroAngleDisplay.lf @@ -1,9 +1,9 @@ /** * Display measurements from the gyroscope on the - * Pololu 3pi+ 2040 robot - * with integration so the result is in degrees since reset. - * The gyroscope is provided by an - * ST LMS6DSO inertial measurement unit. + * Pololu 3pi+ 2040 robot with integration so the + * result is in degrees since reset. The gyroscope is provided by an + * ST LMS6DSO inertial measurement + * unit. * @author Abhi Gundrala * @author Edward A. Lee */ @@ -12,7 +12,7 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true } import Display from "lib/Display.lf" @@ -22,7 +22,7 @@ main reactor { display = new Display() gyro = new GyroAngle() - timer t(0, 100ms) + timer t(0, 100 ms) reaction(t) -> gyro.trigger {= lf_set(gyro.trigger, true); @@ -49,4 +49,4 @@ main reactor { snprintf(buf, 17, "z: %.1f", gyro.z->value); lf_set(display.line3, buf); =} -} \ No newline at end of file +} diff --git a/src/GyroDisplay.lf b/src/GyroDisplay.lf index 89355d4..9bdf414 100644 --- a/src/GyroDisplay.lf +++ b/src/GyroDisplay.lf @@ -1,9 +1,9 @@ /** * Display measurements from the gyroscope on the - * Pololu 3pi+ 2040 robot. - * The gyroscope is provided by an - * ST LMS6DSO inertial measurement unit. - * The display shows angular velocity in degrees per second. + * Pololu 3pi+ 2040 robot. The gyroscope is provided + * by an + * ST LMS6DSO inertial measurement + * unit. The display shows angular velocity in degrees per second. * @author Abhi Gundrala * @author Edward A. Lee */ @@ -12,7 +12,7 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true } import Display from "lib/Display.lf" @@ -22,7 +22,7 @@ main reactor { display = new Display() gyro = new Gyro() - timer t(0, 100ms) + timer t(0, 100 ms) reaction(t) -> gyro.trigger {= lf_set(gyro.trigger, true); @@ -49,4 +49,4 @@ main reactor { snprintf(buf, 17, "z: %.1f", gyro.z->value); lf_set(display.line3, buf); =} -} \ No newline at end of file +} diff --git a/src/HelloPico.lf b/src/HelloPico.lf index 49284f1..ae88ac8 100644 --- a/src/HelloPico.lf +++ b/src/HelloPico.lf @@ -1,43 +1,42 @@ /** - * Simple test of use of printf with the Raspberry Pi 2040. - * To compile and run this program, put your RPi in BOOTSEL mode and - * go to the lf-pico directory and do this: - * + * Simple test of use of printf with the Raspberry Pi 2040. To compile and run this program, put + * your RPi in BOOTSEL mode and go to the lf-pico directory and do this: * ``` * $ lfc src/HelloPico.lf * $ picotool load -x bin/HelloPico.elf * ``` + * - * This will create a new serial port USB device on your host machine that - * you can use to connect to the running program and observe its printed - * outputs. You need to first find the name of the device. Here is an example: - * + * This will create a new serial port USB device on your host machine that you can use to connect to + * the running program and observe its printed outputs. You need to first find the name of the + * device. Here is an example: * ``` * $ ls /dev/*usb* * /dev/cu.usbmodem14201 /dev/tty.usbmodem14201 * ``` + * * From a terminal, connect to the first of these devices (the cu... one) using screen: - * * ``` * screen /dev/cu.usbmodem14201 115200 * ``` + * * The second argument is the baud rate. You should now see a sequence like this: - * * ``` * Hello World! 135 * Hello World! 136 * Hello World! 137 * Hello World! 138 * ``` + * - * You can get back to a normal terminal by detaching from screen by typing Control-A - * followed by d. You can reattach (and see any missing printing) using the command: - * + * You can get back to a normal terminal by detaching from screen by typing Control-A followed by d. + * You can reattach (and see any missing printing) using the command: * ``` * $ screen -r * ``` + * * @author Abhi Gundrala * @author Edward A. Lee @@ -47,18 +46,19 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true } preamble {= - #include - #include "pico/stdlib.h" + #include + #include "pico/stdlib.h" =} main reactor { - timer t1(0, 1 sec) - state count:int = 0 - reaction(t1) {= - printf("Hello World! %d\n", self->count++); - =} + timer t1(0, 1 sec) + state count: int = 0 + + reaction(t1) {= + printf("Hello World! %d\n", self->count++); + =} } diff --git a/src/LineDisplay.lf b/src/LineDisplay.lf index 0d1b41a..7bc0f1d 100644 --- a/src/LineDisplay.lf +++ b/src/LineDisplay.lf @@ -1,10 +1,9 @@ /** * Display the outputs from the line sensors on the - * Pololu 3pi+ 2040 robot. - * This program spends the first 10 seconds in calibration mode, during which - * you should move the robot over the light and dark areas that you would like - * it to detect. It then switches into measurement mode and displays the - * measured reflectance of the five IR sensors. + * Pololu 3pi+ 2040 robot. This program spends the + * first 10 seconds in calibration mode, during which you should move the robot over the light and + * dark areas that you would like it to detect. It then switches into measurement mode and displays + * the measured reflectance of the five IR sensors. * * @author Abhi Gundrala * @author Edward A. Lee @@ -14,7 +13,7 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true } import Line from "lib/Line.lf" @@ -25,8 +24,7 @@ main reactor(calibration_time: time = 10 s, sample_period: time = 100 ms) { disp = new Display() timer t(0, sample_period) - // Timer used to display seconds. - timer seconds(0, 1 s) + timer seconds(0, 1 s) // Timer used to display seconds. timer end_calibration(calibration_time) state count: int = 0 diff --git a/src/RobotTemplate.lf b/src/RobotTemplate.lf index dbc8e2b..a6955f6 100644 --- a/src/RobotTemplate.lf +++ b/src/RobotTemplate.lf @@ -1,29 +1,27 @@ /** - * Template for robot driving lab exercises. - * This template just periodically switches between a - * STOPPED and a DRIVING mode, updating the LCD display - * on each change of mode. + * Template for robot driving lab exercises. This template just periodically switches between a + * STOPPED and a DRIVING mode, updating the LCD display on each change of mode. */ target C { platform: { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true } import Display from "lib/Display.lf" reactor Robot { - input drive:bool // Toggle mode. - output notify:string // Notify of mode change. + input drive: bool // Toggle mode. + output notify: string // Notify of mode change. reaction(startup) -> notify {= lf_set(notify, "INIT"); =} initial mode STOPPED { - reaction(drive) -> DRIVING, notify {= + reaction(drive) -> reset(DRIVING), notify {= if (drive->value) { lf_set_mode(DRIVING); lf_set(notify, "DRIVING"); @@ -32,7 +30,7 @@ reactor Robot { } mode DRIVING { - reaction(drive) -> STOPPED, notify {= + reaction(drive) -> reset(STOPPED), notify {= if (!drive->value) { lf_set_mode(STOPPED); lf_set(notify, "STOPPED"); @@ -43,13 +41,14 @@ reactor Robot { main reactor { timer t(0, 2 sec) - state drive:bool = false + state drive: bool = false robot = new Robot() display = new Display() + robot.notify -> display.line0 + reaction(t) -> robot.drive {= - lf_set(robot.drive, self->drive); - // Toggle the drive state variable for next time. - self->drive = !self->drive; + lf_set(robot.drive, self->drive); + // Toggle the drive state variable for next time. + self->drive = !self->drive; =} - robot.notify -> display.line0; } diff --git a/src/Timer.lf b/src/Timer.lf index fc3099b..f4ed3f3 100644 --- a/src/Timer.lf +++ b/src/Timer.lf @@ -1,6 +1,6 @@ /** - * This simple demonstration program prints logical time, physical time, - * and lag (physical time minus logical time) once per second. + * This simple demonstration program prints logical time, physical time, and lag (physical time + * minus logical time) once per second. * @author Abhi Gundrala */ target C { @@ -8,23 +8,24 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, - timeout: 60 sec, + single-threaded: true, + timeout: 60 sec } preamble {= - #include - #include "pico/stdlib.h" + #include + #include "pico/stdlib.h" =} main reactor { - timer t1(0, 1 sec); - reaction(t1) {= - interval_t t = lf_time_logical_elapsed(); - interval_t T = lf_time_physical_elapsed(); - printf( - "Elapsed logical time %lld, physical time %lld, lag: %lld\n", - t, T, T-t - ); - =} + timer t1(0, 1 sec) + + reaction(t1) {= + interval_t t = lf_time_logical_elapsed(); + interval_t T = lf_time_physical_elapsed(); + printf( + "Elapsed logical time %lld, physical time %lld, lag: %lld\n", + t, T, T-t + ); + =} } diff --git a/src/lib/Bump.lf b/src/lib/Bump.lf index fd5162d..79281cf 100644 --- a/src/lib/Bump.lf +++ b/src/lib/Bump.lf @@ -1,13 +1,12 @@ /** * @brief Library reactor for the bump sensors on the - * Pololu 3pi+ 2040 robot. - * When this reactor detects a bump on the left or right, it produces a - * true value on the output. The period at which it periodically samples the bump - * sensors is a parameter. During startup, this reactor auto-calibrates the - * bump sensors. It recalibrates them each time it receives a calibrate input. + * Pololu 3pi+ 2040 robot. When this reactor detects + * a bump on the left or right, it produces a true value on the output. The period at which it + * periodically samples the bump sensors is a parameter. During startup, this reactor + * auto-calibrates the bump sensors. It recalibrates them each time it receives a calibrate input. * - * NOTE: The bump sensors cannot be used together with the line sensors. - * See Section 6.5 of the Pololu 3pi+ 2040 User's Guide. + * NOTE: The bump sensors cannot be used together with the line sensors. See Section 6.5 of the Pololu 3pi+ 2040 User's Guide. * * @author Abhi Gundrala * @author Edward A. Lee @@ -17,32 +16,32 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true } preamble {= - #include - // others + #include + // others =} -reactor Bump(sample_period:time = 100ms) { - timer t1(0, sample_period); - input calibrate:bool; - output left:bool; - output right:bool; +reactor Bump(sample_period: time = 100 ms) { + timer t1(0, sample_period) + input calibrate: bool + output left: bool + output right: bool - reaction(startup, calibrate) {= - bump_sensors_calibrate(); - =} - reaction(t1) -> left, right {= - bump_sensors_read(); - // only is_present when pressed - if (bump_sensor_left_is_pressed()) { - lf_set(left, true); - } - if (bump_sensor_right_is_pressed()) { - lf_set(right, true); - } - =} + reaction(startup, calibrate) {= + bump_sensors_calibrate(); + =} + reaction(t1) -> left, right {= + bump_sensors_read(); + // only is_present when pressed + if (bump_sensor_left_is_pressed()) { + lf_set(left, true); + } + if (bump_sensor_right_is_pressed()) { + lf_set(right, true); + } + =} } diff --git a/src/lib/Display.lf b/src/lib/Display.lf index fffdfa2..3492cc7 100644 --- a/src/lib/Display.lf +++ b/src/lib/Display.lf @@ -10,7 +10,7 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true, files: ["../../robot-lib/"], // Needed to find display.h cmake-include: ["../../robot-lib/robot-lib.txt"] // Needed to find display.h } @@ -21,7 +21,9 @@ preamble {= =} reactor Display { - preamble {= static bool _pololu_robot_display_initialized = false; =} + preamble {= + static bool _pololu_robot_display_initialized = false; + =} input line0: string // inputs input line1: string input line2: string diff --git a/src/lib/Encoders.lf b/src/lib/Encoders.lf index c1aa8a4..8cac3dd 100644 --- a/src/lib/Encoders.lf +++ b/src/lib/Encoders.lf @@ -1,10 +1,9 @@ /** * @brief Library reactors for the encoders on the - * Pololu 3pi+ 2040 robot. - * The output is the angle in degrees seen by the encoder. - * The angle increases or decreases as the motors move forward or backward. - * Eventually, you will get overflow and the angles will wrap around. - * The angles increase as the wheels rotate forward. + * Pololu 3pi+ 2040 robot. The output is the angle in + * degrees seen by the encoder. The angle increases or decreases as the motors move forward or + * backward. Eventually, you will get overflow and the angles will wrap around. The angles increase + * as the wheels rotate forward. * @author Abhi Gundrala * @author Edward A. Lee */ @@ -13,11 +12,11 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true } preamble {= - #include + #include #include #include @@ -29,15 +28,17 @@ preamble {= =} reactor Encoders { - input trigger:bool - output right:int32_t; - output left:int32_t; + input trigger: bool + output right: int32_t + output left: int32_t + reaction(startup) {= PIO pio = pio0; pio_add_program(pio, &quadrature_encoder_program); quadrature_encoder_program_init(pio, RIGHT_SM, RIGHT_ENCODER_AB, 0); quadrature_encoder_program_init(pio, LEFT_SM, LEFT_ENCODER_AB, 0); =} + reaction(trigger) -> left, right {= // Also, the sign is reversed, where reverse increases, so we negate. int32_t rcount = -quadrature_encoder_get_count(pio0, RIGHT_SM); diff --git a/src/lib/IMU.lf b/src/lib/IMU.lf index 876ee77..5001c61 100644 --- a/src/lib/IMU.lf +++ b/src/lib/IMU.lf @@ -1,11 +1,10 @@ /** - * Library reactors for the IMU on the - * Pololu 3pi+ 2040 robot. - * Note that these reactors rely on the fact that they are executed in an unthreaded - * runtime. To adapt them for a threaded runtime, they will need to use mutual - * exclusion to ensure that multiple instances of the reactors are not simultaneously - * accessing the shared hardware resource. - * + * Library reactors for the IMU on the + * Pololu 3pi+ 2040 robot. Note that these reactors + * rely on the fact that they are executed in an unthreaded runtime. To adapt them for a threaded + * runtime, they will need to use mutual exclusion to ensure that multiple instances of the reactors + * are not simultaneously accessing the shared hardware resource. + * * @author Abhi Gundrala * @author Edward A. Lee */ @@ -14,8 +13,8 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, - files: ["../../robot-lib/"], // Needed to find imu.h + single-threaded: true, + files: ["../../robot-lib/"], // Needed to find imu.h cmake-include: ["../../robot-lib/robot-lib.txt"] // Needed to find imu.h } @@ -24,9 +23,7 @@ preamble {= #include =} -/** - * Base class for IMU reactors. - */ +/** Base class for IMU reactors. */ reactor IMUBase { preamble {= // Static global IMU instance struct. @@ -35,11 +32,11 @@ reactor IMUBase { static bool _pololu_robot_imu_initialized = false; =} - input trigger:bool; - - output x:float; - output y:float; - output z:float; + input trigger: bool + + output x: float + output y: float + output z: float reaction(startup) {= if (!_pololu_robot_imu_initialized) { @@ -50,32 +47,32 @@ reactor IMUBase { } /** - * When triggered by an input (whose value is ignored), sample the accelerometer - * on the Pololu 3pi+ 2040 robot. - * The accelerometer is provided by an - * ST LMS6DSO inertial measurement unit. - * The outputs give acceleration in g's with a range of -2 to +2 g - * and a sensitivity of approximately 0.061 mg's. + * When triggered by an input (whose value is ignored), sample the accelerometer on the Pololu 3pi+ 2040 robot. The accelerometer is provided + * by an + * ST LMS6DSO inertial measurement + * unit. The outputs give acceleration in g's with a range of -2 to +2 g and a + * sensitivity of approximately 0.061 mg's. */ -reactor Accelerometer extends IMUBase { - reaction(trigger) -> x, y, z {= +reactor Accelerometer extends IMUBase { + reaction(trigger) -> x, y, z {= axes_data_t acc_data; - imu_read_acc(&imu_instance, &acc_data); + imu_read_acc(&imu_instance, &acc_data); - lf_set(x, acc_data.x); - lf_set(y, acc_data.y); - lf_set(z, acc_data.z); + lf_set(x, acc_data.x); + lf_set(y, acc_data.y); + lf_set(z, acc_data.z); =} } /** - * When triggered by an input (whose value is ignored), sample the gyroscope - * on the Pololu 3pi+ 2040 robot. - * The gyroscope is provided by an - * ST LMS6DSO inertial measurement unit. - * The outputs give angular velocity in degrees per second. + * When triggered by an input (whose value is ignored), sample the gyroscope on the Pololu 3pi+ 2040 robot. The gyroscope is provided by + * an + * ST LMS6DSO inertial measurement + * unit. The outputs give angular velocity in degrees per second. */ - reactor Gyro extends IMUBase { +reactor Gyro extends IMUBase { reaction(trigger) -> x, y, z {= axes_data_t gyro_data; imu_read_gyro(&imu_instance, &gyro_data); @@ -86,17 +83,17 @@ reactor Accelerometer extends IMUBase { } /** - * Integrate the sequence of inputs using the trapezoidal method. - * The first output is always zero. Subsequent outputs are the - * sum of the current and previous inputs multiplied by the time - * interval since the last input (in seconds) divided by two. + * Integrate the sequence of inputs using the trapezoidal method. The first output is always zero. + * Subsequent outputs are the sum of the current and previous inputs multiplied by the time interval + * since the last input (in seconds) divided by two. */ reactor TrapezoidalIntegrator { - input in:float - output out:float - reset state s:float = 0 - reset state prev_in:float = 0 - reset state prev_time:instant_t = 0 + input in: float + output out: float + reset state s: float = 0 + reset state prev_in: float = 0 + reset state prev_time: instant_t = 0 + reaction(in) -> out {= instant_t now = lf_time_logical(); if (self->prev_time > SEC(0)) { @@ -110,19 +107,19 @@ reactor TrapezoidalIntegrator { } /** - * When triggered by an input (whose value is ignored), sample the gyroscope - * on the Pololu 3pi+ 2040 robot - * and integrate its output. The output is an estimate of the angle (in degrees) - * of the robot relative to its angle when first triggered along each of three axes. - * The gyroscope is provided by an - * ST LMS6DSO inertial measurement unit. + * When triggered by an input (whose value is ignored), sample the gyroscope on the Pololu 3pi+ 2040 robot and integrate its output. The + * output is an estimate of the angle (in degrees) of the robot relative to its angle when first + * triggered along each of three axes. The gyroscope is provided by an + * ST LMS6DSO inertial measurement + * unit. */ - reactor GyroAngle { - input trigger:bool; - - output x:float; - output y:float; - output z:float; +reactor GyroAngle { + input trigger: bool + + output x: float + output y: float + output z: float g = new Gyro() integrator1 = new TrapezoidalIntegrator() diff --git a/src/lib/Line.lf b/src/lib/Line.lf index 32fb07f..a259a5c 100644 --- a/src/lib/Line.lf +++ b/src/lib/Line.lf @@ -25,7 +25,7 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true, files: ["../../robot-lib/"], // Needed to find ir_senrors.h cmake-include: ["../../robot-lib/robot-lib.txt"] // Needed to find ir_senrors.h } @@ -42,7 +42,9 @@ reactor Line { state calibrating: bool = true state calibrated: bool = false // Indicator of whether calibration has occurred at least once. - reaction(calibrate) {= self->calibrating = calibrate->value; =} + reaction(calibrate) {= + self->calibrating = calibrate->value; + =} reaction(trigger) -> reflect {= if (self->calibrating) { diff --git a/src/lib/Motors.lf b/src/lib/Motors.lf index d942bcf..c55057a 100644 --- a/src/lib/Motors.lf +++ b/src/lib/Motors.lf @@ -1,8 +1,8 @@ /** * @brief Library reactor for driving the motors on the - * Pololu 3pi+ 2040 robot. - * The power inputs should range from -1.0 to 1.0. Values outside this range - * will be clamped. Negative values indicate reverse direction. + * Pololu 3pi+ 2040 robot. The power inputs should + * range from -1.0 to 1.0. Values outside this range will be clamped. Negative values indicate + * reverse direction. * @author Abhi Gundrala * @author Edward A. Lee */ @@ -11,30 +11,36 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true, files: ["../../robot-lib/"], // Needed to find motors.h cmake-include: ["../../robot-lib/robot-lib.txt"] // Needed to find motors.h } + preamble {= #include =} + reactor Motors { - input left_power:float - input right_power:float + input left_power: float + input right_power: float + reaction(startup) {= motors_init(1); // 1 indicates no clock division. =} - method set_power(power:float, forward:bool, left:bool) {= + + method set_power(power: float, forward: bool, left: bool) {= power = fabsf(power); if (power > 1.0f) power = 1.0f; // Round down: uint16_t duty_cycle = (uint16_t)(power * MAX_MOTOR_POWER); motors_set_power(duty_cycle, forward, left); =} + reaction(left_power) {= bool forward = (left_power->value >= 0.0f); set_power(left_power->value, forward, true); =} + reaction(right_power) {= bool forward = (right_power->value >= 0.0f); set_power(right_power->value, forward, false); diff --git a/src/lib/MotorsWithFeedback.lf b/src/lib/MotorsWithFeedback.lf index 7bc0a69..c237edf 100644 --- a/src/lib/MotorsWithFeedback.lf +++ b/src/lib/MotorsWithFeedback.lf @@ -1,10 +1,10 @@ /** - * The MotorsWithFeedback reactor wraps the Motors reactor with feedback control. - * You specify the desired speed (in meters per second) on the `left_speed` and `right_speed` inputs - * and then provide the `left` and `right` encoder inputs. For each encoder input, the controller - * updates the power input to each of the motors in an attempt to get the speed to match the desired - * speed. This controller is proportional-integral (PI) controller with empirically chosen gains. - * It seems to work well with a sample period of about 50 ms. + * The MotorsWithFeedback reactor wraps the Motors reactor with feedback control. You specify the + * desired speed (in meters per second) on the `left_speed` and `right_speed` inputs and then + * provide the `left` and `right` encoder inputs. For each encoder input, the controller updates the + * power input to each of the motors in an attempt to get the speed to match the desired speed. This + * controller is proportional-integral (PI) controller with empirically chosen gains. It seems to + * work well with a sample period of about 50 ms. * @author Abhi Gundrala * @author Edward A. Lee */ @@ -13,7 +13,7 @@ target C { name: "rp2040", board: "pololu_3pi_2040_robot" }, - threading: false, + single-threaded: true } import Motors from "Motors.lf" @@ -26,12 +26,10 @@ preamble {= =} reactor MotorsWithFeedback(p_gain: float = 0.5, i_gain: float = 0.25) { - // Desired speed. - input left_speed: float + input left_speed: float // Desired speed. input right_speed: float - // Encoder inputs. - input left: int32_t + input left: int32_t // Encoder inputs. input right: int32_t motors = new Motors() @@ -48,9 +46,13 @@ reactor MotorsWithFeedback(p_gain: float = 0.5, i_gain: float = 0.25) { control_left.ctrl -> motors.left_power control_right.ctrl -> motors.right_power - reaction(left_speed) {= self->target_speed_left = left_speed->value; =} + reaction(left_speed) {= + self->target_speed_left = left_speed->value; + =} - reaction(right_speed) {= self->target_speed_right = right_speed->value; =} + reaction(right_speed) {= + self->target_speed_right = right_speed->value; + =} // React to encoder inputs. reaction(left, right) -> control_left.err, control_right.err {= diff --git a/src/test/MotorFeedbackTest.lf b/src/test/MotorFeedbackTest.lf index 8be739f..fbab22f 100644 --- a/src/test/MotorFeedbackTest.lf +++ b/src/test/MotorFeedbackTest.lf @@ -1,59 +1,58 @@ /** - * This tests the MotorsWithFeedback reactor by driving forward at 0.1 m/s for 3 seconds, - * stopping, the reversing at 0.2 m/s for 1.5 seconds, then stopping again. The robot should - * end up roughly where it started, even on a slope. + * This tests the MotorsWithFeedback reactor by driving forward at 0.1 m/s for 3 seconds, stopping, + * the reversing at 0.2 m/s for 1.5 seconds, then stopping again. The robot should end up roughly + * where it started, even on a slope. * @author Abhi Gundrala * @author Edward A. Lee */ target C { - platform: "RP2040", - threading: false, + platform: "RP2040", + single-threaded: true } import Display from "../lib/Display.lf" import Encoders from "../lib/Encoders.lf" -import MotorsWithFeedback from "../lib/MotorsWithFeedback.lf"; - +import MotorsWithFeedback from "../lib/MotorsWithFeedback.lf" preamble {= - // sprintf - #include + // sprintf + #include =} main reactor { - d0 = new Display(); - mf = new MotorsWithFeedback(); - e0 = new Encoders(); - - logical action next; - - timer t(0, 50 ms) - timer stop(3 s) - timer back(5 s) - timer stop_again(6500 ms) - - e0.right -> mf.right; - e0.left -> mf.left; - - reaction(t) -> e0.trigger {= - lf_set(e0.trigger, true); - =} - - reaction(startup) -> d0.line0, mf.left_speed, mf.right_speed {= - lf_set(d0.line0, "DRIVE"); - lf_set(mf.left_speed, 0.1); - lf_set(mf.right_speed, 0.1); - =} - - reaction(stop, stop_again) -> d0.line0, mf.left_speed, mf.right_speed {= - lf_set(d0.line0, "STOP"); - lf_set(mf.left_speed, 0.0); - lf_set(mf.right_speed, 0.0); - =} - - reaction(back) -> d0.line0, mf.left_speed, mf.right_speed {= - lf_set(d0.line0, "BACK"); - lf_set(mf.left_speed, -0.2); - lf_set(mf.right_speed, -0.2); - =} + d0 = new Display() + mf = new MotorsWithFeedback() + e0 = new Encoders() + + logical action next + + timer t(0, 50 ms) + timer stop(3 s) + timer back(5 s) + timer stop_again(6500 ms) + + e0.right -> mf.right + e0.left -> mf.left + + reaction(t) -> e0.trigger {= + lf_set(e0.trigger, true); + =} + + reaction(startup) -> d0.line0, mf.left_speed, mf.right_speed {= + lf_set(d0.line0, "DRIVE"); + lf_set(mf.left_speed, 0.1); + lf_set(mf.right_speed, 0.1); + =} + + reaction(stop, stop_again) -> d0.line0, mf.left_speed, mf.right_speed {= + lf_set(d0.line0, "STOP"); + lf_set(mf.left_speed, 0.0); + lf_set(mf.right_speed, 0.0); + =} + + reaction(back) -> d0.line0, mf.left_speed, mf.right_speed {= + lf_set(d0.line0, "BACK"); + lf_set(mf.left_speed, -0.2); + lf_set(mf.right_speed, -0.2); + =} } diff --git a/src/test/MotorTest.lf b/src/test/MotorTest.lf index 11a0005..2c4c97f 100644 --- a/src/test/MotorTest.lf +++ b/src/test/MotorTest.lf @@ -1,16 +1,16 @@ -/** - * Simple test of the motors that rotates the robot both ways. - */ - target C { +/** Simple test of the motors that rotates the robot both ways. */ +target C { platform: "RP2040", - threading: false, + single-threaded: true } + import Motors from "../lib/Motors.lf" main reactor { - timer t(0, 2s) - state right:bool = true + timer t(0, 2 s) + state right: bool = true motors = new Motors() + reaction(t) -> motors.left_power, motors.right_power {= float speed = 0.1f; if (!self->right) { @@ -22,4 +22,4 @@ main reactor { lf_set(motors.left_power, -speed); lf_set(motors.right_power, speed); =} -} \ No newline at end of file +} From 656c8042bcd446cb3e640cfa00767a29bc6165e2 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Sun, 4 Feb 2024 20:38:57 -0800 Subject: [PATCH 3/3] Update .github/workflows/ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e874027..83b7a1c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,4 +48,4 @@ jobs: check_mode: "format" exclude_dirs: '["failing", "experimental"]' checkout_dir: '../lingua-franca' - compiler_ref: ${{ needs.find-latest-release.outputs.ref }} \ No newline at end of file + compiler_ref: ${{ needs.find-latest-release.outputs.ref }}