SCARA机器人随机点位生成可视化

1.利用lua脚本随机生成XYZC的关节角度,再把关节逆解为笛卡尔坐标,保存为CSV数据。

2.利用python脚本读取lua生成的CSV表格进行绘图,到达仿真机器人运行的随机点在XY平面的分布。

3.设置生成100万和10万和1万个随机点的效果图:500万时脚本几经奔溃,数据量太大,到达黑洞视界边缘,

一个lua数组变量或python列表能存放数以万计的数据也是很强大了,不要过分弄那么大数据量哦。

红色:为随机点坐标

黄色:为机器人底座中心(x=0,y=0)及机器人不可到达的工作区域

绿色:为机器人可工作区域

因机器人各关节存在软限位,左侧区域是有部分无法到达的。

SCARA机器人随机点位生成可视化_第1张图片SCARA机器人随机点位生成可视化_第2张图片

SCARA机器人随机点位生成可视化_第3张图片

4.实现代码如下:

#!/usr/bin/env python3.6.5
# -*- coding: utf-8 -*-

from matplotlib.patches import Circle #matplotlib绘制圆形库
import matplotlib.pyplot as plt
from lupa import LuaRuntime
import lupa,time,csv #lupa v1.8
#下面两行代码专门用来解决中文显示问题
from pylab import *  
mpl.rcParams['font.sans-serif'] = ['Microsoft YaHei']

lua = LuaRuntime()
SCARA_Kinematics_Module = lua.require('SCARA_Kinematics_Py_Lua') #加载SCARA_Kinematics_Py_Lua.lua
end = "#" #Python代码块结束符

