예제 #1
0
파일: nanocar.py 프로젝트: ncnynl/roscar
    def __init__(self, cfg):
        self.STEERING_NEUTRAL = cfg['servo_neutral_angle']
        self.MIN_STEERING_ANGLE = cfg[
            'servo_min_angle_limit']  # Steering left/right max angle.
        self.MAX_STEERING_ANGLE = cfg[
            'servo_max_angle_limit']  # Steering left/right max angle.
        self.STEERING_RATE = cfg[
            'steering_rate']  # Server steering angle is fomula angle. But car_client depends on car. Drift type steering, normal steering, etc. Therefore, use this rate for ajust good angle.
        self.MOTOR_NEUTRAL_SPEED = cfg['motor_neutral_speed']
        self.MOTOR_FORWARD_SPEED_RATE = float(
            cfg['motor_max_speed_limit']
        ) / float(
            100
        )  # Server max speed is 100. But car_client depends on config parameter.
        self.MOTOR_BACK_SPEED_RATE = float(
            cfg['motor_min_speed_limit']
        ) / float(
            -100
        )  # Server min speed is -100. But car_client depends on config parameter.

        self.steering = Servo(cfg)
        self.motor = Motor(cfg)
        self.steering.set_angle(self.STEERING_NEUTRAL, delay=0)
        self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)

        self.speed = self.MOTOR_NEUTRAL_SPEED
        self.back_in = False
        self.back_start_time = None
        return
예제 #2
0
def quit():
    if _port_motor:
        _port_motor.halt()
    if _stbd_motor:
        _stbd_motor.halt()
    Motor.cancel()
    sys.stderr = DevNull()
    print('exit.')
    sys.exit(0)
예제 #3
0
 def __init__(self, config, ticker, tb, level):
     super().__init__()
     self._log = Logger('motors', level)
     self._log.info('initialising motors...')
     if config is None:
         raise Exception('no config argument provided.')
     if ticker is None:
         raise Exception('no ticker argument provided.')
     self._ticker = ticker
     if tb is None:
         tb = self._configure_thunderborg_motors(level)
         if tb is None:
             raise Exception('unable to configure thunderborg.')
     self._tb = tb
     self._set_max_power_ratio()
     # config pigpio's pi and name its callback thread (ex-API)
     try:
         self._pi = pigpio.pi()
         if self._pi is None:
             raise Exception('unable to instantiate pigpio.pi().')
         elif self._pi._notify is None:
             raise Exception('can\'t connect to pigpio daemon; did you start it?')
         self._pi._notify.name = 'pi.callback'
         self._log.info('pigpio version {}'.format(self._pi.get_pigpio_version()))
         from lib.motor import Motor
         self._log.info('imported Motor.')
     except Exception as e:
         self._log.error('error importing and/or configuring Motor: {}'.format(e))
         traceback.print_exc(file=sys.stdout)
         sys.exit(1)
     self._port_motor = Motor(config, self._ticker, self._tb, self._pi, Orientation.PORT, level)
     self._port_motor.set_max_power_ratio(self._max_power_ratio)
     self._stbd_motor = Motor(config, self._ticker, self._tb, self._pi, Orientation.STBD, level)
     self._stbd_motor.set_max_power_ratio(self._max_power_ratio)
     self._closed  = False
     self._enabled = False # used to be enabled by default
     # a dictionary of motor # to last set value
     self._msgIndex = 0
     self._last_set_power = { 0:0, 1:0 }
     self._log.info('motors ready.')
