If you prefer a video guide, the contents of this guide can be found in the video above.
Before you start, you should have our Raspberry Pi image installed on your Raspberry Pi, as shown in our setup guide, and a new game created. You can also read about the installation process from our documentation website.
Also make sure to watch our earlier guide on how to setup a remote SSH connection to your Raspberry Pi inside VSCode, or watch the video about it.
You can find the final code used in this guide from our Github repository.
Step 2: Update the SurroRTG SDKConnect to your Raspberry Pi by clicking the green "Open a Remote Window" -button and then click "Remote-SSH: Connect to Host..." as shown in the image below.
You should see your Pi's IP address like in the image below. Click it to connect to the Pi. If you don't see your Pi's IP address there, follow the instructions in our earlier guide on the remote SSH setup.
To get the latest SDK updates, first open the Explorer panel on the left side of VSCode and click on "Open folder" as shown in the image below. Select the folder named surrortg-sdk
, click on "Ok" and enter your Pi's password.
Then open a new terminal by selecting "Terminal" and "Newterminal" from the VSCode menus. Use the git pull
command in the terminal to update the SDK.
Most of the popular small hobby servos should work fine with our today's code, but if you are going to use some larger one or add much load to it, you’d probably want to add an external power supply also.
Let’s start by connecting the servo to the Raspberry Pi. To supply power, connect the red wire to a 5 volt pin and the brown one to a ground pin. You can use the pins shown in the picture below. Then connect the orange position control wire to the GPIO pin number 17 as shown in the image.
After this you can make sure that everything works by executing the servo.py
file inside the devices folder, by running python3 surrortg/devices/servo.py
Now you should see some logs, and the servo should move back and forth. If not, double check your wiring.
Step 4: Create a game fileNow let’s create a game around this setup: inside the games
folder, create another folder called servogame
, and create a game.py
file inside it.
Now copy the code below to the file you just created and save the file with Ctrl+S.
import logging
from surrortg import Game
from surrortg.inputs import Joystick
class ServoJoystick(Joystick):
async def handle_coordinates(self, x, y, seat=0):
logging.info(f"x: {x}")
class ServoGame(Game):
async def on_init(self):
self.io.register_inputs({"joystick_main": ServoJoystick()})
ServoGame().run()
We can use this code to see that the game itself works. In the code we first create a custom Joystick
class that just logs the x coordinate whenever it gets player input, by overriding the handle_coordinates
with some logging. Then to use this class in our game, we create a Game
class and register the custom Joystick when the Game initializes.
To change the file which is executed when the game is running in the background, open the controller-rpi.service
file from the scripts
folder, and change the value of Environment=GAME_MODULE=
to games.servogame.game
Press Ctrl+S to save this file. As a result the modified line of the file should look like the one shown below.
Environment=GAME_MODULE=games.servogame.game
Then in your VSCode's terminal run the command sudo scripts/setup-systemd.sh
to set the new game file we just created to be executed by the controller.
When doing development, it might be a good idea to split the terminal window so that you can see the logs and run commands at the same time. This can be done by selecting "Terminal" and then "Split terminal" from the menus in VSCode. To open the logs, use the command sudo journalctl -fu controller
, and to restart the game after code changes, use the sudo systemctl restart controller
command. You can see an example below with the two terminals side by side.
Now go to your game's dashboard on Surrogate.tv and start the camera preview by pressing the "Preview" button next to the controller's name. If you now press the WASD keys, you should see the inputs coming in.
Whenever you make changes and want to see the effects in your game code,
- First save the file with Ctrl+S
- Then use the
sudo systemctl restart controller
command to put those changes into use
Now let’s make the Joystick class to move the servo with the input. We first go through the changes one by one to see how it's done, and then show the resulting new game code.
First, we import the Servo class:
from surrortg.devices import Servo
Then, we create a servo object to the joystick class and set the servo's pin to 17, which is connected to the servo’s orange wire:
GPIO_PIN = 17 # servo control wire pin number
class ServoJoystick(Joystick):
def __init__(self):
self.servo = Servo(GPIO_PIN)
Finally, we add a command to set the servo’s rotation speed to match the input.
async def handle_coordinates(self, x, y, seat=0):
logging.info(f"x: {x}")
self.servo.rotation_speed = x
The resulting game code is shown below. You can now replace the game code you created earlier with this one, save the file with Ctrl+S, and restart the controller to put the new code to use. By going to the camera preview in your games dashboard, you can now test that the servo moves as expected as you press the A and D keys or Left / Right arrows.
import logging
from surrortg import Game
from surrortg.devices import Servo
from surrortg.inputs import Joystick
GPIO_PIN = 17 # servo control wire pin number
class ServoJoystick(Joystick):
def __init__(self):
self.servo = Servo(GPIO_PIN)
async def handle_coordinates(self, x, y, seat=0):
logging.info(f"x: {x}")
self.servo.rotation_speed = x
class ServoGame(Game):
async def on_init(self):
self.io.register_inputs({"joystick_main": ServoJoystick()})
ServoGame().run()
Step 6: Improve the servo game codeNow we know that the servo code works, so let's improve the game code a bit!
First, we make the servo to always reset to the middle position whenever a player disconnects and input reset is automatically called. We can do this by adding a reset
method to the ServoJoystick class:
async def reset(self, seat=0):
self.servo.position = 0
Then, we add a servo stop command to the ServoJoystick's shutdown
method, which is called when the game code is stopped or it is restarted with the sudo systemctl restart controller
command:
async def shutdown(self, seat):
self.servo.stop()
To finish the game code, let's add an optional speed adjustment value and some helpful logs to follow the game from the terminal window. You can see the resulting game code below. You can now once again replace the game code you created earlier with this one, save the file with Ctrl+S, and restart the controller to put the new code to use.
import logging
from surrortg import Game
from surrortg.devices import Servo
from surrortg.inputs import Joystick
GPIO_PIN = 17 # servo control wire pin number
SPEED_ADJUST = 1.0 # set this between 0.0 and 1.0
class ServoJoystick(Joystick):
def __init__(self):
logging.info("Creating Servo")
self.servo = Servo(GPIO_PIN)
async def handle_coordinates(self, x, y, seat=0):
x *= SPEED_ADJUST
logging.info(f"Setting Servo rotation speed to: {x:.2f}")
self.servo.rotation_speed = x
async def reset(self, seat=0):
logging.info("Resetting Servo to the middle")
self.servo.position = 0
async def shutdown(self, seat):
logging.info("Stopping Servo")
self.servo.stop()
class ServoGame(Game):
async def on_init(self):
logging.info("Creating and registering ServoJoystick Input")
self.io.register_inputs({"joystick_main": ServoJoystick()})
ServoGame().run()
Step 7: Finished!Now the basic game is ready, and it can be expanded to do whatever you’d want.
More servo commands can be found from the documentation page. You can find more complex game examples that use servos inside the games
folder of the SDK.
Comments