#-------------------------------------
#Lua代码
LuaCode = """
    function (TransNum)
        --********************* sub1 end *************************--
        --此处预留lua函数
        --******************* sub2 function **********************--
        --********************* sub2 end *************************--
        --此处预留lua函数
        --******************* sub3 function **********************--
        --此处预留lua函数
        --********************* sub3 end *************************--

        --lua入口--
	local T1 = tonumber(os.date("%S",os.time())) --开始时秒数
	--local file1 = assert(io.open("C:/Users/Administrator/Desktop/RandomJointPosData.csv","w")) --创建文件
	local file2 = assert(io.open("C:/Users/Administrator/Desktop/RandomCartPosData.csv","w")) --创建文件
	local ArmX,ArmY = 200,200                --X和Y臂臂长
	local XLimit,YLimit,CLimit = 130,130,180 --XYC关节软限位
	local ZLimit1,ZLimit2 = -140,0           --Z关节软限位
	--获取参数文件中的对应值
	--local XLimit,YLimit,CLimit = rwparam("Dsp_SoftLimitP|0"), rwparam("Dsp_SoftLimitP|1"), rwparam("Dsp_SoftLimitP|3")
	--local ZLimit1,ZLimit2 = rwparam("Dsp_SoftLimitP|2"), rwparam("Dsp_SoftLimitN|2")
	local ToolLen = 1                        --C轴末端工具杆长度
	local DZxLen,DZyLen = 300/2,270/2        --安装座长度和宽度
	local DesktopZ = -60                     --机器人Z原点到安装座的距离
	local UnworkRadius = 130.2               --机器人不可工作半径
	local J1Limit,J2Limit,J3Limit,J4Limit    --关节软限位
	local xpos,ypos,zpos,cpos,Hand           --笛卡尔坐标
	local H = nil                            --手系
	local count = 1                          --计数随机点个数
	local countOK = 0                        --计数随机点完成标志
	local TransNum = TransNum                --训练随机点坐标个数
	local JointPos,CartPos = {},{}           --保存的关节和笛卡尔坐标
        --local WhereFlag = {}                   --随机点在哪个区域的标志
	for i = 1,TransNum do                    --初始化
		--JointPos[i] = {0, 0, 0, 0}
		CartPos[i] = {0, 0, 0, 0, 0}
                --WhereFlag[i] = nil
	end
	
	math.randomseed(tostring(os.time()):reverse():sub(1,7)) --随机种子
	
	while true do
		while true do
			--产生整型关节限位数据
			J1Limit = math.random(-XLimit,XLimit)  --J1轴关节 负正 限位
			J2Limit = math.random(-YLimit,YLimit)  --J2轴关节 负正 限位
			J3Limit = math.random(ZLimit1,ZLimit2) --J3轴关节 负正 限位
			J4Limit = math.random(-CLimit,CLimit)  --J4轴关节 负正 限位
			
			--产生浮点型关节限位数据(random函数的参数只能是整数,实际上需要浮点数)
			J1Limit = J1Limit - J1Limit * math.random()
			J2Limit = J2Limit - J2Limit * math.random()
			J3Limit = J3Limit - J3Limit * math.random()
			J4Limit = J4Limit - J4Limit * math.random()
			
			--解算为笛卡尔坐标系
			xpos,ypos,cpos,Hand = SCARA_Forward_Kinematics(J1Limit,J2Limit,J4Limit,ArmX,ArmY)
			--剔除不需要的坐标
			--先判断Z高度,再选择可以生成在安装座之内还是安装座之外
			zpos = J3Limit
			if zpos > DesktopZ then --在安装座之内
				local Distance = math.sqrt((xpos-0)^2 + (ypos-0)^2) --机器人圆心到当前点的距离
				if Distance <= UnworkRadius + ToolLen then --距离小于工作半径+工具长度
					break --剔除
				end
				--WhereFlag[count] = 0 --在安装座之内的标志
			else --在安装座之外
				if xpos <= DZxLen+ToolLen and xpos >= -DZxLen-ToolLen and ypos <= DZyLen+ToolLen and ypos >= -DZyLen-ToolLen then
					break --剔除
				end
				--WhereFlag[count] = 1 --在安装座之外的标志
			end
			
			--解算为关节坐标
			if Hand == -1 then H = 0 elseif Hand == 1 then H = 1 end
			local jointX,jointY,jointC = SCARA_Inverse_Kinematics(xpos,ypos,cpos,ArmX,ArmY,H)
			--nil为解算错误
			if jointX == nil or jointY == nil or jointC == nil then break end
			--判断关节坐标是否超限
			if jointX>=XLimit or jointX <=-XLimit or jointY>=YLimit or jointY<=-YLimit or jointC>=CLimit or jointC<=-CLimit then
				break --剔除
			end
			if jointY < 0 then H = 0 else H = 1 end --手系(0:L 1:R)
                        
			--file1:write(jointX,",",jointY,",",J3Limit,"\\n") --写/保存关节数据到CSV
			file2:write(xpos,",",ypos,",",J3Limit,"\\n")     --写/保存笛卡尔数据到CSV
			
			--保存点位到数组中
			--JointPos[count][1] = jointX
			--JointPos[count][2] = jointY
			--JointPos[count][3] = J3Limit
			--JointPos[count][4] = jointC
			CartPos[count][1] = xpos
			CartPos[count][2] = ypos
			CartPos[count][3] = J3Limit
			CartPos[count][4] = cpos
			CartPos[count][5] = H
			
			count = count + 1
			if count == TransNum + 1 then --判断训练随机点个数是否达到设定值
				countOK = 1
				break
			end
		end
		if countOK == 1 then break end
	end
	--file1:close()
	file2:close()
	
	local T2 = tonumber(os.date("%S",os.time()))
	print("耗时:",T2 - T1," s") --结束时秒数
	--
	print("Trans pos end")
        --return JointPos, CartPos
        return TransNum
    end
"""
#-------------------------------------