예제 #4
0
파일: nanocar.py 프로젝트: ncnynl/roscar
class RosCar():
    def __init__(self, cfg):
        self.STEERING_NEUTRAL = cfg['servo_neutral_angle']
        self.MIN_STEERING_ANGLE = cfg[
            'servo_min_angle_limit']  # Steering left/right max angle.
        self.MAX_STEERING_ANGLE = cfg[
            'servo_max_angle_limit']  # Steering left/right max angle.
        self.STEERING_RATE = cfg[
            'steering_rate']  # Server steering angle is fomula angle. But car_client depends on car. Drift type steering, normal steering, etc. Therefore, use this rate for ajust good angle.
        self.MOTOR_NEUTRAL_SPEED = cfg['motor_neutral_speed']
        self.MOTOR_FORWARD_SPEED_RATE = float(
            cfg['motor_max_speed_limit']
        ) / float(
            100
        )  # Server max speed is 100. But car_client depends on config parameter.
        self.MOTOR_BACK_SPEED_RATE = float(
            cfg['motor_min_speed_limit']
        ) / float(
            -100
        )  # Server min speed is -100. But car_client depends on config parameter.

        self.steering = Servo(cfg)
        self.motor = Motor(cfg)
        self.steering.set_angle(self.STEERING_NEUTRAL, delay=0)
        self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)

        self.speed = self.MOTOR_NEUTRAL_SPEED
        self.back_in = False
        self.back_start_time = None
        return

    def __del__(self):
        self.steering.set_angle(self.STEERING_NEUTRAL, delay=0)
        self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)
        return

    def listener(self):
        """
        READ ROS TOPICS AND RUN FUNCTION BY HZ.

        rosnode list
        rosnode info /twist_filter
        rostopic echo /cmd_vel
        """
        rospy.init_node('ROSCarNano', anonymous=True)
        rospy.Subscriber('/cmd_vel', Twist, self.cmd_vel)

        # spin() simply keeps python from exiting until this node is stopped
        rospy.spin()
        return

    def cmd_vel(self, values):
        """
        ステアリング・速度のターゲット値の処理

        ステアリング値のomegaはターゲット角速度である。現在の速度を加味してomegaを算出しなければならない

        self.target_speed: target speed (m/s)
        """
        """
        Autoware 1.9.1にバック機能は無い。
        そのため速度は負の値は正の値として扱う。
        """
        print("/cmd_vel: {}".format(values))
        speed = abs(values.linear.x)
        target_speed = map(speed, 0.0, 0.22, 0.0, 30.0)
        """
        Autowareの角速度は右カーブがマイナス、左カーブがプラス。
        omega: rad/s and 10 Hz
        1 processing = 1 Hz = 0.1 * omega
        left/right = -1 * omega
        """
        omega = values.angular.z
        """
        omegaはtarget_speedが時速2kmの時、ベストマッチ。
        速度が上がった時、それに応じてomegaを減算させる。
        """
        print("omega: {} speed: {}".format(omega, speed))
        self.set_speed(target_speed)
        self.set_angle_rad(omega)

        return

    def omega_to_angle(self, omega):
        """
        角速度ωをサーボ可動域に変換する。
        omegaは右カーブがマイナス、左カーブがプラス。
        サーボは右カーブが90-180度、左カーブが0-90度となるため、
        omegaの正負を逆にしてdegreeに変換してから90度加える。
        ω(rad/s)
        θ= ω*180/pi (deg/s)
        rad = θ*pi/180
        """
        omega = -1.0 * omega
        theta = float(omega) * float(180) / math.pi
        angle = 90.0 - (180.0 - theta) / 2.0
        return angle

    def set_angle_rad(self, omega):
        """
        omega: rad/s
        """
        steering_angle = self.omega_to_angle(omega)
        #print("omega to angle: {} -> {}".format(omega, steering_angle))
        steering_angle = int(float(steering_angle) * float(self.STEERING_RATE))
        steering_angle = self.STEERING_NEUTRAL + steering_angle
        """
        Adjust within operable angle
        """
        if steering_angle > self.MAX_STEERING_ANGLE:
            steering_angle = self.MAX_STEERING_ANGLE
        if steering_angle < self.MIN_STEERING_ANGLE:
            steering_angle = self.MIN_STEERING_ANGLE

        print("steering: {}".format(steering_angle))
        self.steering.set_angle(steering_angle)

    def set_speed(self, speed):
        """
        speed: Analog int value for PCA9685
        """
        motor_speed = speed
        if motor_speed > 0:
            motor_speed = int(
                float(motor_speed) * float(self.MOTOR_FORWARD_SPEED_RATE))
        elif motor_speed < 0:
            motor_speed = int(
                float(motor_speed) * float(self.MOTOR_BACK_SPEED_RATE))
        self.motor.set_speed(motor_speed)

    def brake(self, value):
        if value.data:
            self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)
예제 #5
0
def signal_handler(signal, frame):
    print('Ctrl-C caught: exiting...')
    Motor.cancel()
    sys.stderr = DevNull()
    print('exit.')
    sys.exit(0)
예제 #6
0
class Motors():
    '''
    A dual motor controller with encoders.
    '''
    def __init__(self, config, ticker, tb, level):
        super().__init__()
        self._log = Logger('motors', level)
        self._log.info('initialising motors...')
        if config is None:
            raise Exception('no config argument provided.')
        if ticker is None:
            raise Exception('no ticker argument provided.')
        self._ticker = ticker
        if tb is None:
            tb = self._configure_thunderborg_motors(level)
            if tb is None:
                raise Exception('unable to configure thunderborg.')
        self._tb = tb
        self._set_max_power_ratio()
        # config pigpio's pi and name its callback thread (ex-API)
        try:
            self._pi = pigpio.pi()
            if self._pi is None:
                raise Exception('unable to instantiate pigpio.pi().')
            elif self._pi._notify is None:
                raise Exception('can\'t connect to pigpio daemon; did you start it?')
            self._pi._notify.name = 'pi.callback'
            self._log.info('pigpio version {}'.format(self._pi.get_pigpio_version()))
            from lib.motor import Motor
            self._log.info('imported Motor.')
        except Exception as e:
            self._log.error('error importing and/or configuring Motor: {}'.format(e))
            traceback.print_exc(file=sys.stdout)
            sys.exit(1)
        self._port_motor = Motor(config, self._ticker, self._tb, self._pi, Orientation.PORT, level)
        self._port_motor.set_max_power_ratio(self._max_power_ratio)
        self._stbd_motor = Motor(config, self._ticker, self._tb, self._pi, Orientation.STBD, level)
        self._stbd_motor.set_max_power_ratio(self._max_power_ratio)
        self._closed  = False
        self._enabled = False # used to be enabled by default
        # a dictionary of motor # to last set value
        self._msgIndex = 0
        self._last_set_power = { 0:0, 1:0 }
        self._log.info('motors ready.')

    # ..........................................................................
    def name(self):
        return 'Motors'

    # ..........................................................................
    def _configure_thunderborg_motors(self, level):
        '''
        Import the ThunderBorg library, then configure the Motors.
        '''
        self._log.info('configure thunderborg & motors...')
        global pi
        try:
            self._log.info('importing thunderborg...')
            import lib.ThunderBorg3 as ThunderBorg
            self._log.info('successfully imported thunderborg.')
            TB = ThunderBorg.ThunderBorg(level)  # create a new ThunderBorg object
            TB.Init()                       # set the board up (checks the board is connected)
            self._log.info('successfully instantiated thunderborg.')

            if not TB.foundChip:
                boards = ThunderBorg.ScanForThunderBorg()
                if len(boards) == 0:
                    self._log.error('no thunderborg found, check you are attached.')
                else:
                    self._log.error('no ThunderBorg at address {:02x}, but we did find boards:'.format(TB.i2cAddress))
                    for board in boards:
                        self._log.info('board {:02x} {:d}'.format(board, board))
                    self._log.error('if you need to change the I²C address change the setup line so it is correct, e.g. TB.i2cAddress = {:0x}'.format(boards[0]))
                sys.exit(1)
            TB.SetLedShowBattery(True)
            return TB

        except Exception as e:
            self._log.error('unable to import thunderborg: {}'.format(e))
            traceback.print_exc(file=sys.stdout)
            sys.exit(1)

    # ..........................................................................
    def set_led_show_battery(self, enable):
        self._tb.SetLedShowBattery(enable)

    # ..........................................................................
    def set_led_color(self, color):
        self._tb.SetLed1(color.red/255.0, color.green/255.0, color.blue/255.0)

    # ..........................................................................
    def _set_max_power_ratio(self):
        pass
        # initialise ThunderBorg ...........................
        self._log.info('getting battery reading...')
        # get battery voltage to determine max motor power
        # could be: Makita 12V or 18V power tool battery, or 12-20V line supply
        voltage_in = self._tb.GetBatteryReading()
        if voltage_in is None:
            raise OSError('cannot continue: cannot read battery voltage.')
        self._log.info('voltage in:  {:>5.2f}V'.format(voltage_in))
