All Downloads are FREE. Search and download functionalities are using the official Maven repository.

.pi4j.pi4j-example.1.2.M1.source-code.PCA9685GpioServoExample Maven / Gradle / Ivy

/*
 * #%L
 * **********************************************************************
ORGANIZATION  :  Pi4J
PROJECT       :  Pi4J :: Java Examples
FILENAME      :  PCA9685GpioServoExample.java

This file is part of the Pi4J project. More information about
this project can be found here:  http://www.pi4j.com/
**********************************************************************
 * %%
 * Copyright (C) 2012 - 2018 Pi4J
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Scanner;

import com.pi4j.component.servo.Servo;
import com.pi4j.component.servo.impl.GenericServo;
import com.pi4j.component.servo.impl.GenericServo.Orientation;
import com.pi4j.component.servo.impl.PCA9685GpioServoProvider;
import com.pi4j.gpio.extension.pca.PCA9685GpioProvider;
import com.pi4j.gpio.extension.pca.PCA9685Pin;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinPwmOutput;
import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CFactory;
import com.pi4j.io.i2c.I2CFactory.UnsupportedBusNumberException;

/**
 * Simple servo tester application demonstrating Pi4J's Servo component.
 *
 * @author Christian Wehrli
 * @see Servo
 * @see com.pi4j.gpio.extension.pca.PCA9685GpioProvider
 */
public class PCA9685GpioServoExample {

    //------------------------------------------------------------------------------------------------------------------
    // main
    //------------------------------------------------------------------------------------------------------------------
    public static void main(String args[]) throws Exception {
        System.out.println("<--Pi4J--> PCA9685 Servo Tester Example ... started.");
        PCA9685GpioServoExample example = new PCA9685GpioServoExample();
        Scanner scanner = new Scanner(System.in);
        char command = ' ';
        while (command != 'x') {
            printUsage();
            command = readCommand(scanner);
            switch (command) {
                case 'c' : // Choose Channel
                    example.chooseChannel(scanner);
                    break;
                case 'n' : // Neutral Position
                    example.approachNeutralPosition();
                    break;
                case 'm' : // Move
                    example.move(scanner);
                    break;
                case 's' : // Sub Trim
                    example.subtrim(scanner);
                    break;
                case 'r' : // Reverse
                    example.reverse();
                    break;
                case 't' : // Travel (adjust endpoints)
                    example.travel(scanner);
                    break;
                case 'p' : // Sweep
                    example.sweep(scanner);
                    break;
                case 'i' : // Info
                    example.info();
                    break;
                case 'x' : // Exit
                    System.out.println("Servo Example - END.");
                    break;
                case ' ' :
                    System.err.println("Invalid input.");
                    break;
                default :
                    System.err.println("Unknown command [" + command + "].");
                    break;
            }
        }

        System.out.println("Exiting PCA9685GpioServoExample");
    }

    private static char readCommand(Scanner scanner) {
        char result = ' ';
        String input = scanner.nextLine();
        if (input.trim().isEmpty() == false) {
            result = input.trim().toLowerCase().charAt(0);
        }
        return result;
    }

    private static void printUsage() {
        System.out.println("");
        System.out.println("|- Commands ---------------------------------------------------------------------");
        System.out.println("| c : choose active servo channel                                                ");
        System.out.println("| n : neutral - approach neutral position                                        ");
        System.out.println("| m : move servo position                                                        ");
        System.out.println("| s : subtrim                                                                    ");
        System.out.println("| r : reverse servo direction                                                    ");
        System.out.println("| t : travel - adjust endpoints                                                  ");
        System.out.println("| p : sweep - continuously move between max left and max right position)         ");
        System.out.println("| i : info - provide info for all servo channels                                 ");
        System.out.println("| x : exit                                                                       ");
        System.out.println("|--------------------------------------------------------------------------------");
    }

    //------------------------------------------------------------------------------------------------------------------
    // PCA9685GpioProvider
    //------------------------------------------------------------------------------------------------------------------
    private final PCA9685GpioProvider gpioProvider;
    private final PCA9685GpioServoProvider gpioServoProvider;

    private final Servo[] servos;
    private int activeServo;