#python画图
def DrawFig(f):
    #return_joint, return_cart = f
    return_TransNum = f
    font = [
            {'family': 'FangSong',    #字体类型:FangSong-仿宋
             'color':  'red',        #字体颜色:darkred-暗红
             'weight': 'normal',      #字体宽度:
             'size': 20,} ,           #字体大小:
            #-----------------------------------------------
            {'family': 'FangSong',    #字体类型:FangSong-仿宋
             'color':  'blue',         #字体颜色:darkred-暗红
             'weight': 'normal',      #字体宽度:
             'size': 10,} ,           #字体大小:        
            ]
    
    plt.close()  #clf() # 清图  cla() # 清坐标轴 close() # 关窗口
    fig = plt.figure()
    ax = fig.add_subplot(111)

    posNum = return_TransNum #随机点数
    X, Y, Z = [[] for ii in range(posNum)], [[] for jj in range(posNum)], [[] for Kk in range(posNum)] #初始化列表
    i = 0
    for line in open("RandomCartPosData.CSV"): #读取csv文件(一行一行读)
        x,y,z = line.split(",") #解析分隔符
        x,y,z = x.strip(' \t\r\n'),y.strip(' \t\r\n'),z.strip(' \t\r\n') #提取数据
        X[i].append(float(x))
        Y[i].append(float(y))
        #Z[i].append(float(z))
        i += 1
    end

    J1ArmLen,J2ArmLen = 200,200 #机器人J1和J2臂长
    ArmLen = J1ArmLen + J2ArmLen  #机器人臂长
    UnWorkArea = 130.2 #机器人不可工作区域半径

    #机器人工作半径
    cir1 = Circle(xy = (0.0, 0.0), radius = ArmLen, facecolor = 'green', alpha = 0.5) #颜色深度:0.1 ~ 1 = 0 ~ 255
    ax.add_patch(cir1) #画大圆

    #机器人不可工作区域半径
    cir2 = Circle(xy = (0.0, 0.0), radius = UnWorkArea, facecolor = 'yellow', alpha = 1)
    ax.add_patch(cir2) #画小圆
    
    #标签(size:文字大小 rotation:旋转角度 color:文字颜色 ha:文字在X轴的位置 va:文字在Y轴的位置)
    plt.text(0, 0, '不可运动区域',
             size=10, rotation=0, color='r', ha="center", va="center",
             )#bbox=dict(boxstyle="round", ec=(1., 0.5, 0.5), fc=(1., 0.8, 0.8)))#文字外围加边框
    
    plt.xlabel('-------------> X+ 方向', fontdict=font[0])
    plt.ylabel('-------------> Y+ 方向', fontdict=font[0])
    
    #随机位置散点图
    #for color, mark, i, j in [('r', 'o', range(len(X)),range(len(Y)))]:
    for color, mark, i, j in [('r', 'o', range(posNum),range(posNum))]:
        ax.plot(X, Y, 'ro',markersize = 1)
    end
    
    plt.axis('scaled')
    #ax.set_xlim(-4, 4)
    #ax.set_ylim(-4, 4)
    plt.axis('equal') #比例
    plt.grid(True) #添加网格
    plt.savefig('RandomPos.png')
    plt.show()
end

#调用Lua生成数据并保存到CSV文件
def Call_Lua():
    Start_time = time.time() #计时
    LuaFun = lua.eval(LuaCode) #处理数据(调用Lua脚本进行CSV文件处理)
    End_time = time.time()
    print("Process time is:", End_time - Start_time, " s")
    
    TransNum = 200 * 10000 #训练随机点数
    DrawFig(LuaFun(TransNum)) #绘图
end

Call_Lua()

 

5.lua正解和逆解函数,代码就不放了,可以去网上查资料。

需要注意的是,Python的lupa库在调用lua中的math.atan2(y,x)需要改成math.atan(y,x).

其次是lua代码中的"\n"需要改成"\\n",否则运行将出错。

你可能感兴趣的:(Python语言学习笔记,SCARA,机器人,机器人正解和逆解,lupa,Python)