在光度立体三维重建中,光源的光强、颜色、方向对重建效果具有重要意义。一般实际测试中,多采用led点光源。笔者实验中使用的是WS2812B全彩色led灯条。通过Arduino编程可以控制其光强、颜色。Arduino控制点亮led的配置细节可参考该博客,写的很详细。
笔者实验中需要改变小灯的亮度和颜色,包括点亮特定位置的小灯,或者全部点亮小灯。主要通过C#上位机发送颜色 光强 led标号给arduino,进而控制led按照设定显示。所遇到的主要问题是收发数据的格式规定。笔者规定的数据格式为:
“w-100-3”.
其中,w代表白色,颜色集合为{r,g,b,w}; 100代表光强,取值范围为[100,255];3代表标号为3的led小灯。
如果,所发送的数据中不包含led标号,如 “r-200”,默认为全部点亮,颜色为红色,光强为200.
Arduino程序中的loop函数如下,重点是字符串接收和字符分解读取操作。
void loop ()
{
uint16_t j = 0,lens = 0;
recData = "";
//不断循环检测串口缓存,一个个读入字符串,
while (Serial.available() > 0)
{
recData += char(Serial.read()); //拼接读入的字符串
delay(10); //延时一会,否则可能会导致数据丢失,
//Flag = true;
}
Serial.println(recData);
if(recData.length() > 4) // 判断发送过来的字符数据是否有效
{
lens = recData.length();
color = recData[0]; // 首位字符代表颜色
max_bright = recData.substring(2,5).toInt(); // 2到5之间的三位代表光强
Serial.println(color);
Serial.println(max_bright);
FastLED.setBrightness(max_bright); // 设置光强
set_max_power_in_volts_and_milliamps(5, 1000);
if(lens > 6) // 说明字符串中包含led标号
{
lightIndex = recData.substring(6,lens).toInt(); // 读取标号数值
Serial.println(lightIndex);
TurnOnLed(lightIndex,color); // 点亮指定标号小灯
}
else
{
if(color == 'r'){
for(j=0; j<NUM_LEDS; j = j+1)
{leds[j] = ledR;}
// FastLED.show();
}
else if(color == 'g'){
for(j=0; j<NUM_LEDS; j = j+1)
{leds[j] = ledG;}
// FastLED.show();
}
else if(color == 'b'){
//Serial.println("orange");
for(j=0; j<NUM_LEDS; j = j+1)
{leds[j] = ledB;}
// FastLED.show();
}
else if(color == 'o'){
for(j=0; j<NUM_LEDS; j = j+1)
{leds[j] = ledO;}
// FastLED.show();
}
else if(color == 'w'){
for(j=0; j<NUM_LEDS; j = j+1)
{leds[j] = ledW;}
// FastLED.show();
}
else if(color == 'f'){
for(j=0; j<NUM_LEDS; j = j+1)
{leds[j] = ledF;}
// FastLED.show();
}
FastLED.show();
}
recData = "";
}
}
void TurnOnLed(int LedIdx,char color)
{
uint16_t j;
for(j=0;j<NUM_LEDS;j++)
{leds[j] = ledF;} // 先将小灯全部熄灭
if(color == 'r') // 点亮指定位置的小灯
{
leds[LedIdx] = ledR; // 测试用红绿蓝 原为ledW
}
else if(color == 'g')
{
leds[LedIdx] = ledG; // 测试用红绿蓝 原为ledW
}
else if(color == 'b')
{
leds[LedIdx] = ledB; // 测试用红绿蓝 原为ledW
}
else if(color == 'o')
{
leds[LedIdx] = ledO; // 测试用红绿蓝 原为ledW
}
else if(color == 'w')
{
leds[LedIdx] = ledW; // 测试用红绿蓝 原为ledW
}
FastLED.show();
}
C# LED控制界面和程序如下:
private void btnLedControl_Click(object sender, EventArgs e)
{
if(lightTurn.IsBusy)
{
MessageBox.Show("线程正忙");
return;
}
lightTurn.DoWork += new DoWorkEventHandler(lightTurn_Dowork);
lightTurn.RunWorkerCompleted += new RunWorkerCompletedEventHandler(lightTurn_RunWorkerCompleted);
lightTurn.RunWorkerAsync();
}
private void lightTurn_Dowork(object sender,DoWorkEventArgs e)
{
string str = "";
string color = "";
int lightIntensity = 0;
int lightIndex = 0;
try
{
this.Invoke((EventHandler)delegate
{
color = this.comboBox1.SelectedItem.ToString();
}
);
int.TryParse(this.textBox1.Text, out lightIntensity);
int.TryParse(textBox2.Text, out lightIndex);
if (lightIntensity > 255)
{
lightIntensity = 255;
}
if (lightIntensity < 100)
{
lightIntensity = 100;
}
if (lightIndex < 1)
{
lightIndex = 0;
str = color + "-" + lightIntensity.ToString(); // 全亮
serialPort1.Open();// 打开串口
serialPort1.Write(str);
serialPort1.Close();
}
else if (lightIndex < 73)
{
str = color + "-" + lightIntensity.ToString() + "-" + (lightIndex-1).ToString();
serialPort1.Open();// 打开串口
serialPort1.Write(str);
serialPort1.Close();
}
else
{
//serialPort1.Open();// 打开串口
//serialPort1.WriteTimeout = 500;
string[] colorArr = { "r", "g", "b", "w" };
Random rd = new Random(1);
var color_num = 0;
var intensity_num = 0;
for (int i = 0; i < 73; i++)
{
color_num = rd.Next(0, 4);
intensity_num = rd.Next(100, 256);
if (i == 0 || i > 72)
{
str = colorArr[color_num] + "-" + intensity_num.ToString(); // 全亮
}
else
{
lightIndex = i - 1;
str = colorArr[color_num] + "-" + intensity_num.ToString() + "-" + lightIndex.ToString();
}
serialPort1.Open();// 打开串口
serialPort1.Write(str);
serialPort1.Close();
Thread.Sleep(500);
}
}
//MessageBox.Show("发送成功");
}
catch
{
if (serialPort1.IsOpen)
{
serialPort1.Close();
MessageBox.Show("端口打开成功");
}
MessageBox.Show("端口错误", "提示");
}
}
private void lightTurn_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//MessageBox.Show("大功告成");
return;
//if (lightTurn != null)
//{
// lightTurn.CancelAsync();
// lightTurn.Dispose();
//}
}
在测试控制LED颜色 光强等参数时,为了不影响主界面的卡顿,简单地利用backgrounder创建了小线程。最终实现了LED的颜色 光强 以及标号的测试。随机给定颜色和光强。可以最开始有个全亮的状态。