๐งช [Plant Simulation Study #05] – Controlling Plant Simulation with an Xbox Controller via Socket Communication
๐ฌ Overview
In this demo, I integrated Plant Simulation with an Xbox game controller using socket communication.
The goal is not just to passively observe simulations but to interactively control simulation objects in real time using an external device.
This makes the simulation experience more dynamic and hands-on for both experimentation and demonstration purposes.
- Purpose: Test real-time control using an external device
- Tech Stack: Python + Xbox Controller + Socket Communication + Plant Simulation
- Simulation Tools Used: Method, SocketClient object in Plant Simulation
๐ฅ Demo Video
๐ https://youtu.be/wE22Czmx6lM
๐ ๏ธ Simulation Architecture & Communication Flow
Input Device | Xbox controller (data received via Python script) |
Middle Layer | Python socket server processes directional inputs |
Simulation | Plant Simulation connects to Python server and receives movement commands |
Controlled Object | MU or 3D robot joints (position and speed controlled in real time) |
๐ง Key Implementation Details
- Python Layer
Use libraries like pygame or inputs to detect Xbox controller inputs.
The data is sent via TCP socket as strings to the simulation. - Plant Simulation Side
Use SocketClient to receive data and update the simulation dynamically.
Here's how message parsing and joint motion control is implemented:
// writes the value to the global variable ’MessageReceived’
if strLen(SocketMessage) = 0
MessageReceived := to_str(strAscii(SocketMessage)); // byte received
else
MessageReceived := to_str(SocketMessage); // string received
end
- Motion Execution (based on socket command)
Below is the structure for controlling 3D robot joints using the received command:
-- param attribute: string, oldValue, newValue: string
-- param attribute: string, oldValue: string
param newValue: string
switch newValue
case "UP,1"
if ํ์ฌ๋ก๋ด = void or ํ์ฌ_์ ์ด์ถ = ""
messagebox("๋ก๋ด๊ณผ ์ ์ด์ถ์ ๋ค์ ํ์ธํด์ฃผ์ธ์.")
return
end
switch ํ์ฌ_์ ์ด์ถ
case "J1"
ํ์ฌ๋ก๋ด.J1 := ํ์ฌ๋ก๋ด.J1 + ์ด๋๊ฐ
var J1_num := ํ์ฌ๋ก๋ด.J1
ํ์ฌ๋ก๋ด._3D.getobject("J1").moveTo(J1_num)
case "J2"
ํ์ฌ๋ก๋ด.J2 := ํ์ฌ๋ก๋ด.J2 + ์ด๋๊ฐ
var J2_num := ํ์ฌ๋ก๋ด.J2
ํ์ฌ๋ก๋ด._3D.getobject("J1").getobject("J2").moveTo(J2_num)
case "J3"
ํ์ฌ๋ก๋ด.J3 := ํ์ฌ๋ก๋ด.J3 + ์ด๋๊ฐ
var J3_num := ํ์ฌ๋ก๋ด.J3
ํ์ฌ๋ก๋ด._3D.getobject("J1").getobject("J2").getobject("J3").moveTo(J3_num)
case "J4"
ํ์ฌ๋ก๋ด.J4 := ํ์ฌ๋ก๋ด.J4 + ์ด๋๊ฐ
var J4_num := ํ์ฌ๋ก๋ด.J4
ํ์ฌ๋ก๋ด._3D.getobject("J1").getobject("J2").getobject("J3").getobject("J4").moveTo(J4_num)
case "J5"
ํ์ฌ๋ก๋ด.J5 := ํ์ฌ๋ก๋ด.J5 + ์ด๋๊ฐ
var J5_num := ํ์ฌ๋ก๋ด.J5
ํ์ฌ๋ก๋ด._3D.getobject("J1").getobject("J2").getobject("J3").getobject("J4").getobject("J5").moveTo(J5_num)
case "J6"
ํ์ฌ๋ก๋ด.J6 := ํ์ฌ๋ก๋ด.J6 + ์ด๋๊ฐ
var J6_num := ํ์ฌ๋ก๋ด.J6
ํ์ฌ๋ก๋ด._3D.getobject("J1").getobject("J2").getobject("J3").getobject("J4").getobject("J5").getobject("J6").moveTo(J6_num)
end
case "UP,-1"
if ํ์ฌ๋ก๋ด = void or ํ์ฌ_์ ์ด์ถ = ""
messagebox("๋ก๋ด๊ณผ ์ ์ด์ถ์ ๋ค์ ํ์ธํด์ฃผ์ธ์.")
return
end
switch ํ์ฌ_์ ์ด์ถ
case "J1"
ํ์ฌ๋ก๋ด.J1 := ํ์ฌ๋ก๋ด.J1 - ์ด๋๊ฐ
var J1_num1 := ํ์ฌ๋ก๋ด.J1
ํ์ฌ๋ก๋ด._3D.getobject("J1").moveTo(J1_num1)
case "J2"
ํ์ฌ๋ก๋ด.J2 := ํ์ฌ๋ก๋ด.J2 - ์ด๋๊ฐ
var J2_num1 := ํ์ฌ๋ก๋ด.J2
ํ์ฌ๋ก๋ด._3D.getobject("J1").getobject("J2").moveTo(J2_num1)
case "J3"
ํ์ฌ๋ก๋ด.J3 := ํ์ฌ๋ก๋ด.J3 - ์ด๋๊ฐ
var J3_num1 := ํ์ฌ๋ก๋ด.J3
ํ์ฌ๋ก๋ด._3D.getobject("J1").getobject("J2").getobject("J3").moveTo(J3_num1)
case "J4"
ํ์ฌ๋ก๋ด.J4 := ํ์ฌ๋ก๋ด.J4 - ์ด๋๊ฐ
var J4_num1 := ํ์ฌ๋ก๋ด.J4
ํ์ฌ๋ก๋ด._3D.getobject("J1").getobject("J2").getobject("J3").getobject("J4").moveTo(J4_num1)
case "J5"
ํ์ฌ๋ก๋ด.J5 := ํ์ฌ๋ก๋ด.J5 - ์ด๋๊ฐ
var J5_num1 := ํ์ฌ๋ก๋ด.J5
ํ์ฌ๋ก๋ด._3D.getobject("J1").getobject("J2").getobject("J3").getobject("J4").getobject("J5").moveTo(J5_num1)
case "J6"
ํ์ฌ๋ก๋ด.J6 := ํ์ฌ๋ก๋ด.J6 - ์ด๋๊ฐ
var J6_num1 := ํ์ฌ๋ก๋ด.J6
ํ์ฌ๋ก๋ด._3D.getobject("J1").getobject("J2").getobject("J3").getobject("J4").getobject("J5").getobject("J6").moveTo(J6_num1)
end
case "A,1"
if ํ์ฌ๋ก๋ด.empty = false
else
pick.mu.move(ํ์ฌ๋ก๋ด)
end
case "B,1"
if ํ์ฌ๋ก๋ด.empty = true
else
ํ์ฌ๋ก๋ด.mu.move(place)
end
case "X,1"
switch ์ด๋๊ฐ
case 1
์ด๋๊ฐ := 2
case 2
์ด๋๊ฐ := 3
case 3
์ด๋๊ฐ := 5
case 5
์ด๋๊ฐ := 10
case 10
์ด๋๊ฐ := 30
case 30
์ด๋๊ฐ := 90
case 90
์ด๋๊ฐ := 1
end
case "Y,1"
switch ํ์ฌ_์ ์ด์ถ
case ""
ํ์ฌ_์ ์ด์ถ := "J1"
case "J1"
ํ์ฌ_์ ์ด์ถ := "J2"
case "J2"
ํ์ฌ_์ ์ด์ถ := "J3"
case "J3"
ํ์ฌ_์ ์ด์ถ := "J4"
case "J4"
ํ์ฌ_์ ์ด์ถ := "J5"
case "J5"
ํ์ฌ_์ ์ด์ถ := "J6"
case "J6"
ํ์ฌ_์ ์ด์ถ := "J1"
end
end
๐ Experiment Results & Applications
This goes far beyond a simple demo. Possible applications include:
- Real-time simulation tests integrated with external machines or logistics devices
- Virtual commissioning of robotic systems
- Creating interactive simulation models for training or demos
- Testing digital twins with physical control input
๐ง Final Thoughts
While the Xbox controller was used in this example, the architecture supports any external device — including sensors, mobile apps, keyboards, or industrial controllers.
This approach shows how Plant Simulation can be used not just as an analysis tool but as a real-time experimentation and feedback platform.
More integrations are coming soon — stay tuned!