    public PCA9685GpioServoExample() throws Exception {
        gpioProvider = createProvider();

        // Define outputs in use for this example
        provisionPwmOutputs(gpioProvider);

        gpioServoProvider = new PCA9685GpioServoProvider(gpioProvider);

        servos = new Servo[16];

        // Provide servo on channel 0
        servos[0] = new GenericServo(gpioServoProvider.getServoDriver(PCA9685Pin.PWM_00), "Servo_1 (default settings)");

        // Provide servo on channel 1
        servos[1] = new GenericServo(gpioServoProvider.getServoDriver(PCA9685Pin.PWM_01), "Servo_2 (max. endpoints)");
        servos[1].setProperty(Servo.PROP_END_POINT_LEFT, Float.toString(Servo.END_POINT_MAX));
        servos[1].setProperty(Servo.PROP_END_POINT_RIGHT, Float.toString(Servo.END_POINT_MAX));

        // Provide servo on channel 2
        servos[2] = new GenericServo(gpioServoProvider.getServoDriver(PCA9685Pin.PWM_02), "Servo_3 (subtrim)");
        servos[2].setProperty(Servo.PROP_SUBTRIM, Float.toString(Servo.SUBTRIM_MAX_LEFT));

        // Provide servo on channel 3
        servos[3] = new GenericServo(gpioServoProvider.getServoDriver(PCA9685Pin.PWM_03), "Servo_4 (reverse)");
        servos[3].setProperty(Servo.PROP_IS_REVERSE, Boolean.toString(true));

        // Set active servo
        activeServo = 0;
    }

    public void chooseChannel(Scanner scanner) {
        System.out.println("");
        System.out.println("|- Choose channel ---------------------------------------------------------------");
        System.out.println("| Choose active servo channel [0..15]                                            ");
        System.out.println("| Example: 0                                                              ");
        System.out.println("|--------------------------------------------------------------------------------");

        int channel = -1;
        boolean isValidChannel = false;
        while (isValidChannel == false) {
            String input = null;
            try {
                input = scanner.nextLine();
                channel = Integer.parseInt(input);
                if (channel >= 0 && channel <= 15) {
                    isValidChannel = true;
                } else {
                    System.err.println("Unsupported servo channel [" + channel + "], provide number between 0 and 15.");
                }
            } catch (NumberFormatException e) {
                System.err.println("Invalid input [" + input + "], provide number between 0 and 15.");
            }
        }
        activeServo = channel;
        System.out.println("Active servo channel: " + activeServo);
    }

    public void approachNeutralPosition() {
        System.out.println("Approach neutral position");
        servos[activeServo].setPosition(0);
    }

    public void move(Scanner scanner) {
        System.out.println("");
        System.out.println("|- Move Position ----------------------------------------------------------------");
        System.out.println("| Move servo position to the left or to the right.                               ");
        System.out.println("| Example: l10 this would move the servo from its current position to the ");
        System.out.println("|          left by 10%                                                           ");
        System.out.println("| Example: r this would move the servo from its current position to the   ");
        System.out.println("|          right by 1%                                                           ");
        System.out.println("| -> subsequent single  will repeat the previous command                  ");
        System.out.println("| -> max travel to either side is 100%                                           ");
        System.out.println("| Exit command: x                                                         ");
        System.out.println("|--------------------------------------------------------------------------------");

        String command = null;
        while ("x".equals(command) == false) {
            float currentPosition = servos[activeServo].getPosition();
            System.out.println("Current servo position: " + currentPosition);
            String input = scanner.nextLine();
            if (input.trim().isEmpty() == false) {
                command = input.trim().toLowerCase();
            }
            if (command != null) {
                int sign;
                if (command.startsWith("l")) {
                    sign = -1;
                } else if (command.startsWith("r")) {
                    sign = 1;
                } else if (command.equals("x")) {
                    continue;
                } else {
                    System.err.println("Unknown command [" + command + "].");
                    command = null;
                    continue;
                }

                int moveAmount = 1;
                try {
                    moveAmount = Integer.parseInt(command.substring(1));
                    if (moveAmount < 0 || moveAmount > 100) {
                        moveAmount = 1;
                        System.out.println("Move amount is out of range - defaulted to [1].");
                    }
                    System.out.println("Move amount is [" + moveAmount + "].");
                } catch (Exception e) {
                    System.out.println("Move amount defaulted to [1].");
                }
                float newPosition = currentPosition + moveAmount * sign;
                if (newPosition < Servo.POS_MAX_LEFT) {
                    newPosition = Servo.POS_MAX_LEFT;
                    System.out.println("Max left position exceeded - set position to " + Servo.POS_MAX_LEFT + "%");
                } else if (newPosition > Servo.POS_MAX_RIGHT) {
                    newPosition = Servo.POS_MAX_RIGHT;
                    System.out.println("Max right position exceeded - set position to " + Servo.POS_MAX_RIGHT + "%");
                }
                servos[activeServo].setPosition(newPosition);
                command = (sign == 1 ? "r" : "l") + moveAmount;
            }
        }
    }

