Windows11下配置KINOVA GEN3机械臂的Python环境并运行
一、开机前的准备
- 检查电源连接
确保机械臂的电源适配器已正确连接到机械臂的电源接口,并且另一端已连接到电源插座。将红色按钮按起来,而不是按下去,按下去是紧急停止。
- 检查安全事项
确保机械臂周围没有障碍物或人员,避免在开机过程中发生意外。
- 按下电源按钮
找到机械臂底座上的电源按钮,按下并保持3秒钟,直到电源指示灯亮起。
- 等待系统初始化
机械臂开机后,系统需要一段时间进行初始化。此时,电源指示灯会保持蓝色闪烁状态。
- 验证开机成功
当系统初始化完成后,电源指示灯将变为蓝色常亮,表示机械臂已成功开机并处于待机状态。
二、通过Kortex Web App验证
(1)连接网络
使用网线将计算机和机械臂连接,然后在计算机上配置网络
-
控制面板>网络和Internet>网络连接中选择以太网连接
-
配置 IP 地址:
- 滚动到“IPv4”部分。
- 将“IPv4 配置”切换为“手动”。
- 输入以下信息:
- IP 地址:192.168.1.11
- 子网掩码:255.255.255.0
- 默认网关:不填
(2)打开Kortex Web App
在浏览器中输入机械臂的IP地址(默认为192.168.1.10),然后按回车键。
(3)登录
在登录页面中输入默认的用户名和密码(均为admin),然后点击“CONNECT”按钮。
(4)检查状态
在Kortex Web App的“Monitoring”页面中,您可以查看机械臂的实时状态,包括各关节的角度、速度、扭矩等信息,以确认机械臂是否正常工作。
然后再Monitoring界面中找到机械臂的固件版本,在system information中的Base下找到Bootloader Version,我的是2.5.0-2
三、配置Python环境并运行示例
(1)下载Python的API工具包
根据以上查询到的固件版本,下载对应版本的API工具包,点击API的2.6.0
https://github.com/Kinovarobotics/Kinova-kortex2_Gen3_G3L
点击左侧2.5的文件夹,下在.whl文件
下载到本地,为单独创建一个conda环境后,安装到指定的conda环境中,
conda create -n arm38 python=3.8
conda activate arm38
pip install kortex_api-2.5.0.post6-py3-none-any.whl
(2)安装Mosquitto服务
进入mosquitto官网【Eclipse Mosquitto官网】,下载exe安装包,安装成功后,在安装路径下,运行exe安装后,配置环境变量"C:\Program Files\mosquitto",然后打开配置文件“C:\Program Files\mosquitto\mosquitto.conf”,修改监听地址,ctrl+F搜“ listener port-number ”在下面一行增加2行.
listener 1883 192.168.1.11 # 注意这里是以太网的IP,不是机械臂的IP“192.168.1.11”
allow_anonymous true # 允许匿名连接(测试阶段)
在aclfile.example文件中添加允许匿名用户操作的规则:
topic readwrite #
user anonymous # 若匿名用户需单独定义
最后在cmd中输入mosquitto,启动服务,或者以下方法。
- 按
Win + R
打开运行窗口,输入services.msc
,然后按回车。 - 在服务管理器中,查找与 MQTT 相关的服务(例如
Mosquitto Broker
或其他 MQTT 服务名称)。 - 检查服务的状态:
- 如果状态为“正在运行”,则 MQTT 服务已启动。
- 如果状态为“已停止”,则 MQTT 服务未启动,可以右键点击服务并选择“启动”。
(3)检查端口
-
打开命令提示符。
-
运行以下命令查看正在监听的端口:
netstat -ano | findstr :1883
TCP 192.168.1.11:1883 0.0.0.0:0 LISTENING 19144
- 如果输出中包含
192.168.1.1:1883
,则 MQTT 服务正在监听端口1883
。 - 如果没有输出,则 MQTT 服务未监听该端口。
(4)运行Demo程序
从官网的库下载示例程序:https://github.com/Kinovarobotics/Kinova-kortex2_Gen3_G3L/tree/master/api_python/examples
比如以下的程序将机械臂伸直的操作
#! /usr/bin/env python3
###
# KINOVA (R) KORTEX (TM)
#
# Copyright (c) 2018 Kinova inc. All rights reserved.
#
# This software may be modified and distributed
# under the terms of the BSD 3-Clause license.
#
# Refer to the LICENSE file for details.
#
###
import time
import sys
import os
import threading
from kortex_api.autogen.client_stubs.BaseClientRpc import BaseClient
from kortex_api.autogen.client_stubs.BaseCyclicClientRpc import BaseCyclicClient
from kortex_api.autogen.messages import Session_pb2, Base_pb2, BaseCyclic_pb2
# Maximum allowed waiting time during actions (in seconds)
TIMEOUT_DURATION = 20
# Create closure to set an event after an END or an ABORT
def check_for_sequence_end_or_abort(e):
"""Return a closure checking for END or ABORT notifications on a sequence
Arguments:
e -- event to signal when the action is completed
(will be set when an END or ABORT occurs)
"""
def check(notification, e = e):
event_id = notification.event_identifier
task_id = notification.task_index
if event_id == Base_pb2.SEQUENCE_TASK_COMPLETED:
print("Sequence task {} completed".format(task_id))
elif event_id == Base_pb2.SEQUENCE_ABORTED:
print("Sequence aborted with error {}:{}"\
.format(\
notification.abort_details,\
Base_pb2.SubErrorCodes.Name(notification.abort_details)))
e.set()
elif event_id == Base_pb2.SEQUENCE_COMPLETED:
print("Sequence completed.")
e.set()
return check
# Create closure to set an event after an END or an ABORT
def check_for_end_or_abort(e):
"""Return a closure checking for END or ABORT notifications
Arguments:
e -- event to signal when the action is completed
(will be set when an END or ABORT occurs)
"""
def check(notification, e = e):
print("EVENT : " + \
Base_pb2.ActionEvent.Name(notification.action_event))
if notification.action_event == Base_pb2.ACTION_END \
or notification.action_event == Base_pb2.ACTION_ABORT:
e.set()
return check
#
# Example related functions
#
def create_angular_action(actuator_count):
print("Creating angular action")
action = Base_pb2.Action()
action.name = "Example angular action"
action.application_data = ""
for joint_id in range(actuator_count):
joint_angle = action.reach_joint_angles.joint_angles.joint_angles.add()
joint_angle.value = 0.0
return action
def create_cartesian_action(base_cyclic):
print("Creating Cartesian action")
action = Base_pb2.Action()
action.name = "Example Cartesian action"
action.application_data = ""
feedback = base_cyclic.RefreshFeedback()
cartesian_pose = action.reach_pose.target_pose
cartesian_pose.x = feedback.base.tool_pose_x # (meters)
cartesian_pose.y = feedback.base.tool_pose_y - 0.1 # (meters)
cartesian_pose.z = feedback.base.tool_pose_z - 0.2 # (meters)
cartesian_pose.theta_x = feedback.base.tool_pose_theta_x # (degrees)
cartesian_pose.theta_y = feedback.base.tool_pose_theta_y # (degrees)
cartesian_pose.theta_z = feedback.base.tool_pose_theta_z # (degrees)
return action
#
#
# Example core functions
#
def example_move_to_home_position(base):
# Make sure the arm is in Single Level Servoing mode
base_servo_mode = Base_pb2.ServoingModeInformation()
base_servo_mode.servoing_mode = Base_pb2.SINGLE_LEVEL_SERVOING
base.SetServoingMode(base_servo_mode)
# Move arm to ready position
print("Moving the arm to a safe position")
action_type = Base_pb2.RequestedActionType()
action_type.action_type = Base_pb2.REACH_JOINT_ANGLES
action_list = base.ReadAllActions(action_type)
action_handle = None
for action in action_list.action_list:
if action.name == "Home":
action_handle = action.handle
if action_handle == None:
print("Can't reach safe position. Exiting")
sys.exit(0)
e = threading.Event()
notification_handle = base.OnNotificationActionTopic(
check_for_end_or_abort(e),
Base_pb2.NotificationOptions()
)
base.ExecuteActionFromReference(action_handle)
# Leave time to action to complete
finished = e.wait(TIMEOUT_DURATION)
base.Unsubscribe(notification_handle)
if not finished:
print("Timeout on action notification wait")
return finished
def example_create_sequence(base, base_cyclic):
print("Creating Action for Sequence")
actuator_count = base.GetActuatorCount().count
angular_action = create_angular_action(actuator_count)
cartesian_action = create_cartesian_action(base_cyclic)
print("Creating Sequence")
sequence = Base_pb2.Sequence()
sequence.name = "Example sequence"
print("Appending Actions to Sequence")
task_1 = sequence.tasks.add()
task_1.group_identifier = 0
task_1.action.CopyFrom(cartesian_action)
task_2 = sequence.tasks.add()
task_2.group_identifier = 1 # sequence elements with same group_id are played at the same time
task_2.action.CopyFrom(angular_action)
e = threading.Event()
notification_handle = base.OnNotificationSequenceInfoTopic(
check_for_sequence_end_or_abort(e),
Base_pb2.NotificationOptions()
)
print("Creating sequence on device and executing it")
handle_sequence = base.CreateSequence(sequence)
base.PlaySequence(handle_sequence)
print("Waiting for movement to finish ...")
finished = e.wait(TIMEOUT_DURATION)
base.Unsubscribe(notification_handle)
if not finished:
print("Timeout on action notification wait")
return finished
def main():
# Import the utilities helper module
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
import utilities
# Parse arguments
args = utilities.parseConnectionArguments()
# Create connection to the device and get the router
with utilities.DeviceConnection.createTcpConnection(args) as router:
# Create required services
base = BaseClient(router)
base_cyclic = BaseCyclicClient(router)
# Example core
success = True
success &= example_move_to_home_position(base)
success &= example_create_sequence(base, base_cyclic)
# You can also refer to the 110-Waypoints examples for an alternate way to execute
# a trajectory defined by a series of waypoints in joint space or in Cartesian space
return 0 if success else 1
if __name__ == "__main__":
exit(main())