#       voltage_in = 20.5
        # maximum motor voltage
        voltage_out = 9.0
        self._log.info('voltage out: {:>5.2f}V'.format(voltage_out))
        if voltage_in < voltage_out:
            raise OSError('cannot continue: battery voltage too low ({:>5.2f}V).'.format(voltage_in))
        # Setup the power limits
        if voltage_out > voltage_in:
            self._max_power_ratio = 1.0
        else:
            self._max_power_ratio = voltage_out / float(voltage_in)
        # convert float to ratio format
        self._log.info('battery level: {:>5.2f}V; motor voltage: {:>5.2f}V;'.format( voltage_in, voltage_out) + Fore.CYAN + Style.BRIGHT \
                + ' maximum power ratio: {}'.format(str(Fraction(self._max_power_ratio).limit_denominator(max_denominator=20)).replace('/',':')))

    # ..........................................................................
    def get_motor(self, orientation):
        if orientation is Orientation.PORT:
            return self._port_motor
        else:
            return self._stbd_motor

    # ..........................................................................
    def is_in_motion(self):
        '''
        Returns true if either motor is moving.
        '''
        return self._port_motor.is_in_motion() or self._stbd_motor.is_in_motion()

    # ..........................................................................
    def get_steps(self):
        '''
        Returns the port and starboard motor step count.
        '''
        return [ self._port_motor.get_steps() , self._stbd_motor.get_steps() ]

    # ..........................................................................
    def get_current_power_level(self, orientation):
        '''
        Returns the last set power of the specified motor.
        '''
        if orientation is Orientation.PORT:
            return self._port_motor.get_current_power_level()
        else:
            return self._stbd_motor.get_current_power_level()

    # ..........................................................................
    def interrupt(self):
        '''
        Interrupt any motor loops by setting the _interrupt flag.
        '''
        self._port_motor.interrupt()
        self._stbd_motor.interrupt()

    # ..........................................................................
    def halt(self):
        '''
        Quickly (but not immediately) stops both motors.
        '''
        self._log.info('halting...')
        if self.is_stopped():
            _tp = Thread(name='halt-port', target=self.processStop, args=(Event.HALT, Orientation.PORT))
            _ts = Thread(name='hapt-stbd', target=self.processStop, args=(Event.HALT, Orientation.STBD))
            _tp.start()
            _ts.start()
        else:
            self._log.debug('already stopped.')
        self._log.info('halted.')
        return True

    # ..........................................................................
    def brake(self):
        '''
        Slowly coasts both motors to a stop.
        '''
        self._log.info('braking...')
        if self.is_stopped():
            _tp = Thread(name='brake-port', target=self.processStop, args=(Event.BRAKE, Orientation.PORT))
            _ts = Thread(name='brake-stbd', target=self.processStop, args=(Event.BRAKE, Orientation.STBD))
            _tp.start()
            _ts.start()
        else:
            self._log.warning('already stopped.')
        self._log.info('braked.')
        return True

    # ..........................................................................
    def stop(self):
        '''
        Stops both motors immediately, with no slewing.
        '''
        self._log.info('stopping...')
        if not self.is_stopped():
            self._port_motor.stop()
            self._stbd_motor.stop()
            self._log.info('stopped.')
        else:
            self._log.warning('already stopped.')
        return True

    # ..........................................................................
    def is_stopped(self):
        return self._port_motor.is_stopped() and self._stbd_motor.is_stopped()

    # ..........................................................................
    def processStop(self, event, orientation):
        '''
        Synchronised process control over various kinds of stopping.
        '''
        if orientation is Orientation.PORT:
            if event is Event.HALT:
                self._log.info('halting port motor...')
                self._port_motor.halt()
            elif event is Event.BRAKE:
                self._log.info('braking port motor...')
                self._port_motor.brake()
            else: # is stop
                self._log.info('stopping port motor...')
                self._port_motor.stop()
        else:
            if event is Event.HALT:
                self._log.info('halting starboard motor...')
                self._stbd_motor.halt()
            elif event is Event.BRAKE:
                self._log.info('braking starboard motor...')
                self._stbd_motor.brake()
            else: # is stop
                self._log.info('stopping starboard motor...')
                self._stbd_motor.stop()
        self.print_current_power_levels()

    # ..........................................................................
    def get_current_power_levels(self):
        '''
        Returns the last set power values.
        '''
        _port_power = self._port_motor.get_current_power_level()
        _stbd_power = self._stbd_motor.get_current_power_level()
        return [ _port_power, _stbd_power ]

    # ..........................................................................
    def print_current_power_levels(self):
        '''
        Prints the last set power values.
        '''
        self._msgIndex += 1
        self._log.info('{}:\tcurrent power:\t{:6.1f}\t{:6.1f}'.format(self._msgIndex, self._last_set_power[0], self._last_set_power[1]))

    # ..........................................................................
    def enable(self):
        '''
        Enables the motors, ticker and velocity calculator. This issues
        a warning if already enabled, but no harm is done in calling
        it repeatedly.
        '''
        if self._enabled:
            self._log.warning('already enabled.')
        if not self._port_motor.enabled:
            self._port_motor.enable()
        if not self._stbd_motor.enabled:
            self._stbd_motor.enable()
        self._ticker.enable()
        self._enabled = True
        self._log.info('enabled.')

    # ..........................................................................
    def disable(self):
        '''
        Disable the motors, halting first if in motion.
        '''
        if self._enabled:
            self._log.info('disabling...')
            self._enabled = False
            if self.is_in_motion(): # if we're moving then halt
                self._log.warning('event: motors are in motion (halting).')
                self.halt()
            self._port_motor.disable()
            self._stbd_motor.disable()
            self._log.info('disabling pigpio...')
            self._pi.stop()
            self._log.info('disabled.')
        else:
            self._log.debug('already disabled.')

    # ..........................................................................
    def close(self):
        '''
        Halts, turn everything off and stop doing anything.
        '''
        if not self._closed:
            if self._enabled:
                self.disable()
            self._log.info('closing...')
            self._port_motor.close()
            self._stbd_motor.close()
            self._closed = True
            self._log.info('closed.')
        else:
            self._log.debug('already closed.')

    # ..........................................................................
    @staticmethod
    def cancel():
        print('cancelling motors...')
        Motor.cancel()