    public void subtrim(Scanner scanner) {
        System.out.println("");
        System.out.println("|- Subtrim, adjust servo neutral position ---------------------------------------");
        System.out.println("| Example: r this would move the servos neutral position by one step to   ");
        System.out.println("|          the right                                                             ");
        System.out.println("| Example: l this would move the servos neutral position by one step to   ");
        System.out.println("|          the left                                                              ");
        System.out.println("| -> subsequent single  will repeat the previous command                  ");
        System.out.println("| -> max adjustment to either side is 200 steps                                  ");
        System.out.println("| Exit command: x                                                         ");
        System.out.println("|--------------------------------------------------------------------------------");
        System.out.println("| Current Servo position: " + servos[activeServo].getPosition() + "]             ");
        System.out.println("|--------------------------------------------------------------------------------");

        String command = null;
        while ("x".equals(command) == false) {
            String propertySubtrim = servos[activeServo].getProperty(Servo.PROP_SUBTRIM, Servo.PROP_SUBTRIM_DEFAULT);
            int currentSubtrim = Integer.parseInt(propertySubtrim);
            System.out.println("Current subtrim: " + currentSubtrim);
            String input = scanner.nextLine();
            if (input.trim().isEmpty() == false) {
                command = input.trim().toLowerCase();
            }
            if (command != null) {
                int moveAmount;
                if (command.startsWith("l")) {
                    moveAmount = -1;
                } else if (command.startsWith("r")) {
                    moveAmount = 1;
                } else if (command.equals("x")) {
                    continue;
                } else {
                    System.err.println("Unknown command [" + command + "].");
                    command = null;
                    continue;
                }

                float newSubtrim = currentSubtrim + moveAmount;
                if (newSubtrim < Servo.SUBTRIM_MAX_LEFT) {
                    newSubtrim = Servo.SUBTRIM_MAX_LEFT;
                    System.out.println("Max left subtrim exceeded - set value to " + Servo.SUBTRIM_MAX_LEFT);
                } else if (newSubtrim > Servo.SUBTRIM_MAX_RIGHT) {
                    newSubtrim = Servo.SUBTRIM_MAX_RIGHT;
                    System.out.println("Max right subtrim exceeded - set value to " + Servo.SUBTRIM_MAX_RIGHT);
                }
                servos[activeServo].setProperty(Servo.PROP_SUBTRIM, Float.toString(newSubtrim));
            }
        }
    }

    public void reverse() {
        boolean isReverse = Boolean.parseBoolean(servos[activeServo].getProperty(Servo.PROP_IS_REVERSE));
        Boolean newValue = isReverse ? Boolean.FALSE : Boolean.TRUE;
        servos[activeServo].setProperty(Servo.PROP_IS_REVERSE, newValue.toString());
        System.out.println("is reverse: " + newValue);
    }

    public void travel(Scanner scanner) {
        System.out.println("");
        System.out.println("|- Travel -----------------------------------------------------------------------");
        System.out.println("| Adjust endpoints.                                                              ");
        System.out.println("| Example: r125  adjust RIGHT endpoint to 125                             ");
        System.out.println("| -> min: 0, max: 150, default 100                                               ");
        System.out.println("| Exit command: x                                                         ");
        System.out.println("|--------------------------------------------------------------------------------");

        String command = null;
        while ("x".equals(command) == false) {
            String propertyEndpointLeft = servos[activeServo].getProperty(Servo.PROP_END_POINT_LEFT, Servo.PROP_END_POINT_DEFAULT);
            String propertyEndpointRight = servos[activeServo].getProperty(Servo.PROP_END_POINT_RIGHT, Servo.PROP_END_POINT_DEFAULT);
            System.out.println("Current endpoints: LEFT [" + propertyEndpointLeft + "], RIGHT [" + propertyEndpointRight + "]");

            String input = scanner.nextLine();
            if (input.trim().isEmpty() == false) {
                command = input.trim().toLowerCase();
            }
            if (command != null) {
                String propertyToAdjust;
                if (command.startsWith("l")) {
                    propertyToAdjust = Servo.PROP_END_POINT_LEFT;
                } else if (command.startsWith("r")) {
                    propertyToAdjust = Servo.PROP_END_POINT_RIGHT;
                } else if (command.equals("x")) {
                    continue;
                } else {
                    System.err.println("Unknown command [" + command + "].");
                    command = null;
                    continue;
                }

                int newEndpointValue;
                try {
                    newEndpointValue = Integer.parseInt(command.substring(1));
                    if (newEndpointValue < Servo.END_POINT_MIN || newEndpointValue > Servo.END_POINT_MAX) {
                        System.out.println("Endpoint value is out of range - defaulted to [" + Servo.PROP_END_POINT_DEFAULT + "].");
                        newEndpointValue = Integer.parseInt(Servo.PROP_END_POINT_DEFAULT);
                    }
                    System.out.println("New value for property [" + propertyToAdjust + "]: " + newEndpointValue + "");
                } catch (Exception e) {
                    System.out.println("Endpoint value for property [" + propertyToAdjust + "] defaulted to [" + Servo.PROP_END_POINT_DEFAULT + "].");
                    newEndpointValue = Integer.parseInt(Servo.PROP_END_POINT_DEFAULT);
                }
                servos[activeServo].setProperty(propertyToAdjust, Integer.toString(newEndpointValue));
            }
        }
    }

