IndustrialKit
is a framework that allows you to create applications for design and
management means of production. This material provides learning with its
main functionality.
Begins
It is enough for you to have any
actual
iPad. For greater convenience, it is also recommended to get a separate
keyboard.
Install the Swift
Playground app and open it. This is a development environment in which
you can create your applications – write a code, add resources and of
course – use Swift Packages.
Make a part
Let's start with something simple – with the part. We initialize it by
specifying the name and scene name from which the visual
model will be taken – the part node.
Next, using the ObjectSceneView control, we display the part node
on application view.
Part View
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import SceneKit | |
import IndustrialKit | |
struct ContentView: View | |
{ | |
var body: some View | |
{ | |
PartView() | |
} | |
} | |
let bushing = Part(name: "Bushing", scene_name: "Bushing.scn") | |
struct PartView: View | |
{ | |
var body: some View | |
{ | |
ObjectSceneView(node: bushing.node!) | |
.frame(width: 280, height: 280) | |
.background | |
{ | |
Rectangle() | |
.fill(.thinMaterial) | |
.shadow(radius: 4) | |
} | |
} | |
} |
Make a tool
Now move on to the tool. We set a scene with the tool model. Next, we
initialize the tool, where in addition to the name and scene, the
model controller and connector are also specified. The first
allows you to control the visual model of the tool. The second provides
connection to a real tool in production.
Tools perform technological operations associated with certain values of
the operation code supplied to the perform function of the tool. For the
gripper in question, values 0 and 1 are used – closing and opening,
respectively.
Let's create a field to set a custom opcode value with button to perform
it.
Tool View
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import SceneKit | |
import IndustrialKit | |
//... | |
let tool_scene = SCNScene(named: "Gripper.scn") ?? SCNScene() | |
struct ToolView: View | |
{ | |
@State var gripper = Tool(name: "Gripper", model_controller: Gripper_Controller(), connector: ToolConnector(), scene: tool_scene) | |
@State var code = 0 | |
var body: some View | |
{ | |
VStack | |
{ | |
ObjectSceneView(scene: tool_scene, on_init: { scene_view in prepare_scene() }) | |
.frame(width: 280, height: 280) | |
.background | |
{ | |
Rectangle() | |
.fill(.thinMaterial) | |
.shadow(radius: 4) | |
} | |
HStack | |
{ | |
TextField("0", value: $code, format: .number) | |
.textFieldStyle(.roundedBorder) | |
.frame(width: 64) | |
Button(action: { perform_tool(code) }) | |
{ | |
Label("Perform", systemImage: "play") | |
} | |
.buttonStyle(.borderedProminent) | |
} | |
.padding(.top, 4) | |
} | |
} | |
// Prepare scene with tool visual model | |
func prepare_scene() | |
{ | |
let viewed_node = tool_scene.rootNode.childNode(withName: "tool", recursively: true) | |
apply_bit_mask(node: viewed_node ?? SCNNode(), Workspace.tool_bit_mask) | |
gripper.workcell_connect(scene: tool_scene, name: "tool") | |
} | |
// Perform tool by inputed code | |
func perform_tool(_ code: Int) | |
{ | |
gripper.perform(code: code) | |
{ | |
print("Finished") | |
} | |
} | |
} |
We can also replace that with a view for controlling the gripper with two
buttons.
Tool View with opcode input
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import SceneKit | |
import IndustrialKit | |
//... | |
let tool_scene = SCNScene(named: "Gripper.scn") ?? SCNScene() | |
struct ToolView: View | |
{ | |
//... | |
var body: some View | |
{ | |
VStack | |
{ | |
ObjectSceneView(scene: tool_scene, on_init: { scene_view in prepare_scene() }) | |
.frame(width: 280, height: 280) | |
.background | |
{ | |
Rectangle() | |
.fill(.thinMaterial) | |
.shadow(radius: 4) | |
} | |
HStack | |
{ | |
Button(action: { perform_tool(0) }) | |
{ | |
Label("Close", systemImage: "arrowtriangle.right.and.line.vertical.and.arrowtriangle.left.fill") | |
} | |
.buttonStyle(.bordered) | |
Button(action: { perform_tool(1) }) | |
{ | |
Label("Open", systemImage: "arrowtriangle.left.and.line.vertical.and.arrowtriangle.right.fill") | |
} | |
.buttonStyle(.bordered) | |
} | |
.padding(.top, 4) | |
} | |
} | |
//... | |
} |
Now let's create a button to perform a sequence of operations.
The sequence can be specified as a nesting of single operations (perform_single
function), or as a program (perform_program function).
Tool View with program
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import SceneKit | |
import IndustrialKit | |
//... | |
struct ToolView: View | |
{ | |
//... | |
var body: some View | |
{ | |
VStack | |
{ | |
ObjectSceneView(scene: tool_scene, on_init: { scene_view in prepare_scene() }) | |
.frame(width: 280, height: 280) | |
.background | |
{ | |
Rectangle() | |
.fill(.thinMaterial) | |
.shadow(radius: 4) | |
} | |
Button(action: perform_program) | |
{ | |
Label("Perform", systemImage: "play") | |
} | |
.buttonStyle(.borderedProminent) | |
.padding(.top, 4) | |
} | |
} | |
// Prepare scene with tool visual model | |
func prepare_scene() | |
{ | |
let viewed_node = tool_scene.rootNode.childNode(withName: "tool", recursively: true) | |
apply_bit_mask(node: viewed_node ?? SCNNode(), Workspace.tool_bit_mask) | |
gripper.workcell_connect(scene: tool_scene, name: "tool") | |
} | |
// Perform tool by inputed code | |
func perform_tool(_ code: Int) | |
{ | |
gripper.perform(code: code) | |
{ | |
print("Finished") | |
} | |
} | |
// Order of single actions | |
func perform_single() | |
{ | |
gripper.perform(code: 0) | |
{ | |
gripper.perform(code: 1) | |
} | |
} | |
// Operation codes program | |
func perform_program() | |
{ | |
let open_close_program = OperationsProgram(name: "O/C") | |
open_close_program.add_code(OperationCode(0)) | |
open_close_program.add_code(OperationCode(1)) | |
gripper.add_program(open_close_program) | |
gripper.select_program(name: "O/C") | |
gripper.start_pause_performing() | |
} | |
} |
Make a robot
And now, we move on to the robot. It initializes with the name,
controller, connector and scene name parameters.
However, there are differences in the approach to displaying the robot on
the stage.
First, an empty scene robot_scene is created. Next, when initializing the
scene, you must first connect to the scene using the
workcell_connect function on view appear. The position of the
origin of the coordinate system of the manipulator's movement space sets
by origin_location and origin_rotation variable.
In order for the robot model to be updated in real time, the robot update
function (update_model) is specified in the
ObjectSceneView control when initializing the control to be called
on the scene rendering.
Robot View
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let robot_scene = SCNScene() | |
struct RobotView: View | |
{ | |
@State var arm = Robot(name: "Robot", model_controller: _6DOF_Controller(), connector: RobotConnector(), scene_name: "6DOF.scn") | |
var body: some View | |
{ | |
VStack(spacing: 0) | |
{ | |
ObjectSceneView(scene: robot_scene, on_init: { scene_view in prepare_scene() }) | |
.frame(width: 280, height: 280) | |
.background | |
{ | |
Rectangle() | |
.fill(.thinMaterial) | |
.shadow(radius: 4) | |
} | |
} | |
} | |
// Prepare scene with robot visual model | |
func prepare_scene() | |
{ | |
arm.perform_update() | |
arm.workcell_connect(scene: robot_scene, name: "unit", connect_camera: false) | |
arm.origin_location = [250, 0, 50] | |
} | |
} |
Next, using the PositionControl control, we ensure that the
position parameters of the manipulator (location &
rotation) are changed manually.
Robot View with control
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import SceneKit | |
import IndustrialKit | |
//... | |
struct RobotView: View | |
{ | |
//... | |
var body: some View | |
{ | |
VStack(spacing: 0) | |
{ | |
ObjectSceneView(scene: robot_scene, on_init: { scene_view in prepare_scene() }) | |
.frame(width: 280, height: 280) | |
.background | |
{ | |
Rectangle() | |
.fill(.thinMaterial) | |
.shadow(radius: 4) | |
} | |
PositionControl(location: $arm.pointer_location, rotation: $arm.pointer_rotation, scale: $arm.space_scale) | |
.frame(width: 320) | |
.disabled(arm.performed) | |
} | |
} | |
//... | |
} |
Similar to a tool for a robot, a sequence of operations – movements to
certain positions can be specified. Position parameters are specified in a
rectangular coordinate system local to the robot. Additionally, the angles
of rotation in the position and the speed of movement into it can be
specified.
Performing sequence can be specified either as nested single actions or as
a position program.
Robot View with program
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import SceneKit | |
import IndustrialKit | |
//... | |
struct RobotView: View | |
{ | |
//... | |
var body: some View | |
{ | |
VStack(spacing: 0) | |
{ | |
ObjectSceneView(scene: robot_scene, on_init: { scene_view in prepare_scene() }) | |
.frame(width: 280, height: 280) | |
.background | |
{ | |
Rectangle() | |
.fill(.thinMaterial) | |
.shadow(radius: 4) | |
} | |
Button(action: perform_program) | |
{ | |
Label("Perform", systemImage: "play") | |
} | |
.buttonStyle(.borderedProminent) | |
.padding() | |
} | |
} | |
//... | |
// Single point actions perform | |
func perform_single() | |
{ | |
arm.move_to(point: PositionPoint(x: 50, y: 0, z: 50)) | |
{ | |
arm.move_to(point: PositionPoint(x: 100, y: 0, z: 50, r: 0, p: 90, w: 0)) | |
{ | |
arm.move_to(point: PositionPoint(x: 100, y: 0, z: 50, r: 0, p: 90, w: 0, move_speed: 40)) | |
} | |
} | |
} | |
// Position program perform | |
func perform_program() | |
{ | |
arm.points_node?.isHidden = true | |
let program = PositionsProgram(name: "Square") | |
program.add_point(PositionPoint(x: 10, y: 10, z: 10)) | |
program.add_point(PositionPoint(x: 100, y: 10, z: 10)) | |
program.add_point(PositionPoint(x: 100, y: 100, z: 10)) | |
program.add_point(PositionPoint(x: 10, y: 100, z: 10)) | |
program.add_point(PositionPoint(x: 10, y: 10, z: 10)) | |
arm.add_program(program) | |
arm.select_program(name: "Square") | |
arm.start_pause_moving() | |
} | |
} |
Conclusion
You learned methods for creating and basic use of individual components of
a manufacturing system – robots, tools, and parts.
This material is quite sufficient for creating applications for monitoring
and modeling individual industrial devices, as well as combining them.
This is the basis for further work with the framework.
The next stage is complex application within Workspace and Ithi Macro
Assembler.