예제 #7
0
def test_motors():
    global _port_motor, _stbd_motor, action_A, action_B

    # read YAML configuration
    _loader = ConfigLoader(Level.INFO)
    filename = 'config.yaml'
    _config = _loader.configure(filename)

    _log.info('creating message factory...')
    _message_factory = MessageFactory(Level.INFO)
    _log.info('creating message bus...')
    _message_bus = MessageBus(Level.WARN)
    _log.info('creating clock...')
    _clock = Clock(_config, _message_bus, _message_factory, Level.WARN)

    _motor_configurer = MotorConfigurer(_config, _clock, Level.INFO)
    _motors = _motor_configurer.get_motors()
    _motors.enable()

    _i2c_scanner = I2CScanner(Level.WARN)
    if ENABLE_MOTH:
        if _i2c_scanner.has_address([0x18]):
            _rgbmatrix = RgbMatrix(Level.WARN)
            #           _rgbmatrix.set_display_type(DisplayType.SOLID)
            _moth = Moth(_config, None, Level.WARN)
        else:
            _log.warning('cannot enable moth: no IO Expander found.')
            _moth = None

    _pin_A = 16
    _button_16 = Button(_pin_A, callback_method_A, Level.INFO)
    _log.info(
        Style.BRIGHT +
        'press button A (connected to pin {:d}) to toggle or initiate action.'.
        format(_pin_A))

    _pin_B = 24
    _button_24 = Button(_pin_B, callback_method_B, Level.INFO)
    _log.info(Style.BRIGHT +
              'press button B connected to pin {:d}) to exit.'.format(_pin_B))

    _log.info('starting motors...')
    _port_motor = _motors.get_motor(Orientation.PORT)
    _stbd_motor = _motors.get_motor(Orientation.STBD)
    if ENABLE_PORT:
        _port_motor.enable()
    if ENABLE_STBD:
        _stbd_motor.enable()

    _rot_ctrl = RotaryControl(_config, 0, 50, 2, Level.WARN)  # min, max, step
    _rate = Rate(5)
    _step_limit = 2312
    _velocity_stbd = 0.0
    _velocity_port = 0.0
    _start_time = dt.now()
    _moth_port = 1.0
    _moth_stbd = 1.0
    _moth_offset = 0.6
    _moth_bias = [0.0, 0.0]
    _moth_fudge = 0.7

    try:

        action_A = True  # if not using buttons at all set to True
        action_B = True

        while INFINITE or action_B or (_port_motor.steps < _step_limit
                                       and _stbd_motor.steps < _step_limit):
            if action_A:
                action_A = False  # trigger once
                while action_B:
                    if USE_ROTARY_CONTROL:
                        _target_velocity = _rot_ctrl.read()
                    else:
                        _target_velocity = 30.0
        #           _power = _target_velocity / 100.0
                    _power = Motor.velocity_to_power(_target_velocity)
                    if ENABLE_MOTH and _moth:
                        _moth_bias = _moth.get_bias()
                        #                       _log.info(Fore.WHITE + Style.BRIGHT + 'port: {:5.2f}; stbd: {:5.2f}'.format(_moth_port, _moth_stbd))
                        #                       _rgbmatrix.show_hue(_moth_hue, Orientation.BOTH)
                        _orientation = _moth.get_orientation()
                        if _orientation is Orientation.PORT:
                            _moth_port = _moth_bias[0] * _moth_fudge
                            _moth_stbd = 1.0
                            _rgbmatrix.show_color(Color.BLACK,
                                                  Orientation.STBD)
                            _rgbmatrix.show_color(Color.RED, Orientation.PORT)
                        elif _orientation is Orientation.STBD:
                            _moth_port = 1.0
                            _moth_stbd = _moth_bias[1] * _moth_fudge
                            _rgbmatrix.show_color(Color.BLACK,
                                                  Orientation.PORT)
                            _rgbmatrix.show_color(Color.GREEN,
                                                  Orientation.STBD)
                        else:
                            _moth_port = 1.0
                            _moth_stbd = 1.0
                            _rgbmatrix.show_color(Color.BLACK,
                                                  Orientation.PORT)
                            _rgbmatrix.show_color(Color.BLACK,
                                                  Orientation.STBD)
                    if ENABLE_STBD:
                        _stbd_motor.set_motor_power(_stbd_rotate * _power *
                                                    _moth_stbd)
                        _velocity_stbd = _stbd_motor.velocity
                    if ENABLE_PORT:
                        _port_motor.set_motor_power(_port_rotate * _power *
                                                    _moth_port)
                        _velocity_port = _port_motor.velocity
                    _log.info(Fore.YELLOW + 'power: {:5.2f}; bias: '.format(_power) \
                            + Fore.RED + ' {:5.2f} '.format(_moth_bias[0]) + Fore.GREEN + '{:5.2f};'.format(_moth_bias[1]) \
                            + Fore.BLACK + ' target velocity: {:5.2f};'.format(_target_velocity) \
                            + Fore.CYAN + ' velocity: ' \
                            + Fore.RED   + ' {:5.2f} '.format(_velocity_port) + Fore.GREEN + ' {:5.2f}'.format(_velocity_stbd))

                    #           _log.info(Fore.RED   + 'power {:5.2f}/{:5.2f}; {:>4d} steps; \t'.format(_stbd_motor.get_current_power_level(), _power, _port_motor.steps) \
                    #                   + Fore.GREEN + 'power {:5.2f}/{:5.2f}; {:>4d} steps.'.format(_port_motor.get_current_power_level(), _power, _stbd_motor.steps))
                    _rate.wait()
                action_B = True  # reentry into B loop, waiting for A
            _log.info('waiting for A button press...')
            time.sleep(1.0)
            # end wait loop ....................................................

        if ENABLE_PORT:
            _log.info('port motor: {:d} steps.'.format(_port_motor.steps))
        if ENABLE_STBD:
            _log.info('stbd motor: {:d} steps.'.format(_stbd_motor.steps))

    except KeyboardInterrupt:
        _log.info('Ctrl-C caught; exiting...')
    except Exception as e:
        _log.error('error: {}'.format(e))
    finally:
        close_motors(_log)
    _elapsed_ms = round((dt.now() - _start_time).total_seconds() * 1000.0)
    _log.info(Fore.YELLOW + 'complete: elapsed: {:d}ms'.format(_elapsed_ms))
