环境如下:
#!/usr/bin/env python2
from turtle_turtlebot.turtlebot import TurtleBot
if True:
x = TurtleBot()
x.move2goal(10,10)
webEngineView->load(QUrl("file:///" + strHtml));
即可
将blockly块拖拽完成之后,可以生成python代码,也可以将工作区保存下来。点击保存文件按钮,将生成的py和xml都存了下来。
1.qt点击保存按钮,触发js方法
/**
* @brief pushButton相应槽函数
* @param
* @retval void
*/
void RobotTaskFrame::pushButtonClickedSlot()
{
QPushButton *pBtn = qobject_cast<QPushButton *>(sender());
if(pBtn == ui->pushButton_save1)
{
//qt调用js方法
jsContext->jsSendPathfile(webEngineView->page(),"");
}
......
2.js调用生成python代码和xml工作区代码,并调用qt的保存文件方法
// 接收qt发送的消息
function recvMessage(msg)
{
var pathfile = msg;
var xml = Blockly.Xml.workspaceToDom(robotWorkspace,false);
var strXml = Blockly.Xml.domToText(xml);
var pythonCode = Blockly.Python.workspaceToCode(robotWorkspace);
blocklyObj.onSaveFile(pathfile,strXml,pythonCode);
}
3.qt中保存代码到磁盘
void RobotTaskFrame::saveFileSlot(const QString &msg, const QString &strXml, const QString &strPy)
{
QString magic = QString(tr("#!/usr/bin/env python2\n"));
std::string ss = ros::package::getPath("robot_control_python");
QString fileName = QFileDialog::getSaveFileName(this, tr("选择保存路径"),QString(ss.c_str()));
if(fileName == nullptr)
{
return;
}
QString xmlFileName = fileName + QString(".xml");
QString pyFileName = fileName + QString(".py");
QFile xmlfile;
xmlfile.setFileName(xmlFileName);
xmlfile.open(QIODevice::WriteOnly | QIODevice::Text);
xmlfile.write(strXml.toUtf8());
xmlfile.close();
QFile pyfile;
pyfile.setFileName(pyFileName);
pyfile.open(QIODevice::WriteOnly | QIODevice::Text);
pyfile.write(magic.toUtf8());
pyfile.write(strPy.toUtf8());
pyfile.setPermissions(pyfile.permissions() | QFileDevice::ExeOwner);
pyfile.close();
}
这里要注意的一点是,生成的python代码加上了#!/usr/bin/env python2
头,这样使用rosrun是才能运行
4.rosrun运行即可rosrun robot_control_python my_test.py
1.qt读取上一步保存的xml,并触发js
else if(pBtn == ui->pushButton_open)
{
QString strXml;
std::string ss = ros::package::getPath("robot_control_python");
QString fileName = QFileDialog::getOpenFileName(this, tr("打开blockly文件"),QString(ss.c_str()));
if(fileName != nullptr)
{
QFile file;
file.setFileName(fileName);
if(file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QByteArray t ;
while(!file.atEnd())
{
t += file.readLine();
}
strXml = QString(t);
file.close();
}
jsContext->jsSendXml(webEngineView->page(),strXml);
}
}
2.js将xml转换为blockly工作区
function recvXml(xml)
{
var blocklyXml = xml;
let workspace = Blockly.getMainWorkspace();
workspace.clear();
var domXml = Blockly.Xml.textToDom(blocklyXml);
Blockly.Xml.domToWorkspace(domXml, workspace);
}
robotWorkspace.highlightBlock(id);
if(!isStep)
{
ui->pushButton_debug->setText(QString(tr("停止调试")));
jsContext->jsSrcReq(webEngineView->page(),"");
ui->pushButton_step->setEnabled(true);
isStep = true;
isStop = false;
}
2.js中生成python代码
function recvPython(prefix)
{
Blockly.Python.STATEMENT_PREFIX = 'sys.stdout.flush();\npdb.set_trace();\nblockid=%1;\n';
latestCode = Blockly.Python.workspaceToCode(robotWorkspace);
outputArea.value = '<< Program started: >>';
blocklyObj.onSaveDebugSrc('',latestCode);
}
注意:
void RobotTaskFrame::saveDebugSrcSlot(const QString &msg, const QString &strPy)
{
//qDebug() << strPy;
QString magic = QString(tr("#!/usr/bin/env python2\nimport pdb\nimport sys\n"));
std::string ss = ros::package::getPath("robot_control_python");
QString fileName = QString("%1.py").arg(QDateTime::currentSecsSinceEpoch());
QString pathFile = QString("/%1/%2").arg(ss.c_str()).arg(fileName);
tempFilename = pathFile;
#if 1
QFile pyfile;
pyfile.setFileName(pathFile);
pyfile.open(QIODevice::WriteOnly | QIODevice::Text);
pyfile.write(magic.toUtf8());
pyfile.write(strPy.toUtf8());
pyfile.setPermissions(pyfile.permissions() | QFileDevice::ExeOwner);
pyfile.close();
#endif
QString program = "python";
QStringList arguments;
arguments << fileName;
process->start(program, arguments);
process->waitForStarted();
process->write("c\r\n");
process->waitForBytesWritten();
}
生成的py文件如下:
#!/usr/bin/env python2
import pdb
import sys
sys.stdout.flush();
pdb.set_trace();
blockid='-2.(~eJmZY@q|j7,tM$n';
if True:
sys.stdout.flush();
pdb.set_trace();
blockid='Fk?d:jA`P!oDat3s])%h';
print('a')
sys.stdout.flush();
pdb.set_trace();
blockid='g_sB,-:}H,!NUE2EYuIo';
print('b')
4.连续点击单步执行,即可以按照块进行执行
else if(pBtn == ui->pushButton_step)
{
process->write("c\r\n");
process->waitForBytesWritten();
}
注意:pdb中,输入c表示继续执行
5.执行输出和切换块的高亮
void RobotTaskFrame::readFromClientSlot()
{
//> 程序当前行数 > /home/test2/bit_ws/install/share/robot_control_python/1583120215.py(6)()
//-> 当前行代码 -> blockid='~LoZ?n!exE/^j0t]*9or';
//其他的认为是程序输出
if( !process)
return;
QByteArray output = process->readAllStandardOutput();
//qDebug() << output;
//blockid='J+3zS5^y.KF88a3V;~%b';
QString string = output;
//1.以回车分割,找到以blockid开始的行,然后拿到单引号之内的内容
QStringList list = string.split('\n');
//qDebug() << list;
QString blockid;
QString pout;
//-> blockid=
for(int i = 0;i < list.size(); ++i)
{
QString temp = list.at(i);
if(temp.startsWith("-> blockid=") == true)
{
QStringList list1 = temp.split('\'');
//qDebug() << list1;
if(list1.length() == 3)
{
blockid = list1.at(1);
}
}
else if(temp.startsWith(">") == true)
{
qDebug() << temp;
}
else if(temp.startsWith("(Pdb)") == true)
{
//qDebug() << temp;
pout = temp.remove("(Pdb) ");
}
}
if(blockid.length() <= 0)
{
return;
}
//2.调用js函数highlightBlock(blockid)
jsContext->jsHighLight(webEngineView->page(),blockid,pout);
}
注意:readFromClientSlot为readyRead信号的槽函数,用于读取标准输出内容
6.程序结束
void RobotTaskFrame::processFinishedSlot(int exitCode, QProcess::ExitStatus exitStatus)
{
isStop = true;
ui->pushButton_step->setEnabled(false);
jsContext->jsHighLightOff(webEngineView->page(),"");
QFile file(tempFilename);
file.remove();
}
注意:processFinishedSlot为finished信号的槽函数,用于处理进程结束
Writing a Simple Publisher and Subscriber (Python)
blockly开发之使用python驱动浏览器中的turtle(2)