Robotpy Sim

I was playing around with the simulator today (not the websim), and using the default robot.py project (the one in the docs), it seemed like no matter what I put the speed value to in the arcade drive, the robot went backwards off the SIM screen. The encoders were negative as well.

Any idea what I am doing wrong?

Thanks.
~Mr. R.^2

P.S. Thank you all for adding in the elements for this year’s game.

There are a lot of examples… can you post a link to the particular one you’re thinking of?

It is this one. I am working in auto as I have not yet installed pygame on the team’s programming machine yet.

!/usr/bin/env python3
"""
    This is a good foundation to build your robot code on
"""

import wpilib
import wpilib.drive


class MyRobot(wpilib.TimedRobot):

    def robotInit(self):
        """
        This function is called upon program startup and
        should be used for any initialization code.
        """
        self.left_motor = wpilib.Spark(0)
        self.right_motor = wpilib.Spark(1)
        self.drive = wpilib.drive.DifferentialDrive(self.left_motor, self.right_motor)
        self.stick = wpilib.Joystick(1)
        self.timer = wpilib.Timer()

    def autonomousInit(self):
        """This function is run once each time the robot enters autonomous mode."""
        self.timer.reset()
        self.timer.start()

    def autonomousPeriodic(self):
        """This function is called periodically during autonomous."""

        # Drive for two seconds
        if self.timer.get() < 2.0:
            self.drive.arcadeDrive(-0.5, 0)  # Drive forwards at half speed
        else:
            self.drive.arcadeDrive(0, 0)  # Stop robot

    def teleopPeriodic(self):
        """This function is called periodically during operator control."""
        self.drive.arcadeDrive(self.stick.getY(), self.stick.getX())


if __name__ == "__main__":
    wpilib.run(MyRobot)

This seems to match the getting-started example, which doesn’t have a physics implementation associated with it. That means your physics.py is doing something wrong. Can you post your physics.py also – or maybe you might consider starting with one of the existing physics examples?

1 Like

Thank you.

Here is the physics.py


'''
Created on Sep 16, 2018

@author: Leko
'''
#
# See the documentation for more details on how this works
#
# The idea here is you provide a simulation object that overrides specific
# pieces of WPILib, and modifies motors/sensors accordingly depending on the
# state of the simulation. An example of this would be measuring a motor
# moving for a set period of time, and then changing a limit switch to turn
# on after that period of time. This can help you do more complex simulations
# of your robot code without too much extra effort.
#


import math

from pyfrc.physics import motor_cfgs, tankmodel
from pyfrc.physics.units import units


class PhysicsEngine(object):
    '''
        Simulates a motor moving something that strikes two limit switches,
        one on each end of the track. Obviously, this is not particularly
        realistic, but it's good enough to illustrate the point
    '''
    
    def __init__(self, physics_controller):
        '''
            :param physics_controller: `pyfrc.physics.core.PhysicsInterface` object
                                       to communicate simulation effects to
        '''
        
        self.physics_controller = physics_controller
        self.position = 0
        
        # Change these parameters to fit your robot!
        bumper_width = 3.25*units.inch
        
        self.drivetrain = tankmodel.TankModel.theory(
            motor_cfgs.MOTOR_CFG_CIM,           # motor configuration
            110*units.lbs,                      # robot mass
            10.71,                              # drivetrain gear ratio
            2,                                  # motors per side
            22*units.inch,                      # robot wheelbase
            23*units.inch + bumper_width*2,     # robot width
            32*units.inch + bumper_width*2,     # robot length
            6*units.inch                        # wheel diameter
        )
        
        # Precompute the encoder constant
        # -> encoder counts per revolution / wheel circumference
        self.kEncoder = 360 / (0.5 * math.pi)
        
        self.l_distance = 0
        self.r_distance = 0
            
    def update_sim(self, hal_data, now, tm_diff):
        '''
            Called when the simulation parameters for the program need to be
            updated.
            
            :param now: The current time as a float
            :param tm_diff: The amount of time that has passed since the last
                            time that this function was called
        '''
        
        # Simulate the drivetrain
        l_motor = hal_data['pwm'][1]['value']
        r_motor = hal_data['pwm'][2]['value']
        
        x, y, angle = self.drivetrain.get_distance(l_motor, r_motor, tm_diff)
        self.physics_controller.distance_drive(x, y, angle)
        
        # Update encoders
        self.l_distance += self.drivetrain.l_velocity * tm_diff
        self.r_distance += self.drivetrain.r_velocity * tm_diff
        
        hal_data['encoder'][0]['count'] = int(self.l_distance * self.kEncoder)
        hal_data['encoder'][1]['count'] = int(self.r_distance * self.kEncoder)

The motor ports in the robot code and the pwm ports in simulation have to match.

Doh!
Thank you.
Yep, that worked.

I’m not sure if this is the best place to post this, but has there been any work done, or any desire, to have a more powerful physics engine integrated into the robotpy simulator? I was thinking of working on this integration (box2D seems to be the one coming up the most often), but I don’t want to work on something that would not have much value for the robotpy community even right out of the gate.

Hey @warren.parsons, sounds like the sort of thing that would be appropriate in a new thread. :slight_smile:

However, the idea of enhanced physics has definitely come up in the past, and we’ve done some work towards improving them over the years. I think the primary problem is just someone needs to do the work of (a) identifying a suitable engine and (b) actually doing the work.

@AmoryG has done some work with robotpy-websim, and has integrated Matter.js (a 2D rigid body physics engine) with it. Eventually I’d like for the websim to be our default so that it would be easier to build C++/Java backends for it, but I haven’t really taken the time to play with that yet. I’d encourage you to take a look and see if that meets your needs.

I am sorry for resurrecting an old post, but it seemed most relevant.

I can’t seem to find much documentation for the hal_data structure in the simulator. Specifically how would you access motor/controller values for a CAN motor; would you just swap ‘can’ for ‘pwm’ in the hal_data data structure access?

I would like to read more about this part of the simulator. Could someone point me to the best document describing it?

Thanks

Also really belongs in it’s own thread. :slight_smile:

It’s not really documented, the best place is the source code: https://github.com/robotpy/robotpy-wpilib/blob/master/hal-sim/hal_impl/data.py

For CAN stuff, the CTRE source code is the best place. Unfortunately, it’s autogenerated, so you need to dig into the installed package to find it. Looking at the SimUI is vaguely helpful however: https://github.com/robotpy/robotpy-ctre/blob/master/ctre/_impl/sim_ui.py