예제 #8
0
 def cancel():
     print('cancelling motors...')
     Motor.cancel()
예제 #9
0
def main():
    print("start")

    motor = None
    try:
        """
        LOAD SETUP VARIABLES
        """
        cfg = load_config()

        motor = Motor(cfg)
        """
        # NEUTRAL ANALOG RANGE: 370-393
        neutral = 370
        print(motor.analog_to_pulse(neutral))
        neutral = 393
        print(motor.analog_to_pulse(neutral))
        # FORWARD MAXIMUM ANALOG VALUE: 280
        analog = 280
        print(motor.analog_to_pulse(analog))
        # BACKWARD MAXIMUM ANALOG VALUE: 440
        analog = 440
        print(motor.analog_to_pulse(analog))
        """

        # FORWARD: 369(START) - 280(MAX SPEED)
        motor.set_speed(0)
        time.sleep(2)
        speed = 0
        """
        for i in range(100):
            speed += 1
            motor.set_speed(speed)
            print(motor.get_speed())
            time.sleep(0.1)
        for i in range(100):
            speed -= 1
            motor.set_speed(speed)
            print(motor.get_speed())
            time.sleep(0.1)
        """

        # Setting the "BACKWARD" value to the value will apply the brake. (It is probably the function of ESC.)

        # BACKWORD: 394(START) - 440(MAX SPEED)
        speed = -30  # 30% backword throttle
        delay = 5.0
        for i in range(2):
            speed = 30  # 30% throttle
            motor.set_speed(speed, delay)
            time.sleep(2.5)
            speed = 0
            motor.set_speed(speed, delay)
            time.sleep(2.5)
            motor.set_speed(0)
            time.sleep(2)

    except:
        import traceback
        traceback.print_exc()
    finally:
        if motor is not None:
            motor.set_speed(0)
            time.sleep(3)

    print("end")
예제 #10
0
def test_velocity_to_power_conversion():
    # velocity to power conversion test:
    for v in numpy.arange(0.0, 60.0, 2.0):
        p = Motor.velocity_to_power(v)
        _log.info('velocity: {:5.2f};'.format(v) + Fore.YELLOW +
                  ' power: {:5.2f};'.format(p))
예제 #11
0
    dist_prox_cone.append(dpc)

    return da,dpc
	
def pegar_coordenadas_com_delay():
    for i in range(0,5):
        da, dpc = ground.logica_localizacao()
        diff_ang.append(da)
        dist_prox_cone.append(dpc)
        time.sleep(0.01) # wait for the coordinates to update
    return da,dpc    

diff_ang = []; dist_prox_cone = []

ground = gps()
motor = Motor(23,24,18)
motor.move_forward()
servo = Curves(12)
servo.posicionar(0,100)
vel1 = motor.change_speed(15,80)
da,dpc = pegar_coordenadas_com_delay()

while (dpc[-1] > 3):
    vel1 = motor.change_speed(45,30)
    da,dpc = pegar_coordenadas()
    angulo = servo.posicionar(da[-1]*.25,50)
    #print("da = " + str(da))
    #if (da[-1] < -25):
    #    angulo1 = servo.posicionar(da[-1],50)
    #elif (((da[-1] > -40) & (da[-1] < -25))):
    #    angulo1 = servo.posicionar(da[-1],50)
예제 #12
0
class RosCar():
    def __init__(self, cfg):
        self.STEERING_NEUTRAL = cfg['servo_neutral_angle']
        self.MIN_STEERING_ANGLE = cfg[
            'servo_min_angle_limit']  # Steering left/right max angle.
        self.MAX_STEERING_ANGLE = cfg[
            'servo_max_angle_limit']  # Steering left/right max angle.
        self.STEERING_RATE = cfg[
            'steering_rate']  # Server steering angle is fomula angle. But car_client depends on car. Drift type steering, normal steering, etc. Therefore, use this rate for ajust good angle.
        self.MOTOR_NEUTRAL_SPEED = cfg['motor_neutral_speed']
        self.MOTOR_FORWARD_SPEED_RATE = float(
            cfg['motor_max_speed_limit']
        ) / float(
            100
        )  # Server max speed is 100. But car_client depends on config parameter.
        self.MOTOR_BACK_SPEED_RATE = float(
            cfg['motor_min_speed_limit']
        ) / float(
            -100
        )  # Server min speed is -100. But car_client depends on config parameter.

        self.steering = Servo(cfg)
        self.motor = Motor(cfg)
        self.steering.set_angle(self.STEERING_NEUTRAL, delay=0)
        self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)
        return

    def listener(self):
        """
        READ ROS TOPICS AND RUN FUNCTION BY HZ.
        angle_deg: -45 to 45
        speed_deg: -100 to 100
        brake_bool: True or False
        """
        rospy.init_node('RoboCarROS', anonymous=True)
        rospy.Subscriber('/steer/angle_deg', Int8, self.set_angle)
        rospy.Subscriber('/motor/speed_deg', Int8, self.set_speed)
        rospy.Subscriber('/motor/brake_bool', Bool, self.brake)

        # spin() simply keeps python from exiting until this node is stopped
        rospy.spin()
        return

    def set_angle(self, angle):
        """
        angle.data: -45 to 45 degree.
        """
        steering_angle = angle.data
        steering_angle = int(float(steering_angle) * float(self.STEERING_RATE))
        steering_angle = self.STEERING_NEUTRAL + steering_angle
        """
        Adjust within operable angle
        """
        if steering_angle > self.MAX_STEERING_ANGLE:
            steering_angle = self.MAX_STEERING_ANGLE
        if steering_angle < self.MIN_STEERING_ANGLE:
            steering_angle = self.MIN_STEERING_ANGLE

        self.steering.set_angle(steering_angle)

    def set_speed(self, speed):
        motor_speed = speed.data
        if motor_speed > 0:
            motor_speed = int(
                float(motor_speed) * float(self.MOTOR_FORWARD_SPEED_RATE))
        elif motor_speed < 0:
            motor_speed = int(
                float(motor_speed) * float(self.MOTOR_BACK_SPEED_RATE))
        self.motor.set_speed(motor_speed)

    def brake(self, value):
        if value.data:
            self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)