    public void sweep(Scanner scanner) throws Exception {
        System.out.println("");
        System.out.println("|- Sweep ------------------------------------------------------------------------");
        System.out.println("| Continuously moves the servo between POS_MAX_LEFT and POS_MAX_RIGHT.           ");
        System.out.println("| To change speed provide value between 1 and 10 (10 for max speed)              ");
        System.out.println("| Example: 7                                                              ");
        System.out.println("| Default speed: 5                                                               ");
        System.out.println("| Exit command: x                                                         ");
        System.out.println("|--------------------------------------------------------------------------------");

        // create and start sweeper thread
        Sweeper sweeper = new Sweeper();
        sweeper.start();

        // handle user commands
        String command = null;
        while ("x".equals(command) == false) {
            String input = scanner.nextLine();
            if (input.trim().isEmpty() == false) {
                command = input.trim().toLowerCase();
            }
            if (command != null) {
                if (command.equals("x")) {
                    continue;
                }
                try {
                    int speed = Integer.parseInt(command);
                    sweeper.setSpeed(speed);
                } catch (NumberFormatException e) {
                    System.err.println("Invalid speed value [" + command + "]. Allowed values [1..10] ");
                }
            }
        }
        sweeper.interrupt();
        servos[activeServo].setPosition(Servo.POS_NEUTRAL);
    }

    public void info() {
        for (int i = 0; i < servos.length; i++) {
            Servo servo = servos[i];
            System.out.println("Channel " + (i < 10 ? " " : "") + i + ": " + (servo != null ? servo.toString() : "N.A."));
        }
    }

    //------------------------------------------------------------------------------------------------------------------
    // Helpers
    //------------------------------------------------------------------------------------------------------------------
    private PCA9685GpioProvider createProvider() throws UnsupportedBusNumberException, IOException {
        BigDecimal frequency = PCA9685GpioProvider.ANALOG_SERVO_FREQUENCY;
        BigDecimal frequencyCorrectionFactor = new BigDecimal("1.0578");

        I2CBus bus = I2CFactory.getInstance(I2CBus.BUS_1);
        return new PCA9685GpioProvider(bus, 0x40, frequency, frequencyCorrectionFactor);
    }

    private GpioPinPwmOutput[] provisionPwmOutputs(final PCA9685GpioProvider gpioProvider) {
        GpioController gpio = GpioFactory.getInstance();
        GpioPinPwmOutput myOutputs[] = {
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_00, "Servo 00"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_01, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_02, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_03, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_04, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_05, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_06, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_07, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_08, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_09, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_10, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_11, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_12, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_13, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_14, "not used"),
                gpio.provisionPwmOutputPin(gpioProvider, PCA9685Pin.PWM_15, "not used")};
        return myOutputs;
    }

    private class Sweeper extends Thread {

        private int speed = 5;
        private final int step = 1; // make sure this is always true: 100 % step = 0
        private final int maxSleepBetweenSteps = 100;

        @Override
        public void run() {
            int position = 0;
            Orientation orientation = Orientation.RIGHT;
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    if (orientation == Orientation.RIGHT) {
                        if (position < Servo.POS_MAX_RIGHT) {
                            position += step;
                        } else {
                            orientation = Orientation.LEFT;
                            position -= step;
                        }
                    } else if (orientation == Orientation.LEFT) {
                        if (position > Servo.POS_MAX_LEFT) {
                            position -= step;
                        } else {
                            orientation = Orientation.RIGHT;
                            position += step;
                        }
                    } else {
                        System.err.println("Unsupported value for enum : [" + orientation + "].");
                    }

                    servos[activeServo].setPosition(position);
                    Thread.currentThread();
                    if (position % 10 == 0) {
                        System.out.println("Position: " + position);
                    }
                    Thread.sleep(maxSleepBetweenSteps / speed);
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            }
        }

        public void setSpeed(int speed) {
            if (speed < 1) {
                this.speed = 1;
            } else if (speed > 10) {
                this.speed = 10;
            } else {
                this.speed = speed;
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy