add old lci module
This commit is contained in:
1 parent
38a6e815f0
commit
8499631091
171 files changed
+25562
No files matched your search
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
/* Camera */
|
||||
#define cimg_display 0 /* 不显示图像,只保存 */
|
||||
#include "CImg.h"
|
||||
|
||||
void Camera_init(int w, int h);
|
||||
void Camera_close();
|
||||
bool Camera_is_open();
|
||||
|
||||
/* 在线程安全的情况下取得一帧图像 */
|
||||
cimg_library::CImg<unsigned char> get_frame_from_camera(bool& flag);
|
||||
@@ -0,0 +1,241 @@
|
||||
#pragma once
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <unistd.h>
|
||||
#include "cn/中文化.hpp"
|
||||
#include "Dashun_linux.hpp"
|
||||
命名空间 qing{
|
||||
类 伺服电机{ /* 180度舵机 */
|
||||
公开的:
|
||||
|
||||
/* FIXME: min只能比max小 */
|
||||
伺服电机(整数 通道, 单精度小数 上限=180, 单精度小数 下限=0, 逻辑型 逆向=false)
|
||||
: 通道(通道), 上限(上限), 下限(下限), 逆向(逆向) {}
|
||||
|
||||
/* 控制舵机运行至一个角度 */
|
||||
空类型 转动至(单精度小数 角度) {
|
||||
角度 = std::min(上限, 角度);
|
||||
角度 = std::max(下限, 角度);
|
||||
PCA9685_调整角度(
|
||||
通道, (逆向) ? 180 - 角度 : 角度
|
||||
);
|
||||
}
|
||||
|
||||
/* FIXME: 返回最大值 */
|
||||
单精度小数 取上限() {
|
||||
返回 上限;
|
||||
}
|
||||
|
||||
|
||||
私有的:
|
||||
整数 通道; /* 通道编号 */
|
||||
单精度小数 上限; /* 角度上限 */
|
||||
单精度小数 下限; /* 角度下限 */
|
||||
逻辑型 逆向; /* 是否反向 */
|
||||
};
|
||||
}
|
||||
|
||||
命名空间 qing {
|
||||
类 ActParser{ /* 动作脚本解析器 */
|
||||
公开的:
|
||||
|
||||
/* 解析标准输入中的动作脚本 */
|
||||
空类型 fromStdin() {
|
||||
计数 = 0;
|
||||
清除所有();
|
||||
解析(std::cin);
|
||||
}
|
||||
|
||||
/* 解析文件输入流中的动作脚本 */
|
||||
空类型 fromFile(const std::string& 路径) {
|
||||
计数 = 0;
|
||||
std::ifstream 文件(路径.c_str(), std::ios::in);
|
||||
如果 (!文件.is_open())
|
||||
抛出异常 std::runtime_error("打开文件失败");
|
||||
清除所有();
|
||||
解析(文件);
|
||||
文件.close();
|
||||
}
|
||||
|
||||
/* 解析字符串流中的动作脚本 */
|
||||
空类型 fromStr(const std::string& 脚本) {
|
||||
std::stringstream 流(脚本);
|
||||
计数 = 0;
|
||||
清除所有();
|
||||
解析(流);
|
||||
}
|
||||
|
||||
/* 执行刚刚解析出来的机器人和动作 */
|
||||
空类型 play() {
|
||||
如果 (机组.empty() || 矩阵.empty())
|
||||
抛出异常 std::runtime_error("没动作或机组");
|
||||
机器人扮演(机组, 矩阵);
|
||||
}
|
||||
|
||||
/* 获得机器人的最大值向量, FIXME: 把逻辑写在外面 */
|
||||
std::vector<float> get() {
|
||||
适应 结果 = std::vector<float>();
|
||||
计次循环 (适应& 项目: this->机组) {
|
||||
结果.push_back(项目.取上限());
|
||||
}
|
||||
/* 这个数组中包含机器人每个舵机的角度上限 */
|
||||
返回 结果;
|
||||
}
|
||||
|
||||
/* 获取当前这一组动作 */
|
||||
std::vector<float> now() {
|
||||
如果 (计数 >= 矩阵.size())
|
||||
抛出异常 std::runtime_error("now finished");
|
||||
返回 矩阵[计数];
|
||||
}
|
||||
|
||||
/* 执行下一组动作 */
|
||||
空类型 next() {
|
||||
如果 (计数 >= 矩阵.size())
|
||||
抛出异常 std::runtime_error("没下一个动作了");
|
||||
适应 临时向量 = 矩阵[计数++];
|
||||
适应 临时矩阵 = std::vector<std::vector<float>> ({临时向量});
|
||||
机器人扮演(机组, 临时矩阵);
|
||||
}
|
||||
|
||||
/* 输入下一个动作执行 */
|
||||
空类型 next(std::vector<float>& act) {
|
||||
计数++;
|
||||
auto vv = std::vector<std::vector<float>> ({act});
|
||||
机器人扮演(机组, vv);
|
||||
}
|
||||
private:
|
||||
字符 句[16] = {0}; /* FIXME: 这个栈有越界风险 */
|
||||
整数 顶 = 0;
|
||||
整数 计数 = 0;
|
||||
std::vector<float> 数组; /* 临时使用 */
|
||||
std::vector<std::vector<float>> 矩阵; /* 解析出的整套动作 */
|
||||
std::vector<伺服电机> 机组; /* 机器人抽象 */
|
||||
空类型 解析(std::istream& 源) { /* NOTE: 修改为非静态成员函数能够减少行数 FIXME: 改为使用C++风格的文件操作 */
|
||||
清除临时();
|
||||
字符 c = 0;
|
||||
布尔 end_flag = true;
|
||||
布尔 comment_flag = false;
|
||||
布尔 obj_flag = false;
|
||||
判断循环 (end_flag) { /* 255 for arm */
|
||||
end_flag = (bool)源.get(c);
|
||||
//std::cout<<c;
|
||||
如果 ((!comment_flag && c >= '0' && c <= '9') || c == '+' || c == '-') { /* 读取数字 */
|
||||
句[顶++] = c;
|
||||
std::cout<<c;
|
||||
}
|
||||
否则 如果 (!comment_flag && c == ' ') { /* 每个角度以空格结尾 */
|
||||
句[顶] = '\0';
|
||||
递交舵机();
|
||||
}
|
||||
否则 如果 (!comment_flag && (c == '\r' || c == '\n')) { /* 忽略回车 */
|
||||
;
|
||||
}
|
||||
否则 如果 (!comment_flag && c == '#') { /* 注释以#开头 */
|
||||
comment_flag = 真;
|
||||
}
|
||||
否则 如果 (comment_flag && c == '\n') { /* 注释以换行结尾 */
|
||||
comment_flag = 假;
|
||||
}
|
||||
否则 如果 (comment_flag && c != '\n') { /* 忽略注释 */
|
||||
;
|
||||
}
|
||||
否则 如果 (!comment_flag && !obj_flag && 顶 == 0 && c == '!') { /* 构建模式 */
|
||||
obj_flag = 真;
|
||||
}
|
||||
否则 如果 (!comment_flag && obj_flag && (c==';' || end_flag)) { /* 构建机器人 */
|
||||
句[顶] = '\0';
|
||||
递交舵机();
|
||||
递交机组();
|
||||
obj_flag = 假;
|
||||
}
|
||||
否则 如果 (!comment_flag && !obj_flag && (c == ';' || end_flag)) { /* 每个动作以分号结尾 */
|
||||
句[顶] = '\0';
|
||||
递交舵机();
|
||||
递交动作();
|
||||
}
|
||||
否则 {
|
||||
抛出异常 std::runtime_error(
|
||||
"Invalid action: " + std::to_string(int(c)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
空类型 递交舵机() {
|
||||
如果 (顶 > 0) {
|
||||
单精度小数 角度 = (单精度小数)atoi(句);
|
||||
数组.push_back(角度);
|
||||
std::cout<<角度<<std::endl;
|
||||
}
|
||||
句[0] = '\0';
|
||||
顶 = 0;
|
||||
}
|
||||
|
||||
空类型 递交动作() {
|
||||
如果 (!数组.empty()) {
|
||||
std::cout<<"接收到动作: " << 数组.size() << std::endl;
|
||||
矩阵.push_back(数组);
|
||||
数组 = std::vector<float>{};
|
||||
}
|
||||
}
|
||||
|
||||
空类型 递交机组() {
|
||||
如果 (!数组.empty()) {
|
||||
std::cout << "接收到机组: " << 数组.size() << std::endl;
|
||||
机组 = 机组工厂(数组);
|
||||
数组 = std::vector<float>{};
|
||||
}
|
||||
}
|
||||
|
||||
空类型 清除临时() {
|
||||
句[0] = '\0';
|
||||
顶 = 0;
|
||||
数组 = std::vector<float> {};
|
||||
}
|
||||
|
||||
空类型 清除所有() {
|
||||
句[0] = '\0';
|
||||
顶 = 0;
|
||||
数组 = std::vector<float> {};
|
||||
矩阵 = std::vector<std::vector<float>> {};
|
||||
机组 = std::vector<伺服电机> {};
|
||||
}
|
||||
|
||||
/* 机器人工厂,FIXME: 这里可以做成舵机工厂就可以了, */
|
||||
静态的 std::vector<伺服电机> 机组工厂(const std::vector<float>& 上限集) {
|
||||
std::vector<伺服电机> 机组;
|
||||
计次循环 (整数 甲=0; 甲 < 上限集.size(); ++甲)
|
||||
机组.push_back(
|
||||
伺服电机(甲, std::abs(上限集[甲]), 0, (上限集[甲] >= 0) ? 假 : 真));
|
||||
返回 机组;
|
||||
}
|
||||
|
||||
/* 机器人移动,输入一组舵机对象和一组目标角度 */
|
||||
静态的 空类型 机器人行动(std::vector<伺服电机>& 机组, std::vector<float>& 动作) {
|
||||
如果 (机组.size() + 1 != 动作.size())
|
||||
抛出异常 std::runtime_error(
|
||||
"动作与机组不符合, 我们有"
|
||||
+ std::to_string(机组.size()) + "和" + std::to_string(动作.size())
|
||||
);
|
||||
|
||||
/* FIXME: 随机下标以消除先后时间差 */
|
||||
计次循环 (int 甲=0; 甲<机组.size(); ++甲) {
|
||||
机组[甲].转动至(动作[甲]);
|
||||
}
|
||||
/* 最后一组数据是毫秒延时 */
|
||||
预求值的 整数 缩放 = 1000;
|
||||
usleep(动作[动作.size()-1] * 缩放);
|
||||
}
|
||||
|
||||
/* 机器人整套动作 */
|
||||
静态的 空类型 机器人扮演(
|
||||
std::vector<伺服电机>& 机组, std::vector<std::vector<float>>& 动作集)
|
||||
{
|
||||
计次循环 (适应 动作: 动作集)
|
||||
机器人行动(机组, 动作);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* 这是cpp使用linux C手段读写串口的实现。
|
||||
*
|
||||
* 作者在其中加入了“沟通”手段,这种手段主要是针对COPS设备。
|
||||
*
|
||||
* COPS设备的通信手段主要是上位机问,下位机答,一问一答的形式。
|
||||
*
|
||||
* (!)还未进行对于热插拔的支持。
|
||||
*
|
||||
* 20250621 暂时不用了
|
||||
*/
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <cstdio>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <sys/time.h>
|
||||
namespace qing {
|
||||
/*
|
||||
* 串口类
|
||||
*
|
||||
* 长连接的速度会更快
|
||||
*/
|
||||
class Serial {
|
||||
private:
|
||||
/* 串口文件描述符 */
|
||||
int fd = 0;
|
||||
public:
|
||||
/* 输入设备文件地址,进行构造。打开后通常需要等待一下 */
|
||||
Serial(const std::string& path, double wait = 2) {
|
||||
fd = open(path.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
if (fd == -1) {
|
||||
throw DeviceOpenErroring();
|
||||
}
|
||||
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds((long)(wait*1000))); /* 等待串口 */
|
||||
}
|
||||
//释放
|
||||
~Serial() {
|
||||
if (fd != -1) close(fd);
|
||||
}
|
||||
|
||||
/* 设置串口 */
|
||||
void Set() {
|
||||
struct termios options;
|
||||
tcgetattr(fd, &options);
|
||||
cfsetispeed(&options, B115200); /* 设置波特率 */
|
||||
cfsetospeed(&options, B115200);
|
||||
options.c_cflag |= (CLOCAL | CREAD);// 启用接收和本地模式
|
||||
options.c_cflag &= ~PARENB;// 8位数据位,无校验,1位停止位
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
options.c_cflag &= ~CSIZE;
|
||||
options.c_cflag |= CS8;
|
||||
options.c_cflag &= ~CRTSCTS;// 禁用硬件流控
|
||||
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);// 原始输入模式
|
||||
options.c_oflag &= ~OPOST;// 原始输出模式
|
||||
options.c_cc[VMIN] = 0;// 设置超时 - 1秒
|
||||
options.c_cc[VTIME] = 10;
|
||||
tcsetattr(fd, TCSANOW, &options);
|
||||
tcflush(fd, TCIOFLUSH); /* 清空缓冲区 */
|
||||
}
|
||||
|
||||
/* 写数据 每次写之前清空缓冲区数据*/
|
||||
void Write(const std::string& msg) {
|
||||
tcflush(fd, TCIOFLUSH); /* 清空缓冲区 */
|
||||
write(fd, msg.c_str(), msg.size());
|
||||
}
|
||||
|
||||
/* 读数据 */
|
||||
std::string CircleRead() {
|
||||
char buffer[1024] = {0};
|
||||
std::string ret = "";
|
||||
ssize_t n;
|
||||
do {
|
||||
n = read(fd, buffer, sizeof(buffer));
|
||||
if (n == -1 && ret == "") {
|
||||
throw NoResponse();
|
||||
} else if (n == -1 && ret != "") {
|
||||
return ret;
|
||||
} else if (n == 0) {
|
||||
return ret;
|
||||
} else if (n > 0) {
|
||||
buffer[n] = '\0';
|
||||
ret += buffer;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/* 读数据 */
|
||||
std::string Read() {
|
||||
char buffer[1024] = {0};
|
||||
std::string ret = "";
|
||||
ssize_t n;
|
||||
n = read(fd, buffer, sizeof(buffer));
|
||||
if (n == -1 && ret == "") {
|
||||
throw NoResponse();
|
||||
} else if (n > 0) {
|
||||
buffer[n] = '\0';
|
||||
ret += buffer;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* 发送然后获取 */
|
||||
std::string Send_Wait_And_Get(const std::string& snd, double wait) {
|
||||
Write(snd);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds((long)(wait*1000)));
|
||||
return Read();
|
||||
}
|
||||
|
||||
/* 一问一答,尝试一定次数 */
|
||||
std::string Try_Comm(const std::string& snd, double wait, int times = 10, int drop_tail = 0) {
|
||||
int num = 0;
|
||||
while (true) {
|
||||
try {
|
||||
num ++;
|
||||
if (num > times) break;
|
||||
std::string msg = Send_Wait_And_Get(snd, wait);
|
||||
DropTail(msg, drop_tail);
|
||||
return msg;
|
||||
} catch (qing::Serial::Serial_Error e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
throw NoResponse();
|
||||
}
|
||||
|
||||
/* 去掉字符串末尾一定数量的字符 */
|
||||
static void DropTail(std::string& msg, int n) {
|
||||
for (int i=0; i<n; i++) {
|
||||
msg.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
/* 串口异常类 */
|
||||
class Serial_Error: public std::exception {
|
||||
private:
|
||||
std::string message;
|
||||
public:
|
||||
explicit Serial_Error(const std::string& msg): message(msg) {}
|
||||
const char* what() const noexcept override {
|
||||
return message.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
/* 打开设备异常 */
|
||||
class DeviceOpenErroring: public Serial_Error {
|
||||
public:
|
||||
DeviceOpenErroring(): Serial_Error("Device Open Erroring") {}
|
||||
};
|
||||
|
||||
/* select异常 */
|
||||
class SelectErroring: public Serial_Error {
|
||||
public:
|
||||
SelectErroring(): Serial_Error("Select Erroring") {}
|
||||
};
|
||||
|
||||
/* 无响应 */
|
||||
class NoResponse: public Serial_Error {
|
||||
public:
|
||||
NoResponse(): Serial_Error(" No Response") {}
|
||||
};
|
||||
|
||||
/* 无响应异常 */
|
||||
class SerialReadError: public Serial_Error {
|
||||
public:
|
||||
SerialReadError(): Serial_Error("Serial Read Error") {}
|
||||
};
|
||||
|
||||
/* 获取所有的串口 */
|
||||
static std::vector<std::string> GetPorts() {
|
||||
std::vector<std::string> ports;
|
||||
//Linux实现
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
const std::regex serial_regex("(ttyS|ttyUSB|ttyACM)[0-9]+");
|
||||
if ((dir = opendir("/dev")) != NULL) {
|
||||
while((ent = readdir(dir)) != NULL) {
|
||||
std::string name = ent->d_name;
|
||||
if (std::regex_match(name, serial_regex)) {
|
||||
ports.push_back("/dev/"+name);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
return ports;
|
||||
}
|
||||
|
||||
/* 以线程不安全的方式打印所有的串口 */
|
||||
static void UnsafePrintPorts() {
|
||||
auto v = GetPorts();
|
||||
for (const auto& i: v) {
|
||||
std::cout << i << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
|
||||
struct CpuData {
|
||||
std::string cpu_name;
|
||||
long user;
|
||||
long nice;
|
||||
long system;
|
||||
long idle;
|
||||
long iowait;
|
||||
long irq;
|
||||
long softirq;
|
||||
long steal;
|
||||
long guest;
|
||||
long guest_nice;
|
||||
|
||||
long total() const {
|
||||
return user + nice + system + idle + iowait + irq + softirq + steal;
|
||||
}
|
||||
|
||||
long idle_total() const {
|
||||
return idle + iowait;
|
||||
}
|
||||
};
|
||||
|
||||
class CpuMonitor {
|
||||
private:
|
||||
std::vector<CpuData> read_cpu_stats() {
|
||||
std::vector<CpuData> stats;
|
||||
std::ifstream file("/proc/stat");
|
||||
std::string line;
|
||||
|
||||
while (std::getline(file, line)) {
|
||||
if (line.substr(0, 3) == "cpu") {
|
||||
std::istringstream iss(line);
|
||||
CpuData data;
|
||||
iss >> data.cpu_name >> data.user >> data.nice >> data.system
|
||||
>> data.idle >> data.iowait >> data.irq >> data.softirq
|
||||
>> data.steal >> data.guest >> data.guest_nice;
|
||||
stats.push_back(data);
|
||||
}
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
public:
|
||||
double get_cpu_usage() {
|
||||
auto stats1 = read_cpu_stats();
|
||||
sleep(1);
|
||||
auto stats2 = read_cpu_stats();
|
||||
|
||||
if (stats1.empty() || stats2.empty()) {
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
long total_diff = stats2[0].total() - stats1[0].total();
|
||||
long idle_diff = stats2[0].idle_total() - stats1[0].idle_total();
|
||||
|
||||
if (total_diff == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return 100.0 * (total_diff - idle_diff) / total_diff;
|
||||
}
|
||||
|
||||
std::vector<double> get_per_cpu_usage() {
|
||||
auto stats1 = read_cpu_stats();
|
||||
sleep(1);
|
||||
auto stats2 = read_cpu_stats();
|
||||
|
||||
std::vector<double> usages;
|
||||
|
||||
for (size_t i = 1; i < stats1.size() && i < stats2.size(); i++) {
|
||||
long total_diff = stats2[i].total() - stats1[1].total();
|
||||
long idle_diff = stats2[i].idle_total() - stats1[i].idle_total();
|
||||
|
||||
if (total_diff > 0) {
|
||||
usages.push_back(100.0 * (total_diff - idle_diff) / total_diff);
|
||||
} else {
|
||||
usages.push_back(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
return usages;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef HD_MEM_H
|
||||
#define HD_MEM_H
|
||||
#include <iostream>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
struct MemoryInfo {
|
||||
long totalMemory; /* 总内存(bytes) */
|
||||
long freeMemory; /* 空闲内存 */
|
||||
long usedMemory; /* 已用内存 */
|
||||
double usageRate; /* 使用率(%) */
|
||||
};
|
||||
|
||||
MemoryInfo getMemoryUsageWithSysinfo();
|
||||
#endif
|
||||
Reference in new issue
Block a user