예제 #13
0
class RosCar():
    def __init__(self, cfg):
        self.STEERING_NEUTRAL = cfg['servo_neutral_angle']
        self.MIN_STEERING_ANGLE = cfg[
            'servo_min_angle_limit']  # Steering left/right max angle.
        self.MAX_STEERING_ANGLE = cfg[
            'servo_max_angle_limit']  # Steering left/right max angle.
        self.STEERING_RATE = cfg[
            'steering_rate']  # Server steering angle is fomula angle. But car_client depends on car. Drift type steering, normal steering, etc. Therefore, use this rate for ajust good angle.
        self.MOTOR_NEUTRAL_SPEED = cfg['motor_neutral_speed']
        self.MOTOR_FORWARD_SPEED_RATE = float(
            cfg['motor_max_speed_limit']
        ) / float(
            100
        )  # Server max speed is 100. But car_client depends on config parameter.
        self.MOTOR_BACK_SPEED_RATE = float(
            cfg['motor_min_speed_limit']
        ) / float(
            -100
        )  # Server min speed is -100. But car_client depends on config parameter.

        self.steering = Servo(cfg)
        self.motor = Motor(cfg)
        self.steering.set_angle(self.STEERING_NEUTRAL, delay=0)
        self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)

        self.speed = self.MOTOR_NEUTRAL_SPEED
        return

    def __del__(self):
        self.steering.set_angle(self.STEERING_NEUTRAL, delay=0)
        self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)
        return

    def listener(self):
        """
        ROS Topicの更新時に処理を行う設定
        rosnode list
        rostopic echo /cmd_vel
        rostopic echo /ackermann_cmd
        """
        rospy.init_node('ROSCarNano', anonymous=True)
        """
        アッカーマン運動力学
        """
        ackermann = AckermannPublisher()
        ackermann.add()
        rospy.Subscriber('/ackermann_cmd', AckermannDriveStamped,
                         self.ackermann_cmd)

        # spin() simply keeps python from exiting until this node is stopped
        rospy.spin()
        return

    def ackermann_cmd(self, values):
        """
        ステアリング・速度のターゲット値の処理
        ステアリング値のsteering_angleは角度(rad)なので、degreeに変換する
        speed: m/s
        target_speed: motor power %
          # map(指示を受けた速度(m/s), 指示速度の後方最高速度m/s, 指示速度の最高速度m/s, モーター後方最高出力%, モーター前方最高出力%)
          # ここでは前後モーター最高出力は100%として、デバイス設定時に車両設定の速度制限を適用する。
        """
        print("/ackermann_cmd: {}".format(values))
        #speed = abs(values.drive.speed) # no backwords
        speed = values.drive.speed
        target_speed = map(speed, -0.28, 0.28, -100.0, 100.0)
        """
        ステアリング角
        アッカーマン運動力学のステアリング角を利用する
        """
        angle_rad = values.drive.steering_angle
        self.set_speed(target_speed)
        self.set_angle_rad(angle_rad)

    def rad_to_angle(self, angle_rad):
        """
        angle_radをサーボ可動域に変換する。
        angle_radは右カーブがマイナス、左カーブがプラス。
        サーボは右カーブが90-180度、左カーブが0-90度となるため、
        angle_radの正負を逆にしてdegreeに変換してから90度加える。
        ω(rad/s)
        θ= angle_rad*180/pi (deg/s)
        rad = θ*pi/180
        """
        angle_rad = -1.0 * angle_rad
        theta = float(angle_rad) * float(180) / math.pi
        angle = 90.0 - (180.0 - theta) / 2.0
        return angle

    def set_angle_rad(self, angle_rad):
        """
        omega: rad/s
        """
        steering_angle = self.rad_to_angle(angle_rad)
        #print("omega to angle: {} -> {}".format(omega, steering_angle))
        steering_angle = int(float(steering_angle) * float(self.STEERING_RATE))
        steering_angle = self.STEERING_NEUTRAL + steering_angle
        """
        Adjust within operable angle
        """
        if steering_angle > self.MAX_STEERING_ANGLE:
            steering_angle = self.MAX_STEERING_ANGLE
        if steering_angle < self.MIN_STEERING_ANGLE:
            steering_angle = self.MIN_STEERING_ANGLE

        print("steering: {}".format(steering_angle))
        self.steering.set_angle(steering_angle)

    def set_speed(self, speed):
        """
        speed: Analog int value for PCA9685
        """
        motor_speed = speed
        if motor_speed > 0:
            motor_speed = int(
                float(motor_speed) * float(self.MOTOR_FORWARD_SPEED_RATE))
        elif motor_speed < 0:
            motor_speed = int(
                float(motor_speed) * float(self.MOTOR_BACK_SPEED_RATE))
        print("motor: {}".format(motor_speed))
        self.motor.set_speed(motor_speed)

    def brake(self, value):
        if value.data:
            self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)
예제 #14
0
def quit():
    Motor.cancel()
    sys.stderr = DevNull()
    print('exit.')
    sys.exit(0)
