Robotpy Magicbot Framework Errors

Hello CD!

I have been investigating robotpy framework known as “MagicBot”, and I have a few questions.

Let me first state that I am not new to python, nor is my team. We have been using a command-based framework, however we like to experiment a little bit in the offseason.

First question is, can we only instantiate WPILIB objects (such as wpilib.Joystick), in the create objects method? I have been trying to instantiate WPI_TalonSRX objects in the createObjects method, and then access them in a separate component (not a state-machine), inside of the telop-periodic and teleopInit, and it does not seem to create the objects properly (I can display a piece of code if requested). I have been referencing both the examples and the documentation, but I am still unsure.

Next, if I want to run something continuously in a component, not a state-machine, do I just put it in execute and instantiate it robot.py?

Thanks!

To your first question - yes. Due to how MagicBot handles variable injection from the robot to the individual components - all of the instances of objects that you desire to pass on to your components should be instantiated in the createObjects() method of your robot. Feel free to post your code here and we’ll gladly take a look. Did you make sure to properly use the naming conventions for the variable injections? You can see the reference for variable injections here.

Secondly, also yes. The execute() method of any component is run periodically the same way teleopPeriodic() and the other periodic methods run. So the execute() method is the right place to put any periodic code for your component. After that you inject the component to your robot and the execute method of that component will be called perodically.

Hopefully that helps a bit, and feel free to share your code or ask anything else :slight_smile:

1 Like

Thanks for the help first of all. Here is my code; I could not find any errors with this. Unless they have to be WPILIB objects.

What follows is my robot.py

import magicbot

from components.drivebase.robotdrive import RobotDrive

from ctre import WPI_TalonSRX

class CleanRobot(magicbot.MagicRobot):
    robotdrive = RobotDrive

    def createObjects(self):

    self.robotdrive_motors = [
            WPI_TalonSRX(0),
            WPI_TalonSRX(1),
            WPI_TalonSRX(2),
            WPI_TalonSRX(3)
            ]

def teleopInit(self):
    self.robotdrive.prepareToDrive()
    ''' Starts at the beginning of teleop (initialize) '''

def teleopPeriodic(self):
    pass
    ''' Starts on each iteration of the control loop'''

What follows is a portion of my robotdrive.py (component):

import wpilib

from controller import logicalaxes
from controller.buildlayout import BuildLayout

from ctre import WPI_TalonSRX, ControlMode, NeutralMode, FeedbackDevice

class RobotDrive:

motors = [
          WPI_TalonSRX,
          WPI_TalonSRX,
          WPI_TalonSRX,
          WPI_TalonSRX
          ]

def __init__(self):
    self.enabled = True

def prepareToDrive(self):
    for motor in self.motors:
        motor.setNeutralMode(NeutralMode.Brake)
        motor.setSafetyEnabled(False)
        motor.configSelectedFeedbackSensor(FeedbackDevice.QuadEncoder, 0, 0)

    self.declareJoysticks()

def calculateTankSpeed(self, y, rotate, x=0):
    return [y + rotate, -y + rotate]

def move(self):
    speeds = self.calculateTankSpeed(
                                    y=logicalaxes.driveY.get(),
                                    rotate=logicalaxes.driveRotate.get()
                                    )
    for speed, motor in zip(speeds, self.activeMotors):
        motor.set(2, speed)

def execute(self):
    self.move()

Again, I omitted several parts such as joystick creation. I am getting my error in motor.set(2, 0.5) of robotdrive.py, and I have the controlmode at 2, percent output, and 50% selected, ignoring the calculated speed values. Do you see any notable issues? My code returns the following:

AttributeError: 'int' object has no attribute 'speed' 

I think that the Talon I’m calling this on might not be a Talon.
I’d appreciate any feedback. Thanks!

Ahh. I changed the motors variable in the component to a type alone and it seemed to fix it. If someone can explain why this is, or if this is simply an error masking, please let me know!
Thanks for your help @MisterShadow!

[WPI_TalonSRX, ...] is not a type. list is a type though.

Also please note that the old non-type-hint-style declaration is deprecated, and will not work in 2020. See the docs for more information.

Where did you declare self.activeMotors btw? I don’t see it in your class. Second of all, like @auscompgeek said, you need to type hint your injected variable. Instead, you declared a list of pointers to the ‘WPI_ TalonSRX’ class. You can simply type hint it as a list, or if you want to be more explicit, then there is a way to type-hint Lists with their argument type as you can see here. I personally never tried it with injected variables but feel free to try and report if it works.

We are in the process of droping support for Python 3.5, and since Python 3.6 we will only support the type-hint-style so if you need an example of how to inject your motors, I suggest either of these:

from typing import List
motors: List
motors: List[WPI_TalonSRX]  # if you want to be more explicit

Thanks! I figured it out, and yes you guys are correct. Thanks for the correction once again!

1 Like

Currently the “types” from the typing module won’t work with magicbot injection, as they aren’t actually types at runtime. We would appreciate a patch to add support for such type hints though.

Ok, so in the component I could just write
motors = list, right?
Basically, what I am asking is, do I need the typing module?

You will want to specify something like motors: list. As mentioned earlier, the old assignment style injection declaration is deprecated and being removed for 2020.

1 Like

Ok, will do. Thanks!

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.