C++ command in Simulator

Anyone encounter this. I’m monkeying around with command based c++ code. I’ve added a command to the dashboard so I can test in the simulator. The command shows up but the button to run it does not. I’m getting Unknown Command where the button should be

RobotContainer

  frc2::CommandPtr turnCommandPtr = neo550Subsystem.createTurnToPositionCommand(3.2);
  frc2::Command* turnCommand = turnCommandPtr.get();
  frc::SmartDashboard::PutData(turnCommand);
createTurnToPositionCommand
    frc2::CommandPtr resetControllerCommand = frc2::cmd::RunOnce(
        [this]
        {
            positionPIDController.Reset();
        }, {this});
    frc2::CommandPtr turnToPositionCommand = this->Run(
        [this, rotations]
        {
            NEO550SimSubsystem::turnToPosition(rotations);
        });
    frc2::CommandPtr command = std::move(resetControllerCommand).AndThen(std::move(turnToPositionCommand));
    
    return command;

If the CommandPtr goes out of scope, the command is destroyed (it’s a wrapper around std::unique_ptr), so the Command* passed to PutData is a dangling pointer. You will need to store the CommandPtr somewhere in the RobotContainer instance so it doesn’t go out of scope.

2 Likes

Thank you. Everything worked when I moved items to RobotContainer.h

For reference I had the previous setup in RobotContainer.cpp
I moved them to RobotContainer.h like so.

  NEO550SimSubsystem neo550Subsystem;
  frc2::CommandPtr turnCommandPtr{neo550Subsystem.createTurnToPositionCommand(3.2)};
  frc2::Command* turnCommand{turnCommandPtr.get()};

In the createTurnToPositionCommand referenced above I’ve got an error at the last line when I try to stitch these two together with Seqence

   frc2::CommandPtr resetControllerCommandPtr = frc2::cmd::RunOnce(
        [this]
        {
            positionPIDController.Reset();
        },
        {this});

    auto resetControllerCommand = resetControllerCommandPtr.get();

    frc2::CommandPtr turnToPositionCommandPtr = this->Run(
        [this, rotations]
        {
            NEO550SimSubsystem::turnToPosition(rotations);
        });

    auto turnToPositionCommand = turnToPositionCommandPtr.get();

    std::vector<frc2::CommandPtr> commandVector = {&resetControllerCommandPtr, &turnToPositionCommandPtr};

    auto command = frc2::cmd::Sequence(commandVector);

That’s not the correct way to build a vector of CommandPtr. The CommandPtr’s need to be moved into the vector (they’re not copyable). You also have to move the vector into the sequence. So the last two lines become:

std::vector<frc2::CommandPtr> commandVector{std::move(resetControllerCommandPtr), std::move(turnToPositionCommandPtr)};

auto command = frc2::cmd::Sequence(std::move(commandVector));
2 Likes

I simplified things to this

    frc2::CommandPtr resetControllerCommandPtr = frc2::cmd::RunOnce(
        [this]
        {
            positionPIDController.Reset();
        },
        {this});

    frc2::CommandPtr turnToPositionCommandPtr = this->Run(
        [this, rotations]
        {
            this->turnToPosition(rotations);
        });

    auto command = frc2::cmd::Sequence(std::move(resetControllerCommandPtr), std::move(turnToPositionCommandPtr));

    return resetControllerCommandPtr;

And upon running the simulator I got this error after the simulator immediately crashed

Error at frc2::CommandPtr::AssertValid [CommandPtr.cpp:28]: Illegal use of Command: Moved-from CommandPtr object used!
Error at frc::impl::RunRobot: Error: The robot program quit unexpectedly. This is usually due to a code error.

I got a attempting to reference a deleted function for CommandPtr when I tried your fix.

Okay this seemed to fix everything. Posting for reference

    frc2::CommandPtr resetControllerCommandPtr = frc2::cmd::RunOnce(
        [this]
        {
            positionPIDController.Reset();
        },
        {this});

    frc2::CommandPtr turnToPositionCommandPtr = this->Run(
        [this, rotations]
        {
            NEO550SimSubsystem::turnToPosition(rotations);
        });

    auto command = frc2::cmd::Sequence(std::move(resetControllerCommandPtr), std::move(turnToPositionCommandPtr));
    return command;

I’d like to add a FinallyDo decorator to this.

Here is what I have so far, but I’m not sure what the issue iss

    frc2::CommandPtr driveAtVelocityCommandPtr = this->Run(
        [this, rpm]
        {
            NEO550SimSubsystem::driveAtVelocity(rpm);
        });

    std::function<void()> end = [this]() {
            dcMotorSim.SetInputVoltage(0.0_V);
            simVoltage.Set(0.0);
    };

    auto driveAtVelocityCommand = driveAtVelocityCommandPtr.get();
    auto shutOff = driveAtVelocityCommand->FinallyDo(end);

Error message is : no instance of overloaded function “frc2::Command::FinallyDo” matches the argument list and object

So FinallyDo() is only available on rvalues (it’s a && overload). It’s also directly available on CommandPtr. So you need to do something like: auto shutOff = std::move(driveAtVelocityCommandPtr).FinallyDo(end);

Most of these functions are designed to be chained in a single statement, not stored in variables, which would avoid the need for all the std::move’s, e.g.

return Run(
        [this, rpm]
        {
            NEO550SimSubsystem::driveAtVelocity(rpm);
        })
  .FinallyDo([this] {
            dcMotorSim.SetInputVoltage(0.0_V);
            simVoltage.Set(0.0);
    });
1 Like

Thanks. I literally figured out the auto part 5 minutes ago that you mentioned, but I’ll use the chaining.

BTW. You’ve been a great help.

I’m mostly a Java person. I’m taking it upon myself to get better at C++ as a personal challenge.

You’ve probably seen this with what little CPP code that I’ve worked out in the betas.

Probably why I’m focusing more on the Java units class extensions.

Again though thanks a million

1 Like

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