예제 #15
0
class RosCar():

    def __init__(self, cfg):
        self.STEERING_NEUTRAL     = cfg['servo_neutral_angle']
        self.MIN_STEERING_ANGLE   = cfg['servo_min_angle_limit'] # Steering left/right max angle.
        self.MAX_STEERING_ANGLE   = cfg['servo_max_angle_limit'] # Steering left/right max angle.
        self.STEERING_RATE        = cfg['steering_rate'] # Server steering angle is fomula angle. But car_client depends on car. Drift type steering, normal steering, etc. Therefore, use this rate for ajust good angle.
        self.MOTOR_NEUTRAL_SPEED  = cfg['motor_neutral_speed']
        self.MOTOR_FORWARD_SPEED_RATE = float(cfg['motor_max_speed_limit'])/float(100) # Server max speed is 100. But car_client depends on config parameter.
        self.MOTOR_BACK_SPEED_RATE    = float(cfg['motor_min_speed_limit'])/float(-100) # Server min speed is -100. But car_client depends on config parameter.

        self.steering = Servo(cfg)
        self.motor = Motor(cfg)
        self.steering.set_angle(self.STEERING_NEUTRAL, delay=0)
        self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)

        self.speed = self.MOTOR_NEUTRAL_SPEED
        self.back_in = False
        self.back_start_time = None
        self.target_speed = self.MOTOR_NEUTRAL_SPEED
        return

    def __del__(self):
        self.steering.set_angle(self.STEERING_NEUTRAL, delay=0)
        self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)
        return

    def listener(self):
        """
        READ ROS TOPICS AND RUN FUNCTION BY HZ.

        rosnode list
        rosnode info /twist_filter
        rostopic echo /twist_cmd
        """
        rospy.init_node('RoboCarROS', anonymous=True)
        rospy.Subscriber('/twist_cmd', TwistStamped, self.twist_cmd)
        # current_velocity
        rospy.Subscriber('/current_velocity', TwistStamped, self.current_velocity)

        # spin() simply keeps python from exiting until this node is stopped
        rospy.spin()
        return

    def current_velocity(self, values):
        """
        現在速度と目標速度を比較して、モーター出力を調整する。
        self.speed: モーター出力
        current_velocity: 現在速度
        self.target_speed: 目標速度
        """
        current_velocity = values.twist.linear.x
        print("speed now: {} target: {}".format(current_velocity, self.target_speed))
        if current_velocity < self.target_speed:
            self.speed += 1
        elif current_velocity > self.target_speed:
            self.speed -= 1
        if self.speed >= 100:
            self.speed = 100
        elif self.speed <= 0:
            self.speed = 0
        """
        現在速度が0.1(m/s)未満の時、急発進を抑えるためにモーター出力を制限する。
        """
        if self.speed > 25 and current_velocity < 0.1:
            self.speed = 25
        self.set_speed(self.speed)
        return

    def twist_cmd(self, values):
        """
        ステアリング・速度のターゲット値の処理

        ステアリング値はここで適用する
        速度は変数で保持し、current_velocityによる現在速度取得時に適用する
        ステアリング値のomegaはターゲット角速度である。現在の速度を加味してomegaを算出しなければならない

        self.target_speed: target speed (m/s)
        """
        #print(values)
        """
        Autoware 1.9.1にバック機能は無い。
        そのため速度は負の値は正の値として扱う。
        """
        speed = abs(values.twist.linear.x)
        self.target_speed = speed

        """
        Autowareの角速度は右カーブがマイナス、左カーブがプラス。
        omega: rad/s and 10 Hz
        1 processing = 1 Hz = 0.1 * omega
        left/right = -1 * omega
        """
        omega = values.twist.angular.z

        """
        omegaはtarget_speedが時速2kmの時、ベストマッチ。
        速度が上がった時、それに応じてomegaを減算させる。
        """
        print("before omega: {} speed: {}".format(omega, speed))
        if self.target_speed >= 0.56:
            """
            目標速度が時速2km(0.56m/s)以上の時、比率に応じてomegaを小さくする
            """
            ratio = map(self.target_speed, 2.0, 1000.0, 1.0, 1000.0)
            omega = omega*ratio

        print("after omega: {} speed: {}".format(omega, speed))
        self.set_angle_rad(omega)

        return

    def omega_to_angle(self, omega):
        """
        角速度ωをサーボ可動域に変換する。
        omegaは右カーブがマイナス、左カーブがプラス。
        サーボは右カーブが90-180度、左カーブが0-90度となるため、
        omegaの正負を逆にしてdegreeに変換してから90度加える。
        ω(rad/s)
        θ= ω*180/pi (deg/s)
        rad = θ*pi/180
        """
        omega = -1.0 * omega
        theta = float(omega)*float(180)/math.pi
        angle = 90.0 - (180.0 - theta)/2.0
        return angle

    def set_angle_rad(self, omega):
        """
        omega: rad/s
        """
        steering_angle = self.omega_to_angle(omega)
        #print("omega to angle: {} -> {}".format(omega, steering_angle))
        steering_angle = int(float(steering_angle) * float(self.STEERING_RATE))
        steering_angle = self.STEERING_NEUTRAL + steering_angle
        """
        Adjust within operable angle
        """
        if steering_angle > self.MAX_STEERING_ANGLE:
            steering_angle = self.MAX_STEERING_ANGLE
        if steering_angle < self.MIN_STEERING_ANGLE:
            steering_angle = self.MIN_STEERING_ANGLE

        print("steering: {}".format(steering_angle))
        self.steering.set_angle(steering_angle)

    def set_speed(self, speed):
        """
        speed: Analog int value for PCA9685
        """
        motor_speed = speed
        if motor_speed > 0:
            motor_speed = int(float(motor_speed) * float(self.MOTOR_FORWARD_SPEED_RATE))
        elif motor_speed < 0:
            motor_speed = int(float(motor_speed) * float(self.MOTOR_BACK_SPEED_RATE))
        self.motor.set_speed(motor_speed)

    def brake(self, value):
        if value.data:
            self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)